summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine')
-rw-r--r--src/devices/machine/1801vp128.cpp813
-rw-r--r--src/devices/machine/1801vp128.h213
-rw-r--r--src/devices/machine/1ma6.cpp14
-rw-r--r--src/devices/machine/1ma6.h12
-rw-r--r--src/devices/machine/1mb5.cpp13
-rw-r--r--src/devices/machine/1mb5.h8
-rw-r--r--src/devices/machine/2812fifo.cpp13
-rw-r--r--src/devices/machine/2812fifo.h14
-rw-r--r--src/devices/machine/28fxxx.cpp10
-rw-r--r--src/devices/machine/28fxxx.h6
-rw-r--r--src/devices/machine/40105.cpp35
-rw-r--r--src/devices/machine/40105.h8
-rw-r--r--src/devices/machine/53c7xx.cpp55
-rw-r--r--src/devices/machine/53c7xx.h5
-rw-r--r--src/devices/machine/53c810.cpp2
-rw-r--r--src/devices/machine/64h156.cpp29
-rw-r--r--src/devices/machine/64h156.h28
-rw-r--r--src/devices/machine/6522via.cpp381
-rw-r--r--src/devices/machine/6522via.h93
-rw-r--r--src/devices/machine/6525tpi.cpp50
-rw-r--r--src/devices/machine/6525tpi.h26
-rw-r--r--src/devices/machine/6532riot.cpp515
-rw-r--r--src/devices/machine/6532riot.h123
-rw-r--r--src/devices/machine/68153bim.cpp24
-rw-r--r--src/devices/machine/68153bim.h12
-rw-r--r--src/devices/machine/6821pia.cpp252
-rw-r--r--src/devices/machine/6821pia.h53
-rw-r--r--src/devices/machine/68230pit.cpp288
-rw-r--r--src/devices/machine/68230pit.h74
-rw-r--r--src/devices/machine/68307.cpp71
-rw-r--r--src/devices/machine/68307.h18
-rw-r--r--src/devices/machine/68307bus.cpp24
-rw-r--r--src/devices/machine/68307sim.cpp20
-rw-r--r--src/devices/machine/68307tmu.cpp52
-rw-r--r--src/devices/machine/68340.cpp68
-rw-r--r--src/devices/machine/68340.h31
-rw-r--r--src/devices/machine/68340dma.cpp8
-rw-r--r--src/devices/machine/68340ser.cpp12
-rw-r--r--src/devices/machine/68340ser.h2
-rw-r--r--src/devices/machine/68340sim.cpp131
-rw-r--r--src/devices/machine/68340tmu.cpp26
-rw-r--r--src/devices/machine/68340tmu.h5
-rw-r--r--src/devices/machine/6840ptm.cpp614
-rw-r--r--src/devices/machine/6840ptm.h51
-rw-r--r--src/devices/machine/6850acia.cpp17
-rw-r--r--src/devices/machine/6850acia.h10
-rw-r--r--src/devices/machine/68561mpcc.cpp40
-rw-r--r--src/devices/machine/68561mpcc.h12
-rw-r--r--src/devices/machine/6883sam.cpp491
-rw-r--r--src/devices/machine/6883sam.h219
-rw-r--r--src/devices/machine/7200fifo.cpp55
-rw-r--r--src/devices/machine/7200fifo.h7
-rw-r--r--src/devices/machine/7400.cpp94
-rw-r--r--src/devices/machine/7400.h85
-rw-r--r--src/devices/machine/7404.cpp26
-rw-r--r--src/devices/machine/7404.h26
-rw-r--r--src/devices/machine/74123.cpp50
-rw-r--r--src/devices/machine/74123.h13
-rw-r--r--src/devices/machine/74145.cpp3
-rw-r--r--src/devices/machine/74148.cpp11
-rw-r--r--src/devices/machine/74153.cpp28
-rw-r--r--src/devices/machine/74153.h24
-rw-r--r--src/devices/machine/74157.cpp45
-rw-r--r--src/devices/machine/74157.h26
-rw-r--r--src/devices/machine/74161.cpp25
-rw-r--r--src/devices/machine/74161.h22
-rw-r--r--src/devices/machine/74165.cpp12
-rw-r--r--src/devices/machine/74165.h6
-rw-r--r--src/devices/machine/74166.cpp12
-rw-r--r--src/devices/machine/74166.h6
-rw-r--r--src/devices/machine/74175.cpp29
-rw-r--r--src/devices/machine/74175.h16
-rw-r--r--src/devices/machine/74181.cpp4
-rw-r--r--src/devices/machine/74181.h12
-rw-r--r--src/devices/machine/74259.cpp21
-rw-r--r--src/devices/machine/74259.h20
-rw-r--r--src/devices/machine/74381.cpp4
-rw-r--r--src/devices/machine/74543.cpp15
-rw-r--r--src/devices/machine/74543.h12
-rw-r--r--src/devices/machine/7474.cpp30
-rw-r--r--src/devices/machine/7474.h16
-rw-r--r--src/devices/machine/8042kbdc.cpp197
-rw-r--r--src/devices/machine/8042kbdc.h41
-rw-r--r--src/devices/machine/82s129.cpp34
-rw-r--r--src/devices/machine/82s129.h28
-rw-r--r--src/devices/machine/8364_paula.cpp264
-rw-r--r--src/devices/machine/8364_paula.h74
-rw-r--r--src/devices/machine/8530scc.cpp94
-rw-r--r--src/devices/machine/8530scc.h4
-rw-r--r--src/devices/machine/aakart.cpp209
-rw-r--r--src/devices/machine/aakart.h81
-rw-r--r--src/devices/machine/acorn_bmu.cpp267
-rw-r--r--src/devices/machine/acorn_bmu.h87
-rw-r--r--src/devices/machine/acorn_ioc.cpp400
-rw-r--r--src/devices/machine/acorn_ioc.h129
-rw-r--r--src/devices/machine/acorn_lc.cpp152
-rw-r--r--src/devices/machine/acorn_lc.h85
-rw-r--r--src/devices/machine/acorn_memc.cpp512
-rw-r--r--src/devices/machine/acorn_memc.h101
-rw-r--r--src/devices/machine/acorn_vidc.cpp215
-rw-r--r--src/devices/machine/acorn_vidc.h59
-rw-r--r--src/devices/machine/adc0804.cpp11
-rw-r--r--src/devices/machine/adc0804.h6
-rw-r--r--src/devices/machine/adc0808.cpp19
-rw-r--r--src/devices/machine/adc0808.h7
-rw-r--r--src/devices/machine/adc083x.cpp14
-rw-r--r--src/devices/machine/adc083x.h12
-rw-r--r--src/devices/machine/adc0844.cpp30
-rw-r--r--src/devices/machine/adc0844.h9
-rw-r--r--src/devices/machine/adc1038.cpp8
-rw-r--r--src/devices/machine/adc1038.h8
-rw-r--r--src/devices/machine/aic565.cpp15
-rw-r--r--src/devices/machine/aic565.h3
-rw-r--r--src/devices/machine/aic580.cpp23
-rw-r--r--src/devices/machine/aic580.h5
-rw-r--r--src/devices/machine/aic6250.cpp17
-rw-r--r--src/devices/machine/aic6250.h2
-rw-r--r--src/devices/machine/aicartc.cpp11
-rw-r--r--src/devices/machine/aicartc.h3
-rw-r--r--src/devices/machine/akiko.cpp251
-rw-r--r--src/devices/machine/akiko.h7
-rw-r--r--src/devices/machine/alpha_8921.cpp12
-rw-r--r--src/devices/machine/alpha_8921.h12
-rw-r--r--src/devices/machine/am25s55x.cpp2
-rw-r--r--src/devices/machine/am2847.cpp18
-rw-r--r--src/devices/machine/am2847.h18
-rw-r--r--src/devices/machine/am2901b.cpp28
-rw-r--r--src/devices/machine/am2901b.h12
-rw-r--r--src/devices/machine/am2910.cpp31
-rw-r--r--src/devices/machine/am2910.h13
-rw-r--r--src/devices/machine/am53cf96.cpp193
-rw-r--r--src/devices/machine/am53cf96.h72
-rw-r--r--src/devices/machine/am79c30.cpp12
-rw-r--r--src/devices/machine/am79c30.h3
-rw-r--r--src/devices/machine/am79c90.cpp48
-rw-r--r--src/devices/machine/am79c90.h2
-rw-r--r--src/devices/machine/am9513.cpp58
-rw-r--r--src/devices/machine/am9513.h40
-rw-r--r--src/devices/machine/am9516.cpp1027
-rw-r--r--src/devices/machine/am9516.h135
-rw-r--r--src/devices/machine/am9517a.cpp159
-rw-r--r--src/devices/machine/am9517a.h24
-rw-r--r--src/devices/machine/am9519.cpp135
-rw-r--r--src/devices/machine/am9519.h24
-rw-r--r--src/devices/machine/amiga_copper.cpp393
-rw-r--r--src/devices/machine/amiga_copper.h102
-rw-r--r--src/devices/machine/amigafdc.cpp144
-rw-r--r--src/devices/machine/amigafdc.h5
-rw-r--r--src/devices/machine/appldriv.cpp336
-rw-r--r--src/devices/machine/appldriv.h71
-rw-r--r--src/devices/machine/applefdc.cpp586
-rw-r--r--src/devices/machine/applefdc.h152
-rw-r--r--[-rwxr-xr-x]src/devices/machine/applefdintf.cpp56
-rw-r--r--[-rwxr-xr-x]src/devices/machine/applefdintf.h33
-rw-r--r--src/devices/machine/applepic.cpp434
-rw-r--r--src/devices/machine/applepic.h108
-rw-r--r--src/devices/machine/archimedes_keyb.cpp414
-rw-r--r--src/devices/machine/archimedes_keyb.h73
-rw-r--r--src/devices/machine/arm_iomd.cpp121
-rw-r--r--src/devices/machine/arm_iomd.h29
-rw-r--r--src/devices/machine/at.cpp426
-rw-r--r--src/devices/machine/at.h107
-rw-r--r--src/devices/machine/at28c16.cpp46
-rw-r--r--src/devices/machine/at28c16.h10
-rw-r--r--src/devices/machine/at28c64b.cpp271
-rw-r--r--src/devices/machine/at28c64b.h80
-rw-r--r--src/devices/machine/at29x.cpp36
-rw-r--r--src/devices/machine/at29x.h9
-rw-r--r--src/devices/machine/at45dbxx.cpp49
-rw-r--r--src/devices/machine/at45dbxx.h12
-rw-r--r--src/devices/machine/at_keybc.cpp27
-rw-r--r--src/devices/machine/at_keybc.h10
-rw-r--r--src/devices/machine/ataflash.cpp45
-rw-r--r--src/devices/machine/ataflash.h23
-rw-r--r--src/devices/machine/atahle.cpp921
-rw-r--r--src/devices/machine/atahle.h261
-rw-r--r--src/devices/machine/atastorage.cpp1000
-rw-r--r--src/devices/machine/atastorage.h131
-rw-r--r--src/devices/machine/atmel_arm_aic.cpp6
-rw-r--r--src/devices/machine/atmel_arm_aic.h46
-rw-r--r--src/devices/machine/ay31015.cpp34
-rw-r--r--src/devices/machine/ay31015.h41
-rw-r--r--src/devices/machine/bacta_datalogger.cpp217
-rw-r--r--src/devices/machine/bacta_datalogger.h39
-rw-r--r--src/devices/machine/bitmap_printer.cpp484
-rw-r--r--src/devices/machine/bitmap_printer.h124
-rw-r--r--src/devices/machine/bl_handhelds_menucontrol.cpp12
-rw-r--r--src/devices/machine/bl_handhelds_menucontrol.h10
-rw-r--r--src/devices/machine/bq4847.cpp502
-rw-r--r--src/devices/machine/bq4847.h121
-rw-r--r--src/devices/machine/bq48x2.cpp40
-rw-r--r--src/devices/machine/bq48x2.h6
-rw-r--r--src/devices/machine/buffer.h16
-rw-r--r--src/devices/machine/busmouse.cpp9
-rw-r--r--src/devices/machine/busmouse.h3
-rw-r--r--src/devices/machine/cammu.cpp814
-rw-r--r--src/devices/machine/cammu.h665
-rw-r--r--src/devices/machine/cat702.cpp310
-rw-r--r--src/devices/machine/cat702.h63
-rw-r--r--src/devices/machine/cdp1852.cpp16
-rw-r--r--src/devices/machine/cdp1852.h2
-rw-r--r--src/devices/machine/cdp1871.cpp43
-rw-r--r--src/devices/machine/cdp1871.h13
-rw-r--r--src/devices/machine/cdp1879.cpp16
-rw-r--r--src/devices/machine/cdp1879.h3
-rw-r--r--src/devices/machine/ch376.cpp527
-rw-r--r--src/devices/machine/ch376.h81
-rw-r--r--src/devices/machine/chessmachine.cpp91
-rw-r--r--src/devices/machine/chessmachine.h19
-rw-r--r--src/devices/machine/clock.cpp125
-rw-r--r--src/devices/machine/clock.h37
-rw-r--r--src/devices/machine/com52c50.cpp157
-rw-r--r--src/devices/machine/com52c50.h88
-rw-r--r--src/devices/machine/com8116.cpp62
-rw-r--r--src/devices/machine/com8116.h12
-rw-r--r--src/devices/machine/cop452.cpp107
-rw-r--r--src/devices/machine/cop452.h47
-rw-r--r--src/devices/machine/corvushd.cpp223
-rw-r--r--src/devices/machine/corvushd.h16
-rw-r--r--src/devices/machine/cr511b.cpp25
-rw-r--r--src/devices/machine/cr511b.h9
-rw-r--r--src/devices/machine/cs4031.cpp59
-rw-r--r--src/devices/machine/cs4031.h98
-rw-r--r--src/devices/machine/cs8221.cpp4
-rw-r--r--src/devices/machine/cs8900a.cpp29
-rw-r--r--src/devices/machine/cs8900a.h2
-rw-r--r--src/devices/machine/cxd1095.cpp12
-rw-r--r--src/devices/machine/cxd1185.cpp11
-rw-r--r--src/devices/machine/cxd1185.h2
-rw-r--r--src/devices/machine/dc7085.cpp449
-rw-r--r--src/devices/machine/dc7085.h186
-rw-r--r--src/devices/machine/diablo_hd.cpp25
-rw-r--r--src/devices/machine/diablo_hd.h4
-rw-r--r--src/devices/machine/dimm_spd.cpp328
-rw-r--r--src/devices/machine/dimm_spd.h70
-rw-r--r--src/devices/machine/dl11.cpp283
-rw-r--r--src/devices/machine/dl11.h103
-rw-r--r--src/devices/machine/dmac.cpp22
-rw-r--r--src/devices/machine/dmac.h10
-rw-r--r--src/devices/machine/dp8390.cpp12
-rw-r--r--src/devices/machine/dp8390.h6
-rw-r--r--src/devices/machine/dp83932c.cpp161
-rw-r--r--src/devices/machine/dp83932c.h8
-rw-r--r--src/devices/machine/dp8573.cpp358
-rw-r--r--src/devices/machine/dp8573.h149
-rw-r--r--src/devices/machine/dp8573a.cpp486
-rw-r--r--src/devices/machine/dp8573a.h73
-rw-r--r--src/devices/machine/ds1204.cpp116
-rw-r--r--src/devices/machine/ds1204.h12
-rw-r--r--src/devices/machine/ds1205.cpp132
-rw-r--r--src/devices/machine/ds1205.h12
-rw-r--r--src/devices/machine/ds1207.cpp682
-rw-r--r--src/devices/machine/ds1207.h122
-rw-r--r--src/devices/machine/ds128x.cpp15
-rw-r--r--src/devices/machine/ds1302.cpp110
-rw-r--r--src/devices/machine/ds1302.h34
-rw-r--r--src/devices/machine/ds1315.cpp8
-rw-r--r--src/devices/machine/ds1386.cpp185
-rw-r--r--src/devices/machine/ds1386.h46
-rw-r--r--src/devices/machine/ds1994.cpp597
-rw-r--r--src/devices/machine/ds1994.h33
-rw-r--r--src/devices/machine/ds2401.cpp133
-rw-r--r--src/devices/machine/ds2401.h13
-rw-r--r--src/devices/machine/ds2404.cpp29
-rw-r--r--src/devices/machine/ds2404.h6
-rw-r--r--src/devices/machine/ds2430a.cpp693
-rw-r--r--src/devices/machine/ds2430a.h145
-rw-r--r--src/devices/machine/ds6417.cpp174
-rw-r--r--src/devices/machine/ds6417.h63
-rw-r--r--src/devices/machine/ds75160a.cpp22
-rw-r--r--src/devices/machine/ds75160a.h4
-rw-r--r--src/devices/machine/ds75161a.cpp111
-rw-r--r--src/devices/machine/ds75161a.h40
-rw-r--r--src/devices/machine/e0516.cpp259
-rw-r--r--src/devices/machine/e0516.h43
-rw-r--r--src/devices/machine/e05a03.cpp33
-rw-r--r--src/devices/machine/e05a03.h12
-rw-r--r--src/devices/machine/e05a30.cpp39
-rw-r--r--src/devices/machine/e05a30.h27
-rw-r--r--src/devices/machine/edlc.cpp21
-rw-r--r--src/devices/machine/edlc.h9
-rw-r--r--src/devices/machine/eeprom.cpp56
-rw-r--r--src/devices/machine/eeprom.h14
-rw-r--r--src/devices/machine/eeprompar.cpp4
-rw-r--r--src/devices/machine/eeprompar.h2
-rw-r--r--src/devices/machine/eepromser.cpp114
-rw-r--r--src/devices/machine/eepromser.h26
-rw-r--r--src/devices/machine/em_reel.cpp125
-rw-r--r--src/devices/machine/em_reel.h89
-rw-r--r--src/devices/machine/er1400.cpp54
-rw-r--r--src/devices/machine/er1400.h19
-rw-r--r--src/devices/machine/er2055.cpp14
-rw-r--r--src/devices/machine/er2055.h6
-rw-r--r--src/devices/machine/exorterm.cpp61
-rw-r--r--src/devices/machine/exorterm.h40
-rw-r--r--src/devices/machine/f3853.cpp21
-rw-r--r--src/devices/machine/f3853.h8
-rw-r--r--src/devices/machine/f4702.cpp260
-rw-r--r--src/devices/machine/f4702.h75
-rw-r--r--src/devices/machine/fdc37c665gt.cpp453
-rw-r--r--src/devices/machine/fdc37c665gt.h121
-rw-r--r--src/devices/machine/fdc37c93x.cpp145
-rw-r--r--src/devices/machine/fdc37c93x.h98
-rw-r--r--src/devices/machine/fdc_pll.cpp15
-rw-r--r--src/devices/machine/fdc_pll.h6
-rw-r--r--src/devices/machine/fga002.cpp111
-rw-r--r--src/devices/machine/fga002.h24
-rw-r--r--src/devices/machine/fm_scsi.cpp436
-rw-r--r--src/devices/machine/fm_scsi.h73
-rw-r--r--src/devices/machine/gayle.cpp397
-rw-r--r--src/devices/machine/gayle.h117
-rw-r--r--src/devices/machine/gen_fifo.cpp72
-rw-r--r--src/devices/machine/gen_fifo.h4
-rw-r--r--src/devices/machine/gen_latch.cpp21
-rw-r--r--src/devices/machine/gen_latch.h16
-rw-r--r--src/devices/machine/generalplus_gpl16250soc.cpp208
-rw-r--r--src/devices/machine/generalplus_gpl16250soc.h76
-rw-r--r--src/devices/machine/generalplus_gpl16250soc_video.cpp35
-rw-r--r--src/devices/machine/generalplus_gpl16250soc_video.h7
-rw-r--r--src/devices/machine/generic_spi_flash.cpp199
-rw-r--r--src/devices/machine/generic_spi_flash.h83
-rw-r--r--src/devices/machine/genpc.cpp214
-rw-r--r--src/devices/machine/genpc.h82
-rw-r--r--src/devices/machine/gt64xxx.cpp320
-rw-r--r--src/devices/machine/gt64xxx.h10
-rw-r--r--src/devices/machine/gt913_io.cpp155
-rw-r--r--src/devices/machine/gt913_io.h73
-rw-r--r--src/devices/machine/gt913_kbd.cpp104
-rw-r--r--src/devices/machine/gt913_kbd.h56
-rw-r--r--src/devices/machine/gt913_snd.cpp384
-rw-r--r--src/devices/machine/gt913_snd.h88
-rw-r--r--src/devices/machine/hd63450.cpp143
-rw-r--r--src/devices/machine/hd63450.h26
-rw-r--r--src/devices/machine/hd64610.cpp60
-rw-r--r--src/devices/machine/hd64610.h9
-rw-r--r--src/devices/machine/hdc92x4.cpp354
-rw-r--r--src/devices/machine/hdc92x4.h37
-rw-r--r--src/devices/machine/hp_dc100_tape.cpp345
-rw-r--r--src/devices/machine/hp_dc100_tape.h31
-rw-r--r--src/devices/machine/hp_taco.cpp300
-rw-r--r--src/devices/machine/hp_taco.h25
-rw-r--r--src/devices/machine/i2cmem.cpp297
-rw-r--r--src/devices/machine/i2cmem.h44
-rw-r--r--src/devices/machine/i3001.cpp2
-rw-r--r--src/devices/machine/i3001.h30
-rw-r--r--src/devices/machine/i3002.cpp4
-rw-r--r--src/devices/machine/i3002.h34
-rw-r--r--src/devices/machine/i7220.cpp297
-rw-r--r--src/devices/machine/i7220.h51
-rw-r--r--src/devices/machine/i80130.cpp27
-rw-r--r--src/devices/machine/i80130.h24
-rw-r--r--src/devices/machine/i8087.cpp52
-rw-r--r--src/devices/machine/i8087.h7
-rw-r--r--src/devices/machine/i8155.cpp55
-rw-r--r--src/devices/machine/i8212.cpp12
-rw-r--r--src/devices/machine/i8212.h2
-rw-r--r--src/devices/machine/i8214.cpp21
-rw-r--r--src/devices/machine/i8214.h4
-rw-r--r--src/devices/machine/i82355.cpp13
-rw-r--r--src/devices/machine/i82355.h3
-rw-r--r--src/devices/machine/i82357.cpp16
-rw-r--r--src/devices/machine/i82357.h10
-rw-r--r--src/devices/machine/i82371eb_acpi.cpp194
-rw-r--r--src/devices/machine/i82371eb_acpi.h63
-rw-r--r--src/devices/machine/i82371eb_ide.cpp37
-rw-r--r--src/devices/machine/i82371eb_ide.h26
-rw-r--r--src/devices/machine/i82371eb_isa.cpp49
-rw-r--r--src/devices/machine/i82371eb_isa.h29
-rw-r--r--src/devices/machine/i82371eb_usb.cpp96
-rw-r--r--src/devices/machine/i82371eb_usb.h37
-rw-r--r--src/devices/machine/i82371sb.cpp371
-rw-r--r--src/devices/machine/i82371sb.h151
-rw-r--r--src/devices/machine/i8243.cpp13
-rw-r--r--src/devices/machine/i8243.h4
-rw-r--r--src/devices/machine/i82439hx.cpp108
-rw-r--r--src/devices/machine/i82439hx.h17
-rw-r--r--src/devices/machine/i82439tx.cpp3
-rw-r--r--src/devices/machine/i82443bx_host.cpp193
-rw-r--r--src/devices/machine/i82443bx_host.h105
-rw-r--r--src/devices/machine/i8251.cpp41
-rw-r--r--src/devices/machine/i8251.h25
-rw-r--r--src/devices/machine/i8255.cpp37
-rw-r--r--src/devices/machine/i8255.h11
-rw-r--r--src/devices/machine/i8257.cpp24
-rw-r--r--src/devices/machine/i82586.cpp357
-rw-r--r--src/devices/machine/i82586.h11
-rw-r--r--src/devices/machine/i8271.cpp126
-rw-r--r--src/devices/machine/i8271.h8
-rw-r--r--src/devices/machine/i8279.cpp69
-rw-r--r--src/devices/machine/i8279.h5
-rw-r--r--src/devices/machine/i82875p.cpp3
-rw-r--r--src/devices/machine/i8291a.cpp149
-rw-r--r--src/devices/machine/i8355.cpp20
-rw-r--r--src/devices/machine/ibm21s850.cpp31
-rw-r--r--src/devices/machine/ibm21s850.h5
-rw-r--r--src/devices/machine/icd2061a.cpp323
-rw-r--r--src/devices/machine/icd2061a.h105
-rw-r--r--src/devices/machine/icm7170.cpp26
-rw-r--r--src/devices/machine/icm7170.h7
-rw-r--r--src/devices/machine/idectrl.h3
-rw-r--r--src/devices/machine/ie15.cpp58
-rw-r--r--src/devices/machine/ie15.h60
-rw-r--r--src/devices/machine/ie15_kbd.cpp13
-rw-r--r--src/devices/machine/ie15_kbd.h5
-rw-r--r--src/devices/machine/im6402.cpp27
-rw-r--r--src/devices/machine/im6402.h3
-rw-r--r--src/devices/machine/input_merger.cpp38
-rw-r--r--src/devices/machine/input_merger.h14
-rw-r--r--src/devices/machine/ins8154.cpp23
-rw-r--r--src/devices/machine/ins8250.cpp83
-rw-r--r--src/devices/machine/ins8250.h16
-rw-r--r--src/devices/machine/intelfsh.cpp615
-rw-r--r--src/devices/machine/intelfsh.h247
-rw-r--r--src/devices/machine/iopdma.cpp6
-rw-r--r--src/devices/machine/iopsio2.cpp2
-rw-r--r--src/devices/machine/ioptimer.cpp13
-rw-r--r--src/devices/machine/it8705f.cpp593
-rw-r--r--src/devices/machine/it8705f.h131
-rw-r--r--src/devices/machine/iwm.cpp277
-rw-r--r--src/devices/machine/iwm.h23
-rw-r--r--src/devices/machine/jvsdev.cpp10
-rw-r--r--src/devices/machine/jvsdev.h2
-rw-r--r--src/devices/machine/jvshost.cpp10
-rw-r--r--src/devices/machine/k033906.cpp12
-rw-r--r--src/devices/machine/k033906.h7
-rw-r--r--src/devices/machine/k053252.cpp28
-rw-r--r--src/devices/machine/k056230.cpp118
-rw-r--r--src/devices/machine/k056230.h32
-rw-r--r--src/devices/machine/kb3600.cpp43
-rw-r--r--src/devices/machine/kb3600.h3
-rw-r--r--src/devices/machine/keyboard.cpp7
-rw-r--r--src/devices/machine/keyboard.ipp6
-rw-r--r--src/devices/machine/keytronic_l2207.cpp311
-rw-r--r--src/devices/machine/keytronic_l2207.h75
-rw-r--r--src/devices/machine/kr1601rr1.cpp154
-rw-r--r--src/devices/machine/kr1601rr1.h77
-rw-r--r--src/devices/machine/kr2376.cpp152
-rw-r--r--src/devices/machine/kr2376.h25
-rw-r--r--src/devices/machine/laserdsc.cpp296
-rw-r--r--src/devices/machine/laserdsc.h73
-rw-r--r--src/devices/machine/latch8.cpp70
-rw-r--r--src/devices/machine/latch8.h104
-rw-r--r--src/devices/machine/ldp1000.cpp2
-rw-r--r--src/devices/machine/ldp1450.cpp2
-rw-r--r--src/devices/machine/ldpr8210.cpp233
-rw-r--r--src/devices/machine/ldpr8210.h34
-rw-r--r--src/devices/machine/ldstub.cpp4
-rw-r--r--src/devices/machine/ldstub.h16
-rw-r--r--src/devices/machine/ldv1000.cpp181
-rw-r--r--src/devices/machine/ldv1000.h45
-rw-r--r--src/devices/machine/ldv1000hle.cpp1046
-rw-r--r--src/devices/machine/ldv1000hle.h201
-rw-r--r--src/devices/machine/ldv4200hle.cpp979
-rw-r--r--src/devices/machine/ldv4200hle.h212
-rw-r--r--src/devices/machine/ldvp931.cpp243
-rw-r--r--src/devices/machine/ldvp931.h38
-rw-r--r--src/devices/machine/legscsi.cpp8
-rw-r--r--src/devices/machine/lh5810.cpp12
-rw-r--r--src/devices/machine/linflash.cpp5
-rw-r--r--src/devices/machine/linflash.h1
-rw-r--r--src/devices/machine/locomo.cpp376
-rw-r--r--src/devices/machine/locomo.h34
-rw-r--r--src/devices/machine/lpci.cpp13
-rw-r--r--src/devices/machine/lpci.h5
-rw-r--r--src/devices/machine/m3002.cpp26
-rw-r--r--src/devices/machine/m3002.h15
-rw-r--r--src/devices/machine/m68sfdc.cpp74
-rw-r--r--src/devices/machine/m68sfdc.h29
-rw-r--r--src/devices/machine/m6m80011ap.cpp23
-rw-r--r--src/devices/machine/m6m80011ap.h14
-rw-r--r--src/devices/machine/m950x0.cpp207
-rw-r--r--src/devices/machine/m950x0.h97
-rw-r--r--src/devices/machine/mb14241.cpp2
-rw-r--r--src/devices/machine/mb3773.cpp6
-rw-r--r--src/devices/machine/mb3773.h4
-rw-r--r--src/devices/machine/mb8421.cpp2
-rw-r--r--src/devices/machine/mb8421.h20
-rw-r--r--src/devices/machine/mb87030.cpp320
-rw-r--r--src/devices/machine/mb87030.h46
-rw-r--r--src/devices/machine/mb87078.cpp4
-rw-r--r--src/devices/machine/mb8795.cpp38
-rw-r--r--src/devices/machine/mb8795.h6
-rw-r--r--src/devices/machine/mb89352.cpp671
-rw-r--r--src/devices/machine/mb89352.h73
-rw-r--r--src/devices/machine/mb89363b.cpp48
-rw-r--r--src/devices/machine/mb89374.cpp4
-rw-r--r--src/devices/machine/mb89374.h2
-rw-r--r--src/devices/machine/mc14411.cpp105
-rw-r--r--src/devices/machine/mc14411.h60
-rw-r--r--src/devices/machine/mc146818.cpp325
-rw-r--r--src/devices/machine/mc146818.h65
-rw-r--r--src/devices/machine/mc68328.cpp6123
-rw-r--r--src/devices/machine/mc68328.h1397
-rw-r--r--src/devices/machine/mc6843.cpp1497
-rw-r--r--src/devices/machine/mc6843.h233
-rw-r--r--src/devices/machine/mc6844.cpp20
-rw-r--r--src/devices/machine/mc6844.h8
-rw-r--r--src/devices/machine/mc6846.cpp47
-rw-r--r--src/devices/machine/mc6852.cpp6
-rw-r--r--src/devices/machine/mc6852.h16
-rw-r--r--src/devices/machine/mc6854.cpp36
-rw-r--r--src/devices/machine/mc6854.h10
-rw-r--r--src/devices/machine/mc68681.cpp140
-rw-r--r--src/devices/machine/mc68681.h28
-rw-r--r--src/devices/machine/mc68901.cpp201
-rw-r--r--src/devices/machine/mc68901.h33
-rw-r--r--src/devices/machine/mc88200.cpp992
-rw-r--r--src/devices/machine/mc88200.h141
-rw-r--r--src/devices/machine/mccs1850.cpp65
-rw-r--r--src/devices/machine/mccs1850.h31
-rw-r--r--src/devices/machine/mcf5206e.cpp16
-rw-r--r--src/devices/machine/mcf5206e.h9
-rw-r--r--src/devices/machine/mdcr.cpp326
-rw-r--r--src/devices/machine/mdcr.h181
-rw-r--r--src/devices/machine/mediagx_cs5530_bridge.cpp561
-rw-r--r--src/devices/machine/mediagx_cs5530_bridge.h149
-rw-r--r--src/devices/machine/mediagx_cs5530_ide.cpp142
-rw-r--r--src/devices/machine/mediagx_cs5530_ide.h66
-rw-r--r--src/devices/machine/mediagx_cs5530_video.cpp55
-rw-r--r--src/devices/machine/mediagx_cs5530_video.h29
-rw-r--r--src/devices/machine/mediagx_host.cpp375
-rw-r--r--src/devices/machine/mediagx_host.h83
-rw-r--r--src/devices/machine/meters.cpp90
-rw-r--r--src/devices/machine/meters.h36
-rw-r--r--src/devices/machine/micomxe1a.cpp368
-rw-r--r--src/devices/machine/micomxe1a.h49
-rw-r--r--src/devices/machine/microtch.cpp121
-rw-r--r--src/devices/machine/microtch.h23
-rw-r--r--src/devices/machine/mm5307.cpp15
-rw-r--r--src/devices/machine/mm5307.h3
-rw-r--r--src/devices/machine/mm5740.cpp86
-rw-r--r--src/devices/machine/mm5740.h48
-rw-r--r--src/devices/machine/mm58167.cpp36
-rw-r--r--src/devices/machine/mm58167.h3
-rw-r--r--src/devices/machine/mm58174.cpp40
-rw-r--r--src/devices/machine/mm58174.h7
-rw-r--r--src/devices/machine/mm58274c.cpp60
-rw-r--r--src/devices/machine/mm58274c.h10
-rw-r--r--src/devices/machine/mm74c922.cpp13
-rw-r--r--src/devices/machine/mm74c922.h5
-rw-r--r--src/devices/machine/mos6526.cpp110
-rw-r--r--src/devices/machine/mos6526.h49
-rw-r--r--src/devices/machine/mos6529.cpp2
-rw-r--r--src/devices/machine/mos6530.cpp729
-rw-r--r--src/devices/machine/mos6530.h190
-rw-r--r--src/devices/machine/mos6530n.cpp811
-rw-r--r--src/devices/machine/mos6530n.h235
-rw-r--r--src/devices/machine/mos6551.cpp25
-rw-r--r--src/devices/machine/mos6551.h18
-rw-r--r--src/devices/machine/mos8722.cpp14
-rw-r--r--src/devices/machine/mos8722.h2
-rw-r--r--src/devices/machine/mos8726.cpp2
-rw-r--r--src/devices/machine/mos8726.h2
-rw-r--r--src/devices/machine/mpc106.cpp384
-rw-r--r--src/devices/machine/mpc106.h99
-rw-r--r--src/devices/machine/mpu401.cpp20
-rw-r--r--src/devices/machine/mpu401.h3
-rw-r--r--src/devices/machine/msm5001n.cpp199
-rw-r--r--src/devices/machine/msm5001n.h65
-rw-r--r--src/devices/machine/msm5832.cpp27
-rw-r--r--src/devices/machine/msm5832.h17
-rw-r--r--src/devices/machine/msm58321.cpp120
-rw-r--r--src/devices/machine/msm58321.h35
-rw-r--r--src/devices/machine/msm6200.cpp99
-rw-r--r--src/devices/machine/msm6200.h40
-rw-r--r--src/devices/machine/msm6242.cpp56
-rw-r--r--src/devices/machine/msm6242.h5
-rw-r--r--src/devices/machine/msm6253.cpp2
-rw-r--r--src/devices/machine/mv6436x.cpp1230
-rw-r--r--src/devices/machine/mv6436x.h282
-rw-r--r--src/devices/machine/mv_sonora.cpp343
-rw-r--r--src/devices/machine/mv_sonora.h72
-rw-r--r--src/devices/machine/myb3k_kbd.cpp54
-rw-r--r--src/devices/machine/myb3k_kbd.h19
-rw-r--r--src/devices/machine/nandflash.cpp637
-rw-r--r--src/devices/machine/nandflash.h162
-rw-r--r--src/devices/machine/ncr5380.cpp918
-rw-r--r--src/devices/machine/ncr5380.h210
-rw-r--r--src/devices/machine/ncr5380n.cpp666
-rw-r--r--src/devices/machine/ncr5380n.h186
-rw-r--r--src/devices/machine/ncr5385.cpp895
-rw-r--r--src/devices/machine/ncr5385.h145
-rw-r--r--src/devices/machine/ncr539x.cpp776
-rw-r--r--src/devices/machine/ncr539x.h83
-rw-r--r--src/devices/machine/ncr53c90.cpp (renamed from src/devices/machine/ncr5390.cpp)463
-rw-r--r--src/devices/machine/ncr53c90.h (renamed from src/devices/machine/ncr5390.h)79
-rw-r--r--src/devices/machine/netlist.cpp202
-rw-r--r--src/devices/machine/netlist.h98
-rw-r--r--src/devices/machine/nmc9306.cpp165
-rw-r--r--src/devices/machine/nmc9306.h28
-rw-r--r--src/devices/machine/nmk112.cpp103
-rw-r--r--src/devices/machine/nmk112.h53
-rw-r--r--src/devices/machine/ns32081.cpp891
-rw-r--r--src/devices/machine/ns32081.h114
-rw-r--r--src/devices/machine/ns32082.cpp497
-rw-r--r--src/devices/machine/ns32082.h69
-rw-r--r--src/devices/machine/ns32202.cpp487
-rw-r--r--src/devices/machine/ns32202.h86
-rw-r--r--src/devices/machine/ns32382.cpp429
-rw-r--r--src/devices/machine/ns32382.h66
-rw-r--r--src/devices/machine/nsc810.cpp230
-rw-r--r--src/devices/machine/nsc810.h35
-rw-r--r--src/devices/machine/nscsi_bus.cpp267
-rw-r--r--src/devices/machine/nscsi_bus.h447
-rw-r--r--src/devices/machine/nscsi_cb.cpp35
-rw-r--r--src/devices/machine/nvram.cpp50
-rw-r--r--src/devices/machine/nvram.h15
-rw-r--r--src/devices/machine/output_latch.cpp8
-rw-r--r--src/devices/machine/output_latch.h1
-rw-r--r--src/devices/machine/pc87306.cpp491
-rw-r--r--src/devices/machine/pc87306.h123
-rw-r--r--src/devices/machine/pc_fdc.cpp12
-rw-r--r--src/devices/machine/pc_lpt.cpp2
-rw-r--r--src/devices/machine/pccard.cpp66
-rw-r--r--src/devices/machine/pccard.h34
-rw-r--r--src/devices/machine/pccard_sram.cpp390
-rw-r--r--src/devices/machine/pccard_sram.h166
-rw-r--r--src/devices/machine/pcf8573.cpp356
-rw-r--r--src/devices/machine/pcf8573.h127
-rw-r--r--src/devices/machine/pcf8583.cpp437
-rw-r--r--src/devices/machine/pcf8583.h77
-rw-r--r--src/devices/machine/pcf8584.cpp17
-rw-r--r--src/devices/machine/pcf8584.h3
-rw-r--r--src/devices/machine/pcf8593.cpp66
-rw-r--r--src/devices/machine/pcf8593.h15
-rw-r--r--src/devices/machine/pci-ide.cpp11
-rw-r--r--src/devices/machine/pci-ide.h12
-rw-r--r--src/devices/machine/pci-smbus.h3
-rw-r--r--src/devices/machine/pci.cpp127
-rw-r--r--src/devices/machine/pci.h45
-rw-r--r--src/devices/machine/pci9050.cpp8
-rw-r--r--src/devices/machine/pckeybrd.cpp40
-rw-r--r--src/devices/machine/pckeybrd.h4
-rw-r--r--src/devices/machine/pdc.cpp16
-rw-r--r--src/devices/machine/pdc.h2
-rw-r--r--src/devices/machine/phi.cpp269
-rw-r--r--src/devices/machine/phi.h53
-rw-r--r--src/devices/machine/pic8259.cpp59
-rw-r--r--src/devices/machine/pic8259.h37
-rw-r--r--src/devices/machine/pit8253.cpp50
-rw-r--r--src/devices/machine/pit8253.h36
-rw-r--r--src/devices/machine/pla.cpp14
-rw-r--r--src/devices/machine/ps2timer.cpp4
-rw-r--r--src/devices/machine/psion_asic1.cpp484
-rw-r--r--src/devices/machine/psion_asic1.h100
-rw-r--r--src/devices/machine/psion_asic2.cpp448
-rw-r--r--src/devices/machine/psion_asic2.h100
-rw-r--r--src/devices/machine/psion_asic3.cpp302
-rw-r--r--src/devices/machine/psion_asic3.h79
-rw-r--r--src/devices/machine/psion_asic4.cpp170
-rw-r--r--src/devices/machine/psion_asic4.h59
-rw-r--r--src/devices/machine/psion_asic5.cpp458
-rw-r--r--src/devices/machine/psion_asic5.h121
-rw-r--r--src/devices/machine/psion_asic9.cpp1202
-rw-r--r--src/devices/machine/psion_asic9.h179
-rw-r--r--src/devices/machine/psion_condor.cpp278
-rw-r--r--src/devices/machine/psion_condor.h75
-rw-r--r--src/devices/machine/psion_ssd.cpp292
-rw-r--r--src/devices/machine/psion_ssd.h82
-rw-r--r--src/devices/machine/pxa255.cpp2608
-rw-r--r--src/devices/machine/pxa255.h555
-rw-r--r--src/devices/machine/pxa255defs.h426
-rw-r--r--src/devices/machine/r10696.cpp7
-rw-r--r--src/devices/machine/r10788.cpp49
-rw-r--r--src/devices/machine/r10788.h5
-rw-r--r--src/devices/machine/ra17xx.cpp9
-rw-r--r--src/devices/machine/ram.cpp17
-rw-r--r--src/devices/machine/ram.h4
-rw-r--r--src/devices/machine/rf5c296.cpp4
-rw-r--r--src/devices/machine/rf5c296.h4
-rw-r--r--src/devices/machine/ripple_counter.cpp64
-rw-r--r--src/devices/machine/ripple_counter.h18
-rw-r--r--src/devices/machine/roc10937.cpp76
-rw-r--r--src/devices/machine/roc10937.h10
-rw-r--r--src/devices/machine/rp5c01.cpp74
-rw-r--r--src/devices/machine/rp5c01.h28
-rw-r--r--src/devices/machine/rp5c15.cpp65
-rw-r--r--src/devices/machine/rp5c15.h14
-rw-r--r--src/devices/machine/rp5h01.cpp16
-rw-r--r--src/devices/machine/rp5h01.h14
-rw-r--r--src/devices/machine/rstbuf.cpp14
-rw-r--r--src/devices/machine/rstbuf.h15
-rw-r--r--src/devices/machine/rtc4543.cpp22
-rw-r--r--src/devices/machine/rtc4543.h13
-rw-r--r--src/devices/machine/rtc65271.cpp211
-rw-r--r--src/devices/machine/rtc65271.h22
-rw-r--r--src/devices/machine/rtc9701.cpp50
-rw-r--r--src/devices/machine/rtc9701.h22
-rw-r--r--src/devices/machine/s2350.cpp414
-rw-r--r--src/devices/machine/s2350.h119
-rw-r--r--src/devices/machine/s2636.cpp4
-rw-r--r--src/devices/machine/s3520cf.cpp48
-rw-r--r--src/devices/machine/s3520cf.h24
-rw-r--r--src/devices/machine/s3c2400.cpp10
-rw-r--r--src/devices/machine/s3c2410.cpp14
-rw-r--r--src/devices/machine/s3c2410.h4
-rw-r--r--src/devices/machine/s3c2440.cpp14
-rw-r--r--src/devices/machine/s3c2440.h4
-rw-r--r--src/devices/machine/s3c24xx.hxx123
-rw-r--r--src/devices/machine/s3c44b0.cpp78
-rw-r--r--src/devices/machine/s_smp.cpp14
-rw-r--r--src/devices/machine/s_smp.h7
-rw-r--r--src/devices/machine/sa1110.cpp3107
-rw-r--r--src/devices/machine/sa1110.h897
-rw-r--r--src/devices/machine/sa1111.cpp2194
-rw-r--r--src/devices/machine/sa1111.h689
-rw-r--r--src/devices/machine/saa1043.cpp45
-rw-r--r--src/devices/machine/saa1043.h76
-rw-r--r--src/devices/machine/saa5070.cpp350
-rw-r--r--src/devices/machine/saa5070.h151
-rw-r--r--src/devices/machine/saa7191.cpp214
-rw-r--r--src/devices/machine/saa7191.h172
-rw-r--r--src/devices/machine/scc2698b.cpp31
-rw-r--r--src/devices/machine/scc2698b.h1
-rw-r--r--src/devices/machine/scc66470.cpp890
-rw-r--r--src/devices/machine/scc66470.h115
-rw-r--r--src/devices/machine/scc68070.cpp764
-rw-r--r--src/devices/machine/scc68070.h165
-rw-r--r--src/devices/machine/scn_pci.cpp55
-rw-r--r--src/devices/machine/scn_pci.h26
-rw-r--r--src/devices/machine/scnxx562.cpp298
-rw-r--r--src/devices/machine/scnxx562.h14
-rw-r--r--src/devices/machine/scoop.cpp176
-rw-r--r--src/devices/machine/scoop.h42
-rw-r--r--src/devices/machine/sda2006.cpp20
-rw-r--r--src/devices/machine/sda2006.h12
-rw-r--r--src/devices/machine/sdlc.cpp3
-rw-r--r--src/devices/machine/sdlc.h8
-rw-r--r--src/devices/machine/sega_scu.cpp54
-rw-r--r--src/devices/machine/sega_scu.h23
-rw-r--r--src/devices/machine/segacrp2_device.cpp451
-rw-r--r--src/devices/machine/segacrp2_device.h126
-rw-r--r--src/devices/machine/segacrpt_device.cpp1068
-rw-r--r--src/devices/machine/segacrpt_device.h294
-rw-r--r--src/devices/machine/sensorboard.cpp108
-rw-r--r--src/devices/machine/sensorboard.h40
-rw-r--r--src/devices/machine/serflash.cpp473
-rw-r--r--src/devices/machine/serflash.h91
-rw-r--r--src/devices/machine/sis5513_ide.cpp363
-rw-r--r--src/devices/machine/sis5513_ide.h90
-rw-r--r--src/devices/machine/sis630_gui.cpp327
-rw-r--r--src/devices/machine/sis630_gui.h98
-rw-r--r--src/devices/machine/sis630_host.cpp440
-rw-r--r--src/devices/machine/sis630_host.h98
-rw-r--r--src/devices/machine/sis7001_usb.cpp93
-rw-r--r--src/devices/machine/sis7001_usb.h50
-rw-r--r--src/devices/machine/sis7018_audio.cpp163
-rw-r--r--src/devices/machine/sis7018_audio.h54
-rw-r--r--src/devices/machine/sis85c496.cpp320
-rw-r--r--src/devices/machine/sis85c496.h92
-rw-r--r--src/devices/machine/sis900_eth.cpp161
-rw-r--r--src/devices/machine/sis900_eth.h53
-rw-r--r--src/devices/machine/sis950_lpc.cpp786
-rw-r--r--src/devices/machine/sis950_lpc.h189
-rw-r--r--src/devices/machine/sis950_smbus.cpp108
-rw-r--r--src/devices/machine/sis950_smbus.h32
-rw-r--r--src/devices/machine/smartboard.cpp336
-rw-r--r--src/devices/machine/smartboard.h63
-rw-r--r--src/devices/machine/smartmed.cpp598
-rw-r--r--src/devices/machine/smartmed.h203
-rw-r--r--src/devices/machine/smc91c9x.cpp105
-rw-r--r--src/devices/machine/smc91c9x.h38
-rw-r--r--src/devices/machine/smioc.cpp34
-rw-r--r--src/devices/machine/smioc.h4
-rw-r--r--src/devices/machine/smpc.cpp277
-rw-r--r--src/devices/machine/smpc.h22
-rw-r--r--src/devices/machine/sonydriv.cpp628
-rw-r--r--src/devices/machine/sonydriv.h66
-rw-r--r--src/devices/machine/spg110.cpp31
-rw-r--r--src/devices/machine/spg110.h11
-rw-r--r--src/devices/machine/spg110_video.cpp204
-rw-r--r--src/devices/machine/spg110_video.h8
-rw-r--r--src/devices/machine/spg290_cdservo.cpp69
-rw-r--r--src/devices/machine/spg290_cdservo.h7
-rw-r--r--src/devices/machine/spg290_i2c.cpp9
-rw-r--r--src/devices/machine/spg290_i2c.h2
-rw-r--r--src/devices/machine/spg290_ppu.cpp11
-rw-r--r--src/devices/machine/spg290_timer.cpp6
-rw-r--r--src/devices/machine/spg290_timer.h2
-rw-r--r--src/devices/machine/spg2xx.cpp45
-rw-r--r--src/devices/machine/spg2xx.h22
-rw-r--r--src/devices/machine/spg2xx_audio.cpp52
-rw-r--r--src/devices/machine/spg2xx_audio.h7
-rw-r--r--src/devices/machine/spg2xx_io.cpp367
-rw-r--r--src/devices/machine/spg2xx_io.h58
-rw-r--r--src/devices/machine/spg2xx_sysdma.cpp2
-rw-r--r--src/devices/machine/spg2xx_video.cpp53
-rw-r--r--src/devices/machine/spg2xx_video.h33
-rw-r--r--src/devices/machine/spg_renderer.cpp16
-rw-r--r--src/devices/machine/spg_renderer.h4
-rw-r--r--src/devices/machine/spi_sdcard.cpp458
-rw-r--r--src/devices/machine/spi_sdcard.h96
-rw-r--r--src/devices/machine/spifi3.cpp1878
-rw-r--r--src/devices/machine/spifi3.h304
-rw-r--r--src/devices/machine/steppers.cpp55
-rw-r--r--src/devices/machine/steppers.h7
-rw-r--r--src/devices/machine/strata.cpp13
-rw-r--r--src/devices/machine/strata.h4
-rw-r--r--src/devices/machine/stvcd.cpp434
-rw-r--r--src/devices/machine/stvcd.h8
-rw-r--r--src/devices/machine/sun4c_mmu.cpp796
-rw-r--r--src/devices/machine/sun4c_mmu.h73
-rw-r--r--src/devices/machine/swim1.cpp1203
-rw-r--r--src/devices/machine/swim1.h101
-rw-r--r--src/devices/machine/swim2.cpp498
-rw-r--r--src/devices/machine/swim2.h32
-rw-r--r--src/devices/machine/swim3.cpp695
-rw-r--r--src/devices/machine/swim3.h84
-rw-r--r--src/devices/machine/swtpc8212.cpp50
-rw-r--r--src/devices/machine/swtpc8212.h10
-rw-r--r--src/devices/machine/t10mmc.cpp923
-rw-r--r--src/devices/machine/t10mmc.h36
-rw-r--r--src/devices/machine/t10sbc.cpp80
-rw-r--r--src/devices/machine/t10sbc.h5
-rw-r--r--src/devices/machine/t10spc.cpp11
-rw-r--r--src/devices/machine/t10spc.h4
-rw-r--r--src/devices/machine/tc009xlvc.cpp137
-rw-r--r--src/devices/machine/tc009xlvc.h30
-rw-r--r--src/devices/machine/tc9223.cpp75
-rw-r--r--src/devices/machine/tc9223.h30
-rw-r--r--src/devices/machine/tdc1008.cpp27
-rw-r--r--src/devices/machine/tdc1008.h22
-rw-r--r--src/devices/machine/te7750.cpp23
-rw-r--r--src/devices/machine/te7750.h9
-rw-r--r--src/devices/machine/terminal.cpp16
-rw-r--r--src/devices/machine/terminal.h7
-rw-r--r--src/devices/machine/ticket.cpp33
-rw-r--r--src/devices/machine/ticket.h17
-rw-r--r--src/devices/machine/timekpr.cpp74
-rw-r--r--src/devices/machine/timekpr.h28
-rw-r--r--src/devices/machine/timer.cpp92
-rw-r--r--src/devices/machine/timer.h25
-rw-r--r--src/devices/machine/tmc0430.cpp21
-rw-r--r--src/devices/machine/tmc0430.h8
-rw-r--r--src/devices/machine/tmc0999.cpp97
-rw-r--r--src/devices/machine/tmc0999.h57
-rw-r--r--src/devices/machine/tmc208k.cpp4
-rw-r--r--src/devices/machine/tmp68301.cpp380
-rw-r--r--src/devices/machine/tmp68301.h100
-rw-r--r--src/devices/machine/tms1024.cpp23
-rw-r--r--src/devices/machine/tms5501.cpp52
-rw-r--r--src/devices/machine/tms5501.h3
-rw-r--r--src/devices/machine/tms9901.cpp100
-rw-r--r--src/devices/machine/tms9901.h13
-rw-r--r--src/devices/machine/tms9902.cpp71
-rw-r--r--src/devices/machine/tms9902.h7
-rw-r--r--src/devices/machine/tms9914.cpp155
-rw-r--r--src/devices/machine/tms9914.h27
-rw-r--r--src/devices/machine/tsb12lv01a.cpp16
-rw-r--r--src/devices/machine/tsb12lv01a.h2
-rw-r--r--src/devices/machine/tube.cpp30
-rw-r--r--src/devices/machine/tube.h3
-rw-r--r--src/devices/machine/ucb1200.cpp370
-rw-r--r--src/devices/machine/ucb1200.h147
-rw-r--r--src/devices/machine/upc82c710.cpp411
-rw-r--r--src/devices/machine/upc82c710.h109
-rw-r--r--src/devices/machine/upc82c711.cpp466
-rw-r--r--src/devices/machine/upc82c711.h127
-rw-r--r--src/devices/machine/upd1990a.cpp110
-rw-r--r--src/devices/machine/upd1990a.h34
-rw-r--r--src/devices/machine/upd4701.cpp64
-rw-r--r--src/devices/machine/upd4701.h31
-rw-r--r--src/devices/machine/upd4991a.cpp135
-rw-r--r--src/devices/machine/upd4991a.h52
-rw-r--r--src/devices/machine/upd4992.cpp14
-rw-r--r--src/devices/machine/upd4992.h11
-rw-r--r--src/devices/machine/upd7001.cpp24
-rw-r--r--src/devices/machine/upd7001.h17
-rw-r--r--src/devices/machine/upd7002.cpp53
-rw-r--r--src/devices/machine/upd7002.h10
-rw-r--r--src/devices/machine/upd7004.cpp13
-rw-r--r--src/devices/machine/upd7004.h3
-rw-r--r--src/devices/machine/upd71071.cpp26
-rw-r--r--src/devices/machine/upd7261.cpp733
-rw-r--r--src/devices/machine/upd7261.h104
-rw-r--r--src/devices/machine/upd765.cpp448
-rw-r--r--src/devices/machine/upd765.h76
-rw-r--r--src/devices/machine/v3021.cpp10
-rw-r--r--src/devices/machine/v3021.h6
-rw-r--r--src/devices/machine/vic_pl192.cpp424
-rw-r--r--src/devices/machine/vic_pl192.h105
-rw-r--r--src/devices/machine/vrc4373.cpp12
-rw-r--r--src/devices/machine/vrc4373.h4
-rw-r--r--src/devices/machine/vrc5074.cpp168
-rw-r--r--src/devices/machine/vrc5074.h14
-rw-r--r--src/devices/machine/vrender0.cpp66
-rw-r--r--src/devices/machine/vrender0.h23
-rw-r--r--src/devices/machine/vt8231_isa.cpp226
-rw-r--r--src/devices/machine/vt8231_isa.h84
-rw-r--r--src/devices/machine/w83787f.cpp345
-rw-r--r--src/devices/machine/w83787f.h95
-rw-r--r--src/devices/machine/w83977tf.cpp535
-rw-r--r--src/devices/machine/w83977tf.h120
-rw-r--r--src/devices/machine/watchdog.cpp81
-rw-r--r--src/devices/machine/watchdog.h11
-rw-r--r--src/devices/machine/wd1000.cpp110
-rw-r--r--src/devices/machine/wd1000.h10
-rw-r--r--src/devices/machine/wd1010.cpp133
-rw-r--r--src/devices/machine/wd1010.h20
-rw-r--r--src/devices/machine/wd11c00_17.cpp20
-rw-r--r--src/devices/machine/wd2010.cpp163
-rw-r--r--src/devices/machine/wd2010.h13
-rw-r--r--src/devices/machine/wd33c9x.cpp28
-rw-r--r--src/devices/machine/wd33c9x.h5
-rw-r--r--src/devices/machine/wd7600.cpp46
-rw-r--r--src/devices/machine/wd7600.h76
-rw-r--r--src/devices/machine/wd_fdc.cpp533
-rw-r--r--src/devices/machine/wd_fdc.h43
-rw-r--r--src/devices/machine/wozfdc.cpp15
-rw-r--r--src/devices/machine/wozfdc.h5
-rw-r--r--src/devices/machine/wtl3132.cpp10
-rw-r--r--src/devices/machine/x2201.cpp19
-rw-r--r--src/devices/machine/x2201.h10
-rw-r--r--src/devices/machine/x2212.cpp13
-rw-r--r--src/devices/machine/x2212.h4
-rw-r--r--src/devices/machine/x76f041.cpp370
-rw-r--r--src/devices/machine/x76f041.h70
-rw-r--r--src/devices/machine/x76f100.cpp201
-rw-r--r--src/devices/machine/x76f100.h33
-rw-r--r--src/devices/machine/xc1700e.cpp4
-rw-r--r--src/devices/machine/ym2148.cpp13
-rw-r--r--src/devices/machine/ym2148.h5
-rw-r--r--src/devices/machine/ym3802.cpp32
-rw-r--r--src/devices/machine/ym3802.h20
-rw-r--r--src/devices/machine/z8038.cpp18
-rw-r--r--src/devices/machine/z8038.h6
-rw-r--r--src/devices/machine/z80ctc.cpp48
-rw-r--r--src/devices/machine/z80ctc.h33
-rw-r--r--src/devices/machine/z80daisy_generic.cpp7
-rw-r--r--src/devices/machine/z80daisy_generic.h4
-rw-r--r--src/devices/machine/z80dma.cpp135
-rw-r--r--src/devices/machine/z80dma.h78
-rw-r--r--src/devices/machine/z80pio.cpp40
-rw-r--r--src/devices/machine/z80pio.h56
-rw-r--r--src/devices/machine/z80scc.cpp591
-rw-r--r--src/devices/machine/z80scc.h47
-rw-r--r--src/devices/machine/z80sio.cpp67
-rw-r--r--src/devices/machine/z80sio.h55
-rw-r--r--src/devices/machine/z80sti.cpp78
-rw-r--r--src/devices/machine/z80sti.h25
-rw-r--r--src/devices/machine/z8536.cpp83
-rw-r--r--src/devices/machine/z8536.h79
-rw-r--r--src/devices/machine/zfmicro_usb.cpp100
-rw-r--r--src/devices/machine/zfmicro_usb.h39
944 files changed, 96430 insertions, 35220 deletions
diff --git a/src/devices/machine/1801vp128.cpp b/src/devices/machine/1801vp128.cpp
new file mode 100644
index 00000000000..de63cbe0dd7
--- /dev/null
+++ b/src/devices/machine/1801vp128.cpp
@@ -0,0 +1,813 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/**********************************************************************
+
+ 1801VP1-128 gate array (MFM codec for floppy controllers)
+
+ https://github.com/1801BM1/k1801/tree/master/128
+ https://felixl.com/UKNC_FDD_1801vp1-128
+ https://zx-pk.ru/threads/20406-emulyatsiya-1801vp1-128-v-plis.html
+
+ To do:
+ - DRQ status in read and write modes is tracked separately (TR bit)
+ - missing MFM clock is added by MFM encoder for every 00 sequence
+ - deep internals of CRC, GDR bits; read/write mode switching
+ - optional external timer for PY device
+
+**********************************************************************/
+
+#include "emu.h"
+#include "1801vp128.h"
+
+#define LOG_WARN (1U << 1) // Show warnings
+#define LOG_SHIFT (1U << 2) // Shows shift register contents
+#define LOG_REGS (1U << 6) // Register I/O
+#define LOG_STATE (1U << 11) // State machine
+#define LOG_LIVE (1U << 12) // Live states
+
+//#define VERBOSE (LOG_GENERAL | LOG_REGS | LOG_STATE)
+#include "logmacro.h"
+
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+#define LOGSHIFT(...) LOGMASKED(LOG_SHIFT, __VA_ARGS__)
+#define LOGREGS(...) LOGMASKED(LOG_REGS, __VA_ARGS__)
+#define LOGLIVE(...) LOGMASKED(LOG_LIVE, __VA_ARGS__)
+#define LOGSTATE(...) LOGMASKED(LOG_STATE, __VA_ARGS__)
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(K1801VP128, k1801vp128_device, "1801vp1_128", "1801VP1-128 FDC")
+
+
+
+inline k1801vp128_device::floppy_info::floppy_info()
+ : tm(nullptr)
+ , dev(nullptr)
+ , id(0)
+ , main_state(0)
+ , sub_state(0)
+ , dir(0)
+ , counter(0)
+ , live(false)
+ , index(false)
+{
+}
+
+
+inline k1801vp128_device::live_info::live_info()
+ : tm(attotime::never)
+ , state(IDLE)
+ , next_state(-1)
+ , fi(nullptr)
+ , shift_reg(0)
+ , crc(0)
+ , bit_counter(0)
+ , data_separator_phase(false)
+ , data_bit_context(false)
+ , crc_init(false)
+ , data_reg(0)
+ , pll()
+{
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// k1801vp128_device - constructor
+//-------------------------------------------------
+
+k1801vp128_device::k1801vp128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, K1801VP128, tag, owner, clock)
+ , m_connectors(*this, "%u", 0U)
+ , m_read_ds(*this, -1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void k1801vp128_device::device_start()
+{
+ for (int i = 0; i != 4; i++)
+ {
+ flopi[i].tm = timer_alloc(FUNC(k1801vp128_device::update_floppy), this);
+ flopi[i].id = i;
+ if (m_connectors[i])
+ {
+ flopi[i].dev = m_connectors[i]->get_device();
+ if (flopi[i].dev != nullptr)
+ flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&k1801vp128_device::index_callback, this));
+ }
+ else
+ flopi[i].dev = nullptr;
+
+ flopi[i].main_state = IDLE;
+ flopi[i].sub_state = IDLE;
+ flopi[i].live = false;
+ }
+
+ m_wbuf = m_rbuf = 0;
+
+ // register for state saving
+ save_item(NAME(selected_drive));
+ save_item(NAME(m_cr));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_rbuf));
+ save_item(NAME(m_wbuf));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void k1801vp128_device::device_reset()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ flopi[i].main_state = IDLE;
+ flopi[i].sub_state = IDLE;
+ flopi[i].live = false;
+ }
+ live_abort();
+ m_cr = m_sr = 0;
+ set_ds(-1);
+}
+
+//-------------------------------------------------
+// read - register read
+//-------------------------------------------------
+
+uint16_t k1801vp128_device::read(offs_t offset)
+{
+ uint16_t data = 0;
+
+ switch (offset & 1)
+ {
+ case 0:
+ data = m_sr;
+ if (selected_drive != -1)
+ {
+ floppy_info &fi = flopi[selected_drive];
+ data = (fi.dev->trk00_r() ^ 1) | (fi.dev->ready_r() << 1) | (fi.dev->wpt_r() << 2) | (fi.dev->idx_r() << 15) | m_sr;
+ }
+ break;
+
+ case 1:
+ data = m_rbuf;
+ if (!machine().side_effects_disabled())
+ {
+ m_sr &= ~CSR_R_TR;
+ if (selected_drive != -1)
+ {
+ floppy_info &fi = flopi[selected_drive];
+ if (fi.main_state == WRITE_DATA)
+ {
+ // semi-read mode
+ live_abort();
+ fi.main_state = READ_DATA;
+ fi.sub_state = SCAN_ID;
+ read_data_continue(fi);
+ }
+ }
+ }
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write - register write
+//-------------------------------------------------
+
+void k1801vp128_device::write(offs_t offset, uint16_t data)
+{
+ LOGREGS("%s W %06o <- %06o\n", machine().describe_context(), 0177130 + (offset << 1), data);
+
+ switch (offset & 1)
+ {
+ case 0:
+ set_ds((int16_t)m_read_ds(data & (CSR_W_DS | CSR_W_REZ)));
+ if (selected_drive != -1)
+ {
+ floppy_info &fi = flopi[selected_drive];
+ fi.dev->mon_w(!BIT(data, 4));
+ fi.dev->ss_w(BIT(data, 5));
+ if (BIT(data, 7))
+ {
+ LOG("COMMAND STEP %d %s\n", fi.id, BIT(data, 6) ? "+1" : "-1");
+ execute_command(CMD_SEEK);
+ }
+ if (BIT(m_cr ^ data, 8) && !BIT(data, 8))
+ {
+ LOG("COMMAND READ drive %d c:h %d:%d\n", selected_drive, fi.dev->get_cyl(), BIT(data, 5));
+ m_sr &= ~CSR_R_TR;
+ execute_command(CMD_READ);
+ }
+ }
+ m_cr = data;
+ break;
+
+ case 1:
+ m_wbuf = data;
+ m_sr &= ~CSR_R_TR;
+ if (selected_drive != -1)
+ {
+ floppy_info &fi = flopi[selected_drive];
+ if (fi.main_state != WRITE_DATA)
+ {
+ LOG("COMMAND WRITE drive %d c:h %d:%d\n", selected_drive, fi.dev->get_cyl(), BIT(m_cr, 5));
+ execute_command(CMD_WRITE);
+ }
+ }
+ break;
+ }
+}
+
+void k1801vp128_device::execute_command(int command)
+{
+ live_abort();
+
+ switch (command)
+ {
+ case CMD_READ:
+ read_data_start(flopi[selected_drive]);
+ break;
+
+ case CMD_WRITE:
+ write_data_start(flopi[selected_drive]);
+ break;
+
+ case CMD_SEEK:
+ seek_start(flopi[selected_drive]);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// update_tick - pump the device life cycle
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(k1801vp128_device::update_floppy)
+{
+ live_sync();
+
+ floppy_info &fi = flopi[param];
+ 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 k1801vp128_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.crc_init = false;
+ cur_live.bit_counter = 0;
+ cur_live.data_separator_phase = false;
+ cur_live.data_reg = 0;
+ cur_live.data_bit_context = false;
+ cur_live.pll.reset(cur_live.tm);
+ cur_live.pll.set_clock(attotime::from_hz(500000));
+ checkpoint_live = cur_live;
+ fi.live = true;
+
+ live_run();
+}
+
+void k1801vp128_device::checkpoint()
+{
+ if (cur_live.fi)
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ checkpoint_live = cur_live;
+}
+
+void k1801vp128_device::rollback()
+{
+ cur_live = checkpoint_live;
+}
+
+void k1801vp128_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(), cur_live.fi->id);
+ else
+ live_sync();
+}
+
+void k1801vp128_device::live_sync()
+{
+ if (!cur_live.tm.is_never())
+ {
+ if (cur_live.tm > machine().time())
+ {
+ rollback();
+ live_run(machine().time());
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ }
+ else
+ {
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ if (cur_live.next_state != -1)
+ {
+ cur_live.state = cur_live.next_state;
+ cur_live.next_state = -1;
+ }
+ if (cur_live.state == IDLE)
+ {
+ cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm);
+ cur_live.tm = attotime::never;
+ cur_live.fi->live = false;
+ cur_live.fi = nullptr;
+ }
+ }
+ cur_live.next_state = -1;
+ checkpoint();
+ }
+}
+
+void k1801vp128_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 = nullptr;
+ }
+
+ cur_live.tm = attotime::never;
+ cur_live.state = IDLE;
+ cur_live.next_state = -1;
+}
+
+void k1801vp128_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), cur_live.fi->id);
+ }
+ }
+
+ for (;;)
+ {
+ switch (cur_live.state)
+ {
+ case SEARCH_ADDRESS_MARK_HEADER:
+ if (read_one_bit(limit))
+ return;
+
+ if (!(cur_live.bit_counter & 255))
+ {
+ LOGSHIFT("%s (%s): shift = %04x data=%02x c=%d\n", cur_live.tm.to_string(), limit.to_string(), cur_live.shift_reg,
+ bitswap<8>(cur_live.shift_reg, 14, 12, 10, 8, 6, 4, 2, 0), cur_live.bit_counter);
+ }
+
+ if (cur_live.shift_reg == 0x4489)
+ {
+ LOGLIVE("%s: Found A1\n", cur_live.tm.to_string());
+ cur_live.crc = 0x443b;
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 0;
+ cur_live.state = READ_DATA_LOW;
+ cur_live.data_reg = 0xa1;
+ m_sr &= ~CSR_R_CRC;
+ checkpoint();
+ }
+ break;
+
+ case READ_DATA_HIGH:
+ if (read_one_bit(limit))
+ return;
+ if (cur_live.bit_counter & 15)
+ break;
+ live_delay(READ_DATA_HIGH_BYTE);
+ return;
+
+ case READ_DATA_HIGH_BYTE:
+ cur_live.state = READ_DATA_LOW;
+ checkpoint();
+ break;
+
+ case READ_DATA_LOW:
+ if (read_one_bit(limit))
+ return;
+ if (cur_live.bit_counter & 15)
+ break;
+ live_delay(READ_DATA_LOW_BYTE);
+ return;
+
+ case READ_DATA_LOW_BYTE:
+ m_rbuf = cur_live.data_reg;
+ if (cur_live.crc == 0)
+ {
+ m_sr |= CSR_R_CRC;
+ }
+ m_sr |= CSR_R_TR;
+ LOGLIVE("%s: Read %04x (CRC %04x)\n", cur_live.tm.to_string(), cur_live.data_reg, cur_live.crc);
+ cur_live.state = READ_DATA_HIGH;
+ checkpoint();
+ break;
+
+ case WRITE_MFM_DATA_LOW:
+ if ((m_wbuf & 255) == 0xa1 && cur_live.crc_init == false && !(m_sr & CSR_R_CRC))
+ {
+ cur_live.crc_init = true;
+ cur_live.crc = 0xffff;
+ }
+ // if DRQ has not been serviced, write CRC
+ // if DRQ has not been serviced AND CRC has been written, write zeros
+ if (m_sr & CSR_R_TR)
+ {
+ if (cur_live.crc_init)
+ {
+ LOGLIVE("%s: Write CRC %04x\n", cur_live.tm.to_string(), cur_live.crc);
+ m_sr |= CSR_R_CRC;
+ m_sr &= ~CSR_R_TR;
+ cur_live.crc_init = false;
+ }
+ else
+ {
+ LOGLIVE("%s: Write after CRC\n", cur_live.tm.to_string());
+ m_wbuf = 0;
+ }
+ }
+ live_write_mfm((m_sr & CSR_R_CRC) ? (cur_live.crc >> 8) : m_wbuf, BIT(m_cr, 9));
+ cur_live.state++;
+ cur_live.bit_counter = 16;
+ checkpoint();
+ break;
+
+ case WRITE_MFM_DATA_HIGH:
+ live_write_mfm((m_sr & CSR_R_CRC) ? cur_live.crc : (m_wbuf >> 8), BIT(m_cr, 9));
+ LOGLIVE("%s: Write next %s\n", cur_live.tm.to_string(), (m_sr & CSR_R_TR)?"TR":"");
+ if (!(m_sr & CSR_R_CRC))
+ m_sr |= CSR_R_TR;
+ cur_live.state++;
+ cur_live.bit_counter = 16;
+ checkpoint();
+ break;
+
+ case WRITE_MFM_DATA_LOW_BYTE:
+ if (write_one_bit(limit))
+ return;
+ if (cur_live.bit_counter == 0)
+ {
+ live_delay(WRITE_MFM_DATA_HIGH);
+ return;
+ }
+ break;
+
+ case WRITE_MFM_DATA_HIGH_BYTE:
+ if (write_one_bit(limit))
+ return;
+ if (cur_live.bit_counter == 0)
+ {
+ live_delay(WRITE_MFM_DATA_LOW);
+ m_sr &= ~CSR_R_CRC;
+ return;
+ }
+ break;
+
+ default:
+ LOGWARN("%s: Unknown live state %d\n", cur_live.tm.to_string(), cur_live.state);
+ return;
+ }
+ }
+}
+
+
+void k1801vp128_device::seek_start(floppy_info &fi)
+{
+ fi.sub_state = SEEK_MOVE;
+ fi.dir = !BIT(m_cr, 6);
+ general_continue(fi);
+}
+
+
+void k1801vp128_device::read_data_start(floppy_info &fi)
+{
+ fi.main_state = READ_DATA;
+ fi.sub_state = WAIT_INDEX_DONE;
+ m_sr &= ~CSR_R_CRC;
+ read_data_continue(fi);
+}
+
+void k1801vp128_device::read_data_continue(floppy_info &fi)
+{
+ for (;;)
+ {
+ switch (fi.sub_state)
+ {
+ case SEEK_MOVE:
+ LOGSTATE("sub %d SEEK_MOVE\n", fi.id);
+ fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
+ fi.tm->adjust(attotime::from_msec(2), fi.id);
+ return;
+
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ LOGSTATE("sub %d SEEK_WAIT_STEP_SIGNAL_TIME\n", fi.id);
+ return;
+
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ LOGSTATE("sub %d SEEK_WAIT_STEP_SIGNAL_TIME_DONE\n", fi.id);
+ if (fi.dev)
+ {
+ fi.dev->dir_w(fi.dir);
+ fi.dev->stp_w(0);
+ fi.dev->stp_w(1);
+ fi.sub_state = WAIT_INDEX_DONE;
+ }
+ else
+ fi.main_state = fi.sub_state = IDLE;
+ break;
+
+ case WAIT_INDEX:
+ LOGSTATE("sub %d WAIT_INDEX\n", fi.id);
+ return;
+
+ case WAIT_INDEX_DONE:
+ LOGSTATE("sub %d WAIT_INDEX_DONE\n", fi.id);
+ fi.counter = 0;
+ fi.sub_state = SCAN_ID;
+ LOGSTATE("live %d SEARCH_ADDRESS_MARK_HEADER\n", fi.id);
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
+
+ case SCAN_ID:
+ LOGSTATE("sub %d SCAN_ID\n", fi.id);
+ fi.sub_state = TRACK_READ;
+ LOGSTATE("live %d READ_DATA_HIGH\n", fi.id);
+ live_start(fi, READ_DATA_HIGH);
+ return;
+
+ case SCAN_ID_FAILED:
+ LOGSTATE("sub %d SCAN_ID_FAILED\n", fi.id);
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case TRACK_READ:
+ LOGSTATE("sub %d TRACK_READ\n", fi.id);
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case COMMAND_DONE:
+ LOGSTATE("sub %d COMMAND_DONE\n", fi.id);
+ fi.main_state = fi.sub_state = IDLE;
+ return;
+
+ default:
+ LOGWARN("%s: read sector unknown sub-state %d\n", ttsn(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+void k1801vp128_device::write_data_start(floppy_info &fi)
+{
+ fi.main_state = WRITE_DATA;
+ fi.sub_state = WAIT_INDEX_DONE;
+ m_sr &= ~CSR_R_CRC;
+ write_data_continue(fi);
+}
+
+void k1801vp128_device::write_data_continue(floppy_info &fi)
+{
+ for (;;)
+ {
+ switch (fi.sub_state)
+ {
+ case WAIT_INDEX:
+ LOGSTATE("sub %d WAIT_INDEX\n", fi.id);
+ return;
+
+ case WAIT_INDEX_DONE:
+ LOGSTATE("sub %d WAIT_INDEX_DONE\n", fi.id);
+ fi.sub_state = TRACK_WRITTEN;
+ LOGSTATE("live %d WRITE_MFM_DATA_LOW\n", fi.id);
+ live_start(fi, WRITE_MFM_DATA_LOW);
+ return;
+
+ case TRACK_WRITTEN:
+ LOGSTATE("sub %d TRACK_WRITTEN\n", fi.id);
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case COMMAND_DONE:
+ LOGSTATE("sub %d COMMAND_DONE\n", fi.id);
+ fi.main_state = fi.sub_state = IDLE;
+ return;
+
+ default:
+ LOGWARN("%s: write sector unknown sub-state %d\n", ttsn(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+
+void k1801vp128_device::index_callback(floppy_image_device *floppy, int state)
+{
+ LOGLIVE("%s: Pulse %d\n", machine().time().to_string(), state);
+ for (floppy_info &fi : flopi)
+ {
+ if (fi.dev != floppy)
+ continue;
+
+ if (!state)
+ {
+ general_continue(fi);
+ continue;
+ }
+
+ switch (fi.sub_state)
+ {
+ case IDLE:
+ case SEEK_MOVE:
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ case SEEK_WAIT_STEP_TIME:
+ case SEEK_WAIT_STEP_TIME_DONE:
+ case HEAD_LOAD:
+ case HEAD_LOAD_DONE:
+ case SCAN_ID:
+ case SCAN_ID_FAILED:
+ break;
+
+ case TRACK_READ:
+ fi.sub_state = IDLE;
+ break;
+
+ case WAIT_INDEX:
+ fi.sub_state = WAIT_INDEX_DONE;
+ live_abort();
+ break;
+
+ default:
+ LOGWARN("%s: Index pulse on unknown sub-state %d\n", ttsn(), fi.sub_state);
+ break;
+ }
+
+ general_continue(fi);
+ }
+}
+
+
+void k1801vp128_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 READ_DATA:
+ read_data_continue(fi);
+ break;
+
+ case WRITE_DATA:
+ write_data_continue(fi);
+ break;
+
+ default:
+ LOGWARN("%s: general_continue on unknown main-state %d\n", ttsn(), fi.main_state);
+ break;
+ }
+}
+
+
+bool k1801vp128_device::read_one_bit(const attotime &limit)
+{
+ int bit = cur_live.pll.get_next_bit(cur_live.tm, cur_live.fi->dev, limit);
+ if (bit < 0)
+ return true;
+ cur_live.shift_reg = (cur_live.shift_reg << 1) | bit;
+ cur_live.bit_counter++;
+ if (cur_live.data_separator_phase)
+ {
+ cur_live.data_reg = (cur_live.data_reg << 1) | bit;
+ if ((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ cur_live.crc = (cur_live.crc << 1) ^ 0x1021;
+ else
+ cur_live.crc = cur_live.crc << 1;
+ }
+ cur_live.data_separator_phase = !cur_live.data_separator_phase;
+ return false;
+}
+
+bool k1801vp128_device::write_one_bit(const attotime &limit)
+{
+ bool bit = cur_live.shift_reg & 0x8000;
+ if (cur_live.pll.write_next_bit(bit, cur_live.tm, cur_live.fi->dev, limit))
+ return true;
+ if ((cur_live.bit_counter & 1) && cur_live.crc_init)
+ {
+ 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 k1801vp128_device::live_write_mfm(uint8_t mfm, bool marker)
+{
+ bool context = cur_live.data_bit_context;
+ uint16_t 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;
+ }
+ if (marker && (mfm & 0xc) == 0) raw &= 0xffdf; // A1 and C2 sync sequences
+ cur_live.data_reg = mfm;
+ cur_live.shift_reg = raw;
+ cur_live.data_bit_context = context;
+ LOGLIVE("%s: write %02x %04x %04x\n", cur_live.tm.to_string(), mfm, cur_live.crc, raw);
+}
+
+
+void k1801vp128_device::set_ds(int fid)
+{
+ if (selected_drive == fid)
+ return;
+
+ live_abort();
+
+ // pass drive select to connected drives
+ for (floppy_info &fi : flopi)
+ if (fi.dev)
+ fi.dev->ds_w(fid);
+
+ // record selected drive
+ selected_drive = fid;
+
+ if (fid != -1)
+ {
+ LOG("COMMAND ~READ drive %d c:h %d:%d\n", selected_drive, flopi[fid].dev->get_cyl(), BIT(m_cr, 5));
+ m_sr &= ~CSR_R_TR;
+ execute_command(CMD_READ);
+ }
+}
diff --git a/src/devices/machine/1801vp128.h b/src/devices/machine/1801vp128.h
new file mode 100644
index 00000000000..4a83f58b018
--- /dev/null
+++ b/src/devices/machine/1801vp128.h
@@ -0,0 +1,213 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/**********************************************************************
+
+ 1801VP1-128 gate array (MFM codec for floppy controllers)
+
+**********************************************************************
+ _____ _____
+ _AD0 1 |* \_/ | 42 +5V
+ _AD1 2 | | 41 _DS0
+ _AD2 3 | | 30 _DS1
+ _AD3 4 | | 39 _DS2
+ _AD4 5 | | 38 _DS3
+ _AD5 6 | | 37 _MSW
+ _AD6 7 | | 36 HS
+ _AD7 8 | | 35 DIR
+ _AD8 9 | | 34 _ST
+ _AD9 10 | | 33 TR0
+ _AD10 11 | 1801VP1-128 | 32 RDY
+ _AD11 12 | | 31 WPR
+ _AD12 13 | | 30 _REZ
+ _AD13 14 | | 29 DI
+ _AD14 15 | | 28 _WRE
+ _AD15 16 | | 27 _D01
+ _SYNC 17 | | 26 _D02
+ _DIN 18 | | 25 _D03
+ _DOUT 19 | | 24 IND
+ _INIT 20 | | 23 _RPLY
+ GND 21 |_____________| 22 CLC
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_1801VP128_H
+#define MAME_MACHINE_1801VP128_H
+
+#pragma once
+
+#include "imagedev/floppy.h"
+#include "machine/pdp11.h"
+
+#include "fdc_pll.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> k1801vp128_device
+
+class k1801vp128_device : public device_t
+{
+public:
+ // construction/destruction
+ k1801vp128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto ds_in_callback() { return m_read_ds.bind(); }
+
+ uint16_t read(offs_t offset);
+ void write(offs_t offset, uint16_t data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ TIMER_CALLBACK_MEMBER(update_floppy);
+
+private:
+ enum {
+ CMD_READ,
+ CMD_WRITE,
+ CMD_SEEK
+ };
+
+ enum {
+ IDLE,
+
+ // Main states
+ READ_DATA,
+ WRITE_DATA,
+
+ // Sub-states
+ COMMAND_DONE,
+
+ SEEK_MOVE,
+ SEEK_WAIT_STEP_SIGNAL_TIME,
+ SEEK_WAIT_STEP_SIGNAL_TIME_DONE,
+ SEEK_WAIT_STEP_TIME,
+ SEEK_WAIT_STEP_TIME_DONE,
+ SEEK_WAIT_DONE,
+ SEEK_DONE,
+
+ HEAD_LOAD,
+ HEAD_LOAD_DONE,
+
+ WAIT_INDEX,
+ WAIT_INDEX_DONE,
+
+ SCAN_ID,
+ SCAN_ID_FAILED,
+
+ TRACK_READ,
+ TRACK_WRITTEN,
+
+ // Live states
+ SEARCH_ADDRESS_MARK_HEADER,
+ READ_DATA_HIGH,
+ READ_DATA_HIGH_BYTE,
+ READ_DATA_LOW,
+ READ_DATA_LOW_BYTE,
+
+ WRITE_MFM_DATA_HIGH,
+ WRITE_MFM_DATA_HIGH_BYTE,
+ WRITE_MFM_DATA_LOW,
+ WRITE_MFM_DATA_LOW_BYTE,
+ };
+
+ enum {
+ CSR_R_TR0 = 0000001,
+ CSR_R_RDY = 0000002,
+ CSR_R_WPR = 0000004,
+ CSR_R_TR = CSR_DONE,
+ CSR_R_CRC = 0040000,
+ CSR_R_IND = 0100000,
+
+ CSR_W_DS0 = 0000001,
+ CSR_W_DS1 = 0000002,
+ CSR_W_DS2 = 0000004,
+ CSR_W_DS3 = 0000010,
+ CSR_W_MSW = 0000020, // motor
+ CSR_W_HS = 0000040, // head select
+ CSR_W_DIR = 0000100, // step direction
+ CSR_W_ST = 0000200, // step pulse
+ CSR_W_GDR = 0000400,
+ CSR_W_WM = 0001000,
+ CSR_W_REZ = 0002000,
+ CSR_W_DS = 0000017,
+ };
+
+ struct floppy_info
+ {
+ floppy_info();
+
+ emu_timer *tm;
+ floppy_image_device *dev;
+ int id;
+ int main_state, sub_state;
+ int dir, counter;
+ bool live, index;
+ };
+
+ struct live_info
+ {
+ live_info();
+
+ attotime tm;
+ int state, next_state;
+ floppy_info *fi;
+ uint16_t shift_reg, crc;
+ int bit_counter;
+ bool data_separator_phase, data_bit_context, crc_init;
+ uint16_t data_reg;
+ fdc_pll_t pll;
+ };
+
+ required_device_array<floppy_connector, 4> m_connectors;
+ devcb_read16 m_read_ds;
+
+ std::string ttsn() const;
+
+ floppy_info flopi[4];
+ int selected_drive;
+
+ uint16_t m_cr;
+ uint16_t m_sr;
+ uint16_t m_rbuf;
+ uint16_t m_wbuf;
+
+ live_info cur_live, checkpoint_live;
+
+ void execute_command(int command);
+ void set_ds(int fid);
+
+ void seek_start(floppy_info &fi);
+ void seek_continue(floppy_info &fi);
+
+ void read_data_start(floppy_info &fi);
+ void read_data_continue(floppy_info &fi);
+
+ void write_data_start(floppy_info &fi);
+ void write_data_continue(floppy_info &fi);
+
+ void general_continue(floppy_info &fi);
+ void index_callback(floppy_image_device *floppy, int state);
+
+ void live_start(floppy_info &fi, int live_state);
+ void live_abort();
+ void checkpoint();
+ void rollback();
+ void live_delay(int state);
+ void live_sync();
+ void live_run(attotime limit = attotime::never);
+ void live_write_mfm(uint8_t mfm, bool marker);
+
+ bool read_one_bit(const attotime &limit);
+ bool write_one_bit(const attotime &limit);
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(K1801VP128, k1801vp128_device)
+
+#endif // MAME_MACHINE_1801VP128_H
diff --git a/src/devices/machine/1ma6.cpp b/src/devices/machine/1ma6.cpp
index 284088a9f00..97b3eeb7292 100644
--- a/src/devices/machine/1ma6.cpp
+++ b/src/devices/machine/1ma6.cpp
@@ -181,7 +181,7 @@ uint8_t hp_1ma6_device::reg_r(offs_t offset)
return res;
}
-WRITE_LINE_MEMBER(hp_1ma6_device::cart_out_w)
+void hp_1ma6_device::cart_out_w(int state)
{
LOG_DBG("cart_out_w %d\n" , state);
if (state) {
@@ -190,7 +190,7 @@ WRITE_LINE_MEMBER(hp_1ma6_device::cart_out_w)
}
}
-WRITE_LINE_MEMBER(hp_1ma6_device::hole_w)
+void hp_1ma6_device::hole_w(int state)
{
if (state) {
LOG_DBG("hole_w\n");
@@ -198,7 +198,7 @@ WRITE_LINE_MEMBER(hp_1ma6_device::hole_w)
}
}
-WRITE_LINE_MEMBER(hp_1ma6_device::tacho_tick_w)
+void hp_1ma6_device::tacho_tick_w(int state)
{
if (state) {
LOG_DBG("tacho_tick_w\n");
@@ -206,7 +206,7 @@ WRITE_LINE_MEMBER(hp_1ma6_device::tacho_tick_w)
}
}
-WRITE_LINE_MEMBER(hp_1ma6_device::motion_w)
+void hp_1ma6_device::motion_w(int state)
{
if (state) {
LOG_DBG("motion_w @%.6f st=%d\n" , machine().time().as_double() , m_cmd_state);
@@ -279,7 +279,7 @@ WRITE_LINE_MEMBER(hp_1ma6_device::motion_w)
}
}
-WRITE_LINE_MEMBER(hp_1ma6_device::rd_bit_w)
+void hp_1ma6_device::rd_bit_w(int state)
{
LOG_RW("RD bit %d (st=%d,sr=%02x,i=%u)\n" , state , m_cmd_state , m_data_sr , m_bit_idx);
switch (m_cmd_state) {
@@ -319,7 +319,7 @@ WRITE_LINE_MEMBER(hp_1ma6_device::rd_bit_w)
}
}
-READ_LINE_MEMBER(hp_1ma6_device::wr_bit_r)
+int hp_1ma6_device::wr_bit_r()
{
bool bit = m_cmd_state == CMD_WR_PREAMBLE ? false : BIT(m_data_sr , m_bit_idx);
if (m_bit_idx) {
@@ -341,7 +341,7 @@ void hp_1ma6_device::device_add_mconfig(machine_config &config)
m_tape->set_acceleration(ACCELERATION);
m_tape->set_set_points(SLOW_SPEED , FAST_SPEED);
m_tape->set_tick_size(TACH_TICK_LEN);
- m_tape->set_bits_per_word(16);
+ m_tape->set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS);
m_tape->set_go_threshold(MOVING_THRESHOLD);
m_tape->cart_out().set(FUNC(hp_1ma6_device::cart_out_w));
m_tape->hole().set(FUNC(hp_1ma6_device::hole_w));
diff --git a/src/devices/machine/1ma6.h b/src/devices/machine/1ma6.h
index cb083e05c88..33075250055 100644
--- a/src/devices/machine/1ma6.h
+++ b/src/devices/machine/1ma6.h
@@ -26,12 +26,12 @@ public:
void reg_w(offs_t offset, uint8_t data);
uint8_t reg_r(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER(cart_out_w);
- DECLARE_WRITE_LINE_MEMBER(hole_w);
- DECLARE_WRITE_LINE_MEMBER(tacho_tick_w);
- DECLARE_WRITE_LINE_MEMBER(motion_w);
- DECLARE_WRITE_LINE_MEMBER(rd_bit_w);
- DECLARE_READ_LINE_MEMBER(wr_bit_r);
+ void cart_out_w(int state);
+ void hole_w(int state);
+ void tacho_tick_w(int state);
+ void motion_w(int state);
+ void rd_bit_w(int state);
+ int wr_bit_r();
protected:
// device-level overrides
diff --git a/src/devices/machine/1mb5.cpp b/src/devices/machine/1mb5.cpp
index 054202b06e1..f3dacdbe7ba 100644
--- a/src/devices/machine/1mb5.cpp
+++ b/src/devices/machine/1mb5.cpp
@@ -160,22 +160,22 @@ void hp_1mb5_device::uc_w(offs_t offset, uint8_t data)
}
}
-READ_LINE_MEMBER(hp_1mb5_device::irl_r)
+int hp_1mb5_device::irl_r()
{
return m_service;
}
-READ_LINE_MEMBER(hp_1mb5_device::halt_r)
+int hp_1mb5_device::halt_r()
{
return m_halt;
}
-READ_LINE_MEMBER(hp_1mb5_device::reset_r)
+int hp_1mb5_device::reset_r()
{
return m_reset;
}
-READ_LINE_MEMBER(hp_1mb5_device::int_r)
+int hp_1mb5_device::int_r()
{
return m_cint;
}
@@ -193,11 +193,6 @@ void hp_1mb5_device::clear_service()
void hp_1mb5_device::device_start()
{
- m_irl_handler.resolve_safe();
- m_halt_handler.resolve_safe();
- m_reset_handler.resolve_safe();
- m_int_handler.resolve_safe();
-
save_item(NAME(m_sr));
save_item(NAME(m_cr));
save_item(NAME(m_ib));
diff --git a/src/devices/machine/1mb5.h b/src/devices/machine/1mb5.h
index 13b1296e6cc..34c081ed672 100644
--- a/src/devices/machine/1mb5.h
+++ b/src/devices/machine/1mb5.h
@@ -34,12 +34,12 @@ public:
void uc_w(offs_t offset, uint8_t data);
// Signals to CPU
- DECLARE_READ_LINE_MEMBER(irl_r);
- DECLARE_READ_LINE_MEMBER(halt_r);
+ int irl_r();
+ int halt_r();
// Signals to uC
- DECLARE_READ_LINE_MEMBER(reset_r);
- DECLARE_READ_LINE_MEMBER(int_r);
+ int reset_r();
+ int int_r();
// Interrupt enable
void inten();
diff --git a/src/devices/machine/2812fifo.cpp b/src/devices/machine/2812fifo.cpp
index 3cc10965ecb..ea2bb69a31a 100644
--- a/src/devices/machine/2812fifo.cpp
+++ b/src/devices/machine/2812fifo.cpp
@@ -46,7 +46,7 @@ fifo2812_device::fifo2812_device(machine_config const &mconfig, char const *tag,
}
-WRITE_LINE_MEMBER(fifo2812_device::mr_w)
+void fifo2812_device::mr_w(int state)
{
if (bool(state) != bool(m_mr))
{
@@ -56,7 +56,7 @@ WRITE_LINE_MEMBER(fifo2812_device::mr_w)
}
}
-WRITE_LINE_MEMBER(fifo2812_device::pl_w)
+void fifo2812_device::pl_w(int state)
{
if (bool(state) != bool(m_pl))
{
@@ -104,7 +104,7 @@ WRITE_LINE_MEMBER(fifo2812_device::pl_w)
}
}
-WRITE_LINE_MEMBER(fifo2812_device::pd_w)
+void fifo2812_device::pd_w(int state)
{
if (bool(state) != bool(m_pd))
{
@@ -151,7 +151,7 @@ WRITE_LINE_MEMBER(fifo2812_device::pd_w)
}
}
-WRITE_LINE_MEMBER(fifo2812_device::oe_w)
+void fifo2812_device::oe_w(int state)
{
if (bool(state) != bool(m_oe))
{
@@ -191,11 +191,6 @@ void fifo2812_device::write(u8 data)
void fifo2812_device::device_resolve_objects()
{
- m_q_cb.resolve_safe();
- m_ir_cb.resolve_safe();
- m_or_cb.resolve_safe();
- m_flag_cb.resolve_safe();
-
m_d = 0U;
m_mr = 1U;
m_pl = 0U;
diff --git a/src/devices/machine/2812fifo.h b/src/devices/machine/2812fifo.h
index 01c42624c09..5b56d70a77a 100644
--- a/src/devices/machine/2812fifo.h
+++ b/src/devices/machine/2812fifo.h
@@ -42,14 +42,14 @@ public:
// control signal interface
void d_w(u8 data) { m_d = data; }
- DECLARE_WRITE_LINE_MEMBER(mr_w);
- DECLARE_WRITE_LINE_MEMBER(pl_w);
- DECLARE_WRITE_LINE_MEMBER(pd_w);
- DECLARE_WRITE_LINE_MEMBER(oe_w);
+ void mr_w(int state);
+ void pl_w(int state);
+ void pd_w(int state);
+ void oe_w(int state);
u8 q_r() const { return m_oe ? m_data[LENGTH - 1] : 0xff; }
- DECLARE_READ_LINE_MEMBER(ir_r) const { return BIT(m_control, 0); }
- DECLARE_READ_LINE_MEMBER(or_r) const { return BIT(m_control, LENGTH - 1); }
- DECLARE_READ_LINE_MEMBER(flag_r);
+ int ir_r() const { return BIT(m_control, 0); }
+ int or_r() const { return BIT(m_control, LENGTH - 1); }
+ int flag_r();
// read/write interface
u8 read();
diff --git a/src/devices/machine/28fxxx.cpp b/src/devices/machine/28fxxx.cpp
index e434a761c46..1c424b44b01 100644
--- a/src/devices/machine/28fxxx.cpp
+++ b/src/devices/machine/28fxxx.cpp
@@ -103,14 +103,16 @@ void base_28fxxx_device::nvram_default()
erase();
}
-void base_28fxxx_device::nvram_read(emu_file &file)
+bool base_28fxxx_device::nvram_read(util::read_stream &file)
{
- file.read(m_data.get(), m_size);
+ auto const [err, actual] = util::read(file, m_data.get(), m_size);
+ return !err && (actual == m_size);
}
-void base_28fxxx_device::nvram_write(emu_file &file)
+bool base_28fxxx_device::nvram_write(util::write_stream &file)
{
- file.write(m_data.get(), m_size);
+ auto const [err, actual] = util::write(file, m_data.get(), m_size);
+ return !err;
}
void base_28fxxx_device::erase()
diff --git a/src/devices/machine/28fxxx.h b/src/devices/machine/28fxxx.h
index 153fd785960..0551f874f27 100644
--- a/src/devices/machine/28fxxx.h
+++ b/src/devices/machine/28fxxx.h
@@ -21,7 +21,7 @@ public:
RESET = 0xff
};
- DECLARE_WRITE_LINE_MEMBER(vpp) { m_program_power = state; }
+ void vpp(int state) { m_program_power = state; }
u8 read(address_space &space, offs_t offset, u8 mem_mask = ~0);
void write(offs_t offset, u8 data);
@@ -31,8 +31,8 @@ protected:
virtual void device_start() override;
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
optional_memory_region m_region;
diff --git a/src/devices/machine/40105.cpp b/src/devices/machine/40105.cpp
index ffcfab73da9..8e528a83329 100644
--- a/src/devices/machine/40105.cpp
+++ b/src/devices/machine/40105.cpp
@@ -43,17 +43,17 @@ DEFINE_DEVICE_TYPE(CD40105, cmos_40105_device, "cd40105", "CD40105B FIFO Registe
// cmos_40105_device - constructor
//-------------------------------------------------
-cmos_40105_device::cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, CD40105, tag, owner, clock),
- m_write_dir(*this),
- m_write_dor(*this),
- m_write_q(*this),
- m_d(0),
- m_q(0),
- m_dir(false),
- m_dor(false),
- m_si(false),
- m_so(false)
+cmos_40105_device::cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, CD40105, tag, owner, clock),
+ m_write_dir(*this),
+ m_write_dor(*this),
+ m_write_q(*this),
+ m_d(0),
+ m_q(0),
+ m_dir(false),
+ m_dor(false),
+ m_si(false),
+ m_so(false)
{
}
@@ -64,11 +64,6 @@ cmos_40105_device::cmos_40105_device(const machine_config &mconfig, const char *
void cmos_40105_device::device_start()
{
- // resolve callbacks
- m_write_dir.resolve_safe();
- m_write_dor.resolve_safe();
- m_write_q.resolve_safe();
-
// state saving
save_item(NAME(m_d));
save_item(NAME(m_q));
@@ -163,7 +158,7 @@ void cmos_40105_device::output_ready()
// si_w - shift in write
//-------------------------------------------------
-WRITE_LINE_MEMBER( cmos_40105_device::si_w )
+void cmos_40105_device::si_w(int state)
{
// load input on rising edge when ready
if (m_dir && !m_si && state)
@@ -185,7 +180,7 @@ WRITE_LINE_MEMBER( cmos_40105_device::si_w )
// so_w - shift out write
//-------------------------------------------------
-WRITE_LINE_MEMBER( cmos_40105_device::so_w )
+void cmos_40105_device::so_w(int state)
{
// shift out on falling edge when ready
if (m_dor && m_so && !state)
@@ -218,7 +213,7 @@ WRITE_LINE_MEMBER( cmos_40105_device::so_w )
// dir_r - data in ready read
//-------------------------------------------------
-READ_LINE_MEMBER( cmos_40105_device::dir_r )
+int cmos_40105_device::dir_r()
{
return m_dir;
}
@@ -228,7 +223,7 @@ READ_LINE_MEMBER( cmos_40105_device::dir_r )
// dor_r - data out ready read
//-------------------------------------------------
-READ_LINE_MEMBER( cmos_40105_device::dor_r )
+int cmos_40105_device::dor_r()
{
return m_dor;
}
diff --git a/src/devices/machine/40105.h b/src/devices/machine/40105.h
index 5b35de12a58..74f44da8d2a 100644
--- a/src/devices/machine/40105.h
+++ b/src/devices/machine/40105.h
@@ -44,11 +44,11 @@ public:
u8 read();
void write(u8 data);
- DECLARE_WRITE_LINE_MEMBER( si_w );
- DECLARE_WRITE_LINE_MEMBER( so_w );
+ void si_w(int state);
+ void so_w(int state);
- DECLARE_READ_LINE_MEMBER( dir_r );
- DECLARE_READ_LINE_MEMBER( dor_r );
+ int dir_r();
+ int dor_r();
protected:
// device-level overrides
diff --git a/src/devices/machine/53c7xx.cpp b/src/devices/machine/53c7xx.cpp
index 40c481a448f..21fa52528be 100644
--- a/src/devices/machine/53c7xx.cpp
+++ b/src/devices/machine/53c7xx.cpp
@@ -23,10 +23,10 @@
// DEBUGGERY
//**************************************************************************
-#define LOG_UNHANDLED (1U << 0)
-#define LOG_HOST (1U << 1)
-#define LOG_STATE (1U << 2)
-#define LOG_SCRIPTS (1U << 3)
+#define LOG_UNHANDLED (1U << 1)
+#define LOG_HOST (1U << 2)
+#define LOG_STATE (1U << 3)
+#define LOG_SCRIPTS (1U << 4)
#define VERBOSE (0)
#include "logmacro.h"
@@ -87,14 +87,14 @@ DEFINE_DEVICE_TYPE(NCR53C7XX, ncr53c7xx_device, "ncr537xx", "NCR 53C7xx SCSI")
// ncr53c7xx_device - constructor/destructor
//-------------------------------------------------
-ncr53c7xx_device::ncr53c7xx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nscsi_device(mconfig, NCR53C7XX, tag, owner, clock),
- nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF),
- device_execute_interface(mconfig, *this),
- m_icount(0),
- m_irq_handler(*this),
- m_host_write(*this),
- m_host_read(*this)
+ncr53c7xx_device::ncr53c7xx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ nscsi_device(mconfig, NCR53C7XX, tag, owner, clock),
+ nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_irq_handler(*this),
+ m_host_write(*this),
+ m_host_read(*this, 0)
{
}
@@ -108,12 +108,7 @@ void ncr53c7xx_device::device_start()
// set our instruction counter
set_icountptr(m_icount);
- // resolve line callbacks
- m_irq_handler.resolve_safe();
- m_host_read.resolve_safe(0);
- m_host_write.resolve_safe();
-
- m_tm = timer_alloc(0);
+ m_tm = timer_alloc(FUNC(ncr53c7xx_device::step_timer), this);
// The SCRIPTS processor runs at ~2 MIPS so approximate this
set_unscaled_clock(2000000);
@@ -292,7 +287,8 @@ uint32_t ncr53c7xx_device::read(offs_t offset, uint32_t mem_mask)
if (ACCESSING_BITS_0_7)
{
ret = m_dstat;
- m_dstat = 0;
+ // DFE isn't cleared on read
+ m_dstat &= DSTAT_DFE;
update_irqs();
}
if (ACCESSING_BITS_8_15)
@@ -756,11 +752,11 @@ void ncr53c7xx_device::recv_byte()
//-------------------------------------------------
-// device_timer - callback to step the SCSI
+// step_timer - callback to step the SCSI
// state machine
//-------------------------------------------------
-void ncr53c7xx_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ncr53c7xx_device::step_timer)
{
step(true);
}
@@ -1735,7 +1731,7 @@ void ncr53c7xx_device::tc_int()
// disassemble_scripts -
//-------------------------------------------------
-const char* ncr53c7xx_device::disassemble_scripts()
+std::string ncr53c7xx_device::disassemble_scripts()
{
static char const *const phases[] =
{
@@ -1749,14 +1745,13 @@ const char* ncr53c7xx_device::disassemble_scripts()
"Message In"
};
- static char buffer[64];
- char opstring[64];
+ std::string opstring;
switch ((m_dcmd >> 6) & 3)
{
case 0:
{
- sprintf(opstring, "BMOV: %s [%x] %d bytes\n", phases[m_dcmd & 7], m_dnad, m_dbc);
+ opstring = util::string_format("BMOV: %s [%x] %d bytes\n", phases[m_dcmd & 7], m_dnad, m_dbc);
break;
}
case 1:
@@ -1773,7 +1768,7 @@ const char* ncr53c7xx_device::disassemble_scripts()
"ILLEGAL",
};
- sprintf(opstring, "IO: %s (%x)\n", ops[(m_dcmd >> 3) & 7], m_dnad);
+ opstring = util::string_format("IO: %s (%x)\n", ops[(m_dcmd >> 3) & 7], m_dnad);
break;
}
case 2:
@@ -1790,17 +1785,15 @@ const char* ncr53c7xx_device::disassemble_scripts()
"ILLEGAL",
};
- sprintf(opstring, "TC: %s %c (%s) (%x)\n", ops[(m_dcmd >> 3) & 7], m_dbc & (1 << 19) ? 'T' : 'F', phases[m_dcmd & 7], m_dnad);
+ opstring = util::string_format("TC: %s %c (%s) (%x)\n", ops[(m_dcmd >> 3) & 7], m_dbc & (1 << 19) ? 'T' : 'F', phases[m_dcmd & 7], m_dnad);
break;
}
case 3:
{
- sprintf(opstring, "ILLEGAL");
+ opstring = "ILLEGAL";
break;
}
}
- sprintf(buffer, "SCRIPTS [%08x]: %s", m_dsp - 8, opstring);
-
- return buffer;
+ return util::string_format("SCRIPTS [%08x]: %s", m_dsp - 8, opstring);
}
diff --git a/src/devices/machine/53c7xx.h b/src/devices/machine/53c7xx.h
index 5adae84d790..2d6c695acd2 100644
--- a/src/devices/machine/53c7xx.h
+++ b/src/devices/machine/53c7xx.h
@@ -35,9 +35,10 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void execute_run() override;
+ TIMER_CALLBACK_MEMBER(step_timer);
+
int m_icount;
private:
@@ -122,7 +123,7 @@ private:
void tc_return();
void tc_int();
void illegal();
- const char* disassemble_scripts();
+ std::string disassemble_scripts();
// SCSI registers
diff --git a/src/devices/machine/53c810.cpp b/src/devices/machine/53c810.cpp
index 30fd7b08f33..261d640b340 100644
--- a/src/devices/machine/53c810.cpp
+++ b/src/devices/machine/53c810.cpp
@@ -723,7 +723,7 @@ unsigned lsi53c810_device::lsi53c810_dasm(char *buf, uint32_t pc)
buf += sprintf(buf, "%s ", op_mnemonic);
need_cojunction = false;
- for (i = 0; i < ARRAY_LENGTH(flags); i++)
+ for (i = 0; i < std::size(flags); i++)
{
if (op & flags[i].flag)
{
diff --git a/src/devices/machine/64h156.cpp b/src/devices/machine/64h156.cpp
index 7826cfdce58..6613b34ab69 100644
--- a/src/devices/machine/64h156.cpp
+++ b/src/devices/machine/64h156.cpp
@@ -86,13 +86,8 @@ c64h156_device::c64h156_device(const machine_config &mconfig, const char *tag, d
void c64h156_device::device_start()
{
- // resolve callbacks
- m_write_atn.resolve_safe();
- m_write_sync.resolve_safe();
- m_write_byte.resolve_safe();
-
// allocate timer
- t_gen = timer_alloc(0);
+ t_gen = timer_alloc(FUNC(c64h156_device::update_tick), this);
// register for state saving
save_item(NAME(m_mtr));
@@ -130,10 +125,10 @@ void c64h156_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// update_tick - pump the device life cycle
//-------------------------------------------------
-void c64h156_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(c64h156_device::update_tick)
{
live_sync();
live_run();
@@ -197,7 +192,7 @@ bool c64h156_device::write_next_bit(bool bit, const attotime &limit)
if(etime > limit)
return true;
- if(bit && cur_live.write_position < ARRAY_LENGTH(cur_live.write_buffer))
+ if(bit && cur_live.write_position < std::size(cur_live.write_buffer))
cur_live.write_buffer[cur_live.write_position++] = cur_live.tm - m_period;
LOG("%s write bit %u (%u)\n", cur_live.tm.as_string(), cur_live.bit_counter, bit);
@@ -455,7 +450,7 @@ void c64h156_device::yb_w(uint8_t data)
// test_w - test write
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::test_w )
+void c64h156_device::test_w(int state)
{
}
@@ -464,7 +459,7 @@ WRITE_LINE_MEMBER( c64h156_device::test_w )
// accl_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::accl_w )
+void c64h156_device::accl_w(int state)
{
if (m_accl != state)
{
@@ -481,7 +476,7 @@ WRITE_LINE_MEMBER( c64h156_device::accl_w )
// ted_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::ted_w )
+void c64h156_device::ted_w(int state)
{
if (m_ted != state)
{
@@ -502,7 +497,7 @@ WRITE_LINE_MEMBER( c64h156_device::ted_w )
// mtr_w - motor write
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::mtr_w )
+void c64h156_device::mtr_w(int state)
{
if (m_mtr != state)
{
@@ -529,7 +524,7 @@ WRITE_LINE_MEMBER( c64h156_device::mtr_w )
// oe_w - output enable write
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::oe_w )
+void c64h156_device::oe_w(int state)
{
if (m_oe != state)
{
@@ -551,7 +546,7 @@ WRITE_LINE_MEMBER( c64h156_device::oe_w )
// soe_w - SO enable write
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::soe_w )
+void c64h156_device::soe_w(int state)
{
if (m_soe != state)
{
@@ -568,7 +563,7 @@ WRITE_LINE_MEMBER( c64h156_device::soe_w )
// atni_w - serial attention input write
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::atni_w )
+void c64h156_device::atni_w(int state)
{
LOG("ATNI %u\n", state);
@@ -582,7 +577,7 @@ WRITE_LINE_MEMBER( c64h156_device::atni_w )
// atna_w - serial attention acknowledge write
//-------------------------------------------------
-WRITE_LINE_MEMBER( c64h156_device::atna_w )
+void c64h156_device::atna_w(int state)
{
LOG("ATNA %u\n", state);
diff --git a/src/devices/machine/64h156.h b/src/devices/machine/64h156.h
index c8ef50cc3ea..ed607885db7 100644
--- a/src/devices/machine/64h156.h
+++ b/src/devices/machine/64h156.h
@@ -60,9 +60,6 @@
#pragma once
#include "imagedev/floppy.h"
-#include "formats/d64_dsk.h"
-#include "formats/g64_dsk.h"
-#include "formats/d71_dsk.h"
@@ -85,18 +82,18 @@ public:
uint8_t yb_r();
void yb_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( test_w );
- DECLARE_WRITE_LINE_MEMBER( accl_w );
- DECLARE_WRITE_LINE_MEMBER( ted_w );
- DECLARE_WRITE_LINE_MEMBER( mtr_w );
- DECLARE_WRITE_LINE_MEMBER( oe_w );
- DECLARE_WRITE_LINE_MEMBER( soe_w );
- DECLARE_WRITE_LINE_MEMBER( atni_w );
- DECLARE_WRITE_LINE_MEMBER( atna_w );
+ void test_w(int state);
+ void accl_w(int state);
+ void ted_w(int state);
+ void mtr_w(int state);
+ void oe_w(int state);
+ void soe_w(int state);
+ void atni_w(int state);
+ void atna_w(int state);
- DECLARE_READ_LINE_MEMBER( sync_r ) { return checkpoint_live.sync; }
- DECLARE_READ_LINE_MEMBER( byte_r ) { return checkpoint_live.byte; }
- DECLARE_READ_LINE_MEMBER( atn_r ) { return m_atni ^ m_atna; }
+ int sync_r() { return checkpoint_live.sync; }
+ int byte_r() { return checkpoint_live.byte; }
+ int atn_r() { return m_atni ^ m_atna; }
void stp_w(int stp);
void ds_w(int ds);
@@ -108,7 +105,8 @@ protected:
virtual void device_start() override;
virtual void device_clock_changed() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_tick);
private:
enum {
diff --git a/src/devices/machine/6522via.cpp b/src/devices/machine/6522via.cpp
index 06f557c4355..1b1d0ea0766 100644
--- a/src/devices/machine/6522via.cpp
+++ b/src/devices/machine/6522via.cpp
@@ -11,17 +11,6 @@
**********************************************************************/
-/*
- 1999-Dec-22 PeT
- vc20 random number generation only partly working
- (reads (uninitialized) timer 1 and timer 2 counter)
- timer init, reset, read changed
-
- 2017-Feb-15 Edstrom
- Fixed shift registers to be more accurate, eg 50/50 duty cycle, latching
- on correct edges and leading and trailing edges added + logging.
- */
-
#include "emu.h"
#include "6522via.h"
@@ -29,10 +18,10 @@
PARAMETERS
***************************************************************************/
-#define LOG_SETUP (1U << 1)
-#define LOG_SHIFT (1U << 2)
-#define LOG_READ (1U << 3)
-#define LOG_INT (1U << 4)
+#define LOG_SETUP (1U << 1)
+#define LOG_SHIFT (1U << 2)
+#define LOG_READ (1U << 3)
+#define LOG_INT (1U << 4)
//#define VERBOSE (LOG_SHIFT|LOG_INT|LOG_SETUP)
//#define LOG_OUTPUT_FUNC printf
@@ -165,8 +154,11 @@ void via6522_device::counter2_decrement()
// LIVE DEVICE
//**************************************************************************
-// device type definition
-DEFINE_DEVICE_TYPE(VIA6522, via6522_device, "via6522", "6522 VIA")
+// device type definitions
+DEFINE_DEVICE_TYPE(MOS6522, mos6522_device, "mos6522", "MOS 6522 VIA")
+DEFINE_DEVICE_TYPE(R65C22, r65c22_device, "r65c22", "Rockwell R65C22 VIA")
+DEFINE_DEVICE_TYPE(R65NC22, r65nc22_device, "r65nc22", "Rockwell R65NC22 VIA")
+DEFINE_DEVICE_TYPE(W65C22S, w65c22s_device, "w65c22s", "WDC W65C22S VIA")
void via6522_device::map(address_map &map)
{
@@ -177,27 +169,64 @@ void via6522_device::map(address_map &map)
// via6522_device - constructor
//-------------------------------------------------
-via6522_device::via6522_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, VIA6522, tag, owner, clock),
- m_in_a_handler(*this),
- m_in_b_handler(*this),
- m_out_a_handler(*this),
- m_out_b_handler(*this),
- m_ca2_handler(*this),
- m_cb1_handler(*this),
- m_cb2_handler(*this),
- m_irq_handler(*this),
- m_in_a(0xff),
- m_in_ca1(0),
- m_in_ca2(0),
- m_out_ca2(0),
- m_in_b(0xff),
- m_in_cb1(0),
- m_in_cb2(0),
- m_pcr(0),
- m_acr(0),
- m_ier(0),
- m_ifr(0)
+via6522_device::via6522_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_in_a_handler(*this, 0xff),
+ m_in_b_handler(*this, 0xff),
+ m_out_a_handler(*this),
+ m_out_b_handler(*this),
+ m_ca2_handler(*this),
+ m_cb1_handler(*this),
+ m_cb2_handler(*this),
+ m_irq_handler(*this),
+ m_in_a(0xff),
+ m_in_ca1(0),
+ m_in_ca2(0),
+ m_in_b(0xff),
+ m_in_cb1(0),
+ m_in_cb2(0),
+ m_pcr(0),
+ m_acr(0)
+{
+}
+
+
+//-------------------------------------------------
+// mos6522_device - constructor
+//-------------------------------------------------
+
+mos6522_device::mos6522_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, MOS6522, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// r65c22_device - constructor
+//-------------------------------------------------
+
+r65c22_device::r65c22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, R65C22, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// r65c22_device - constructor
+//-------------------------------------------------
+
+r65nc22_device::r65nc22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, R65NC22, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// w65c22s_device - constructor
+//-------------------------------------------------
+
+w65c22s_device::w65c22s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, W65C22S, tag, owner, clock)
{
}
@@ -208,30 +237,49 @@ via6522_device::via6522_device(const machine_config &mconfig, const char *tag, d
void via6522_device::device_start()
{
- m_in_a_handler.resolve();
- m_in_b_handler.resolve();
- m_out_a_handler.resolve_safe();
- m_out_b_handler.resolve_safe();
- m_cb1_handler.resolve_safe();
- m_ca2_handler.resolve_safe();
- m_cb2_handler.resolve_safe();
- m_irq_handler.resolve_safe();
-
m_t1ll = 0xf3; /* via at 0x9110 in vic20 show these values */
m_t1lh = 0xb5; /* ports are not written by kernel! */
m_t2ll = 0xff; /* taken from vice */
m_t2lh = 0xff;
+
+ m_time1 = machine().time();
+ m_time2 = machine().time();
+
+ m_t1 = timer_alloc(FUNC(via6522_device::t1_tick), this);
+ m_t2 = timer_alloc(FUNC(via6522_device::t2_tick), this);
+ m_ca2_timer = timer_alloc(FUNC(via6522_device::ca2_tick), this);
+ m_cb2_timer = machine().scheduler().timer_alloc(timer_expired_delegate());
+ m_shift_timer = timer_alloc(FUNC(via6522_device::shift_tick), this);
+ m_shift_irq_timer = timer_alloc(FUNC(via6522_device::shift_irq_tick), this);
+
+ // zerofill other
+ m_out_a = 0;
+ m_out_ca2 = 0;
+ m_ddr_a = 0;
+ m_latch_a = 0;
+ m_out_b = 0;
+ m_out_cb1 = 0;
+ m_out_cb2 = 0;
+ m_ddr_b = 0;
+ m_latch_b = 0;
+
+ m_t1cl = 0;
+ m_t1ch = 0;
+ m_t2cl = 0;
+ m_t2ch = 0;
+
m_sr = 0;
+ m_pcr = 0;
+ m_acr = 0;
+ m_ier = 0;
+ m_ifr = 0;
- m_time2 = m_time1 = machine().time();
- m_t1 = timer_alloc(TIMER_T1);
- m_t2 = timer_alloc(TIMER_T2);
- m_ca2_timer = timer_alloc(TIMER_CA2);
- m_cb2_timer = timer_alloc(TIMER_CB2);
- m_shift_timer = timer_alloc(TIMER_SHIFT);
- m_shift_irq_timer = timer_alloc(TIMER_SHIFT_IRQ);
+ m_t1_active = 0;
+ m_t1_pb7 = 0;
+ m_t2_active = 0;
+ m_shift_counter = 0;
- /* save state register */
+ // save state register
save_item(NAME(m_in_a));
save_item(NAME(m_in_ca1));
save_item(NAME(m_in_ca2));
@@ -239,6 +287,7 @@ void via6522_device::device_start()
save_item(NAME(m_out_ca2));
save_item(NAME(m_ddr_a));
save_item(NAME(m_latch_a));
+
save_item(NAME(m_in_b));
save_item(NAME(m_in_cb1));
save_item(NAME(m_in_cb2));
@@ -247,6 +296,7 @@ void via6522_device::device_start()
save_item(NAME(m_out_cb2));
save_item(NAME(m_ddr_b));
save_item(NAME(m_latch_b));
+
save_item(NAME(m_t1cl));
save_item(NAME(m_t1ch));
save_item(NAME(m_t1ll));
@@ -255,11 +305,13 @@ void via6522_device::device_start()
save_item(NAME(m_t2ch));
save_item(NAME(m_t2ll));
save_item(NAME(m_t2lh));
+
save_item(NAME(m_sr));
save_item(NAME(m_pcr));
save_item(NAME(m_acr));
save_item(NAME(m_ier));
save_item(NAME(m_ifr));
+
save_item(NAME(m_time1));
save_item(NAME(m_t1_active));
save_item(NAME(m_t1_pb7));
@@ -383,7 +435,7 @@ void via6522_device::clear_int(int data)
/*-------------------------------------------------
- via_shift
+ shift_out
-------------------------------------------------*/
void via6522_device::shift_out()
@@ -406,7 +458,7 @@ void via6522_device::shift_out()
}
else // Check for INT condition, eg the last and raising edge of the 15-0 falling/raising edges
{
- if (!SO_T2_RATE(m_acr)) // The T2 continous shifter doesn't do interrupts (mode 4)
+ if (!SO_T2_RATE(m_acr)) // The T2 continuous shifter doesn't do interrupts (mode 4)
{
if (m_shift_counter == 0 && (SO_O2_CONTROL(m_acr) || SO_T2_CONTROL(m_acr)))
{
@@ -421,13 +473,13 @@ void via6522_device::shift_out()
void via6522_device::shift_in()
{
// Only shift in data on raising edge
- if ( !(m_shift_counter & 1) )
+ if (!(m_shift_counter & 1))
{
LOGSHIFT("%s shift In SR: %02x->", tag(), m_sr);
m_sr = (m_sr << 1) | (m_in_cb2 & 1);
LOGSHIFT("%02x\n", m_sr);
- if (m_shift_counter == 0)
+ if (m_shift_counter == 0 && !SR_DISABLED(m_acr))
{
LOGINT("SHIFT in INT request ");
// set_int(INT_SR);// TODO: this interrupt is 1-2 clock cycles too early
@@ -437,94 +489,92 @@ void via6522_device::shift_in()
m_shift_counter = (m_shift_counter - 1) & 0x0f; // Count all edges
}
-void via6522_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(via6522_device::shift_irq_tick)
{
- switch (id)
- {
- case TIMER_SHIFT_IRQ: // This timer event is a delayed IRQ for improved cycle accuracy
- set_int(INT_SR); // triggered from shift_in or shift_out on the last rising edge
- m_shift_irq_timer->adjust(attotime::never); // Not needed really...
- break;
- case TIMER_SHIFT:
- LOGSHIFT("SHIFT timer event CB1 %s edge, %d\n", m_out_cb1 & 1 ? "falling" : "raising", m_shift_counter);
- m_out_cb1 ^= 1;
- m_cb1_handler(m_out_cb1);
-
- // we call shift methods for all edges
- if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
- {
- shift_out();
- }
- else if (SI_T2_CONTROL(m_acr) || SI_O2_CONTROL(m_acr))
- {
- shift_in();
- }
-
- // If in continous mode or the shifter is still shifting we re-arm the timer
- if (SO_T2_RATE(m_acr) || (m_shift_counter < 0x0f))
- {
- if (SI_O2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
- {
- m_shift_timer->adjust(clocks_to_attotime(1));
- }
- else if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SI_T2_CONTROL(m_acr))
- {
- m_shift_timer->adjust(clocks_to_attotime(m_t2ll + 2) / 2);
- }
- else // otherwise we stop it
- {
- m_shift_timer->adjust(attotime::never);
- }
- }
- break;
- case TIMER_T1:
- if (T1_CONTINUOUS (m_acr))
- {
- m_t1_pb7 = !m_t1_pb7;
- m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY));
- }
- else
- {
- m_t1_pb7 = 1;
- m_t1_active = 0;
- m_time1 = machine().time();
- }
+ // This timer event is a delayed IRQ for improved cycle accuracy
+ set_int(INT_SR); // triggered from shift_in or shift_out on the last rising edge
+ m_shift_irq_timer->adjust(attotime::never); // Not needed really...
+}
- if (T1_SET_PB7(m_acr))
- {
- output_pb();
- }
+TIMER_CALLBACK_MEMBER(via6522_device::shift_tick)
+{
+ LOGSHIFT("SHIFT timer event CB1 %s edge, %d\n", m_out_cb1 & 1 ? "falling" : "raising", m_shift_counter);
+ m_out_cb1 ^= 1;
+ m_cb1_handler(m_out_cb1);
- LOGINT("T1 INT request ");
- set_int(INT_T1);
- break;
+ // we call shift methods for all edges
+ if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
+ {
+ shift_out();
+ }
+ else if (SI_T2_CONTROL(m_acr) || SI_O2_CONTROL(m_acr))
+ {
+ shift_in();
+ }
- case TIMER_T2:
- m_t2_active = 0;
- m_time2 = machine().time();
+ // If in continuous mode or the shifter is still shifting we re-arm the timer
+ if (SO_T2_RATE(m_acr) || (m_shift_counter < 0x0f))
+ {
+ if (SI_O2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(clocks_to_attotime(1));
+ }
+ else if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SI_T2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(clocks_to_attotime(m_t2ll + 2) / 2);
+ }
+ else // otherwise we stop it
+ {
+ m_shift_timer->adjust(attotime::never);
+ }
+ }
+}
- LOGINT("T2 INT request ");
- set_int(INT_T2);
- break;
+TIMER_CALLBACK_MEMBER(via6522_device::t1_tick)
+{
+ if (T1_CONTINUOUS (m_acr))
+ {
+ m_t1_pb7 = !m_t1_pb7;
+ m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY));
+ }
+ else
+ {
+ m_t1_pb7 = 1;
+ m_t1_active = 0;
+ m_time1 = machine().time();
+ }
- case TIMER_CA2:
- m_out_ca2 = 1;
- m_ca2_handler(m_out_ca2);
- break;
+ if (T1_SET_PB7(m_acr))
+ {
+ output_pb();
}
+
+ LOGINT("T1 INT request ");
+ set_int(INT_T1);
}
-uint8_t via6522_device::input_pa()
+TIMER_CALLBACK_MEMBER(via6522_device::t2_tick)
{
- uint8_t pa = m_in_a & ~m_ddr_a;
+ m_t2_active = 0;
+ m_time2 = machine().time();
- /// TODO: REMOVE THIS
- if (m_ddr_a != 0xff && !m_in_a_handler.isnull())
- pa &= m_in_a_handler();
+ LOGINT("T2 INT request ");
+ set_int(INT_T2);
+}
- pa |= m_out_a & m_ddr_a;
+TIMER_CALLBACK_MEMBER(via6522_device::ca2_tick)
+{
+ m_out_ca2 = 1;
+ m_ca2_handler(m_out_ca2);
+}
- return pa;
+uint8_t via6522_device::input_pa()
+{
+ // HACK: port a in the real 6522 does not mask off the output pins, but you can't trust handlers.
+ if (!m_in_a_handler.isunset())
+ return (m_in_a & ~m_ddr_a & m_in_a_handler()) | (m_out_a & m_ddr_a);
+ else
+ return (m_out_a | ~m_ddr_a) & m_in_a;
}
void via6522_device::output_pa()
@@ -533,12 +583,17 @@ void via6522_device::output_pa()
m_out_a_handler(pa);
}
+uint8_t via6522_device::read_pa() const
+{
+ return (m_out_a & m_ddr_a) | ~m_ddr_a;
+}
+
uint8_t via6522_device::input_pb()
{
uint8_t pb = m_in_b & ~m_ddr_b;
/// TODO: REMOVE THIS
- if (m_ddr_b != 0xff && !m_in_b_handler.isnull())
+ if (m_ddr_b != 0xff && !m_in_b_handler.isunset())
{
pb &= m_in_b_handler();
}
@@ -561,6 +616,16 @@ void via6522_device::output_pb()
m_out_b_handler(pb);
}
+uint8_t via6522_device::read_pb() const
+{
+ uint8_t pb = (m_out_b & m_ddr_b) | ~m_ddr_b;
+
+ if (T1_SET_PB7(m_acr))
+ pb = (pb & 0x7f) | (m_t1_pb7 << 7);
+
+ return pb;
+}
+
/*-------------------------------------------------
via_r - CPU interface for VIA read
-------------------------------------------------*/
@@ -574,13 +639,13 @@ u8 via6522_device::read(offs_t offset)
{
case VIA_PB:
/* update the input */
- if (PB_LATCH_ENABLE(m_acr) == 0)
+ if ((PB_LATCH_ENABLE(m_acr) != 0) && ((m_ifr & INT_CB1) != 0))
{
- val = input_pb();
+ val = m_latch_b;
}
else
{
- val = m_latch_b;
+ val = input_pb();
}
if (!machine().side_effects_disabled())
@@ -592,13 +657,13 @@ u8 via6522_device::read(offs_t offset)
case VIA_PA:
/* update the input */
- if (PA_LATCH_ENABLE(m_acr) == 0)
+ if ((PA_LATCH_ENABLE(m_acr) != 0) && ((m_ifr & INT_CA1) != 0))
{
- val = input_pa();
+ val = m_latch_a;
}
else
{
- val = m_latch_a;
+ val = input_pa();
}
if (!machine().side_effects_disabled())
@@ -620,13 +685,13 @@ u8 via6522_device::read(offs_t offset)
case VIA_PANH:
/* update the input */
- if (PA_LATCH_ENABLE(m_acr) == 0)
+ if ((PA_LATCH_ENABLE(m_acr) != 0) && ((m_ifr & INT_CA1) != 0))
{
- val = input_pa();
+ val = m_latch_a;
}
else
{
- val = m_latch_a;
+ val = input_pa();
}
break;
@@ -718,7 +783,7 @@ u8 via6522_device::read(offs_t offset)
LOGSHIFT(" - ACR: %02x ", m_acr);
if (SI_O2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
{
- m_shift_timer->adjust(clocks_to_attotime(8) / 2); // 8 edges to start shifter from a read
+ m_shift_timer->adjust(clocks_to_attotime(7) / 2); // 7 edges to cb1 change from start of read
LOGSHIFT(" - read SR starts O2 timer ");
}
else if (SI_T2_CONTROL(m_acr) || SO_T2_CONTROL(m_acr))
@@ -827,7 +892,7 @@ void via6522_device::write(offs_t offset, u8 data)
break;
case VIA_DDRB:
- if ( data != m_ddr_b )
+ if (data != m_ddr_b)
{
m_ddr_b = data;
@@ -914,7 +979,7 @@ void via6522_device::write(offs_t offset, u8 data)
LOGSHIFT(" - ACR is: %02x ", m_acr);
if (SO_O2_CONTROL(m_acr) || SI_O2_CONTROL(m_acr))
{
- m_shift_timer->adjust(clocks_to_attotime(8) / 2); // 8 edges to start shifter from a write
+ m_shift_timer->adjust(clocks_to_attotime(6) / 2); // 6 edges to cb2 change from start of write
LOGSHIFT(" - write SR starts O2 timer");
}
else if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SI_T2_CONTROL(m_acr))
@@ -961,7 +1026,7 @@ void via6522_device::write(offs_t offset, u8 data)
if (SI_T2_CONTROL(m_acr)) LOGSHIFT("IN on T2");
if (SI_O2_CONTROL(m_acr)) LOGSHIFT("IN on O2");
if (SI_EXT_CONTROL(m_acr)) LOGSHIFT("IN on EXT");
- if (SO_T2_RATE(m_acr)) LOGSHIFT("OUT on continous T2");
+ if (SO_T2_RATE(m_acr)) LOGSHIFT("OUT on continuous T2");
if (SO_T2_CONTROL(m_acr)) LOGSHIFT("OUT on T2");
if (SO_O2_CONTROL(m_acr)) LOGSHIFT("OUT on O2");
if (SO_EXT_CONTROL(m_acr)) LOGSHIFT("OUT on EXT");
@@ -1002,12 +1067,8 @@ void via6522_device::write(offs_t offset, u8 data)
break;
case VIA_IFR:
- if (data & INT_ANY)
- {
- data = 0x7f;
- }
LOGINT("IFR INT ");
- clear_int(data);
+ clear_int(data & 0x7f);
break;
}
}
@@ -1020,7 +1081,7 @@ void via6522_device::set_pa_line(int line, int state)
m_in_a &= ~(1 << line);
}
-void via6522_device::write_pa( u8 data )
+void via6522_device::write_pa(u8 data)
{
m_in_a = data;
}
@@ -1029,7 +1090,7 @@ void via6522_device::write_pa( u8 data )
ca1_w - interface setting VIA port CA1 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_ca1 )
+void via6522_device::write_ca1(int state)
{
if (m_in_ca1 != state)
{
@@ -1061,7 +1122,7 @@ WRITE_LINE_MEMBER( via6522_device::write_ca1 )
ca2_w - interface setting VIA port CA2 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_ca2 )
+void via6522_device::write_ca2(int state)
{
if (m_in_ca2 != state)
{
@@ -1091,7 +1152,7 @@ void via6522_device::set_pb_line(int line, int state)
}
}
-void via6522_device::write_pb( u8 data )
+void via6522_device::write_pb(u8 data)
{
if (!BIT(data, 6) && BIT(m_in_b, 6))
counter2_decrement();
@@ -1103,7 +1164,7 @@ void via6522_device::write_pb( u8 data )
write_cb1 - interface setting VIA port CB1 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_cb1 )
+void via6522_device::write_cb1(int state)
{
if (m_in_cb1 != state)
{
@@ -1131,7 +1192,7 @@ WRITE_LINE_MEMBER( via6522_device::write_cb1 )
LOGSHIFT("SHIFT OUT EXT/CB1 falling edge, %d\n", m_shift_counter);
shift_out();
}
- else if (SI_EXT_CONTROL(m_acr))
+ else if (SI_EXT_CONTROL(m_acr) || SR_DISABLED(m_acr))
{
LOGSHIFT("SHIFT IN EXT/CB1 raising edge, %d\n", m_shift_counter);
shift_in();
@@ -1144,7 +1205,7 @@ WRITE_LINE_MEMBER( via6522_device::write_cb1 )
write_cb2 - interface setting VIA port CB2 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_cb2 )
+void via6522_device::write_cb2(int state)
{
if (m_in_cb2 != state)
{
diff --git a/src/devices/machine/6522via.h b/src/devices/machine/6522via.h
index 1a705ab6a29..6a2d66ab76b 100644
--- a/src/devices/machine/6522via.h
+++ b/src/devices/machine/6522via.h
@@ -11,6 +11,29 @@
Written by Mathis Rosenhauer
+**********************************************************************
+ _____ _____
+ Vss 1 |* \_/ | 40 CA1
+ PA0 2 | | 39 CA2
+ PA1 3 | | 38 RS0
+ PA2 4 | | 37 RS1
+ PA3 5 | | 36 RS2
+ PA4 6 | | 35 RS3
+ PA5 7 | | 34 _RES
+ PA6 8 | | 33 D0
+ PA7 9 | | 32 D1
+ PB0 10 | | 31 D2
+ PB1 11 | MCS6522 | 30 D3
+ PB2 12 | | 29 D4
+ PB3 13 | | 28 D5
+ PB4 14 | | 27 D6
+ PB5 15 | | 26 D7
+ PB6 16 | | 25 ϕ2
+ PB7 17 | | 24 CS1
+ CB1 18 | | 23 _CS2
+ CB2 19 | | 22 R/_W
+ Vcc 20 |_____________| 21 _IRQ
+
**********************************************************************/
#ifndef MAME_MACHINE_6522VIA_H
@@ -48,9 +71,6 @@ public:
VIA_PANH = 15
};
- // construction/destruction
- via6522_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
// TODO: REMOVE THESE
auto readpa_handler() { return m_in_a_handler.bind(); }
auto readpb_handler() { return m_in_b_handler.bind(); }
@@ -77,7 +97,7 @@ public:
void write_pa5(int state) { set_pa_line(5, state); }
void write_pa6(int state) { set_pa_line(6, state); }
void write_pa7(int state) { set_pa_line(7, state); }
- void write_pa( u8 data );
+ void write_pa(u8 data);
void write_ca1(int state);
void write_ca2(int state);
@@ -89,25 +109,28 @@ public:
void write_pb5(int state) { set_pb_line(5, state); }
void write_pb6(int state) { set_pb_line(6, state); }
void write_pb7(int state) { set_pb_line(7, state); }
- void write_pb( u8 data );
+ void write_pb(u8 data);
void write_cb1(int state);
void write_cb2(int state);
+ uint8_t read_pa() const;
+ uint8_t read_pb() const;
+
protected:
+ // construction/destruction
+ via6522_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
-private:
- static constexpr device_timer_id TIMER_SHIFT = 0;
- static constexpr device_timer_id TIMER_T1 = 1;
- static constexpr device_timer_id TIMER_T2 = 2;
- static constexpr device_timer_id TIMER_CA2 = 3;
- static constexpr device_timer_id TIMER_SHIFT_IRQ = 4;
- static constexpr device_timer_id TIMER_CB2 = 5;
+ TIMER_CALLBACK_MEMBER(shift_irq_tick);
+ TIMER_CALLBACK_MEMBER(shift_tick);
+ TIMER_CALLBACK_MEMBER(t1_tick);
+ TIMER_CALLBACK_MEMBER(t2_tick);
+ TIMER_CALLBACK_MEMBER(ca2_tick);
+private:
uint16_t get_counter1_value();
void counter2_decrement();
@@ -184,9 +207,47 @@ private:
uint8_t m_shift_counter;
};
+// ======================> mos6522_device
+
+class mos6522_device : public via6522_device
+{
+public:
+ // construction/destruction
+ mos6522_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+// ======================> r65c22_device
+
+class r65c22_device : public via6522_device
+{
+public:
+ // construction/destruction
+ r65c22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+// ======================> r65nc22_device
+
+class r65nc22_device : public via6522_device
+{
+public:
+ // construction/destruction
+ r65nc22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+// ======================> w65c22s_device
+
+class w65c22s_device : public via6522_device
+{
+public:
+ // construction/destruction
+ w65c22s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
-// device type definition
-DECLARE_DEVICE_TYPE(VIA6522, via6522_device)
+// device type declarations
+DECLARE_DEVICE_TYPE(MOS6522, mos6522_device)
+DECLARE_DEVICE_TYPE(R65C22, r65c22_device)
+DECLARE_DEVICE_TYPE(R65NC22, r65nc22_device)
+DECLARE_DEVICE_TYPE(W65C22S, w65c22s_device)
#endif // MAME_MACHINE_6522VIA_H
diff --git a/src/devices/machine/6525tpi.cpp b/src/devices/machine/6525tpi.cpp
index 83d28fc0355..cffb9ba5f50 100644
--- a/src/devices/machine/6525tpi.cpp
+++ b/src/devices/machine/6525tpi.cpp
@@ -106,14 +106,14 @@
DEFINE_DEVICE_TYPE(TPI6525, tpi6525_device, "tpi6525", "6525 TPI")
-tpi6525_device::tpi6525_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, TPI6525, tag, owner, clock),
+tpi6525_device::tpi6525_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, TPI6525, tag, owner, clock),
m_out_irq_cb(*this),
- m_in_pa_cb(*this),
+ m_in_pa_cb(*this, 0xff),
m_out_pa_cb(*this),
- m_in_pb_cb(*this),
+ m_in_pb_cb(*this, 0xff),
m_out_pb_cb(*this),
- m_in_pc_cb(*this),
+ m_in_pc_cb(*this, 0xff),
m_out_pc_cb(*this),
m_out_ca_cb(*this),
m_out_cb_cb(*this),
@@ -144,16 +144,10 @@ tpi6525_device::tpi6525_device(const machine_config &mconfig, const char *tag, d
void tpi6525_device::device_start()
{
- // resolve callbacks
- m_out_irq_cb.resolve_safe();
- m_in_pa_cb.resolve();
- m_out_pa_cb.resolve_safe();
- m_in_pb_cb.resolve();
- m_out_pb_cb.resolve_safe();
- m_in_pc_cb.resolve();
- m_out_pc_cb.resolve_safe();
- m_out_ca_cb.resolve_safe();
- m_out_cb_cb.resolve_safe();
+ /* setup some initial values */
+ m_in_a = 0xff;
+ m_in_b = 0xff;
+ m_in_c = 0xff;
/* register for state saving */
save_item(NAME(m_port_a));
@@ -179,10 +173,6 @@ void tpi6525_device::device_start()
void tpi6525_device::device_reset()
{
- /* setup some initial values */
- m_in_a = 0xff;
- m_in_b = 0xff;
- m_in_c = 0xff;
}
@@ -216,7 +206,7 @@ void tpi6525_device::clear_interrupt()
}
-WRITE_LINE_MEMBER( tpi6525_device::i0_w )
+void tpi6525_device::i0_w(int state)
{
if (INTERRUPT_MODE && (state != m_irq_level[0]))
{
@@ -231,7 +221,7 @@ WRITE_LINE_MEMBER( tpi6525_device::i0_w )
}
-WRITE_LINE_MEMBER( tpi6525_device::i1_w )
+void tpi6525_device::i1_w(int state)
{
if (INTERRUPT_MODE && (state != m_irq_level[1]))
{
@@ -246,7 +236,7 @@ WRITE_LINE_MEMBER( tpi6525_device::i1_w )
}
-WRITE_LINE_MEMBER( tpi6525_device::i2_w )
+void tpi6525_device::i2_w(int state)
{
if (INTERRUPT_MODE && (state != m_irq_level[2]))
{
@@ -261,7 +251,7 @@ WRITE_LINE_MEMBER( tpi6525_device::i2_w )
}
-WRITE_LINE_MEMBER( tpi6525_device::i3_w )
+void tpi6525_device::i3_w(int state)
{
if (INTERRUPT_MODE && (state != m_irq_level[3]))
{
@@ -278,7 +268,7 @@ WRITE_LINE_MEMBER( tpi6525_device::i3_w )
}
-WRITE_LINE_MEMBER( tpi6525_device::i4_w )
+void tpi6525_device::i4_w(int state)
{
if (INTERRUPT_MODE && (state != m_irq_level[4]) )
{
@@ -298,7 +288,7 @@ uint8_t tpi6525_device::pa_r()
{
uint8_t data = m_in_a;
- if (!m_in_pa_cb.isnull())
+ if (!m_in_pa_cb.isunset())
data = m_in_pa_cb();
data = (data & ~m_ddr_a) | (m_ddr_a & m_port_a);
@@ -317,7 +307,7 @@ uint8_t tpi6525_device::pb_r()
{
uint8_t data = m_in_b;
- if (!m_in_pb_cb.isnull())
+ if (!m_in_pb_cb.isunset())
data = m_in_pb_cb();
data = (data & ~m_ddr_b) | (m_ddr_b & m_port_b);
@@ -336,7 +326,7 @@ uint8_t tpi6525_device::pc_r()
{
uint8_t data = m_in_c;
- if (!m_in_pc_cb.isnull())
+ if (!m_in_pc_cb.isunset())
data &= m_in_pc_cb();
data = (data & ~m_ddr_c) | (m_ddr_c & m_port_c);
@@ -360,7 +350,7 @@ uint8_t tpi6525_device::read(offs_t offset)
case 0:
data = m_in_a;
- if (!m_in_pa_cb.isnull())
+ if (!m_in_pa_cb.isunset())
data &= m_in_pa_cb(0);
data = (data & ~m_ddr_a) | (m_ddr_a & m_port_a);
@@ -370,7 +360,7 @@ uint8_t tpi6525_device::read(offs_t offset)
case 1:
data = m_in_b;
- if (!m_in_pb_cb.isnull())
+ if (!m_in_pb_cb.isunset())
data &= m_in_pb_cb(0);
data = (data & ~m_ddr_b) | (m_ddr_b & m_port_b);
@@ -395,7 +385,7 @@ uint8_t tpi6525_device::read(offs_t offset)
{
data = m_in_c;
- if (!m_in_pc_cb.isnull())
+ if (!m_in_pc_cb.isunset())
data &= m_in_pc_cb(0);
data = (data & ~m_ddr_c) | (m_ddr_c & m_port_c);
diff --git a/src/devices/machine/6525tpi.h b/src/devices/machine/6525tpi.h
index 4052662d50a..52fc12dd359 100644
--- a/src/devices/machine/6525tpi.h
+++ b/src/devices/machine/6525tpi.h
@@ -56,11 +56,11 @@ public:
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( i0_w );
- DECLARE_WRITE_LINE_MEMBER( i1_w );
- DECLARE_WRITE_LINE_MEMBER( i2_w );
- DECLARE_WRITE_LINE_MEMBER( i3_w );
- DECLARE_WRITE_LINE_MEMBER( i4_w );
+ void i0_w(int state);
+ void i1_w(int state);
+ void i2_w(int state);
+ void i3_w(int state);
+ void i4_w(int state);
uint8_t pa_r();
uint8_t pb_r();
@@ -69,14 +69,14 @@ public:
void pb_w(uint8_t data);
void pc_w(uint8_t data);
- WRITE_LINE_MEMBER( pb0_w ) { port_line_w(m_in_b, 0, state); }
- WRITE_LINE_MEMBER( pb1_w ) { port_line_w(m_in_b, 1, state); }
- WRITE_LINE_MEMBER( pb2_w ) { port_line_w(m_in_b, 2, state); }
- WRITE_LINE_MEMBER( pb3_w ) { port_line_w(m_in_b, 3, state); }
- WRITE_LINE_MEMBER( pb4_w ) { port_line_w(m_in_b, 4, state); }
- WRITE_LINE_MEMBER( pb5_w ) { port_line_w(m_in_b, 5, state); }
- WRITE_LINE_MEMBER( pb6_w ) { port_line_w(m_in_b, 6, state); }
- WRITE_LINE_MEMBER( pb7_w ) { port_line_w(m_in_b, 7, state); }
+ void pb0_w(int state) { port_line_w(m_in_b, 0, state); }
+ void pb1_w(int state) { port_line_w(m_in_b, 1, state); }
+ void pb2_w(int state) { port_line_w(m_in_b, 2, state); }
+ void pb3_w(int state) { port_line_w(m_in_b, 3, state); }
+ void pb4_w(int state) { port_line_w(m_in_b, 4, state); }
+ void pb5_w(int state) { port_line_w(m_in_b, 5, state); }
+ void pb6_w(int state) { port_line_w(m_in_b, 6, state); }
+ void pb7_w(int state) { port_line_w(m_in_b, 7, state); }
uint8_t get_ddr_a();
uint8_t get_ddr_b();
diff --git a/src/devices/machine/6532riot.cpp b/src/devices/machine/6532riot.cpp
deleted file mode 100644
index 1d4e4845e68..00000000000
--- a/src/devices/machine/6532riot.cpp
+++ /dev/null
@@ -1,515 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
-
- RIOT 6532 emulation
-
-The timer seems to follow these rules:
-- When the timer flag changes from 0 to 1 the timer continues to count
- down at a 1 cycle rate.
-- When the timer is being read or written the timer flag is reset.
-- When the timer flag is set and the timer contents are 0, the counting
- stops.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "6532riot.h"
-
-
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-// device type definition
-DEFINE_DEVICE_TYPE(RIOT6532, riot6532_device, "riot6532", "6532 RIOT")
-
-enum
-{
- TIMER_IDLE,
- TIMER_COUNTING,
- TIMER_FINISHING
-};
-
-#define TIMER_FLAG 0x80
-#define PA7_FLAG 0x40
-
-
-
-/***************************************************************************
- INTERNAL FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- update_irqstate - update the IRQ state
- based on interrupt enables
--------------------------------------------------*/
-
-void riot6532_device::update_irqstate()
-{
- int irq = (m_irqstate & m_irqenable) ? ASSERT_LINE : CLEAR_LINE;
-
- if (m_irq != irq)
- {
- m_irq_cb(irq);
- m_irq = irq;
- }
-}
-
-
-/*-------------------------------------------------
- apply_ddr - combine inputs and outputs
- according to the DDR
--------------------------------------------------*/
-
-uint8_t riot6532_device::apply_ddr(const riot6532_port *port)
-{
- return (port->m_out & port->m_ddr) | (port->m_in & ~port->m_ddr);
-}
-
-
-/*-------------------------------------------------
- update_pa7_state - see if PA7 has changed
- and signal appropriately
--------------------------------------------------*/
-
-void riot6532_device::update_pa7_state()
-{
- uint8_t data = apply_ddr(&m_port[0]) & 0x80;
-
- /* if the state changed in the correct direction, set the PA7 flag and update IRQs */
- if ((m_pa7prev ^ data) && (m_pa7dir ^ data) == 0)
- {
- m_irqstate |= PA7_FLAG;
- update_irqstate();
- }
- m_pa7prev = data;
-}
-
-
-/*-------------------------------------------------
- get_timer - return the current timer value
--------------------------------------------------*/
-
-uint8_t riot6532_device::get_timer()
-{
- /* if idle, return 0 */
- if (m_timerstate == TIMER_IDLE)
- {
- return 0;
- }
-
- /* if counting, return the number of ticks remaining */
- else if (m_timerstate == TIMER_COUNTING)
- {
- return m_timer->remaining().as_ticks(clock()) >> m_timershift;
- }
-
- /* if finishing, return the number of ticks without the shift */
- else
- {
- return m_timer->remaining().as_ticks(clock());
- }
-}
-
-
-
-void riot6532_device::timer_end()
-{
- assert(m_timerstate != TIMER_IDLE);
-
- /* if we finished counting, switch to the finishing state */
- if(m_timerstate == TIMER_COUNTING)
- {
- m_timerstate = TIMER_FINISHING;
- m_timer->adjust(attotime::from_ticks(256, clock()));
-
- /* signal timer IRQ as well */
- m_irqstate |= TIMER_FLAG;
- update_irqstate();
- }
-
- /* if we finished finishing, keep spinning */
- else if (m_timerstate == TIMER_FINISHING)
- {
- m_timer->adjust(attotime::from_ticks(256, clock()));
- }
-}
-
-
-
-/***************************************************************************
- I/O ACCESS
-***************************************************************************/
-
-/*-------------------------------------------------
- riot6532_w - master I/O write access
--------------------------------------------------*/
-
-void riot6532_device::write(offs_t offset, uint8_t data)
-{
- reg_w(offset, data);
-}
-
-void riot6532_device::reg_w(uint8_t offset, uint8_t data)
-{
- /* if A4 == 1 and A2 == 1, we are writing to the timer */
- if ((offset & 0x14) == 0x14)
- {
- static const uint8_t timershift[4] = { 0, 3, 6, 10 };
- attotime curtime = machine().time();
- int64_t target;
-
- /* A0-A1 contain the timer divisor */
- m_timershift = timershift[offset & 3];
-
- /* A3 contains the timer IRQ enable */
- if (offset & 8)
- m_irqenable |= TIMER_FLAG;
- else
- m_irqenable &= ~TIMER_FLAG;
-
- /* writes here clear the timer flag */
- if (m_timerstate != TIMER_FINISHING || get_timer() != 0xff)
- {
- m_irqstate &= ~TIMER_FLAG;
- }
- update_irqstate();
-
- /* update the timer */
- m_timerstate = TIMER_COUNTING;
- target = curtime.as_ticks(clock()) + 1 + (data << m_timershift);
- m_timer->adjust(attotime::from_ticks(target, clock()) - curtime);
- }
-
- /* if A4 == 0 and A2 == 1, we are writing to the edge detect control */
- else if ((offset & 0x14) == 0x04)
- {
- /* A1 contains the A7 IRQ enable */
- if (offset & 2)
- {
- m_irqenable |= PA7_FLAG;
- }
- else
- {
- m_irqenable &= ~PA7_FLAG;
- }
-
- /* A0 specifies the edge detect direction: 0=negative, 1=positive */
- m_pa7dir = (offset & 1) << 7;
- }
-
- /* if A4 == anything and A2 == 0, we are writing to the I/O section */
- else
- {
- /* A1 selects the port */
- riot6532_port *port = &m_port[BIT(offset, 1)];
-
- /* if A0 == 1, we are writing to the port's DDR */
- if (offset & 1)
- {
- port->m_ddr = data;
- }
-
- /* if A0 == 0, we are writing to the port's output */
- else
- {
- port->m_out = data;
- (*port->m_out_cb)((offs_t)0, data);
- }
-
- /* writes to port A need to update the PA7 state */
- if (port == &m_port[0])
- {
- update_pa7_state();
- }
- }
-}
-
-
-/*-------------------------------------------------
- riot6532_r - master I/O read access
--------------------------------------------------*/
-
-uint8_t riot6532_device::read(offs_t offset)
-{
- return reg_r(offset, machine().side_effects_disabled());
-}
-
-uint8_t riot6532_device::reg_r(uint8_t offset, bool debugger_access)
-{
- uint8_t val;
-
- /* if A2 == 1 and A0 == 1, we are reading interrupt flags */
- if ((offset & 0x05) == 0x05)
- {
- val = m_irqstate;
-
- if ( ! debugger_access )
- {
- /* implicitly clears the PA7 flag */
- m_irqstate &= ~PA7_FLAG;
- update_irqstate();
- }
- }
-
- /* if A2 == 1 and A0 == 0, we are reading the timer */
- else if ((offset & 0x05) == 0x04)
- {
- val = get_timer();
-
- if ( ! debugger_access )
- {
- /* A3 contains the timer IRQ enable */
- if (offset & 8)
- {
- m_irqenable |= TIMER_FLAG;
- }
- else
- {
- m_irqenable &= ~TIMER_FLAG;
- }
-
- /* implicitly clears the timer flag */
- if (m_timerstate != TIMER_FINISHING || val != 0xff)
- {
- m_irqstate &= ~TIMER_FLAG;
- }
- update_irqstate();
- }
- }
-
- /* if A2 == 0 and A0 == anything, we are reading from ports */
- else
- {
- /* A1 selects the port */
- riot6532_port *port = &m_port[BIT(offset, 1)];
-
- /* if A0 == 1, we are reading the port's DDR */
- if (offset & 1)
- {
- val = port->m_ddr;
- }
-
- /* if A0 == 0, we are reading the port as an input */
- else
- {
- /* call the input callback if it exists */
- if (!(*port->m_in_cb).isnull())
- {
- port->m_in = (*port->m_in_cb)(0);
-
- /* changes to port A need to update the PA7 state */
- if (port == &m_port[0])
- {
- if (!debugger_access)
- {
- update_pa7_state();
- }
- }
- }
-
- /* apply the DDR to the result */
- val = apply_ddr(port);
- }
- }
- return val;
-}
-
-
-/*-------------------------------------------------
- porta_in_set - set port A input value
--------------------------------------------------*/
-
-void riot6532_device::porta_in_set(uint8_t data, uint8_t mask)
-{
- m_port[0].m_in = (m_port[0].m_in & ~mask) | (data & mask);
- update_pa7_state();
-}
-
-
-/*-------------------------------------------------
- portb_in_set - set port B input value
--------------------------------------------------*/
-
-void riot6532_device::portb_in_set(uint8_t data, uint8_t mask)
-{
- m_port[1].m_in = (m_port[1].m_in & ~mask) | (data & mask);
-}
-
-
-/*-------------------------------------------------
- porta_in_get - return port A input value
--------------------------------------------------*/
-
-uint8_t riot6532_device::porta_in_get()
-{
- return m_port[0].m_in;
-}
-
-
-/*-------------------------------------------------
- portb_in_get - return port B input value
--------------------------------------------------*/
-
-uint8_t riot6532_device::portb_in_get()
-{
- return m_port[1].m_in;
-}
-
-
-/*-------------------------------------------------
- porta_in_get - return port A output value
--------------------------------------------------*/
-
-uint8_t riot6532_device::porta_out_get()
-{
- return m_port[0].m_out;
-}
-
-
-/*-------------------------------------------------
- portb_in_get - return port B output value
--------------------------------------------------*/
-
-uint8_t riot6532_device::portb_out_get()
-{
- return m_port[1].m_out;
-}
-
-
-//-------------------------------------------------
-// paN_w - write Port A lines individually
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER(riot6532_device::pa0_w) { porta_in_set(state ? 0x01 : 0x00, 0x01); }
-WRITE_LINE_MEMBER(riot6532_device::pa1_w) { porta_in_set(state ? 0x02 : 0x00, 0x02); }
-WRITE_LINE_MEMBER(riot6532_device::pa2_w) { porta_in_set(state ? 0x04 : 0x00, 0x04); }
-WRITE_LINE_MEMBER(riot6532_device::pa3_w) { porta_in_set(state ? 0x08 : 0x00, 0x08); }
-WRITE_LINE_MEMBER(riot6532_device::pa4_w) { porta_in_set(state ? 0x10 : 0x00, 0x10); }
-WRITE_LINE_MEMBER(riot6532_device::pa5_w) { porta_in_set(state ? 0x20 : 0x00, 0x20); }
-WRITE_LINE_MEMBER(riot6532_device::pa6_w) { porta_in_set(state ? 0x40 : 0x00, 0x40); }
-WRITE_LINE_MEMBER(riot6532_device::pa7_w) { porta_in_set(state ? 0x80 : 0x00, 0x80); }
-
-//-------------------------------------------------
-// pbN_w - write Port B lines individually
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER(riot6532_device::pb0_w) { portb_in_set(state ? 0x01 : 0x00, 0x01); }
-WRITE_LINE_MEMBER(riot6532_device::pb1_w) { portb_in_set(state ? 0x02 : 0x00, 0x02); }
-WRITE_LINE_MEMBER(riot6532_device::pb2_w) { portb_in_set(state ? 0x04 : 0x00, 0x04); }
-WRITE_LINE_MEMBER(riot6532_device::pb3_w) { portb_in_set(state ? 0x08 : 0x00, 0x08); }
-WRITE_LINE_MEMBER(riot6532_device::pb4_w) { portb_in_set(state ? 0x10 : 0x00, 0x10); }
-WRITE_LINE_MEMBER(riot6532_device::pb5_w) { portb_in_set(state ? 0x20 : 0x00, 0x20); }
-WRITE_LINE_MEMBER(riot6532_device::pb6_w) { portb_in_set(state ? 0x40 : 0x00, 0x40); }
-WRITE_LINE_MEMBER(riot6532_device::pb7_w) { portb_in_set(state ? 0x80 : 0x00, 0x80); }
-
-
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
-
-//-------------------------------------------------
-// riot6532_device - constructor
-//-------------------------------------------------
-
-riot6532_device::riot6532_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, RIOT6532, tag, owner, clock),
- m_in_pa_cb(*this),
- m_out_pa_cb(*this),
- m_in_pb_cb(*this),
- m_out_pb_cb(*this),
- m_irq_cb(*this),
- m_irqstate(0),
- m_irqenable(0),
- m_irq(CLEAR_LINE),
- m_pa7dir(0),
- m_pa7prev(0),
- m_timershift(0),
- m_timerstate(0),
- m_timer(nullptr)
-{
- memset(m_port, 0x00, sizeof(m_port));
-}
-
-/*-------------------------------------------------
- device_start - device-specific startup
--------------------------------------------------*/
-
-void riot6532_device::device_start()
-{
- /* resolve callbacks */
- m_in_pa_cb.resolve();
- m_port[0].m_in_cb = &m_in_pa_cb;
- m_out_pa_cb.resolve_safe();
- m_port[0].m_out_cb = &m_out_pa_cb;
- m_in_pb_cb.resolve();
- m_port[1].m_in_cb = &m_in_pb_cb;
- m_out_pb_cb.resolve_safe();
- m_port[1].m_out_cb = &m_out_pb_cb;
- m_irq_cb.resolve_safe();
-
- /* allocate timers */
- m_timer = timer_alloc(TIMER_END_CB);
-
- /* register for save states */
- save_item(NAME(m_port[0].m_in));
- save_item(NAME(m_port[0].m_out));
- save_item(NAME(m_port[0].m_ddr));
- save_item(NAME(m_port[1].m_in));
- save_item(NAME(m_port[1].m_out));
- save_item(NAME(m_port[1].m_ddr));
-
- save_item(NAME(m_irqstate));
- save_item(NAME(m_irqenable));
- save_item(NAME(m_irq));
-
- save_item(NAME(m_pa7dir));
- save_item(NAME(m_pa7prev));
-
- save_item(NAME(m_timershift));
- save_item(NAME(m_timerstate));
-}
-
-
-
-/*-------------------------------------------------
- device_reset - device-specific reset
--------------------------------------------------*/
-
-void riot6532_device::device_reset()
-{
- /* reset I/O states */
- m_port[0].m_in = 0;
- m_port[0].m_out = 0;
- m_port[0].m_ddr = 0;
- m_port[1].m_in = 0;
- m_port[1].m_out = 0;
- m_port[1].m_ddr = 0;
-
- /* reset IRQ states */
- m_irqenable = 0;
- m_irqstate = 0;
- update_irqstate();
-
- /* reset PA7 states */
- m_pa7dir = 0;
- m_pa7prev = 0;
-
- /* reset timer states */
- m_timershift = 10;
- m_timerstate = TIMER_COUNTING;
- m_timer->adjust(attotime::from_ticks(256 << m_timershift, clock()));
-}
-
-void riot6532_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch (id)
- {
- case TIMER_END_CB:
- timer_end();
- break;
- default:
- throw emu_fatalerror("Unknown id in riot6532_device::device_timer");
- }
-}
diff --git a/src/devices/machine/6532riot.h b/src/devices/machine/6532riot.h
deleted file mode 100644
index e551247d7fa..00000000000
--- a/src/devices/machine/6532riot.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
-
- RIOT 6532 emulation
-
-***************************************************************************/
-
-#pragma once
-
-#ifndef __RIOT6532_H__
-#define __RIOT6532_H__
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-
-// ======================> riot6532_device
-
-class riot6532_device : public device_t
-{
-public:
- // construction/destruction
- riot6532_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto in_pa_callback() { return m_in_pa_cb.bind(); }
- auto out_pa_callback() { return m_out_pa_cb.bind(); }
- auto in_pb_callback() { return m_in_pb_cb.bind(); }
- auto out_pb_callback() { return m_out_pb_cb.bind(); }
- auto irq_callback() { return m_irq_cb.bind(); }
-
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
-
- uint8_t reg_r(uint8_t offset, bool debugger_access = false);
- void reg_w(uint8_t offset, uint8_t data);
-
- void porta_in_set(uint8_t data, uint8_t mask);
- void portb_in_set(uint8_t data, uint8_t mask);
-
- DECLARE_WRITE_LINE_MEMBER(pa0_w);
- DECLARE_WRITE_LINE_MEMBER(pa1_w);
- DECLARE_WRITE_LINE_MEMBER(pa2_w);
- DECLARE_WRITE_LINE_MEMBER(pa3_w);
- DECLARE_WRITE_LINE_MEMBER(pa4_w);
- DECLARE_WRITE_LINE_MEMBER(pa5_w);
- DECLARE_WRITE_LINE_MEMBER(pa6_w);
- DECLARE_WRITE_LINE_MEMBER(pa7_w);
- DECLARE_WRITE_LINE_MEMBER(pb0_w);
- DECLARE_WRITE_LINE_MEMBER(pb1_w);
- DECLARE_WRITE_LINE_MEMBER(pb2_w);
- DECLARE_WRITE_LINE_MEMBER(pb3_w);
- DECLARE_WRITE_LINE_MEMBER(pb4_w);
- DECLARE_WRITE_LINE_MEMBER(pb5_w);
- DECLARE_WRITE_LINE_MEMBER(pb6_w);
- DECLARE_WRITE_LINE_MEMBER(pb7_w);
-
- uint8_t porta_in_get();
- uint8_t portb_in_get();
-
- uint8_t porta_out_get();
- uint8_t portb_out_get();
-
- void timer_end();
-
-protected:
- class riot6532_port
- {
- public:
- uint8_t m_in;
- uint8_t m_out;
- uint8_t m_ddr;
- devcb_read8 *m_in_cb;
- devcb_write8 *m_out_cb;
- };
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void device_post_load() override { }
- virtual void device_clock_changed() override { }
-
-
-private:
- void update_irqstate();
- uint8_t apply_ddr(const riot6532_port *port);
- void update_pa7_state();
- uint8_t get_timer();
-
- riot6532_port m_port[2];
-
- devcb_read8 m_in_pa_cb;
- devcb_write8 m_out_pa_cb;
- devcb_read8 m_in_pb_cb;
- devcb_write8 m_out_pb_cb;
- devcb_write_line m_irq_cb;
-
- uint8_t m_irqstate;
- uint8_t m_irqenable;
- int m_irq;
-
- uint8_t m_pa7dir; /* 0x80 = high-to-low, 0x00 = low-to-high */
- uint8_t m_pa7prev;
-
- uint8_t m_timershift;
- uint8_t m_timerstate;
- emu_timer * m_timer;
-
- enum
- {
- TIMER_END_CB
- };
-};
-
-
-// device type definition
-DECLARE_DEVICE_TYPE(RIOT6532, riot6532_device)
-
-#endif
diff --git a/src/devices/machine/68153bim.cpp b/src/devices/machine/68153bim.cpp
index 20d63ef959e..85758b13b56 100644
--- a/src/devices/machine/68153bim.cpp
+++ b/src/devices/machine/68153bim.cpp
@@ -27,18 +27,16 @@
#include "68153bim.h"
#include "cpu/m68000/m68000.h"
-//#define LOG_GENERAL (1U << 0)
-#define LOG_SETUP (1U << 1)
-#define LOG_INT (1U << 2)
-#define LOG_READ (1U << 3)
-#define LOG_IACK (1U << 4)
+#define LOG_SETUP (1U << 1)
+#define LOG_INT (1U << 2)
+#define LOG_READ (1U << 3)
+#define LOG_IACK (1U << 4)
//#define VERBOSE ( LOG_SETUP | LOG_INT | LOG_IACK | LOG_GENERAL | LOG_READ)
//#define LOG_OUTPUT_FUNC printf
#include "logmacro.h"
-//#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__)
#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__)
#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__)
@@ -88,7 +86,7 @@ bim68153_device::bim68153_device(const machine_config &mconfig, device_type type
, m_out_int_cb(*this)
, m_out_intal0_cb(*this)
, m_out_intal1_cb(*this)
- , m_out_iackout_cb(*this)
+ , m_out_iackout_cb(*this, 0)
, m_iackin(ASSERT_LINE)
, m_irq_level(0)
{
@@ -128,11 +126,6 @@ int bim68153_device::get_channel_index(bim68153_channel *ch)
void bim68153_device::device_start()
{
LOG("%s\n", FUNCNAME);
- // resolve callbacks
- m_out_int_cb.resolve_safe();
- m_out_intal0_cb.resolve_safe();
- m_out_intal1_cb.resolve_safe();
- m_out_iackout_cb.resolve_safe(0);
}
//-------------------------------------------------
@@ -320,7 +313,7 @@ void bim68153_device::write(offs_t offset, uint8_t data)
bim68153_channel::bim68153_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, MC68153_CHANNEL, tag, owner, clock)
- , m_out_iack_cb(*this)
+ , m_out_iack_cb(*this, 0)
, m_int_state(NONE)
, m_control(0)
, m_vector(0)
@@ -343,9 +336,6 @@ void bim68153_channel::device_start()
save_item(NAME(m_control));
save_item(NAME(m_vector));
save_item(NAME(m_int_state));
-
- // Resolve callbacks
- m_out_iack_cb.resolve_safe(0);
}
@@ -364,7 +354,7 @@ void bim68153_channel::device_reset()
}
/* Trigger an interrupt */
-WRITE_LINE_MEMBER( bim68153_channel::int_w )
+void bim68153_channel::int_w(int state)
{
LOGINT("%s Ch %d: %s\n",FUNCNAME, m_index, state == CLEAR_LINE ? "Cleared" : "Asserted");
if (state == ASSERT_LINE)
diff --git a/src/devices/machine/68153bim.h b/src/devices/machine/68153bim.h
index 124870b8194..5a8dd59428e 100644
--- a/src/devices/machine/68153bim.h
+++ b/src/devices/machine/68153bim.h
@@ -59,7 +59,7 @@ public:
void do_bimreg_control_w(uint8_t data);
void do_bimreg_vector_w(uint8_t vector);
- DECLARE_WRITE_LINE_MEMBER( int_w );
+ void int_w(int state);
devcb_read8 m_out_iack_cb;
uint8_t m_int_state;
@@ -126,11 +126,11 @@ public:
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( iackin_w ) { m_iackin = state; }
- DECLARE_WRITE_LINE_MEMBER( int0_w ) { m_chn[CHN_0]->int_w(state); }
- DECLARE_WRITE_LINE_MEMBER( int1_w ) { m_chn[CHN_1]->int_w(state); }
- DECLARE_WRITE_LINE_MEMBER( int2_w ) { m_chn[CHN_2]->int_w(state); }
- DECLARE_WRITE_LINE_MEMBER( int3_w ) { m_chn[CHN_3]->int_w(state); }
+ void iackin_w(int state) { m_iackin = state; }
+ void int0_w(int state) { m_chn[CHN_0]->int_w(state); }
+ void int1_w(int state) { m_chn[CHN_1]->int_w(state); }
+ void int2_w(int state) { m_chn[CHN_2]->int_w(state); }
+ void int3_w(int state) { m_chn[CHN_3]->int_w(state); }
protected:
bim68153_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
diff --git a/src/devices/machine/6821pia.cpp b/src/devices/machine/6821pia.cpp
index 169dfa1c604..c7233fc5845 100644
--- a/src/devices/machine/6821pia.cpp
+++ b/src/devices/machine/6821pia.cpp
@@ -13,16 +13,21 @@
// MACROS
//**************************************************************************
-#define LOG_GENERAL 0x01
-#define LOG_SETUP 0x02
-#define LOG_CA1 0x08
+#define LOG_SETUP (1U << 1)
+#define LOG_CTL_READ (1U << 2)
+#define LOG_CA1 (1U << 3)
+#define LOG_CB1 (1U << 4)
//#define VERBOSE (LOG_SETUP | LOG_GENERAL | LOG_CA1)
//#define LOG_OUTPUT_STREAM std::cout
+#define VERBOSE (0)
+
#include "logmacro.h"
-#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
-#define LOGCA1(...) LOGMASKED(LOG_CA1, __VA_ARGS__)
+#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
+#define LOGCTLR(...) LOGMASKED(LOG_CTL_READ, __VA_ARGS__)
+#define LOGCA1(...) LOGMASKED(LOG_CA1, __VA_ARGS__)
+#define LOGCB1(...) LOGMASKED(LOG_CB1, __VA_ARGS__)
#define PIA_IRQ1 (0x80)
#define PIA_IRQ2 (0x40)
@@ -40,29 +45,30 @@ DEFINE_DEVICE_TYPE(PIA6821, pia6821_device, "pia6821", "6821 PIA")
// pia6821_device - constructor
//-------------------------------------------------
-pia6821_device::pia6821_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, PIA6821, tag, owner, clock),
- m_in_a_handler(*this),
- m_in_b_handler(*this),
- m_in_ca1_handler(*this),
- m_in_cb1_handler(*this),
- m_in_ca2_handler(*this),
- m_out_a_handler(*this),
- m_out_b_handler(*this),
- m_ca2_handler(*this),
- m_cb2_handler(*this),
- m_irqa_handler(*this),
- m_irqb_handler(*this), m_in_a(0),
- m_in_ca1(0), m_in_ca2(0), m_out_a(0), m_a_input_overrides_output_mask(0), m_out_ca2(0), m_ddr_a(0),
- m_ctl_a(0), m_irq_a1(0), m_irq_a2(0),
- m_irq_a_state(0), m_in_b(0),
- m_in_cb1(0), m_in_cb2(0), m_out_b(0), m_out_cb2(0), m_last_out_cb2_z(0), m_ddr_b(0),
- m_ctl_b(0), m_irq_b1(0), m_irq_b2(0),
- m_irq_b_state(0), m_in_a_pushed(false), m_out_a_needs_pulled(false), m_in_ca1_pushed(false),
- m_in_ca2_pushed(false), m_out_ca2_needs_pulled(false), m_in_b_pushed(false), m_out_b_needs_pulled(false),
- m_in_cb1_pushed(false), m_in_cb2_pushed(false), m_out_cb2_needs_pulled(false), m_logged_port_a_not_connected(false),
- m_logged_port_b_not_connected(false), m_logged_ca1_not_connected(false), m_logged_ca2_not_connected(false),
- m_logged_cb1_not_connected(false), m_logged_cb2_not_connected(false)
+pia6821_device::pia6821_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, PIA6821, tag, owner, clock),
+ m_in_a_handler(*this, 0),
+ m_in_b_handler(*this, 0),
+ m_in_ca1_handler(*this, 1),
+ m_in_cb1_handler(*this, 0),
+ m_in_ca2_handler(*this, 1),
+ m_out_a_handler(*this),
+ m_out_b_handler(*this),
+ m_ts_b_handler(*this, 0),
+ m_ca2_handler(*this),
+ m_cb2_handler(*this),
+ m_irqa_handler(*this),
+ m_irqb_handler(*this), m_in_a(0),
+ m_in_ca1(true), m_in_ca2(true), m_out_a(0), m_a_input_overrides_output_mask(0), m_out_ca2(0), m_ddr_a(0),
+ m_ctl_a(0), m_irq_a1(false), m_irq_a2(false),
+ m_irq_a_state(0), m_in_b(0),
+ m_in_cb1(0), m_in_cb2(0), m_out_b(0), m_out_cb2(0), m_last_out_cb2_z(0), m_ddr_b(0),
+ m_ctl_b(0), m_irq_b1(false), m_irq_b2(false),
+ m_irq_b_state(0), m_in_a_pushed(false), m_out_a_needs_pulled(false), m_in_ca1_pushed(false),
+ m_in_ca2_pushed(false), m_out_ca2_needs_pulled(false), m_in_b_pushed(false), m_out_b_needs_pulled(false),
+ m_in_cb1_pushed(false), m_in_cb2_pushed(false), m_out_cb2_needs_pulled(false), m_logged_port_a_not_connected(false),
+ m_logged_port_b_not_connected(false), m_logged_ca1_not_connected(false), m_logged_ca2_not_connected(false),
+ m_logged_cb1_not_connected(false), m_logged_cb2_not_connected(false)
{
}
@@ -73,18 +79,20 @@ pia6821_device::pia6821_device(const machine_config &mconfig, const char *tag, d
void pia6821_device::device_start()
{
- // resolve callbacks
- m_in_a_handler.resolve();
- m_in_b_handler.resolve();
- m_in_ca1_handler.resolve();
- m_in_cb1_handler.resolve();
- m_in_ca2_handler.resolve();
- m_out_a_handler.resolve();
- m_out_b_handler.resolve();
- m_ca2_handler.resolve();
- m_cb2_handler.resolve();
- m_irqa_handler.resolve_safe();
- m_irqb_handler.resolve_safe();
+ m_in_a = 0xff;
+ m_in_b = 0;
+ m_in_a_pushed = false;
+ m_out_a_needs_pulled = false;
+ m_out_ca2_needs_pulled = false;
+ m_in_b_pushed = false;
+ m_out_b_needs_pulled = false;
+ m_out_cb2_needs_pulled = false;
+ m_logged_port_a_not_connected = false;
+ m_logged_port_b_not_connected = false;
+ m_logged_ca1_not_connected = false;
+ m_logged_ca2_not_connected = false;
+ m_logged_cb1_not_connected = false;
+ m_logged_cb2_not_connected = false;
save_item(NAME(m_in_a));
save_item(NAME(m_in_ca1));
@@ -132,48 +140,35 @@ void pia6821_device::device_reset()
// ports A,CA1,CA2 default to 1
// ports B,CB1,CB2 are three-state and undefined (set to 0)
//
- m_in_a = 0xff;
- m_in_ca1 = true;
- m_in_ca2 = true;
m_out_a = 0;
m_out_ca2 = 0;
m_ddr_a = 0;
m_ctl_a = 0;
- m_irq_a1 = 0;
- m_irq_a2 = 0;
+ m_irq_a1 = false;
+ m_irq_a2 = false;
m_irq_a_state = 0;
- m_in_b = 0;
- m_in_cb1 = 0;
- m_in_cb2 = 0;
m_out_b = 0;
m_out_cb2 = 0;
m_last_out_cb2_z = 0;
m_ddr_b = 0;
m_ctl_b = 0;
- m_irq_b1 = 0;
- m_irq_b2 = 0;
+ m_irq_b1 = false;
+ m_irq_b2 = false;
m_irq_b_state = 0;
- m_in_a_pushed = false;
- m_out_a_needs_pulled = false;
- m_in_ca1_pushed = false;
- m_in_ca2_pushed = false;
- m_out_ca2_needs_pulled = false;
- m_in_b_pushed = false;
- m_out_b_needs_pulled = false;
- m_in_cb1_pushed = false;
- m_in_cb2_pushed = false;
- m_out_cb2_needs_pulled = false;
- m_logged_port_a_not_connected = false;
- m_logged_port_b_not_connected = false;
- m_logged_ca1_not_connected = false;
- m_logged_ca2_not_connected = false;
- m_logged_cb1_not_connected = false;
- m_logged_cb2_not_connected = false;
-
// clear the IRQs
- m_irqa_handler(false);
- m_irqb_handler(false);
+ m_irqa_handler(CLEAR_LINE);
+ m_irqb_handler(CLEAR_LINE);
+
+ // reset port A to internal pullups
+ if (!m_out_a_handler.isunset())
+ m_out_a_handler(0xff);
+ if (!m_ca2_handler.isunset())
+ m_ca2_handler(1);
+
+ // reset port B to three-state outputs
+ if (!m_out_b_handler.isunset() && !m_ts_b_handler.isunset())
+ m_out_b_handler(offs_t(0), m_ts_b_handler(), 0);
}
@@ -189,7 +184,7 @@ void pia6821_device::update_interrupts()
if (new_state != m_irq_a_state)
{
m_irq_a_state = new_state;
- m_irqa_handler(m_irq_a_state);
+ m_irqa_handler(m_irq_a_state ? ASSERT_LINE : CLEAR_LINE);
}
// then do IRQ B
@@ -198,7 +193,7 @@ void pia6821_device::update_interrupts()
if (new_state != m_irq_b_state)
{
m_irq_b_state = new_state;
- m_irqb_handler(m_irq_b_state);
+ m_irqb_handler(m_irq_b_state ? ASSERT_LINE : CLEAR_LINE);
}
}
@@ -213,7 +208,7 @@ uint8_t pia6821_device::get_in_a_value()
uint8_t ret;
// update the input
- if (!m_in_a_handler.isnull())
+ if (!m_in_a_handler.isunset())
{
port_a_data = m_in_a_handler(0);
}
@@ -266,7 +261,7 @@ uint8_t pia6821_device::get_in_b_value()
uint8_t port_b_data;
// update the input
- if (!m_in_b_handler.isnull())
+ if (!m_in_b_handler.isunset())
{
port_b_data = m_in_b_handler(0);
}
@@ -327,8 +322,13 @@ uint8_t pia6821_device::get_out_a_value()
uint8_t pia6821_device::get_out_b_value()
{
- // input pins are high-impedance - we just send them as zeros for backwards compatibility
- return m_out_b & m_ddr_b;
+ uint8_t ret = m_out_b & m_ddr_b;
+
+ // input pins are high-impedance - send them as zeros for backwards compatibility
+ if (m_ddr_b != 0xff && !m_ts_b_handler.isunset())
+ ret |= m_ts_b_handler() & ~m_ddr_b;
+
+ return ret;
}
@@ -338,22 +338,19 @@ uint8_t pia6821_device::get_out_b_value()
void pia6821_device::set_out_ca2(int data)
{
- if (data != m_out_ca2)
- {
- m_out_ca2 = data;
+ m_out_ca2 = data;
- // send to output function
- if (!m_ca2_handler.isnull())
- {
- m_ca2_handler(m_out_ca2);
- }
- else
- {
- if (m_out_ca2_needs_pulled)
- logerror("Warning! No port CA2 write handler. Previous value has been lost!\n");
+ // send to output function
+ if (!m_ca2_handler.isunset())
+ {
+ m_ca2_handler(m_out_ca2);
+ }
+ else
+ {
+ if (m_out_ca2_needs_pulled)
+ logerror("Warning! No port CA2 write handler. Previous value has been lost!\n");
- m_out_ca2_needs_pulled = true;
- }
+ m_out_ca2_needs_pulled = true;
}
}
@@ -372,7 +369,7 @@ void pia6821_device::set_out_cb2(int data)
m_last_out_cb2_z = z;
// send to output function
- if (!m_cb2_handler.isnull())
+ if (!m_cb2_handler.isunset())
{
m_cb2_handler(m_out_cb2);
}
@@ -406,7 +403,8 @@ uint8_t pia6821_device::port_a_r()
if (c2_output(m_ctl_a) && c2_strobe_mode(m_ctl_a))
{
// this will cause a transition low
- set_out_ca2(false);
+ if (m_out_ca2)
+ set_out_ca2(false);
// if the CA2 strobe is cleared by the E, reset it right away
if (strobe_e_reset(m_ctl_a))
@@ -489,21 +487,21 @@ uint8_t pia6821_device::control_a_r()
if (!machine().side_effects_disabled())
{
// update CA1 & CA2 if callback exists, these in turn may update IRQ's
- if (!m_in_ca1_handler.isnull())
+ if (!m_in_ca1_handler.isunset())
{
ca1_w(m_in_ca1_handler());
}
- else if(!m_logged_ca1_not_connected && (!m_in_ca1_pushed))
+ else if (!m_logged_ca1_not_connected && (!m_in_ca1_pushed))
{
logerror("Warning! No CA1 read handler. Assuming pin not connected\n");
m_logged_ca1_not_connected = true;
}
- if (!m_in_ca2_handler.isnull())
+ if (!m_in_ca2_handler.isunset())
{
ca2_w(m_in_ca2_handler());
}
- else if ( !m_logged_ca2_not_connected && c2_input(m_ctl_a) && !m_in_ca2_pushed)
+ else if (!m_logged_ca2_not_connected && c2_input(m_ctl_a) && !m_in_ca2_pushed)
{
logerror("Warning! No CA2 read handler. Assuming pin not connected\n");
m_logged_ca2_not_connected = true;
@@ -520,7 +518,7 @@ uint8_t pia6821_device::control_a_r()
if (m_irq_a2 && c2_input(m_ctl_a))
ret |= PIA_IRQ2;
- LOG("PIA control A read = %02X\n", ret);
+ LOGCTLR("PIA control A read = %02X\n", ret);
return ret;
}
@@ -537,7 +535,7 @@ uint8_t pia6821_device::control_b_r()
if (!machine().side_effects_disabled())
{
// update CB1 & CB2 if callback exists, these in turn may update IRQ's
- if(!m_in_cb1_handler.isnull())
+ if(!m_in_cb1_handler.isunset())
{
cb1_w(m_in_cb1_handler());
}
@@ -564,7 +562,7 @@ uint8_t pia6821_device::control_b_r()
if (m_irq_b2 && c2_input(m_ctl_b))
ret |= PIA_IRQ2;
- LOG("PIA control B read = %02X\n", ret);
+ LOGCTLR("PIA control B read = %02X\n", ret);
return ret;
}
@@ -614,7 +612,7 @@ void pia6821_device::send_to_out_a_func(const char* message)
LOG("PIA %s = %02X DDRA=%02x\n", message, data, m_ddr_a);
- if (!m_out_a_handler.isnull())
+ if (!m_out_a_handler.isunset())
{
m_out_a_handler(offs_t(0), data);
}
@@ -634,14 +632,13 @@ void pia6821_device::send_to_out_a_func(const char* message)
void pia6821_device::send_to_out_b_func(const char* message)
{
- // input pins are high-impedance - we just send them as zeros for backwards compatibility
const uint8_t data = get_out_b_value();
LOG("PIA %s = %02X DDRB=%02x\n", message, data, m_ddr_b);
- if (!m_out_b_handler.isnull())
+ if (!m_out_b_handler.isunset())
{
- m_out_b_handler(offs_t(0), data);
+ m_out_b_handler(offs_t(0), data, m_ddr_b);
}
else
{
@@ -742,25 +739,31 @@ void pia6821_device::control_a_w(uint8_t data)
LOGSETUP(" - Port A %s register selected\n", (data & 0x04) ? "Data" : "DDR");
// update the control register
+ bool ca2_was_output = c2_output(m_ctl_a);
m_ctl_a = data;
// CA2 is configured as output
if (c2_output(m_ctl_a))
{
- bool temp;
if (c2_set_mode(m_ctl_a))
{
- LOGSETUP(" - CA2 set/reset mode: ");
- temp = c2_set(m_ctl_a); // set/reset mode - bit value determines the new output
+ bool set = c2_set(m_ctl_a); // set/reset mode - bit value determines the new output
+ LOGSETUP(" - CA2 %sset output\n", set ? "" : "re");
+ if (!ca2_was_output || m_out_ca2 != set)
+ set_out_ca2(set);
}
else
{
- LOGSETUP(" - CA2 strobe mode: ");
- temp = true; // strobe mode - output is always high unless strobed
+ LOGSETUP(" - CA2 strobe output mode\n");
+ if (!ca2_was_output || !m_out_ca2)
+ set_out_ca2(true); // strobe mode - output is always high unless strobed
}
-
- LOGSETUP("%d\n", temp);
- set_out_ca2(temp);
+ }
+ else if (ca2_was_output)
+ {
+ LOGSETUP(" - CA2 pulled up as input\n");
+ if (!m_ca2_handler.isunset())
+ m_ca2_handler(1);
}
// update externals
@@ -788,16 +791,15 @@ void pia6821_device::control_b_w(uint8_t data)
bool temp;
if (c2_set_mode(m_ctl_b))
{
- LOGSETUP(" - CB2 set/reset mode: ");
temp = c2_set(m_ctl_b); // set/reset mode - bit value determines the new output
+ LOGSETUP(" - CB2 %sset output\n", temp ? "" : "re");
}
else
{
- LOGSETUP(" - CB2 strobe mode: ");
+ LOGSETUP(" - CB2 strobe output mode\n");
temp = true; // strobe mode - output is always high unless strobed
}
- LOGSETUP("%d\n", temp);
set_out_cb2(temp);
// update externals
@@ -822,7 +824,7 @@ void pia6821_device::write(offs_t offset, uint8_t data)
break;
case 0x01:
- control_a_w( data);
+ control_a_w(data);
break;
case 0x02:
@@ -845,7 +847,7 @@ void pia6821_device::write(offs_t offset, uint8_t data)
void pia6821_device::set_a_input(uint8_t data)
{
- if (!m_in_a_handler.isnull())
+ if (!m_in_a_handler.isunset())
throw emu_fatalerror("pia6821_device::set_a_input() called when m_in_a_handler set");
LOG("Set PIA input port A = %02X\n", data);
@@ -895,7 +897,7 @@ uint8_t pia6821_device::a_output()
// ca1_w
//-------------------------------------------------
-WRITE_LINE_MEMBER( pia6821_device::ca1_w )
+void pia6821_device::ca1_w(int state)
{
LOGCA1("Set PIA input CA1 = %d\n", state);
@@ -911,7 +913,7 @@ WRITE_LINE_MEMBER( pia6821_device::ca1_w )
update_interrupts();
// CA2 is configured as output and in read strobe mode and cleared by a CA1 transition
- if (c2_output(m_ctl_a) && c2_strobe_mode(m_ctl_a) && strobe_c1_reset(m_ctl_a))
+ if (c2_output(m_ctl_a) && c2_strobe_mode(m_ctl_a) && strobe_c1_reset(m_ctl_a) && !m_out_ca2)
set_out_ca2(true);
}
@@ -925,7 +927,7 @@ WRITE_LINE_MEMBER( pia6821_device::ca1_w )
// ca2_w
//-------------------------------------------------
-WRITE_LINE_MEMBER( pia6821_device::ca2_w )
+void pia6821_device::ca2_w(int state)
{
LOG("Set PIA input CA2 = %d\n", state);
@@ -979,7 +981,7 @@ bool pia6821_device::ca2_output_z()
void pia6821_device::portb_w(uint8_t data)
{
- if (!m_in_b_handler.isnull())
+ if (!m_in_b_handler.isunset())
throw emu_fatalerror("pia6821_device::portb_w() called when in_b_func implemented");
LOG("Set PIA input port B = %02X\n", data);
@@ -1020,17 +1022,17 @@ uint8_t pia6821_device::b_output()
// cb1_w
//-------------------------------------------------
-WRITE_LINE_MEMBER( pia6821_device::cb1_w )
+void pia6821_device::cb1_w(int state)
{
- LOG("Set PIA input CB1 = %d\n", state);
+ LOGCB1("Set PIA input CB1 = %d\n", state);
// the new state has caused a transition
if ((m_in_cb1 != state) && ((state && c1_low_to_high(m_ctl_b)) || (!state && c1_high_to_low(m_ctl_b))))
{
- LOG("CB1 triggering\n");
+ LOGCB1("CB1 triggering\n");
// mark the IRQ
- m_irq_b1 = 1;
+ m_irq_b1 = true;
// update externals
update_interrupts();
@@ -1051,7 +1053,7 @@ WRITE_LINE_MEMBER( pia6821_device::cb1_w )
// cb2_w
//-------------------------------------------------
-WRITE_LINE_MEMBER( pia6821_device::cb2_w )
+void pia6821_device::cb2_w(int state)
{
LOG("Set PIA input CB2 = %d\n", state);
@@ -1063,7 +1065,7 @@ WRITE_LINE_MEMBER( pia6821_device::cb2_w )
LOG("CB2 triggering\n");
// mark the IRQ
- m_irq_b2 = 1;
+ m_irq_b2 = true;
// update externals
update_interrupts();
diff --git a/src/devices/machine/6821pia.h b/src/devices/machine/6821pia.h
index f6ffa71ca8b..28f8e8af925 100644
--- a/src/devices/machine/6821pia.h
+++ b/src/devices/machine/6821pia.h
@@ -43,9 +43,9 @@ public:
auto readca2_handler() { return m_in_ca2_handler.bind(); }
auto readcb1_handler() { return m_in_cb1_handler.bind(); }
- // TODO: CONVERT THESE TO WRITE LINE
auto writepa_handler() { return m_out_a_handler.bind(); }
auto writepb_handler() { return m_out_b_handler.bind(); }
+ auto tspb_handler() { return m_ts_b_handler.bind(); }
auto ca2_handler() { return m_ca2_handler.bind(); }
auto cb2_handler() { return m_cb2_handler.bind(); }
@@ -65,18 +65,18 @@ public:
uint8_t a_output();
void set_port_a_input_overrides_output_mask(uint8_t mask) { m_a_input_overrides_output_mask = mask; }
- DECLARE_WRITE_LINE_MEMBER( pa0_w ) { write_porta_line(0, state); }
- DECLARE_WRITE_LINE_MEMBER( pa1_w ) { write_porta_line(1, state); }
- DECLARE_WRITE_LINE_MEMBER( pa2_w ) { write_porta_line(2, state); }
- DECLARE_WRITE_LINE_MEMBER( pa3_w ) { write_porta_line(3, state); }
- DECLARE_WRITE_LINE_MEMBER( pa4_w ) { write_porta_line(4, state); }
- DECLARE_WRITE_LINE_MEMBER( pa5_w ) { write_porta_line(5, state); }
- DECLARE_WRITE_LINE_MEMBER( pa6_w ) { write_porta_line(6, state); }
- DECLARE_WRITE_LINE_MEMBER( pa7_w ) { write_porta_line(7, state); }
+ void pa0_w(int state) { write_porta_line(0, state); }
+ void pa1_w(int state) { write_porta_line(1, state); }
+ void pa2_w(int state) { write_porta_line(2, state); }
+ void pa3_w(int state) { write_porta_line(3, state); }
+ void pa4_w(int state) { write_porta_line(4, state); }
+ void pa5_w(int state) { write_porta_line(5, state); }
+ void pa6_w(int state) { write_porta_line(6, state); }
+ void pa7_w(int state) { write_porta_line(7, state); }
- DECLARE_WRITE_LINE_MEMBER( ca1_w );
+ void ca1_w(int state);
- DECLARE_WRITE_LINE_MEMBER( ca2_w );
+ void ca2_w(int state);
bool ca2_output();
bool ca2_output_z();
@@ -84,18 +84,18 @@ public:
void write_portb_line(int line, bool state);
uint8_t b_output();
- DECLARE_WRITE_LINE_MEMBER( pb0_w ) { write_portb_line(0, state); }
- DECLARE_WRITE_LINE_MEMBER( pb1_w ) { write_portb_line(1, state); }
- DECLARE_WRITE_LINE_MEMBER( pb2_w ) { write_portb_line(2, state); }
- DECLARE_WRITE_LINE_MEMBER( pb3_w ) { write_portb_line(3, state); }
- DECLARE_WRITE_LINE_MEMBER( pb4_w ) { write_portb_line(4, state); }
- DECLARE_WRITE_LINE_MEMBER( pb5_w ) { write_portb_line(5, state); }
- DECLARE_WRITE_LINE_MEMBER( pb6_w ) { write_portb_line(6, state); }
- DECLARE_WRITE_LINE_MEMBER( pb7_w ) { write_portb_line(7, state); }
+ void pb0_w(int state) { write_portb_line(0, state); }
+ void pb1_w(int state) { write_portb_line(1, state); }
+ void pb2_w(int state) { write_portb_line(2, state); }
+ void pb3_w(int state) { write_portb_line(3, state); }
+ void pb4_w(int state) { write_portb_line(4, state); }
+ void pb5_w(int state) { write_portb_line(5, state); }
+ void pb6_w(int state) { write_portb_line(6, state); }
+ void pb7_w(int state) { write_portb_line(7, state); }
- DECLARE_WRITE_LINE_MEMBER( cb1_w );
+ void cb1_w(int state);
- DECLARE_WRITE_LINE_MEMBER( cb2_w );
+ void cb2_w(int state);
bool cb2_output();
bool cb2_output_z();
@@ -103,7 +103,7 @@ public:
int irq_b_state() const { return m_irq_b_state; }
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
@@ -162,6 +162,7 @@ private:
devcb_read_line m_in_ca2_handler;
devcb_write8 m_out_a_handler;
devcb_write8 m_out_b_handler;
+ devcb_read8 m_ts_b_handler;
devcb_write_line m_ca2_handler;
devcb_write_line m_cb2_handler;
devcb_write_line m_irqa_handler;
@@ -175,8 +176,8 @@ private:
uint8_t m_out_ca2;
uint8_t m_ddr_a;
uint8_t m_ctl_a;
- uint8_t m_irq_a1;
- uint8_t m_irq_a2;
+ bool m_irq_a1;
+ bool m_irq_a2;
uint8_t m_irq_a_state;
uint8_t m_in_b;
@@ -187,8 +188,8 @@ private:
uint8_t m_last_out_cb2_z;
uint8_t m_ddr_b;
uint8_t m_ctl_b;
- uint8_t m_irq_b1;
- uint8_t m_irq_b2;
+ bool m_irq_b1;
+ bool m_irq_b2;
uint8_t m_irq_b_state;
// variables that indicate if access a line externally -
diff --git a/src/devices/machine/68230pit.cpp b/src/devices/machine/68230pit.cpp
index b6979d5942a..0577d63ddba 100644
--- a/src/devices/machine/68230pit.cpp
+++ b/src/devices/machine/68230pit.cpp
@@ -24,12 +24,11 @@
#include "emu.h"
#include "68230pit.h"
-#define LOG_GENERAL 0x01
-#define LOG_SETUP 0x02
-#define LOG_READ 0x04
-#define LOG_BIT 0x08
-#define LOG_DR 0x10
-#define LOG_INT 0x20
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_BIT (1U << 3)
+#define LOG_DR (1U << 4)
+#define LOG_INT (1U << 5)
#define VERBOSE 0 //(LOG_SETUP | LOG_GENERAL | LOG_INT | LOG_BIT | LOG_DR)
#include "logmacro.h"
@@ -40,12 +39,6 @@
#define LOGDR(...) LOGMASKED(LOG_DR, __VA_ARGS__)
#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__)
-#ifdef _MSC_VER
-#define FUNCNAME __func__
-#else
-#define FUNCNAME __PRETTY_FUNCTION__
-#endif
-
//**************************************************************************
// DEVICE TYPE DEFINITIONS
//**************************************************************************
@@ -58,11 +51,11 @@ DEFINE_DEVICE_TYPE(PIT68230, pit68230_device, "pit68230", "MC68230 PI/T")
pit68230_device::pit68230_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant)
: device_t(mconfig, type, tag, owner, clock)
, m_pa_out_cb(*this)
- , m_pa_in_cb(*this)
+ , m_pa_in_cb(*this, 0)
, m_pb_out_cb(*this)
- , m_pb_in_cb(*this)
+ , m_pb_in_cb(*this, 0)
, m_pc_out_cb(*this)
- , m_pc_in_cb(*this)
+ , m_pc_in_cb(*this, 0)
, m_h1_out_cb(*this)
, m_h2_out_cb(*this)
, m_h3_out_cb(*this)
@@ -102,37 +95,17 @@ pit68230_device::pit68230_device(const machine_config &mconfig, const char *tag,
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
-void pit68230_device::device_start ()
+void pit68230_device::device_start()
{
- LOGSETUP("%s\n", FUNCNAME);
+ LOGSETUP("pit68230_device::device_start\n");
// NOTE:
- // Not using resolve_safe for the m_px_in_cb's is a temporary way to be able to check
+ // Not using resolve_safe for the m_px_in_cb's was a temporary way to be able to check
// if a handler is installed with isnull(). The safe function installs a dummy default
- // handler which disable the isnull() test. TODO: Need a better fix?
-
- // resolve callbacks Port A
- m_pa_out_cb.resolve_safe();
- m_pa_in_cb.resolve();
-
- // resolve callbacks Port B
- m_pb_out_cb.resolve_safe();
- m_pb_in_cb.resolve();
-
- // resolve callbacks Port C
- m_pc_out_cb.resolve_safe();
- m_pc_in_cb.resolve();
-
- m_h1_out_cb.resolve_safe();
- m_h2_out_cb.resolve_safe();
- m_h3_out_cb.resolve_safe();
- m_h4_out_cb.resolve_safe();
-
- m_tirq_out_cb.resolve_safe();
- m_pirq_out_cb.resolve_safe();
+ // handler which disabled the isnull() test. TODO: Need a better fix?
// Timers
- pit_timer = timer_alloc(TIMER_ID_PIT);
+ pit_timer = timer_alloc(FUNC(pit68230_device::tick_clock), this);
// state saving
save_item(NAME(m_pgcr));
@@ -157,9 +130,9 @@ void pit68230_device::device_start ()
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
-void pit68230_device::device_reset ()
+void pit68230_device::device_reset()
{
- LOGSETUP("%s %s \n",tag(), FUNCNAME);
+ LOGSETUP("pit68230_device::device_reset %s\n", tag());
m_pgcr = 0;
m_psrr = 0;
@@ -176,7 +149,7 @@ void pit68230_device::device_reset ()
m_tcr = 0;
m_tivr = 0x0f; m_tirq_out_cb(CLEAR_LINE);
m_tsr = 0;
- LOGSETUP("%s %s DONE!\n",tag(), FUNCNAME);
+ LOGSETUP("pit68230_device::device_reset %s DONE!\n",tag());
}
/*
@@ -184,7 +157,7 @@ void pit68230_device::device_reset ()
*/
uint8_t pit68230_device::irq_piack()
{
- LOGINT("%s %s <- %02x\n",tag(), FUNCNAME, m_pivr);
+ LOGINT("%s pit68230_device::irq_piack <- %02x\n",tag(), m_pivr);
return m_pivr;
}
@@ -193,7 +166,7 @@ uint8_t pit68230_device::irq_piack()
*/
uint8_t pit68230_device::irq_tiack()
{
- LOGINT("%s %s <- %02x\n",tag(), FUNCNAME, m_tivr);
+ LOGINT("%s pit68230_device::irq_tiack <- %02x\n", tag(), m_tivr);
return m_tivr;
}
@@ -203,13 +176,13 @@ uint8_t pit68230_device::irq_tiack()
*/
void pit68230_device::trigger_interrupt(int source)
{
- LOGINT("%s %s Source: %02x\n",tag(), FUNCNAME, source);
+ LOGINT("%s pit68230_device::trigger_interrupt Source: %02x\n", tag(), source);
if (source == INT_TIMER)
{
// TODO: implement priorities and support nested interrupts
- if ( (m_tcr & REG_TCR_TOUT_TIACK_MASK) == REG_TCR_TOUT_TIACK_INT ||
- (m_tcr & REG_TCR_TOUT_TIACK_MASK) == REG_TCR_TOUT_PC7_INT )
+ if ((m_tcr & REG_TCR_TOUT_TIACK_MASK) == REG_TCR_TOUT_TIACK_INT ||
+ (m_tcr & REG_TCR_TOUT_TIACK_MASK) == REG_TCR_TOUT_PC7_INT)
{
m_tirq_out_cb(ASSERT_LINE);
}
@@ -221,7 +194,7 @@ void pit68230_device::trigger_interrupt(int source)
}
}
-void pit68230_device::tick_clock()
+TIMER_CALLBACK_MEMBER(pit68230_device::tick_clock)
{
if (m_tcr & REG_TCR_TIMER_ENABLE)
{
@@ -238,25 +211,9 @@ void pit68230_device::tick_clock()
}
}
-//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-void pit68230_device::device_timer (emu_timer &timer, device_timer_id id, int32_t param, void *ptr)
-{
- switch(id)
- {
- case TIMER_ID_PIT:
- tick_clock();
- break;
- default:
- LOG("Unhandled Timer ID %d\n", id);
- break;
- }
-}
-
-WRITE_LINE_MEMBER( pit68230_device::h1_w )
+void pit68230_device::h1_w(int state)
{
- LOGBIT("%s %s H1 set to %d\n", tag(), FUNCNAME, state);
+ LOGBIT("%s pit68230_device::h1_w H1 set to %d\n", tag(), state);
// Set the direct level in PSR
m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H1L) : (m_psr | REG_PSR_H1L));
@@ -268,9 +225,9 @@ WRITE_LINE_MEMBER( pit68230_device::h1_w )
m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H1S) : (m_psr | REG_PSR_H1S));
}
-WRITE_LINE_MEMBER( pit68230_device::h2_w )
+void pit68230_device::h2_w(int state)
{
- LOGBIT("%s %s H2 set to %d\n", tag(), FUNCNAME, state);
+ LOGBIT("%s pit68230_device::h2_w H2 set to %d\n", tag(), state);
// Set the direct level in PSR
m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H2L) : (m_psr | REG_PSR_H2L));
@@ -282,9 +239,9 @@ WRITE_LINE_MEMBER( pit68230_device::h2_w )
m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H2S) : (m_psr | REG_PSR_H2S));
}
-WRITE_LINE_MEMBER( pit68230_device::h3_w )
+void pit68230_device::h3_w(int state)
{
- LOGBIT("%s %s H3 set to %d\n", tag(), FUNCNAME, state);
+ LOGBIT("%s pit68230_device::h3_w H3 set to %d\n", tag(), state);
// Set the direct level in PSR
m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H3L) : (m_psr | REG_PSR_H3L));
@@ -296,9 +253,9 @@ WRITE_LINE_MEMBER( pit68230_device::h3_w )
m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H3S) : (m_psr | REG_PSR_H3S));
}
-WRITE_LINE_MEMBER( pit68230_device::h4_w )
+void pit68230_device::h4_w(int state)
{
- LOGBIT("%s %s H4 set to %d\n", tag(), FUNCNAME, state);
+ LOGBIT("%s pit68230_device::h4_w H4 set to %d\n", tag(), state);
// Set the direct level in PSR
m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H4L) : (m_psr | REG_PSR_H4L));
@@ -313,14 +270,17 @@ WRITE_LINE_MEMBER( pit68230_device::h4_w )
// TODO: remove this method and replace it with a call to pb_update_bit() in force68k.cpp
void pit68230_device::portb_setbit(uint8_t bit, uint8_t state)
{
- if (state) m_pbdr |= (1 << bit); else m_pbdr &= ~(1 << bit);
+ if (state)
+ m_pbdr |= (1 << bit);
+ else
+ m_pbdr &= ~(1 << bit);
}
void pit68230_device::pa_update_bit(uint8_t bit, uint8_t state)
{
- LOGBIT("%s %s bit %d to %d\n", tag(), FUNCNAME, bit, state);
+ LOGBIT("%s pit68230_device::pa_update_bit bit %d to %d\n", tag(), bit, state);
// Check if requested bit is an output bit and can't be affected
- if (m_paddr & (1 << bit))
+ if (BIT(m_paddr, bit))
{
LOG("- 68230 PIT: tried to set input bit at port A that is programmed as output!\n");
return;
@@ -339,9 +299,9 @@ void pit68230_device::pa_update_bit(uint8_t bit, uint8_t state)
void pit68230_device::pb_update_bit(uint8_t bit, uint8_t state)
{
- LOGBIT("%s %s bit %d to %d\n",tag(), FUNCNAME, bit, state);
+ LOGBIT("%s pit68230_device::pb_update_bit bit %d to %d\n", tag(), bit, state);
// Check if requested bit is an output bit and can't be affected
- if (m_pbddr & (1 << bit))
+ if (BIT(m_pbddr, bit))
{
LOG("- 68230 PIT: tried to set input bit at port B that is programmed as output!\n");
return;
@@ -361,9 +321,9 @@ void pit68230_device::pb_update_bit(uint8_t bit, uint8_t state)
// TODO: Make sure port C is in the right alternate mode
void pit68230_device::pc_update_bit(uint8_t bit, uint8_t state)
{
- LOGBIT("%s %s bit %d to %d\n",tag(), FUNCNAME, bit, state);
+ LOGBIT("%s pit68230_device::pc_update_bit bit %d to %d\n", tag(), bit, state);
// Check if requested bit is an output bit and can't be affected
- if (m_pcddr & (1 << bit))
+ if (BIT(m_pcddr, bit))
{
LOG("- 68230 PIT: tried to set input bit at port C that is programmed as output!\n");
return;
@@ -385,7 +345,7 @@ void pit68230_device::update_tin(uint8_t state)
// Tick clock on falling edge. TODO: check what flank is correct
if (state == CLEAR_LINE)
{
- tick_clock();
+ tick_clock(0);
}
pc_update_bit(REG_PCDR_TIN_BIT, state == ASSERT_LINE ? 0 : 1);
@@ -399,9 +359,9 @@ static int32_t ow_ofs = 0;
void pit68230_device::wr_pitreg_pgcr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
- LOGSETUP("PGCR - Mode %d,", (data >> 6) & 3 );
- LOGSETUP(" H34:%s, H12:%s,", (data & 0x20) ? "enabled" : "disabled", (data & 0x10) ? "enabled" : "disabled" );
+ LOG("pit68230_device::wr_pitreg_pgcr(%02x) \"%s\": pit68230_device::wr_pitreg_pgcr - %02x\n", data, tag(), data);
+ LOGSETUP("PGCR - Mode %d,", (data >> 6) & 3);
+ LOGSETUP(" H34:%s, H12:%s,", (data & 0x20) ? "enabled" : "disabled", (data & 0x10) ? "enabled" : "disabled");
LOGSETUP(" Sense assert H4:%s, H3:%s, H2:%s, H1:%s\n",
data & 0x04 ? "Hi" : "Lo", data & 0x03 ? "Hi" : "Lo",
data & 0x02 ? "Hi" : "Lo", data & 0x01 ? "Hi" : "Lo");
@@ -410,18 +370,18 @@ void pit68230_device::wr_pitreg_pgcr(uint8_t data)
void pit68230_device::wr_pitreg_psrr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_psrr(%02x) \"%s\": pit68230_device::wr_pitreg_psrr - %02x\n", data, tag(), data);
LOGSETUP("PSSR - %s pin activated,", data & 0x40 ? "DMA" : "PC4");
LOGSETUP(" %s pin support %s interrupts,", data & 0x80 ? "PIRQ" : "PC5",
- data & 0x08 ? "no" : (data & 0x10 ? "vectored" : "autovectored" ) );
- LOGSETUP(" H prio mode:%d\n", data & 0x03 );
+ data & 0x08 ? "no" : (data & 0x10 ? "vectored" : "autovectored"));
+ LOGSETUP(" H prio mode:%d\n", data & 0x03);
m_psrr = data;
}
void pit68230_device::wr_pitreg_paddr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_paddr(%02x) \"%s\": pit68230_device::wr_pitreg_paddr - %02x\n", data, tag(), data);
LOGSETUP("%s PADDR: %02x\n", tag(), data);
m_paddr = data;
}
@@ -434,21 +394,21 @@ void pit68230_device::wr_pitreg_pbddr(uint8_t data)
void pit68230_device::wr_pitreg_pcddr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_pcddr(%02x) \"%s\": pit68230_device::wr_pitreg_pcddr - %02x\n", data, tag(), data);
LOGSETUP("%s PCDDR: %02x\n", tag(), data);
m_pcddr = data;
}
void pit68230_device::wr_pitreg_pivr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_pivr(%02x) \"%s\": pit68230_device::wr_pitreg_pivr - %02x\n", data, tag(), data);
LOGSETUP("%s PIVR: %02x\n", tag(), data);
m_pivr = data & 0xfc; // lowest two bits are read as zero
}
void pit68230_device::wr_pitreg_pacr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_pacr(%02x) \"%s\": pit68230_device::wr_pitreg_pacr - %02x\n", data, tag(), data);
LOGSETUP("%s PACR", tag());
m_pacr = data;
// callbacks
@@ -471,7 +431,7 @@ void pit68230_device::wr_pitreg_pacr(uint8_t data)
{
if (m_pacr & REG_PACR_H2_CTRL_IN_OUT)
{
- switch(m_pacr & REG_PACR_H2_CTRL_MASK)
+ switch (m_pacr & REG_PACR_H2_CTRL_MASK)
{
case REG_PACR_H2_CTRL_OUT_00:
LOGSETUP(" - H2 cleared\n");
@@ -487,7 +447,7 @@ void pit68230_device::wr_pitreg_pacr(uint8_t data)
case REG_PACR_H2_CTRL_OUT_11:
LOGSETUP(" - pulsed handshake not implemented\n");
break;
- default: logerror(("Undefined H2 mode, broken driver - please report!\n"));
+ default: logerror("Undefined H2 mode %02x in pit68230_device - please report\n", m_pacr & REG_PACR_H2_CTRL_MASK);
}
}
}
@@ -501,13 +461,13 @@ void pit68230_device::wr_pitreg_pacr(uint8_t data)
// TODO add support for sense status
void pit68230_device::wr_pitreg_pbcr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_pbcr(%02x) \"%s\": pit68230_device::wr_pitreg_pbcr - %02x\n", data, tag(), data);
m_pbcr = data;
if ((m_pgcr & REG_PGCR_H34_ENABLE) || ((m_pbcr & REG_PBCR_SUBMODE_MASK) == REG_PBCR_SUBMODE_1X))
{
if (m_pbcr & REG_PBCR_H4_CTRL_IN_OUT)
{
- switch(m_pbcr & REG_PBCR_H4_CTRL_MASK)
+ switch (m_pbcr & REG_PBCR_H4_CTRL_MASK)
{
case REG_PBCR_H4_CTRL_OUT_00:
LOG(" - H4 cleared\n");
@@ -523,7 +483,7 @@ void pit68230_device::wr_pitreg_pbcr(uint8_t data)
case REG_PBCR_H4_CTRL_OUT_11:
LOGSETUP(" - pulsed handshake not implemented\n");
break;
- default: logerror(("Undefined H4 mode, broken driver - please report!\n"));
+ default: logerror("Undefined H4 mode %02x in pit68230_device - please report\n", m_pbcr & REG_PBCR_H4_CTRL_MASK);
}
}
}
@@ -536,34 +496,34 @@ void pit68230_device::wr_pitreg_pbcr(uint8_t data)
void pit68230_device::wr_pitreg_padr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
- m_padr = (data & m_paddr);
+ LOG("pit68230_device::wr_pitreg_padr(%02x) \"%s\": pit68230_device::wr_pitreg_padr - %02x\n", data, tag(), data);
+ m_padr = data & m_paddr;
// callback
- m_pa_out_cb ((offs_t)0, m_padr);
+ m_pa_out_cb(m_padr);
}
void pit68230_device::wr_pitreg_pbdr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
- m_pbdr = (data & m_pbddr);
+ LOG("pit68230_device::wr_pitreg_pbdr(%02x) \"%s\": pit68230_device::wr_pitreg_pbdr - %02x\n", data, tag(), data);
+ m_pbdr = data & m_pbddr;
// callback
- m_pb_out_cb ((offs_t)0, m_pbdr & m_pbddr);
+ m_pb_out_cb(m_pbdr & m_pbddr);
}
void pit68230_device::wr_pitreg_pcdr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
- m_pcdr = (data & m_pcddr);
+ LOG("pit68230_device::wr_pitreg_pcdr(%02x) \"%s\": pit68230_device::wr_pitreg_pcdr - %02x\n", data, tag(), data);
+ m_pcdr = data & m_pcddr;
// callback
- m_pc_out_cb ((offs_t)0, m_pcdr);
+ m_pc_out_cb(m_pcdr);
}
void pit68230_device::wr_pitreg_psr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_psr(%02x) \"%s\": pit68230_device::wr_pitreg_psr - %02x\n", data, tag(), data);
m_psr = data;
}
@@ -639,7 +599,7 @@ void pit68230_device::wr_pitreg_tcr(uint8_t data)
int pen = 0;
//int sqr = 0;
- LOG("%s(%02x) %s\n", FUNCNAME, data, tag());
+ LOG("pit68230_device::wr_pitreg_tcr(%02x) %s\n", data, tag());
m_tcr = data;
switch (m_tcr & REG_TCR_TOUT_TIACK_MASK)
{
@@ -674,46 +634,46 @@ void pit68230_device::wr_pitreg_tcr(uint8_t data)
if (clk == 1)
{
int rate = clock() / (psc == 1 ? 32 : 1);
- pit_timer->adjust(attotime::from_hz(rate), TIMER_ID_PIT, attotime::from_hz(rate));
+ pit_timer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate));
LOG("PIT timer started @ rate: %d and CLK: %d,\n", rate, clock());
}
}
else
{
- pit_timer->adjust(attotime::never, TIMER_ID_PIT, attotime::never);
+ pit_timer->adjust(attotime::never, 0, attotime::never);
}
}
void pit68230_device::wr_pitreg_tivr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": \n", FUNCNAME, data, tag());
+ LOG("pit68230_device::wr_pitreg_tivr(%02x) \"%s\": \n", data, tag());
m_tivr = data;
}
void pit68230_device::wr_pitreg_cprh(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_cprh(%02x) \"%s\": pit68230_device::wr_pitreg_cprh - %02x\n", data, tag(), data);
m_cpr &= ~0xff0000;
m_cpr |= ((data << 16) & 0xff0000);
}
void pit68230_device::wr_pitreg_cprm(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_cprm(%02x) \"%s\": pit68230_device::wr_pitreg_cprm - %02x\n", data, tag(), data);
m_cpr &= ~0x00ff00;
m_cpr |= ((data << 8) & 0x00ff00);
}
void pit68230_device::wr_pitreg_cprl(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data);
+ LOG("pit68230_device::wr_pitreg_cprl(%02x) \"%s\": pit68230_device::wr_pitreg_cprl - %02x\n", data, tag(), data);
m_cpr &= ~0x0000ff;
- m_cpr |= ((data << 0) & 0x0000ff);
+ m_cpr |= data & 0x0000ff;
}
void pit68230_device::wr_pitreg_tsr(uint8_t data)
{
- LOG("%s(%02x) \"%s\": \n", FUNCNAME, data, tag());
+ LOG("pit68230_device::wr_pitreg_tsr(%02x) \"%s\": \n", data, tag());
if (data & 1)
{
m_tsr = 0; // A write resets the TSR;
@@ -723,9 +683,10 @@ void pit68230_device::wr_pitreg_tsr(uint8_t data)
void pit68230_device::write(offs_t offset, uint8_t data)
{
- LOG("\"%s\" %s: Register write '%02x' -> [%02x]\n", tag(), FUNCNAME, data, offset );
+ LOG("\"%s\" pit68230_device::write: Register write '%02x' -> [%02x]\n", tag(), data, offset);
LOGSETUP(" * %s Reg %02x <- %02x \n", tag(), offset, data);
- switch (offset) {
+ switch (offset)
+ {
case PIT_68230_PGCR: wr_pitreg_pgcr(data); break;
case PIT_68230_PSRR: wr_pitreg_psrr(data); break;
case PIT_68230_PADDR: wr_pitreg_paddr(data); break;
@@ -754,7 +715,8 @@ void pit68230_device::write(offs_t offset, uint8_t data)
}
#if VERBOSE > 2
- if (offset != ow_ofs || data != ow_data || ow_cnt >= 1000) {
+ if (offset != ow_ofs || data != ow_data || ow_cnt >= 1000)
+ {
if (ow_cnt > 1)
{
logerror ("\npit68230_device::write: previous identical operation performed %02x times\n", ow_cnt);
@@ -778,64 +740,64 @@ static int32_t or_ofs = 0;
uint8_t pit68230_device::rr_pitreg_pgcr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_pgcr);
+ LOGR("%s pit68230_device::rr_pitreg_pgcr <- %02x\n", tag(), m_pgcr);
return m_pgcr;
}
uint8_t pit68230_device::rr_pitreg_psrr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_psrr);
+ LOGR("%s pit68230_device::rr_pitreg_psrr <- %02x\n", tag(), m_psrr);
return m_psrr & 0x7f; // mask out unused bits
}
uint8_t pit68230_device::rr_pitreg_paddr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_paddr);
+ LOGR("%s pit68230_device::rr_pitreg_paddr <- %02x\n", tag(), m_paddr);
return m_paddr;
}
uint8_t pit68230_device::rr_pitreg_pbddr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_pbddr);
+ LOGR("%s pit68230_device::rr_pitreg_pbddr <- %02x\n", tag(), m_pbddr);
return m_pbddr;
}
uint8_t pit68230_device::rr_pitreg_pcddr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_pcddr);
+ LOGR("%s pit68230_device::rr_pitreg_pcddr <- %02x\n", tag(), m_pcddr);
return m_pcddr;
}
uint8_t pit68230_device::rr_pitreg_pivr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_pivr);
+ LOGR("%s pit68230_device::rr_pitreg_pivr <- %02x\n", tag(), m_pivr);
return m_pivr;
}
uint8_t pit68230_device::rr_pitreg_pacr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_pacr);
+ LOGR("%s pit68230_device::rr_pitreg_pacr <- %02x\n", tag(), m_pacr);
return m_pacr;
}
uint8_t pit68230_device::rr_pitreg_pbcr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_pbcr);
+ LOGR("%s pit68230_device::rr_pitreg_pbcr <- %02x\n", tag(), m_pbcr);
return m_pbcr;
}
uint8_t pit68230_device::rr_pitreg_padr()
{
m_padr &= m_paddr;
- if (!m_pa_in_cb.isnull())
+ if (!m_pa_in_cb.isunset())
{
- m_padr |= (m_pa_in_cb() & ~m_paddr);
+ m_padr |= m_pa_in_cb() & ~m_paddr;
}
else
{
- m_padr |= (m_pail & ~m_paddr);
+ m_padr |= m_pail & ~m_paddr;
}
- LOGDR("%s %s <- %02x\n",tag(), FUNCNAME, m_padr);
+ LOGDR("%s pit68230_device::rr_pitreg_padr <- %02x\n", tag(), m_padr);
return m_padr;
}
@@ -849,16 +811,16 @@ uint8_t pit68230_device::rr_pitreg_padr()
uint8_t pit68230_device::rr_pitreg_pbdr()
{
m_pbdr &= m_pbddr;
- if (!m_pb_in_cb.isnull())
+ if (!m_pb_in_cb.isunset())
{
- m_pbdr |= (m_pb_in_cb() & ~m_pbddr);
+ m_pbdr |= m_pb_in_cb() & ~m_pbddr;
}
else
{
- m_pbdr |= (m_pbil & ~m_pbddr);
+ m_pbdr |= m_pbil & ~m_pbddr;
}
- LOGDR("%s %s <- %02x\n",tag(), FUNCNAME, m_pbdr);
+ LOGDR("%s pit68230_device::rr_pitreg_pbdr <- %02x\n", tag(), m_pbdr);
return m_pbdr;
}
@@ -866,16 +828,19 @@ uint8_t pit68230_device::rr_pitreg_pbdr()
uint8_t pit68230_device::rr_pitreg_pcdr()
{
m_pcdr &= m_pcddr;
- if (!m_pc_in_cb.isnull()) // Port C has alternate functions that may set bits apart from callback
+ if (!m_pc_in_cb.isunset()) // Port C has alternate functions that may set bits apart from callback
{
- m_pcdr |= (m_pc_in_cb() & ~m_pcddr);
+ m_pcdr |= m_pc_in_cb() & ~m_pcddr;
}
else
{
- m_pcdr |= (m_pcil & ~m_pcddr);
+ m_pcdr |= m_pcil & ~m_pcddr;
}
- if (m_pcdr != 0) { LOGDR("%s %s <- %02x\n",tag(), FUNCNAME, m_pcdr); }
+ if (m_pcdr != 0)
+ {
+ LOGDR("%s pit68230_device::rr_pitreg_pcdr <- %02x\n", tag(), m_pcdr);
+ }
return m_pcdr;
}
@@ -886,9 +851,8 @@ the instantaneous pin level is read and no input latching is performed except at
data bus interface. Writes to this address are answered with DTACK, but the data is ignored.*/
uint8_t pit68230_device::rr_pitreg_paar()
{
- uint8_t ret;
- ret = m_pa_in_cb.isnull() ? 0 : m_pa_in_cb();
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, ret);
+ const uint8_t ret = m_pa_in_cb();
+ LOGR("%s pit68230_device::rr_pitreg_paar <- %02x\n", tag(), ret);
return ret;
}
@@ -898,9 +862,8 @@ the instantaneous pin level is read and no input latching is performed except at
data bus interface.Writes to this address are answered with DTACK, but the data is ignored.*/
uint8_t pit68230_device::rr_pitreg_pbar()
{
- uint8_t ret;
- ret = m_pb_in_cb.isnull() ? 0 : m_pb_in_cb();
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, ret);
+ const uint8_t ret = m_pb_in_cb();
+ LOGR("%s pit68230_device::rr_pitreg_pbar <- %02x\n", tag(), ret);
return ret;
}
@@ -912,68 +875,70 @@ uint8_t pit68230_device::rr_pitreg_pbar()
* 3-0 a one is the active or asserted state. */
uint8_t pit68230_device::rr_pitreg_psr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_psr);
+ LOGR("%s pit68230_device::rr_pitreg_psr <- %02x\n", tag(), m_psr);
return m_psr;
}
uint8_t pit68230_device::rr_pitreg_tcr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_tcr);
+ LOGR("%s pit68230_device::rr_pitreg_tcr <- %02x\n", tag(), m_tcr);
return m_tcr;
}
uint8_t pit68230_device::rr_pitreg_tivr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_tivr);
+ LOGR("%s pit68230_device::rr_pitreg_tivr <- %02x\n", tag(), m_tivr);
return m_tivr;
}
uint8_t pit68230_device::rr_pitreg_cprh()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, (m_cpr >> 16) & 0xff);
+ LOGR("%s pit68230_device::rr_pitreg_cprh <- %02x\n", tag(), (m_cpr >> 16) & 0xff);
return (m_cpr >> 16) & 0xff;
}
uint8_t pit68230_device::rr_pitreg_cprm()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, (m_cpr >> 8) & 0xff);
+ LOGR("%s pit68230_device::rr_pitreg_cprm <- %02x\n", tag(), (m_cpr >> 8) & 0xff);
return (m_cpr >> 8) & 0xff;
}
uint8_t pit68230_device::rr_pitreg_cprl()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, (m_cpr >> 0) & 0xff);
- return (m_cpr >> 0) & 0xff;
+ LOGR("%s pit68230_device::rr_pitreg_cprl <- %02x\n", tag(), m_cpr & 0xff);
+ return m_cpr & 0xff;
}
uint8_t pit68230_device::rr_pitreg_cntrh()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, (m_cntr >> 16) & 0xff);
+ LOGR("%s pit68230_device::rr_pitreg_cntrh <- %02x\n", tag(), (m_cntr >> 16) & 0xff);
return (m_cntr >> 16) & 0xff;
}
uint8_t pit68230_device::rr_pitreg_cntrm()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, (m_cntr >> 8) & 0xff);
+ LOGR("%s pit68230_device::rr_pitreg_cntrm <- %02x\n", tag(), (m_cntr >> 8) & 0xff);
return (m_cntr >> 8) & 0xff;
}
uint8_t pit68230_device::rr_pitreg_cntrl()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, (m_cntr >> 0) & 0xff);
- return (m_cntr >> 0) & 0xff;
+ LOGR("%s pit68230_device::rr_pitreg_cntrl <- %02x\n", tag(), m_cntr & 0xff);
+ return m_cntr & 0xff;
}
uint8_t pit68230_device::rr_pitreg_tsr()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_tsr);
+ LOGR("%s pit68230_device::rr_pitreg_tsr <- %02x\n", tag(), m_tsr);
return m_tsr;
}
-uint8_t pit68230_device::read(offs_t offset){
+uint8_t pit68230_device::read(offs_t offset)
+{
uint8_t data;
- switch (offset) {
+ switch (offset)
+ {
case PIT_68230_PGCR: data = rr_pitreg_pgcr(); break;
case PIT_68230_PSRR: data = rr_pitreg_psrr(); break;
case PIT_68230_PADDR: data = rr_pitreg_paddr(); break;
@@ -1003,12 +968,13 @@ uint8_t pit68230_device::read(offs_t offset){
}
#if VERBOSE > 2
- if (offset != or_ofs || data != or_data || or_cnt >= 1000) {
+ if (offset != or_ofs || data != or_data || or_cnt >= 1000)
+ {
LOGSETUP(" * %s Reg %02x -> %02x \n", tag(), offset, data);
if (or_cnt > 1)
{
- logerror ("\npit68230_device::read: previous identical operation performed %02x times\n", or_cnt);
- logerror (" - pit68230_device::read: offset=%02x data=%02x %s\n", offset, data, machine().describe_context());
+ logerror("\npit68230_device::read: previous identical operation performed %02x times\n", or_cnt);
+ logerror(" - pit68230_device::read: offset=%02x data=%02x %s\n", offset, data, machine().describe_context());
}
or_cnt = 0;
or_data = data;
diff --git a/src/devices/machine/68230pit.h b/src/devices/machine/68230pit.h
index 72f6e94d373..663be81b151 100644
--- a/src/devices/machine/68230pit.h
+++ b/src/devices/machine/68230pit.h
@@ -68,7 +68,7 @@
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-class pit68230_device : public device_t//, public device_execute_interface
+class pit68230_device : public device_t
{
public:
// construction/destruction
@@ -100,37 +100,37 @@ public:
void pc_update_bit(uint8_t bit, uint8_t state);
void update_tin(uint8_t);
- DECLARE_WRITE_LINE_MEMBER( h1_w );
- DECLARE_WRITE_LINE_MEMBER( h2_w );
- DECLARE_WRITE_LINE_MEMBER( h3_w );
- DECLARE_WRITE_LINE_MEMBER( h4_w );
-
- DECLARE_WRITE_LINE_MEMBER( pa0_w ) { pa_update_bit(0, state); }
- DECLARE_WRITE_LINE_MEMBER( pa1_w ) { pa_update_bit(1, state); }
- DECLARE_WRITE_LINE_MEMBER( pa2_w ) { pa_update_bit(2, state); }
- DECLARE_WRITE_LINE_MEMBER( pa3_w ) { pa_update_bit(3, state); }
- DECLARE_WRITE_LINE_MEMBER( pa4_w ) { pa_update_bit(4, state); }
- DECLARE_WRITE_LINE_MEMBER( pa5_w ) { pa_update_bit(5, state); }
- DECLARE_WRITE_LINE_MEMBER( pa6_w ) { pa_update_bit(6, state); }
- DECLARE_WRITE_LINE_MEMBER( pa7_w ) { pa_update_bit(7, state); }
-
- DECLARE_WRITE_LINE_MEMBER( pb0_w ) { pb_update_bit(0, state); }
- DECLARE_WRITE_LINE_MEMBER( pb1_w ) { pb_update_bit(1, state); }
- DECLARE_WRITE_LINE_MEMBER( pb2_w ) { pb_update_bit(2, state); }
- DECLARE_WRITE_LINE_MEMBER( pb3_w ) { pb_update_bit(3, state); }
- DECLARE_WRITE_LINE_MEMBER( pb4_w ) { pb_update_bit(4, state); }
- DECLARE_WRITE_LINE_MEMBER( pb5_w ) { pb_update_bit(5, state); }
- DECLARE_WRITE_LINE_MEMBER( pb6_w ) { pb_update_bit(6, state); }
- DECLARE_WRITE_LINE_MEMBER( pb7_w ) { pb_update_bit(7, state); }
-
- DECLARE_WRITE_LINE_MEMBER( pc0_w ) { pc_update_bit(0, state); }
- DECLARE_WRITE_LINE_MEMBER( pc1_w ) { pc_update_bit(1, state); }
- DECLARE_WRITE_LINE_MEMBER( pc2_w ) { pc_update_bit(2, state); }
- DECLARE_WRITE_LINE_MEMBER( pc3_w ) { pc_update_bit(3, state); }
- DECLARE_WRITE_LINE_MEMBER( pc4_w ) { pc_update_bit(4, state); }
- DECLARE_WRITE_LINE_MEMBER( pc5_w ) { pc_update_bit(5, state); }
- DECLARE_WRITE_LINE_MEMBER( pc6_w ) { pc_update_bit(6, state); }
- DECLARE_WRITE_LINE_MEMBER( pc7_w ) { pc_update_bit(7, state); }
+ void h1_w(int state);
+ void h2_w(int state);
+ void h3_w(int state);
+ void h4_w(int state);
+
+ void pa0_w(int state) { pa_update_bit(0, state); }
+ void pa1_w(int state) { pa_update_bit(1, state); }
+ void pa2_w(int state) { pa_update_bit(2, state); }
+ void pa3_w(int state) { pa_update_bit(3, state); }
+ void pa4_w(int state) { pa_update_bit(4, state); }
+ void pa5_w(int state) { pa_update_bit(5, state); }
+ void pa6_w(int state) { pa_update_bit(6, state); }
+ void pa7_w(int state) { pa_update_bit(7, state); }
+
+ void pb0_w(int state) { pb_update_bit(0, state); }
+ void pb1_w(int state) { pb_update_bit(1, state); }
+ void pb2_w(int state) { pb_update_bit(2, state); }
+ void pb3_w(int state) { pb_update_bit(3, state); }
+ void pb4_w(int state) { pb_update_bit(4, state); }
+ void pb5_w(int state) { pb_update_bit(5, state); }
+ void pb6_w(int state) { pb_update_bit(6, state); }
+ void pb7_w(int state) { pb_update_bit(7, state); }
+
+ void pc0_w(int state) { pc_update_bit(0, state); }
+ void pc1_w(int state) { pc_update_bit(1, state); }
+ void pc2_w(int state) { pc_update_bit(2, state); }
+ void pc3_w(int state) { pc_update_bit(3, state); }
+ void pc4_w(int state) { pc_update_bit(4, state); }
+ void pc5_w(int state) { pc_update_bit(5, state); }
+ void pc6_w(int state) { pc_update_bit(6, state); }
+ void pc7_w(int state) { pc_update_bit(7, state); }
uint8_t irq_tiack();
uint8_t irq_piack();
@@ -272,19 +272,16 @@ protected:
REG_TCR_TOUT_PC7_INT = 0xe0, // 1 1 1
};
- void tick_clock();
-
pit68230_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// Interrupt methods
void trigger_interrupt(int source);
- int m_icount;
+ TIMER_CALLBACK_MEMBER(tick_clock);
devcb_write8 m_pa_out_cb;
devcb_read8 m_pa_in_cb;
@@ -330,11 +327,6 @@ protected:
// Timers
emu_timer *pit_timer;
-
- enum
- {
- TIMER_ID_PIT
- };
};
// device type definition
diff --git a/src/devices/machine/68307.cpp b/src/devices/machine/68307.cpp
index 2a16def71d9..a950be1fd2b 100644
--- a/src/devices/machine/68307.cpp
+++ b/src/devices/machine/68307.cpp
@@ -57,11 +57,11 @@ void m68307_cpu_device::device_add_mconfig(machine_config &config)
m68307_cpu_device::m68307_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- m68000_device(mconfig, tag, owner, clock, M68307, 16, 24, address_map_constructor(FUNC(m68307_cpu_device::internal_map), this)),
+ m68000_device(mconfig, M68307, tag, owner, clock),
m_write_irq(*this),
m_write_a_tx(*this),
m_write_b_tx(*this),
- m_read_inport(*this),
+ m_read_inport(*this, 0),
m_write_outport(*this),
m_porta_r(*this),
m_porta_w(*this),
@@ -79,6 +79,11 @@ m68307_cpu_device::m68307_cpu_device(const machine_config &mconfig, const char *
m_ipl = 0;
m_cpu_space_config.m_internal_map = address_map_constructor(FUNC(m68307_cpu_device::cpu_space_map), this);
+ auto imap = address_map_constructor(FUNC(m68307_cpu_device::internal_map), this);
+ m_program_config.m_internal_map = imap;
+ m_opcodes_config.m_internal_map = imap;
+ m_uprogram_config.m_internal_map = imap;
+ m_uopcodes_config.m_internal_map = imap;
}
@@ -101,7 +106,7 @@ void m68307_cpu_device::device_reset()
set_ipl(0);
}
-void m68307_cpu_device::m68k_reset_peripherals()
+void m68307_cpu_device::reset_peripherals(int state)
{
m_duart->reset();
@@ -127,23 +132,6 @@ inline int m68307_cpu_device::calc_cs(offs_t address) const
return 0;
}
-void m68307_cpu_device::init16_m68307(address_space &space)
-{
- m_space = &space;
- space.cache(m_oprogram16);
- space.specific(m_program16);
-
- m_readimm16 = [this](offs_t address) -> u16 { /* m_m68307_currentcs = calc_cs(address); */ return m_oprogram16.read_word(address); };
- m_read8 = [this](offs_t address) -> u8 { /* m_m68307_currentcs = calc_cs(address); */ return m_program16.read_byte(address); };
- m_read16 = [this](offs_t address) -> u16 { /* m_m68307_currentcs = calc_cs(address); */ return m_program16.read_word(address); };
- m_read32 = [this](offs_t address) -> u32 { /* m_m68307_currentcs = calc_cs(address); */ return m_program16.read_dword(address); };
- m_write8 = [this](offs_t address, u8 data) { /* m_m68307_currentcs = calc_cs(address); */ m_program16.write_byte(address, data); };
- m_write16 = [this](offs_t address, u16 data) { /* m_m68307_currentcs = calc_cs(address); */ m_program16.write_word(address, data); };
- m_write32 = [this](offs_t address, u32 data) { /* m_m68307_currentcs = calc_cs(address); */ m_program16.write_dword(address, data); };
-}
-
-
-
void m68307_cpu_device::set_port_callbacks(
porta_read_delegate &&porta_r,
porta_write_delegate &&porta_w,
@@ -182,7 +170,7 @@ void m68307_cpu_device::set_ipl(int level)
}
}
-WRITE_LINE_MEMBER(m68307_cpu_device::timer0_interrupt)
+void m68307_cpu_device::timer0_interrupt(int state)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x7000) >> 12;
if (state && m_ipl < prioritylevel)
@@ -191,7 +179,7 @@ WRITE_LINE_MEMBER(m68307_cpu_device::timer0_interrupt)
set_ipl(m_m68307SIM->get_ipl(this));
}
-WRITE_LINE_MEMBER(m68307_cpu_device::timer1_interrupt)
+void m68307_cpu_device::timer1_interrupt(int state)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x0700) >> 8;
if (state && m_ipl < prioritylevel)
@@ -200,7 +188,7 @@ WRITE_LINE_MEMBER(m68307_cpu_device::timer1_interrupt)
set_ipl(m_m68307SIM->get_ipl(this));
}
-WRITE_LINE_MEMBER(m68307_cpu_device::m68307_duart_irq_handler)
+void m68307_cpu_device::m68307_duart_irq_handler(int state)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x0070) >> 4;
if (state && m_ipl < prioritylevel)
@@ -209,7 +197,7 @@ WRITE_LINE_MEMBER(m68307_cpu_device::m68307_duart_irq_handler)
set_ipl(m_m68307SIM->get_ipl(this));
}
-WRITE_LINE_MEMBER(m68307_cpu_device::mbus_interrupt)
+void m68307_cpu_device::mbus_interrupt(int state)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x0007) >> 0;
if (state && m_ipl < prioritylevel)
@@ -242,14 +230,14 @@ uint8_t m68307_cpu_device::int_ack(offs_t offset)
void m68307_cpu_device::device_start()
{
- init_cpu_m68000();
+ reset_cb().append(*this, FUNC(m68307_cpu_device::reset_peripherals));
+
+ m68000_device::device_start();
/* basic CS logic, timers, mbus, serial logic
set via remappable register
*/
- init16_m68307(*m_program);
-
m_m68307SIM = new m68307_sim();
m_m68307MBUS = new m68307_mbus();
m_m68307TIMER = new m68307_timer();
@@ -260,17 +248,10 @@ void m68307_cpu_device::device_start()
m_m68307MBUS->reset();
m_m68307TIMER->reset();
- m_internal = &space(AS_PROGRAM);
m_m68307_base = 0xbfff;
m_m68307_scrhigh = 0x0007;
m_m68307_scrlow = 0xf010;
- m_write_irq.resolve_safe();
- m_write_a_tx.resolve_safe();
- m_write_b_tx.resolve_safe();
- m_read_inport.resolve();
- m_write_outport.resolve_safe();
-
m_porta_r.set(nullptr);
m_porta_w.set(nullptr);
m_portb_r.set(nullptr);
@@ -281,7 +262,7 @@ void m68307_cpu_device::device_start()
uint16_t m68307_cpu_device::m68307_internal_base_r(offs_t offset, uint16_t mem_mask)
{
- logerror("%08x m68307_internal_base_r %08x, (%04x)\n", m_ppc, offset*2,mem_mask);
+ logerror("%08x m68307_internal_base_r %08x, (%04x)\n", m_ipc, offset*2,mem_mask);
switch (offset<<1)
{
@@ -297,7 +278,9 @@ uint16_t m68307_cpu_device::m68307_internal_base_r(offs_t offset, uint16_t mem_m
void m68307_cpu_device::m68307_internal_base_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
- logerror("%08x m68307_internal_base_w %08x, %04x (%04x)\n", m_ppc, offset*2,data,mem_mask);
+ // emumem needs some kind of overlay capability... it's probably not the only one
+
+ logerror("%08x m68307_internal_base_w %08x, %04x (%04x)\n", m_ipc, offset*2,data,mem_mask);
int base;
//int mask = 0;
@@ -308,10 +291,10 @@ void m68307_cpu_device::m68307_internal_base_w(offs_t offset, uint16_t data, uin
base = (m_m68307_base & 0x0fff) << 12;
//mask = (m_m68307_base & 0xe000) >> 13;
//if ( m_m68307_base & 0x1000 ) mask |= 7;
- m_internal->unmap_readwrite(base+0x000, base+0x04f);
- m_internal->unmap_readwrite(base+0x100, base+0x11f);
- m_internal->unmap_readwrite(base+0x120, base+0x13f);
- m_internal->unmap_readwrite(base+0x140, base+0x149);
+ m_s_program->unmap_readwrite(base+0x000, base+0x04f);
+ m_s_program->unmap_readwrite(base+0x100, base+0x11f);
+ m_s_program->unmap_readwrite(base+0x120, base+0x13f);
+ m_s_program->unmap_readwrite(base+0x140, base+0x149);
/* store new base address */
COMBINE_DATA(&m_m68307_base);
@@ -320,10 +303,10 @@ void m68307_cpu_device::m68307_internal_base_w(offs_t offset, uint16_t data, uin
base = (m_m68307_base & 0x0fff) << 12;
//mask = (m_m68307_base & 0xe000) >> 13;
//if ( m_m68307_base & 0x1000 ) mask |= 7;
- m_internal->install_readwrite_handler(base + 0x000, base + 0x04f, read16_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_sim_r)), write16_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_sim_w)));
- m_internal->install_readwrite_handler(base + 0x100, base + 0x11f, read8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_serial_r)), write8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_serial_w)), 0xffff);
- m_internal->install_readwrite_handler(base + 0x120, base + 0x13f, read16s_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_timer_r)), write16s_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_timer_w)));
- m_internal->install_readwrite_handler(base + 0x140, base + 0x149, read8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_mbus_r)), write8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_mbus_w)), 0xffff);
+ m_s_program->install_readwrite_handler(base + 0x000, base + 0x04f, read16_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_sim_r)), write16_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_sim_w)));
+ m_s_program->install_readwrite_handler(base + 0x100, base + 0x11f, read8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_serial_r)), write8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_serial_w)), 0xffff);
+ m_s_program->install_readwrite_handler(base + 0x120, base + 0x13f, read16s_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_timer_r)), write16s_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_timer_w)));
+ m_s_program->install_readwrite_handler(base + 0x140, base + 0x149, read8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_mbus_r)), write8sm_delegate(*this, FUNC(m68307_cpu_device::m68307_internal_mbus_w)), 0xffff);
break;
diff --git a/src/devices/machine/68307.h b/src/devices/machine/68307.h
index cc5638b5efb..7056c21548b 100644
--- a/src/devices/machine/68307.h
+++ b/src/devices/machine/68307.h
@@ -40,24 +40,22 @@ protected:
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
- virtual void m68k_reset_peripherals() override;
-
private:
+ void reset_peripherals(int state);
+
void set_ipl(int level);
- DECLARE_WRITE_LINE_MEMBER(timer0_interrupt);
- DECLARE_WRITE_LINE_MEMBER(timer1_interrupt);
- DECLARE_WRITE_LINE_MEMBER(mbus_interrupt);
+ void timer0_interrupt(int state);
+ void timer1_interrupt(int state);
+ void mbus_interrupt(int state);
uint8_t int_ack(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER(m68307_duart_irq_handler);
- DECLARE_WRITE_LINE_MEMBER(m68307_duart_txa) { m_write_a_tx(state); }
- DECLARE_WRITE_LINE_MEMBER(m68307_duart_txb) { m_write_b_tx(state); }
+ void m68307_duart_irq_handler(int state);
+ void m68307_duart_txa(int state) { m_write_a_tx(state); }
+ void m68307_duart_txb(int state) { m_write_b_tx(state); }
uint8_t m68307_duart_input_r() { return m_read_inport(); }
void m68307_duart_output_w(uint8_t data) { m_write_outport(data); }
- void init16_m68307(address_space &space);
-
int calc_cs(offs_t address) const;
uint16_t m68307_internal_base_r(offs_t offset, uint16_t mem_mask = ~0);
diff --git a/src/devices/machine/68307bus.cpp b/src/devices/machine/68307bus.cpp
index 9b6788865e9..2179b1cb443 100644
--- a/src/devices/machine/68307bus.cpp
+++ b/src/devices/machine/68307bus.cpp
@@ -22,19 +22,19 @@ uint8_t m68307_cpu_device::m68307_internal_mbus_r(offs_t offset)
switch (offset)
{
case m68307BUS_MADR:
- logerror("%08x m68307_internal_mbus_r %08x (MADR - M-Bus Address Register)\n", m_ppc, offset);
+ logerror("%08x m68307_internal_mbus_r %08x (MADR - M-Bus Address Register)\n", m_ipc, offset);
return machine().rand();
case m68307BUS_MFDR:
- logerror("%08x m68307_internal_mbus_r %08x (MFDR - M-Bus Frequency Divider Register)\n", m_ppc, offset);
+ logerror("%08x m68307_internal_mbus_r %08x (MFDR - M-Bus Frequency Divider Register)\n", m_ipc, offset);
return machine().rand();
case m68307BUS_MBCR:
- logerror("%08x m68307_internal_mbus_r %08x (MFCR - M-Bus Control Register)\n", m_ppc, offset);
+ logerror("%08x m68307_internal_mbus_r %08x (MFCR - M-Bus Control Register)\n", m_ipc, offset);
return mbus.m_MFCR;//machine().rand();
case m68307BUS_MBSR:
- logerror("%08x m68307_internal_mbus_r %08x (MBSR - M-Bus Status Register)\n", m_ppc, offset);
+ logerror("%08x m68307_internal_mbus_r %08x (MBSR - M-Bus Status Register)\n", m_ipc, offset);
retval = 0;
if (mbus.m_busy) retval |= 0x20;
if (mbus.m_intpend) retval |= 0x02;
@@ -42,13 +42,13 @@ uint8_t m68307_cpu_device::m68307_internal_mbus_r(offs_t offset)
return retval;
case m68307BUS_MBDR:
- logerror("%08x m68307_internal_mbus_r %08x (MBDR - M-Bus Data I/O Register)\n", m_ppc, offset);
+ logerror("%08x m68307_internal_mbus_r %08x (MBDR - M-Bus Data I/O Register)\n", m_ipc, offset);
mbus.m_intpend = true;
mbus_interrupt(1);
return 0xff;//machine().rand();
default:
- logerror("%08x m68307_internal_mbus_r %08x (UNKNOWN / ILLEGAL)\n", m_ppc, offset);
+ logerror("%08x m68307_internal_mbus_r %08x (UNKNOWN / ILLEGAL)\n", m_ipc, offset);
return 0x00;
}
@@ -63,15 +63,15 @@ void m68307_cpu_device::m68307_internal_mbus_w(offs_t offset, uint8_t data)
switch (offset)
{
case m68307BUS_MADR:
- logerror("%08x m68307_internal_mbus_w %08x, %02x (MADR - M-Bus Address Register)\n", m_ppc, offset,data);
+ logerror("%08x m68307_internal_mbus_w %08x, %02x (MADR - M-Bus Address Register)\n", m_ipc, offset,data);
break;
case m68307BUS_MFDR:
- logerror("%08x m68307_internal_mbus_w %08x, %02x (MFDR - M-Bus Frequency Divider Register)\n", m_ppc, offset,data);
+ logerror("%08x m68307_internal_mbus_w %08x, %02x (MFDR - M-Bus Frequency Divider Register)\n", m_ipc, offset,data);
break;
case m68307BUS_MBCR:
- logerror("%08x m68307_internal_mbus_w %08x, %02x (MFCR - M-Bus Control Register)\n", m_ppc, offset,data);
+ logerror("%08x m68307_internal_mbus_w %08x, %02x (MFCR - M-Bus Control Register)\n", m_ipc, offset,data);
mbus.m_MFCR = data;
if (data & 0x80)
@@ -85,11 +85,11 @@ void m68307_cpu_device::m68307_internal_mbus_w(offs_t offset, uint8_t data)
break;
case m68307BUS_MBSR:
- logerror("%08x m68307_internal_mbus_w %08x, %02x (MBSR - M-Bus Status Register)\n", m_ppc, offset,data);
+ logerror("%08x m68307_internal_mbus_w %08x, %02x (MBSR - M-Bus Status Register)\n", m_ipc, offset,data);
break;
case m68307BUS_MBDR:
- logerror("%08x m68307_internal_mbus_w %08x, %02x (MBDR - M-Bus Data I/O Register)\n", m_ppc, offset,data);
+ logerror("%08x m68307_internal_mbus_w %08x, %02x (MBDR - M-Bus Data I/O Register)\n", m_ipc, offset,data);
mbus.m_intpend = true;
mbus_interrupt(1);
@@ -97,7 +97,7 @@ void m68307_cpu_device::m68307_internal_mbus_w(offs_t offset, uint8_t data)
break;
default:
- logerror("%08x m68307_internal_mbus_w %08x, %02x (UNKNOWN / ILLEGAL)\n", m_ppc, offset,data);
+ logerror("%08x m68307_internal_mbus_w %08x, %02x (UNKNOWN / ILLEGAL)\n", m_ipc, offset,data);
break;
}
}
diff --git a/src/devices/machine/68307sim.cpp b/src/devices/machine/68307sim.cpp
index a62a2911ab4..0f592662d50 100644
--- a/src/devices/machine/68307sim.cpp
+++ b/src/devices/machine/68307sim.cpp
@@ -54,7 +54,7 @@ uint16_t m68307_cpu_device::m68307_internal_sim_r(address_space &space, offs_t o
case m68307SIM_OR3: return sim.m_or[3];
default:
- logerror("%08x m68307_internal_sim_r %08x, (%04x)\n", m_ppc, offset*2, mem_mask);
+ logerror("%08x m68307_internal_sim_r %08x, (%04x)\n", m_ipc, offset*2, mem_mask);
return 0xff;
}
@@ -70,12 +70,12 @@ void m68307_cpu_device::m68307_internal_sim_w(address_space &space, offs_t offse
switch (offset<<1)
{
case m68307SIM_PACNT:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port A (8-bit) Control Register - PACNT)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port A (8-bit) Control Register - PACNT)\n", m_ipc, offset*2,data,mem_mask);
sim.write_pacnt(data,mem_mask);
break;
case m68307SIM_PADDR:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port A (8-bit) Direction Register - PADDR)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port A (8-bit) Direction Register - PADDR)\n", m_ipc, offset*2,data,mem_mask);
sim.write_paddr(data,mem_mask);
break;
@@ -84,12 +84,12 @@ void m68307_cpu_device::m68307_internal_sim_w(address_space &space, offs_t offse
break;
case m68307SIM_PBCNT:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port B (16-bit) Control Register - PBCNT)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port B (16-bit) Control Register - PBCNT)\n", m_ipc, offset*2,data,mem_mask);
sim.write_pbcnt(data,mem_mask);
break;
case m68307SIM_PBDDR:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port B (16-bit) Direction Register - PBDDR)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port B (16-bit) Direction Register - PBDDR)\n", m_ipc, offset*2,data,mem_mask);
sim.write_pbddr(data,mem_mask);
break;
@@ -99,22 +99,22 @@ void m68307_cpu_device::m68307_internal_sim_w(address_space &space, offs_t offse
case m68307SIM_LICR1:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Latched Interrupt Control Register 1 - LICR1)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Latched Interrupt Control Register 1 - LICR1)\n", m_ipc, offset*2,data,mem_mask);
sim.write_licr1(this,data,mem_mask);
break;
case m68307SIM_LICR2:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Latched Interrupt Control Register 2 - LICR2)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Latched Interrupt Control Register 2 - LICR2)\n", m_ipc, offset*2,data,mem_mask);
sim.write_licr2(this,data,mem_mask);
break;
case m68307SIM_PICR:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Peripheral Interrupt Control Register - PICR)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Peripheral Interrupt Control Register - PICR)\n", m_ipc, offset*2,data,mem_mask);
sim.write_picr(this,data,mem_mask);
break;
case m68307SIM_PIVR:
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Peripheral Interrupt Vector Register - PIVR)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Peripheral Interrupt Vector Register - PIVR)\n", m_ipc, offset*2,data,mem_mask);
sim.write_pivr(this,data,mem_mask);
break;
@@ -146,7 +146,7 @@ void m68307_cpu_device::m68307_internal_sim_w(address_space &space, offs_t offse
default :
- logerror("%08x m68307_internal_sim_w %08x, %04x (%04x)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_sim_w %08x, %04x (%04x)\n", m_ipc, offset*2,data,mem_mask);
break;
}
}
diff --git a/src/devices/machine/68307tmu.cpp b/src/devices/machine/68307tmu.cpp
index 02e98e78983..12c999c0b40 100644
--- a/src/devices/machine/68307tmu.cpp
+++ b/src/devices/machine/68307tmu.cpp
@@ -25,11 +25,11 @@ uint16_t m68307_cpu_device::m68307_internal_timer_r(offs_t offset, uint16_t mem_
switch (offset&0x7)
{
case m68307TIMER_TCN: /* 0x3 (0x126 / 0x136) */
- //if (m_ppc!=0x2182e) logerror("%08x m68307_internal_timer_r %08x (%04x) (TCN - Timer Counter for timer %d)\n", m_ppc, offset*2,mem_mask, which);
+ //if (m_ipc!=0x2182e) logerror("%08x m68307_internal_timer_r %08x (%04x) (TCN - Timer Counter for timer %d)\n", m_ipc, offset*2,mem_mask, which);
return timer.read_tcn(mem_mask, which);
default:
- logerror("%08x m68307_internal_timer_r %08x, (%04x)\n", m_ppc, offset*2,mem_mask);
+ logerror("%08x m68307_internal_timer_r %08x, (%04x)\n", m_ipc, offset*2,mem_mask);
break;
}
@@ -46,79 +46,77 @@ void m68307_cpu_device::m68307_internal_timer_w(offs_t offset, uint16_t data, ui
switch (offset&0x7)
{
case m68307TIMER_TMR: /* 0x0 (0x120 / 0x130) */
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TMR - Timer Mode Register for timer %d)\n", m_ppc, offset*2,data,mem_mask, which);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TMR - Timer Mode Register for timer %d)\n", m_ipc, offset*2,data,mem_mask, which);
timer.write_tmr(data, mem_mask, which);
break;
case m68307TIMER_TRR: /* 0x1 (0x122 / 0x132) */
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TRR - Timer Reference Register for timer %d)\n", m_ppc, offset*2,data,mem_mask, which);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TRR - Timer Reference Register for timer %d)\n", m_ipc, offset*2,data,mem_mask, which);
timer.write_trr(data, mem_mask, which);
break;
case m68307TIMER_TCR: /* 0x2 (0x124 / 0x134) */
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TCR - Timer Capture Register for timer %d) (illegal, read-only)\n", m_ppc, offset*2,data,mem_mask, which);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TCR - Timer Capture Register for timer %d) (illegal, read-only)\n", m_ipc, offset*2,data,mem_mask, which);
break;
case m68307TIMER_TCN: /* 0x3 (0x126 / 0x136) */
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TCN - Timer Counter for timer %d)\n", m_ppc, offset*2,data,mem_mask, which);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TCN - Timer Counter for timer %d)\n", m_ipc, offset*2,data,mem_mask, which);
break;
case m68307TIMER_TER: /* 0x4 (0x128 / 0x138) */
/* 8-bit only!! */
- //logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TER - Timer Event Register for timer %d)\n", m_ppc, offset*2,data,mem_mask, which);
+ //logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TER - Timer Event Register for timer %d)\n", m_ipc, offset*2,data,mem_mask, which);
timer.write_ter(data, mem_mask, which);
break;
case m68307TIMER_WRR: /* 0x5 (0x12a / 0x13a) */
if (which==0)
{
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (WRR - Watchdog Reference Register)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (WRR - Watchdog Reference Register)\n", m_ipc, offset*2,data,mem_mask);
}
else
{
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", m_ipc, offset*2,data,mem_mask);
}
break;
case m68307TIMER_WCR: /* 0x6 (0x12c / 0x13c) */
if (which==0)
{
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (WRR - Watchdog Counter Register)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (WRR - Watchdog Counter Register)\n", m_ipc, offset*2,data,mem_mask);
}
else
{
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", m_ipc, offset*2,data,mem_mask);
}
break;
case m68307TIMER_XXX: /* 0x7 (0x12e / 0x13e) */
- logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", m_ppc, offset*2,data,mem_mask);
+ logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", m_ipc, offset*2,data,mem_mask);
break;
}
}
TIMER_CALLBACK_MEMBER(m68307_cpu_device::m68307_timer::timer0_callback )
{
- m68307_cpu_device* m68k = (m68307_cpu_device *)ptr;
- single_timer* tptr = &m68k->m_m68307TIMER->singletimer[0];
+ single_timer* tptr = &parent->m_m68307TIMER->singletimer[0];
tptr->regs[m68307TIMER_TER] |= 0x2;
if (BIT(tptr->regs[m68307TIMER_TMR], 4))
- m68k->timer0_interrupt(1);
+ parent->timer0_interrupt(1);
- tptr->mametimer->adjust(m68k->cycles_to_attotime(20000));
+ tptr->mametimer->adjust(parent->cycles_to_attotime(20000));
}
TIMER_CALLBACK_MEMBER(m68307_cpu_device::m68307_timer::timer1_callback )
{
- m68307_cpu_device* m68k = (m68307_cpu_device *)ptr;
- single_timer* tptr = &m68k->m_m68307TIMER->singletimer[1];
+ single_timer* tptr = &parent->m_m68307TIMER->singletimer[1];
tptr->regs[m68307TIMER_TER] |= 0x2;
if (BIT(tptr->regs[m68307TIMER_TMR], 4))
- m68k->timer1_interrupt(1);
+ parent->timer1_interrupt(1);
- tptr->mametimer->adjust(m68k->cycles_to_attotime(20000));
+ tptr->mametimer->adjust(parent->cycles_to_attotime(20000));
}
@@ -134,12 +132,12 @@ void m68307_cpu_device::m68307_timer::init(m68307_cpu_device *device)
single_timer* tptr;
tptr = &singletimer[0];
- tptr->mametimer = device->machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68307_timer::timer0_callback),this), parent);
+ tptr->mametimer = device->timer_alloc(FUNC(m68307_timer::timer0_callback), this);
tptr = &singletimer[1];
- tptr->mametimer = device->machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68307_timer::timer1_callback),this), parent);
+ tptr->mametimer = device->timer_alloc(FUNC(m68307_timer::timer1_callback), this);
- wd_mametimer = device->machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68307_timer::wd_timer_callback),this), parent);
+ wd_mametimer = device->timer_alloc(FUNC(m68307_timer::wd_timer_callback), this);
}
uint16_t m68307_cpu_device::m68307_timer::read_tcn(uint16_t mem_mask, int which)
@@ -152,7 +150,7 @@ uint16_t m68307_cpu_device::m68307_timer::read_tcn(uint16_t mem_mask, int which)
void m68307_cpu_device::m68307_timer::write_ter(uint16_t data, uint16_t mem_mask, int which)
{
- assert(which >= 0 && which < ARRAY_LENGTH(singletimer));
+ assert(which >= 0 && which < std::size(singletimer));
single_timer* tptr = &singletimer[which];
if (data & 0x2)
{
@@ -167,7 +165,7 @@ void m68307_cpu_device::m68307_timer::write_ter(uint16_t data, uint16_t mem_mask
void m68307_cpu_device::m68307_timer::write_tmr(uint16_t data, uint16_t mem_mask, int which)
{
m68307_cpu_device* m68k = parent;
- assert(which >= 0 && which < ARRAY_LENGTH(singletimer));
+ assert(which >= 0 && which < std::size(singletimer));
single_timer* tptr = &singletimer[which];
COMBINE_DATA(&tptr->regs[m68307TIMER_TMR]);
@@ -216,7 +214,7 @@ void m68307_cpu_device::m68307_timer::write_tmr(uint16_t data, uint16_t mem_mask
void m68307_cpu_device::m68307_timer::write_trr(uint16_t data, uint16_t mem_mask, int which)
{
- assert(which >= 0 && which < ARRAY_LENGTH(singletimer));
+ assert(which >= 0 && which < std::size(singletimer));
single_timer* tptr = &singletimer[which];
COMBINE_DATA(&tptr->regs[m68307TIMER_TRR]);
@@ -248,7 +246,7 @@ void m68307_cpu_device::m68307_timer::reset()
bool m68307_cpu_device::m68307_timer::timer_int_pending(int which) const
{
- assert(which >= 0 && which < ARRAY_LENGTH(singletimer));
+ assert(which >= 0 && which < std::size(singletimer));
const single_timer* tptr = &singletimer[which];
return BIT(tptr->regs[m68307TIMER_TER], 1) && BIT(tptr->regs[m68307TIMER_TMR], 4);
diff --git a/src/devices/machine/68340.cpp b/src/devices/machine/68340.cpp
index 56a4ff007a6..84d0d698d6a 100644
--- a/src/devices/machine/68340.cpp
+++ b/src/devices/machine/68340.cpp
@@ -9,8 +9,8 @@
#include <algorithm>
-#define LOG_BASE (1 << 1U)
-#define LOG_IPL (1 << 2U)
+#define LOG_BASE (1U << 1)
+#define LOG_IPL (1U << 2)
#define VERBOSE (LOG_BASE)
#include "logmacro.h"
@@ -127,16 +127,16 @@ uint8_t m68340_cpu_device::int_ack(offs_t offset)
/* 68340 specifics - MOVE */
-uint32_t m68340_cpu_device::m68340_internal_base_r(offs_t offset, uint32_t mem_mask)
+uint16_t m68340_cpu_device::m68340_internal_base_r(offs_t offset, uint16_t mem_mask)
{
if (!machine().side_effects_disabled())
- LOGMASKED(LOG_BASE, "%08x m68340_internal_base_r %08x, (%08x)\n", m_ppc, offset*4,mem_mask);
- return m_m68340_base;
+ LOGMASKED(LOG_BASE, "%08x m68340_internal_base_r %08x, (%08x)\n", m_ppc, offset*2,mem_mask);
+ return ((!BIT(offset, 0) ? (m_m68340_base >> 16): m_m68340_base)) & 0xffff;
}
-void m68340_cpu_device::m68340_internal_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void m68340_cpu_device::m68340_internal_base_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
- LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %08x (%08x)\n", m_ppc, offset*4,data,mem_mask);
+ LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %08x (%08x)\n", m_ppc, offset*2,data,mem_mask);
// other conditions?
if (m_dfc==0x7)
@@ -153,8 +153,16 @@ void m68340_cpu_device::m68340_internal_base_w(offs_t offset, uint32_t data, uin
}
- COMBINE_DATA(&m_m68340_base);
- LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %08x (%08x) (m_m68340_base write)\n", pc(), offset*4,data,mem_mask);
+ uint32_t data32 = data;
+ uint32_t mem_mask32 = mem_mask;
+ if (!BIT(offset,0))
+ {
+ data32 <<= 16;
+ mem_mask32 <<= 16;
+ }
+
+ m_m68340_base = (m_m68340_base & ~mem_mask32) | (data32 & mem_mask32);
+ LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %08x (%08x) (m_m68340_base write)\n", pc(), offset*2,data,mem_mask);
// map new modules
if (m_m68340_base & 1)
@@ -168,8 +176,8 @@ void m68340_cpu_device::m68340_internal_base_w(offs_t offset, uint32_t data, uin
read8sm_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_sim_ports_r)),
write8sm_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_sim_ports_w)),0xffffffff);
m_internal->install_readwrite_handler(base + 0x040, base + 0x05f,
- read32s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_sim_cs_r)),
- write32s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_sim_cs_w)));
+ read16s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_sim_cs_r)),
+ write16s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_sim_cs_w)));
m_internal->install_readwrite_handler(base + 0x600, base + 0x63f,
read16s_delegate(*m_timer[0], FUNC(mc68340_timer_module_device::read)),
write16s_delegate(*m_timer[0], FUNC(mc68340_timer_module_device::write)),0xffffffff);
@@ -180,13 +188,13 @@ void m68340_cpu_device::m68340_internal_base_w(offs_t offset, uint32_t data, uin
read8sm_delegate(*m_serial, FUNC(mc68340_serial_module_device::read)),
write8sm_delegate(*m_serial, FUNC(mc68340_serial_module_device::write)),0xffffffff);
m_internal->install_readwrite_handler(base + 0x780, base + 0x7bf,
- read32s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_dma_r)),
- write32s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_dma_w)));
+ read16s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_dma_r)),
+ write16s_delegate(*this, FUNC(m68340_cpu_device::m68340_internal_dma_w)));
}
}
else
{
- LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %04x (%04x) (should fall through?)\n", pc(), offset*4,data,mem_mask);
+ LOGMASKED(LOG_BASE, "%08x m68340_internal_base_w %08x, %04x (%04x) (should fall through?)\n", pc(), offset*2,data,mem_mask);
}
}
@@ -214,16 +222,16 @@ void m68340_cpu_device::device_add_mconfig(machine_config &config)
//**************************************************************************
m68340_cpu_device::m68340_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : fscpu32_device(mconfig, tag, owner, clock, M68340, 32,32, address_map_constructor(FUNC(m68340_cpu_device::m68340_internal_map), this))
+ : fscpu32_device(mconfig, tag, owner, clock, M68340, address_map_constructor(FUNC(m68340_cpu_device::m68340_internal_map), this))
, m_serial(*this, "serial")
, m_timer(*this, "timer%u", 1U)
, m_clock_mode(0)
, m_crystal(0)
, m_extal(0)
, m_pa_out_cb(*this)
- , m_pa_in_cb(*this)
+ , m_pa_in_cb(*this, 0)
, m_pb_out_cb(*this)
- , m_pb_in_cb(*this)
+ , m_pb_in_cb(*this, 0)
{
m_m68340SIM = nullptr;
m_m68340DMA = nullptr;
@@ -239,7 +247,7 @@ void m68340_cpu_device::device_reset()
// Some hardwares pulls this low when resetting peripherals, most just ties this line to GND or VCC
// TODO: Support Limp mode and external clock with no PLL
-WRITE_LINE_MEMBER( m68340_cpu_device::set_modck )
+void m68340_cpu_device::set_modck(int state)
{
m_modck = state;
m_clock_mode &= ~(m68340_sim::CLOCK_MODCK | m68340_sim::CLOCK_PLL);
@@ -263,11 +271,23 @@ void m68340_cpu_device::device_start()
m_internal = &space(AS_PROGRAM);
}
-void m68340_cpu_device::m68k_reset_peripherals()
+
+void m68340_cpu_device::device_config_complete()
{
- m_m68340SIM->module_reset();
- m_m68340DMA->module_reset();
- m_serial->module_reset();
- m_timer[0]->module_reset();
- m_timer[1]->module_reset();
+ fscpu32_device::device_config_complete();
+
+ reset_cb().append(*this, FUNC(m68340_cpu_device::reset_peripherals));
+}
+
+
+void m68340_cpu_device::reset_peripherals(int state)
+{
+ if (state)
+ {
+ m_m68340SIM->module_reset();
+ m_m68340DMA->module_reset();
+ m_serial->module_reset();
+ m_timer[0]->module_reset();
+ m_timer[1]->module_reset();
+ }
}
diff --git a/src/devices/machine/68340.h b/src/devices/machine/68340.h
index 7f9d5c1e706..848cb7d3832 100644
--- a/src/devices/machine/68340.h
+++ b/src/devices/machine/68340.h
@@ -6,7 +6,7 @@
#pragma once
-#include "cpu/m68000/m68000.h"
+#include "cpu/m68000/fscpu32.h"
#include "68340sim.h"
#include "68340dma.h"
@@ -28,10 +28,8 @@ public:
auto pb_out_callback() { return m_pb_out_cb.bind(); }
auto tout1_out_callback() { return m_timer[0]->m_tout_out_cb.bind(); }
- auto tin1_in_callback() { return m_timer[0]->m_tin_in_cb.bind(); }
auto tgate1_in_callback() { return m_timer[0]->m_tgate_in_cb.bind(); }
auto tout2_out_callback() { return m_timer[1]->m_tout_out_cb.bind(); }
- auto tin2_in_callback() { return m_timer[1]->m_tin_in_cb.bind(); }
auto tgate2_in_callback() { return m_timer[1]->m_tgate_in_cb.bind(); }
uint16_t get_cs(offs_t address);
@@ -39,17 +37,18 @@ public:
void set_crystal(const XTAL &crystal) { set_crystal(crystal.value()); }
// Timer input methods, can be used instead of the corresponding polling MCFG callbacks
- DECLARE_WRITE_LINE_MEMBER( tin1_w ) { m_timer[0]->tin_w(state); }
- DECLARE_WRITE_LINE_MEMBER( tgate1_w ){ m_timer[0]->tgate_w(state); }
- DECLARE_WRITE_LINE_MEMBER( tin2_w ) { m_timer[1]->tin_w(state); }
- DECLARE_WRITE_LINE_MEMBER( tgate2_w ){ m_timer[1]->tgate_w(state); }
+ void tin1_w(int state) { m_timer[0]->tin_w(state); }
+ void tgate1_w(int state){ m_timer[0]->tgate_w(state); }
+ void tin2_w(int state) { m_timer[1]->tin_w(state); }
+ void tgate2_w(int state){ m_timer[1]->tgate_w(state); }
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_config_complete() override;
- virtual void m68k_reset_peripherals() override;
+ void reset_peripherals(int state);
private:
required_device<mc68340_serial_module_device> m_serial;
@@ -83,20 +82,20 @@ private:
m_clock_mode |= (m68340_sim::CLOCK_MODCK | m68340_sim::CLOCK_PLL);
}
- uint32_t m68340_internal_base_r(offs_t offset, uint32_t mem_mask = ~0);
- void m68340_internal_base_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t m68340_internal_dma_r(offs_t offset, uint32_t mem_mask = ~0);
- void m68340_internal_dma_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint16_t m68340_internal_base_r(offs_t offset, uint16_t mem_mask = ~0);
+ void m68340_internal_base_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t m68340_internal_dma_r(offs_t offset, uint16_t mem_mask = ~0);
+ void m68340_internal_dma_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t m68340_internal_sim_r(offs_t offset, uint16_t mem_mask = ~0);
uint8_t m68340_internal_sim_ports_r(offs_t offset);
- uint32_t m68340_internal_sim_cs_r(offs_t offset, uint32_t mem_mask = ~0);
+ uint16_t m68340_internal_sim_cs_r(offs_t offset, uint16_t mem_mask = ~0);
void m68340_internal_sim_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void m68340_internal_sim_ports_w(offs_t offset, uint8_t data);
- void m68340_internal_sim_cs_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ void m68340_internal_sim_cs_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
// Clock/VCO setting TODO: support external clock with PLL and Limp mode
- DECLARE_WRITE_LINE_MEMBER( set_modck );
- DECLARE_WRITE_LINE_MEMBER( extal_w );
+ void set_modck(int state);
+ void extal_w(int state);
void m68340_internal_map(address_map &map);
diff --git a/src/devices/machine/68340dma.cpp b/src/devices/machine/68340dma.cpp
index 6cff61a9464..1a832ff95c4 100644
--- a/src/devices/machine/68340dma.cpp
+++ b/src/devices/machine/68340dma.cpp
@@ -6,22 +6,22 @@
#include "68340.h"
-uint32_t m68340_cpu_device::m68340_internal_dma_r(offs_t offset, uint32_t mem_mask)
+uint16_t m68340_cpu_device::m68340_internal_dma_r(offs_t offset, uint16_t mem_mask)
{
assert(m_m68340DMA);
//m68340_dma &dma = *m_m68340DMA;
- logerror("%08x m68340_internal_dma_r %08x, (%08x)\n", m_ppc, offset*4,mem_mask);
+ logerror("%08x m68340_internal_dma_r %08x, (%08x)\n", m_ppc, offset*2,mem_mask);
return 0x00000000;
}
-void m68340_cpu_device::m68340_internal_dma_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void m68340_cpu_device::m68340_internal_dma_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
assert(m_m68340DMA);
//m68340_dma &dma = *m_m68340DMA;
- logerror("%08x m68340_internal_dma_w %08x, %08x (%08x)\n", m_ppc, offset*4,data,mem_mask);
+ logerror("%08x m68340_internal_dma_w %08x, %08x (%08x)\n", m_ppc, offset*2,data,mem_mask);
}
void m68340_dma::reset()
diff --git a/src/devices/machine/68340ser.cpp b/src/devices/machine/68340ser.cpp
index e0fc3b29fde..c74fc375f04 100644
--- a/src/devices/machine/68340ser.cpp
+++ b/src/devices/machine/68340ser.cpp
@@ -9,18 +9,16 @@
// MACROS / CONSTANTS
//**************************************************************************
-//#define LOG_GENERAL (1U << 0) // Already defined in logmacro.h
-#define LOG_SETUP (1U << 1)
-#define LOG_READ (1U << 2)
-#define LOG_SERIAL (1U << 3)
-#define LOG_INT (1U << 4)
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_SERIAL (1U << 3)
+#define LOG_INT (1U << 4)
//#define VERBOSE (LOG_SETUP|LOG_READ|LOG_SERIAL|LOG_INT)
#define LOG_OUTPUT_FUNC printf // Needs always to be enabled as the default value 'logerror' is not available here
#include "logmacro.h"
-//#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__) // Already defined in logmacro.h
#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__)
#define LOGSERIAL(...) LOGMASKED(LOG_SERIAL, __VA_ARGS__)
@@ -146,7 +144,7 @@ void mc68340_serial_module_device::write(offs_t offset, uint8_t data)
}
-WRITE_LINE_MEMBER( mc68340_serial_module_device::irq_w )
+void mc68340_serial_module_device::irq_w(int state)
{
LOGINT("IRQ!\n%s\n", FUNCNAME);
m_cpu->update_ipl();
diff --git a/src/devices/machine/68340ser.h b/src/devices/machine/68340ser.h
index b9775f2ad86..35a2f77e92b 100644
--- a/src/devices/machine/68340ser.h
+++ b/src/devices/machine/68340ser.h
@@ -21,7 +21,7 @@ public:
virtual uint8_t read(offs_t offset) override;
virtual void write(offs_t offset, uint8_t data) override;
- DECLARE_WRITE_LINE_MEMBER(irq_w);
+ void irq_w(int state);
uint8_t irq_level() const { return irq_pending() ? (m_ilr & REG_ILR_MASK) : 0; }
uint8_t irq_vector() const { return m_ivr; }
diff --git a/src/devices/machine/68340sim.cpp b/src/devices/machine/68340sim.cpp
index 7e1f8457224..4ef9a9c28a0 100644
--- a/src/devices/machine/68340sim.cpp
+++ b/src/devices/machine/68340sim.cpp
@@ -9,23 +9,21 @@
// MACROS / CONSTANTS
//**************************************************************************
-//#define LOG_GENERAL (1U << 0) // Already defined in logmacro.h
-#define LOG_SETUP (1U << 1)
-#define LOG_READ (1U << 2)
-#define LOG_PORTS (1U << 3)
-#define LOG_SIM (1U << 4)
-#define LOG_CLOCK (1U << 5)
-#define LOG_DATA (1U << 6)
-#define LOG_INT (1U << 7)
-#define LOG_PIT (1U << 8)
-#define LOG_CS (1U << 9)
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_PORTS (1U << 3)
+#define LOG_SIM (1U << 4)
+#define LOG_CLOCK (1U << 5)
+#define LOG_DATA (1U << 6)
+#define LOG_INT (1U << 7)
+#define LOG_PIT (1U << 8)
+#define LOG_CS (1U << 9)
#define VERBOSE (LOG_PIT)
#define LOG_OUTPUT_FUNC printf // Needs always to be enabled as the default value 'logerror' is not available here
#include "logmacro.h"
-//#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__) // Already defined in logmacro.h
#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__)
#define LOGPORTS(...) LOGMASKED(LOG_PORTS, __VA_ARGS__)
@@ -115,7 +113,7 @@ void m68340_cpu_device::m68340_internal_sim_w(offs_t offset, uint16_t data, uint
LOGSIM("PC: %08x %s %04x, %04x (%04x) (MCR - Module Configuration Register)\n", m_ppc, FUNCNAME, offset * 2, data, mem_mask);
LOGPIT("- FRZ1: Watchdog and PIT timer are %s\n", (data & m68340_sim::REG_MCR_FRZ1) == 0 ? "enabled" : "disabled");
LOGSIM("- FRZ0: The BUS monitor is %s\n", (data & m68340_sim::REG_MCR_FRZ0) == 0 ? "enabled" : "disabled");
- LOGSIM("- FIRQ: Full Interrupt Request Mode %s\n", data & m68340_sim::REG_MCR_FIRQ ? "used on port B" : "supressed, adding 4 chip select lines on Port B");
+ LOGSIM("- FIRQ: Full Interrupt Request Mode %s\n", data & m68340_sim::REG_MCR_FIRQ ? "used on port B" : "suppressed, adding 4 chip select lines on Port B");
LOGSIM("- SHEN0-SHEN1: Show Cycle Enable %02x - not implemented\n", ((data & m68340_sim::REG_MCR_SHEN) >> 8));
LOGSIM("- Supervisor registers %s - not implemented\n", data & m68340_sim::REG_MCR_SVREG ? "requries supervisor privileges" : "can be accessed by user privileged software");
LOGSIM("- Interrupt Arbitration level: %02x\n", data & m68340_sim::REG_MCR_ARBLV);
@@ -210,7 +208,7 @@ uint8_t m68340_cpu_device::m68340_internal_sim_ports_r(offs_t offset)
sim.m_porta &= sim.m_ddra;
// TODO: call callback
- if (!m_pa_in_cb.isnull())
+ if (!m_pa_in_cb.isunset())
{
sim.m_porta |= (m_pa_in_cb() & ~sim.m_ddra);
}
@@ -247,7 +245,7 @@ uint8_t m68340_cpu_device::m68340_internal_sim_ports_r(offs_t offset)
sim.m_portb &= sim.m_ddrb;
// TODO: call callback
- if (!m_pb_in_cb.isnull())
+ if (!m_pb_in_cb.isunset())
{
sim.m_portb |= (m_pb_in_cb() & ~sim.m_ddrb);
}
@@ -344,87 +342,120 @@ void m68340_cpu_device::m68340_internal_sim_ports_w(offs_t offset, uint8_t data)
}
}
-uint32_t m68340_cpu_device::m68340_internal_sim_cs_r(offs_t offset, uint32_t mem_mask)
+uint16_t m68340_cpu_device::m68340_internal_sim_cs_r(offs_t offset, uint16_t mem_mask)
{
+ uint32_t data = 0;
LOGR("%s\n", FUNCNAME);
- offset += m68340_sim::REG_AM_CS0>>2;
+ offset += m68340_sim::REG_AM_CS0>>1;
assert(m_m68340SIM);
m68340_sim &sim = *m_m68340SIM;
- switch (offset<<2)
+ switch (offset << 1)
{
- case m68340_sim::REG_AM_CS0: return sim.m_am[0];
- case m68340_sim::REG_BA_CS0: return sim.m_ba[0];
- case m68340_sim::REG_AM_CS1: return sim.m_am[1];
- case m68340_sim::REG_BA_CS1: return sim.m_ba[1];
- case m68340_sim::REG_AM_CS2: return sim.m_am[2];
- case m68340_sim::REG_BA_CS2: return sim.m_ba[2];
- case m68340_sim::REG_AM_CS3: return sim.m_am[3];
- case m68340_sim::REG_BA_CS3: return sim.m_ba[3];
+ case m68340_sim::REG_AM_CS0: data = sim.m_am[0]; break;
+ case m68340_sim::REG_BA_CS0: data = sim.m_ba[0]; break;
+ case m68340_sim::REG_AM_CS1: data = sim.m_am[1]; break;
+ case m68340_sim::REG_BA_CS1: data = sim.m_ba[1]; break;
+ case m68340_sim::REG_AM_CS2: data = sim.m_am[2]; break;
+ case m68340_sim::REG_BA_CS2: data = sim.m_ba[2]; break;
+ case m68340_sim::REG_AM_CS3: data = sim.m_am[3]; break;
+ case m68340_sim::REG_BA_CS3: data = sim.m_ba[3]; break;
default:
- logerror("%08x m68340_internal_sim_r %08x, (%08x)\n", m_ppc, offset*4,mem_mask);
+ logerror("%08x m68340_internal_sim_r %08x, (%08x)\n", m_ppc, offset*2,mem_mask);
}
- return 0x00000000;
+ return (BIT(offset,0) ? data : (data >> 16)) & 0xffff;
}
-void m68340_cpu_device::m68340_internal_sim_cs_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void m68340_cpu_device::m68340_internal_sim_cs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
LOG("%s\n", FUNCNAME);
- offset += m68340_sim::REG_AM_CS0>>2;
- if (offset & 1)
+ offset += m68340_sim::REG_AM_CS0>>1;
+
+ if (BIT(offset, 1))
{
- LOGCS("%08x Base address CS%d %08x, %08x (%08x) ", m_ppc, (offset - 0x10) / 2, offset * 4, data, mem_mask);
- LOGCS("- Base: %08x BFC:%02x WP:%d FTE:%d NCS:%d Valid: %s\n", data & 0xffffff00, (data & 0xf0) >> 4, data & 0x08 ? 1 : 0, data & 0x04 ? 1 : 0, data & 0x02 ? 1 : 0, data & 0x01 ? "Yes" : "No");
+ if (BIT(offset, 0))
+ {
+ LOGCS("%08x (LSWORD) Base address CS%d %08x, %04x (%04x) ", m_ppc, (offset - 0x20) / 2, offset * 2, data, mem_mask);
+ LOGCS("- Base: %04x BFC:%02x WP:%d FTE:%d NCS:%d Valid: %s\n", data & 0xff00, (data & 0xf0) >> 4, data & 0x08 ? 1 : 0, data & 0x04 ? 1 : 0, data & 0x02 ? 1 : 0, data & 0x01 ? "Yes" : "No");
+ }
+ else
+ {
+ LOGCS("%08x (MSWORD) Base address CS%d %08x, %04x (%04x) ", m_ppc, (offset - 0x20) / 2, offset * 2, data, mem_mask);
+ LOGCS("- Base: %04x\n", data);
+ }
}
else
{
- LOGCS("%08x Address mask CS%d %08x, %08x (%08x) ", m_ppc, (offset - 0x10) / 2, offset * 4, data, mem_mask);
- LOGCS("- Mask: %08x FCM:%02x DD:%d PS: %s\n", data & 0xffffff00, (data & 0xf0) >> 4, (data >> 2) & 0x03, std::array<char const *, 4>{{"Reserved", "16-Bit", "8-bit", "External DSACK response"}}[data & 0x03]);
+ if (BIT(offset, 0))
+ {
+ LOGCS("%08x Address mask CS%d %08x, %04x (%04x) ", m_ppc, (offset - 0x20) / 2, offset * 2, data, mem_mask);
+ LOGCS("- FCM:%02x DD:%d PS: %s\n", (data & 0xf0) >> 4, (data >> 2) & 0x03, std::array<char const *, 4>{{"Reserved", "16-Bit", "8-bit", "External DSACK response"}}[data & 0x03]);
+ }
+ else
+ {
+ LOGCS("%08x Address mask CS%d %08x, %04x (%04x) ", m_ppc, (offset - 0x20) / 2, offset * 2, data, mem_mask);
+ LOGCS("- Mask: %04x\n", data & 0xff00);
+ }
}
assert(m_m68340SIM);
m68340_sim &sim = *m_m68340SIM;
- switch (offset << 2)
+ auto const combine_data32 =
+ [&offset, &data, &mem_mask] (uint32_t *varptr)
+ {
+ uint32_t data32 = data;
+ uint32_t mem_mask32 = mem_mask;
+
+ if (!BIT(offset,0))
+ {
+ data32 <<= 16;
+ mem_mask32 <<= 16;
+ }
+
+ *varptr = (*varptr & ~mem_mask32) | (data32 & mem_mask32);
+ };
+
+ switch ((offset << 1) & ~3)
{
case m68340_sim::REG_AM_CS0:
- COMBINE_DATA(&sim.m_am[0]);
+ combine_data32(&sim.m_am[0]);
break;
case m68340_sim::REG_BA_CS0:
- COMBINE_DATA(&sim.m_ba[0]);
+ combine_data32(&sim.m_ba[0]);
break;
case m68340_sim::REG_AM_CS1:
- COMBINE_DATA(&sim.m_am[1]);
+ combine_data32(&sim.m_am[1]);
break;
case m68340_sim::REG_BA_CS1:
- COMBINE_DATA(&sim.m_ba[1]);
+ combine_data32(&sim.m_ba[1]);
break;
case m68340_sim::REG_AM_CS2:
- COMBINE_DATA(&sim.m_am[2]);
+ combine_data32(&sim.m_am[2]);
break;
case m68340_sim::REG_BA_CS2:
- COMBINE_DATA(&sim.m_ba[2]);
+ combine_data32(&sim.m_ba[2]);
break;
case m68340_sim::REG_AM_CS3:
- COMBINE_DATA(&sim.m_am[3]);
+ combine_data32(&sim.m_am[3]);
break;
case m68340_sim::REG_BA_CS3:
- COMBINE_DATA(&sim.m_ba[3]);
+ combine_data32(&sim.m_ba[3]);
break;
default:
- logerror("%08x m68340_internal_sim_cs_w %08x, %08x (%08x)\n", m_ppc, offset*4,data,mem_mask);
+ logerror("%08x m68340_internal_sim_cs_w %08x, %08x (%08x)\n", m_ppc, offset*2,data,mem_mask);
break;
}
}
@@ -438,15 +469,7 @@ void m68340_cpu_device::start_68340_sim()
{
LOG("%s\n", FUNCNAME);
LOGCLOCK( " - Clock: %d [0x%08x]\n", clock(), clock());
- m_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68340_cpu_device::periodic_interrupt_timer_callback),this));
-
- // resolve callbacks Port A
- m_pa_out_cb.resolve_safe();
- m_pa_in_cb.resolve();
-
- // resolve callbacks Port B
- m_pb_out_cb.resolve_safe();
- m_pb_in_cb.resolve();
+ m_irq_timer = timer_alloc(FUNC(m68340_cpu_device::periodic_interrupt_timer_callback), this);
// Setup correct VCO/clock speed based on reset values and crystal
assert(m_m68340SIM);
@@ -529,7 +552,7 @@ void m68340_cpu_device::do_tick_pit()
}
}
-WRITE_LINE_MEMBER( m68340_cpu_device::extal_w )
+void m68340_cpu_device::extal_w(int state)
{
LOGPIT("%s H1 set to %d\n", FUNCNAME, state);
m_extal = state;
diff --git a/src/devices/machine/68340tmu.cpp b/src/devices/machine/68340tmu.cpp
index d66f1f2387c..281a0226877 100644
--- a/src/devices/machine/68340tmu.cpp
+++ b/src/devices/machine/68340tmu.cpp
@@ -14,18 +14,16 @@
// MACROS / CONSTANTS
//**************************************************************************
-//#define LOG_GENERAL (1U << 0) // Already defined in logmacro.h
-#define LOG_SETUP (1U << 1)
-#define LOG_READ (1U << 2)
-#define LOG_TIMER (1U << 3)
-#define LOG_INT (1U << 4)
-#define LOG_COUNT (1U << 5)
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_TIMER (1U << 3)
+#define LOG_INT (1U << 4)
+#define LOG_COUNT (1U << 5)
//#define VERBOSE (LOG_SETUP|LOG_INT|LOG_TIMER)
#include "logmacro.h"
-//#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__) // Already defined in logmacro.h
#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__)
#define LOGTIMER(...) LOGMASKED(LOG_TIMER, __VA_ARGS__)
@@ -156,7 +154,7 @@ void mc68340_timer_module_device::write(offs_t offset, uint16_t data, uint16_t m
"Period Measurement - not implemented",
"Event Count - not implemented",
"Timer Bypass (Simple Test Method) - not implemented"
- }}[data & REG_CR_MODE_MASK]);
+ }}[(data & REG_CR_MODE_MASK) >> 2]);
LOGTIMER("- OC: %s mode\n", std::array<char const *, 4>{{"Disabled", "Toggle", "Zero", "One"}}[data & REG_CR_OC_MASK]);
@@ -265,14 +263,14 @@ void mc68340_timer_module_device::write(offs_t offset, uint16_t data, uint16_t m
LOG("%08x m68340_internal_timer_w %08x, %08x (%08x)\n", m_cpu->pcbase(), offset * 2, data, mem_mask);
}
-WRITE_LINE_MEMBER( mc68340_timer_module_device::tin_w)
+void mc68340_timer_module_device::tin_w(int state)
{
LOGTIMER("%s\n", FUNCNAME);
m_tin = state;
}
-WRITE_LINE_MEMBER( mc68340_timer_module_device::tgate_w)
+void mc68340_timer_module_device::tgate_w(int state)
{
LOGTIMER("%s\n", FUNCNAME);
@@ -312,12 +310,9 @@ void mc68340_timer_module_device::device_start()
m_cpu = downcast<m68340_cpu_device *>(owner());
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68340_timer_module_device::timer_callback),this));
+ m_timer = timer_alloc(FUNC(mc68340_timer_module_device::timer_callback), this);
- // Resolve Timer callbacks
- m_tout_out_cb.resolve_safe();
- m_tgate_in_cb.resolve_safe();
- m_tin_in_cb.resolve_safe();
+ m_ir = 0x000f;
}
void mc68340_timer_module_device::device_reset()
@@ -517,7 +512,6 @@ void mc68340_timer_module_device::tout_clear()
mc68340_timer_module_device::mc68340_timer_module_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, MC68340_TIMER_MODULE, tag, owner, clock)
, m_tout_out_cb(*this)
- , m_tin_in_cb(*this)
, m_tgate_in_cb(*this)
{
}
diff --git a/src/devices/machine/68340tmu.h b/src/devices/machine/68340tmu.h
index 653226f8887..f0f0fd181ef 100644
--- a/src/devices/machine/68340tmu.h
+++ b/src/devices/machine/68340tmu.h
@@ -16,8 +16,8 @@ public:
uint16_t read(offs_t offset, uint16_t mem_mask = ~0);
void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- DECLARE_WRITE_LINE_MEMBER( tin_w );
- DECLARE_WRITE_LINE_MEMBER( tgate_w );
+ void tin_w(int state);
+ void tgate_w(int state);
uint8_t irq_level() const { return (m_sr & REG_SR_IRQ) ? (m_ir & REG_IR_INTLEV) >> 8 : 0; }
uint8_t irq_vector() const { return m_ir & REG_IR_INTVEC; }
@@ -47,7 +47,6 @@ protected:
emu_timer *m_timer;
devcb_write_line m_tout_out_cb;
- devcb_write_line m_tin_in_cb;
devcb_write_line m_tgate_in_cb;
void do_timer_irq();
void do_timer_tick();
diff --git a/src/devices/machine/6840ptm.cpp b/src/devices/machine/6840ptm.cpp
index 21d8c0d80e9..42b7c6a45cd 100644
--- a/src/devices/machine/6840ptm.cpp
+++ b/src/devices/machine/6840ptm.cpp
@@ -7,7 +7,7 @@
Programmable Timer Module
Written By J.Wallace based on previous work by Aaron Giles,
- 'Re-Animator' and Mathis Rosenhauer.
+ 'Re-Animator' and Mathis Rosenhauer.
Todo:
Confirm handling for 'Single Shot' operation.
@@ -38,18 +38,17 @@
#include "emu.h"
#include "6840ptm.h"
-#define LOG_COUNTERS (1 << 1)
-#define LOG_STATUS (1 << 2)
-#define LOG_CONTROL (1 << 3)
-#define LOG_RESETS (1 << 4)
-#define LOG_TIMEOUTS (1 << 5)
-#define LOG_IRQS (1 << 6)
+#define LOG_COUNTERS (1U << 1)
+#define LOG_STATUS (1U << 2)
+#define LOG_CONTROL (1U << 3)
+#define LOG_RESETS (1U << 4)
+#define LOG_TIMEOUTS (1U << 5)
+#define LOG_IRQS (1U << 6)
#define LOG_ALL (LOG_COUNTERS | LOG_STATUS | LOG_CONTROL | LOG_RESETS | LOG_TIMEOUTS | LOG_IRQS)
#define VERBOSE (0)
#include "logmacro.h"
-
/***************************************************************************
LOCAL VARIABLES
***************************************************************************/
@@ -91,19 +90,36 @@ ptm6840_device::ptm6840_device(const machine_config &mconfig, const char *tag, d
void ptm6840_device::device_start()
{
- // resolve callbacks
- m_out_cb.resolve_all_safe();
- m_irq_cb.resolve_safe();
-
- m_timer[0] = timer_alloc(0);
- m_timer[1] = timer_alloc(1);
- m_timer[2] = timer_alloc(2);
+ m_timer[0] = timer_alloc(FUNC(ptm6840_device::state_changed), this);
+ m_timer[1] = timer_alloc(FUNC(ptm6840_device::state_changed), this);
+ m_timer[2] = timer_alloc(FUNC(ptm6840_device::state_changed), this);
for (auto & elem : m_timer)
{
elem->enable(false);
}
+ // zerofill
+ m_t3_divisor = 1;
+ m_t3_scaler = 0;
+ m_irq = 0;
+ m_status_reg = 0;
+ m_status_read_since_int = 0;
+ m_lsb_buffer = 0;
+ m_msb_buffer = 0;
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_control_reg[i] = 0;
+ m_counter[i] = 0;
+ m_latch[i] = 0;
+ m_output[i] = false;
+ m_clk[i] = false;
+ m_single_fired[i] = false;
+ m_enabled[i] = false;
+ m_mode[i] = 0;
+ }
+
// register for state saving
save_item(NAME(m_lsb_buffer));
save_item(NAME(m_msb_buffer));
@@ -118,12 +134,12 @@ void ptm6840_device::device_start()
save_item(NAME(m_gate));
save_item(NAME(m_clk));
save_item(NAME(m_mode));
- save_item(NAME(m_fired));
+ save_item(NAME(m_single_fired));
save_item(NAME(m_enabled));
save_item(NAME(m_external_clock));
save_item(NAME(m_counter));
+ save_item(NAME(m_disable_time));
save_item(NAME(m_latch));
- save_item(NAME(m_hightime));
}
@@ -133,145 +149,94 @@ void ptm6840_device::device_start()
void ptm6840_device::device_reset()
{
- m_control_reg[2] = 0;
- m_control_reg[1] = 0;
- m_control_reg[0] = 1;
- m_status_reg = 0;
- m_t3_divisor = 1;
+ m_t3_divisor = 1;
+ m_t3_scaler = 0;
+ m_status_reg = 0;
m_status_read_since_int = 0;
- m_irq = 0;
- m_t3_scaler = 0;
- m_hightime[0] = false;
- m_hightime[1] = false;
- m_hightime[2] = false;
for (int i = 0; i < 3; i++)
{
+ m_control_reg[i] = 0;
m_counter[i] = 0xffff;
- m_latch[i] = 0xffff;
- m_output[i] = 0;
- m_fired[i] = 0;
- m_enabled[i] = 0;
+ m_latch[i] = 0xffff;
+ m_disable_time[i] = attotime::never;
+ m_output[i] = false;
+ m_clk[i] = false;
+ m_single_fired[i] = false;
+ m_enabled[i] = false;
m_mode[i] = 0;
}
-}
-void ptm6840_device::device_resolve_objects()
-{
+ m_control_reg[0] = 1;
+
+ // clear outputs
+ m_irq = 0;
+ m_irq_cb(CLEAR_LINE);
+
for (int i = 0; i < 3; i++)
- m_gate[i] = 0;
+ m_out_cb[i](0);
}
-//-------------------------------------------------
-// device_timer - handle timer callbacks
-//-------------------------------------------------
-
-void ptm6840_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void ptm6840_device::device_resolve_objects()
{
- timeout(id);
+ for (int i = 0; i < 3; i++)
+ m_gate[i] = false;
}
//-------------------------------------------------
-// subtract_from_counter - Subtract from Counter
+// deduct_from_counter - count back by one step
//-------------------------------------------------
-void ptm6840_device::subtract_from_counter(int counter, int count)
+void ptm6840_device::deduct_from_counter(int idx)
{
- // Determine the clock frequency for this timer
- double clk = m_control_reg[counter] & INTERNAL_CLK_EN ? static_cast<double>(clock()) : m_external_clock[counter];
-
- // Dual-byte mode
- if (m_control_reg[counter] & COUNT_MODE_8BIT)
+ if (m_control_reg[idx] & COUNT_MODE_8BIT)
{
- int lsb = m_counter[counter] & 0xff;
- int msb = m_counter[counter] >> 8;
+ // Dual-byte mode
+ uint16_t msb = m_counter[idx] >> 8;
+ uint16_t lsb = m_counter[idx] & 0xff;
- // Count the clocks
- lsb -= count;
+ lsb--;
- // Loop while we're less than zero
- while (lsb < 0)
+ bool timed_out = false;
+ if (lsb == 0xffff)
{
// Borrow from the MSB
- lsb += (m_latch[counter] & 0xff) + 1;
+ lsb = (m_latch[idx] & 0xff) + 1;
msb--;
- // If MSB goes less than zero, we've expired
- if ((msb == 0 && !m_hightime[counter]) || (msb < 0 && m_hightime[counter]))
+ if (msb == 0xffff)
{
- timeout(counter);
- msb = (m_latch[counter] >> 8) + 1;
+ // If MSB is less than zero, we've timed out, no need to manually reload
+ timed_out = true;
+ state_changed(idx);
+ }
+ else if (msb == 0)
+ {
+ // If MSB is at zero, our output state potentially needs to change, also no need to manually reload
+ msb = (m_latch[idx] >> 8) + 1;
+ state_changed(idx);
}
}
- // Store the result
- m_counter[counter] = (msb << 8) | lsb;
- }
-
- // Word mode
- else
- {
- int word = m_counter[counter];
-
- // Count the clocks
- word -= count;
-
- // loop while we're less than zero
- while (word < 0)
- {
- // Borrow from the MSB
- word += m_latch[counter] + 1;
-
- // We've expired
- timeout(counter);
- }
-
- // Store the result
- m_counter[counter] = word;
- }
-
- if (m_enabled[counter])
- {
- int clks = m_counter[counter];
- if (m_control_reg[counter] & COUNT_MODE_8BIT)
- {
- /* In dual 8 bit mode, let the counter fire when MSB == 0 */
- m_hightime[counter] = !(clks & 0xff00);
- clks &= 0xff00;
- }
-
- attotime duration = attotime::from_hz(clk) * clks;
- if (counter == 2)
+ // Store the result if we haven't timed out (which already reloads the counter from the latches)
+ if (!timed_out)
{
- duration *= m_t3_divisor;
+ m_counter[idx] = (msb << 8) + lsb;
}
- m_timer[counter]->adjust(duration);
}
-}
-
-
-
-//-------------------------------------------------
-// tick
-//-------------------------------------------------
-
-void ptm6840_device::tick(int counter, int count)
-{
- if (counter == 2)
+ else
{
- m_t3_scaler += count;
+ // Word mode
+ m_counter[idx]--;
- if ( m_t3_scaler > m_t3_divisor - 1)
+ const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6;
+ // If we've ticked once in one-shot-mode, or we've expired, our state needs to change
+ if ((one_shot_mode && !m_output[idx]) || m_counter[idx] == 0xffff)
{
- subtract_from_counter(counter, 1);
- m_t3_scaler = 0;
+ state_changed(idx);
}
}
- else
- {
- subtract_from_counter(counter, count);
- }
}
@@ -314,67 +279,75 @@ void ptm6840_device::update_interrupts()
// compute_counter - Compute Counter
//-------------------------------------------------
-uint16_t ptm6840_device::compute_counter( int counter ) const
+int ptm6840_device::compute_counter(int idx) const
{
- double clk;
+ uint32_t clk;
- // If there's no timer, return the count
- if (!m_enabled[counter])
+ // If the timer is disabled, return the raw counter value
+ if (!m_enabled[idx])
+ {
+ LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %04x\n", idx + 1, m_counter[idx]);
+ return m_counter[idx];
+ }
+ else if (m_control_reg[0] & RESET_TIMERS)
{
- LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %d\n", counter + 1, m_counter[counter]);
- return m_counter[counter];
+ // If we're held in reset, return either the latch value for 16-bit mode, or the computed count for dual-8-bit
+ if (m_control_reg[idx] & COUNT_MODE_8BIT)
+ {
+ const uint16_t latch_lsb = m_latch[idx] & 0xff;
+ const uint16_t latch_msb = m_latch[idx] >> 8;
+ return latch_msb * (latch_lsb + 1);
+ }
+ return m_latch[idx];
}
// determine the clock frequency for this timer
- if (m_control_reg[counter] & INTERNAL_CLK_EN)
+ if (m_control_reg[idx] & INTERNAL_CLK_EN)
{
- clk = static_cast<double>(clock());
+ clk = clock();
}
else
{
- clk = m_external_clock[counter];
+ clk = m_external_clock[idx];
}
- if (counter == 2)
+ if (idx == 2)
{
clk /= m_t3_divisor;
}
- LOGMASKED(LOG_COUNTERS, "Timer #%d %s clock freq %f \n", counter + 1, (m_control_reg[counter] & INTERNAL_CLK_EN) ? "internal" : "external", clk);
+ LOGMASKED(LOG_COUNTERS, "Timer #%d %s clock freq %d\n", idx + 1, (m_control_reg[idx] & INTERNAL_CLK_EN) ? "internal" : "external", clk);
// See how many are left
- int remaining = (m_timer[counter]->remaining() * clk).as_double();
-
- // Adjust the count for dual byte mode
- if (m_control_reg[counter] & COUNT_MODE_8BIT)
+ attotime remaining_time = m_timer[idx]->remaining();
+ if (remaining_time.is_never())
{
- int divisor = (m_counter[counter] & 0xff) + 1;
- int msb = remaining / divisor;
- int lsb = remaining % divisor;
- remaining = (msb << 8) | lsb;
+ if (m_disable_time[idx].is_never())
+ {
+ return m_counter[idx];
+ }
+ remaining_time = m_disable_time[idx];
}
+ int remaining = remaining_time.as_ticks(clk);
- LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %d\n", counter + 1, remaining);
+ LOGMASKED(LOG_COUNTERS, "Timer #%d read counter: %04x\n", idx + 1, remaining);
return remaining;
}
//-------------------------------------------------
-// reload_count - Reload Counter
+// reload_counter
//-------------------------------------------------
-void ptm6840_device::reload_count(int idx)
+void ptm6840_device::reload_counter(int idx)
{
- double clk;
+ const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6;
// Copy the latched value in
m_counter[idx] = m_latch[idx];
- // If reset is held, don't start counting
- if (m_control_reg[0] & RESET_TIMERS)
- return;
-
// Determine the clock frequency for this timer
+ double clk;
if (m_control_reg[idx] & INTERNAL_CLK_EN)
{
clk = static_cast<double> (clock());
@@ -387,38 +360,43 @@ void ptm6840_device::reload_count(int idx)
}
// Determine the number of clock periods before we expire
- int count = m_counter[idx];
+ int count = m_counter[idx] + 1;
if (m_control_reg[idx] & COUNT_MODE_8BIT)
{
- if (m_hightime[idx])
- count = 0xff;
+ const uint16_t latch_lsb = m_latch[idx] & 0xff;
+ const uint16_t latch_msb = m_latch[idx] >> 8;
+ if (!m_output[idx])
+ {
+ count = (latch_lsb + 1) * latch_msb;
+ }
else
- count = ((count >> 8) + 1) * ((count & 0xff) + 1);
-
- }
- else
- {
- count = count + 1;
+ {
+ count = latch_lsb + 1;
+ }
}
-
- m_fired[idx] = 0;
-
- if ((m_mode[idx] == 4) || (m_mode[idx] == 6))
+ else if (one_shot_mode)
{
- m_output[idx] = 1;
- m_out_cb[idx](m_output[idx]);
+ if (!m_output[idx])
+ {
+ count = 1;
+ }
+ else
+ {
+ count = m_counter[idx];
+ }
}
// Set the timer
- LOGMASKED(LOG_COUNTERS, "Timer #%d reload_count: clock = %f count = %d\n", idx + 1, clk, count);
+ LOGMASKED(LOG_COUNTERS, "Timer #%d init_timer: clock = %f count = %04x\n", idx + 1, clk, count);
if (clk == 0.0)
{
- m_enabled[idx] = 0;
- m_timer[idx]->enable(false);
+ m_enabled[idx] = false;
+ m_timer[idx]->adjust(attotime::never);
}
else
{
+ m_enabled[idx] = true;
attotime duration = attotime::from_hz(clk) * count;
if (idx == 2)
@@ -426,11 +404,19 @@ void ptm6840_device::reload_count(int idx)
duration *= m_t3_divisor;
}
- LOGMASKED(LOG_COUNTERS, "Timer #%d reload_count: output = %f\n", idx + 1, duration.as_double());
+ LOGMASKED(LOG_COUNTERS, "Timer #%d init_timer: duration = %f\n", idx + 1, duration.as_double());
- m_enabled[idx] = 1;
- m_timer[idx]->adjust(duration);
- m_timer[idx]->enable(true);
+ const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6;
+ const bool gated = (!one_shot_mode && m_gate[idx]) || (m_control_reg[0] & RESET_TIMERS);
+ if (gated)
+ {
+ m_disable_time[idx] = duration;
+ m_timer[idx]->adjust(attotime::never);
+ }
+ else
+ {
+ m_timer[idx]->adjust(duration, idx);
+ }
}
}
@@ -447,25 +433,28 @@ uint8_t ptm6840_device::read(offs_t offset)
switch ( offset )
{
case PTM_6840_CTRL1:
- {
val = 0;
break;
- }
case PTM_6840_STATUS:
- {
LOGMASKED(LOG_STATUS, "%s: Status read = %04X\n", machine().describe_context(), m_status_reg);
m_status_read_since_int |= m_status_reg & 0x07;
val = m_status_reg;
break;
- }
+
+ case PTM_6840_LSB1:
+ case PTM_6840_LSB2:
+ case PTM_6840_LSB3:
+ val = m_lsb_buffer;
+ LOGMASKED(LOG_COUNTERS, "%s: Counter LSB read = %02x\n", machine().describe_context(), val);
+ break;
case PTM_6840_MSBBUF1:
case PTM_6840_MSBBUF2:
case PTM_6840_MSBBUF3:
{
int idx = (offset - 2) / 2;
- int result = compute_counter(idx);
+ uint16_t result = compute_counter(idx);
// Clear the interrupt if the status has been read
if (m_status_read_since_int & (1 << idx))
@@ -474,26 +463,16 @@ uint8_t ptm6840_device::read(offs_t offset)
update_interrupts();
}
- m_lsb_buffer = result & 0xff;
-
- LOGMASKED(LOG_COUNTERS, "%s: Counter %d read = %04X\n", machine().describe_context(), idx + 1, result >> 8);
val = result >> 8;
- break;
- }
+ m_lsb_buffer = (uint8_t)result;
- case PTM_6840_LSB1:
- case PTM_6840_LSB2:
- case PTM_6840_LSB3:
- {
- val = m_lsb_buffer;
+ LOGMASKED(LOG_COUNTERS, "%s: Counter %d MSB read = %02x\n", machine().describe_context(), idx + 1, val);
break;
}
default:
- {
val = 0;
break;
- }
}
return val;
@@ -519,8 +498,11 @@ void ptm6840_device::write(offs_t offset, uint8_t data)
LOGMASKED(LOG_CONTROL, "Control register #%d selected\n", idx + 1);
LOGMASKED(LOG_CONTROL, "operation mode = %s\n", opmode[m_mode[idx]]);
- LOGMASKED(LOG_CONTROL, "value = %04X\n", m_control_reg[idx]);
+ LOGMASKED(LOG_CONTROL, "value = %02x\n", m_control_reg[idx]);
LOGMASKED(LOG_CONTROL, "t3divisor = %d\n", m_t3_divisor);
+ LOGMASKED(LOG_CONTROL, "irq/output/int = %d/%d/%d\n", BIT(m_control_reg[idx], 6), BIT(m_control_reg[idx], 7), BIT(m_control_reg[idx], 1));
+ LOGMASKED(LOG_CONTROL, "latch = %04x\n", m_latch[idx]);
+ LOGMASKED(LOG_CONTROL, "counter = %04x\n", m_counter[idx]);
if (diffs & INTERRUPT_EN)
update_interrupts();
@@ -537,12 +519,17 @@ void ptm6840_device::write(offs_t offset, uint8_t data)
// Holding reset down
if (data & RESET_TIMERS)
{
+ m_status_reg = 0;
+ m_status_read_since_int = 0;
+ update_interrupts();
LOGMASKED(LOG_RESETS, "Timer reset\n");
for (int i = 0; i < 3; i++)
{
- m_timer[i]->enable(false);
- m_enabled[i] = 0;
- m_hightime[idx] = false;
+ m_timer[i]->adjust(attotime::never);
+ m_enabled[i] = false;
+ reload_counter(i);
+ m_output[i] = false;
+ m_out_cb[i](m_output[i]);
}
}
// Releasing reset
@@ -550,8 +537,13 @@ void ptm6840_device::write(offs_t offset, uint8_t data)
{
for (int i = 0; i < 3; i++)
{
- m_hightime[idx] = false;
- reload_count(i);
+ m_single_fired[i] = false;
+ reload_counter(i);
+ if (!m_disable_time[i].is_never() && m_timer[i]->remaining().is_never() && ((m_control_reg[i] & INTERNAL_CLK_EN) || m_external_clock[i] != 0.0))
+ {
+ m_timer[i]->adjust(m_disable_time[i], i);
+ m_disable_time[i] = attotime::never;
+ }
}
}
@@ -562,8 +554,7 @@ void ptm6840_device::write(offs_t offset, uint8_t data)
// Changing the clock source? (e.g. Zwackery)
if (diffs & INTERNAL_CLK_EN)
{
- m_hightime[idx] = false;
- reload_count(idx);
+ update_expiration_for_clock_source(idx, !(m_control_reg[idx] & INTERNAL_CLK_EN), m_external_clock[idx]);
}
break;
}
@@ -591,8 +582,7 @@ void ptm6840_device::write(offs_t offset, uint8_t data)
// Reload the count if in an appropriate mode
if (!(m_control_reg[idx] & 0x10) || (m_control_reg[0] & RESET_TIMERS))
{
- m_hightime[idx] = false;
- reload_count(idx);
+ reload_counter(idx);
}
LOGMASKED(LOG_COUNTERS, "%s: Counter #%d latch = %04X\n", machine().describe_context(), idx + 1, m_latch[idx]);
@@ -603,60 +593,69 @@ void ptm6840_device::write(offs_t offset, uint8_t data)
//-------------------------------------------------
-// timeout - Called if timer is mature
+// state_changed - called if timer output state
+// changes (masked or not)
//-------------------------------------------------
-void ptm6840_device::timeout(int idx)
+TIMER_CALLBACK_MEMBER(ptm6840_device::state_changed)
{
- LOGMASKED(LOG_TIMEOUTS, "**ptm6840 t%d timeout**\n", idx + 1);
+ LOGMASKED(LOG_TIMEOUTS, "**ptm6840 t%d state_changed**\n", param + 1);
- // Set the interrupt flag
- m_status_reg |= (1 << idx);
- m_status_read_since_int &= ~(1 << idx);
- update_interrupts();
+ // Set the interrupt flag if at the end of a full cycle
+ const bool one_shot_mode = m_mode[param] == 4 || m_mode[param] == 6;
+ const bool dual_8bit = m_control_reg[param] & COUNT_MODE_8BIT;
+ const bool end_of_cycle = (!dual_8bit && !one_shot_mode) || m_output[param];
+ if (end_of_cycle)
+ {
+ m_status_reg |= (1 << param);
+ m_status_read_since_int &= ~(1 << param);
+ update_interrupts();
+ }
- if (m_control_reg[idx] & COUNT_OUT_EN)
+ const bool enable_output = m_control_reg[param] & COUNT_OUT_EN;
+ switch (m_mode[param])
{
- switch (m_mode[idx])
- {
- case 0:
- case 2:
+ case 0:
+ case 2:
+ m_output[param] = !m_output[param];
+ if (enable_output)
+ {
+ m_out_cb[param](m_output[param]);
+ }
+ else
+ {
+ m_out_cb[param](0);
+ }
+ LOGMASKED(LOG_TIMEOUTS, "%6.6f: **ptm6840 t%d output %d **\n", machine().time().as_double(), param + 1, m_output[param]);
+ break;
- if (m_control_reg[idx] & COUNT_MODE_8BIT)
- {
- m_hightime[idx] = !m_hightime[idx];
- m_output[idx] = m_hightime[idx];
- m_out_cb[idx](m_output[idx]);
- }
- else
+ case 4:
+ case 6:
+ m_output[param] = !m_output[param];
+ LOGMASKED(LOG_TIMEOUTS, "**ptm6840 t%d output %d **\n", param + 1, m_output[param]);
+
+ if (!m_single_fired[param])
+ {
+ if (enable_output)
{
- m_output[idx] = m_output[idx] ^ 1;
- m_out_cb[idx](m_output[idx]);
+ m_out_cb[param](m_output[param]);
}
- LOGMASKED(LOG_TIMEOUTS, "%6.6f: **ptm6840 t%d output %d **\n", machine().time().as_double(), idx + 1, m_output[idx]);
- break;
- case 4:
- case 6:
- if (!m_fired[idx])
+ if (!m_output[param])
{
- m_output[idx] = 1;
- LOGMASKED(LOG_TIMEOUTS, "**ptm6840 t%d output %d **\n", idx + 1, m_output[idx]);
-
- m_out_cb[idx](m_output[idx]);
-
- // No changes in output until reinit
- m_fired[idx] = 1;
-
- m_status_reg |= (1 << idx);
- m_status_read_since_int &= ~(1 << idx);
- update_interrupts();
+ // Don't allow output to change until reinitialization
+ m_single_fired[param] = true;
}
- break;
- }
+ }
+ else
+ {
+ m_out_cb[param](0);
+ }
+ break;
}
- m_enabled[idx]= 0;
- reload_count(idx);
+
+ m_enabled[param] = false;
+ reload_counter(param);
}
@@ -666,14 +665,26 @@ void ptm6840_device::timeout(int idx)
void ptm6840_device::set_gate(int idx, int state)
{
- if ((m_mode[idx] & 1) == 0)
+ const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6;
+ if (state == 0 && m_gate[idx])
{
- if (state == 0 && m_gate[idx])
+ if (!(m_control_reg[0] & RESET_TIMERS))
+ {
+ m_single_fired[idx] = false;
+ m_output[idx] = false;
+ reload_counter(idx);
+ }
+ if (!m_disable_time[idx].is_never() && ((m_control_reg[idx] & INTERNAL_CLK_EN) || m_external_clock[idx] != 0.0))
{
- m_hightime[idx] = false;
- reload_count(idx);
+ m_timer[idx]->adjust(m_disable_time[idx], idx);
+ m_disable_time[idx] = attotime::never;
}
}
+ else if (state == 1 && !m_gate[idx] && !one_shot_mode) // Gate disable is ignored in one-shot mode
+ {
+ m_disable_time[idx] = m_timer[idx]->remaining();
+ m_timer[idx]->adjust(attotime::never);
+ }
m_gate[idx] = state;
}
@@ -684,60 +695,127 @@ void ptm6840_device::set_gate(int idx, int state)
void ptm6840_device::set_clock(int idx, int state)
{
+ if (m_clk[idx] == state)
+ {
+ return;
+ }
+
+ const bool old_clk = m_clk[idx];
m_clk[idx] = state;
+ const bool rising_edge = !old_clk && state;
+ if (rising_edge)
+ {
+ return;
+ }
- if (!(m_control_reg[idx] & INTERNAL_CLK_EN))
+ const bool use_external_clk = !(m_control_reg[idx] & INTERNAL_CLK_EN);
+ const bool timer_running = !(m_control_reg[0] & RESET_TIMERS);
+ const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6;
+ const bool gated = !one_shot_mode && m_gate[idx];
+
+ // Don't allow ticking if timers are held in reset, internally-clocked, or gated
+ if (use_external_clk && timer_running && !gated)
{
- if (state)
+ if (idx == 2)
+ {
+ m_t3_scaler++;
+ if (m_t3_scaler >= m_t3_divisor)
+ {
+ deduct_from_counter(idx);
+ m_t3_scaler = 0;
+ }
+ }
+ else
{
- tick(idx, 1);
+ deduct_from_counter(idx);
}
}
}
//-------------------------------------------------
-// set_ext_clock - set external clock frequency
+// update_expiration_for_clock_source
//-------------------------------------------------
-void ptm6840_device::set_ext_clock(int counter, double clock)
+void ptm6840_device::update_expiration_for_clock_source(int idx, bool changed_to_external, double new_external_clock)
{
- m_external_clock[counter] = clock;
-
- if (!(m_control_reg[counter] & INTERNAL_CLK_EN))
+ if (!(m_control_reg[0] & RESET_TIMERS))
{
- if (!m_external_clock[counter])
+ double divisor = idx == 2 ? m_t3_divisor : 1.0;
+ double clk = (m_control_reg[idx] & INTERNAL_CLK_EN ? static_cast<double>(clock()) : new_external_clock) / divisor;
+
+ // First, figure out how much time was remaining on the counter
+ if (changed_to_external)
{
- m_enabled[counter] = 0;
- m_timer[counter]->enable(false);
+ m_control_reg[idx] |= INTERNAL_CLK_EN;
}
- }
- else
- {
- int count;
- attotime duration;
- // Determine the number of clock periods before we expire
- count = m_counter[counter];
+ int updated_counter = compute_counter(idx);
- if (m_control_reg[counter] & COUNT_MODE_8BIT)
+ if (changed_to_external)
{
- count = ((count >> 8) + 1) * ((count & 0xff) + 1);
+ m_control_reg[idx] &= ~INTERNAL_CLK_EN;
}
- else
+
+ if (clk == 0.0)
{
- count = count + 1;
- }
+ // If we're externally clocked with no fixed incoming clock
- duration = attotime::from_hz(clock) * count;
+ // Adjust for dual-byte mode if we're not in the last countdown
+ if ((m_control_reg[idx] & COUNT_MODE_8BIT) && !m_output[idx])
+ {
+ const uint16_t latch_lsb = m_latch[idx] & 0xff;
+ const uint16_t latch_msb = m_latch[idx] >> 8;
+ const uint8_t count_lsb = updated_counter % latch_msb;
+ const uint8_t count_msb = (updated_counter - count_lsb) / (latch_lsb + 1);
+ m_counter[idx] = (count_msb << 8) | count_lsb;
+ }
+ else
+ {
+ m_counter[idx] = updated_counter;
+ }
- if (counter == 2)
+ m_enabled[idx] = false;
+ m_timer[idx]->adjust(attotime::never);
+ return;
+ }
+ else
{
- duration *= m_t3_divisor;
+ // If we're externally clocked with a valid incoming clock OR we're internally-clocked
+ attotime duration = attotime::from_hz(clk) * updated_counter;
+
+ m_enabled[idx] = true;
+
+ const bool one_shot_mode = m_mode[idx] == 4 || m_mode[idx] == 6;
+ const bool gated = !one_shot_mode && m_gate[idx];
+ if (gated)
+ {
+ m_timer[idx]->adjust(attotime::never);
+ m_disable_time[idx] = duration;
+ }
+ else
+ {
+ m_timer[idx]->adjust(duration, idx);
+ }
}
+ }
+}
+
- m_enabled[counter] = 1;
- m_timer[counter]->adjust(duration);
- m_timer[counter]->enable(true);
+
+//-------------------------------------------------
+// set_ext_clock - set external clock frequency
+//-------------------------------------------------
+
+void ptm6840_device::set_ext_clock(int idx, double clk)
+{
+ if (m_external_clock[idx] == clk)
+ return;
+
+ if (!(m_control_reg[idx] & INTERNAL_CLK_EN))
+ {
+ update_expiration_for_clock_source(idx, false, clk);
}
+
+ m_external_clock[idx] = clk;
}
diff --git a/src/devices/machine/6840ptm.h b/src/devices/machine/6840ptm.h
index 6836aa5d317..bd2c6304a73 100644
--- a/src/devices/machine/6840ptm.h
+++ b/src/devices/machine/6840ptm.h
@@ -20,7 +20,7 @@
// ======================> ptm6840_device
-class ptm6840_device : public device_t
+class ptm6840_device : public device_t
{
public:
// construction/destruction
@@ -33,24 +33,24 @@ public:
auto o3_callback() { return m_out_cb[2].bind(); }
auto irq_callback() { return m_irq_cb.bind(); }
- int status(int clock) const { return m_enabled[clock]; } // get whether timer is enabled
- int irq_state() const { return m_irq; } // get IRQ state
- uint16_t count(int counter) const { return compute_counter(counter); } // get counter value
- void set_ext_clock(int counter, double clock); // set clock frequency
- int ext_clock(int counter) const { return m_external_clock[counter]; } // get clock frequency
+ int status(int idx) const { return m_enabled[idx]; } // get whether timer is enabled
+ int irq_state() const { return m_irq; } // get IRQ state
+ int count(int idx) const { return compute_counter(idx); } // get counter value
+ void set_ext_clock(int counter, double clock); // set clock frequency
+ int ext_clock(int idx) const { return m_external_clock[idx]; } // get clock frequency
void write(offs_t offset, uint8_t data);
uint8_t read(offs_t offset);
void set_gate(int idx, int state);
- DECLARE_WRITE_LINE_MEMBER( set_g1 ) { set_gate(0, state); }
- DECLARE_WRITE_LINE_MEMBER( set_g2 ) { set_gate(1, state); }
- DECLARE_WRITE_LINE_MEMBER( set_g3 ) { set_gate(2, state); }
+ void set_g1(int state) { set_gate(0, state); }
+ void set_g2(int state) { set_gate(1, state); }
+ void set_g3(int state) { set_gate(2, state); }
void set_clock(int idx, int state);
- DECLARE_WRITE_LINE_MEMBER( set_c1 ) { set_clock(0, state); }
- DECLARE_WRITE_LINE_MEMBER( set_c2 ) { set_clock(1, state); }
- DECLARE_WRITE_LINE_MEMBER( set_c3 ) { set_clock(2, state); }
+ void set_c1(int state) { set_clock(0, state); }
+ void set_c2(int state) { set_clock(1, state); }
+ void set_c3(int state) { set_clock(2, state); }
void update_interrupts();
@@ -59,15 +59,15 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_resolve_objects() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
- void subtract_from_counter(int counter, int count);
- void tick(int counter, int count);
- void timeout(int idx);
+ void deduct_from_counter(int idx);
+ void tick(int counter);
+ TIMER_CALLBACK_MEMBER(state_changed);
- uint16_t compute_counter(int counter) const;
- void reload_count(int idx);
+ int compute_counter(int idx) const;
+ void reload_counter(int idx);
+ void update_expiration_for_clock_source(int idx, bool changed_to_external = false, double new_external_clock = 0.0);
enum
{
@@ -89,6 +89,7 @@ private:
T3_PRESCALE_EN = 0x01,
INTERNAL_CLK_EN = 0x02,
COUNT_MODE_8BIT = 0x04,
+ MODE_BITS = 0x38,
INTERRUPT_EN = 0x40,
COUNT_OUT_EN = 0x80
};
@@ -107,12 +108,12 @@ private:
devcb_write_line m_irq_cb;
uint8_t m_control_reg[3];
- uint8_t m_output[3]; // Output states
- uint8_t m_gate[3]; // Input gate states
- uint8_t m_clk[3]; // Clock states
- uint8_t m_enabled[3];
+ bool m_output[3]; // Output states
+ bool m_gate[3]; // Counter gate states
+ bool m_clk[3]; // Clock states
+ bool m_enabled[3];
uint8_t m_mode[3];
- uint8_t m_fired[3];
+ bool m_single_fired[3];
uint8_t m_t3_divisor;
uint8_t m_t3_scaler;
uint8_t m_irq;
@@ -126,11 +127,9 @@ private:
uint16_t m_latch[3];
uint16_t m_counter[3];
+ attotime m_disable_time[3];
static const char *const opmode[];
-
- // set in dual 8 bit mode to indicate Output high time cycle
- bool m_hightime[3];
};
diff --git a/src/devices/machine/6850acia.cpp b/src/devices/machine/6850acia.cpp
index d428851ad8f..625f5ba67b5 100644
--- a/src/devices/machine/6850acia.cpp
+++ b/src/devices/machine/6850acia.cpp
@@ -97,6 +97,8 @@ acia6850_device::acia6850_device(const machine_config &mconfig, device_type type
, m_tx_irq_enable(false)
, m_rxc(0)
, m_rxd(1)
+ , m_rx_state(0)
+ , m_rx_counter(0)
, m_rx_irq_enable(false)
{
}
@@ -107,11 +109,6 @@ acia6850_device::acia6850_device(const machine_config &mconfig, device_type type
void acia6850_device::device_start()
{
- // resolve callbacks
- m_txd_handler.resolve_safe();
- m_rts_handler.resolve_safe();
- m_irq_handler.resolve_safe();
-
save_item(NAME(m_status));
save_item(NAME(m_tdr));
save_item(NAME(m_rdr));
@@ -317,7 +314,7 @@ uint8_t acia6850_device::read(offs_t offset)
return BIT(offset, 0) ? data_r() : status_r();
}
-DECLARE_WRITE_LINE_MEMBER( acia6850_device::write_cts )
+void acia6850_device::write_cts(int state)
{
if (state)
{
@@ -329,12 +326,12 @@ DECLARE_WRITE_LINE_MEMBER( acia6850_device::write_cts )
}
}
-DECLARE_WRITE_LINE_MEMBER( acia6850_device::write_dcd )
+void acia6850_device::write_dcd(int state)
{
m_dcd = state;
}
-WRITE_LINE_MEMBER( acia6850_device::write_rxc )
+void acia6850_device::write_rxc(int state)
{
if (m_rxc != state)
{
@@ -482,12 +479,12 @@ WRITE_LINE_MEMBER( acia6850_device::write_rxc )
}
}
-DECLARE_WRITE_LINE_MEMBER( acia6850_device::write_rxd )
+void acia6850_device::write_rxd(int state)
{
m_rxd = state;
}
-WRITE_LINE_MEMBER( acia6850_device::write_txc )
+void acia6850_device::write_txc(int state)
{
if (m_txc != state)
{
diff --git a/src/devices/machine/6850acia.h b/src/devices/machine/6850acia.h
index 4d99209d519..b95e4101bae 100644
--- a/src/devices/machine/6850acia.h
+++ b/src/devices/machine/6850acia.h
@@ -31,11 +31,11 @@ public:
void write(offs_t offset, uint8_t data);
uint8_t read(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER( write_cts );
- DECLARE_WRITE_LINE_MEMBER( write_dcd );
- DECLARE_WRITE_LINE_MEMBER( write_rxd );
- DECLARE_WRITE_LINE_MEMBER( write_rxc );
- DECLARE_WRITE_LINE_MEMBER( write_txc );
+ void write_cts(int state);
+ void write_dcd(int state);
+ void write_rxd(int state);
+ void write_rxc(int state);
+ void write_txc(int state);
protected:
acia6850_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
diff --git a/src/devices/machine/68561mpcc.cpp b/src/devices/machine/68561mpcc.cpp
index 1a3280d7975..77bad6bf7a3 100644
--- a/src/devices/machine/68561mpcc.cpp
+++ b/src/devices/machine/68561mpcc.cpp
@@ -44,25 +44,23 @@ FEATURES
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
-//#define LOG_GENERAL (1U << 0)
-#define LOG_SETUP (1U << 1)
-#define LOG_INT (1U << 2)
-#define LOG_READ (1U << 4)
-#define LOG_CMD (1U << 5)
-#define LOG_TX (1U << 6)
-#define LOG_RCV (1U << 7)
-#define LOG_CTS (1U << 8)
-#define LOG_DCD (1U << 9)
-#define LOG_SYNC (1U << 10)
-#define LOG_CHAR (1U << 11)
-#define LOG_RX (1U << 12)
+#define LOG_SETUP (1U << 1)
+#define LOG_INT (1U << 2)
+#define LOG_READ (1U << 3)
+#define LOG_CMD (1U << 4)
+#define LOG_TX (1U << 5)
+#define LOG_RCV (1U << 6)
+#define LOG_CTS (1U << 7)
+#define LOG_DCD (1U << 8)
+#define LOG_SYNC (1U << 9)
+#define LOG_CHAR (1U << 10)
+#define LOG_RX (1U << 11)
//#define VERBOSE ( LOG_SETUP | LOG_GENERAL | LOG_INT)
//#define LOG_OUTPUT_FUNC printf
#include "logmacro.h"
-//#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__)
#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__)
#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__)
@@ -171,14 +169,6 @@ void mpcc_device::device_start()
{
LOGSETUP("%s\n", FUNCNAME);
- // resolve callbacks
- m_out_txd_cb.resolve_safe();
- m_out_dtr_cb.resolve_safe();
- m_out_rts_cb.resolve_safe();
- m_out_rtxc_cb.resolve_safe();
- m_out_trxc_cb.resolve_safe();
- m_out_int_cb.resolve_safe();
-
// state saving
save_item(NAME(m_int_state));
save_item(NAME(m_rsr));
@@ -256,7 +246,7 @@ void mpcc_device::device_reset()
/*
* Serial device implementation
*/
-WRITE_LINE_MEMBER(mpcc_device::cts_w)
+void mpcc_device::cts_w(int state)
{
if (state == CLEAR_LINE)
{
@@ -280,7 +270,7 @@ WRITE_LINE_MEMBER(mpcc_device::cts_w)
m_sisr |= REG_SISR_CTSLVL;
}
-WRITE_LINE_MEMBER(mpcc_device::dsr_w)
+void mpcc_device::dsr_w(int state)
{
if (state == ASSERT_LINE)
{
@@ -303,7 +293,7 @@ WRITE_LINE_MEMBER(mpcc_device::dsr_w)
m_sisr &= ~REG_SISR_DSRLVL;
}
-WRITE_LINE_MEMBER(mpcc_device::dcd_w)
+void mpcc_device::dcd_w(int state)
{
if (state == CLEAR_LINE)
{
@@ -648,7 +638,7 @@ void mpcc_device::rcv_complete()
// write_rx - called by terminal through rs232/diserial
// when character is sent to board
//-------------------------------------------------
-WRITE_LINE_MEMBER(mpcc_device::write_rx)
+void mpcc_device::write_rx(int state)
{
LOGRCV("%s(%d)\n", FUNCNAME, state);
m_rxd = state;
diff --git a/src/devices/machine/68561mpcc.h b/src/devices/machine/68561mpcc.h
index 9758f387976..4de388254b9 100644
--- a/src/devices/machine/68561mpcc.h
+++ b/src/devices/machine/68561mpcc.h
@@ -69,12 +69,12 @@ public:
uint8_t iack(offs_t offset); // declared but not defined?
/* Callbacks to be called by others for signals driven by connected devices */
- DECLARE_WRITE_LINE_MEMBER( write_rx );
- DECLARE_WRITE_LINE_MEMBER( cts_w );
- DECLARE_WRITE_LINE_MEMBER( dsr_w );
- DECLARE_WRITE_LINE_MEMBER( dcd_w );
- DECLARE_WRITE_LINE_MEMBER( rxc_w ) {} // { m_chanA->rxc_w(state); }
- DECLARE_WRITE_LINE_MEMBER( txc_w ) {} // { m_chanA->txc_w(state); }
+ void write_rx(int state);
+ void cts_w(int state);
+ void dsr_w(int state);
+ void dcd_w(int state);
+ void rxc_w(int state) {} // { m_chanA->rxc_w(state); }
+ void txc_w(int state) {} // { m_chanA->txc_w(state); }
protected:
mpcc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
diff --git a/src/devices/machine/6883sam.cpp b/src/devices/machine/6883sam.cpp
new file mode 100644
index 00000000000..13e5dec2dd5
--- /dev/null
+++ b/src/devices/machine/6883sam.cpp
@@ -0,0 +1,491 @@
+// license:BSD-3-Clause
+// copyright-holders:Nathan Woods
+/***************************************************************************
+
+ 6883sam.cpp
+
+ 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 "emu.h"
+#include "6883sam.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define LOG_FBITS (1U << 1)
+#define LOG_VBITS (1U << 2)
+#define LOG_PBITS (1U << 3)
+#define LOG_TBITS (1U << 4)
+#define LOG_MBITS (1U << 5)
+#define LOG_RBITS (1U << 6)
+
+#define VERBOSE (0)
+// #define VERBOSE (LOG_FBITS)
+// #define VERBOSE (LOG_FBITS | LOG_VBITS | LOG_PBITS | LOG_TBITS | LOG_MBITS | LOG_RBITS)
+
+#include "logmacro.h"
+
+#define LOGFBITS(...) LOGMASKED(LOG_FBITS, __VA_ARGS__)
+#define LOGVBITS(...) LOGMASKED(LOG_VBITS, __VA_ARGS__)
+#define LOGPBITS(...) LOGMASKED(LOG_PBITS, __VA_ARGS__)
+#define LOGTBITS(...) LOGMASKED(LOG_TBITS, __VA_ARGS__)
+#define LOGMBITS(...) LOGMASKED(LOG_MBITS, __VA_ARGS__)
+#define LOGRBITS(...) LOGMASKED(LOG_RBITS, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SAM6883, sam6883_device, "sam6883", "MC6883 SAM")
+
+
+
+//**************************************************************************
+// DEVICE SETUP
+//**************************************************************************
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+sam6883_device::sam6883_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SAM6883, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , sam6883_friend_device_interface(mconfig, *this, 4)
+ , m_ram_config("ram", ENDIANNESS_BIG, 8, 16, 0)
+ , m_rom0_config("rom0", ENDIANNESS_BIG, 8, 13, 0)
+ , m_rom1_config("rom1", ENDIANNESS_BIG, 8, 13, 0)
+ , m_rom2_config("rom2", ENDIANNESS_BIG, 8, 14, 0)
+ , m_io0_config("io0", ENDIANNESS_BIG, 8, 5, 0)
+ , m_io1_config("io1", ENDIANNESS_BIG, 8, 5, 0)
+ , m_io2_config("io2", ENDIANNESS_BIG, 8, 5, 0)
+ , m_boot_config("boot", ENDIANNESS_BIG, 8, 7, 0)
+{
+}
+
+sam6883_friend_device_interface::sam6883_friend_device_interface(const machine_config &mconfig, device_t &device, int divider)
+ : device_interface(device, "sam6883")
+ , m_cpu(device, finder_base::DUMMY_TAG)
+ , m_sam_state(0x0000)
+ , m_divider(divider)
+{
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return the configuration
+// for the address spaces
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector sam6883_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_ram_config),
+ std::make_pair(1, &m_rom0_config),
+ std::make_pair(2, &m_rom1_config),
+ std::make_pair(3, &m_rom2_config),
+ std::make_pair(4, &m_io0_config),
+ std::make_pair(5, &m_io1_config),
+ std::make_pair(6, &m_io2_config),
+ std::make_pair(7, &m_boot_config)
+ };
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sam6883_device::device_start()
+{
+ // get spaces
+ space(0).cache(m_ram_space);
+ for (int i = 0; i < 3; i++)
+ space(i + 1).cache(m_rom_space[i]);
+ for (int i = 0; i < 3; i++)
+ space(i + 4).specific(m_io_space[i]);
+ space(7).cache(m_boot_space);
+
+ // save state support
+ save_item(NAME(m_sam_state));
+ save_item(NAME(m_divider));
+ save_item(NAME(m_counter_mask));
+ save_item(NAME(m_counter));
+ save_item(NAME(m_counter_xdiv));
+ save_item(NAME(m_counter_ydiv));
+}
+
+
+//-------------------------------------------------
+// read - read from one of the eight spaces
+//-------------------------------------------------
+
+uint8_t sam6883_device::read(offs_t offset)
+{
+ bool mode_64k = (m_sam_state & SAM_STATE_M1) == SAM_STATE_M1;
+ if (offset < (mode_64k && (m_sam_state & SAM_STATE_TY) ? 0xff00 : 0x8000))
+ {
+ // RAM reads: 0000–7FFF or 0000–FEFF
+ if (mode_64k && (m_sam_state & (SAM_STATE_TY | SAM_STATE_P1)) == SAM_STATE_P1)
+ offset |= 0x8000;
+ return m_ram_space.read_byte(offset);
+ }
+ else if (offset < 0xc000 || offset >= 0xffe0)
+ {
+ // ROM spaces: 8000–9FFF and A000–BFFF + FFE0–FFFF
+ return m_rom_space[BIT(offset, 13)].read_byte(offset & 0x1fff);
+ }
+ else if (offset < 0xff00)
+ {
+ // ROM2 space: C000–FEFF
+ return m_rom_space[2].read_byte(offset & 0x3fff);
+ }
+ else if (offset < 0xff60)
+ {
+ // I/O spaces: FF00–FF1F (slow), FF20–FF3F, FF40–FF5F
+ return m_io_space[BIT(offset, 5, 2)].read_byte(offset & 0x1f);
+ }
+ else
+ {
+ // FF60–FFDF
+ return m_boot_space.read_byte(offset - 0xff60);
+ }
+}
+
+
+//-------------------------------------------------
+// write - write to RAM, I/O or internal register
+//-------------------------------------------------
+
+void sam6883_device::write(offs_t offset, uint8_t data)
+{
+ bool mode_64k = (m_sam_state & SAM_STATE_M1) == SAM_STATE_M1;
+ if (offset < 0x8000)
+ {
+ // RAM write space: 0000–7FFF (nominally space 7)
+ if (mode_64k && (m_sam_state & (SAM_STATE_TY | SAM_STATE_P1)) == SAM_STATE_P1)
+ offset |= 0x8000;
+ m_ram_space.write_byte(offset, data);
+ }
+ else if (offset < 0xc000 || offset >= 0xffe0)
+ {
+ // ROM spaces: 8000–9FFF and A000–BFFF + FFE0–FFFF (may write through to RAM)
+ if (offset < 0xc000 && mode_64k && (m_sam_state & SAM_STATE_TY))
+ m_ram_space.write_byte(offset, data);
+ m_rom_space[BIT(offset, 13)].write_byte(offset & 0x1fff, data);
+ }
+ else if (offset < 0xff00)
+ {
+ // ROM2 space: C000–FEFF (may write through to RAM)
+ if (mode_64k && (m_sam_state & SAM_STATE_TY))
+ m_ram_space.write_byte(offset, data);
+ m_rom_space[2].write_byte(offset & 0x3fff, data);
+ }
+ else if (offset < 0xff60)
+ {
+ // I/O spaces: FF00–FF1F (slow), FF20–FF3F, FF40–FF5F
+ m_io_space[BIT(offset, 5, 2)].write_byte(offset & 0x1f, data);
+ }
+ else
+ {
+ // FF60–FFDF
+ m_boot_space.write_byte(offset - 0xff60, data);
+ if (offset >= 0xffc0)
+ internal_write(offset & 0x1f, data);
+ }
+}
+
+
+//-------------------------------------------------
+// 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()
+{
+ update_memory();
+ update_cpu_clock();
+}
+
+
+
+//-------------------------------------------------
+// update_memory
+//-------------------------------------------------
+
+void sam6883_device::update_memory()
+{
+ // 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
+
+ // switch depending on the M1/M0 variables
+ switch(m_sam_state & (SAM_STATE_M1|SAM_STATE_M0))
+ {
+ case 0:
+ // 4K mode
+ m_counter_mask = 0x0FFF;
+ break;
+
+ case SAM_STATE_M0:
+ // 16K mode
+ m_counter_mask = 0x3FFF;
+ break;
+
+ case SAM_STATE_M1:
+ // 64k mode (dynamic)
+ case SAM_STATE_M1|SAM_STATE_M0:
+ // 64k mode (static)
+ // full 64k RAM or ROM/RAM
+ // CoCo Max requires these two be treated the same
+ m_counter_mask = 0xfFFF;
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// update_cpu_clock - adjusts the speed of the CPU
+// clock
+//-------------------------------------------------
+
+void sam6883_friend_device_interface::update_cpu_clock()
+{
+ // 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;
+ m_cpu->owner()->set_unscaled_clock(device().clock() / (m_divider * (speed ? 2 : 4)));
+}
+
+
+
+//-------------------------------------------------
+// internal_write
+//-------------------------------------------------
+
+void sam6883_device::internal_write(offs_t offset, uint8_t data)
+{
+ // data is ignored
+ (void)data;
+
+ // alter the SAM state
+ uint16_t 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();
+
+ if (xorval & (SAM_STATE_F6|SAM_STATE_F5|SAM_STATE_F4|SAM_STATE_F3|SAM_STATE_F2|SAM_STATE_F1|SAM_STATE_F0))
+ {
+ LOGFBITS("%s: SAM F Address: $%04x\n",
+ machine().describe_context(),
+ display_offset());
+ }
+
+ if (xorval & (SAM_STATE_V0|SAM_STATE_V1|SAM_STATE_V2))
+ {
+ LOGVBITS("%s: SAM V Bits: $%02x\n",
+ machine().describe_context(),
+ (m_sam_state & (SAM_STATE_V0|SAM_STATE_V1|SAM_STATE_V2)));
+ }
+
+ if (xorval & (SAM_STATE_P1))
+ {
+ LOGPBITS("%s: SAM P1 Bit: $%02x\n",
+ machine().describe_context(),
+ (m_sam_state & (SAM_STATE_P1)) >> 10);
+ }
+
+ if (xorval & (SAM_STATE_TY))
+ {
+ LOGTBITS("%s: SAM TY Bit: $%02x\n",
+ machine().describe_context(),
+ (m_sam_state & (SAM_STATE_TY)) >> 15);
+ }
+
+ if (xorval & (SAM_STATE_M0|SAM_STATE_M1))
+ {
+ LOGMBITS("%s: SAM M Bits: $%02x\n",
+ machine().describe_context(),
+ (m_sam_state & (SAM_STATE_M0|SAM_STATE_M1)) >> 13);
+ }
+
+ if (xorval & (SAM_STATE_R0|SAM_STATE_R1))
+ {
+ LOGRBITS("%s: SAM R Bits: $%02x\n",
+ machine().describe_context(),
+ (m_sam_state & (SAM_STATE_R0|SAM_STATE_R1)) >> 11);
+ }
+}
+
+
+
+//-------------------------------------------------
+// horizontal_sync
+//-------------------------------------------------
+
+void sam6883_device::horizontal_sync()
+{
+ 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\n");
+ }
+}
+
+
+
+//-------------------------------------------------
+// hs_w
+//-------------------------------------------------
+
+void sam6883_device::hs_w(int state)
+{
+ if (state)
+ {
+ horizontal_sync();
+ }
+}
diff --git a/src/devices/machine/6883sam.h b/src/devices/machine/6883sam.h
new file mode 100644
index 00000000000..9fbf1f70a47
--- /dev/null
+++ b/src/devices/machine/6883sam.h
@@ -0,0 +1,219 @@
+// license:BSD-3-Clause
+// copyright-holders:Nathan Woods
+/***************************************************************************
+
+ 6883sam.h
+
+ Motorola 6883 Synchronous Address Multiplexer
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_6883SAM_H
+#define MAME_MACHINE_6883SAM_H
+
+#pragma once
+
+
+//**************************************************************************
+// SAM6883 CORE
+//**************************************************************************
+
+// base class so that GIME emulation can use some functionality
+class sam6883_friend_device_interface : public device_interface
+{
+public:
+ sam6883_friend_device_interface(const machine_config &mconfig, device_t &device, int divider);
+
+protected:
+ // SAM state constants
+ static const uint16_t SAM_STATE_TY = 0x8000;
+ static const uint16_t SAM_STATE_M1 = 0x4000;
+ static const uint16_t SAM_STATE_M0 = 0x2000;
+ static const uint16_t SAM_STATE_R1 = 0x1000;
+ static const uint16_t SAM_STATE_R0 = 0x0800;
+ static const uint16_t SAM_STATE_P1 = 0x0400;
+ static const uint16_t SAM_STATE_F6 = 0x0200;
+ static const uint16_t SAM_STATE_F5 = 0x0100;
+ static const uint16_t SAM_STATE_F4 = 0x0080;
+ static const uint16_t SAM_STATE_F3 = 0x0040;
+ static const uint16_t SAM_STATE_F2 = 0x0020;
+ static const uint16_t SAM_STATE_F1 = 0x0010;
+ static const uint16_t SAM_STATE_F0 = 0x0008;
+ static const uint16_t SAM_STATE_V2 = 0x0004;
+ static const uint16_t SAM_STATE_V1 = 0x0002;
+ static const uint16_t SAM_STATE_V0 = 0x0001;
+
+ // incidentals
+ required_device<cpu_device> m_cpu;
+
+ // device state
+ uint16_t m_sam_state;
+
+ // base clock divider (/4 for MC6883, /8 for GIME)
+ int m_divider;
+
+ ATTR_FORCE_INLINE uint16_t display_offset()
+ {
+ 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_t alter_sam_state(offs_t offset)
+ {
+ /* determine the mask */
+ uint16_t mask = 1 << (offset >> 1);
+
+ /* determine the new state */
+ uint16_t new_state;
+ if (offset & 0x0001)
+ new_state = m_sam_state | mask;
+ else
+ new_state = m_sam_state & ~mask;
+
+ /* specify the new state */
+ uint16_t xorval = m_sam_state ^ new_state;
+ m_sam_state = new_state;
+ return xorval;
+ }
+
+ void update_cpu_clock();
+};
+
+class sam6883_device : public device_t, public device_memory_interface, public sam6883_friend_device_interface
+{
+public:
+ template <typename T>
+ sam6883_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ : sam6883_device(mconfig, tag, owner, clock)
+ {
+ m_cpu.set_tag(std::forward<T>(cpu_tag));
+ }
+
+ sam6883_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // CPU read/write handlers
+ uint8_t read(offs_t offset);
+ void write(offs_t offset, uint8_t data);
+
+ // typically called by VDG
+ ATTR_FORCE_INLINE uint8_t display_read(offs_t offset)
+ {
+ 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_ram_space.read_byte(m_counter & m_counter_mask);
+ }
+
+ void hs_w(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_post_load() override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ // memory space configuration
+ address_space_config m_ram_config;
+ address_space_config m_rom0_config;
+ address_space_config m_rom1_config;
+ address_space_config m_rom2_config;
+ address_space_config m_io0_config;
+ address_space_config m_io1_config;
+ address_space_config m_io2_config;
+ address_space_config m_boot_config;
+
+ // memory spaces
+ memory_access<16, 0, 0, ENDIANNESS_BIG>::cache m_ram_space;
+ memory_access<14, 0, 0, ENDIANNESS_BIG>::cache m_rom_space[3];
+ memory_access< 5, 0, 0, ENDIANNESS_BIG>::specific m_io_space[3];
+ memory_access< 7, 0, 0, ENDIANNESS_BIG>::cache m_boot_space;
+ uint16_t m_counter_mask = 0;
+
+ // SAM state
+ uint16_t m_counter = 0;
+ uint8_t m_counter_xdiv = 0;
+ uint8_t m_counter_ydiv = 0;
+
+ // typically called by CPU
+ void internal_write(offs_t offset, uint8_t data);
+
+ // called when there is a carry out of bit 3 on the counter
+ ATTR_FORCE_INLINE void counter_carry_bit3()
+ {
+ uint8_t 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\n");
+ 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()
+ {
+ uint8_t 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\n");
+ return;
+ }
+
+ if (++m_counter_ydiv >= y_division)
+ {
+ m_counter_ydiv = 0;
+ m_counter += 0x0020;
+ }
+ }
+
+ // other members
+ void horizontal_sync();
+ void update_state();
+ void update_memory();
+};
+
+DECLARE_DEVICE_TYPE(SAM6883, sam6883_device)
+
+#endif // MAME_MACHINE_6883SAM_H
diff --git a/src/devices/machine/7200fifo.cpp b/src/devices/machine/7200fifo.cpp
index a5af4967dc1..d411d7ededa 100644
--- a/src/devices/machine/7200fifo.cpp
+++ b/src/devices/machine/7200fifo.cpp
@@ -11,7 +11,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/7200fifo.h"
+#include "7200fifo.h"
DEFINE_DEVICE_TYPE(IDT7200, idt7200_device, "idt7200", "IDT7200 FIFO (256x9)")
@@ -22,13 +22,13 @@ DEFINE_DEVICE_TYPE(IDT7202, idt7202_device, "idt7202", "IDT7202 FIFO (1024x9)")
// fifo7200_device - constructor
//-------------------------------------------------
-fifo7200_device::fifo7200_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int size)
- : device_t(mconfig, type, tag, owner, (uint32_t)0),
- m_ram_size(size),
- m_read_ptr(0), m_write_ptr(0), m_ef(0), m_ff(0), m_hf(0),
- m_ef_handler(*this),
- m_ff_handler(*this),
- m_hf_handler(*this)
+fifo7200_device::fifo7200_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int size) :
+ device_t(mconfig, type, tag, owner, (uint32_t)0),
+ m_ram_size(size),
+ m_read_ptr(0), m_write_ptr(0), m_ef(0), m_ff(0), m_hf(0),
+ m_ef_handler(*this),
+ m_ff_handler(*this),
+ m_hf_handler(*this)
{
}
@@ -37,8 +37,8 @@ fifo7200_device::fifo7200_device(const machine_config &mconfig, device_type type
// idt7200_device - constructor
//-------------------------------------------------
-idt7200_device::idt7200_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : fifo7200_device(mconfig, IDT7200, tag, owner, 0x100)
+idt7200_device::idt7200_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ fifo7200_device(mconfig, IDT7200, tag, owner, 0x100)
{
}
@@ -47,8 +47,8 @@ idt7200_device::idt7200_device(const machine_config &mconfig, const char *tag, d
// idt7201_device - constructor
//-------------------------------------------------
-idt7201_device::idt7201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : fifo7200_device(mconfig, IDT7201, tag, owner, 0x200)
+idt7201_device::idt7201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ fifo7200_device(mconfig, IDT7201, tag, owner, 0x200)
{
}
@@ -57,8 +57,8 @@ idt7201_device::idt7201_device(const machine_config &mconfig, const char *tag, d
// idt7202_device - constructor
//-------------------------------------------------
-idt7202_device::idt7202_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : fifo7200_device(mconfig, IDT7202, tag, owner, 0x400)
+idt7202_device::idt7202_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ fifo7200_device(mconfig, IDT7202, tag, owner, 0x400)
{
}
@@ -72,11 +72,6 @@ void fifo7200_device::device_start()
assert(m_ram_size > 1 && ~m_ram_size & 1);
m_buffer.resize(m_ram_size);
- // resolve callbacks
- m_ef_handler.resolve_safe();
- m_ff_handler.resolve_safe();
- m_hf_handler.resolve_safe();
-
// state save
save_item(NAME(m_buffer));
save_item(NAME(m_read_ptr));
@@ -132,7 +127,7 @@ void fifo7200_device::fifo_write(uint16_t data)
m_ff_handler(!m_ff);
}
- else if (((m_read_ptr + 1 + m_ram_size / 2) % m_ram_size) == m_write_ptr)
+ else if (!m_hf && (fifo_used() >= m_ram_size / 2))
{
m_hf = 1;
m_hf_handler(!m_hf);
@@ -166,12 +161,30 @@ uint16_t fifo7200_device::fifo_read()
m_ef_handler(!m_ef);
}
- else if (((m_read_ptr + m_ram_size / 2) % m_ram_size) == m_write_ptr)
+ else if (m_hf && (fifo_used() < m_ram_size / 2))
{
m_hf = 0;
m_hf_handler(!m_hf);
}
}
+ return ret;
+}
+
+int fifo7200_device::fifo_used()
+{
+ int ret = m_ram_size;
+
+ if (!m_ff)
+ {
+ if (m_write_ptr >= m_read_ptr)
+ {
+ ret = m_write_ptr - m_read_ptr;
+ }
+ else
+ {
+ ret = m_ram_size + m_write_ptr - m_read_ptr;
+ }
+ }
return ret;
}
diff --git a/src/devices/machine/7200fifo.h b/src/devices/machine/7200fifo.h
index 4ed323a98ac..3d9bf1fa703 100644
--- a/src/devices/machine/7200fifo.h
+++ b/src/devices/machine/7200fifo.h
@@ -66,9 +66,9 @@ public:
auto ff_handler() { return m_ff_handler.bind(); }
auto hf_handler() { return m_hf_handler.bind(); }
- DECLARE_READ_LINE_MEMBER( ef_r ) { return !m_ef; } // _EF
- DECLARE_READ_LINE_MEMBER( ff_r ) { return !m_ff; } // _FF
- DECLARE_READ_LINE_MEMBER( hf_r ) { return !m_hf; } // _HF
+ int ef_r() { return !m_ef; } // _EF
+ int ff_r() { return !m_ff; } // _FF
+ int hf_r() { return !m_hf; } // _HF
// normal configuration
void data_word_w(uint16_t data) { fifo_write(data); }
@@ -88,6 +88,7 @@ protected:
private:
void fifo_write(uint16_t data);
uint16_t fifo_read();
+ int fifo_used();
std::vector<uint16_t> m_buffer;
const int m_ram_size;
diff --git a/src/devices/machine/7400.cpp b/src/devices/machine/7400.cpp
deleted file mode 100644
index f8ab747715d..00000000000
--- a/src/devices/machine/7400.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/*****************************************************************************
-
- 7400 Quad 2-Input NAND Gate
-
-*****************************************************************************/
-
-#include "emu.h"
-#include "7400.h"
-
-DEFINE_DEVICE_TYPE(TTL7400, ttl7400_device, "7400", "7400 Quad 2-Input NAND Gate")
-
-ttl7400_device::ttl7400_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, TTL7400, tag, owner, clock)
- , m_y_func(*this)
- , m_a(0)
- , m_b(0)
- , m_y(0)
-{
-}
-
-void ttl7400_device::device_start()
-{
- m_y_func.resolve_all_safe();
-
- save_item(NAME(m_a));
- save_item(NAME(m_b));
- save_item(NAME(m_y));
-}
-
-void ttl7400_device::device_reset()
-{
- m_a = 0;
- m_b = 0;
- m_y = 0;
-}
-
-void ttl7400_device::update()
-{
- uint8_t last_y = m_y;
-
- m_y = (m_a & m_b) & 0xf;
-
- if (m_y != last_y)
- {
- for (std::size_t bit = 0; bit < 4; bit++)
- {
- if (BIT(m_y, bit) == BIT(last_y, bit))
- continue;
-
- m_y_func[bit](BIT(m_y, bit));
- }
- }
-}
-
-void ttl7400_device::a_w(uint8_t line, uint8_t state)
-{
- uint8_t old_a = m_a;
- m_a &= ~(1 << line);
- m_a |= (state << line);
- if (old_a != m_a)
- update();
-}
-
-void ttl7400_device::b_w(uint8_t line, uint8_t state)
-{
- uint8_t old_b = m_b;
- m_b &= ~(1 << line);
- m_b |= (state << line);
- if (old_b != m_b)
- update();
-}
-
-uint8_t ttl7400_device::y_r(uint8_t line)
-{
- return (m_y >> line) & 1;
-}
-
-
-WRITE_LINE_MEMBER( ttl7400_device::a1_w ) { a_w(0, state); }
-WRITE_LINE_MEMBER( ttl7400_device::a2_w ) { a_w(1, state); }
-WRITE_LINE_MEMBER( ttl7400_device::a3_w ) { a_w(2, state); }
-WRITE_LINE_MEMBER( ttl7400_device::a4_w ) { a_w(3, state); }
-
-WRITE_LINE_MEMBER( ttl7400_device::b1_w ) { b_w(0, state); }
-WRITE_LINE_MEMBER( ttl7400_device::b2_w ) { b_w(1, state); }
-WRITE_LINE_MEMBER( ttl7400_device::b3_w ) { b_w(2, state); }
-WRITE_LINE_MEMBER( ttl7400_device::b4_w ) { b_w(3, state); }
-
-READ_LINE_MEMBER( ttl7400_device::y1_r ) { return y_r(0); }
-READ_LINE_MEMBER( ttl7400_device::y2_r ) { return y_r(1); }
-READ_LINE_MEMBER( ttl7400_device::y3_r ) { return y_r(2); }
-READ_LINE_MEMBER( ttl7400_device::y4_r ) { return y_r(3); }
diff --git a/src/devices/machine/7400.h b/src/devices/machine/7400.h
deleted file mode 100644
index 13939cda7a7..00000000000
--- a/src/devices/machine/7400.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/*****************************************************************************
-
- 7400 Quad 2-Input NAND Gate
-
-***********************************************************************
-
- Connection Diagram:
- ___ ___
- 1A 1 |* u | 14 Vcc
- 1B 2 | | 13 4B
- 1Y 3 | | 12 4A
- 2A 4 | | 11 4Y
- 2B 5 | | 10 3B
- 2Y 6 | | 9 3A
- GND 7 |_______| 8 3Y
-
- Truth Table:
- ___________
- | A | B | Y |
- |---|---|---|
- | 0 | 0 | 0 |
- | 0 | 1 | 0 |
- | 1 | 0 | 0 |
- | 1 | 1 | 1 |
- |___|___|___|
-
-**********************************************************************/
-
-#ifndef MAME_MACHINE_7400_H
-#define MAME_MACHINE_7400_H
-
-#pragma once
-
-class ttl7400_device : public device_t
-{
-public:
- // construction/destruction
- ttl7400_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
-
- template <std::size_t Bit> auto y_cb() { return m_y_func[Bit].bind(); }
-
- // public interfaces
- DECLARE_WRITE_LINE_MEMBER( a1_w );
- DECLARE_WRITE_LINE_MEMBER( a2_w );
- DECLARE_WRITE_LINE_MEMBER( a3_w );
- DECLARE_WRITE_LINE_MEMBER( a4_w );
- DECLARE_WRITE_LINE_MEMBER( b1_w );
- DECLARE_WRITE_LINE_MEMBER( b2_w );
- DECLARE_WRITE_LINE_MEMBER( b3_w );
- DECLARE_WRITE_LINE_MEMBER( b4_w );
-
- DECLARE_READ_LINE_MEMBER( y1_r );
- DECLARE_READ_LINE_MEMBER( y2_r );
- DECLARE_READ_LINE_MEMBER( y3_r );
- DECLARE_READ_LINE_MEMBER( y4_r );
-
-protected:
- void a_w(uint8_t line, uint8_t state);
- void b_w(uint8_t line, uint8_t state);
- uint8_t y_r(uint8_t line);
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
-private:
- void update();
-
- // callbacks
- devcb_write_line::array<4> m_y_func;
-
- // inputs
- uint8_t m_a; // pins 1,4,9,12
- uint8_t m_b; // pins 2,5,10,13
-
- // outputs
- uint8_t m_y; // pins 3,6,8,11
-};
-
-// device type definition
-DECLARE_DEVICE_TYPE(TTL7400, ttl7400_device)
-
-#endif // MAME_MACHINE_7400_H
diff --git a/src/devices/machine/7404.cpp b/src/devices/machine/7404.cpp
index ad3ca9e234e..4ffddf2548a 100644
--- a/src/devices/machine/7404.cpp
+++ b/src/devices/machine/7404.cpp
@@ -21,8 +21,6 @@ ttl7404_device::ttl7404_device(const machine_config &mconfig, const char *tag, d
void ttl7404_device::device_start()
{
- m_y_func.resolve_all_safe();
-
save_item(NAME(m_a));
save_item(NAME(m_y));
}
@@ -66,16 +64,16 @@ uint8_t ttl7404_device::y_r(uint8_t line)
}
-WRITE_LINE_MEMBER( ttl7404_device::a1_w ) { a_w(0, state); }
-WRITE_LINE_MEMBER( ttl7404_device::a2_w ) { a_w(1, state); }
-WRITE_LINE_MEMBER( ttl7404_device::a3_w ) { a_w(2, state); }
-WRITE_LINE_MEMBER( ttl7404_device::a4_w ) { a_w(3, state); }
-WRITE_LINE_MEMBER( ttl7404_device::a5_w ) { a_w(4, state); }
-WRITE_LINE_MEMBER( ttl7404_device::a6_w ) { a_w(5, state); }
+void ttl7404_device::a1_w(int state) { a_w(0, state); }
+void ttl7404_device::a2_w(int state) { a_w(1, state); }
+void ttl7404_device::a3_w(int state) { a_w(2, state); }
+void ttl7404_device::a4_w(int state) { a_w(3, state); }
+void ttl7404_device::a5_w(int state) { a_w(4, state); }
+void ttl7404_device::a6_w(int state) { a_w(5, state); }
-READ_LINE_MEMBER( ttl7404_device::y1_r ) { return y_r(0); }
-READ_LINE_MEMBER( ttl7404_device::y2_r ) { return y_r(1); }
-READ_LINE_MEMBER( ttl7404_device::y3_r ) { return y_r(2); }
-READ_LINE_MEMBER( ttl7404_device::y4_r ) { return y_r(3); }
-READ_LINE_MEMBER( ttl7404_device::y5_r ) { return y_r(4); }
-READ_LINE_MEMBER( ttl7404_device::y6_r ) { return y_r(5); }
+int ttl7404_device::y1_r() { return y_r(0); }
+int ttl7404_device::y2_r() { return y_r(1); }
+int ttl7404_device::y3_r() { return y_r(2); }
+int ttl7404_device::y4_r() { return y_r(3); }
+int ttl7404_device::y5_r() { return y_r(4); }
+int ttl7404_device::y6_r() { return y_r(5); }
diff --git a/src/devices/machine/7404.h b/src/devices/machine/7404.h
index 9bc680997e5..873cb95fc11 100644
--- a/src/devices/machine/7404.h
+++ b/src/devices/machine/7404.h
@@ -69,19 +69,19 @@ public:
template <std::size_t Bit> auto y_cb() { return m_y_func[Bit].bind(); }
// public interfaces
- DECLARE_WRITE_LINE_MEMBER( a1_w );
- DECLARE_WRITE_LINE_MEMBER( a2_w );
- DECLARE_WRITE_LINE_MEMBER( a3_w );
- DECLARE_WRITE_LINE_MEMBER( a4_w );
- DECLARE_WRITE_LINE_MEMBER( a5_w );
- DECLARE_WRITE_LINE_MEMBER( a6_w );
-
- DECLARE_READ_LINE_MEMBER( y1_r );
- DECLARE_READ_LINE_MEMBER( y2_r );
- DECLARE_READ_LINE_MEMBER( y3_r );
- DECLARE_READ_LINE_MEMBER( y4_r );
- DECLARE_READ_LINE_MEMBER( y5_r );
- DECLARE_READ_LINE_MEMBER( y6_r );
+ void a1_w(int state);
+ void a2_w(int state);
+ void a3_w(int state);
+ void a4_w(int state);
+ void a5_w(int state);
+ void a6_w(int state);
+
+ int y1_r();
+ int y2_r();
+ int y3_r();
+ int y4_r();
+ int y5_r();
+ int y6_r();
protected:
void a_w(uint8_t line, uint8_t state);
diff --git a/src/devices/machine/74123.cpp b/src/devices/machine/74123.cpp
index 6596bf58bf3..9e57a805664 100644
--- a/src/devices/machine/74123.cpp
+++ b/src/devices/machine/74123.cpp
@@ -9,7 +9,8 @@
*****************************************************************************/
#include "emu.h"
-#include "machine/74123.h"
+#include "74123.h"
+
#include "machine/rescap.h"
//#define VERBOSE 1
@@ -27,16 +28,17 @@ DEFINE_DEVICE_TYPE(TTL74123, ttl74123_device, "ttl74123", "74123 TTL")
// ttl74123_device - constructor
//-------------------------------------------------
-ttl74123_device::ttl74123_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, TTL74123, tag, owner, clock),
- m_timer(nullptr),
- m_connection_type(TTL74123_NOT_GROUNDED_NO_DIODE),
- m_res(1.0),
- m_cap(1.0),
- m_a(0),
- m_b(0),
- m_clear(0),
- m_output_changed_cb(*this)
+ttl74123_device::ttl74123_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, TTL74123, tag, owner, clock),
+ m_clear_timer(nullptr),
+ m_output_timer(nullptr),
+ m_connection_type(TTL74123_NOT_GROUNDED_NO_DIODE),
+ m_res(1.0),
+ m_cap(1.0),
+ m_a(0),
+ m_b(0),
+ m_clear(0),
+ m_output_changed_cb(*this)
{
}
@@ -46,9 +48,8 @@ ttl74123_device::ttl74123_device(const machine_config &mconfig, const char *tag,
void ttl74123_device::device_start()
{
- m_output_changed_cb.resolve_safe();
-
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ttl74123_device::clear_callback),this));
+ m_clear_timer = timer_alloc(FUNC(ttl74123_device::clear_callback), this);
+ m_output_timer = timer_alloc(FUNC(ttl74123_device::output_callback), this);
/* register for state saving */
save_item(NAME(m_a));
@@ -110,8 +111,7 @@ attotime ttl74123_device::compute_duration()
int ttl74123_device::timer_running()
{
- return (m_timer->remaining() > attotime::zero) &&
- (m_timer->remaining() != attotime::never);
+ return m_clear_timer->remaining() > attotime::zero && !m_clear_timer->remaining().is_never();
}
@@ -133,7 +133,7 @@ void ttl74123_device::set_output()
{
int output = timer_running();
- machine().scheduler().timer_set( attotime::zero, timer_expired_delegate(FUNC(ttl74123_device::output_callback ),this), output);
+ m_output_timer->adjust(attotime::zero, output);
LOG("74123: Output: %d\n", output);
}
@@ -163,9 +163,9 @@ void ttl74123_device::start_pulse()
/* retriggering, but not if we are called to quickly */
attotime delay_time = attotime(0, ATTOSECONDS_PER_SECOND * m_cap * 220);
- if(m_timer->elapsed() >= delay_time)
+ if(m_clear_timer->elapsed() >= delay_time)
{
- m_timer->adjust(duration);
+ m_clear_timer->adjust(duration);
LOG("74123: Retriggering pulse. Duration: %f\n", duration.as_double());
}
@@ -177,7 +177,7 @@ void ttl74123_device::start_pulse()
else
{
/* starting */
- m_timer->adjust(duration);
+ m_clear_timer->adjust(duration);
set_output();
@@ -190,7 +190,7 @@ void ttl74123_device::start_pulse()
// a_w - write register a data
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl74123_device::a_w )
+void ttl74123_device::a_w(int state)
{
/* start/regtrigger pulse if B=HI and falling edge on A (while clear is HI) */
if (!state && m_a && m_b && m_clear)
@@ -206,7 +206,7 @@ WRITE_LINE_MEMBER( ttl74123_device::a_w )
// b_w - write register b data
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl74123_device::b_w)
+void ttl74123_device::b_w(int state)
{
/* start/regtrigger pulse if A=LO and rising edge on B (while clear is HI) */
if (state && !m_b && !m_a && m_clear)
@@ -222,7 +222,7 @@ WRITE_LINE_MEMBER( ttl74123_device::b_w)
// clear_w - write register clear data
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl74123_device::clear_w)
+void ttl74123_device::clear_w(int state)
{
/* start/regtrigger pulse if B=HI and A=LO and rising edge on clear */
if (state && !m_a && m_b && !m_clear)
@@ -231,7 +231,7 @@ WRITE_LINE_MEMBER( ttl74123_device::clear_w)
}
else if (!state) /* clear the output */
{
- m_timer->adjust(attotime::zero);
+ m_clear_timer->adjust(attotime::zero);
LOG("74123: Cleared\n");
}
@@ -243,7 +243,7 @@ WRITE_LINE_MEMBER( ttl74123_device::clear_w)
// reset_w - reset device
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl74123_device::reset_w)
+void ttl74123_device::reset_w(int state)
{
set_output();
}
diff --git a/src/devices/machine/74123.h b/src/devices/machine/74123.h
index bdff8d29aee..ed571f12273 100644
--- a/src/devices/machine/74123.h
+++ b/src/devices/machine/74123.h
@@ -84,12 +84,12 @@ public:
auto out_cb() { return m_output_changed_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER(a_w);
- DECLARE_WRITE_LINE_MEMBER(b_w);
- DECLARE_WRITE_LINE_MEMBER(clear_w);
- DECLARE_WRITE_LINE_MEMBER(reset_w);
+ void a_w(int state);
+ void b_w(int state);
+ void clear_w(int state);
+ void reset_w(int state);
- DECLARE_READ_LINE_MEMBER(q_r) { return timer_running(); }
+ int q_r() { return timer_running(); }
protected:
// device-level overrides
@@ -107,7 +107,8 @@ private:
void set_output();
attotime compute_duration();
- emu_timer *m_timer;
+ emu_timer *m_clear_timer;
+ emu_timer *m_output_timer;
int m_connection_type; /* the hook up type - one of the constants above */
double m_res; /* resistor connected to RCext */
double m_cap; /* capacitor connected to Cext and RCext */
diff --git a/src/devices/machine/74145.cpp b/src/devices/machine/74145.cpp
index 1ac1a41ffa6..922fa104885 100644
--- a/src/devices/machine/74145.cpp
+++ b/src/devices/machine/74145.cpp
@@ -73,9 +73,6 @@ ttl74145_device::ttl74145_device(const machine_config &mconfig, const char *tag,
void ttl74145_device::device_start()
{
- /* resolve callbacks */
- m_output_line_cb.resolve_all_safe();
-
// register for state saving
save_item(NAME(m_number));
}
diff --git a/src/devices/machine/74148.cpp b/src/devices/machine/74148.cpp
index 45ce281ed51..216d98a05d1 100644
--- a/src/devices/machine/74148.cpp
+++ b/src/devices/machine/74148.cpp
@@ -41,7 +41,7 @@
*****************************************************************************/
#include "emu.h"
-#include "machine/74148.h"
+#include "74148.h"
DEFINE_DEVICE_TYPE(TTL74148, ttl74148_device, "74148", "74148 TTL")
@@ -58,7 +58,7 @@ ttl74148_device::ttl74148_device(const machine_config &mconfig, const char *tag,
, m_last_output_valid(0)
, m_last_enable_output(0)
{
- for (auto & elem : m_input_lines)
+ for (auto &elem : m_input_lines)
elem = 0;
}
@@ -68,8 +68,6 @@ ttl74148_device::ttl74148_device(const machine_config &mconfig, const char *tag,
void ttl74148_device::device_start()
{
- m_output_cb.resolve_safe();
-
save_item(NAME(m_input_lines));
save_item(NAME(m_enable_input));
save_item(NAME(m_output));
@@ -157,9 +155,8 @@ void ttl74148_device::update()
/* call callback if any of the outputs changed */
- if (!m_output_cb.isnull() &&
- ((m_output != m_last_output) ||
- (m_output_valid != m_last_output_valid) || (m_enable_output != m_last_enable_output)))
+ if ((m_output != m_last_output) ||
+ (m_output_valid != m_last_output_valid) || (m_enable_output != m_last_enable_output))
{
m_last_output = m_output;
m_last_output_valid = m_output_valid;
diff --git a/src/devices/machine/74153.cpp b/src/devices/machine/74153.cpp
index 18352ff7e06..b13b1ecb53b 100644
--- a/src/devices/machine/74153.cpp
+++ b/src/devices/machine/74153.cpp
@@ -44,10 +44,6 @@ ttl153_device::ttl153_device(const machine_config &mconfig, const char *tag, dev
void ttl153_device::device_start()
{
- // resolve callbacks
- m_za_cb.resolve_safe();
- m_zb_cb.resolve_safe();
-
// register for save states
save_pointer(NAME(m_s), 2);
save_pointer(NAME(m_ia), 4);
@@ -112,14 +108,14 @@ void ttl153_device::update_b()
// INTERFACE
//**************************************************************************
-WRITE_LINE_MEMBER( ttl153_device::s0_w )
+void ttl153_device::s0_w(int state)
{
m_s[0] = bool(state);
update_a();
update_b();
}
-WRITE_LINE_MEMBER( ttl153_device::s1_w )
+void ttl153_device::s1_w(int state)
{
m_s[1] = bool(state);
update_a();
@@ -134,25 +130,25 @@ void ttl153_device::s_w(uint8_t data)
update_b();
}
-WRITE_LINE_MEMBER( ttl153_device::i0a_w )
+void ttl153_device::i0a_w(int state)
{
m_ia[0] = bool(state);
update_a();
}
-WRITE_LINE_MEMBER( ttl153_device::i1a_w )
+void ttl153_device::i1a_w(int state)
{
m_ia[1] = bool(state);
update_a();
}
-WRITE_LINE_MEMBER( ttl153_device::i2a_w )
+void ttl153_device::i2a_w(int state)
{
m_ia[2] = bool(state);
update_a();
}
-WRITE_LINE_MEMBER( ttl153_device::i3a_w )
+void ttl153_device::i3a_w(int state)
{
m_ia[3] = bool(state);
update_a();
@@ -167,25 +163,25 @@ void ttl153_device::ia_w(uint8_t data)
update_a();
}
-WRITE_LINE_MEMBER( ttl153_device::i0b_w )
+void ttl153_device::i0b_w(int state)
{
m_ib[0] = bool(state);
update_b();
}
-WRITE_LINE_MEMBER( ttl153_device::i1b_w )
+void ttl153_device::i1b_w(int state)
{
m_ib[1] = bool(state);
update_b();
}
-WRITE_LINE_MEMBER( ttl153_device::i2b_w )
+void ttl153_device::i2b_w(int state)
{
m_ib[2] = bool(state);
update_b();
}
-WRITE_LINE_MEMBER( ttl153_device::i3b_w )
+void ttl153_device::i3b_w(int state)
{
m_ib[3] = bool(state);
update_b();
@@ -200,12 +196,12 @@ void ttl153_device::ib_w(uint8_t data)
update_b();
}
-READ_LINE_MEMBER( ttl153_device::za_r )
+int ttl153_device::za_r()
{
return m_z[0] ? 1 : 0;
}
-READ_LINE_MEMBER( ttl153_device::zb_r )
+int ttl153_device::zb_r()
{
return m_z[1] ? 1 : 0;
}
diff --git a/src/devices/machine/74153.h b/src/devices/machine/74153.h
index ae2f3a37353..6cc412b28cd 100644
--- a/src/devices/machine/74153.h
+++ b/src/devices/machine/74153.h
@@ -38,27 +38,27 @@ public:
auto zb_cb() { return m_zb_cb.bind(); }
// select
- DECLARE_WRITE_LINE_MEMBER(s0_w);
- DECLARE_WRITE_LINE_MEMBER(s1_w);
+ void s0_w(int state);
+ void s1_w(int state);
void s_w(uint8_t data);
// input a
- DECLARE_WRITE_LINE_MEMBER(i0a_w);
- DECLARE_WRITE_LINE_MEMBER(i1a_w);
- DECLARE_WRITE_LINE_MEMBER(i2a_w);
- DECLARE_WRITE_LINE_MEMBER(i3a_w);
+ void i0a_w(int state);
+ void i1a_w(int state);
+ void i2a_w(int state);
+ void i3a_w(int state);
void ia_w(uint8_t data);
// input b
- DECLARE_WRITE_LINE_MEMBER(i0b_w);
- DECLARE_WRITE_LINE_MEMBER(i1b_w);
- DECLARE_WRITE_LINE_MEMBER(i2b_w);
- DECLARE_WRITE_LINE_MEMBER(i3b_w);
+ void i0b_w(int state);
+ void i1b_w(int state);
+ void i2b_w(int state);
+ void i3b_w(int state);
void ib_w(uint8_t data);
// output
- DECLARE_READ_LINE_MEMBER(za_r);
- DECLARE_READ_LINE_MEMBER(zb_r);
+ int za_r();
+ int zb_r();
protected:
// device-level overrides
diff --git a/src/devices/machine/74157.cpp b/src/devices/machine/74157.cpp
index 1dc7eb1289b..aea9dbaa532 100644
--- a/src/devices/machine/74157.cpp
+++ b/src/devices/machine/74157.cpp
@@ -42,8 +42,8 @@ ls157_device::ls157_device(const machine_config &mconfig, const char *tag, devic
ls157_device::ls157_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 mask)
: device_t(mconfig, type, tag, owner, clock)
- , m_a_in_cb(*this)
- , m_b_in_cb(*this)
+ , m_a_in_cb(*this, 0)
+ , m_b_in_cb(*this, 0)
, m_out_cb(*this)
, m_data_mask(mask)
{
@@ -71,11 +71,6 @@ ls157_x2_device::ls157_x2_device(const machine_config &mconfig, const char *tag,
void ls157_device::device_start()
{
- // resolve callbacks
- m_a_in_cb.resolve();
- m_b_in_cb.resolve();
- m_out_cb.resolve();
-
// register items for save state
save_item(NAME(m_a));
save_item(NAME(m_b));
@@ -156,10 +151,10 @@ void ls157_device::interleave_w(u8 data)
// aN_w -- update one bit of first data input
//-------------------------------------------------
-WRITE_LINE_MEMBER(ls157_device::a0_w) { write_a_bit(0, state); }
-WRITE_LINE_MEMBER(ls157_device::a1_w) { write_a_bit(1, state); }
-WRITE_LINE_MEMBER(ls157_device::a2_w) { write_a_bit(2, state); }
-WRITE_LINE_MEMBER(ls157_device::a3_w) { write_a_bit(3, state); }
+void ls157_device::a0_w(int state) { write_a_bit(0, state); }
+void ls157_device::a1_w(int state) { write_a_bit(1, state); }
+void ls157_device::a2_w(int state) { write_a_bit(2, state); }
+void ls157_device::a3_w(int state) { write_a_bit(3, state); }
void ls157_device::write_a_bit(int bit, bool state)
{
@@ -170,7 +165,7 @@ void ls157_device::write_a_bit(int bit, bool state)
else
m_a &= ~(1 << bit);
- if (!m_strobe && !m_select && !m_out_cb.isnull())
+ if (!m_strobe && !m_select && !m_out_cb.isunset())
m_out_cb(m_a);
}
}
@@ -180,10 +175,10 @@ void ls157_device::write_a_bit(int bit, bool state)
// bN_w -- update one bit of second data input
//-------------------------------------------------
-WRITE_LINE_MEMBER(ls157_device::b0_w) { write_b_bit(0, state); }
-WRITE_LINE_MEMBER(ls157_device::b1_w) { write_b_bit(1, state); }
-WRITE_LINE_MEMBER(ls157_device::b2_w) { write_b_bit(2, state); }
-WRITE_LINE_MEMBER(ls157_device::b3_w) { write_b_bit(3, state); }
+void ls157_device::b0_w(int state) { write_b_bit(0, state); }
+void ls157_device::b1_w(int state) { write_b_bit(1, state); }
+void ls157_device::b2_w(int state) { write_b_bit(2, state); }
+void ls157_device::b3_w(int state) { write_b_bit(3, state); }
void ls157_device::write_b_bit(int bit, bool state)
{
@@ -194,7 +189,7 @@ void ls157_device::write_b_bit(int bit, bool state)
else
m_b &= ~(1 << bit);
- if (!m_strobe && m_select && !m_out_cb.isnull())
+ if (!m_strobe && m_select && !m_out_cb.isunset())
m_out_cb(m_b);
}
}
@@ -208,7 +203,7 @@ void ls157_device::write_b_bit(int bit, bool state)
// select_w -- set select input
//-------------------------------------------------
-WRITE_LINE_MEMBER(ls157_device::select_w)
+void ls157_device::select_w(int state)
{
if (m_select != bool(state))
{
@@ -222,14 +217,14 @@ WRITE_LINE_MEMBER(ls157_device::select_w)
// strobe_w -- set strobe input (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(ls157_device::strobe_w)
+void ls157_device::strobe_w(int state)
{
if (m_strobe != bool(state))
{
m_strobe = bool(state);
// Clear output when strobe goes high
- if (m_strobe && !m_out_cb.isnull())
+ if (m_strobe && !m_out_cb.isunset())
m_out_cb(0);
else
update_output();
@@ -246,12 +241,12 @@ void ls157_device::update_output()
{
// S high, strobe low: Y1-Y4 = B1-B4
// S low, strobe low: Y1-Y4 = A1-A4
- if (!m_strobe && !m_out_cb.isnull())
+ if (!m_strobe && !m_out_cb.isunset())
{
if (m_select)
- m_out_cb(m_b_in_cb.isnull() ? m_b : (m_b_in_cb() & m_data_mask));
+ m_out_cb(m_b_in_cb.isunset() ? m_b : (m_b_in_cb() & m_data_mask));
else
- m_out_cb(m_a_in_cb.isnull() ? m_a : (m_a_in_cb() & m_data_mask));
+ m_out_cb(m_a_in_cb.isunset() ? m_a : (m_a_in_cb() & m_data_mask));
}
}
@@ -265,9 +260,9 @@ u8 ls157_device::output_r()
if (m_strobe)
return 0;
else if (m_select)
- return m_b_in_cb.isnull() ? m_b : (m_b_in_cb() & m_data_mask);
+ return m_b_in_cb.isunset() ? m_b : (m_b_in_cb() & m_data_mask);
else
- return m_a_in_cb.isnull() ? m_a : (m_a_in_cb() & m_data_mask);
+ return m_a_in_cb.isunset() ? m_a : (m_a_in_cb() & m_data_mask);
}
diff --git a/src/devices/machine/74157.h b/src/devices/machine/74157.h
index 52875cc0a76..fbeec1aaea3 100644
--- a/src/devices/machine/74157.h
+++ b/src/devices/machine/74157.h
@@ -49,18 +49,18 @@ public:
void interleave_w(u8 data);
// data line writes
- DECLARE_WRITE_LINE_MEMBER(a0_w);
- DECLARE_WRITE_LINE_MEMBER(a1_w);
- DECLARE_WRITE_LINE_MEMBER(a2_w);
- DECLARE_WRITE_LINE_MEMBER(a3_w);
- DECLARE_WRITE_LINE_MEMBER(b0_w);
- DECLARE_WRITE_LINE_MEMBER(b1_w);
- DECLARE_WRITE_LINE_MEMBER(b2_w);
- DECLARE_WRITE_LINE_MEMBER(b3_w);
+ void a0_w(int state);
+ void a1_w(int state);
+ void a2_w(int state);
+ void a3_w(int state);
+ void b0_w(int state);
+ void b1_w(int state);
+ void b2_w(int state);
+ void b3_w(int state);
// control line writes
- DECLARE_WRITE_LINE_MEMBER(select_w);
- DECLARE_WRITE_LINE_MEMBER(strobe_w);
+ void select_w(int state);
+ void strobe_w(int state);
// output read
u8 output_r();
@@ -96,7 +96,7 @@ class ls157_x2_device : public ls157_device
{
public:
// construction/destruction
- ls157_x2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ ls157_x2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
};
// ======================> hc157_device
@@ -105,7 +105,7 @@ class hc157_device : public ls157_device
{
public:
// construction/destruction
- hc157_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ hc157_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
};
// ======================> hct157_device
@@ -114,7 +114,7 @@ class hct157_device : public ls157_device
{
public:
// construction/destruction
- hct157_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ hct157_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
};
diff --git a/src/devices/machine/74161.cpp b/src/devices/machine/74161.cpp
index 64e935152f5..888cf7f608c 100644
--- a/src/devices/machine/74161.cpp
+++ b/src/devices/machine/74161.cpp
@@ -65,9 +65,6 @@ void ttl7416x_device::device_start()
save_item(NAME(m_pclock));
save_item(NAME(m_p));
save_item(NAME(m_out));
-
- m_output_func.resolve_safe();
- m_tc_func.resolve_safe();
}
void ttl7416x_device::device_reset()
@@ -141,7 +138,7 @@ void ttl7416x_device::increment()
m_out &= 0x0f;
}
-WRITE_LINE_MEMBER( ttl7416x_device::clear_w )
+void ttl7416x_device::clear_w(int state)
{
m_clear = state;
if (!m_synchronous_reset)
@@ -149,22 +146,22 @@ WRITE_LINE_MEMBER( ttl7416x_device::clear_w )
}
-WRITE_LINE_MEMBER( ttl7416x_device::pe_w )
+void ttl7416x_device::pe_w(int state)
{
m_pe = state ^ 1;
}
-WRITE_LINE_MEMBER( ttl7416x_device::cet_w )
+void ttl7416x_device::cet_w(int state)
{
m_cet = state;
}
-WRITE_LINE_MEMBER( ttl7416x_device::cep_w )
+void ttl7416x_device::cep_w(int state)
{
m_cep = state;
}
-WRITE_LINE_MEMBER( ttl7416x_device::clock_w )
+void ttl7416x_device::clock_w(int state)
{
uint8_t last_clock = m_pclock;
m_pclock = state;
@@ -179,31 +176,31 @@ void ttl7416x_device::p_w(uint8_t data)
m_p = data & 0xf;
}
-WRITE_LINE_MEMBER( ttl7416x_device::p1_w )
+void ttl7416x_device::p1_w(int state)
{
m_p &= ~(1 << 0);
m_p |= (state << 0);
}
-WRITE_LINE_MEMBER( ttl7416x_device::p2_w )
+void ttl7416x_device::p2_w(int state)
{
m_p &= ~(1 << 1);
m_p |= (state << 1);
}
-WRITE_LINE_MEMBER( ttl7416x_device::p3_w )
+void ttl7416x_device::p3_w(int state)
{
m_p &= ~(1 << 2);
m_p |= (state << 2);
}
-WRITE_LINE_MEMBER( ttl7416x_device::p4_w )
+void ttl7416x_device::p4_w(int state)
{
m_p &= ~(1 << 3);
m_p |= (state << 3);
}
-READ_LINE_MEMBER( ttl7416x_device::output_r )
+int ttl7416x_device::output_r()
{
return m_out;
}
@@ -212,7 +209,7 @@ READ_LINE_MEMBER( ttl7416x_device::output_r )
TC is an asynchronous signal, depending on the current states of CET, CEP,
and the counter value.
*/
-READ_LINE_MEMBER( ttl7416x_device::tc_r )
+int ttl7416x_device::tc_r()
{
return ((m_cet==1) && (m_cep==1) && (m_out==m_limit-1))? 1:0;
}
diff --git a/src/devices/machine/74161.h b/src/devices/machine/74161.h
index 0145e08a9fb..f265f9b4243 100644
--- a/src/devices/machine/74161.h
+++ b/src/devices/machine/74161.h
@@ -68,19 +68,19 @@ public:
auto tc_cb() { return m_tc_func.bind(); }
// public interfaces
- DECLARE_WRITE_LINE_MEMBER( clear_w );
- DECLARE_WRITE_LINE_MEMBER( pe_w );
- DECLARE_WRITE_LINE_MEMBER( cet_w );
- DECLARE_WRITE_LINE_MEMBER( cep_w );
- DECLARE_WRITE_LINE_MEMBER( clock_w );
+ void clear_w(int state);
+ void pe_w(int state);
+ void cet_w(int state);
+ void cep_w(int state);
+ void clock_w(int state);
void p_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( p1_w );
- DECLARE_WRITE_LINE_MEMBER( p2_w );
- DECLARE_WRITE_LINE_MEMBER( p3_w );
- DECLARE_WRITE_LINE_MEMBER( p4_w );
+ void p1_w(int state);
+ void p2_w(int state);
+ void p3_w(int state);
+ void p4_w(int state);
- DECLARE_READ_LINE_MEMBER( output_r );
- DECLARE_READ_LINE_MEMBER( tc_r );
+ int output_r();
+ int tc_r();
void set_cet_pin_value(int value) { m_cetpre = value; }
void set_cep_pin_value(int value) { m_ceppre = value; }
diff --git a/src/devices/machine/74165.cpp b/src/devices/machine/74165.cpp
index 9ba4415d56c..706b3f98274 100644
--- a/src/devices/machine/74165.cpp
+++ b/src/devices/machine/74165.cpp
@@ -39,7 +39,7 @@ void ttl165_device::device_add_mconfig(machine_config &config)
ttl165_device::ttl165_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, TTL165, tag, owner, clock),
m_timer(*this, "timer"),
- m_data_cb(*this), m_qh_cb(*this),
+ m_data_cb(*this, 0x00), m_qh_cb(*this),
m_data(0x00),
m_ser(0), m_clk(0), m_shld(0)
{
@@ -51,10 +51,6 @@ ttl165_device::ttl165_device(const machine_config &mconfig, const char *tag, dev
void ttl165_device::device_start()
{
- // resolve callbacks
- m_data_cb.resolve_safe(0x00);
- m_qh_cb.resolve_safe();
-
// register for save states
save_item(NAME(m_data));
save_item(NAME(m_ser));
@@ -89,7 +85,7 @@ TIMER_DEVICE_CALLBACK_MEMBER( ttl165_device::qh_output )
// INTERFACE
//**************************************************************************
-WRITE_LINE_MEMBER( ttl165_device::serial_w )
+void ttl165_device::serial_w(int state)
{
m_ser = state;
}
@@ -100,7 +96,7 @@ void ttl165_device::update_qh()
m_timer->adjust(attotime::from_nsec(25), BIT(m_data, 7));
}
-WRITE_LINE_MEMBER( ttl165_device::clock_w )
+void ttl165_device::clock_w(int state)
{
if (m_shld && !m_clk && state)
{
@@ -114,7 +110,7 @@ WRITE_LINE_MEMBER( ttl165_device::clock_w )
m_clk = state;
}
-WRITE_LINE_MEMBER( ttl165_device::shift_load_w )
+void ttl165_device::shift_load_w(int state)
{
if (!m_shld || !state)
{
diff --git a/src/devices/machine/74165.h b/src/devices/machine/74165.h
index 145f3195172..b20de384c16 100644
--- a/src/devices/machine/74165.h
+++ b/src/devices/machine/74165.h
@@ -39,9 +39,9 @@ public:
auto data_callback() { return m_data_cb.bind(); }
auto qh_callback() { return m_qh_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER(serial_w);
- DECLARE_WRITE_LINE_MEMBER(clock_w);
- DECLARE_WRITE_LINE_MEMBER(shift_load_w);
+ void serial_w(int state);
+ void clock_w(int state);
+ void shift_load_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/74166.cpp b/src/devices/machine/74166.cpp
index 1611b526762..3a2139e6843 100644
--- a/src/devices/machine/74166.cpp
+++ b/src/devices/machine/74166.cpp
@@ -39,7 +39,7 @@ void ttl166_device::device_add_mconfig(machine_config &config)
ttl166_device::ttl166_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, TTL166, tag, owner, clock),
m_timer(*this, "timer"),
- m_data_cb(*this), m_qh_cb(*this),
+ m_data_cb(*this, 0x00), m_qh_cb(*this),
m_data(0x00),
m_ser(0), m_clk(0), m_shld(0)
{
@@ -51,10 +51,6 @@ ttl166_device::ttl166_device(const machine_config &mconfig, const char *tag, dev
void ttl166_device::device_start()
{
- // resolve callbacks
- m_data_cb.resolve_safe(0x00);
- m_qh_cb.resolve_safe();
-
// register for save states
save_item(NAME(m_data));
save_item(NAME(m_ser));
@@ -89,12 +85,12 @@ TIMER_DEVICE_CALLBACK_MEMBER( ttl166_device::qh_output )
// INTERFACE
//**************************************************************************
-WRITE_LINE_MEMBER( ttl166_device::serial_w )
+void ttl166_device::serial_w(int state)
{
m_ser = state;
}
-WRITE_LINE_MEMBER( ttl166_device::clock_w )
+void ttl166_device::clock_w(int state)
{
if (m_clk == 0 && state == 1)
{
@@ -117,7 +113,7 @@ WRITE_LINE_MEMBER( ttl166_device::clock_w )
m_clk = state;
}
-WRITE_LINE_MEMBER( ttl166_device::shift_load_w )
+void ttl166_device::shift_load_w(int state)
{
m_shld = state;
}
diff --git a/src/devices/machine/74166.h b/src/devices/machine/74166.h
index e15149a50cd..2547fdd5bff 100644
--- a/src/devices/machine/74166.h
+++ b/src/devices/machine/74166.h
@@ -39,9 +39,9 @@ public:
auto data_callback() { return m_data_cb.bind(); }
auto qh_callback() { return m_qh_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER(serial_w);
- DECLARE_WRITE_LINE_MEMBER(clock_w);
- DECLARE_WRITE_LINE_MEMBER(shift_load_w);
+ void serial_w(int state);
+ void clock_w(int state);
+ void shift_load_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/74175.cpp b/src/devices/machine/74175.cpp
index 28d3152dbeb..d3263c9cff3 100644
--- a/src/devices/machine/74175.cpp
+++ b/src/devices/machine/74175.cpp
@@ -61,11 +61,6 @@ void ttl741745_device::device_start()
save_item(NAME(m_q2));
save_item(NAME(m_q3));
save_item(NAME(m_q4));
-
- m_q1_func.resolve_safe();
- m_q2_func.resolve_safe();
- m_q3_func.resolve_safe();
- m_q4_func.resolve_safe();
}
void ttl741745_device::device_reset()
@@ -81,9 +76,6 @@ void ttl74174_device::device_start()
save_item(NAME(m_d6));
save_item(NAME(m_q5));
save_item(NAME(m_q6));
-
- m_q5_func.resolve_safe();
- m_q6_func.resolve_safe();
}
void ttl74175_device::device_start()
@@ -92,11 +84,6 @@ void ttl74175_device::device_start()
save_item(NAME(m_not_q2));
save_item(NAME(m_not_q3));
save_item(NAME(m_not_q4));
-
- m_not_q1_func.resolve_safe();
- m_not_q2_func.resolve_safe();
- m_not_q3_func.resolve_safe();
- m_not_q4_func.resolve_safe();
}
void ttl741745_device::init()
@@ -149,12 +136,12 @@ void ttl741745_device::tick()
m_q4_func(m_q4);
}
-WRITE_LINE_MEMBER( ttl741745_device::clear_w )
+void ttl741745_device::clear_w(int state)
{
m_clear = state;
}
-WRITE_LINE_MEMBER( ttl741745_device::clock_w )
+void ttl741745_device::clock_w(int state)
{
uint8_t last_clock = m_clock;
m_clock = state;
@@ -164,32 +151,32 @@ WRITE_LINE_MEMBER( ttl741745_device::clock_w )
}
}
-WRITE_LINE_MEMBER( ttl741745_device::d1_w )
+void ttl741745_device::d1_w(int state)
{
m_d1 = state;
}
-WRITE_LINE_MEMBER( ttl741745_device::d2_w )
+void ttl741745_device::d2_w(int state)
{
m_d2 = state;
}
-WRITE_LINE_MEMBER( ttl741745_device::d3_w )
+void ttl741745_device::d3_w(int state)
{
m_d3 = state;
}
-WRITE_LINE_MEMBER( ttl741745_device::d4_w )
+void ttl741745_device::d4_w(int state)
{
m_d4 = state;
}
-WRITE_LINE_MEMBER( ttl74174_device::d5_w )
+void ttl74174_device::d5_w(int state)
{
m_d5 = state;
}
-WRITE_LINE_MEMBER( ttl74174_device::d6_w )
+void ttl74174_device::d6_w(int state)
{
m_d6 = state;
}
diff --git a/src/devices/machine/74175.h b/src/devices/machine/74175.h
index 2eb716d481c..531afa4f743 100644
--- a/src/devices/machine/74175.h
+++ b/src/devices/machine/74175.h
@@ -56,12 +56,12 @@ public:
auto q3_callback() { return m_q3_func.bind(); }
auto q4_callback() { return m_q4_func.bind(); }
- DECLARE_WRITE_LINE_MEMBER( clear_w );
- DECLARE_WRITE_LINE_MEMBER( d1_w );
- DECLARE_WRITE_LINE_MEMBER( d2_w );
- DECLARE_WRITE_LINE_MEMBER( d3_w );
- DECLARE_WRITE_LINE_MEMBER( d4_w );
- DECLARE_WRITE_LINE_MEMBER( clock_w );
+ void clear_w(int state);
+ void d1_w(int state);
+ void d2_w(int state);
+ void d3_w(int state);
+ void d4_w(int state);
+ void clock_w(int state);
uint8_t q_w();
@@ -101,8 +101,8 @@ public:
auto q5_cb() { return m_q5_func.bind(); }
auto q6_cb() { return m_q6_func.bind(); }
- DECLARE_WRITE_LINE_MEMBER( d5_w );
- DECLARE_WRITE_LINE_MEMBER( d6_w );
+ void d5_w(int state);
+ void d6_w(int state);
protected:
virtual void device_start() override;
diff --git a/src/devices/machine/74181.cpp b/src/devices/machine/74181.cpp
index 66901510b32..a3fef1451a0 100644
--- a/src/devices/machine/74181.cpp
+++ b/src/devices/machine/74181.cpp
@@ -132,7 +132,7 @@ void ttl74181_device::select_w(uint8_t data)
}
}
-WRITE_LINE_MEMBER( ttl74181_device::mode_w )
+void ttl74181_device::mode_w(int state)
{
if (m_m != state)
{
@@ -141,7 +141,7 @@ WRITE_LINE_MEMBER( ttl74181_device::mode_w )
}
}
-WRITE_LINE_MEMBER( ttl74181_device::carry_w )
+void ttl74181_device::carry_w(int state)
{
if (m_c != state)
{
diff --git a/src/devices/machine/74181.h b/src/devices/machine/74181.h
index 40a55abc042..018eb3efaa0 100644
--- a/src/devices/machine/74181.h
+++ b/src/devices/machine/74181.h
@@ -30,15 +30,15 @@ public:
void input_a_w(uint8_t data);
void input_b_w(uint8_t data);
void select_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( mode_w );
- DECLARE_WRITE_LINE_MEMBER( carry_w );
+ void mode_w(int state);
+ void carry_w(int state);
// outputs
uint8_t function_r() { return m_f; }
- DECLARE_READ_LINE_MEMBER( carry_r ) { return m_cn; }
- DECLARE_READ_LINE_MEMBER( generate_r ) { return m_g; }
- DECLARE_READ_LINE_MEMBER( propagate_r ) { return m_p; }
- DECLARE_READ_LINE_MEMBER( equals_r ) { return m_equals; }
+ int carry_r() { return m_cn; }
+ int generate_r() { return m_g; }
+ int propagate_r() { return m_p; }
+ int equals_r() { return m_equals; }
protected:
// device-level overrides
diff --git a/src/devices/machine/74259.cpp b/src/devices/machine/74259.cpp
index 806ea280eb1..4ebecc5ab7e 100644
--- a/src/devices/machine/74259.cpp
+++ b/src/devices/machine/74259.cpp
@@ -116,10 +116,6 @@ addressable_latch_device::addressable_latch_device(const machine_config &mconfig
void addressable_latch_device::device_start()
{
- // resolve callbacks
- m_q_out_cb.resolve_all();
- m_parallel_out_cb.resolve();
-
// initial input state
m_address = 0;
m_data = false;
@@ -181,7 +177,7 @@ void addressable_latch_device::write_abcd(u8 a, bool d)
// enable_w - handle enable input (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(addressable_latch_device::enable_w)
+void addressable_latch_device::enable_w(int state)
{
m_enable = !state;
if (m_enable)
@@ -214,15 +210,13 @@ void addressable_latch_device::update_bit()
}
// update output line via callback
- if (!m_q_out_cb[m_address].isnull())
- m_q_out_cb[m_address](m_data);
+ m_q_out_cb[m_address](m_data);
// update parallel output
- if (!m_parallel_out_cb.isnull())
- m_parallel_out_cb(0, m_q, 1 << m_address);
+ m_parallel_out_cb(0, m_q, 1 << m_address);
// do some logging
- if (LOG_ALL_WRITES || (LOG_UNDEFINED_WRITES && m_q_out_cb[m_address].isnull() && m_parallel_out_cb.isnull()))
+ if (LOG_ALL_WRITES || (LOG_UNDEFINED_WRITES && m_q_out_cb[m_address].isunset() && m_parallel_out_cb.isunset()))
logerror("Q%d %s at %s\n", m_address, m_data ? "set" : "cleared", machine().describe_context());
}
@@ -346,7 +340,7 @@ void addressable_latch_device::clear(u8 data)
// clear_w - handle clear/reset input
//-------------------------------------------------
-WRITE_LINE_MEMBER(addressable_latch_device::clear_w)
+void addressable_latch_device::clear_w(int state)
{
m_clear = bool(state) == m_clear_active;
if (m_clear)
@@ -367,12 +361,11 @@ void addressable_latch_device::clear_outputs(u8 new_q)
// return any previously set output lines to clear state
for (int bit = 0; bit < 8; bit++)
- if (BIT(bits_changed, bit) && !m_q_out_cb[bit].isnull())
+ if (BIT(bits_changed, bit))
m_q_out_cb[bit](BIT(new_q, bit));
// update parallel output
- if (!m_parallel_out_cb.isnull())
- m_parallel_out_cb(0, new_q, bits_changed);
+ m_parallel_out_cb(0, new_q, bits_changed);
}
//**************************************************************************
diff --git a/src/devices/machine/74259.h b/src/devices/machine/74259.h
index a2192701cba..4f758b753df 100644
--- a/src/devices/machine/74259.h
+++ b/src/devices/machine/74259.h
@@ -58,19 +58,19 @@ public:
void clear(u8 data = 0);
// read handlers (inlined for the sake of optimization)
- DECLARE_READ_LINE_MEMBER(q0_r) { return BIT(m_q, 0); }
- DECLARE_READ_LINE_MEMBER(q1_r) { return BIT(m_q, 1); }
- DECLARE_READ_LINE_MEMBER(q2_r) { return BIT(m_q, 2); }
- DECLARE_READ_LINE_MEMBER(q3_r) { return BIT(m_q, 3); }
- DECLARE_READ_LINE_MEMBER(q4_r) { return BIT(m_q, 4); }
- DECLARE_READ_LINE_MEMBER(q5_r) { return BIT(m_q, 5); }
- DECLARE_READ_LINE_MEMBER(q6_r) { return BIT(m_q, 6); }
- DECLARE_READ_LINE_MEMBER(q7_r) { return BIT(m_q, 7); }
+ int q0_r() { return BIT(m_q, 0); }
+ int q1_r() { return BIT(m_q, 1); }
+ int q2_r() { return BIT(m_q, 2); }
+ int q3_r() { return BIT(m_q, 3); }
+ int q4_r() { return BIT(m_q, 4); }
+ int q5_r() { return BIT(m_q, 5); }
+ int q6_r() { return BIT(m_q, 6); }
+ int q7_r() { return BIT(m_q, 7); }
u8 output_state() const { return m_q; }
// control inputs
- DECLARE_WRITE_LINE_MEMBER(enable_w);
- DECLARE_WRITE_LINE_MEMBER(clear_w);
+ void enable_w(int state);
+ void clear_w(int state);
protected:
// construction/destruction
diff --git a/src/devices/machine/74381.cpp b/src/devices/machine/74381.cpp
index 65514a414e3..1ce19a17121 100644
--- a/src/devices/machine/74381.cpp
+++ b/src/devices/machine/74381.cpp
@@ -42,10 +42,6 @@ void sn74s381_device::device_start()
save_item(NAME(m_f));
save_item(NAME(m_p));
save_item(NAME(m_g));
-
- m_f_out.resolve_safe();
- m_p_out.resolve_safe();
- m_g_out.resolve_safe();
}
void sn74s381_device::device_reset()
diff --git a/src/devices/machine/74543.cpp b/src/devices/machine/74543.cpp
index 2abba597941..632deaf26a9 100644
--- a/src/devices/machine/74543.cpp
+++ b/src/devices/machine/74543.cpp
@@ -35,9 +35,6 @@ void ttl74543_device::device_start()
save_item(NAME(m_oeba));
save_item(NAME(m_latch));
-
- m_output_a.resolve_safe();
- m_output_b.resolve_safe();
}
void ttl74543_device::device_reset()
@@ -85,35 +82,35 @@ void ttl74543_device::outputa_rz(uint8_t& value)
if (m_ceba && m_oeba) value = m_latch;
}
-WRITE_LINE_MEMBER( ttl74543_device::ceab_w )
+void ttl74543_device::ceab_w(int state)
{
m_ceab = (state == 0);
if (m_ceab && m_oeab) m_output_b(m_latch);
}
-WRITE_LINE_MEMBER( ttl74543_device::leab_w )
+void ttl74543_device::leab_w(int state)
{
m_leab = (state == 0);
}
-WRITE_LINE_MEMBER( ttl74543_device::oeab_w )
+void ttl74543_device::oeab_w(int state)
{
m_oeab = (state == 0);
if (m_ceab && m_oeab) m_output_b(m_latch);
}
-WRITE_LINE_MEMBER( ttl74543_device::ceba_w )
+void ttl74543_device::ceba_w(int state)
{
m_ceba = (state == 0);
if (m_ceba && m_oeba) m_output_a(m_latch);
}
-WRITE_LINE_MEMBER( ttl74543_device::leba_w )
+void ttl74543_device::leba_w(int state)
{
m_leba = (state == 0);
}
-WRITE_LINE_MEMBER( ttl74543_device::oeba_w )
+void ttl74543_device::oeba_w(int state)
{
m_oeba = (state == 0);
if (m_ceba && m_oeba) m_output_a(m_latch);
diff --git a/src/devices/machine/74543.h b/src/devices/machine/74543.h
index ab2c7a561d2..4c333f5fd90 100644
--- a/src/devices/machine/74543.h
+++ b/src/devices/machine/74543.h
@@ -71,12 +71,12 @@ public:
auto outputb_cb() { return m_output_b.bind(); }
// public interfaces
- DECLARE_WRITE_LINE_MEMBER(ceab_w);
- DECLARE_WRITE_LINE_MEMBER(leab_w);
- DECLARE_WRITE_LINE_MEMBER(oeab_w);
- DECLARE_WRITE_LINE_MEMBER(ceba_w);
- DECLARE_WRITE_LINE_MEMBER(leba_w);
- DECLARE_WRITE_LINE_MEMBER(oeba_w);
+ void ceab_w(int state);
+ void leab_w(int state);
+ void oeab_w(int state);
+ void ceba_w(int state);
+ void leba_w(int state);
+ void oeba_w(int state);
void a_w(uint8_t a);
void b_w(uint8_t a);
diff --git a/src/devices/machine/7474.cpp b/src/devices/machine/7474.cpp
index ae2a90e8f61..45e21406edc 100644
--- a/src/devices/machine/7474.cpp
+++ b/src/devices/machine/7474.cpp
@@ -55,14 +55,15 @@ DEFINE_DEVICE_TYPE(TTL7474, ttl7474_device, "7474", "7474 TTL")
// ttl7474_device - constructor
//-------------------------------------------------
-ttl7474_device::ttl7474_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, TTL7474, tag, owner, clock),
- m_output_func(*this),
- m_comp_output_func(*this)
+ttl7474_device::ttl7474_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, TTL7474, tag, owner, clock),
+ m_output_func(*this),
+ m_comp_output_func(*this)
{
init();
}
+
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -78,9 +79,6 @@ void ttl7474_device::device_start()
save_item(NAME(m_last_clock));
save_item(NAME(m_last_output));
save_item(NAME(m_last_output_comp));
-
- m_output_func.resolve_safe();
- m_comp_output_func.resolve_safe();
}
@@ -90,6 +88,7 @@ void ttl7474_device::device_start()
void ttl7474_device::device_reset()
{
+ // FIXME: remove this - many flipflops aren't connected to system reset
init();
}
@@ -128,13 +127,13 @@ void ttl7474_device::update()
if (m_output != m_last_output)
{
m_last_output = m_output;
- m_output_func(m_output!=0);
+ m_output_func(m_output != 0);
}
// call callback if any of the outputs changed
if (m_output_comp != m_last_output_comp)
{
m_last_output_comp = m_output_comp;
- m_comp_output_func(m_output_comp!=0);
+ m_comp_output_func(m_output_comp != 0);
}
}
@@ -143,7 +142,7 @@ void ttl7474_device::update()
// clear_w - set the clear line state
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl7474_device::clear_w )
+void ttl7474_device::clear_w(int state)
{
m_clear = state & 1;
update();
@@ -154,7 +153,7 @@ WRITE_LINE_MEMBER( ttl7474_device::clear_w )
// clear_w - set the clear line state
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl7474_device::preset_w )
+void ttl7474_device::preset_w(int state)
{
m_preset = state & 1;
update();
@@ -165,7 +164,7 @@ WRITE_LINE_MEMBER( ttl7474_device::preset_w )
// clock_w - set the clock line state
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl7474_device::clock_w )
+void ttl7474_device::clock_w(int state)
{
m_clk = state & 1;
update();
@@ -176,7 +175,7 @@ WRITE_LINE_MEMBER( ttl7474_device::clock_w )
// d_w - set the d line state
//-------------------------------------------------
-WRITE_LINE_MEMBER( ttl7474_device::d_w )
+void ttl7474_device::d_w(int state)
{
m_d = state & 1;
update();
@@ -187,7 +186,7 @@ WRITE_LINE_MEMBER( ttl7474_device::d_w )
// output_r - get the output line state
//-------------------------------------------------
-READ_LINE_MEMBER( ttl7474_device::output_r )
+int ttl7474_device::output_r()
{
return m_output!=0;
}
@@ -197,7 +196,7 @@ READ_LINE_MEMBER( ttl7474_device::output_r )
// output_comp_r - get the output-compare line state
//-----------------------------------------------------
-READ_LINE_MEMBER( ttl7474_device::output_comp_r )
+int ttl7474_device::output_comp_r()
{
return m_output_comp!=0;
}
@@ -210,6 +209,7 @@ void ttl7474_device::init()
m_d = 1;
m_output = -1;
+ m_output_comp = -1;
m_last_clock = 1;
m_last_output = -1;
m_last_output_comp = -1;
diff --git a/src/devices/machine/7474.h b/src/devices/machine/7474.h
index 0f9d87fa5bf..3bf2f1ee2e7 100644
--- a/src/devices/machine/7474.h
+++ b/src/devices/machine/7474.h
@@ -62,19 +62,17 @@ public:
auto comp_output_cb() { return m_comp_output_func.bind(); }
// public interfaces
- DECLARE_WRITE_LINE_MEMBER( clear_w );
- DECLARE_WRITE_LINE_MEMBER( preset_w );
- DECLARE_WRITE_LINE_MEMBER( clock_w );
- DECLARE_WRITE_LINE_MEMBER( d_w );
- DECLARE_READ_LINE_MEMBER( output_r );
- DECLARE_READ_LINE_MEMBER( output_comp_r ); // NOT strictly the same as !output_r()
+ void clear_w(int state);
+ void preset_w(int state);
+ void clock_w(int state);
+ void d_w(int state);
+ int output_r();
+ int output_comp_r(); // NOT strictly the same as !output_r()
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_post_load() override { }
- virtual void device_clock_changed() override { }
private:
// callbacks
diff --git a/src/devices/machine/8042kbdc.cpp b/src/devices/machine/8042kbdc.cpp
index 1e904888344..8f6918767e5 100644
--- a/src/devices/machine/8042kbdc.cpp
+++ b/src/devices/machine/8042kbdc.cpp
@@ -10,7 +10,7 @@
#include "emu.h"
-#include "machine/8042kbdc.h"
+#include "8042kbdc.h"
/***************************************************************************
@@ -22,8 +22,10 @@
#define PS2_MOUSE_ON 1
#define KEYBOARD_ON 1
-#define LOG_KEYBOARD 0
-#define LOG_ACCESSES 0
+#define LOG_KEYBOARD (1U << 1)
+#define LOG_ACCESSES (1U << 2)
+#define VERBOSE (0)
+#include "logmacro.h"
DEFINE_DEVICE_TYPE(KBDC8042, kbdc8042_device, "kbdc8042", "8042 Keyboard/Mouse Controller")
@@ -33,22 +35,19 @@ DEFINE_DEVICE_TYPE(KBDC8042, kbdc8042_device, "kbdc8042", "8042 Keyboard/Mouse C
kbdc8042_device::kbdc8042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, KBDC8042, tag, owner, clock)
- , m_keyboard_dev(*this, "at_keyboard")
+ , m_keyboard_dev(*this, finder_base::DUMMY_TAG)
, m_mousex_port(*this, "MOUSEX")
, m_mousey_port(*this, "MOUSEY")
, m_mousebtn_port(*this, "MOUSEBTN")
, m_system_reset_cb(*this)
, m_gate_a20_cb(*this)
, m_input_buffer_full_cb(*this)
+ , m_input_buffer_full_mouse_cb(*this)
, m_output_buffer_empty_cb(*this)
, m_speaker_cb(*this)
{
-}
-
-void kbdc8042_device::device_add_mconfig(machine_config &config)
-{
- AT_KEYB(config, m_keyboard_dev, pc_keyboard_device::KEYBOARD_TYPE::AT, 1);
- m_keyboard_dev->keypress().set(FUNC(kbdc8042_device::keyboard_w));
+ m_keybtype = KBDC8042_STANDARD;
+ m_interrupttype = KBDC8042_SINGLE;
}
@@ -58,24 +57,17 @@ void kbdc8042_device::device_add_mconfig(machine_config &config)
void kbdc8042_device::device_start()
{
- // resolve callbacks
- m_system_reset_cb.resolve_safe();
- m_gate_a20_cb.resolve_safe();
- m_input_buffer_full_cb.resolve_safe();
- m_output_buffer_empty_cb.resolve_safe();
- m_speaker_cb.resolve_safe();
- m_operation_write_state = 0; /* first write to 0x60 might occur before anything can set this */
memset(&m_keyboard, 0x00, sizeof(m_keyboard));
memset(&m_mouse, 0x00, sizeof(m_mouse));
m_mouse.sample_rate = 100;
+ m_mouse.resolution = 3;
+ m_mouse.on = true;
m_sending = 0;
m_last_write_to_control = 0;
- m_status_read_mode = 0;
m_speaker = 0;
m_offset1 = 0;
- m_update_timer = timer_alloc(TIMER_UPDATE);
- m_update_timer->adjust(attotime::never);
+ m_update_timer = timer_alloc(FUNC(kbdc8042_device::update_timer), this);
}
/*-------------------------------------------------
@@ -84,6 +76,10 @@ void kbdc8042_device::device_start()
void kbdc8042_device::device_reset()
{
+ m_operation_write_state = -1;
+ m_status_read_mode = 2;
+ m_keyboard.on = false;
+
m_poll_delay = 10;
/* ibmat bios wants 0x20 set! (keyboard locked when not set) 0x80 */
@@ -94,7 +90,7 @@ void kbdc8042_device::device_reset()
m_mouse_y = 0;
m_mouse_btn = 0;
- m_update_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
+ m_update_timer->adjust(attotime::never);
}
void kbdc8042_device::at_8042_set_outport(uint8_t data, int initial)
@@ -102,13 +98,10 @@ void kbdc8042_device::at_8042_set_outport(uint8_t data, int initial)
uint8_t change = initial ? 0xFF : (m_outport ^ data);
m_outport = data;
if (change & 0x02)
- {
- if (!m_gate_a20_cb.isnull())
- m_gate_a20_cb(data & 0x02 ? 1 : 0);
- }
+ m_gate_a20_cb(data & 0x02 ? 1 : 0);
}
-WRITE_LINE_MEMBER( kbdc8042_device::keyboard_w )
+void kbdc8042_device::keyboard_w(int state)
{
if(state)
at_8042_check_keyboard();
@@ -116,8 +109,7 @@ WRITE_LINE_MEMBER( kbdc8042_device::keyboard_w )
void kbdc8042_device::at_8042_receive(uint8_t data, bool mouse)
{
- if (LOG_KEYBOARD)
- logerror("at_8042_receive Received 0x%02x\n", data);
+ LOGMASKED(LOG_KEYBOARD, "at_8042_receive Received 0x%02x\n", data);
m_data = data;
if(!(m_speaker & 0x80) || mouse)
@@ -127,14 +119,27 @@ void kbdc8042_device::at_8042_receive(uint8_t data, bool mouse)
else
m_keyboard.received = 1;
- if (!m_input_buffer_full_cb.isnull())
+ if (m_interrupttype == KBDC8042_SINGLE)
+ {
m_input_buffer_full_cb(1);
+ }
+ else
+ {
+ if (m_keyboard.received && (m_command & 1))
+ {
+ m_input_buffer_full_cb(1);
+ }
+ if (m_mouse.received && (m_command & 2))
+ {
+ m_input_buffer_full_mouse_cb(1);
+ }
+ }
}
}
void kbdc8042_device::at_8042_check_keyboard()
{
- if (!m_keyboard.received && !m_mouse.received)
+ if (!m_keyboard.received && !m_mouse.received && m_keyboard_dev.found())
{
int data = m_keyboard_dev->read();
if (data)
@@ -146,7 +151,7 @@ void kbdc8042_device::at_8042_check_mouse()
{
if ((m_keybtype == KBDC8042_PS2) && PS2_MOUSE_ON && !m_keyboard.received && !m_mouse.received)
{
- if (m_mouse.to_transmit == 0)
+ if (m_mouse.reporting && (m_mouse.to_transmit == 0))
{
uint16_t x = m_mousex_port->read();
uint16_t y = m_mousey_port->read();
@@ -173,6 +178,7 @@ void kbdc8042_device::at_8042_check_mouse()
if (dx != 0 || dy != 0 || buttons != old_mouse_btn)
{
m_mouse.to_transmit = 3;
+ m_mouse.from_transmit = 0;
m_mouse.transmit_buf[0] = buttons | 0x08 | (BIT(dx, 8) << 4) | (BIT(dy, 8) << 5);
m_mouse.transmit_buf[1] = dx & 0xff;
m_mouse.transmit_buf[2] = dy & 0xff;
@@ -181,12 +187,9 @@ void kbdc8042_device::at_8042_check_mouse()
if (m_mouse.to_transmit)
{
- at_8042_receive(m_mouse.transmit_buf[0], true);
+ at_8042_receive(m_mouse.transmit_buf[m_mouse.from_transmit], true);
m_mouse.to_transmit--;
- for (int i = 0; i < m_mouse.to_transmit; i++)
- {
- m_mouse.transmit_buf[i] = m_mouse.transmit_buf[i + 1];
- }
+ m_mouse.from_transmit = (m_mouse.from_transmit + 1) & (sizeof(m_mouse.transmit_buf) - 1);
}
}
}
@@ -195,22 +198,29 @@ void kbdc8042_device::at_8042_clear_keyboard_received()
{
if (m_keyboard.received)
{
- if (LOG_KEYBOARD)
- logerror("kbdc8042_8_r(): Clearing m_keyboard.received\n");
+ LOGMASKED(LOG_KEYBOARD, "kbdc8042_8_r(): Clearing m_keyboard.received\n");
}
m_input_buffer_full_cb(0);
+ m_input_buffer_full_mouse_cb(0);
m_keyboard.received = 0;
m_mouse.received = 0;
+ m_data = 0;
+}
+
+TIMER_CALLBACK_MEMBER(kbdc8042_device::update_timer)
+{
+ at_8042_check_keyboard();
+ if (m_mouse.on)
+ at_8042_check_mouse();
}
-void kbdc8042_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void kbdc8042_device::mouse_enqueue(uint8_t value)
{
- if (id == TIMER_UPDATE)
+ if (m_mouse.to_transmit < 8)
{
- at_8042_check_keyboard();
- if (m_mouse.on)
- at_8042_check_mouse();
+ m_mouse.transmit_buf[(m_mouse.from_transmit + m_mouse.to_transmit) & (sizeof(m_mouse.transmit_buf) - 1)] = value;
+ m_mouse.to_transmit++;
}
}
@@ -246,6 +256,8 @@ uint8_t kbdc8042_device::data_r(offs_t offset)
data = m_data;
at_8042_clear_keyboard_received();
at_8042_check_keyboard();
+ if (m_mouse.on)
+ at_8042_check_mouse();
break;
case 1:
@@ -307,8 +319,7 @@ uint8_t kbdc8042_device::data_r(offs_t offset)
break;
}
- if (LOG_ACCESSES)
- logerror("kbdc8042_8_r(): offset=%d data=0x%02x\n", offset, (unsigned) data);
+ LOGMASKED(LOG_ACCESSES, "kbdc8042_8_r(): offset=%d data=0x%02x\n", offset, (unsigned) data);
return data;
}
@@ -321,10 +332,14 @@ void kbdc8042_device::data_w(offs_t offset, uint8_t data)
m_last_write_to_control = 0;
m_status_read_mode = 0;
switch (m_operation_write_state) {
+ case -1:
+ break;
+
case 0:
m_data = data;
m_sending = 1;
- m_keyboard_dev->write(data);
+ if (m_keyboard_dev.found())
+ m_keyboard_dev->write(data);
break;
case 1:
@@ -356,9 +371,16 @@ void kbdc8042_device::data_w(offs_t offset, uint8_t data)
m_data = data;
if (m_mouse.receiving_sample_rate)
{
- m_mouse.received = 1;
m_mouse.sample_rate = data;
- m_data = 0xfa;
+ m_mouse.receiving_sample_rate = false;
+ mouse_enqueue(0xfa);
+ break;
+ }
+ if (m_mouse.receiving_resolution)
+ {
+ m_mouse.resolution = data;
+ m_mouse.receiving_resolution = false;
+ mouse_enqueue(0xfa);
break;
}
@@ -367,17 +389,52 @@ void kbdc8042_device::data_w(offs_t offset, uint8_t data)
case 0xff:
logerror("Mouse reset command received\n");
m_mouse.sample_rate = 100;
- m_mouse.received = 1;
- m_data = 0xfa;
+ m_mouse.from_transmit = 0;
+ m_mouse.to_transmit = 0;
+ m_mouse.reporting = false;
+ if (m_mouse.on)
+ {
+ mouse_enqueue(0xfa);
+ mouse_enqueue(0xaa);
+ mouse_enqueue(0x00);
+ }
+ else
+ {
+ m_mouse.received = 1;
+ m_data = 0xfa;
+ }
break;
case 0xf6:
- m_mouse.received = 1;
- m_data = 0xfa;
+ mouse_enqueue(0xfa);
+ break;
+ case 0xf5:
+ m_mouse.reporting = false;
+ mouse_enqueue(0xfa);
+ break;
+ case 0xf4:
+ m_mouse.reporting = true;
+ mouse_enqueue(0xfa);
break;
case 0xf3:
- m_mouse.received = 1;
- m_data = 0xfa;
m_mouse.receiving_sample_rate = true;
+ mouse_enqueue(0xfa);
+ break;
+ case 0xf2:
+ mouse_enqueue(0xfa);
+ mouse_enqueue(0x00);
+ break;
+ case 0xe8:
+ mouse_enqueue(0xfa);
+ m_mouse.receiving_resolution = true;
+ break;
+ case 0xe6:
+ mouse_enqueue(0xfa);
+ break;
+ case 0xe9:
+ mouse_enqueue(0xfa);
+ mouse_enqueue(0x00);
+ mouse_enqueue(m_mouse.resolution);
+ mouse_enqueue(m_mouse.sample_rate);
break;
default:
logerror("%s: Unknown mouse command: %02x\n", machine().describe_context(), m_data);
@@ -401,13 +458,24 @@ void kbdc8042_device::data_w(offs_t offset, uint8_t data)
at_8042_clear_keyboard_received();
}
m_speaker &= ~0x80;
- if (!m_speaker_cb.isnull())
- m_speaker_cb((offs_t)0, m_speaker);
+ m_speaker_cb(offs_t(0), m_speaker);
break;
case 4:
- m_last_write_to_control=1;
+ m_last_write_to_control = 1;
+
+ if (m_operation_write_state == -1)
+ {
+ m_status_read_mode = 0;
+ if (data != 0xaa && data != 0xd1)
+ break;
+ else
+ {
+ m_operation_write_state = 0;
+ m_update_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
+ }
+ }
/* switch based on the command */
switch(data) {
@@ -416,13 +484,12 @@ void kbdc8042_device::data_w(offs_t offset, uint8_t data)
break;
case 0x60: /* next data byte is placed in 8042 command byte */
m_operation_write_state = 5;
- m_send_to_mouse = 0;
break;
case 0xa7: /* disable auxilary interface */
- m_mouse.on = 0;
+ m_mouse.on = false;
break;
case 0xa8: /* enable auxilary interface */
- m_mouse.on = 1;
+ m_mouse.on = true;
break;
case 0xa9: /* test mouse */
at_8042_receive(((m_keybtype == KBDC8042_PS2) && PS2_MOUSE_ON) ? 0x00 : 0xff);
@@ -473,21 +540,18 @@ void kbdc8042_device::data_w(offs_t offset, uint8_t data)
* write is written to port 60h output register as if initiated
* by a device; invokes interrupt if enabled */
m_operation_write_state = 2;
- m_send_to_mouse = 0;
break;
case 0xd3:
/* write auxillary output register; on PS/2 systems next port 60h
* write is written to port 60h input register as if initiated
* by a device; invokes interrupt if enabled */
m_operation_write_state = 3;
- m_send_to_mouse = 1;
break;
case 0xd4:
/* write auxillary device; on PS/2 systems the next data byte
* written to input register a port at 60h is sent to the
* auxiliary device */
m_operation_write_state = 4;
- m_send_to_mouse = 1;
break;
case 0xe0:
/* read test inputs; read T1/T0 test inputs into bit 1/0 */
@@ -514,13 +578,18 @@ void kbdc8042_device::data_w(offs_t offset, uint8_t data)
m_system_reset_cb(CLEAR_LINE);
at_8042_set_outport(m_outport | 0x02, 0);
break;
+ default:
+ if (data != 0xff)
+ {
+ logerror("%s: Unknown command: %02x\n", machine().describe_context(), data);
+ }
}
m_sending = 1;
break;
}
}
-WRITE_LINE_MEMBER(kbdc8042_device::write_out2)
+void kbdc8042_device::write_out2(int state)
{
m_out2 = state;
}
diff --git a/src/devices/machine/8042kbdc.h b/src/devices/machine/8042kbdc.h
index e70b2398b29..80e855018a4 100644
--- a/src/devices/machine/8042kbdc.h
+++ b/src/devices/machine/8042kbdc.h
@@ -30,21 +30,35 @@ public:
KBDC8042_STANDARD,
KBDC8042_PS2
};
+ enum kbdc8042_interrupt_type_t
+ {
+ KBDC8042_SINGLE,
+ KBDC8042_DOUBLE
+ };
// construction/destruction
kbdc8042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ template <typename T> void set_keyboard_tag(T &&tag) { m_keyboard_dev.set_tag(std::forward<T>(tag)); }
+
void set_keyboard_type(kbdc8042_type_t keybtype) { m_keybtype = keybtype; }
+ void set_interrupt_type(kbdc8042_interrupt_type_t interrupttype) { m_interrupttype = interrupttype; }
auto system_reset_callback() { return m_system_reset_cb.bind(); }
auto gate_a20_callback() { return m_gate_a20_cb.bind(); }
auto input_buffer_full_callback() { return m_input_buffer_full_cb.bind(); }
+ auto input_buffer_full_mouse_callback() { return m_input_buffer_full_mouse_cb.bind(); }
auto output_buffer_empty_callback() { return m_output_buffer_empty_cb.bind(); }
auto speaker_callback() { return m_speaker_cb.bind(); }
uint8_t data_r(offs_t offset);
void data_w(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( write_out2 );
+ uint8_t port60_r(offs_t offset) { return data_r(0); }
+ void port60_w(offs_t offset, uint8_t data) { data_w(0, data); }
+ uint8_t port64_r(offs_t offset) { return data_r(4); }
+ void port64_w(offs_t offset, uint8_t data) { data_w(4, data); }
+
+ void write_out2(int state);
void at_8042_set_outport(uint8_t data, int initial);
void at_8042_receive(uint8_t data, bool mouse = false);
@@ -52,15 +66,17 @@ public:
void at_8042_check_mouse();
void at_8042_clear_keyboard_received();
+ void keyboard_w(int state);
+
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_add_mconfig(machine_config &config) override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual ioport_constructor device_input_ports() const override;
- static const device_timer_id TIMER_UPDATE = 0;
+ TIMER_CALLBACK_MEMBER(update_timer);
+
+ void mouse_enqueue(uint8_t value);
private:
uint8_t m_inport;
@@ -74,16 +90,19 @@ private:
} m_keyboard;
struct {
int received;
- int on;
+ bool on;
+ bool reporting;
uint8_t sample_rate;
+ uint8_t resolution;
bool receiving_sample_rate;
+ bool receiving_resolution;
uint8_t transmit_buf[8];
- uint8_t to_transmit;
+ int to_transmit;
+ int from_transmit;
} m_mouse;
int m_last_write_to_control;
int m_sending;
- int m_send_to_mouse;
int m_operation_write_state;
int m_status_read_mode;
@@ -96,17 +115,19 @@ private:
int m_poll_delay;
- required_device<at_keyboard_device> m_keyboard_dev;
+ optional_device<at_keyboard_device> m_keyboard_dev;
optional_ioport m_mousex_port;
optional_ioport m_mousey_port;
optional_ioport m_mousebtn_port;
kbdc8042_type_t m_keybtype;
+ kbdc8042_interrupt_type_t m_interrupttype;
devcb_write_line m_system_reset_cb;
devcb_write_line m_gate_a20_cb;
devcb_write_line m_input_buffer_full_cb;
- devcb_write_line m_output_buffer_empty_cb;
+ devcb_write_line m_input_buffer_full_mouse_cb;
+ devcb_write_line m_output_buffer_empty_cb; // currently not used
devcb_write8 m_speaker_cb;
@@ -115,8 +136,6 @@ private:
uint8_t m_mouse_btn;
emu_timer * m_update_timer;
-
- DECLARE_WRITE_LINE_MEMBER( keyboard_w );
};
// device type definition
diff --git a/src/devices/machine/82s129.cpp b/src/devices/machine/82s129.cpp
index ca147f17c2f..39df497009c 100644
--- a/src/devices/machine/82s129.cpp
+++ b/src/devices/machine/82s129.cpp
@@ -50,12 +50,6 @@ void prom82s129_base_device::device_start()
save_item(NAME(m_ce2));
save_item(NAME(m_a));
save_item(NAME(m_out));
-
- m_out_func.resolve_safe();
- m_o1_func.resolve_safe();
- m_o2_func.resolve_safe();
- m_o3_func.resolve_safe();
- m_o4_func.resolve_safe();
}
void prom82s129_base_device::device_reset()
@@ -100,7 +94,7 @@ void prom82s129_base_device::update()
}
}
-WRITE_LINE_MEMBER( prom82s129_base_device::ce1_w )
+void prom82s129_base_device::ce1_w(int state)
{
uint8_t last_ce1 = m_ce1;
m_ce1 = state;
@@ -108,7 +102,7 @@ WRITE_LINE_MEMBER( prom82s129_base_device::ce1_w )
update();
}
-WRITE_LINE_MEMBER( prom82s129_base_device::ce2_w )
+void prom82s129_base_device::ce2_w(int state)
{
uint8_t last_ce2 = m_ce2;
m_ce2 = state;
@@ -133,21 +127,21 @@ void prom82s129_base_device::write_line(uint8_t line, uint8_t state)
update();
}
-WRITE_LINE_MEMBER( prom82s129_base_device::a0_w ) { write_line(0, state); }
-WRITE_LINE_MEMBER( prom82s129_base_device::a1_w ) { write_line(1, state); }
-WRITE_LINE_MEMBER( prom82s129_base_device::a2_w ) { write_line(2, state); }
-WRITE_LINE_MEMBER( prom82s129_base_device::a3_w ) { write_line(3, state); }
-WRITE_LINE_MEMBER( prom82s129_base_device::a4_w ) { write_line(4, state); }
-WRITE_LINE_MEMBER( prom82s129_base_device::a5_w ) { write_line(5, state); }
-WRITE_LINE_MEMBER( prom82s129_base_device::a6_w ) { write_line(6, state); }
-WRITE_LINE_MEMBER( prom82s129_base_device::a7_w ) { write_line(7, state); }
+void prom82s129_base_device::a0_w(int state) { write_line(0, state); }
+void prom82s129_base_device::a1_w(int state) { write_line(1, state); }
+void prom82s129_base_device::a2_w(int state) { write_line(2, state); }
+void prom82s129_base_device::a3_w(int state) { write_line(3, state); }
+void prom82s129_base_device::a4_w(int state) { write_line(4, state); }
+void prom82s129_base_device::a5_w(int state) { write_line(5, state); }
+void prom82s129_base_device::a6_w(int state) { write_line(6, state); }
+void prom82s129_base_device::a7_w(int state) { write_line(7, state); }
uint8_t prom82s129_base_device::output_r()
{
return m_out;
}
-READ_LINE_MEMBER( prom82s129_base_device::o1_r ) { return BIT(m_out, 0); }
-READ_LINE_MEMBER( prom82s129_base_device::o2_r ) { return BIT(m_out, 1); }
-READ_LINE_MEMBER( prom82s129_base_device::o3_r ) { return BIT(m_out, 2); }
-READ_LINE_MEMBER( prom82s129_base_device::o4_r ) { return BIT(m_out, 3); }
+int prom82s129_base_device::o1_r() { return BIT(m_out, 0); }
+int prom82s129_base_device::o2_r() { return BIT(m_out, 1); }
+int prom82s129_base_device::o3_r() { return BIT(m_out, 2); }
+int prom82s129_base_device::o4_r() { return BIT(m_out, 3); }
diff --git a/src/devices/machine/82s129.h b/src/devices/machine/82s129.h
index 96f278c85e9..244c85ce01a 100644
--- a/src/devices/machine/82s129.h
+++ b/src/devices/machine/82s129.h
@@ -55,24 +55,24 @@ public:
auto o3_callback() { return m_o3_func.bind(); }
auto o4_callback() { return m_o4_func.bind(); }
- DECLARE_WRITE_LINE_MEMBER( ce1_w );
- DECLARE_WRITE_LINE_MEMBER( ce2_w );
+ void ce1_w(int state);
+ void ce2_w(int state);
void a_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( a0_w );
- DECLARE_WRITE_LINE_MEMBER( a1_w );
- DECLARE_WRITE_LINE_MEMBER( a2_w );
- DECLARE_WRITE_LINE_MEMBER( a3_w );
- DECLARE_WRITE_LINE_MEMBER( a4_w );
- DECLARE_WRITE_LINE_MEMBER( a5_w );
- DECLARE_WRITE_LINE_MEMBER( a6_w );
- DECLARE_WRITE_LINE_MEMBER( a7_w );
+ void a0_w(int state);
+ void a1_w(int state);
+ void a2_w(int state);
+ void a3_w(int state);
+ void a4_w(int state);
+ void a5_w(int state);
+ void a6_w(int state);
+ void a7_w(int state);
uint8_t output_r();
- DECLARE_READ_LINE_MEMBER( o1_r );
- DECLARE_READ_LINE_MEMBER( o2_r );
- DECLARE_READ_LINE_MEMBER( o3_r );
- DECLARE_READ_LINE_MEMBER( o4_r );
+ int o1_r();
+ int o2_r();
+ int o3_r();
+ int o4_r();
uint8_t get_output() const { return m_out; }
diff --git a/src/devices/machine/8364_paula.cpp b/src/devices/machine/8364_paula.cpp
index 6869ffb3395..a06eed90ca4 100644
--- a/src/devices/machine/8364_paula.cpp
+++ b/src/devices/machine/8364_paula.cpp
@@ -1,23 +1,39 @@
// license: BSD-3-Clause
// copyright-holders: Aaron Giles, Dirk Best
-/***************************************************************************
+/******************************************************************************
- Commodore 8364 "Paula"
+ MOS Technology 8364 "Paula"
-***************************************************************************/
+ TODO:
+ - Inherit FDC, serial and irq controller to here;
+ - Move Agnus "location" logic from here;
+ - low-pass filter;
+ - convert volume values to non-linear dB scale (cfr. )
+ - Verify ADKCON modulation;
+ - Verify manual mode:
+ \- AGA roadkill during gameplay, which also has very long period setups,
+ extremely aliased;
+ - When a DMA stop occurs, is the correlated channel playback stopped
+ at the end of the current cycle or as soon as possible like current
+ implementation?
+
+******************************************************************************/
#include "emu.h"
#include "8364_paula.h"
+#define LIVE_AUDIO_VIEW 0
+
//#define VERBOSE 1
#include "logmacro.h"
+#include <cstring>
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
-DEFINE_DEVICE_TYPE(PAULA_8364, paula_8364_device, "paula_8364", "8364 Paula")
+DEFINE_DEVICE_TYPE(PAULA_8364, paula_8364_device, "paula_8364", "MOS 8364 \"Paula\"")
//*************************************************************************
@@ -29,11 +45,11 @@ DEFINE_DEVICE_TYPE(PAULA_8364, paula_8364_device, "paula_8364", "8364 Paula")
//-------------------------------------------------
paula_8364_device::paula_8364_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, PAULA_8364, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- m_mem_r(*this), m_int_w(*this),
- m_dmacon(0), m_adkcon(0),
- m_stream(nullptr)
+ : device_t(mconfig, PAULA_8364, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , m_chipmem_r(*this, 0)
+ , m_int_w(*this)
+ , m_stream(nullptr)
{
}
@@ -43,24 +59,36 @@ paula_8364_device::paula_8364_device(const machine_config &mconfig, const char *
void paula_8364_device::device_start()
{
- // resolve callbacks
- m_mem_r.resolve_safe(0);
- m_int_w.resolve_safe();
-
// initialize channels
for (int i = 0; i < 4; i++)
{
m_channel[i].index = i;
- m_channel[i].curticks = 0;
- m_channel[i].manualmode = false;
- m_channel[i].curlocation = 0;
- m_channel[i].irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(paula_8364_device::signal_irq), this));
+ m_channel[i].irq_timer = timer_alloc(FUNC(paula_8364_device::signal_irq), this);
}
// create the stream
m_stream = stream_alloc(0, 4, clock() / CLOCK_DIVIDER);
}
+void paula_8364_device::device_reset()
+{
+ m_dma_master_enable = false;
+ for (auto &chan : m_channel)
+ {
+ chan.loc = 0;
+ chan.len = 0;
+ chan.per = 0;
+ chan.vol = 0;
+ chan.curticks = 0;
+ chan.manualmode = false;
+ chan.curlocation = 0;
+ chan.curlength = 0;
+ chan.dma_enabled = false;
+ chan.atper = false;
+ chan.atvol = false;
+ }
+}
+
//-------------------------------------------------
// update - stream updater
//-------------------------------------------------
@@ -75,64 +103,91 @@ void paula_8364_device::update()
// IMPLEMENTATION
//**************************************************************************
-uint16_t paula_8364_device::reg_r(offs_t offset)
+template <u8 ch> void paula_8364_device::audio_channel_map(address_map &map)
+{
+ // TODO: location addresses belongs to Agnus
+ map(0x00, 0x01).w(FUNC(paula_8364_device::audxlch_w<ch>));
+ map(0x02, 0x03).w(FUNC(paula_8364_device::audxlcl_w<ch>));
+ map(0x04, 0x05).w(FUNC(paula_8364_device::audxlen_w<ch>));
+ map(0x06, 0x07).w(FUNC(paula_8364_device::audxper_w<ch>));
+ map(0x08, 0x09).w(FUNC(paula_8364_device::audxvol_w<ch>));
+ map(0x0a, 0x0b).w(FUNC(paula_8364_device::audxdat_w<ch>));
+}
+
+// Instantiate channel maps
+template void paula_8364_device::audio_channel_map<0>(address_map &map);
+template void paula_8364_device::audio_channel_map<1>(address_map &map);
+template void paula_8364_device::audio_channel_map<2>(address_map &map);
+template void paula_8364_device::audio_channel_map<3>(address_map &map);
+
+template <u8 ch> void paula_8364_device::audxlch_w(u16 data)
+{
+ m_stream->update();
+ // TODO: chipmem mask
+ m_channel[ch].loc = (m_channel[ch].loc & 0x0000ffff) | ((data & 0x001f) << 16);
+}
+
+template <u8 ch> void paula_8364_device::audxlcl_w(u16 data)
+{
+ m_stream->update();
+ m_channel[ch].loc = (m_channel[ch].loc & 0xffff0000) | ((data & 0xfffe) << 0);
+}
+
+template <u8 ch> void paula_8364_device::audxlen_w(u16 data)
+{
+ m_stream->update();
+ m_channel[ch].len = data;
+}
+
+template <u8 ch> void paula_8364_device::audxper_w(u16 data)
+{
+ m_stream->update();
+ m_channel[ch].per = data;
+}
+
+template <u8 ch> void paula_8364_device::audxvol_w(u16 data)
+{
+ m_stream->update();
+ m_channel[ch].vol = data & 0x7f;
+}
+
+template <u8 ch> void paula_8364_device::audxdat_w(u16 data)
+{
+ m_stream->update();
+ m_channel[ch].dat = data;
+ m_channel[ch].manualmode = true;
+}
+
+void paula_8364_device::dmacon_set(u16 data)
{
- switch (offset)
+ m_stream->update();
+
+ m_dma_master_enable = bool(BIT(data, 9));
+
+ // update the DMA latches on each channel and reload if fresh
+ // This holds true particularly for Ocean games (bchvolly, lostpatr, pang) and waylildr:
+ // they sets a DMA length for a channel then enable DMA finally resets that length to 1
+ // after a short delay loop.
+ for (int channum = 0; channum < 4; channum++)
{
- case REG_DMACONR:
- return m_dmacon;
+ audio_channel *chan = &m_channel[channum];
+ if (!chan->dma_enabled && ((data >> channum) & 1))
+ dma_reload(chan, true);
- case REG_ADKCONR:
- return m_adkcon;
+ chan->dma_enabled = bool(BIT(data, channum));
}
-
- return 0xffff;
}
-void paula_8364_device::reg_w(offs_t offset, uint16_t data)
+void paula_8364_device::adkcon_set(u16 data)
{
- if (offset >= 0xa0 && offset <= 0xdf)
- m_stream->update();
+ m_stream->update();
- switch (offset)
+ for (int channum = 0; channum < 4; channum++)
{
- case REG_DMACON:
- m_stream->update();
- m_dmacon = (data & 0x8000) ? (m_dmacon | (data & 0x021f)) : (m_dmacon & ~(data & 0x021f)); // only bits 15, 9 and 5 to 0
- break;
-
- case REG_ADKCON:
- m_stream->update();
- m_adkcon = (data & 0x8000) ? (m_adkcon | (data & 0x7fff)) : (m_adkcon & ~(data & 0x7fff));
- break;
-
- // to be moved
- case REG_AUD0LCL: m_channel[CHAN_0].loc = (m_channel[CHAN_0].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
- case REG_AUD0LCH: m_channel[CHAN_0].loc = (m_channel[CHAN_0].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
- case REG_AUD1LCL: m_channel[CHAN_1].loc = (m_channel[CHAN_1].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
- case REG_AUD1LCH: m_channel[CHAN_1].loc = (m_channel[CHAN_1].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
- case REG_AUD2LCL: m_channel[CHAN_2].loc = (m_channel[CHAN_2].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
- case REG_AUD2LCH: m_channel[CHAN_2].loc = (m_channel[CHAN_2].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
- case REG_AUD3LCL: m_channel[CHAN_3].loc = (m_channel[CHAN_3].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
- case REG_AUD3LCH: m_channel[CHAN_3].loc = (m_channel[CHAN_3].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
-
- // audio data
- case REG_AUD0LEN: m_channel[CHAN_0].len = data; break;
- case REG_AUD0PER: m_channel[CHAN_0].per = data; break;
- case REG_AUD0VOL: m_channel[CHAN_0].vol = data; break;
- case REG_AUD0DAT: m_channel[CHAN_0].dat = data; m_channel[CHAN_0].manualmode = true; break;
- case REG_AUD1LEN: m_channel[CHAN_1].len = data; break;
- case REG_AUD1PER: m_channel[CHAN_1].per = data; break;
- case REG_AUD1VOL: m_channel[CHAN_1].vol = data; break;
- case REG_AUD1DAT: m_channel[CHAN_1].dat = data; m_channel[CHAN_1].manualmode = true; break;
- case REG_AUD2LEN: m_channel[CHAN_2].len = data; break;
- case REG_AUD2PER: m_channel[CHAN_2].per = data; break;
- case REG_AUD2VOL: m_channel[CHAN_2].vol = data; break;
- case REG_AUD2DAT: m_channel[CHAN_2].dat = data; m_channel[CHAN_2].manualmode = true; break;
- case REG_AUD3LEN: m_channel[CHAN_3].len = data; break;
- case REG_AUD3PER: m_channel[CHAN_3].per = data; break;
- case REG_AUD3VOL: m_channel[CHAN_3].vol = data; break;
- case REG_AUD3DAT: m_channel[CHAN_3].dat = data; m_channel[CHAN_3].manualmode = true; break;
+ audio_channel *chan = &m_channel[channum];
+
+ chan->atper = bool(BIT(data, channum + 4));
+ chan->atvol = bool(BIT(data, channum));
}
}
@@ -142,20 +197,52 @@ void paula_8364_device::reg_w(offs_t offset, uint16_t data)
TIMER_CALLBACK_MEMBER( paula_8364_device::signal_irq )
{
- m_int_w(param);
+ m_int_w(param, 1);
}
//-------------------------------------------------
// dma_reload
//-------------------------------------------------
-void paula_8364_device::dma_reload(audio_channel *chan)
+void paula_8364_device::dma_reload(audio_channel *chan, bool startup)
{
chan->curlocation = chan->loc;
- chan->curlength = chan->len;
- chan->irq_timer->adjust(attotime::from_hz(15750), chan->index); // clock() / 227
+ // TODO: Unconfirmed, assume max size if length is 0.
+ // cfr. wrestlmn and videokid, where they pratically never get even close to buffer exhaustion.
+ chan->curlength = chan->len == 0 ? 0x10000 : chan->len;
+ // TODO: on startup=false irq should be delayed two cycles
+ if (startup)
+ chan->irq_timer->adjust(attotime::from_hz(15750), chan->index); // clock() / 227
+ else
+ signal_irq(chan->index);
+
+ LOG("dma_reload(%d): offs=%06X len=%04X\n", chan->index, chan->curlocation, chan->curlength);
+}
- LOG("dma_reload(%d): offs=%05X len=%04X\n", chan->index, chan->curlocation, chan->curlength);
+std::string paula_8364_device::print_audio_state()
+{
+ std::ostringstream outbuffer;
+
+ util::stream_format(outbuffer, "DMA master %d\n", m_dma_master_enable);
+ for (auto &chan : m_channel)
+ {
+ util::stream_format(outbuffer, "%d DMA (%d) ADK (%d%d) REGS: %06x %04x %03x %02x %d LIVE: %06x %04x %d\n"
+ , chan.index
+ , chan.dma_enabled
+ , chan.atper
+ , chan.atvol
+ , chan.loc
+ , chan.len
+ , chan.per
+ , chan.vol
+ , chan.manualmode
+ , chan.curlocation
+ , chan.curlength
+ , chan.dma_enabled
+ );
+ }
+
+ return outbuffer.str();
}
//-------------------------------------------------
@@ -167,7 +254,7 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re
int channum, sampoffs = 0;
// if all DMA off, disable all channels
- if (BIT(m_dmacon, 9) == 0)
+ if (m_dma_master_enable == false)
{
m_channel[0].dma_enabled =
m_channel[1].dma_enabled =
@@ -182,15 +269,8 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re
int samples = outputs[0].samples() * CLOCK_DIVIDER;
- // update the DMA states on each channel and reload if fresh
- for (channum = 0; channum < 4; channum++)
- {
- audio_channel *chan = &m_channel[channum];
- if (!chan->dma_enabled && ((m_dmacon >> channum) & 1))
- dma_reload(chan);
-
- chan->dma_enabled = BIT(m_dmacon, channum);
- }
+ if (LIVE_AUDIO_VIEW)
+ popmessage(print_audio_state());
// loop until done
while (samples > 0)
@@ -219,11 +299,12 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re
int i;
// normalize the volume value
+ // FIXME: definitely not linear
volume = (volume & 0x40) ? 64 : (volume & 0x3f);
volume *= 4;
// are we modulating the period of the next channel?
- if ((m_adkcon >> channum) & 0x10)
+ if (chan->atper)
{
nextper = chan->dat;
nextvol = -1;
@@ -231,7 +312,7 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re
}
// are we modulating the volume of the next channel?
- else if ((m_adkcon >> channum) & 0x01)
+ else if (chan->atvol)
{
nextper = -1;
nextvol = chan->dat;
@@ -263,14 +344,23 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re
chan->curlocation++;
if (chan->dma_enabled && !(chan->curlocation & 1))
{
- chan->dat = m_mem_r(chan->curlocation);
+ chan->dat = m_chipmem_r(chan->curlocation);
if (chan->curlength != 0)
chan->curlength--;
- // if we run out of data, reload the dma
+ // if we run out of data, reload the dma and signal an IRQ,
+ // gpmaster/asparmgp definitely expects this
+ // (uses channel 3 as a sequencer, changing the start address on the fly)
if (chan->curlength == 0)
- dma_reload(chan);
+ {
+ dma_reload(chan, false);
+ // reload the data pointer, otherwise aliasing / buzzing outside the given buffer will be heard
+ // For example: Xenon 2 sets up location=0x63298 length=0x20
+ // for silencing channels on-the-fly without relying on irqs.
+ // Without this the location will read at 0x632d8 (data=0x7a7d), causing annoying buzzing.
+ chan->dat = m_chipmem_r(chan->curlocation);
+ }
}
// latch the next byte of the sample
@@ -282,7 +372,7 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re
// if we're in manual mode, signal an interrupt once we latch the low byte
if (!chan->dma_enabled && chan->manualmode && (chan->curlocation & 1))
{
- signal_irq(nullptr, channum);
+ signal_irq(channum);
chan->manualmode = false;
}
}
diff --git a/src/devices/machine/8364_paula.h b/src/devices/machine/8364_paula.h
index 9fa7a6ebf38..b4b371f8a98 100644
--- a/src/devices/machine/8364_paula.h
+++ b/src/devices/machine/8364_paula.h
@@ -55,62 +55,30 @@ public:
paula_8364_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// configuration
- auto mem_read_cb() { return m_mem_r.bind(); }
+ auto mem_read_cb() { return m_chipmem_r.bind(); }
auto int_cb() { return m_int_w.bind(); }
- uint16_t reg_r(offs_t offset);
- void reg_w(offs_t offset, uint16_t data);
-
void update();
+ template <u8 ch> void audio_channel_map(address_map &map);
+ void dmacon_set(u16 data);
+ void adkcon_set(u16 data);
+
protected:
// device-level overrides
virtual void device_start() override;
+ virtual void device_reset() override;
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
- enum
- {
- CHAN_0 = 0,
- CHAN_1 = 1,
- CHAN_2 = 2,
- CHAN_3 = 3
- };
-
- enum
- {
- REG_DMACONR = 0x02/2,
- REG_ADKCONR = 0x10/2,
- REG_DMACON = 0x96/2,
- REG_INTREQ = 0x9c/2,
- REG_ADKCON = 0x9e/2,
- REG_AUD0LCH = 0xa0/2, // to be moved, not part of paula
- REG_AUD0LCL = 0xa2/2, // to be moved, not part of paula
- REG_AUD0LEN = 0xa4/2,
- REG_AUD0PER = 0xa6/2,
- REG_AUD0VOL = 0xa8/2,
- REG_AUD0DAT = 0xaa/2,
- REG_AUD1LCH = 0xb0/2, // to be moved, not part of paula
- REG_AUD1LCL = 0xb2/2, // to be moved, not part of paula
- REG_AUD1LEN = 0xb4/2,
- REG_AUD1PER = 0xb6/2,
- REG_AUD1VOL = 0xb8/2,
- REG_AUD1DAT = 0xba/2,
- REG_AUD2LCH = 0xc0/2, // to be moved, not part of paula
- REG_AUD2LCL = 0xc2/2, // to be moved, not part of paula
- REG_AUD2LEN = 0xc4/2,
- REG_AUD2PER = 0xc6/2,
- REG_AUD2VOL = 0xc8/2,
- REG_AUD2DAT = 0xca/2,
- REG_AUD3LCH = 0xd0/2, // to be moved, not part of paula
- REG_AUD3LCL = 0xd2/2, // to be moved, not part of paula
- REG_AUD3LEN = 0xd4/2,
- REG_AUD3PER = 0xd6/2,
- REG_AUD3VOL = 0xd8/2,
- REG_AUD3DAT = 0xda/2
- };
+ template <u8 ch> void audxlch_w(u16 data);
+ template <u8 ch> void audxlcl_w(u16 data);
+ template <u8 ch> void audxlen_w(u16 data);
+ template <u8 ch> void audxper_w(u16 data);
+ template <u8 ch> void audxvol_w(u16 data);
+ template <u8 ch> void audxdat_w(u16 data);
static constexpr int CLOCK_DIVIDER = 16;
@@ -118,7 +86,7 @@ private:
{
emu_timer *irq_timer;
uint32_t curlocation;
- uint16_t curlength;
+ uint32_t curlength;
uint16_t curticks;
uint8_t index;
bool dma_enabled;
@@ -131,22 +99,24 @@ private:
uint16_t per;
uint16_t vol;
uint16_t dat;
+ bool atper;
+ bool atvol;
};
- void dma_reload(audio_channel *chan);
+ bool m_dma_master_enable;
- // callbacks
- devcb_read16 m_mem_r;
- devcb_write_line m_int_w;
+ void dma_reload(audio_channel *chan, bool startup);
- // internal state
- uint16_t m_dmacon;
- uint16_t m_adkcon;
+ // callbacks
+ devcb_read16 m_chipmem_r;
+ devcb_write8 m_int_w;
audio_channel m_channel[4];
sound_stream *m_stream;
TIMER_CALLBACK_MEMBER( signal_irq );
+
+ std::string print_audio_state();
};
// device type definition
diff --git a/src/devices/machine/8530scc.cpp b/src/devices/machine/8530scc.cpp
index c331037d0a1..72e438366db 100644
--- a/src/devices/machine/8530scc.cpp
+++ b/src/devices/machine/8530scc.cpp
@@ -19,7 +19,8 @@ DEFINE_DEVICE_TYPE(SCC8530, scc8530_legacy_device, "scc8530l", "Zilog 8530 SCC (
PARAMETERS
***************************************************************************/
-#define LOG_SCC (0)
+#define VERBOSE (0)
+#include "logmacro.h"
/***************************************************************************
IMPLEMENTATION
@@ -79,11 +80,8 @@ void scc8530_legacy_device::updateirqs()
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);
+ LOG("SCC8530 IRQ status => %d\n", irqstat);
+ intrq_cb(irqstat);
}
}
@@ -111,26 +109,44 @@ void scc8530_legacy_device::resetchannel(int ch)
}
/*-------------------------------------------------
- scc8530_baud_expire - baud rate timer expiry
+ updatebaudtimer - baud rate timer calculation
-------------------------------------------------*/
-void scc8530_legacy_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void scc8530_legacy_device::updatebaudtimer(int ch)
{
- Chan *pChan = &channel[id];
- int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14];
- int rate;
-
- if (brconst)
+ Chan *pChan = &channel[ch];
+ // BR Generator Enable
+ if(!BIT(pChan->reg_val[14], 0))
{
- rate = clock() / brconst;
+ pChan->baudtimer->adjust(attotime::never, ch, attotime::never);
+ return;
}
- else
+
+ // BR Time Constant
+ int brconst = pChan->reg_val[13] << 8 | pChan->reg_val[12];
+
+ // Clock Mode is 1x, 16x, 32x, or 64x
+ int clockmode = pChan->reg_val[4] >> 6;
+ int clockrate = 1;
+ if (clockmode)
{
- rate = 0;
+ clockrate = 8 << clockmode;
}
- // is baud counter IRQ enabled on this channel?
- // always flag pending in case it's enabled after this
+ int baudrate = clock() / ((brconst + 2) * 2 * clockrate);
+ attotime attorate = attotime::from_hz(baudrate);
+ pChan->baudtimer->adjust(attorate, ch, attorate);
+}
+
+/*-------------------------------------------------
+ baud_expire - baud rate timer expiry
+-------------------------------------------------*/
+
+TIMER_CALLBACK_MEMBER(scc8530_legacy_device::baud_expire)
+{
+ Chan *pChan = &channel[param];
+
+ // always flag IRQ pending in case baud IRQ is enabled after this
pChan->baudIRQPending = 1;
if (pChan->baudIRQEnable)
{
@@ -141,17 +157,7 @@ void scc8530_legacy_device::device_timer(emu_timer &timer, device_timer_id id, i
updateirqs();
}
}
-
- // reset timer according to current register values
- if (rate)
- {
- attotime attorate = attotime::from_hz(rate);
- timer.adjust(attorate, 0, attorate);
- }
- else
- {
- timer.adjust(attotime::never, 0, attotime::never);
- }
+ updatebaudtimer(param);
}
/*-------------------------------------------------
@@ -160,8 +166,6 @@ void scc8530_legacy_device::device_timer(emu_timer &timer, device_timer_id id, i
void scc8530_legacy_device::device_start()
{
- intrq_cb.resolve();
-
memset(channel, 0, sizeof(channel));
mode = 0;
@@ -172,8 +176,8 @@ void scc8530_legacy_device::device_start()
lastIRQStat = 0;
IRQType = IRQ_NONE;
- channel[0].baudtimer = timer_alloc(0);
- channel[1].baudtimer = timer_alloc(1);
+ channel[0].baudtimer = timer_alloc(FUNC(scc8530_legacy_device::baud_expire), this);
+ channel[1].baudtimer = timer_alloc(FUNC(scc8530_legacy_device::baud_expire), this);
}
@@ -207,8 +211,7 @@ void scc8530_legacy_device::set_status(int _status)
void scc8530_legacy_device::acknowledge()
{
- if(!intrq_cb.isnull())
- intrq_cb(0);
+ intrq_cb(0);
}
/*-------------------------------------------------
@@ -217,10 +220,7 @@ void scc8530_legacy_device::acknowledge()
uint8_t scc8530_legacy_device::getareg()
{
- /* Not yet implemented */
- #if LOG_SCC
- printf("SCC: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]);
- #endif
+ LOG("SCC: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]);
if (reg == 0)
{
@@ -249,9 +249,7 @@ uint8_t scc8530_legacy_device::getareg()
uint8_t scc8530_legacy_device::getbreg()
{
- #if LOG_SCC
- printf("SCC: port B reg %i read 0x%02x\n", reg, channel[1].reg_val[reg]);
- #endif
+ LOG("SCC: port B reg %i read 0x%02x\n", reg, channel[1].reg_val[reg]);
if (reg == 0)
{
@@ -291,9 +289,7 @@ void scc8530_legacy_device::putreg(int ch, uint8_t 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
+ LOG("SCC: port %c reg %d write 0x%02x\n", 'A'+ch, reg, data);
switch (reg)
{
@@ -396,13 +392,7 @@ void scc8530_legacy_device::putreg(int ch, uint8_t data)
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));
- }
+ updatebaudtimer(ch);
break;
case 15: // external/status interrupt control
diff --git a/src/devices/machine/8530scc.h b/src/devices/machine/8530scc.h
index 4a706df22a0..e4af88b3e97 100644
--- a/src/devices/machine/8530scc.h
+++ b/src/devices/machine/8530scc.h
@@ -46,7 +46,8 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(baud_expire);
private:
struct Chan {
@@ -85,6 +86,7 @@ private:
devcb_write_line intrq_cb;
+ void updatebaudtimer(int ch);
void updateirqs();
void initchannel(int ch);
void resetchannel(int ch);
diff --git a/src/devices/machine/aakart.cpp b/src/devices/machine/aakart.cpp
deleted file mode 100644
index 0ffb88e094e..00000000000
--- a/src/devices/machine/aakart.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-// license:LGPL-2.1+
-// copyright-holders:Angelo Salese
-/***************************************************************************
-
-Acorn Archimedes KART interface
-
-TODO:
-- FIFO
-
-***************************************************************************/
-
-#include "emu.h"
-#include "machine/aakart.h"
-
-
-
-//**************************************************************************
-// GLOBAL VARIABLES
-//**************************************************************************
-
-// device type definition
-DEFINE_DEVICE_TYPE(AAKART, aakart_device, "aakart", "Acorn Archimedes KART")
-
-#define HRST 0xff
-#define RAK1 0xfe
-#define RAK2 0xfd
-#define BACK 0x3f
-#define SMAK 0x33 /* keyboard + mouse ack */
-#define MACK 0x32 /* mouse ack */
-#define SACK 0x31 /* keyboard ack */
-#define NACK 0x30 /* no data ack */
-#define RQID 0x20
-
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
-
-//-------------------------------------------------
-// aakart_device - constructor
-//-------------------------------------------------
-
-aakart_device::aakart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, AAKART, tag, owner, clock), m_rxtimer(nullptr),
- m_txtimer(nullptr), m_mousetimer(nullptr), m_keybtimer(nullptr),
- m_out_tx_cb(*this),
- m_out_rx_cb(*this),
- m_tx_latch(0), m_rx(0), m_new_command(0), m_status(0), m_mouse_enable(0), m_keyb_enable(0)
-{
-}
-
-
-//-------------------------------------------------
-// device_validity_check - perform validity checks
-// on this device
-//-------------------------------------------------
-
-void aakart_device::device_validity_check(validity_checker &valid) const
-{
-}
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void aakart_device::device_start()
-{
- m_out_tx_cb.resolve_safe();
- m_out_rx_cb.resolve_safe();
- m_rxtimer = timer_alloc(RX_TIMER);
- m_rxtimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
- m_txtimer = timer_alloc(TX_TIMER);
- m_txtimer->adjust(attotime::from_hz(1), 0, attotime::from_hz(clock()));
- m_mousetimer = timer_alloc(MOUSE_TIMER);
- m_mousetimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
- m_keybtimer = timer_alloc(KEYB_TIMER);
- m_keybtimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
-}
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void aakart_device::device_reset()
-{
- m_status = STATUS_HRST;
- m_new_command = 0;
- m_rx = -1;
- m_keyb_enable = 0;
- m_mouse_enable = 0;
- m_queue_size = 0;
-}
-
-//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void aakart_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- if(id == TX_TIMER && m_new_command)
- {
- switch(m_tx_latch)
- {
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- // ---- -x-- scroll lock
- // ---- --x- num lock
- // ---- ---x caps lock
- break;
- case 0x20:
- m_rx = 0x81;
- m_out_tx_cb(ASSERT_LINE);
- break;
- case 0x30:
- case 0x31:
- case 0x32:
- case 0x33:
- m_keyb_enable = m_tx_latch & 1;
- m_mouse_enable = (m_tx_latch & 2) >> 1;
- if(m_queue_size)
- {
- m_rx = m_queue[0] & 0xff;
- m_out_tx_cb(ASSERT_LINE);
- }
- break;
- case 0x3f:
- if(m_queue_size)
- {
- m_rx = (m_queue[0] >> 8) & 0xff;
- m_out_tx_cb(ASSERT_LINE);
-
- m_queue_size--;
- for(int i=0; i<m_queue_size; i++)
- m_queue[i] = m_queue[i + 1];
- }
- break;
- case 0xfd:
- m_rx = 0xfd;
- m_out_tx_cb(ASSERT_LINE);
- break;
- case 0xfe:
- m_rx = 0xfe;
- m_out_tx_cb(ASSERT_LINE);
- break;
- case 0xff:
- m_rx = 0xff;
- m_out_tx_cb(ASSERT_LINE);
- break;
- default:
- //printf("%02x %02x %02x\n",m_tx_latch,m_rx_latch,m_keyb_enable);
- break;
- }
-
- m_new_command = 0;
- m_out_rx_cb(ASSERT_LINE);
- }
- else if(id == TX_TIMER && m_queue_size && (m_keyb_enable || m_mouse_enable))
- {
- m_rx = m_queue[0] & 0xff;
- m_out_tx_cb(ASSERT_LINE);
- }
-}
-
-//**************************************************************************
-// READ/WRITE HANDLERS
-//**************************************************************************
-
-
-uint8_t aakart_device::read()
-{
- m_out_tx_cb(CLEAR_LINE);
- //machine().debug_break();
- return m_rx;
-}
-
-void aakart_device::write(uint8_t data)
-{
- // if(m_new_command) printf("skip cmd %02x\n",data);
-
- m_tx_latch = data;
- m_out_rx_cb(CLEAR_LINE);
- m_new_command |= 1;
-}
-
-void aakart_device::send_keycode_down(uint8_t row, uint8_t col)
-{
- //printf("keycode down\n");
- if (m_keyb_enable && m_queue_size < 0x10)
- m_queue[m_queue_size++] = ((col | 0xc0) << 8) | (row | 0xc0);
-}
-
-void aakart_device::send_keycode_up(uint8_t row, uint8_t col)
-{
- //printf("keycode up\n");
- if (m_keyb_enable && m_queue_size < 0x10)
- m_queue[m_queue_size++] = ((col | 0xd0) << 8) | (row | 0xd0);
-}
-
-void aakart_device::send_mouse(uint8_t x, uint8_t y)
-{
- if (m_mouse_enable && m_queue_size < 0x10)
- m_queue[m_queue_size++] = ((y & 0x7f) << 8) | (x & 0x7f);
-}
diff --git a/src/devices/machine/aakart.h b/src/devices/machine/aakart.h
deleted file mode 100644
index d9b367b8678..00000000000
--- a/src/devices/machine/aakart.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// license:LGPL-2.1+
-// copyright-holders:Angelo Salese
-/***************************************************************************
-
-Acorn Archimedes KART interface
-
-***************************************************************************/
-
-#ifndef MAME_MACHINE_AAKART_H
-#define MAME_MACHINE_AAKART_H
-
-#pragma once
-
-
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-// ======================> aakart_device
-
-class aakart_device : public device_t
-{
-public:
- // construction/destruction
- aakart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto out_tx_callback() { return m_out_tx_cb.bind(); }
- auto out_rx_callback() { return m_out_rx_cb.bind(); }
-
- // I/O operations
- void write(uint8_t data);
- uint8_t read();
- void send_keycode_down(uint8_t row, uint8_t col);
- void send_keycode_up(uint8_t row, uint8_t col);
- void send_mouse(uint8_t x, uint8_t y);
-
-protected:
- // device-level overrides
- virtual void device_validity_check(validity_checker &valid) const override;
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
-private:
- enum {
- STATUS_NORMAL = 0,
- STATUS_KEYUP,
- STATUS_KEYDOWN,
- STATUS_MOUSE,
- STATUS_HRST,
- STATUS_UNDEFINED
- };
-
- static const device_timer_id RX_TIMER = 1;
- static const device_timer_id TX_TIMER = 2;
- static const device_timer_id MOUSE_TIMER = 3;
- static const device_timer_id KEYB_TIMER = 4;
- emu_timer * m_rxtimer;
- emu_timer * m_txtimer;
- emu_timer * m_mousetimer;
- emu_timer * m_keybtimer;
-
- devcb_write_line m_out_tx_cb;
- devcb_write_line m_out_rx_cb;
- uint8_t m_tx_latch;
- //uint8_t m_rx_latch;
- uint8_t m_rx;
- uint8_t m_new_command;
- uint8_t m_status;
- uint8_t m_mouse_enable;
- uint8_t m_keyb_enable;
- int m_queue_size;
- uint16_t m_queue[0x10];
-};
-
-
-// device type definition
-DECLARE_DEVICE_TYPE(AAKART, aakart_device)
-
-#endif // MAME_MACHINE_AAKART_H
diff --git a/src/devices/machine/acorn_bmu.cpp b/src/devices/machine/acorn_bmu.cpp
new file mode 100644
index 00000000000..94f5e953a53
--- /dev/null
+++ b/src/devices/machine/acorn_bmu.cpp
@@ -0,0 +1,267 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ Acorn Battery Management Unit
+
+ The BMU is actually a 4-bit Hitachi HD404304F MCU, marked as
+ BMU 0290032.
+
+ TODO:
+ - configurable status
+ - callback when battery low
+
+*********************************************************************/
+
+#include "emu.h"
+#include "acorn_bmu.h"
+
+#define LOG_DATA (1U << 1)
+#define LOG_LINE (1U << 2)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(ACORN_BMU, acorn_bmu_device, "acorn_bmu", "Acorn Battery Management Unit")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// acorn_bmu_device - constructor
+//-------------------------------------------------
+
+acorn_bmu_device::acorn_bmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ACORN_BMU, tag, owner, clock)
+ , m_slave_address(BMU_SLAVE_ADDRESS)
+ , m_scl(0)
+ , m_sdaw(0)
+ , m_sdar(1)
+ , m_state(STATE_IDLE)
+ , m_bits(0)
+ , m_shift(0)
+ , m_devsel(0)
+ , m_register(0)
+ , m_estimate(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void acorn_bmu_device::device_start()
+{
+ save_item(NAME(m_scl));
+ save_item(NAME(m_sdaw));
+ save_item(NAME(m_sdar));
+ save_item(NAME(m_state));
+ save_item(NAME(m_bits));
+ save_item(NAME(m_shift));
+ save_item(NAME(m_devsel));
+ save_item(NAME(m_register));
+ save_item(NAME(m_slave_address));
+ save_item(NAME(m_estimate));
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void acorn_bmu_device::scl_w(int state)
+{
+ if (m_scl != state)
+ {
+ m_scl = state;
+ LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_scl);
+
+ switch (m_state)
+ {
+ case STATE_DEVSEL:
+ case STATE_REGISTER:
+ case STATE_DATAIN:
+ if (m_bits < 8)
+ {
+ if (m_scl)
+ {
+ m_shift = ((m_shift << 1) | m_sdaw) & 0xff;
+ m_bits++;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ m_bits++;
+ }
+ else
+ {
+ if (m_bits == 8)
+ {
+ switch (m_state)
+ {
+ case STATE_DEVSEL:
+ m_devsel = m_shift;
+
+ if ((m_devsel & 0xfe) != m_slave_address)
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: not this device\n", m_devsel);
+ m_state = STATE_IDLE;
+ }
+ else if ((m_devsel & 1) == 0)
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: write\n", m_devsel);
+ m_state = STATE_REGISTER;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: read\n", m_devsel);
+ m_state = STATE_READSELACK;
+ }
+ break;
+
+ case STATE_REGISTER:
+ m_register = m_shift;
+
+ LOGMASKED(LOG_DATA, "register %02x\n", m_register);
+
+ m_state = STATE_DATAIN;
+ break;
+
+ case STATE_DATAIN:
+ LOGMASKED(LOG_DATA, "register[ %02x ] <- %02x\n", m_register, m_shift);
+
+ switch (m_register)
+ {
+ case BMU_CHARGE_ESTIMATE:
+ m_estimate = m_shift;
+ break;
+ }
+
+ m_register++;
+ break;
+ }
+
+ if( m_state != STATE_IDLE )
+ {
+ m_sdar = 0 ;
+ }
+ }
+ else
+ {
+ m_bits = 0;
+ m_sdar = 1;
+ }
+ }
+ }
+ break;
+
+ case STATE_READSELACK:
+ m_bits = 0;
+ m_state = STATE_DATAOUT;
+ break;
+
+ case STATE_DATAOUT:
+ if (m_bits < 8)
+ {
+ if (m_scl)
+ {
+ m_bits++;
+ }
+ else
+ {
+ if (m_bits == 0)
+ {
+ switch (m_register)
+ {
+ case BMU_VERSION:
+ m_shift = 0x03;
+ break;
+
+ case BMU_STATUS:
+ m_shift = STATUS_CHARGER_PRESENT | STATUS_BATTERY_PRESENT | STATUS_CHARGE_STATE_KNOWN | STATUS_LID_OPEN;
+ break;
+
+ case BMU_CAPACITY_USED:
+ m_shift = 0x40;
+ break;
+
+ case BMU_CHARGE_ESTIMATE:
+ m_shift = m_estimate;
+ break;
+
+ case BMU_COMMAND:
+ m_shift = 0;
+ break;
+ }
+
+ LOGMASKED(LOG_DATA, "register[ %02x ] -> %02x\n", m_register, m_shift);
+ m_register++;
+ }
+
+ m_sdar = (m_shift >> 7) & 1;
+
+ m_shift = (m_shift << 1) & 0xff;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "nack\n");
+ m_state = STATE_IDLE;
+ }
+
+ m_bits = 0;
+ }
+ else
+ {
+ m_sdar = 1;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void acorn_bmu_device::sda_w(int state)
+{
+ state &= 1;
+ if (m_sdaw != state)
+ {
+ LOGMASKED(LOG_LINE, "set sda %d\n", state);
+ m_sdaw = state;
+
+ if (m_scl)
+ {
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "stop\n");
+ m_state = STATE_IDLE;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "start\n");
+ m_state = STATE_DEVSEL;
+ m_bits = 0;
+ }
+
+ m_sdar = 1;
+ }
+ }
+}
+
+int acorn_bmu_device::sda_r()
+{
+ int res = m_sdar & 1;
+
+ LOGMASKED(LOG_LINE, "read sda %d\n", res);
+
+ return res;
+}
diff --git a/src/devices/machine/acorn_bmu.h b/src/devices/machine/acorn_bmu.h
new file mode 100644
index 00000000000..8cb4bb556a0
--- /dev/null
+++ b/src/devices/machine/acorn_bmu.h
@@ -0,0 +1,87 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ Acorn Battery Management Unit
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_ACORN_BMU_H
+#define MAME_MACHINE_ACORN_BMU_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> acorn_bmu_device
+
+class acorn_bmu_device : public device_t
+{
+public:
+ acorn_bmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void scl_w(int state);
+ void sda_w(int state);
+ int sda_r();
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+private:
+ static constexpr uint8_t BMU_SLAVE_ADDRESS = 0xa2;
+
+ // internal state
+ int m_slave_address;
+ int m_scl;
+ int m_sdaw;
+ int m_sdar;
+ int m_state;
+ int m_bits;
+ int m_shift;
+ int m_devsel;
+ int m_register;
+
+ enum { STATE_IDLE, STATE_DEVSEL, STATE_REGISTER, STATE_DATAIN, STATE_DATAOUT, STATE_READSELACK };
+
+ // registers
+ enum
+ {
+ BMU_VERSION = 0x50,
+ BMU_TEMPERATURE = 0x52,
+ BMU_CURRENT = 0x54,
+ BMU_VOLTAGE = 0x56,
+ BMU_STATUS = 0x5c,
+ BMU_CHARGE_RATE = 0x5e,
+ BMU_CAPACITY_NOMINAL = 0x80,
+ BMU_CAPACITY_MEASURED = 0x82,
+ BMU_CAPACITY_USED = 0x88,
+ BMU_CAPACITY_USABLE = 0x8a,
+ BMU_CHARGE_ESTIMATE = 0x8e,
+ BMU_COMMAND = 0x90,
+ BMU_AUTOSTART = 0x9e
+ };
+
+ // flags
+ enum
+ {
+ STATUS_THRESHOLD_3 = 1 << 0, // Battery fully charged
+ STATUS_LID_OPEN = 1 << 1, // Lid open
+ STATUS_THRESHOLD_2 = 1 << 2, // Battery flat [shutdown now]
+ STATUS_THRESHOLD_1 = 1 << 3, // Battery low [warn user]
+ STATUS_CHARGING_FAULT = 1 << 4, // Fault in charging system
+ STATUS_CHARGE_STATE_KNOWN = 1 << 5, // Charge state known
+ STATUS_BATTERY_PRESENT = 1 << 6, // Battery present
+ STATUS_CHARGER_PRESENT = 1 << 7 // Charger present
+ };
+
+ uint8_t m_estimate;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(ACORN_BMU, acorn_bmu_device)
+
+#endif // MAME_MACHINE_ACORN_BMU_H
diff --git a/src/devices/machine/acorn_ioc.cpp b/src/devices/machine/acorn_ioc.cpp
new file mode 100644
index 00000000000..b105eabed7d
--- /dev/null
+++ b/src/devices/machine/acorn_ioc.cpp
@@ -0,0 +1,400 @@
+// license:LGPL-2.1+
+// copyright-holders:Angelo Salese, R. Belmont, Juergen Buchmueller, Sandro Ronco
+/**************************************************************************************************
+
+ Acorn RISC Machine Input/Output Controller (IOC)
+
+ TODO:
+ - support IOEB used in the ARM250 (partially implemented in aristmk5.cpp)
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "acorn_ioc.h"
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(ACORN_IOC, acorn_ioc_device, "ioc", "Acorn IOC")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+acorn_ioc_device::acorn_ioc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ACORN_IOC, tag, owner, clock)
+ , device_serial_interface(mconfig, *this)
+ , m_peripherals_r(*this, 0xffffffff)
+ , m_peripherals_w(*this)
+ , m_giop_r(*this, 1)
+ , m_giop_w(*this)
+ , m_irq_w(*this)
+ , m_fiq_w(*this)
+ , m_kout_w(*this)
+ , m_baud_w(*this)
+{
+}
+
+void acorn_ioc_device::device_start()
+{
+ for (int i=0; i <4; i++)
+ m_timers[i] = timer_alloc(FUNC(acorn_ioc_device::timer_tick), this);
+
+ save_item(NAME(m_ir));
+ save_item(NAME(m_if));
+ save_item(NAME(m_baud));
+ save_item(NAME(m_timercnt));
+ save_item(NAME(m_timerout));
+ save_item(NAME(m_regs));
+}
+
+void acorn_ioc_device::device_reset()
+{
+ std::fill(std::begin(m_regs), std::end(m_regs), 0);
+ m_regs[IRQ_STATUS_A] = 0x10 | 0x80; // set up POR (Power On Reset) and Force IRQ at start-up
+ m_regs[IRQ_STATUS_B] = 0x40; // set up KART Tx empty
+ m_regs[FIQ_STATUS] = 0x80; // set up Force FIQ
+
+ m_ir = CLEAR_LINE;
+ m_if = CLEAR_LINE;
+ m_baud = CLEAR_LINE;
+
+ // KART interface
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_2);
+ set_rate(31250);
+
+ for (int i = 0; i < 6; i++)
+ m_giop_w[i](1);
+
+ for (int i=0; i < 2; i++)
+ {
+ m_timercnt[i] = 0;
+ m_timerout[i] = 0;
+ set_timer(i);
+ }
+
+ transmit_register_reset();
+ receive_register_reset();
+}
+
+void acorn_ioc_device::map(address_map &map)
+{
+ // Typical configuration
+ // IOA[2:6] --> A[2:6] Internal registers address
+ // IOA[16:18] --> B[0:2] Peripherals select
+ // IOA[19:20] --> T[0:1] Peripherals access timing
+ // IOA[21] --> CS Chip select
+ map(0x00200000, 0x0020007f).mirror(0x0018ff80).rw(FUNC(acorn_ioc_device::registers_r), FUNC(acorn_ioc_device::registers_w));
+ map(0x00210000, 0x0021ffff).select(0x00180000).rw(FUNC(acorn_ioc_device::periph_r<1>), FUNC(acorn_ioc_device::periph_w<1>));
+ map(0x00220000, 0x0022ffff).select(0x00180000).rw(FUNC(acorn_ioc_device::periph_r<2>), FUNC(acorn_ioc_device::periph_w<2>));
+ map(0x00230000, 0x0023ffff).select(0x00180000).rw(FUNC(acorn_ioc_device::periph_r<3>), FUNC(acorn_ioc_device::periph_w<3>));
+ map(0x00240000, 0x0024ffff).select(0x00180000).rw(FUNC(acorn_ioc_device::periph_r<4>), FUNC(acorn_ioc_device::periph_w<4>));
+ map(0x00250000, 0x0025ffff).select(0x00180000).rw(FUNC(acorn_ioc_device::periph_r<5>), FUNC(acorn_ioc_device::periph_w<5>));
+ map(0x00260000, 0x0026ffff).select(0x00180000).rw(FUNC(acorn_ioc_device::periph_r<6>), FUNC(acorn_ioc_device::periph_w<6>));
+ map(0x00270000, 0x0027ffff).select(0x00180000).rw(FUNC(acorn_ioc_device::periph_r<7>), FUNC(acorn_ioc_device::periph_w<7>));
+}
+
+TIMER_CALLBACK_MEMBER(acorn_ioc_device::timer_tick)
+{
+ // all timers always run
+ set_timer(param);
+
+ // but only timers 0 and 1 generate IRQs
+ switch (param)
+ {
+ case 0:
+ change_interrupt(IRQ_STATUS_A, 0x20, ASSERT_LINE);
+ break;
+
+ case 1:
+ change_interrupt(IRQ_STATUS_A, 0x40, ASSERT_LINE);
+ break;
+
+ case 2:
+ m_baud ^= 1;
+ m_baud_w(m_baud ? ASSERT_LINE : CLEAR_LINE);
+ break;
+ }
+}
+
+void acorn_ioc_device::change_interrupt(int reg, uint8_t mask, int state)
+{
+ if (state)
+ m_regs[reg] |= mask;
+ else
+ m_regs[reg] &= ~mask;
+
+ update_interrups();
+}
+
+void acorn_ioc_device::tra_complete()
+{
+ change_interrupt(IRQ_STATUS_B, 0x40, ASSERT_LINE); // KART Rx empty
+}
+
+void acorn_ioc_device::rcv_complete()
+{
+ receive_register_extract();
+ m_regs[KART] = get_received_char();
+ change_interrupt(IRQ_STATUS_B, 0x80, ASSERT_LINE); // KART Rx full
+}
+
+void acorn_ioc_device::tra_callback()
+{
+ m_kout_w(transmit_register_get_data_bit());
+}
+
+void acorn_ioc_device::set_timer(int tmr)
+{
+ double freq = 0;
+
+ switch (tmr)
+ {
+ case 0: // Timers
+ case 1:
+ if (m_timercnt[tmr] == 0)
+ m_timers[tmr]->adjust(attotime::never, tmr);
+ else
+ m_timers[tmr]->adjust(attotime::from_usec(m_timercnt[tmr] / 2), tmr); // TODO: ARM timings are quite off there, it should be latch and not latch/2
+ break;
+
+ case 2: // Baud generator
+ freq = (double)clock() / 8 / (double)(m_timercnt[tmr] + 1);
+ if (!m_baud_w.isunset())
+ m_timers[tmr]->adjust(attotime::from_usec(freq), tmr);
+ break;
+
+ case 3: // KART clock
+ freq = (double)clock() / 8 / (double)((m_timercnt[tmr] + 1) * 16);
+ set_rate((int)freq);
+ break;
+ }
+}
+
+void acorn_ioc_device::latch_timer_cnt(int tmr)
+{
+ // find out how many 2 MHz ticks have gone by
+ m_timerout[tmr] = m_timercnt[tmr] - (uint32_t)m_timers[tmr]->elapsed().as_ticks(clock() / 4);
+}
+
+void acorn_ioc_device::if_w(int state)
+{
+ // set on falling edge
+ if (m_if && !state)
+ change_interrupt(IRQ_STATUS_A, 0x04, ASSERT_LINE);
+
+ m_if = state;
+}
+
+void acorn_ioc_device::ir_w(int state)
+{
+ // set on rising edge
+ if (!m_ir && state)
+ change_interrupt(IRQ_STATUS_A, 0x08, ASSERT_LINE);
+
+ m_ir = state;
+}
+
+void acorn_ioc_device::update_interrups()
+{
+ if ((m_regs[IRQ_STATUS_A] & m_regs[IRQ_MASK_A]) || (m_regs[IRQ_STATUS_B] & m_regs[IRQ_MASK_B]))
+ m_irq_w(ASSERT_LINE);
+ else
+ m_irq_w(CLEAR_LINE);
+
+ if (m_regs[FIQ_STATUS] & m_regs[FIQ_MASK])
+ m_fiq_w(ASSERT_LINE);
+ else
+ m_fiq_w(CLEAR_LINE);
+}
+
+uint32_t acorn_ioc_device::registers_r(offs_t offset, uint32_t mem_mask)
+{
+ LOG("%s: IOC R %02x = %02x\n", machine().describe_context(), offset, m_regs[offset]);
+
+ uint8_t data = 0;
+ switch (offset & 0x1f)
+ {
+ case CONTROL:
+ // x--- ---- IR line
+ // -x-- ---- IF line
+ // --xx xxxx GPIO (C0-C5)
+
+ for (int i = 0; i < 6; i++)
+ data |= m_giop_r[i]() << i;
+
+ data |= m_if << 6;
+ data |= m_ir << 7;
+ return data;
+
+ case KART:
+ if (!machine().side_effects_disabled())
+ change_interrupt(IRQ_STATUS_B, 0x80, CLEAR_LINE);
+ return m_regs[KART];
+
+ case IRQ_STATUS_A:
+ // x--- ---- Always 1 (force IRQ)
+ // -x-- ---- Timer 1
+ // --x- ---- Timer 0
+ // ---x ---- POR line
+ // ---- x-- IR line
+ // ---- -x-- IF line
+ // ---- --x- IL7 line
+ // ---- ---x IL6 line
+
+ return m_regs[IRQ_STATUS_A];
+
+ case IRQ_REQUEST_A:
+ return m_regs[IRQ_STATUS_A] & m_regs[IRQ_MASK_A];
+
+ case IRQ_MASK_A:
+ return m_regs[IRQ_MASK_A];
+
+ case IRQ_STATUS_B:
+ // x--- ---- KART Rx full
+ // -x-- ---- KART Tx empty
+ // --xx xxxx IL0-IL5 lines
+
+ return m_regs[IRQ_STATUS_B];
+
+ case IRQ_REQUEST_B:
+ return m_regs[IRQ_STATUS_B] & m_regs[IRQ_MASK_B];
+
+ case IRQ_MASK_B:
+ return m_regs[IRQ_MASK_B];
+
+ case FIQ_STATUS:
+ // x--- ---- Always 1 (force FIQ)
+ // -x-- ---- IL0 line
+ // --xx x--- C5, C4 and C3 lines
+ // ---- -x-- IF line
+ // ---- --xx FH0 and FH1 lines
+
+ return m_regs[FIQ_STATUS];
+
+ case FIQ_REQUEST:
+ return m_regs[FIQ_STATUS] & m_regs[FIQ_MASK];
+
+ case FIQ_MASK:
+ return m_regs[FIQ_MASK];
+
+ case T0_LATCH_LO:
+ return m_timerout[0] & 0xff;
+
+ case T0_LATCH_HI:
+ return (m_timerout[0] >> 8) & 0xff;
+
+ case T1_LATCH_LO:
+ return m_timerout[1] & 0xff;
+
+ case T1_LATCH_HI:
+ return (m_timerout[1] >> 8) & 0xff;
+
+ case T2_LATCH_LO:
+ return m_timerout[2] & 0xff;
+
+ case T2_LATCH_HI:
+ return (m_timerout[2] >> 8) & 0xff;
+
+ case T3_LATCH_LO:
+ return m_timerout[3] & 0xff;
+
+ case T3_LATCH_HI:
+ return (m_timerout[3] >> 8) & 0xff;
+
+ default:
+ return m_regs[offset & 0x1f];
+ }
+}
+
+void acorn_ioc_device::registers_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOG("%s: IOC W %02x = %02x\n", machine().describe_context(), offset, data);
+
+ // IOC uses the data bus lines D16-D23 as inputs, this also works with byte store (STRB)
+ // because the ARM CPU repeats the byte four times across the data bus.
+ if (ACCESSING_BITS_16_31)
+ data >>= 16;
+
+ switch (offset & 0x1f)
+ {
+ case CONTROL:
+ for (int i = 0; i < 6; i++)
+ m_giop_w[i](BIT(data, i));
+ break;
+
+ case KART:
+ change_interrupt(IRQ_STATUS_B, 0x40, CLEAR_LINE);
+ m_regs[KART] = data;
+ transmit_register_setup(data);
+ break;
+
+ case IRQ_REQUEST_A:
+ m_regs[IRQ_STATUS_A] &= ~(data & 0x7c);
+ update_interrups(); // check pending irqs
+ break;
+
+ case IRQ_MASK_A:
+ m_regs[IRQ_MASK_A] = data;
+ update_interrups();
+ break;
+
+ case IRQ_MASK_B:
+ m_regs[IRQ_MASK_B] = data;
+ update_interrups();
+ break;
+
+ case FIQ_MASK:
+ m_regs[FIQ_MASK] = data;
+ update_interrups();
+ break;
+
+ case T0_LATCH_LO: case T0_LATCH_HI:
+ case T1_LATCH_LO: case T1_LATCH_HI:
+ case T2_LATCH_LO: case T2_LATCH_HI:
+ case T3_LATCH_LO: case T3_LATCH_HI:
+ m_regs[offset] = data;
+ break;
+
+ case T0_LATCH: // Timer 0 latch
+ latch_timer_cnt(0);
+ break;
+
+ case T1_LATCH: // Timer 1 latch
+ latch_timer_cnt(1);
+ break;
+
+ case T2_LATCH: // Timer 2 latch
+ latch_timer_cnt(2);
+ break;
+
+ case T3_LATCH: // Timer 3 latch
+ latch_timer_cnt(3);
+ break;
+
+ case T0_GO: // Timer 0 start
+ m_timercnt[0] = m_regs[T0_LATCH_HI] << 8 | m_regs[T0_LATCH_LO];
+ set_timer(0);
+ break;
+
+ case T1_GO: // Timer 1 start
+ m_timercnt[1] = m_regs[T1_LATCH_HI] << 8 | m_regs[T1_LATCH_LO];
+ set_timer(1);
+ break;
+
+ case T2_GO: // Timer 2 start
+ m_timercnt[2] = m_regs[T2_LATCH_HI] << 8 | m_regs[T2_LATCH_LO];
+ set_timer(2);
+ break;
+
+ case T3_GO: // Timer 3 start
+ m_timercnt[3] = m_regs[T3_LATCH_HI] << 8 | m_regs[T3_LATCH_LO];
+ set_timer(3);
+ break;
+
+ default:
+ m_regs[offset & 0x1f] = data;
+ break;
+ }
+}
diff --git a/src/devices/machine/acorn_ioc.h b/src/devices/machine/acorn_ioc.h
new file mode 100644
index 00000000000..d4761e6089a
--- /dev/null
+++ b/src/devices/machine/acorn_ioc.h
@@ -0,0 +1,129 @@
+// license:LGPL-2.1+
+// copyright-holders:Angelo Salese, R. Belmont, Juergen Buchmueller, Sandro Ronco
+/**************************************************************************************************
+
+ Acorn RISC Machine Input/Output Controller (IOC)
+
+**************************************************************************************************/
+
+#ifndef MAME_MACHINE_ACORN_IOC_H
+#define MAME_MACHINE_ACORN_IOC_H
+
+#pragma once
+
+#include "diserial.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> acorn_ioc_device
+
+class acorn_ioc_device : public device_t, public device_serial_interface
+{
+public:
+ acorn_ioc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <unsigned N> auto peripheral_r() { static_assert(N >= 1 && N <= 7); return m_peripherals_r[N - 1].bind(); }
+ template <unsigned N> auto peripheral_w() { static_assert(N >= 1 && N <= 7); return m_peripherals_w[N - 1].bind(); }
+ template <unsigned N> auto gpio_r() { static_assert(N <= 5); return m_giop_r[N].bind(); }
+ template <unsigned N> auto gpio_w() { static_assert(N <= 5); return m_giop_w[N].bind(); }
+ auto irq_w() { return m_irq_w.bind(); }
+ auto fiq_w() { return m_fiq_w.bind(); }
+ auto baud_w() { return m_baud_w.bind(); }
+ auto kout_w() { return m_kout_w.bind(); }
+
+ void map(address_map &map);
+
+ uint32_t registers_r(offs_t offset, uint32_t mem_mask = ~0);
+ void registers_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ template<unsigned N> uint32_t periph_r(offs_t offset, uint32_t mem_mask = ~0) { return m_peripherals_r[N - 1](offset, mem_mask); }
+ template<unsigned N> void periph_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_peripherals_w[N - 1](offset, data, mem_mask); }
+
+ void il0_w(int state) { change_interrupt(IRQ_STATUS_B, 0x01, state); change_interrupt(FIQ_STATUS, 0x40, state); }
+ void il1_w(int state) { change_interrupt(IRQ_STATUS_B, 0x02, state); }
+ void il2_w(int state) { change_interrupt(IRQ_STATUS_B, 0x04, state); }
+ void il3_w(int state) { change_interrupt(IRQ_STATUS_B, 0x08, state); }
+ void il4_w(int state) { change_interrupt(IRQ_STATUS_B, 0x10, state); }
+ void il5_w(int state) { change_interrupt(IRQ_STATUS_B, 0x20, state); }
+ void il6_w(int state) { change_interrupt(IRQ_STATUS_A, 0x01, state); }
+ void il7_w(int state) { change_interrupt(IRQ_STATUS_A, 0x02, state); }
+ void fh0_w(int state) { change_interrupt(FIQ_STATUS , 0x01, state); }
+ void fh1_w(int state) { change_interrupt(FIQ_STATUS , 0x02, state); }
+ void fl_w(int state) { change_interrupt(FIQ_STATUS , 0x04, !state); }
+ void por_w(int state) { if (state) change_interrupt(IRQ_STATUS_A, 0x10, state); }
+ void kin_w(int state) { rx_w(state); }
+ void if_w(int state);
+ void ir_w(int state);
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_serial_interface implementation
+ virtual void tra_callback() override;
+ virtual void tra_complete() override;
+ virtual void rcv_complete() override;
+
+private:
+ void update_interrups();
+ void change_interrupt(int reg, uint8_t mask, int state);
+ void set_timer(int tmr);
+ void latch_timer_cnt(int tmr);
+ TIMER_CALLBACK_MEMBER(timer_tick);
+
+ enum // registers
+ {
+ CONTROL = 0x00 / 4,
+ KART = 0x04 / 4,
+ IRQ_STATUS_A = 0x10 / 4,
+ IRQ_REQUEST_A = 0x14 / 4,
+ IRQ_MASK_A = 0x18 / 4,
+ IRQ_STATUS_B = 0x20 / 4,
+ IRQ_REQUEST_B = 0x24 / 4,
+ IRQ_MASK_B = 0x28 / 4,
+ FIQ_STATUS = 0x30 / 4,
+ FIQ_REQUEST = 0x34 / 4,
+ FIQ_MASK = 0x38 / 4,
+ T0_LATCH_LO = 0x40 / 4,
+ T0_LATCH_HI = 0x44 / 4,
+ T0_GO = 0x48 / 4,
+ T0_LATCH = 0x4c / 4,
+ T1_LATCH_LO = 0x50 / 4,
+ T1_LATCH_HI = 0x54 / 4,
+ T1_GO = 0x58 / 4,
+ T1_LATCH = 0x5c / 4,
+ T2_LATCH_LO = 0x60 / 4,
+ T2_LATCH_HI = 0x64 / 4,
+ T2_GO = 0x68 / 4,
+ T2_LATCH = 0x6c / 4,
+ T3_LATCH_LO = 0x70 / 4,
+ T3_LATCH_HI = 0x74 / 4,
+ T3_GO = 0x78 / 4,
+ T3_LATCH = 0x7c / 4,
+ };
+
+ devcb_read32::array<7> m_peripherals_r;
+ devcb_write32::array<7> m_peripherals_w;
+ devcb_read_line::array<6> m_giop_r;
+ devcb_write_line::array<6> m_giop_w;
+ devcb_write_line m_irq_w;
+ devcb_write_line m_fiq_w;
+ devcb_write_line m_kout_w;
+ devcb_write_line m_baud_w;
+ emu_timer * m_timers[4];
+
+ int m_ir;
+ int m_if;
+ int m_baud;
+ uint32_t m_timercnt[4];
+ uint32_t m_timerout[4];
+ uint8_t m_regs[0x20];
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(ACORN_IOC, acorn_ioc_device)
+
+#endif // MAME_MACHINE_ACORN_IOC_H
diff --git a/src/devices/machine/acorn_lc.cpp b/src/devices/machine/acorn_lc.cpp
new file mode 100644
index 00000000000..71a545521cb
--- /dev/null
+++ b/src/devices/machine/acorn_lc.cpp
@@ -0,0 +1,152 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ Acorn LC ASIC (for Acorn A4)
+
+ No public documentation exists, this is mostly based on the A4 TRM.
+
+*********************************************************************/
+
+#include "emu.h"
+#include "acorn_lc.h"
+#include "screen.h"
+
+
+DEFINE_DEVICE_TYPE(ACORN_LC, acorn_lc_device, "acorn_lc", "Acorn LC ASIC")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// acorn_lc_device - constructor
+//-------------------------------------------------
+
+acorn_lc_device::acorn_lc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, ACORN_LC, tag, owner, clock)
+ //, device_memory_interface(mconfig, *this)
+ //, device_palette_interface(mconfig, *this)
+ //, device_video_interface(mconfig, *this)
+ , m_vdsr(0)
+ , m_vdlr(0)
+ , m_hdsr(0)
+ , m_hdlr(0)
+ , m_licr(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void acorn_lc_device::device_start()
+{
+ // state saving
+ save_item(NAME(m_vdsr));
+ save_item(NAME(m_vdlr));
+ save_item(NAME(m_hdsr));
+ save_item(NAME(m_hdlr));
+ save_item(NAME(m_licr));
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+u8 acorn_lc_device::read(offs_t offset)
+{
+ u8 data = 0xff;
+
+ switch (offset & 0x0f)
+ {
+ case LC_LICR_L:
+ data = m_licr & 0x0f;
+ break;
+ case LC_LICR_M:
+ data = (m_licr >> 4) & 0x0f;
+ break;
+ case LC_LICR_H:
+ data = (m_licr >> 8) & 0x0f;
+ break;
+
+ case LC_RESET:
+ data = 0x04;
+ break;
+ }
+ logerror("lc_r: % 04x % 02x\n", offset, data);
+ return data;
+}
+
+void acorn_lc_device::write(offs_t offset, u8 data)
+{
+ logerror("lc_w: % 04x % 02x\n", offset, data);
+ switch (offset & 0x0f)
+ {
+ case LC_VDSR_L:
+ m_vdsr = (m_vdsr & 0x0ff0) | (data & 0x0f);
+ break;
+ case LC_VDSR_M:
+ m_vdsr = (m_vdsr & 0x0f0f) | ((data & 0x0f) << 4);
+ break;
+ case LC_VDSR_H:
+ m_vdsr = (m_vdsr & 0x00ff) | ((data & 0x0f) << 8);
+ break;
+
+ case LC_VDLR_L:
+ m_vdlr = (m_vdlr & 0x0ff0) | (data & 0x0f);
+ break;
+ case LC_VDLR_M:
+ m_vdlr = (m_vdlr & 0x0f0f) | ((data & 0x0f) << 4);
+ break;
+ case LC_VDLR_H:
+ m_vdlr = (m_vdlr & 0x00ff) | ((data & 0x0f) << 8);
+ break;
+
+ case LC_HDSR_L:
+ m_hdsr = (m_hdsr & 0x0ff0) | (data & 0x0f);
+ break;
+ case LC_HDSR_M:
+ m_hdsr = (m_hdsr & 0x0f0f) | ((data & 0x0f) << 4);
+ break;
+ case LC_HDSR_H:
+ m_hdsr = (m_hdsr & 0x00ff) | ((data & 0x0f) << 8);
+ break;
+
+ case LC_HDLR_L:
+ m_hdlr = (m_hdlr & 0x0ff0) | (data & 0x0f);
+ break;
+ case LC_HDLR_M:
+ m_hdlr = (m_hdlr & 0x0f0f) | ((data & 0x0f) << 4);
+ break;
+ case LC_HDLR_H:
+ m_hdlr = (m_hdlr & 0x00ff) | ((data & 0x0f) << 8);
+ break;
+
+ case LC_LICR_L:
+ m_licr = (m_licr & 0x0ff0) | (data & 0x0f);
+ break;
+ case LC_LICR_M:
+ m_licr = (m_licr & 0x0f0f) | ((data & 0x0f) << 4);
+ switch (m_licr & LICR_CLOCK_MASK)
+ {
+ case LICR_CLOCK_CRYS:
+ //m_vidc->set_unscaled_clock(24_MHz_XTAL);
+ break;
+ case LICR_CLOCK_CRYS2:
+ //m_vidc->set_unscaled_clock(24_MHz_XTAL / 2);
+ break;
+ case LICR_CLOCK_IOEB:
+ default:
+ //m_vidc->set_unscaled_cloc(ioeb_clock_select);
+ break;
+ }
+ break;
+ case LC_LICR_H:
+ m_licr = (m_licr & 0x00ff) | ((data & 0x0f) << 8);
+ break;
+ }
+ //if (offset & 0x40)
+ //pal[(offset >> 2) & 0xf] = lc_palette[data & 0xf];
+}
diff --git a/src/devices/machine/acorn_lc.h b/src/devices/machine/acorn_lc.h
new file mode 100644
index 00000000000..8367c90fdf1
--- /dev/null
+++ b/src/devices/machine/acorn_lc.h
@@ -0,0 +1,85 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ Acorn LC ASIC
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_ACORN_LC_H
+#define MAME_MACHINE_ACORN_LC_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> acorn_lc_device
+
+class acorn_lc_device : public device_t
+ //public device_memory_interface,
+ //public device_palette_interface,
+ //public device_video_interface
+{
+public:
+ acorn_lc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+private:
+
+ enum
+ {
+ // VDSR = 512 - lines from start of VSYNC to start of display
+ LC_VDSR_L = 0,
+ LC_VDSR_M,
+ LC_VDSR_H,
+
+ // VDLC = lines per panel - 3
+ LC_VDLR_L,
+ LC_VDLR_M,
+ LC_VDLR_H,
+
+ // HDSR = 2047 - pixels of HSYNC + back porch
+ LC_HDSR_L,
+ LC_HDSR_M,
+ LC_HDSR_H,
+
+ // HDLR = horizontal display pixels / 8
+ LC_HDLR_L,
+ LC_HDLR_M ,
+ LC_HDLR_H,
+
+ LC_LICR_L,
+ LC_LICR_M,
+ LC_LICR_H,
+
+ LC_RESET,
+ };
+
+ enum
+ {
+ LICR_CLOCK_IOEB = 0 << 5,
+ LICR_CLOCK_CRYS2 = 1 << 5,
+ LICR_CLOCK_CRYS = 2 << 5,
+ LICR_CLOCK_MASK = 3 << 5
+ };
+
+ u32 m_vdsr;
+ u32 m_vdlr;
+ u32 m_hdsr;
+ u32 m_hdlr;
+ u32 m_licr;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(ACORN_LC, acorn_lc_device)
+
+#endif // MAME_MACHINE_ACORN_LC_H
diff --git a/src/devices/machine/acorn_memc.cpp b/src/devices/machine/acorn_memc.cpp
new file mode 100644
index 00000000000..8056c85d785
--- /dev/null
+++ b/src/devices/machine/acorn_memc.cpp
@@ -0,0 +1,512 @@
+// license:LGPL-2.1+
+// copyright-holders:Angelo Salese, R. Belmont, Juergen Buchmueller, Sandro Ronco
+/**************************************************************************************************
+
+ Acorn RISC Machine Memory Controller (MEMC)
+
+ TODO:
+ - VIDC DMA interface needs to be cleaned up.
+ - Slave mode.
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "acorn_memc.h"
+
+#include "debug/debugcon.h"
+#include "debugger.h"
+
+#include <functional>
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(ACORN_MEMC, acorn_memc_device, "memc", "Acorn MEMC")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+acorn_memc_device::acorn_memc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ACORN_MEMC, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , m_vidc(*this, finder_base::DUMMY_TAG)
+ , m_space_config("memc", ENDIANNESS_LITTLE, 32, 26, 0)
+ , m_abort_w(*this)
+ , m_sirq_w(*this)
+ , m_output_dram_rowcol(false)
+{
+}
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector acorn_memc_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+void acorn_memc_device::memc_map_debug_commands(const std::vector<std::string_view> &params)
+{
+ uint64_t offset;
+ if (params.size() != 1 || !machine().debugger().console().validate_number_parameter(params[0], offset))
+ return;
+
+ // figure out the page number and offset in the page
+ uint32_t pagesize = m_page_sizes[m_pagesize];
+ uint32_t page = offset / pagesize;
+ uint32_t poffs = offset % pagesize;
+
+ machine().debugger().console().printf("0x%08lx == ", offset);
+ if (offset >= 0x02000000)
+ machine().debugger().console().printf("physical\n");
+ else if (m_pages[page] == -1)
+ machine().debugger().console().printf("unmapped\n");
+ else
+ machine().debugger().console().printf("0x%08lx (PPL %x)\n", 0x02000000 | ((m_pages[page] * pagesize) + poffs), m_pages_ppl[page]);
+}
+
+void acorn_memc_device::device_start()
+{
+ m_space = &space();
+
+ save_item(NAME(m_spvmd));
+ save_item(NAME(m_pagesize));
+ save_item(NAME(m_latchrom));
+ save_item(NAME(m_video_dma_on));
+ save_item(NAME(m_sound_dma_on));
+ save_item(NAME(m_cursor_enabled));
+ save_item(NAME(m_os_mode));
+ save_item(NAME(m_vidinit));
+ save_item(NAME(m_vidstart));
+ save_item(NAME(m_vidend));
+ save_item(NAME(m_vidcur));
+ save_item(NAME(m_cinit));
+ save_item(NAME(m_sndstart));
+ save_item(NAME(m_sndend));
+ save_item(NAME(m_sndcur));
+ save_item(NAME(m_sndendcur));
+ save_item(NAME(m_pages));
+ save_item(NAME(m_pages_ppl));
+
+ if (machine().debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ using namespace std::placeholders;
+ machine().debugger().console().register_command("memc_map", CMDFLAG_NONE, 1, 1, std::bind(&acorn_memc_device::memc_map_debug_commands, this, _1));
+ }
+}
+
+void acorn_memc_device::device_reset()
+{
+ m_latchrom = true; // map in the boot ROM
+ m_pagesize = 0;
+ m_video_dma_on = false;
+ m_sound_dma_on = false;
+ m_cursor_enabled = false;
+ m_os_mode = false;
+ m_vidinit = 0;
+ m_vidstart = 0;
+ m_vidend = 0;
+ m_vidcur = 0;
+ m_cinit = 0;
+ m_sndstart = 0;
+ m_sndend = 0;
+ m_sndcur = 0;
+ m_sndendcur = 0;
+ m_spvmd = ASSERT_LINE;
+
+ // kill all MEMC mappings
+ std::fill(std::begin(m_pages), std::end(m_pages), -1); // indicate unmapped
+ std::fill(std::begin(m_pages_ppl), std::end(m_pages_ppl), 0);
+}
+
+uint32_t acorn_memc_device::invalid_access(bool is_write, offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ {
+ if (is_write)
+ logerror("abort W 0x%08x 0x%08x (0x%08x)\n", offset << 2, data, mem_mask);
+ else
+ logerror("abort R 0x%08x (0x%08x)\n", offset << 2, mem_mask);
+
+ m_abort_w(ASSERT_LINE);
+ }
+
+ return 0xdeadbeef;
+}
+
+bool acorn_memc_device::is_valid_access(int page, bool write)
+{
+ if (m_pages[page] != -1)
+ {
+ if (m_spvmd || machine().side_effects_disabled())
+ return true;
+
+ switch (m_pages_ppl[page])
+ {
+ case 0: return true;
+ case 1: return m_os_mode || (write == false);
+ case 2: return m_os_mode && (write == false);
+ case 3: return m_os_mode && (write == false);
+ }
+ }
+
+ return false;
+}
+
+void acorn_memc_device::registers_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ // is it a register?
+ if ((data & 0x03e00000) != 0x03600000)
+ return;
+
+ LOG("%s: MEMC W %02x = %04x\n", machine().describe_context(), (data >> 17) & 7, data & 0xffff);
+
+ switch ((data >> 17) & 7)
+ {
+ case 0: // Video init
+ m_vidinit = ((data >> 2) & 0x7fff) * 16;
+ break;
+
+ case 1: // Video start
+ m_vidstart = ((data >> 2) & 0x7fff) * 16;
+ break;
+
+ case 2: // Video end
+ m_vidend = ((data >> 2) & 0x7fff) * 16;
+ break;
+
+ case 3: // Cursor init
+ m_cursor_enabled = true;
+ if (m_vidc.found())
+ m_vidc->set_cursor_enable(m_cursor_enabled);
+
+ m_cinit = ((data >> 2) & 0x7fff) * 16;
+ break;
+
+ case 4: // Sound start
+ m_sirq_w(CLEAR_LINE);
+ m_sndstart = ((data >> 2) & 0x7fff) * 16;
+ break;
+
+ case 5: // Sound end
+ // end buffer is actually +16 bytes wrt sound start
+ // TODO: it actually don't apply for ertictac and poizone?
+ m_sndend = ((data >> 2) & 0x7fff) * 16;
+ break;
+
+ case 6: // Sound pointer
+ m_sndcur = m_sndstart;
+ m_sndendcur = m_sndend;
+ m_sirq_w(ASSERT_LINE);
+ break;
+
+ case 7: // Control
+ // --x- ---- ---- ---- Test Mode
+ // ---x ---- ---- ---- OS Mode
+ // ---- x--- ---- ---- Sound DMA
+ // ---- -x-- ---- ---- Video DMA
+ // ---- --xx ---- ---- DRAM refresh config
+ // ---- ---- xx-- ---- High ROM access time
+ // ---- ---- --xx ---- Low ROM access time
+ // ---- ---- ---- xx-- Page size
+ // ---- ---- ---- --xx Not used
+
+ m_pagesize = BIT(data, 2, 2);
+ m_video_dma_on = BIT(data, 10);
+ m_sound_dma_on = BIT(data, 11);
+ m_os_mode = BIT(data, 12);
+
+ LOG("%s MEMC: %x to Control (page size %d, %s, %s)\n", machine().describe_context(), data & 0x1ffc, m_page_sizes[m_pagesize], m_video_dma_on ? "Video DMA on" : "Video DMA off", m_sound_dma_on ? "Sound DMA on" : "Sound DMA off");
+
+ if (m_video_dma_on)
+ {
+ m_vidcur = 0;
+ // TODO: update internally
+ }
+ else
+ {
+ m_cursor_enabled = false;
+ if (m_vidc.found())
+ m_vidc->set_cursor_enable(m_cursor_enabled);
+ }
+
+ if (m_vidc.found())
+ m_vidc->update_sound_mode(m_sound_dma_on);
+
+ if (m_sound_dma_on)
+ {
+ //logerror("MEMC: Starting audio DMA at %d uSec, buffer from %x to %x\n", ((m_regs[0xc0]&0xff)-2)*8, m_sndstart, m_sndend);
+ //logerror("MEMC: audio DMA start, sound freq %d, sndhz = %f\n", (m_regs[0xc0] & 0xff)-2, sndhz);
+
+ m_sndcur = m_sndstart;
+ m_sndendcur = m_sndend;
+ }
+ break;
+ default:
+ logerror("MEMC: %06x to unknown reg %d\n", data & 0x1ffff, (data >> 17) & 7);
+ break;
+ }
+}
+
+
+//**************************************************************************
+//
+// 22 2222 1111 1111 1100 0000 0000
+// 54 3210 9876 5432 1098 7654 3210
+// 4k page: 11 1LLL LLLL LLLL LLAA MPPP PPPP
+// 8k page: 11 1LLL LLLL LLLM LLAA MPPP PPPP
+// 16k page: 11 1LLL LLLL LLxM LLAA MPPP PPPP
+// 32k page: 11 1LLL LLLL LxxM LLAA MPPP PPPP
+// 3 8 2 9 0 f f
+//
+// L - logical page
+// P - physical page
+// A - access permissions
+// M - MEMC number (for machines with multiple MEMCs)
+//
+// The logical page is encoded with bits 11+10 being the most significant bits
+// (in that order), and the rest being bit 22 down.
+//
+// The physical page is encoded differently depending on the page size :
+//
+// 4k page: bits 6-0 being bits 6-0
+// 8k page: bits 6-1 being bits 5-0, bit 0 being bit 6
+// 16k page: bits 6-2 being bits 4-0, bits 1-0 being bits 6-5
+// 32k page: bits 6-3 being bits 4-0, bit 0 being bit 4, bit 2 being bit 5, bit 1 being bit 6
+//
+//**************************************************************************
+
+void acorn_memc_device::page_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ uint32_t logaddr = 0;
+ uint32_t phyaddr = 0;
+ uint32_t memc = 0;
+
+ switch (m_pagesize)
+ {
+ case 0:
+ phyaddr = BIT(data, 0, 7);
+ logaddr = BIT(data, 12, 11) | (BIT(data, 10, 2) << 11);
+ memc = BIT(data, 7);
+ break;
+
+ case 1:
+ phyaddr = BIT(data, 1, 6) | (BIT(data, 0) << 6);
+ logaddr = BIT(data, 13, 10) | (BIT(data, 10, 2) << 10);
+ memc = BIT(data, 7) | (BIT(data, 12) << 1);
+ break;
+
+ case 2:
+ phyaddr = BIT(data, 2, 5) | (BIT(data, 0, 2) << 5);
+ logaddr = BIT(data, 14, 9) | (BIT(data, 10, 2) << 9);
+ memc = BIT(data, 7) | (BIT(data, 12) << 1);
+ break;
+
+ case 3:
+ phyaddr = BIT(data, 3, 4) | (BIT(data, 0) << 4) | (BIT(data, 1) << 6) | (BIT(data, 2) << 5);
+ logaddr = BIT(data, 15, 8) | (BIT(data, 10, 2) << 8);
+ memc = BIT(data, 7) | (BIT(data, 12) << 1);
+ break;
+ }
+
+ // always make sure ROM mode is disconnected when this occurs
+ m_latchrom = false;
+
+ phyaddr += memc * 0x80;
+
+ // unmap all logical pages that resolve to the same physical address
+ for (int i=0; i < 0x2000; i++)
+ if (m_pages[i] == phyaddr)
+ m_pages[i] = -1;
+
+ // now go ahead and set the mapping in the page table
+ m_pages[logaddr] = phyaddr;
+ m_pages_ppl[logaddr] = BIT(data, 8, 2);
+
+ LOG("%s = MEMC_PAGE(%d): W %08x: logaddr %08x to phyaddr %08x, MEMC %d, perms %d\n", machine().describe_context(), m_pages[logaddr], data, logaddr * m_page_sizes[m_pagesize], phyaddr * m_page_sizes[m_pagesize], memc, m_pages_ppl[logaddr]);
+}
+
+
+// TODO: what type of DMA this is, burst or cycle steal? Docs doesn't explain it (4 usec is the DRAM refresh). */
+// TODO: Erotictac and Poizone sets up vidinit register AFTER vidend, for double buffering? (fixes Poizone "Eterna" logo display on attract)
+// TODO: understand how to make quazer to work (sets video DMA param in-flight)
+void acorn_memc_device::do_video_dma()
+{
+ uint32_t size = (m_vidend - m_vidstart + 0x10) & 0x1fffff;
+ uint32_t offset_ptr = m_vidinit;
+
+ if (offset_ptr >= m_vidend + 0x10) // TODO: correct?
+ offset_ptr = m_vidstart;
+
+ //popmessage("%08x %08x %08x",m_vidstart, m_vidinit, m_vidend);
+
+ if (m_vidc.found())
+ {
+ for (m_vidcur = 0; m_vidcur < size; m_vidcur++)
+ {
+ m_vidc->write_vram(m_vidcur, m_space->read_byte(dram_address((offset_ptr))));
+ offset_ptr++;
+ if (offset_ptr >= m_vidend + 0x10) // TODO: correct?
+ offset_ptr = m_vidstart;
+ }
+
+ if (m_cursor_enabled)
+ {
+ uint16_t ccur_size = m_vidc->get_cursor_size() & 0x1ff;
+
+ for (int ccur = 0; ccur < ccur_size; ccur++)
+ m_vidc->write_cram(ccur, m_space->read_byte(dram_address((m_cinit + ccur))));
+ }
+ }
+}
+
+void acorn_memc_device::do_sound_dma()
+{
+ if (m_vidc.found())
+ {
+ for (int ch = 0; ch < 8; ch++)
+ m_vidc->write_dac(ch, m_space->read_byte(dram_address(m_sndcur + ch)));
+ }
+
+ m_sndcur += 8;
+
+ if (m_sndcur >= m_sndendcur)
+ {
+ m_sirq_w(ASSERT_LINE);
+
+ // TODO: nuke this implementation detail, repeated below
+ if (m_vidc.found())
+ m_vidc->update_sound_mode(m_sound_dma_on);
+
+ if (m_sound_dma_on)
+ {
+ //logerror("Chaining to next: start %x end %x\n", m_sndstart, m_sndend);
+ m_sndcur = m_sndstart;
+ m_sndendcur = m_sndend;
+ }
+ else if (m_vidc.found())
+ {
+ for (int ch=0; ch<8; ch++)
+ m_vidc->clear_dac(ch);
+ }
+ }
+}
+
+void acorn_memc_device::spvmd_w(int state)
+{
+ m_spvmd = state;
+ m_abort_w(CLEAR_LINE);
+}
+
+void acorn_memc_device::sndrq_w(int state)
+{
+ if (state && m_sound_dma_on)
+ do_sound_dma();
+}
+
+
+void acorn_memc_device::vidrq_w(int state)
+{
+ if (state && m_video_dma_on)
+ do_video_dma();
+}
+
+uint32_t acorn_memc_device::dram_address(uint32_t address)
+{
+ if (m_output_dram_rowcol)
+ {
+ // The correct DRAM row / column for every page size is shown in Appendix A of the Acorn MEMC datasheet
+ // xx-- ---- ---- ---- ---- ---- MEMC (for systems with multiple MEMC)
+ // --xx xxxx xxxx ---- ---- ---- DRAM row
+ // ---- ---- ---- xxxx xxxx xx-- DRAM column
+ // ---- ---- ---- ---- ---- --xx CAS
+
+ switch (m_pagesize)
+ {
+ // Page size MEMC Unused DRAM row Unused DRAM column CAS Mask unused
+ case 0: address = bitswap<24>(address, 23, 22, 21,20, 11,10,9,8,7,6,5,4, 19, 18,17,16,15,14,13,12,3,2, 1,0) & 0xcff7ff; break;
+ case 1: address = bitswap<24>(address, 23, 22, 21, 12,11,10,9,8,7,6,5,4, 20, 18,17,16,15,14,13,19,3,2, 1,0) & 0xdff7ff; break;
+ case 2: address = bitswap<24>(address, 23, 22, 21, 12,11,10,9,8,7,6,5,4, 20,18,17,16,15,14,13,19,3,2, 1,0) & 0xdfffff; break;
+ case 3: address = bitswap<24>(address, 23, 22, 13,12,11,10,9,8,7,6,5,4, 20,18,17,16,15,14,21,19,3,2, 1,0) & 0xffffff; break;
+ }
+ }
+
+ return 0x02000000 | address;
+}
+
+uint32_t acorn_memc_device::logical_r(offs_t offset, uint32_t mem_mask)
+{
+ // are we mapping in the boot ROM?
+ if (m_latchrom)
+ return m_space->read_dword(0x3800000 | ((offset & 0x1fffff) << 2), mem_mask);
+
+ // figure out the page number and offset in the page
+ uint32_t pagesize = m_page_sizes[m_pagesize];
+ uint32_t page = (offset << 2) / pagesize;
+ uint32_t poffs = (offset << 2) % pagesize;
+
+ if (is_valid_access(page, false))
+ return m_space->read_dword(dram_address(m_pages[page] * pagesize + poffs), mem_mask);
+ else
+ return invalid_access(false, offset, 0, mem_mask);
+}
+
+
+void acorn_memc_device::logical_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ // if the boot ROM is mapped, ignore writes
+ if (m_latchrom)
+ return;
+
+ // figure out the page number and offset in the page
+ uint32_t pagesize = m_page_sizes[m_pagesize];
+ uint32_t page = (offset << 2) / pagesize;
+ uint32_t poffs = (offset << 2) % pagesize;
+
+ if (is_valid_access(page, true))
+ m_space->write_dword(dram_address(m_pages[page] * pagesize + poffs), data, mem_mask);
+ else
+ invalid_access(true, offset, data, mem_mask);
+}
+
+
+uint32_t acorn_memc_device::high_mem_r(offs_t offset, uint32_t mem_mask)
+{
+ uint32_t addr = offset << 2;
+ if (!machine().side_effects_disabled())
+ m_latchrom = false;
+
+ if (!m_spvmd)
+ return invalid_access(false, addr, 0, mem_mask);
+ else if (addr < 0x1000000) // DRAM
+ return m_space->read_dword(dram_address(addr), mem_mask);
+ else
+ return m_space->read_dword(0x2000000 | addr, mem_mask);
+}
+
+void acorn_memc_device::high_mem_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ uint32_t addr = offset << 2;
+ m_latchrom = false;
+
+ if (!m_spvmd)
+ invalid_access(true, addr, data, mem_mask);
+ else if (addr < 0x1000000) // DRAM
+ m_space->write_dword(dram_address(addr), data, mem_mask);
+ else if (addr < 0x1400000) // Buffer enabled by IOC
+ {
+ if (ACCESSING_BITS_16_31)
+ {
+ data >>= 16;
+ mem_mask >>= 16;
+ }
+ m_space->write_dword(0x2000000 | addr, data, mem_mask);
+ }
+ else
+ m_space->write_dword(0x2000000 | addr, data, mem_mask);
+}
diff --git a/src/devices/machine/acorn_memc.h b/src/devices/machine/acorn_memc.h
new file mode 100644
index 00000000000..7977527fd31
--- /dev/null
+++ b/src/devices/machine/acorn_memc.h
@@ -0,0 +1,101 @@
+// license:LGPL-2.1+
+// copyright-holders:Angelo Salese, R. Belmont, Juergen Buchmueller, Sandro Ronco
+/**************************************************************************************************
+
+ Acorn RISC Machine Memory Controller (MEMC)
+
+**************************************************************************************************/
+
+#ifndef MAME_MACHINE_ACORN_MEMC_H
+#define MAME_MACHINE_ACORN_MEMC_H
+
+#pragma once
+
+#include "machine/acorn_vidc.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> acorn_memc_device
+
+class acorn_memc_device : public device_t, public device_memory_interface
+{
+public:
+ acorn_memc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T>
+ acorn_memc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&vidc_tag)
+ : acorn_memc_device(mconfig, tag, owner, clock)
+ {
+ m_vidc.set_tag(std::forward<T>(vidc_tag));
+ }
+
+ auto abort_w() { return m_abort_w.bind(); }
+ auto sirq_w() { return m_sirq_w.bind(); }
+
+ // enable/disable the output of the correct DRAM row and column for DRAM access.
+ // This allows to emulate the correct DRAM mirrors that are used by RISC OS to detect the installed RAM,
+ // but requires a bitswap on every access and is not required by machines with 2 or more MB of RAM.
+ void output_dram_rowcol(bool v) { m_output_dram_rowcol = v; }
+
+ uint32_t logical_r(offs_t offset, uint32_t mem_mask = ~0);
+ void logical_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ void page_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ void registers_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint32_t high_mem_r(offs_t offset, uint32_t mem_mask = ~0);
+ void high_mem_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+
+ void spvmd_w(int state);
+ void sndrq_w(int state);
+ void vidrq_w(int state);
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_memory_interface implementation
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ void memc_map_debug_commands(const std::vector<std::string_view> &params);
+ uint32_t dram_address(uint32_t address);
+ bool is_valid_access(int page, bool write);
+ uint32_t invalid_access(bool is_write, offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ void do_sound_dma();
+ void do_video_dma();
+
+ static constexpr const int m_page_sizes[4] = { 4096, 8192, 16384, 32768 };
+ optional_device<acorn_vidc10_device> m_vidc;
+ const address_space_config m_space_config;
+
+ address_space * m_space;
+ devcb_write_line m_abort_w;
+ devcb_write_line m_sirq_w;
+ bool m_output_dram_rowcol;
+ int m_spvmd;
+ uint8_t m_pagesize;
+ bool m_latchrom;
+ bool m_video_dma_on;
+ bool m_sound_dma_on;
+ bool m_cursor_enabled;
+ bool m_os_mode;
+ uint32_t m_vidinit;
+ uint32_t m_vidstart;
+ uint32_t m_vidend;
+ uint32_t m_vidcur;
+ uint32_t m_cinit;
+ uint32_t m_sndstart;
+ uint32_t m_sndend;
+ uint32_t m_sndcur;
+ uint32_t m_sndendcur;
+ int16_t m_pages[0x2000]; // the logical RAM area is 32 megs, and the smallest page size is 4k
+ uint8_t m_pages_ppl[0x2000];
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(ACORN_MEMC, acorn_memc_device)
+
+#endif // MAME_MACHINE_ACORN_MEMC_H
diff --git a/src/devices/machine/acorn_vidc.cpp b/src/devices/machine/acorn_vidc.cpp
index 3ea63a91740..ae4021e412f 100644
--- a/src/devices/machine/acorn_vidc.cpp
+++ b/src/devices/machine/acorn_vidc.cpp
@@ -12,8 +12,10 @@
* nebulus: 20 lines off with aa310;
* lotustc2: abuses color flipping;
* quazer: needs in-flight DMA;
- - improve sound DAC writes;
- - subclass this for VIDC20 emulation (RiscPC);
+ - move DAC handling into a separate sub-device(s),
+ particularly needed for proper VIDC20 mixing and likely for fixing aliasing
+ issues in VIDC10;
+ - complete VIDC20 emulation (RiscPC/ssfindo.cpp);
- Are CRTC values correct? VGA modes have a +1 in display line;
**********************************************************************************************/
@@ -28,8 +30,8 @@
//**************************************************************************
// device type definition
-DEFINE_DEVICE_TYPE(ACORN_VIDC10, acorn_vidc10_device, "acorn_vidc10", "Acorn VIDC10")
-DEFINE_DEVICE_TYPE(ACORN_VIDC10_LCD, acorn_vidc10_lcd_device, "acorn_vidc10_lcd", "Acorn VIDC10 with LCD monitor")
+DEFINE_DEVICE_TYPE(ACORN_VIDC1, acorn_vidc1_device, "acorn_vidc1", "Acorn VIDC1")
+DEFINE_DEVICE_TYPE(ACORN_VIDC1A, acorn_vidc1a_device, "acorn_vidc1a", "Acorn VIDC1a")
DEFINE_DEVICE_TYPE(ARM_VIDC20, arm_vidc20_device, "arm_vidc20", "ARM VIDC20")
@@ -52,7 +54,7 @@ void acorn_vidc10_device::regs_map(address_map &map)
}
-acorn_vidc10_device::acorn_vidc10_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+acorn_vidc10_device::acorn_vidc10_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int dac_type)
: device_t(mconfig, type, tag, owner, clock)
, device_memory_interface(mconfig, *this)
, device_palette_interface(mconfig, *this)
@@ -62,6 +64,7 @@ acorn_vidc10_device::acorn_vidc10_device(const machine_config &mconfig, device_t
, m_sound_frequency_latch(0)
, m_sound_mode(false)
, m_dac(*this, "dac%u", 0)
+ , m_dac_type(dac_type)
, m_lspeaker(*this, "lspeaker")
, m_rspeaker(*this, "rspeaker")
, m_vblank_cb(*this)
@@ -74,21 +77,19 @@ acorn_vidc10_device::acorn_vidc10_device(const machine_config &mconfig, device_t
std::fill(std::begin(m_stereo_image), std::end(m_stereo_image), 0);
}
-acorn_vidc10_device::acorn_vidc10_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : acorn_vidc10_device(mconfig, ACORN_VIDC10, tag, owner, clock)
+acorn_vidc1_device::acorn_vidc1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : acorn_vidc10_device(mconfig, ACORN_VIDC1, tag, owner, clock, 1)
{
- m_space_config = address_space_config("regs_space", ENDIANNESS_LITTLE, 32, 8, 0, address_map_constructor(FUNC(acorn_vidc10_device::regs_map), this));
+ m_space_config = address_space_config("regs_space", ENDIANNESS_LITTLE, 32, 8, 0, address_map_constructor(FUNC(acorn_vidc1_device::regs_map), this));
m_pal_4bpp_base = 0x100;
m_pal_cursor_base = 0x10;
m_pal_border_base = 0x110;
}
-
-acorn_vidc10_lcd_device::acorn_vidc10_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : acorn_vidc10_device(mconfig, ACORN_VIDC10_LCD, tag, owner, clock)
+acorn_vidc1a_device::acorn_vidc1a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : acorn_vidc10_device(mconfig, ACORN_VIDC1A, tag, owner, clock, 2)
{
- m_space_config = address_space_config("regs_space", ENDIANNESS_LITTLE, 32, 8, 0, address_map_constructor(FUNC(acorn_vidc10_lcd_device::regs_map), this));
- // TODO: confirm being identical to raster version
+ m_space_config = address_space_config("regs_space", ENDIANNESS_LITTLE, 32, 8, 0, address_map_constructor(FUNC(acorn_vidc1a_device::regs_map), this));
m_pal_4bpp_base = 0x100;
m_pal_cursor_base = 0x10;
m_pal_border_base = 0x110;
@@ -104,7 +105,7 @@ device_memory_interface::space_config_vector acorn_vidc10_device::memory_space_c
//-------------------------------------------------
// device_add_mconfig - device-specific machine
-// configuration addiitons
+// configuration additions
//-------------------------------------------------
void acorn_vidc10_device::device_add_mconfig(machine_config &config)
@@ -118,13 +119,7 @@ void acorn_vidc10_device::device_add_mconfig(machine_config &config)
}
}
-void acorn_vidc10_lcd_device::device_add_mconfig(machine_config &config)
-{
- acorn_vidc10_device::device_add_mconfig(config);
- // TODO: verify !Configure with automatic type detection, there must be an ID telling this is a LCD machine.
-}
-
-u32 acorn_vidc10_device::palette_entries() const
+u32 acorn_vidc10_device::palette_entries() const noexcept
{
return 0x100+0x10+4; // 8bpp + 1/2/4bpp + 2bpp for cursor
}
@@ -153,9 +148,6 @@ void acorn_vidc10_device::device_config_complete()
void acorn_vidc10_device::device_start()
{
- m_vblank_cb.resolve_safe();
- m_sound_drq_cb.resolve_safe();
-
for (int i = 0; i < entries(); i++)
set_pen_color(i, rgb_t::black());
@@ -173,17 +165,27 @@ void acorn_vidc10_device::device_start()
save_pointer(NAME(m_cursor_vram), m_cursor_vram_size);
save_pointer(NAME(m_stereo_image), m_sound_max_channels);
- m_video_timer = timer_alloc(TIMER_VIDEO);
- m_sound_timer = timer_alloc(TIMER_SOUND);
+ m_video_timer = timer_alloc(FUNC(acorn_vidc10_device::vblank_timer), this);
+ m_sound_timer = timer_alloc(FUNC(acorn_vidc10_device::sound_drq_timer), this);
// generate u255 law lookup table
// cfr. page 48 of the VIDC20 manual, page 33 of the VIDC manual
- // TODO: manual mentions a format difference between VIDC10 revisions
for (int rawval = 0; rawval < 256; rawval++)
{
- u8 chord = rawval >> 5;
- u8 point = (rawval & 0x1e) >> 1;
- bool sign = rawval & 1;
+ u8 chord, point;
+ bool sign;
+ if (m_dac_type == 1)
+ {
+ chord = (rawval & 0x70) >> 4;
+ point = rawval & 0x0f;
+ sign = rawval >> 7;
+ }
+ else
+ {
+ chord = rawval >> 5;
+ point = (rawval & 0x1e) >> 1;
+ sign = rawval & 1;
+ }
int16_t result = ((16+point)<<chord)-16;
if (sign)
@@ -205,28 +207,21 @@ void acorn_vidc10_device::device_reset()
{
m_cursor_enable = false;
memset(m_stereo_image, 4, m_sound_max_channels);
- for (int ch=0;ch<m_sound_max_channels;ch++)
+ for (int ch = 0; ch < m_sound_max_channels; ch++)
refresh_stereo_image(ch);
m_video_timer->adjust(attotime::never);
m_sound_timer->adjust(attotime::never);
}
-//-------------------------------------------------
-// device_timer - device-specific timer
-//-------------------------------------------------
+TIMER_CALLBACK_MEMBER(acorn_vidc10_device::vblank_timer)
+{
+ m_vblank_cb(ASSERT_LINE);
+ screen_vblank_line_update();
+}
-void acorn_vidc10_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(acorn_vidc10_device::sound_drq_timer)
{
- switch (id)
- {
- case TIMER_VIDEO:
- m_vblank_cb(ASSERT_LINE);
- screen_vblank_line_update();
- break;
- case TIMER_SOUND:
- m_sound_drq_cb(ASSERT_LINE);
- break;
- }
+ m_sound_drq_cb(ASSERT_LINE);
}
//**************************************************************************
@@ -300,13 +295,11 @@ void acorn_vidc10_device::write(offs_t offset, u32 data, u32 mem_mask)
inline void acorn_vidc10_device::update_4bpp_palette(u16 index, u32 paldata)
{
- int r,g,b;
-
// TODO: for TV Tuner we need to output this, also check if cursor mode actually sets this up for offset = 0
// i = (paldata & 0x1000) >> 12; //supremacy bit
- b = (paldata & 0x0f00) >> 8;
- g = (paldata & 0x00f0) >> 4;
- r = (paldata & 0x000f) >> 0;
+ int b = (paldata & 0x0f00) >> 8;
+ int g = (paldata & 0x00f0) >> 4;
+ int r = (paldata & 0x000f) >> 0;
set_pen_color(index, pal4bit(r), pal4bit(g), pal4bit(b) );
screen().update_partial(screen().vpos());
@@ -314,11 +307,11 @@ inline void acorn_vidc10_device::update_4bpp_palette(u16 index, u32 paldata)
void acorn_vidc10_device::pal_data_display_w(offs_t offset, u32 data)
{
- update_4bpp_palette(offset+0x100, data);
+ update_4bpp_palette(offset + 0x100, data);
//printf("%02x: %01x %01x %01x [%d]\n",offset,r,g,b,screen().vpos());
// 8bpp
- for(int idx=0;idx<0x100;idx+=0x10)
+ for (int idx = 0; idx < 0x100; idx += 0x10)
{
int b = ((data & 0x700) >> 8) | ((idx & 0x80) >> 4);
int g = ((data & 0x030) >> 4) | ((idx & 0x60) >> 3);
@@ -412,8 +405,8 @@ inline void acorn_vidc10_device::refresh_stereo_image(u8 channel)
const float left_gain[8] = { 1.0f, 2.0f, 1.66f, 1.34f, 1.0f, 0.66f, 0.34f, 0.0f };
const float right_gain[8] = { 1.0f, 0.0f, 0.34f, 0.66f, 1.0f, 1.34f, 1.66f, 2.0f };
- m_lspeaker->set_input_gain(channel,left_gain[m_stereo_image[channel]]*m_sound_input_gain);
- m_rspeaker->set_input_gain(channel,right_gain[m_stereo_image[channel]]*m_sound_input_gain);
+ m_lspeaker->set_input_gain(channel, left_gain[m_stereo_image[channel]] * m_sound_input_gain);
+ m_rspeaker->set_input_gain(channel, right_gain[m_stereo_image[channel]] * m_sound_input_gain);
//printf("%d %f %f\n",channel,m_lspeaker->input(channel).gain(),m_rspeaker->input(channel).gain());
}
@@ -439,8 +432,7 @@ void acorn_vidc10_device::sound_frequency_w(u32 data)
void acorn_vidc10_device::write_dac(u8 channel, u8 data)
{
- int16_t res;
- res = m_ulaw_lookup[data];
+ int16_t res = m_ulaw_lookup[data];
m_dac[channel & 7]->write(res);
}
@@ -451,7 +443,7 @@ void acorn_vidc10_device::refresh_sound_frequency()
{
// TODO: Range is between 3 and 256 usecs
double sndhz = 1e6 / ((m_sound_frequency_latch & 0xff) + 2);
- sndhz /= m_sound_internal_divider;
+ sndhz /= get_dac_mode() == true ? 2.0 : 8.0;
m_sound_timer->adjust(attotime::zero, 0, attotime::from_hz(sndhz));
//printf("VIDC: audio DMA start, sound freq %d, sndhz = %f\n", (m_crtc_regs[0xc0] & 0xff)-2, sndhz);
}
@@ -476,17 +468,17 @@ void acorn_vidc10_device::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect,
//printf("%d %d %d %d\n",ystart, ysize, cliprect.min_y, cliprect.max_y);
- for (int srcy = raster_ystart; srcy<ysize; srcy++)
+ for (int srcy = raster_ystart; srcy < ysize; srcy++)
{
- int dsty = (srcy + ystart)*(m_crtc_interlace+1);
- for (int srcx = 0; srcx<xsize; srcx++)
+ int dsty = (srcy + ystart) * (m_crtc_interlace+1);
+ for (int srcx = 0; srcx < xsize; srcx++)
{
u8 pen = vram[srcx + srcy * xsize];
int dstx = (srcx*xchar_size) + xstart;
- for (int xi=0;xi<xchar_size;xi++)
+ for (int xi = 0; xi < xchar_size; xi++)
{
- u16 dot = ((pen>>(xi*pen_byte_size)) & pen_mask);
+ u16 dot = (pen >> (xi * pen_byte_size)) & pen_mask;
if (is_cursor == true && dot == 0)
continue;
dot += pen_base;
@@ -500,29 +492,25 @@ void acorn_vidc10_device::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect,
u32 acorn_vidc10_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int xstart,ystart,xend,yend;
- int xsize,ysize;
- int calc_dxs = 0,calc_dxe = 0;
-
/* border color */
bitmap.fill(pen(m_pal_border_base), cliprect);
/* define X display area through BPP mode register */
- calc_dxs = m_crtc_regs[CRTC_HDSR];
- calc_dxe = m_crtc_regs[CRTC_HDER];
+ int calc_dxs = m_crtc_regs[CRTC_HDSR];
+ int calc_dxe = m_crtc_regs[CRTC_HDER];
/* now calculate display clip rectangle start/end areas */
- xstart = (calc_dxs)-m_crtc_regs[CRTC_HBSR];
- ystart = (m_crtc_regs[CRTC_VDSR]-m_crtc_regs[CRTC_VBSR]);
- xend = (calc_dxe)+xstart;
- yend = (m_crtc_regs[CRTC_VDER] * (m_crtc_interlace+1))+ystart;
+ int xstart = (calc_dxs)-m_crtc_regs[CRTC_HBSR];
+ int ystart = (m_crtc_regs[CRTC_VDSR]-m_crtc_regs[CRTC_VBSR]);
+ int xend = (calc_dxe)+xstart;
+ int yend = (m_crtc_regs[CRTC_VDER] * (m_crtc_interlace+1))+ystart;
/* disable the screen if display params are invalid */
if(xstart > xend || ystart > yend)
return 0;
- xsize = calc_dxe-calc_dxs;
- ysize = m_crtc_regs[CRTC_VDER]-m_crtc_regs[CRTC_VDSR];
+ int xsize = calc_dxe-calc_dxs;
+ int ysize = m_crtc_regs[CRTC_VDER]-m_crtc_regs[CRTC_VDSR];
if (xsize <= 0 || ysize <= 0)
return 0;
@@ -541,7 +529,7 @@ u32 acorn_vidc10_device::screen_update(screen_device &screen, bitmap_rgb32 &bitm
return 0;
}
-READ_LINE_MEMBER(acorn_vidc10_device::flyback_r )
+int acorn_vidc10_device::flyback_r()
{
int vert_pos = screen().vpos();
if (vert_pos <= m_crtc_regs[CRTC_VDSR] * (m_crtc_interlace+1))
@@ -553,7 +541,11 @@ READ_LINE_MEMBER(acorn_vidc10_device::flyback_r )
return false;
}
-// VIDC20
+/*
+ *
+ * VIDC20 overrides
+ *
+ */
void arm_vidc20_device::regs_map(address_map &map)
{
@@ -561,6 +553,7 @@ void arm_vidc20_device::regs_map(address_map &map)
map(0x10, 0x1f).w(FUNC(arm_vidc20_device::vidc20_pal_data_index_w));
map(0x40, 0x7f).w(FUNC(arm_vidc20_device::vidc20_pal_data_cursor_w));
map(0x80, 0x9f).w(FUNC(arm_vidc20_device::vidc20_crtc_w));
+// map(0xa0, 0xa7) stereo image
map(0xb0, 0xb0).w(FUNC(arm_vidc20_device::vidc20_sound_frequency_w));
map(0xb1, 0xb1).w(FUNC(arm_vidc20_device::vidc20_sound_control_w));
map(0xd0, 0xdf).w(FUNC(arm_vidc20_device::fsynreg_w));
@@ -568,7 +561,8 @@ void arm_vidc20_device::regs_map(address_map &map)
}
arm_vidc20_device::arm_vidc20_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : acorn_vidc10_device(mconfig, ARM_VIDC20, tag, owner, clock)
+ : acorn_vidc10_device(mconfig, ARM_VIDC20, tag, owner, clock, 2)
+ , m_dac32(*this, "serial_dac_%u", 0)
{
m_space_config = address_space_config("regs_space", ENDIANNESS_LITTLE, 32, 8, -2, address_map_constructor(FUNC(arm_vidc20_device::regs_map), this));
m_pal_4bpp_base = 0x000;
@@ -580,8 +574,20 @@ arm_vidc20_device::arm_vidc20_device(const machine_config &mconfig, const char *
void arm_vidc20_device::device_add_mconfig(machine_config &config)
{
acorn_vidc10_device::device_add_mconfig(config);
- // ...
- // TODO: for simplicity we may as well add separate DACs for 32-bit mode
+
+ // FIXME: disable DACs for the time being
+ // so that it won't mixin with QS1000 source for ssfindo.cpp games
+ for (int i = 0; i < m_sound_max_channels; i++)
+ {
+ m_dac[i]->reset_routes();
+ m_dac[i]->add_route(0, m_lspeaker, 0.0);
+ m_dac[i]->add_route(0, m_rspeaker, 0.0);
+ }
+
+ // For simplicity we separate DACs for 32-bit mode
+ // TODO: how stereo image copes with this if at all?
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac32[0], 0).add_route(ALL_OUTPUTS, m_lspeaker, 0.25);
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac32[1], 0).add_route(ALL_OUTPUTS, m_rspeaker, 0.25);
}
void arm_vidc20_device::device_config_complete()
@@ -596,7 +602,7 @@ void arm_vidc20_device::device_config_complete()
screen().set_screen_update(*this, FUNC(arm_vidc20_device::screen_update));
}
-u32 arm_vidc20_device::palette_entries() const
+u32 arm_vidc20_device::palette_entries() const noexcept
{
return 0x100+4; // 8bpp + 2bpp for cursor
}
@@ -620,22 +626,31 @@ void arm_vidc20_device::device_reset()
// TODO: sensible defaults
m_vco_r_modulo = 1;
m_vco_v_modulo = 1;
+
+ // make sure DACs don't output any undefined behaviour for now
+ // (will cause wild DC offset in ssfindo.cpp games)
+ for (int ch = 0; ch < 8; ch ++)
+ write_dac(ch, 0);
+
+ write_dac32(0, 0);
+ write_dac32(1, 0);
}
-void arm_vidc20_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+inline void arm_vidc20_device::refresh_stereo_image(u8 channel)
{
- acorn_vidc10_device::device_timer(timer, id, param, ptr);
+ // TODO: set_input_gain hampers with both QS1000 and serial DAC mode
+ // Best option is to move the legacy DAC handling into a separate device,
+ // make it proper 8 channel output while clients are responsible of mix-ins
}
+
inline void arm_vidc20_device::update_8bpp_palette(u16 index, u32 paldata)
{
- int r,g,b;
-
// TODO: ext hookup, supremacy plus other stuff according to the manual
// ext = (paldata & 0x0f000000) >> 24;
- b = (paldata & 0x00ff0000) >> 16;
- g = (paldata & 0x0000ff00) >> 8;
- r = (paldata & 0x000000ff) >> 0;
+ int b = (paldata & 0x00ff0000) >> 16;
+ int g = (paldata & 0x0000ff00) >> 8;
+ int r = (paldata & 0x000000ff) >> 0;
set_pen_color(index, r, g, b );
screen().update_partial(screen().vpos());
@@ -729,7 +744,7 @@ void arm_vidc20_device::vidc20_control_w(u32 data)
// ---- --00: VCLK
// ---- --01: HCLK
// ---- --10: RCLK ("recommended" 24 MHz)
- // ---- --11: undefined, prolly same as RCLK
+ // ---- --11: undefined, probably same as RCLK
m_pixel_source = data & 3;
m_pixel_rate = (data & 0x1c) >> 2;
// (data & 0x700) >> 8 FIFO load
@@ -747,6 +762,26 @@ void arm_vidc20_device::vidc20_sound_control_w(u32 data)
{
// TODO: VIDC10 mode, ext clock bit 0
m_dac_serial_mode = BIT(data, 1);
+
+ if (m_dac_serial_mode)
+ {
+ m_dac32[0]->set_output_gain(0, 1.0);
+ m_dac32[1]->set_output_gain(0, 1.0);
+
+ for (int ch = 0; ch < m_sound_max_channels; ch++)
+ m_dac[ch]->set_output_gain(0, 0.0);
+ }
+ else
+ {
+ m_dac32[0]->set_output_gain(0, 0.0);
+ m_dac32[1]->set_output_gain(0, 0.0);
+
+ for (int ch = 0; ch < m_sound_max_channels; ch++)
+ {
+ //m_dac[ch]->set_output_gain(0, 0.0);
+ refresh_stereo_image(ch);
+ }
+ }
}
void arm_vidc20_device::vidc20_sound_frequency_w(u32 data)
@@ -758,7 +793,7 @@ void arm_vidc20_device::vidc20_sound_frequency_w(u32 data)
void arm_vidc20_device::write_dac32(u8 channel, u16 data)
{
- m_dac[channel & 1]->write(data);
+ m_dac32[channel & 1]->write(data);
}
bool arm_vidc20_device::get_dac_mode()
@@ -771,5 +806,3 @@ u32 arm_vidc20_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
// TODO: support for true color modes
return acorn_vidc10_device::screen_update(screen, bitmap, cliprect);
}
-
-
diff --git a/src/devices/machine/acorn_vidc.h b/src/devices/machine/acorn_vidc.h
index 2bf2bcde1de..436ee7a920b 100644
--- a/src/devices/machine/acorn_vidc.h
+++ b/src/devices/machine/acorn_vidc.h
@@ -32,12 +32,9 @@ class acorn_vidc10_device : public device_t,
public device_video_interface
{
public:
- // construction/destruction
- acorn_vidc10_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
-
// I/O operations
void write(offs_t offset, u32 data, u32 mem_mask = ~0);
- DECLARE_READ_LINE_MEMBER( flyback_r );
+ int flyback_r();
auto vblank() { return m_vblank_cb.bind(); }
auto sound_drq() { return m_sound_drq_cb.bind(); }
// MEMC comms
@@ -49,22 +46,27 @@ public:
void set_cursor_enable(bool state) { m_cursor_enable = state; }
u32 get_cursor_size() { return (m_crtc_regs[CRTC_VCER] - m_crtc_regs[CRTC_VCSR]) * (32/4); }
+ virtual bool get_dac_mode() { return false; }
+
protected:
- acorn_vidc10_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+ acorn_vidc10_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int dac_type);
// device-level overrides
//virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_add_mconfig(machine_config &config) override;
- virtual u32 palette_entries() const override;
+ virtual u32 palette_entries() const noexcept override;
virtual void device_config_complete() override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual space_config_vector memory_space_config() const override;
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
virtual u32 get_pixel_clock();
+ TIMER_CALLBACK_MEMBER(vblank_timer);
+ TIMER_CALLBACK_MEMBER(sound_drq_timer);
+
address_space_config m_space_config;
+
void regs_map(address_map &map);
enum {
@@ -72,10 +74,6 @@ protected:
CRTC_VCR, CRTC_VSWR, CRTC_VBSR, CRTC_VDSR, CRTC_VDER, CRTC_VBER, CRTC_VCSR, CRTC_VCER
};
u32 m_crtc_regs[16];
- enum {
- TIMER_VIDEO = 1,
- TIMER_SOUND = 2
- };
inline void screen_vblank_line_update();
inline void screen_dynamic_res_change();
@@ -84,17 +82,20 @@ protected:
u16 m_pal_4bpp_base;
u16 m_pal_cursor_base;
u16 m_pal_border_base;
- const double m_sound_internal_divider = 8.0;
u8 m_bpp_mode, m_crtc_interlace;
u8 m_sound_frequency_latch;
bool m_sound_mode;
required_device_array<dac_16bit_r2r_twos_complement_device, 8> m_dac;
+ int m_dac_type;
-private:
required_device<speaker_device> m_lspeaker;
required_device<speaker_device> m_rspeaker;
+
+ virtual void refresh_stereo_image(u8 channel);
+ const int m_sound_max_channels = 8;
+private:
devcb_write_line m_vblank_cb;
devcb_write_line m_sound_drq_cb;
@@ -126,23 +127,26 @@ private:
bool m_sound_frequency_test_bit;
u8 m_stereo_image[8];
const float m_sound_input_gain = 0.05f;
- const int m_sound_max_channels = 8;
int16_t m_ulaw_lookup[256];
- inline void refresh_stereo_image(u8 channel);
};
-class acorn_vidc10_lcd_device : public acorn_vidc10_device
+class acorn_vidc1_device : public acorn_vidc10_device
{
public:
// construction/destruction
- acorn_vidc10_lcd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
-protected:
- virtual void device_add_mconfig(machine_config &config) override;
+ acorn_vidc1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+class acorn_vidc1a_device : public acorn_vidc10_device
+{
+public:
+ // construction/destruction
+ acorn_vidc1a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// device type definition
-DECLARE_DEVICE_TYPE(ACORN_VIDC10, acorn_vidc10_device)
-DECLARE_DEVICE_TYPE(ACORN_VIDC10_LCD, acorn_vidc10_lcd_device)
+DECLARE_DEVICE_TYPE(ACORN_VIDC1, acorn_vidc1_device)
+DECLARE_DEVICE_TYPE(ACORN_VIDC1A, acorn_vidc1a_device)
class arm_vidc20_device : public acorn_vidc10_device
{
@@ -151,21 +155,18 @@ public:
arm_vidc20_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
void write_dac32(u8 channel, u16 data);
- bool get_dac_mode();
+ virtual bool get_dac_mode() override;
protected:
virtual void device_add_mconfig(machine_config &config) override;
void regs_map(address_map &map);
- virtual u32 palette_entries() const override;
+ virtual u32 palette_entries() const noexcept override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_config_complete() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
virtual u32 get_pixel_clock() override;
- const double m_sound_internal_divider = 1.0;
-
private:
void vidc20_pal_data_display_w(offs_t offset, u32 data);
void vidc20_pal_data_index_w(u32 data);
@@ -183,6 +184,10 @@ private:
u8 m_pixel_rate;
u8 m_vco_r_modulo;
u8 m_vco_v_modulo;
+
+ required_device_array<dac_16bit_r2r_twos_complement_device, 2> m_dac32;
+
+ virtual void refresh_stereo_image(u8 channel) override;
};
DECLARE_DEVICE_TYPE(ARM_VIDC20, arm_vidc20_device)
@@ -193,4 +198,4 @@ DECLARE_DEVICE_TYPE(ARM_VIDC20, arm_vidc20_device)
//**************************************************************************
-#endif // MAME_MACHINE_ACORN_VIDC10_H
+#endif // MAME_MACHINE_ACORN_VIDC_H
diff --git a/src/devices/machine/adc0804.cpp b/src/devices/machine/adc0804.cpp
index 048b99734b6..5a3813b66b7 100644
--- a/src/devices/machine/adc0804.cpp
+++ b/src/devices/machine/adc0804.cpp
@@ -59,7 +59,7 @@ ALLOW_SAVE_TYPE(adc0804_device::read_mode);
adc0804_device::adc0804_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
- , m_vin_callback(*this)
+ , m_vin_callback(*this, 0)
, m_intr_callback(*this)
, m_res(0.0)
, m_cap(0.0)
@@ -97,9 +97,6 @@ adc0803_device::adc0803_device(const machine_config &mconfig, const char *tag, d
void adc0804_device::device_resolve_objects()
{
- m_vin_callback.resolve_safe(0);
- m_intr_callback.resolve_safe();
-
if (m_rd_mode == RD_GROUNDED)
m_rd_active = true;
}
@@ -118,7 +115,7 @@ void adc0804_device::device_start()
m_fclk_rc = attotime::from_double(m_res * m_cap / 1.1);
// create timer
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(adc0804_device::conversion_done), this));
+ m_timer = timer_alloc(FUNC(adc0804_device::conversion_done), this);
// save state
if (m_rd_mode == RD_BITBANGED)
@@ -244,7 +241,7 @@ u8 adc0804_device::read_and_write()
// rd_w - enable data bus by line write
//-------------------------------------------------
-WRITE_LINE_MEMBER(adc0804_device::rd_w)
+void adc0804_device::rd_w(int state)
{
assert(m_rd_mode == RD_BITBANGED);
@@ -263,7 +260,7 @@ WRITE_LINE_MEMBER(adc0804_device::rd_w)
// wr_w - begin conversion by line write
//-------------------------------------------------
-WRITE_LINE_MEMBER(adc0804_device::wr_w)
+void adc0804_device::wr_w(int state)
{
// WR input is active low
if (!state && !m_wr_active)
diff --git a/src/devices/machine/adc0804.h b/src/devices/machine/adc0804.h
index d8fe6ad950e..8e5ca6596b2 100644
--- a/src/devices/machine/adc0804.h
+++ b/src/devices/machine/adc0804.h
@@ -63,11 +63,11 @@ public:
void write(u8 data = 0);
// control line interface
- DECLARE_WRITE_LINE_MEMBER(rd_w);
- DECLARE_WRITE_LINE_MEMBER(wr_w);
+ void rd_w(int state);
+ void wr_w(int state);
// status line interface
- DECLARE_READ_LINE_MEMBER(intr_r) { return m_intr_active ? 0 : 1; }
+ int intr_r() { return m_intr_active ? 0 : 1; }
protected:
adc0804_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
diff --git a/src/devices/machine/adc0808.cpp b/src/devices/machine/adc0808.cpp
index 3988254dc71..101e84a7749 100644
--- a/src/devices/machine/adc0808.cpp
+++ b/src/devices/machine/adc0808.cpp
@@ -42,7 +42,7 @@ ALLOW_SAVE_TYPE(adc0808_device::state);
adc0808_device::adc0808_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
m_eoc_cb(*this), m_eoc_ff_cb(*this),
- m_in_cb(*this),
+ m_in_cb(*this, 0xff),
m_state(STATE_IDLE),
m_cycle_timer(nullptr),
m_start(0), m_address(0), m_sar(0xff), m_eoc(1)
@@ -78,13 +78,8 @@ m58990_device::m58990_device(const machine_config &mconfig, const char *tag, dev
void adc0808_device::device_start()
{
- // resolve callbacks
- m_eoc_cb.resolve_safe();
- m_eoc_ff_cb.resolve_safe();
- m_in_cb.resolve_all_safe(0xff);
-
// allocate timers
- m_cycle_timer = timer_alloc();
+ m_cycle_timer = timer_alloc(FUNC(adc0808_device::update_state), this);
m_cycle_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
// register for save states
@@ -96,10 +91,10 @@ void adc0808_device::device_start()
}
//-------------------------------------------------
-// device_timer - handler timer events
+// update_state
//-------------------------------------------------
-void adc0808_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(adc0808_device::update_state)
{
switch (m_state)
{
@@ -140,7 +135,7 @@ void adc0808_device::device_timer(emu_timer &timer, device_timer_id id, int para
logerror("Conversion finished, result %02x\n", m_sar);
if (m_sar != start_sar)
- logerror("Conversion finished, should fail - starting value %02x, ending value %02x", start_sar, m_sar);
+ logerror("Conversion finished, should fail - starting value %02x, ending value %02x\n", start_sar, m_sar);
// eoc is delayed by one cycle
m_cycle_timer->adjust(attotime::never);
@@ -173,7 +168,7 @@ void adc0808_device::address_w(u8 data)
m_address = data & 7;
}
-WRITE_LINE_MEMBER( adc0808_device::start_w )
+void adc0808_device::start_w(int state)
{
if (m_start == state)
return;
@@ -191,7 +186,7 @@ WRITE_LINE_MEMBER( adc0808_device::start_w )
m_start = state;
}
-READ_LINE_MEMBER( adc0808_device::eoc_r )
+int adc0808_device::eoc_r()
{
return m_eoc;
}
diff --git a/src/devices/machine/adc0808.h b/src/devices/machine/adc0808.h
index 296921c1271..91237a949b3 100644
--- a/src/devices/machine/adc0808.h
+++ b/src/devices/machine/adc0808.h
@@ -53,8 +53,8 @@ public:
u8 data_r();
void address_w(u8 data);
- DECLARE_WRITE_LINE_MEMBER(start_w);
- DECLARE_READ_LINE_MEMBER(eoc_r);
+ void start_w(int state);
+ int eoc_r();
// common hookups
void address_offset_start_w(offs_t offset, u8 data); // start and ale connected, address to the address bus
@@ -65,7 +65,8 @@ protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_state);
private:
// callbacks
diff --git a/src/devices/machine/adc083x.cpp b/src/devices/machine/adc083x.cpp
index 1e0fd2dd7e7..8759cabe095 100644
--- a/src/devices/machine/adc083x.cpp
+++ b/src/devices/machine/adc083x.cpp
@@ -11,6 +11,8 @@
#include "emu.h"
#include "adc083x.h"
+#include <cstdarg>
+
#define VERBOSE_LEVEL ( 0 )
static inline void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, device_t &device, const char *s_fmt, ... )
@@ -137,7 +139,7 @@ void adc083x_device::clear_sars()
adc083x_device::cs_write
-------------------------------------------------*/
-WRITE_LINE_MEMBER( adc083x_device::cs_write )
+void adc083x_device::cs_write(int state)
{
if( m_cs != state )
{
@@ -252,7 +254,7 @@ uint8_t adc083x_device::conversion()
adc083x_device::clk_write
-------------------------------------------------*/
-WRITE_LINE_MEMBER( adc083x_device::clk_write )
+void adc083x_device::clk_write(int state)
{
if( m_clk != state )
{
@@ -400,7 +402,7 @@ WRITE_LINE_MEMBER( adc083x_device::clk_write )
adc083x_device::di_write
-------------------------------------------------*/
-WRITE_LINE_MEMBER( adc083x_device::di_write )
+void adc083x_device::di_write(int state)
{
if( m_di != state )
{
@@ -414,7 +416,7 @@ WRITE_LINE_MEMBER( adc083x_device::di_write )
adc083x_device::se_write
-------------------------------------------------*/
-WRITE_LINE_MEMBER( adc083x_device::se_write )
+void adc083x_device::se_write(int state)
{
if( m_se != state )
{
@@ -428,7 +430,7 @@ WRITE_LINE_MEMBER( adc083x_device::se_write )
adc083x_device::sars_read
-------------------------------------------------*/
-READ_LINE_MEMBER( adc083x_device::sars_read )
+int adc083x_device::sars_read()
{
verboselog( 1, *this, "adc083x_sars_read( %s ) %d\n", tag(), m_sars );
return m_sars;
@@ -438,7 +440,7 @@ READ_LINE_MEMBER( adc083x_device::sars_read )
adc083x_device::do_read
-------------------------------------------------*/
-READ_LINE_MEMBER( adc083x_device::do_read )
+int adc083x_device::do_read()
{
verboselog( 1, *this, "adc083x_do_read( %s ) %d\n", tag(), m_do );
return m_do;
diff --git a/src/devices/machine/adc083x.h b/src/devices/machine/adc083x.h
index babde2515b1..3ccc6da79da 100644
--- a/src/devices/machine/adc083x.h
+++ b/src/devices/machine/adc083x.h
@@ -42,12 +42,12 @@ public:
// configuration helpers
template <typename... T> void set_input_callback(T &&... args) { m_input_callback.set(std::forward<T>(args)...); }
- DECLARE_WRITE_LINE_MEMBER( cs_write );
- DECLARE_WRITE_LINE_MEMBER( clk_write );
- DECLARE_WRITE_LINE_MEMBER( di_write );
- DECLARE_WRITE_LINE_MEMBER( se_write );
- DECLARE_READ_LINE_MEMBER( sars_read );
- DECLARE_READ_LINE_MEMBER( do_read );
+ void cs_write(int state);
+ void clk_write(int state);
+ void di_write(int state);
+ void se_write(int state);
+ int sars_read();
+ int do_read();
protected:
adc083x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t mux_bits);
diff --git a/src/devices/machine/adc0844.cpp b/src/devices/machine/adc0844.cpp
index c3616035927..1f745041138 100644
--- a/src/devices/machine/adc0844.cpp
+++ b/src/devices/machine/adc0844.cpp
@@ -31,7 +31,7 @@ DEFINE_DEVICE_TYPE(ADC0848, adc0848_device, "adc0848", "ADC0848 A/D Converter")
adc0844_device::adc0844_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
m_intr_cb(*this),
- m_ch1_cb(*this), m_ch2_cb(*this), m_ch3_cb(*this), m_ch4_cb(*this),
+ m_ch1_cb(*this, 0xff), m_ch2_cb(*this, 0xff), m_ch3_cb(*this, 0xff), m_ch4_cb(*this, 0xff),
m_conversion_timer(nullptr),
m_channel(0x0f),
m_result(0xff)
@@ -49,7 +49,7 @@ adc0844_device::adc0844_device(const machine_config &mconfig, const char *tag, d
adc0848_device::adc0848_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
adc0844_device(mconfig, ADC0848, tag, owner, clock),
- m_ch5_cb(*this), m_ch6_cb(*this), m_ch7_cb(*this), m_ch8_cb(*this)
+ m_ch5_cb(*this, 0xff), m_ch6_cb(*this, 0xff), m_ch7_cb(*this, 0xff), m_ch8_cb(*this, 0xff)
{
}
@@ -59,32 +59,14 @@ adc0848_device::adc0848_device(const machine_config &mconfig, const char *tag, d
void adc0844_device::device_start()
{
- // resolve callbacks
- m_intr_cb.resolve_safe();
- m_ch1_cb.resolve_safe(0xff);
- m_ch2_cb.resolve_safe(0xff);
- m_ch3_cb.resolve_safe(0xff);
- m_ch4_cb.resolve_safe(0xff);
-
// allocate timers
- m_conversion_timer = timer_alloc();
+ m_conversion_timer = timer_alloc(FUNC(adc0844_device::conversion_complete), this);
// register for save states
save_item(NAME(m_channel));
save_item(NAME(m_result));
}
-void adc0848_device::device_start()
-{
- adc0844_device::device_start();
-
- // resolve callbacks
- m_ch5_cb.resolve_safe(0xff);
- m_ch6_cb.resolve_safe(0xff);
- m_ch7_cb.resolve_safe(0xff);
- m_ch8_cb.resolve_safe(0xff);
-}
-
//-------------------------------------------------
// clamp - restrict value to 0..255
//-------------------------------------------------
@@ -100,10 +82,10 @@ uint8_t adc0844_device::clamp(int value)
}
//-------------------------------------------------
-// device_timer - handler timer events
+// conversion_complete - finish ADC conversion
//-------------------------------------------------
-void adc0844_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(adc0844_device::conversion_complete)
{
switch (m_channel)
{
@@ -132,7 +114,7 @@ void adc0844_device::device_timer(emu_timer &timer, device_timer_id id, int para
m_intr_cb(ASSERT_LINE);
}
-void adc0848_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(adc0848_device::conversion_complete)
{
switch (m_channel)
{
diff --git a/src/devices/machine/adc0844.h b/src/devices/machine/adc0844.h
index 51dff681f16..b1496690e31 100644
--- a/src/devices/machine/adc0844.h
+++ b/src/devices/machine/adc0844.h
@@ -49,9 +49,10 @@ public:
protected:
adc0844_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ virtual TIMER_CALLBACK_MEMBER(conversion_complete);
uint8_t clamp(int value);
@@ -81,9 +82,7 @@ public:
virtual void write(u8 data) override;
protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ virtual TIMER_CALLBACK_MEMBER(conversion_complete) override;
private:
devcb_read8 m_ch5_cb, m_ch6_cb, m_ch7_cb, m_ch8_cb;
diff --git a/src/devices/machine/adc1038.cpp b/src/devices/machine/adc1038.cpp
index 3baac1fd1be..33de2805f96 100644
--- a/src/devices/machine/adc1038.cpp
+++ b/src/devices/machine/adc1038.cpp
@@ -65,7 +65,7 @@ void adc1038_device::device_reset()
DEVICE HANDLERS
*****************************************************************************/
-READ_LINE_MEMBER( adc1038_device::do_read )
+int adc1038_device::do_read()
{
m_data_out = (m_adc_data & 0x200) ? 1 : 0;
m_adc_data <<= 1;
@@ -74,12 +74,12 @@ READ_LINE_MEMBER( adc1038_device::do_read )
return m_data_out;
}
-WRITE_LINE_MEMBER( adc1038_device::di_write )
+void adc1038_device::di_write(int state)
{
m_data_in = state;
}
-WRITE_LINE_MEMBER( adc1038_device::clk_write )
+void adc1038_device::clk_write(int state)
{
// GTI Club doesn't sync on SARS
if (m_gticlub_hack)
@@ -117,7 +117,7 @@ WRITE_LINE_MEMBER( adc1038_device::clk_write )
m_clk = state;
}
-READ_LINE_MEMBER( adc1038_device::sars_read )
+int adc1038_device::sars_read()
{
m_cycle = 0;
diff --git a/src/devices/machine/adc1038.h b/src/devices/machine/adc1038.h
index d4ee5362fd0..ea399ba550d 100644
--- a/src/devices/machine/adc1038.h
+++ b/src/devices/machine/adc1038.h
@@ -35,10 +35,10 @@ public:
void set_gti_club_hack(bool hack) { m_gticlub_hack = hack; }
- DECLARE_READ_LINE_MEMBER( do_read );
- DECLARE_READ_LINE_MEMBER( sars_read );
- DECLARE_WRITE_LINE_MEMBER( di_write );
- DECLARE_WRITE_LINE_MEMBER( clk_write );
+ int do_read();
+ int sars_read();
+ void di_write(int state);
+ void clk_write(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/aic565.cpp b/src/devices/machine/aic565.cpp
index 34da7f4fd14..dac7d15aa5a 100644
--- a/src/devices/machine/aic565.cpp
+++ b/src/devices/machine/aic565.cpp
@@ -49,21 +49,6 @@ aic565_device::aic565_device(const machine_config &mconfig, const char *tag, dev
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void aic565_device::device_resolve_objects()
-{
- // resolve callbacks
- m_hrst_callback.resolve_safe();
- m_srst_callback.resolve_safe();
- m_irq_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
diff --git a/src/devices/machine/aic565.h b/src/devices/machine/aic565.h
index 581a595d77c..3c799453ed5 100644
--- a/src/devices/machine/aic565.h
+++ b/src/devices/machine/aic565.h
@@ -37,8 +37,7 @@ public:
void local_w(offs_t offset, u8 data);
protected:
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/aic580.cpp b/src/devices/machine/aic580.cpp
index c5bf3a51e96..b06d6b1362b 100644
--- a/src/devices/machine/aic580.cpp
+++ b/src/devices/machine/aic580.cpp
@@ -35,10 +35,10 @@ DEFINE_DEVICE_TYPE(AIC580, aic580_device, "aic580", "AIC-580 DMA Bus Master")
aic580_device::aic580_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, AIC580, tag, owner, clock)
- , m_bdin_callback(*this)
+ , m_bdin_callback(*this, 0)
, m_bdout_callback(*this)
, m_back_callback(*this)
- , m_sread_callback(*this)
+ , m_sread_callback(*this, 0)
, m_swrite_callback(*this)
, m_dma_mode(0)
, m_channel_addr{0}
@@ -50,23 +50,6 @@ aic580_device::aic580_device(const machine_config &mconfig, const char *tag, dev
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void aic580_device::device_resolve_objects()
-{
- // resolve callbacks
- m_bdin_callback.resolve_safe(0);
- m_bdout_callback.resolve_safe();
- m_back_callback.resolve_safe();
- m_sread_callback.resolve_safe(0);
- m_swrite_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -97,7 +80,7 @@ void aic580_device::device_reset()
// breq_w - handle transfer requests for port B
//-------------------------------------------------
-WRITE_LINE_MEMBER(aic580_device::breq_w)
+void aic580_device::breq_w(int state)
{
if (state)
{
diff --git a/src/devices/machine/aic580.h b/src/devices/machine/aic580.h
index b764daa1710..2ac102d4489 100644
--- a/src/devices/machine/aic580.h
+++ b/src/devices/machine/aic580.h
@@ -34,11 +34,10 @@ public:
void mpu_map(address_map &map);
// port B DMA interface
- DECLARE_WRITE_LINE_MEMBER(breq_w);
+ void breq_w(int state);
protected:
- // device-specific overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/aic6250.cpp b/src/devices/machine/aic6250.cpp
index 71859bdee05..6f08895ac44 100644
--- a/src/devices/machine/aic6250.cpp
+++ b/src/devices/machine/aic6250.cpp
@@ -29,7 +29,6 @@
#include "emu.h"
#include "aic6250.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_REG (1U << 1)
#define LOG_STATE (1U << 2)
#define LOG_CONFIG (1U << 3)
@@ -52,9 +51,9 @@ aic6250_device::aic6250_device(const machine_config &mconfig, device_type type,
, nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF)
, m_int_cb(*this)
, m_breq_cb(*this)
- , m_port_a_r_cb(*this)
+ , m_port_a_r_cb(*this, 0xff)
, m_port_a_w_cb(*this)
- , m_port_b_r_cb(*this)
+ , m_port_b_r_cb(*this, 0xff)
, m_port_b_w_cb(*this)
{
}
@@ -154,14 +153,6 @@ void aic6250_device::write(offs_t offset, u8 data)
void aic6250_device::device_start()
{
- m_int_cb.resolve_safe();
- m_breq_cb.resolve_safe();
-
- m_port_a_r_cb.resolve_safe(0xff);
- m_port_a_w_cb.resolve_safe();
- m_port_b_r_cb.resolve_safe(0xff);
- m_port_b_w_cb.resolve_safe();
-
save_item(NAME(m_dma_count));
save_item(NAME(m_int_msk_reg_0));
save_item(NAME(m_offset_cntrl));
@@ -182,7 +173,7 @@ void aic6250_device::device_start()
m_rev_cntrl = 0x02;
- m_state_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aic6250_device::state_loop), this));
+ m_state_timer = timer_alloc(FUNC(aic6250_device::state_loop), this);
m_state = IDLE;
m_int_asserted = false;
@@ -1015,7 +1006,7 @@ void aic6250_device::set_int_state(bool asserted)
* the DMA transfer count falls below 8, data is transferred via individual
* cycles on demand rather than prefetched.
*/
-WRITE_LINE_MEMBER(aic6250_device::back_w)
+void aic6250_device::back_w(int state)
{
LOGMASKED(LOG_DMA, "back_w %d\n", state);
diff --git a/src/devices/machine/aic6250.h b/src/devices/machine/aic6250.h
index 048aa6de0c8..8b8b283b0ba 100644
--- a/src/devices/machine/aic6250.h
+++ b/src/devices/machine/aic6250.h
@@ -23,7 +23,7 @@ public:
auto port_b_r_cb() { return m_port_b_r_cb.bind(); }
auto port_b_w_cb() { return m_port_b_w_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER(back_w);
+ void back_w(int state);
u8 read(address_space &space, offs_t offset);
void write(offs_t offset, u8 data);
diff --git a/src/devices/machine/aicartc.cpp b/src/devices/machine/aicartc.cpp
index 0f8ad30c283..f68ca2e3bca 100644
--- a/src/devices/machine/aicartc.cpp
+++ b/src/devices/machine/aicartc.cpp
@@ -10,7 +10,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/aicartc.h"
+#include "aicartc.h"
@@ -54,7 +54,7 @@ void aicartc_device::device_validity_check(validity_checker &valid) const
void aicartc_device::device_start()
{
- m_clock_timer = timer_alloc();
+ m_clock_timer = timer_alloc(FUNC(aicartc_device::clock_tick), this);
m_clock_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
}
@@ -107,11 +107,10 @@ void aicartc_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// clock_tick - advance the RTC counter
//-------------------------------------------------
-
-void aicartc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(aicartc_device::clock_tick)
{
m_rtc_tick++;
if(m_rtc_tick & 0x8000)
@@ -152,7 +151,7 @@ void aicartc_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
if(m_we)
{
COMBINE_DATA(&m_rtc_reg_hi);
- // clear write enable here?
+ m_we = 0;
}
break;
diff --git a/src/devices/machine/aicartc.h b/src/devices/machine/aicartc.h
index 6af901ac363..fb1955ec685 100644
--- a/src/devices/machine/aicartc.h
+++ b/src/devices/machine/aicartc.h
@@ -33,13 +33,14 @@ protected:
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_rtc_interface overrides
virtual bool rtc_feature_y2k() const override { return true; }
virtual bool rtc_feature_leap_year() const override { return true; }
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+ TIMER_CALLBACK_MEMBER(clock_tick);
+
private:
emu_timer *m_clock_timer;
};
diff --git a/src/devices/machine/akiko.cpp b/src/devices/machine/akiko.cpp
index 1505eab2a56..5ebe4603a0e 100644
--- a/src/devices/machine/akiko.cpp
+++ b/src/devices/machine/akiko.cpp
@@ -11,20 +11,34 @@
- Chunky to planar converter
- 2x CIA chips
+ TODO:
+ - Reportedly the CD drive should be a Sony KSM-2101BAM,
+ schematics shows Akiko connected to a laconic "26-pin CD connector"
+ - NVRAM needs inheriting from i2c_24c08_device;
+ - Handle tray open/close events, needed at very least by:
+ \- cdtv:cdremix2 load sequences;
+ \- kangfu on cd32 as "out of memory" workaround;
+
***************************************************************************/
#include "emu.h"
#include "akiko.h"
+
#include "coreutil.h"
-#include "romload.h"
+#include "multibyte.h"
+#define LOG_WARN (1U << 1) // Show warnings
+#define LOG_REGS (1U << 2) // Show register r/w
+#define LOG_CD (1U << 3) // Show CD interactions and commands
-//**************************************************************************
-// CONSTANTS / MACROS
-//**************************************************************************
+#define VERBOSE (LOG_WARN)
+//#define LOG_OUTPUT_STREAM std::cout
-#define LOG_AKIKO 0
-#define LOG_AKIKO_CD 0
+#include "logmacro.h"
+
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+#define LOGREGS(...) LOGMASKED(LOG_REGS, __VA_ARGS__)
+#define LOGCD(...) LOGMASKED(LOG_CD, __VA_ARGS__)
//**************************************************************************
@@ -39,6 +53,11 @@ DEFINE_DEVICE_TYPE(AKIKO, akiko_device, "akiko", "CBM AKIKO")
void akiko_device::device_add_mconfig(machine_config &config)
{
+ CDROM(config, m_cdrom).set_interface("cdrom");
+ CDDA(config, m_cdda);
+ m_cdda->add_route(0, ":lspeaker", 0.50);
+ m_cdda->add_route(1, ":rspeaker", 0.50);
+ m_cdda->set_cdrom_tag(m_cdrom);
}
@@ -51,33 +70,32 @@ void akiko_device::device_add_mconfig(machine_config &config)
//-------------------------------------------------
akiko_device::akiko_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, AKIKO, tag, owner, clock),
- m_c2p_input_index(0),
- m_c2p_output_index(0),
- m_i2c_scl_out(0),
- m_i2c_scl_dir(0),
- m_i2c_sda_out(0),
- m_i2c_sda_dir(0),
- m_cdrom_track_index(0),
- m_cdrom_lba_start(0),
- m_cdrom_lba_end(0),
- m_cdrom_lba_cur(0),
- m_cdrom_readmask(0),
- m_cdrom_readreqmask(0),
- m_cdrom_dmacontrol(0),
- m_cdrom_numtracks(0),
- m_cdrom_speed(0),
- m_cdrom_cmd_start(0),
- m_cdrom_cmd_end(0),
- m_cdrom_cmd_resp(0),
- m_cdda(*this, "^cdda"),
- m_cddevice(*this, "^cdrom"),
- m_cdrom(nullptr),
- m_cdrom_toc(nullptr),
- m_dma_timer(nullptr),
- m_frame_timer(nullptr),
- m_mem_r(*this), m_mem_w(*this), m_int_w(*this),
- m_scl_w(*this), m_sda_r(*this), m_sda_w(*this)
+ : device_t(mconfig, AKIKO, tag, owner, clock)
+ , m_c2p_input_index(0)
+ , m_c2p_output_index(0)
+ , m_i2c_scl_out(0)
+ , m_i2c_scl_dir(0)
+ , m_i2c_sda_out(0)
+ , m_i2c_sda_dir(0)
+ , m_cdrom_track_index(0)
+ , m_cdrom_lba_start(0)
+ , m_cdrom_lba_end(0)
+ , m_cdrom_lba_cur(0)
+ , m_cdrom_readmask(0)
+ , m_cdrom_readreqmask(0)
+ , m_cdrom_dmacontrol(0)
+ , m_cdrom_numtracks(0)
+ , m_cdrom_speed(0)
+ , m_cdrom_cmd_start(0)
+ , m_cdrom_cmd_end(0)
+ , m_cdrom_cmd_resp(0)
+ , m_cdda(*this, "cdda")
+ , m_cdrom(*this, "cdrom")
+ , m_cdrom_toc(nullptr)
+ , m_dma_timer(nullptr)
+ , m_frame_timer(nullptr)
+ , m_mem_r(*this, 0xffff), m_mem_w(*this), m_int_w(*this)
+ , m_scl_w(*this), m_sda_r(*this, 1), m_sda_w(*this)
{
for (int i = 0; i < 8; i++)
{
@@ -98,14 +116,6 @@ akiko_device::akiko_device(const machine_config &mconfig, const char *tag, devic
void akiko_device::device_start()
{
- // resolve callbacks
- m_mem_r.resolve_safe(0xffff);
- m_mem_w.resolve_safe();
- m_int_w.resolve_safe();
- m_scl_w.resolve_safe();
- m_sda_r.resolve_safe(1);
- m_sda_w.resolve_safe();
-
m_c2p_input_index = 0;
m_c2p_output_index = 0;
@@ -130,8 +140,8 @@ void akiko_device::device_start()
m_cdrom_cmd_resp = 0;
m_cdrom_toc = nullptr;
- m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::dma_proc), this));
- m_frame_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::frame_proc), this));
+ m_dma_timer = timer_alloc(FUNC(akiko_device::dma_proc), this);
+ m_frame_timer = timer_alloc(FUNC(akiko_device::frame_proc), this);
}
//-------------------------------------------------
@@ -140,29 +150,18 @@ void akiko_device::device_start()
void akiko_device::device_reset()
{
- if (m_cddevice.found())
- {
- // MESS case
- m_cdrom = m_cddevice->get_cdrom_file();
- }
- else
- {
- // MAME case
- m_cdrom = cdrom_open(machine().rom_load().get_disk_handle(":cdrom"));
- }
-
/* create the TOC table */
- if ( m_cdrom != nullptr && cdrom_get_last_track(m_cdrom) )
+ if ( m_cdrom->exists() && m_cdrom->get_last_track() )
{
uint8_t *p;
- int i, addrctrl = cdrom_get_adr_control( m_cdrom, 0 );
+ int i, addrctrl = m_cdrom->get_adr_control( 0 );
uint32_t discend;
- discend = cdrom_get_track_start(m_cdrom,cdrom_get_last_track(m_cdrom)-1);
- discend += cdrom_get_toc(m_cdrom)->tracks[cdrom_get_last_track(m_cdrom)-1].frames;
- discend = lba_to_msf(discend);
+ discend = m_cdrom->get_track_start(m_cdrom->get_last_track()-1);
+ discend += m_cdrom->get_toc().tracks[m_cdrom->get_last_track()-1].frames;
+ discend = cdrom_file::lba_to_msf(discend);
- m_cdrom_numtracks = cdrom_get_last_track(m_cdrom)+3;
+ m_cdrom_numtracks = m_cdrom->get_last_track()+3;
m_cdrom_toc = std::make_unique<uint8_t[]>(13*m_cdrom_numtracks);
memset( m_cdrom_toc.get(), 0, 13*m_cdrom_numtracks);
@@ -174,27 +173,23 @@ void akiko_device::device_reset()
p += 13;
p[1] = 0x01;
p[3] = 0xa1; /* last track */
- p[8] = cdrom_get_last_track(m_cdrom);
+ p[8] = m_cdrom->get_last_track();
p += 13;
p[1] = 0x01;
p[3] = 0xa2; /* disc end */
- p[8] = (discend >> 16 ) & 0xff;
- p[9] = (discend >> 8 ) & 0xff;
- p[10] = discend & 0xff;
+ put_u24be(&p[8], discend);
p += 13;
- for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ )
+ for( i = 0; i < m_cdrom->get_last_track(); i++ )
{
- uint32_t trackpos = cdrom_get_track_start(m_cdrom,i);
+ uint32_t trackpos = m_cdrom->get_track_start(i);
- trackpos = lba_to_msf(trackpos);
- addrctrl = cdrom_get_adr_control( m_cdrom, i );
+ trackpos = cdrom_file::lba_to_msf(trackpos);
+ addrctrl = m_cdrom->get_adr_control( i );
p[1] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
p[3] = dec_2_bcd( i+1 );
- p[8] = (trackpos >> 16 ) & 0xff;
- p[9] = (trackpos >> 8 ) & 0xff;
- p[10] = trackpos & 0xff;
+ put_u24be(&p[8], trackpos);
p += 13;
}
@@ -208,14 +203,6 @@ void akiko_device::device_reset()
void akiko_device::device_stop()
{
- if (!m_cddevice.found())
- {
- if( m_cdrom )
- {
- cdrom_close(m_cdrom);
- m_cdrom = (cdrom_file *)nullptr;
- }
- }
}
void akiko_device::nvram_write(uint32_t data)
@@ -259,6 +246,11 @@ void akiko_device::mem_w8(offs_t offset, uint8_t data)
m_mem_w(offset, data << shift, 0xff << shift);
}
+void akiko_device::set_mute(bool mute)
+{
+ m_cdda->set_output_gain( 0, mute ? 0.0 : 1.0 );
+}
+
/*************************************
*
@@ -340,7 +332,7 @@ void akiko_device::cdda_stop()
if (m_cdda != nullptr)
{
m_cdda->stop_audio();
- m_frame_timer->reset( );
+ m_frame_timer->reset();
}
}
@@ -407,8 +399,7 @@ void akiko_device::set_cd_status(uint32_t status)
if ( m_cdrom_status[0] & m_cdrom_status[1] )
{
- if (LOG_AKIKO_CD)
- logerror("Akiko CD IRQ\n");
+ LOGCD("Akiko CD IRQ\n");
m_int_w(1);
}
@@ -447,6 +438,9 @@ TIMER_CALLBACK_MEMBER(akiko_device::dma_proc)
uint8_t buf[2352];
int index;
+ if ( !m_cdrom->exists() )
+ return;
+
if ( (m_cdrom_dmacontrol & 0x04000000) == 0 )
return;
@@ -457,38 +451,36 @@ TIMER_CALLBACK_MEMBER(akiko_device::dma_proc)
if ( m_cdrom_readreqmask & ( 1 << index ) )
{
- uint32_t track = cdrom_get_track( m_cdrom, m_cdrom_lba_cur );
- uint32_t datasize;// = cdrom_get_toc(m_cdrom)->tracks[track].datasize;
- uint32_t subsize = cdrom_get_toc( m_cdrom )->tracks[track].subsize;
+ uint32_t track = m_cdrom->get_track( m_cdrom_lba_cur );
+ uint32_t datasize;// = m_cdrom->get_toc().tracks[track].datasize;
+ uint32_t subsize = m_cdrom->get_toc().tracks[track].subsize;
- uint32_t curmsf = lba_to_msf( m_cdrom_lba_cur );
+ uint32_t curmsf = cdrom_file::lba_to_msf( m_cdrom_lba_cur );
memset( buf, 0, 16 );
buf[3] = m_cdrom_lba_cur - m_cdrom_lba_start;
memset( &buf[4], 0xff, 8 );
- buf[12] = (curmsf >> 16) & 0xff;
- buf[13] = (curmsf >> 8) & 0xff;
- buf[14] = curmsf & 0xff;
+ put_u24be(&buf[12], curmsf);
buf[15] = 0x01; /* mode1 */
datasize = 2048;
- if ( !cdrom_read_data( m_cdrom, m_cdrom_lba_cur, &buf[16], CD_TRACK_MODE1 ) )
+ if ( !m_cdrom->read_data( m_cdrom_lba_cur, &buf[16], cdrom_file::CD_TRACK_MODE1 ) )
{
- logerror( "AKIKO: Read error trying to read sector %08x!\n", m_cdrom_lba_cur );
+ LOGWARN( "AKIKO: Read error trying to read sector %08x!\n", m_cdrom_lba_cur );
return;
}
if ( subsize )
{
- if ( !cdrom_read_subcode( m_cdrom, m_cdrom_lba_cur, &buf[16+datasize] ) )
+ if ( !m_cdrom->read_subcode( m_cdrom_lba_cur, &buf[16+datasize] ) )
{
- logerror( "AKIKO: Read error trying to read subcode for sector %08x!\n", m_cdrom_lba_cur );
+ LOGWARN( "AKIKO: Read error trying to read subcode for sector %08x!\n", m_cdrom_lba_cur );
return;
}
}
- if (LOG_AKIKO_CD) logerror( "DMA: sector %d - address %08x\n", m_cdrom_lba_cur, m_cdrom_address[0] + (index*4096) );
+ LOGCD( "DMA: sector %d - address %08x\n", m_cdrom_lba_cur, m_cdrom_address[0] + (index*4096) );
// write sector data to host memory
for (int i = 0; i < 2352; i++)
@@ -569,11 +561,11 @@ TIMER_CALLBACK_MEMBER( akiko_device::cd_delayed_cmd )
if ( param == 0x05 )
{
- if (LOG_AKIKO_CD) logerror( "AKIKO: Completing Command %d\n", param );
+ LOGCD( "AKIKO: Completing Command %d\n", param );
resp[0] = 0x06;
- if ( m_cdrom == nullptr || m_cdrom_numtracks == 0 )
+ if ( !m_cdrom->exists() || m_cdrom_numtracks == 0 )
{
resp[1] = 0x80;
setup_response( 15, resp );
@@ -607,7 +599,7 @@ void akiko_device::update_cdrom()
cmd &= 0x0f;
- if (LOG_AKIKO_CD) logerror( "CDROM command: %02X\n", cmd );
+ LOGCD( "CDROM command: %02X\n", cmd );
if ( cmd == 0x02 ) /* pause audio */
{
@@ -618,7 +610,7 @@ void akiko_device::update_cdrom()
cdda_pause(1);
- m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
+ m_cdrom_cmd_start = (m_cdrom_cmd_start + 2) & 0xff;
setup_response( 2, resp );
}
@@ -631,7 +623,7 @@ void akiko_device::update_cdrom()
cdda_pause(0);
- m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
+ m_cdrom_cmd_start = (m_cdrom_cmd_start + 2) & 0xff;
setup_response( 2, resp );
}
@@ -647,9 +639,9 @@ void akiko_device::update_cdrom()
cmd_addr += ( m_cdrom_cmd_start + i + 1 ) & 0xff;
}
- m_cdrom_cmd_start = (m_cdrom_cmd_start+13) & 0xff;
+ m_cdrom_cmd_start = (m_cdrom_cmd_start + 13) & 0xff;
- if ( m_cdrom == nullptr || m_cdrom_numtracks == 0 )
+ if ( !m_cdrom->exists() || m_cdrom_numtracks == 0 )
{
resp[1] = 0x80;
setup_response( 2, resp );
@@ -665,8 +657,8 @@ void akiko_device::update_cdrom()
if ( cmdbuf[7] == 0x80 )
{
- if (LOG_AKIKO_CD) logerror( "%s:AKIKO CD: Data read - start lba: %08x - end lba: %08x\n", machine().describe_context(), startpos, endpos );
m_cdrom_speed = (cmdbuf[8] & 0x40) ? 2 : 1;
+ LOGCD("AKIKO CD: Data read - start lba: %08x - end lba: %08x - divider speed: %d\n", startpos, endpos, m_cdrom_speed );
m_cdrom_lba_start = startpos;
m_cdrom_lba_end = endpos;
@@ -674,18 +666,18 @@ void akiko_device::update_cdrom()
}
else if ( cmdbuf[10] & 0x04 )
{
- logerror( "AKIKO CD: Audio Play - start lba: %08x - end lba: %08x\n", startpos, endpos );
+ LOGCD("AKIKO CD: Audio Play - start lba: %08x - end lba: %08x\n", startpos, endpos );
cdda_play(startpos, endpos - startpos);
resp[1] = 0x08;
}
else
{
- if (LOG_AKIKO_CD) logerror( "AKIKO CD: Seek - start lba: %08x - end lba: %08x\n", startpos, endpos );
+ LOGCD("AKIKO CD: Seek - start lba: %08x - end lba: %08x\n", startpos, endpos );
m_cdrom_track_index = 0;
- for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ )
+ for( i = 0; i < m_cdrom->get_last_track(); i++ )
{
- if ( startpos <= cdrom_get_track_start( m_cdrom, i ) )
+ if ( startpos <= m_cdrom->get_track_start( i ) )
{
/* reset to 0 */
m_cdrom_track_index = i + 2;
@@ -700,9 +692,9 @@ void akiko_device::update_cdrom()
}
else if ( cmd == 0x05 ) /* read toc */
{
- m_cdrom_cmd_start = (m_cdrom_cmd_start+3) & 0xff;
+ m_cdrom_cmd_start = (m_cdrom_cmd_start + 3) & 0xff;
- machine().scheduler().timer_set( attotime::from_msec(1), timer_expired_delegate(FUNC(akiko_device::cd_delayed_cmd ), this), resp[0]);
+ machine().scheduler().timer_set( attotime::from_msec(1), timer_expired_delegate( FUNC( akiko_device::cd_delayed_cmd ), this ), resp[0] );
break;
}
@@ -714,49 +706,47 @@ void akiko_device::update_cdrom()
(void)cdda_getstatus(&lba);
- if ( lba > 0 )
+ if ( lba > 0 && m_cdrom->exists() )
{
uint32_t disk_pos;
uint32_t track_pos;
uint32_t track;
int addrctrl;
- track = cdrom_get_track(m_cdrom, lba);
- addrctrl = cdrom_get_adr_control(m_cdrom, track);
+ track = m_cdrom->get_track(lba);
+ addrctrl = m_cdrom->get_adr_control(track);
resp[2] = 0x00;
resp[3] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
resp[4] = dec_2_bcd(track+1);
resp[5] = 0; /* index */
- disk_pos = lba_to_msf(lba);
- track_pos = lba_to_msf(lba - cdrom_get_track_start(m_cdrom, track));
+ disk_pos = cdrom_file::lba_to_msf(lba);
+ track_pos = cdrom_file::lba_to_msf(lba - m_cdrom->get_track_start(track));
/* track position */
- resp[6] = (track_pos >> 16) & 0xff;
- resp[7] = (track_pos >> 8) & 0xff;
- resp[8] = track_pos & 0xff;
+ put_u24be(&resp[6], track_pos);
/* disk position */
- resp[9] = (disk_pos >> 24) & 0xff;
- resp[10] = (disk_pos >> 16) & 0xff;
- resp[11] = (disk_pos >> 8) & 0xff;
- resp[12] = disk_pos & 0xff;
+ put_u32be(&resp[9], disk_pos);
}
else
{
resp[1] = 0x80;
}
+ // needed by cdtv:defcrown (would otherwise hardlock emulation)
+ m_cdrom_cmd_start = (m_cdrom_cmd_start + 2) & 0xff;
+
setup_response( 15, resp );
}
else if ( cmd == 0x07 ) /* check door status */
{
resp[1] = 0x01;
- m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
+ m_cdrom_cmd_start = (m_cdrom_cmd_start + 2) & 0xff;
- if ( m_cdrom == nullptr || m_cdrom_numtracks == 0 )
+ if ( !m_cdrom->exists() || m_cdrom_numtracks == 0 )
resp[1] = 0x80;
setup_response( 20, resp );
@@ -773,15 +763,12 @@ uint32_t akiko_device::read(offs_t offset)
{
uint32_t retval;
- if ( LOG_AKIKO && offset < (0x30/4) )
- {
- logerror( "Reading AKIKO reg %0x [%s] at %s\n", offset, get_akiko_reg_name(offset), machine().describe_context());
- }
+ if ( offset < (0x30/4) )
+ LOGREGS("Reading AKIKO reg %0x [%s] at %s\n", offset, get_akiko_reg_name(offset), machine().describe_context());
switch( offset )
{
case 0x00/4: /* ID */
- if ( m_cdrom != nullptr ) m_cdda->set_cdrom(m_cdrom);
return 0x0000cafe;
case 0x04/4: /* CDROM STATUS 1 */
@@ -833,10 +820,8 @@ uint32_t akiko_device::read(offs_t offset)
void akiko_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
{
- if ( LOG_AKIKO && offset < (0x30/4) )
- {
- logerror( "Writing AKIKO reg %0x [%s] with %08x at %s\n", offset, get_akiko_reg_name(offset), data, machine().describe_context());
- }
+ if ( offset < (0x30/4) )
+ LOGREGS("Writing AKIKO reg %0x [%s] with %08x at %s\n", offset, get_akiko_reg_name(offset), data, machine().describe_context());
switch( offset )
{
@@ -875,7 +860,7 @@ void akiko_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
break;
case 0x20/4: /* CDROM DMA SECTOR READ REQUEST WRITE */
- if (LOG_AKIKO_CD) logerror( "Read Req mask W: data %08x - mem mask %08x\n", data, mem_mask );
+ LOGCD( "Read Req mask W: data %08x - mem mask %08x\n", data, mem_mask );
if ( ACCESSING_BITS_16_31 )
{
m_cdrom_readreqmask = (data >> 16);
@@ -884,7 +869,7 @@ void akiko_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
break;
case 0x24/4: /* CDROM DMA ENABLE? */
- if (LOG_AKIKO_CD) logerror( "DMA enable W: data %08x - mem mask %08x\n", data, mem_mask );
+ LOGCD( "DMA enable W: data %08x - mem mask %08x\n", data, mem_mask );
if ( ( m_cdrom_dmacontrol ^ data ) & 0x04000000 )
{
if ( data & 0x04000000 )
diff --git a/src/devices/machine/akiko.h b/src/devices/machine/akiko.h
index 8a0ffec8e76..eddf3525e61 100644
--- a/src/devices/machine/akiko.h
+++ b/src/devices/machine/akiko.h
@@ -18,7 +18,7 @@
#pragma once
#include "cdrom.h"
-#include "imagedev/chd_cd.h"
+#include "imagedev/cdromimg.h"
#include "sound/cdda.h"
@@ -44,6 +44,8 @@ public:
uint32_t read(offs_t offset);
void write(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ void set_mute(bool mute);
+
protected:
// device-level overrides
virtual void device_start() override;
@@ -84,8 +86,7 @@ private:
uint8_t m_cdrom_cmd_resp;
required_device<cdda_device> m_cdda;
- optional_device<cdrom_image_device> m_cddevice;
- cdrom_file *m_cdrom;
+ optional_device<cdrom_image_device> m_cdrom;
std::unique_ptr<uint8_t[]> m_cdrom_toc;
diff --git a/src/devices/machine/alpha_8921.cpp b/src/devices/machine/alpha_8921.cpp
index bf57902b31e..b0217e8bfd2 100644
--- a/src/devices/machine/alpha_8921.cpp
+++ b/src/devices/machine/alpha_8921.cpp
@@ -89,7 +89,7 @@ void alpha_8921_device::device_reset()
// clk_w - Change clock pin status
//-------------------------------------------------
-WRITE_LINE_MEMBER(alpha_8921_device::clk_w)
+void alpha_8921_device::clk_w(int state)
{
if (m_clk != state)
{
@@ -110,7 +110,7 @@ WRITE_LINE_MEMBER(alpha_8921_device::clk_w)
// load_w - Change LOAD pin status
//-------------------------------------------------
-WRITE_LINE_MEMBER(alpha_8921_device::load_w)
+void alpha_8921_device::load_w(int state)
{
m_load = state;
}
@@ -119,7 +119,7 @@ WRITE_LINE_MEMBER(alpha_8921_device::load_w)
// even_w - Change EVEN pin status
//-------------------------------------------------
-WRITE_LINE_MEMBER(alpha_8921_device::even_w)
+void alpha_8921_device::even_w(int state)
{
m_even = state;
}
@@ -128,7 +128,7 @@ WRITE_LINE_MEMBER(alpha_8921_device::even_w)
// h_w - Change H pin status
//-------------------------------------------------
-WRITE_LINE_MEMBER(alpha_8921_device::h_w)
+void alpha_8921_device::h_w(int state)
{
m_h = state;
}
@@ -195,7 +195,7 @@ u8 alpha_8921_device::gbd_r()
// dota_r - Read DOTA pin data (GAD isn't 0)
//-------------------------------------------------
-READ_LINE_MEMBER(alpha_8921_device::dota_r)
+int alpha_8921_device::dota_r()
{
update_output();
return m_dota;
@@ -205,7 +205,7 @@ READ_LINE_MEMBER(alpha_8921_device::dota_r)
// dotb_r - Read DOTB pin data (GBD isn't 0)
//-------------------------------------------------
-READ_LINE_MEMBER(alpha_8921_device::dotb_r)
+int alpha_8921_device::dotb_r()
{
update_output();
return m_dotb;
diff --git a/src/devices/machine/alpha_8921.h b/src/devices/machine/alpha_8921.h
index a6e8ccdb0ad..54d7599cd7d 100644
--- a/src/devices/machine/alpha_8921.h
+++ b/src/devices/machine/alpha_8921.h
@@ -21,17 +21,17 @@ public:
alpha_8921_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// inputs
- DECLARE_WRITE_LINE_MEMBER(clk_w);
- DECLARE_WRITE_LINE_MEMBER(load_w);
- DECLARE_WRITE_LINE_MEMBER(even_w);
- DECLARE_WRITE_LINE_MEMBER(h_w);
+ void clk_w(int state);
+ void load_w(int state);
+ void even_w(int state);
+ void h_w(int state);
void c_w(u32 data);
// outputs
u8 gad_r();
u8 gbd_r();
- DECLARE_READ_LINE_MEMBER(dota_r);
- DECLARE_READ_LINE_MEMBER(dotb_r);
+ int dota_r();
+ int dotb_r();
protected:
// device-level overrides
diff --git a/src/devices/machine/am25s55x.cpp b/src/devices/machine/am25s55x.cpp
index b1624179463..f3073136aad 100644
--- a/src/devices/machine/am25s55x.cpp
+++ b/src/devices/machine/am25s55x.cpp
@@ -55,8 +55,6 @@ void am25s55x_device::device_start()
save_item(NAME(m_x.u));
save_item(NAME(m_y.u));
save_item(NAME(m_s_out.u));
-
- m_s.resolve_safe();
}
void am25s55x_device::device_reset()
diff --git a/src/devices/machine/am2847.cpp b/src/devices/machine/am2847.cpp
index 7e7992a2e85..125a50b7965 100644
--- a/src/devices/machine/am2847.cpp
+++ b/src/devices/machine/am2847.cpp
@@ -62,25 +62,25 @@ void am2847_base_device::init()
m_out = 0;
}
-WRITE_LINE_MEMBER( am2847_base_device::in_a_w )
+void am2847_base_device::in_a_w(int state)
{
m_in &= ~0x01;
m_in |= state;
}
-WRITE_LINE_MEMBER( am2847_base_device::in_b_w )
+void am2847_base_device::in_b_w(int state)
{
m_in &= ~0x02;
m_in |= state << 1;
}
-WRITE_LINE_MEMBER( am2847_base_device::in_c_w )
+void am2847_base_device::in_c_w(int state)
{
m_in &= ~0x04;
m_in |= state << 2;
}
-WRITE_LINE_MEMBER( am2847_base_device::in_d_w )
+void am2847_base_device::in_d_w(int state)
{
m_in &= ~0x08;
m_in |= state << 3;
@@ -91,25 +91,25 @@ void am2847_base_device::in_w(uint8_t data)
m_in = data & 0x0f;
}
-WRITE_LINE_MEMBER( am2847_base_device::rc_a_w )
+void am2847_base_device::rc_a_w(int state)
{
m_rc &= ~0x01;
m_rc |= state;
}
-WRITE_LINE_MEMBER( am2847_base_device::rc_b_w )
+void am2847_base_device::rc_b_w(int state)
{
m_rc &= ~0x02;
m_rc |= state << 1;
}
-WRITE_LINE_MEMBER( am2847_base_device::rc_c_w )
+void am2847_base_device::rc_c_w(int state)
{
m_rc &= ~0x04;
m_rc |= state << 2;
}
-WRITE_LINE_MEMBER( am2847_base_device::rc_d_w )
+void am2847_base_device::rc_d_w(int state)
{
m_rc &= ~0x08;
m_rc |= state << 3;
@@ -120,7 +120,7 @@ void am2847_base_device::rc_w(uint8_t data)
m_rc = data & 0x0f;
}
-WRITE_LINE_MEMBER( am2847_base_device::cp_w )
+void am2847_base_device::cp_w(int state)
{
if (m_cp != state && state != 0)
{
diff --git a/src/devices/machine/am2847.h b/src/devices/machine/am2847.h
index b5d90642e32..f0139233f12 100644
--- a/src/devices/machine/am2847.h
+++ b/src/devices/machine/am2847.h
@@ -48,19 +48,19 @@
class am2847_base_device : public device_t
{
public:
- DECLARE_WRITE_LINE_MEMBER( in_a_w );
- DECLARE_WRITE_LINE_MEMBER( in_b_w );
- DECLARE_WRITE_LINE_MEMBER( in_c_w );
- DECLARE_WRITE_LINE_MEMBER( in_d_w );
+ void in_a_w(int state);
+ void in_b_w(int state);
+ void in_c_w(int state);
+ void in_d_w(int state);
void in_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( rc_a_w );
- DECLARE_WRITE_LINE_MEMBER( rc_b_w );
- DECLARE_WRITE_LINE_MEMBER( rc_c_w );
- DECLARE_WRITE_LINE_MEMBER( rc_d_w );
+ void rc_a_w(int state);
+ void rc_b_w(int state);
+ void rc_c_w(int state);
+ void rc_d_w(int state);
void rc_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( cp_w );
+ void cp_w(int state);
uint8_t out_r() const { return m_out; }
diff --git a/src/devices/machine/am2901b.cpp b/src/devices/machine/am2901b.cpp
index a37ec638085..601cbf679d9 100644
--- a/src/devices/machine/am2901b.cpp
+++ b/src/devices/machine/am2901b.cpp
@@ -93,18 +93,6 @@ void am2901b_device::device_start()
save_item(NAME(m_f0_out));
save_item(NAME(m_f3_out));
save_item(NAME(m_co_out));
-
- m_y.resolve_safe();
- m_g.resolve_safe();
- m_p.resolve_safe();
- m_q0.resolve_safe();
- m_q3.resolve_safe();
- m_ram0.resolve_safe();
- m_ram3.resolve_safe();
- m_ovr.resolve_safe();
- m_f0.resolve_safe();
- m_f3.resolve_safe();
- m_co.resolve_safe();
}
void am2901b_device::device_reset()
@@ -160,32 +148,32 @@ void am2901b_device::i_w(uint16_t data)
m_i = data;
}
-WRITE_LINE_MEMBER(am2901b_device::q0_w)
+void am2901b_device::q0_w(int state)
{
m_q0_in = (bool)state;
}
-WRITE_LINE_MEMBER(am2901b_device::q3_w)
+void am2901b_device::q3_w(int state)
{
m_q3_in = (bool)state;
}
-WRITE_LINE_MEMBER(am2901b_device::ram0_w)
+void am2901b_device::ram0_w(int state)
{
m_ram0_in = (bool)state;
}
-WRITE_LINE_MEMBER(am2901b_device::ram3_w)
+void am2901b_device::ram3_w(int state)
{
m_ram3_in = (bool)state;
}
-WRITE_LINE_MEMBER(am2901b_device::ci_w)
+void am2901b_device::ci_w(int state)
{
m_ci = (bool)state;
}
-WRITE_LINE_MEMBER(am2901b_device::cp_w)
+void am2901b_device::cp_w(int state)
{
bool old = m_cp;
m_cp = (bool)state;
@@ -216,13 +204,13 @@ void am2901b_device::disassemble()
};
char dasm_buf[64];
- int buf_idx = snprintf(dasm_buf, ARRAY_LENGTH(dasm_buf), "%s %s", s_func_table[(m_i >> 3) & 7], s_dst_table[(m_i >> 6) & 7]);
+ int buf_idx = snprintf(dasm_buf, std::size(dasm_buf), "%s %s", s_func_table[(m_i >> 3) & 7], s_dst_table[(m_i >> 6) & 7]);
while (buf_idx < 12)
{
dasm_buf[buf_idx] = ' ';
buf_idx++;
}
- snprintf(dasm_buf + buf_idx, ARRAY_LENGTH(dasm_buf) - 12, "%c,%c", s_r_table[m_i & 7], s_s_table[m_i & 7]);
+ snprintf(dasm_buf + buf_idx, std::size(dasm_buf) - 12, "%c,%c", s_r_table[m_i & 7], s_s_table[m_i & 7]);
LOG("%s: %s\n", machine().describe_context(), dasm_buf);
}
diff --git a/src/devices/machine/am2901b.h b/src/devices/machine/am2901b.h
index 4e7a25e3915..aa35d4589b7 100644
--- a/src/devices/machine/am2901b.h
+++ b/src/devices/machine/am2901b.h
@@ -41,12 +41,12 @@ public:
void d_w(uint8_t data);
void i_w(uint16_t data);
- DECLARE_WRITE_LINE_MEMBER(q0_w);
- DECLARE_WRITE_LINE_MEMBER(q3_w);
- DECLARE_WRITE_LINE_MEMBER(ram0_w);
- DECLARE_WRITE_LINE_MEMBER(ram3_w);
- DECLARE_WRITE_LINE_MEMBER(ci_w);
- DECLARE_WRITE_LINE_MEMBER(cp_w);
+ void q0_w(int state);
+ void q3_w(int state);
+ void ram0_w(int state);
+ void ram3_w(int state);
+ void ci_w(int state);
+ void cp_w(int state);
private:
// device-level overrides
diff --git a/src/devices/machine/am2910.cpp b/src/devices/machine/am2910.cpp
index f3b425d86cb..70b47c30c68 100644
--- a/src/devices/machine/am2910.cpp
+++ b/src/devices/machine/am2910.cpp
@@ -14,9 +14,9 @@
#include "emu.h"
#include "am2910.h"
-#define LOG_INSN (1 << 0)
-#define LOG_STACK (1 << 1)
-#define LOG_ERROR (1 << 2)
+#define LOG_INSN (1U << 1)
+#define LOG_STACK (1U << 2)
+#define LOG_ERROR (1U << 3)
#define LOG_ALL (LOG_INSN | LOG_STACK | LOG_ERROR)
#define VERBOSE (0)
@@ -63,14 +63,8 @@ void am2910_device::device_start()
save_item(NAME(m_d));
save_item(NAME(m_i));
- m_y.resolve_safe();
- m_full.resolve_safe();
- m_pl.resolve_safe();
- m_map.resolve_safe();
- m_vect.resolve_safe();
-
if (clock())
- m_execute_timer = timer_alloc(TIMER_CLOCK);
+ m_execute_timer = timer_alloc(FUNC(am2910_device::clock_tick), this);
else
m_execute_timer = nullptr;
}
@@ -86,35 +80,32 @@ void am2910_device::device_reset()
m_execute_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
}
-void am2910_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(am2910_device::clock_tick)
{
- if (id == TIMER_CLOCK)
- {
- cp_w(m_cp ? 0 : 1);
- }
+ cp_w(m_cp ? 0 : 1);
}
-WRITE_LINE_MEMBER(am2910_device::cc_w)
+void am2910_device::cc_w(int state)
{
m_cc = state;
}
-WRITE_LINE_MEMBER(am2910_device::ccen_w)
+void am2910_device::ccen_w(int state)
{
m_ccen = state;
}
-WRITE_LINE_MEMBER(am2910_device::ci_w)
+void am2910_device::ci_w(int state)
{
m_ci = state;
}
-WRITE_LINE_MEMBER(am2910_device::rld_w)
+void am2910_device::rld_w(int state)
{
m_rld = state;
}
-WRITE_LINE_MEMBER(am2910_device::cp_w)
+void am2910_device::cp_w(int state)
{
int old_state = m_cp;
m_cp = state;
diff --git a/src/devices/machine/am2910.h b/src/devices/machine/am2910.h
index b304d7a09a9..6cbcbb15489 100644
--- a/src/devices/machine/am2910.h
+++ b/src/devices/machine/am2910.h
@@ -24,11 +24,11 @@ public:
// construction/destruction
am2910_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER(cc_w); // !CC
- DECLARE_WRITE_LINE_MEMBER(ccen_w); // !CCEN
- DECLARE_WRITE_LINE_MEMBER(ci_w); // CI
- DECLARE_WRITE_LINE_MEMBER(rld_w); // !RLD
- DECLARE_WRITE_LINE_MEMBER(cp_w); // CP
+ void cc_w(int state); // !CC
+ void ccen_w(int state); // !CCEN
+ void ci_w(int state); // CI
+ void rld_w(int state); // !RLD
+ void cp_w(int state); // CP
void d_w(uint16_t data);
void i_w(uint8_t data);
@@ -42,9 +42,8 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- static constexpr device_timer_id TIMER_CLOCK = 0;
+ TIMER_CALLBACK_MEMBER(clock_tick);
emu_timer *m_execute_timer;
diff --git a/src/devices/machine/am53cf96.cpp b/src/devices/machine/am53cf96.cpp
deleted file mode 100644
index 891f43f680b..00000000000
--- a/src/devices/machine/am53cf96.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:smf
-/*
- * am53cf96.c
- *
- * AMD/NCR/Symbios 53CF96 SCSI-2 controller.
- * Qlogic FAS-236 and Emulex ESP-236 are equivalents
- *
- * References:
- * AMD Am53CF96 manual
- *
- */
-
-#include "emu.h"
-#include "am53cf96.h"
-#include "bus/scsi/scsihle.h"
-
-uint8_t am53cf96_device::read(offs_t offset)
-{
- static constexpr int states[] = { 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 0 };
-
- if (offset == REG_STATUS)
- {
- scsi_regs[REG_STATUS] &= ~0x7;
- scsi_regs[REG_STATUS] |= states[xfer_state];
- if (xfer_state < 10)
- {
- xfer_state++;
- }
- }
-
- int rv = scsi_regs[offset];
-
- if (offset == REG_FIFO)
- {
-// logerror("53cf96: read FIFO %s\n", machine().describe_context());
- return 0;
- }
-
-// logerror("53cf96: read reg %d = %x %s\n", reg, rv>>shift, machine().describe_context());
-
- if (offset == REG_IRQSTATE)
- {
- scsi_regs[REG_STATUS] &= ~0x80; // clear IRQ flag
- }
-
- return rv;
-}
-
-void am53cf96_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
-{
- scsi_regs[REG_IRQSTATE] = 8; // indicate success
- scsi_regs[REG_STATUS] |= 0x80; // indicate IRQ
- m_irq_handler(1);
-}
-
-void am53cf96_device::write(offs_t offset, uint8_t data)
-{
-// logerror("53cf96: w %x to reg %d %s\n", data, offset, machine().describe_context());
-
- // if writing to the target ID, cache it off for later
- if (offset == REG_STATUS)
- {
- last_id = data;
- }
-
- if (offset == REG_XFERCNTLOW || offset == REG_XFERCNTMID || offset == REG_XFERCNTHI)
- {
- scsi_regs[REG_STATUS] &= ~0x10; // clear CTZ bit
- }
-
- // FIFO
- if (offset == REG_FIFO)
- {
-// osd_printf_debug("%02x to FIFO @ %02d\n", data, fptr);
- fifo[fptr++] = data;
- if (fptr > 15)
- {
- fptr = 15;
- }
- }
-
- // command
- if (offset == REG_COMMAND)
- {
- //dma = (data & 0x80) ? 1 : 0;
- fptr = 0;
- switch (data & 0x7f)
- {
- case 0: // NOP
- scsi_regs[REG_IRQSTATE] = 8; // indicate success
- xfer_state = 0;
- break;
- case 2: // reset am53cf96
- scsi_regs[REG_IRQSTATE] = 8; // indicate success
-
- logerror("53cf96: reset target ID = %d %s\n", last_id, machine().describe_context());
-
- xfer_state = 0;
- break;
- case 3: // reset SCSI bus
- scsi_regs[REG_INTSTATE] = 4; // command sent OK
-
- reset_bus();
-
- xfer_state = 0;
- m_transfer_timer->adjust( attotime::from_hz( 16384 ) );
- break;
- case 0x42: // select with ATN steps
- m_transfer_timer->adjust( attotime::from_hz( 16384 ) );
- if ((fifo[1] == 0) || (fifo[1] == 0x48) || (fifo[1] == 0x4b))
- {
- scsi_regs[REG_INTSTATE] = 6;
- }
- else
- {
- scsi_regs[REG_INTSTATE] = 4;
- }
-
- logerror("53cf96: command %x exec. target ID = %d %s\n", fifo[1], last_id, machine().describe_context());
-
- select(last_id);
- send_command(&fifo[1], 12);
- xfer_state = 0;
- break;
- case 0x44: // enable selection/reselection
- xfer_state = 0;
- break;
- case 0x10: // information transfer (must not change xfer_state)
- case 0x11: // second phase of information transfer
- case 0x12: // message accepted
- m_transfer_timer->adjust( attotime::from_hz( 16384 ) );
- scsi_regs[REG_INTSTATE] = 6; // command sent OK
- break;
- default:
- printf( "unsupported command %02x\n", data );
- break;
- }
- }
-
- // only update the register mirror if it's not a write-only reg
- if (offset != REG_STATUS && offset != REG_INTSTATE && offset != REG_IRQSTATE && offset != REG_FIFOSTATE)
- {
- scsi_regs[offset] = data;
- }
-}
-
-am53cf96_device::am53cf96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- legacy_scsi_host_adapter(mconfig, AM53CF96, tag, owner, clock),
- m_irq_handler(*this)
-{
-}
-
-void am53cf96_device::device_start()
-{
- legacy_scsi_host_adapter::device_start();
-
- m_irq_handler.resolve_safe();
-
- memset(scsi_regs, 0, sizeof(scsi_regs));
-
- fptr = 0;
- xfer_state = 0;
- last_id = -1;
-
- save_item( NAME( scsi_regs ) );
- save_item( NAME( fifo ) );
- save_item( NAME( fptr ) );
- save_item( NAME( xfer_state ) );
- save_item( NAME( last_id ) );
-
- m_transfer_timer = timer_alloc( TIMER_TRANSFER );
-}
-
-// retrieve data from the SCSI controller
-void am53cf96_device::dma_read_data(int bytes, uint8_t *pData)
-{
- scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished
-
- read_data(pData, bytes);
-}
-
-// write data to the SCSI controller
-void am53cf96_device::dma_write_data(int bytes, uint8_t *pData)
-{
-// int i;
-
- scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished
-
- write_data(pData, bytes);
-}
-
-DEFINE_DEVICE_TYPE(AM53CF96, am53cf96_device, "am53cf96", "AMD 53CF96 SCSI")
diff --git a/src/devices/machine/am53cf96.h b/src/devices/machine/am53cf96.h
deleted file mode 100644
index d9b2ce1aab4..00000000000
--- a/src/devices/machine/am53cf96.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:smf
-/*
- * am53cf96.h
- *
- */
-
-#ifndef MAME_MACHINE_AM53CF96_H
-#define MAME_MACHINE_AM53CF96_H
-
-#pragma once
-
-#include "legscsi.h"
-
-class am53cf96_device : public legacy_scsi_host_adapter
-{
-public:
- // construction/destruction
- am53cf96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto irq_handler() { return m_irq_handler.bind(); }
-
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
-
- void dma_read_data(int bytes, uint8_t *pData);
- void dma_write_data(int bytes, uint8_t *pData);
-
-protected:
- // 53CF96 register set
- enum
- {
- REG_XFERCNTLOW = 0, // read = current xfer count lo byte, write = set xfer count lo byte
- REG_XFERCNTMID, // read = current xfer count mid byte, write = set xfer count mid byte
- REG_FIFO, // read/write = FIFO
- REG_COMMAND, // read/write = command
-
- REG_STATUS, // read = status, write = destination SCSI ID (4)
- REG_IRQSTATE, // read = IRQ status, write = timeout (5)
- REG_INTSTATE, // read = internal state, write = sync xfer period (6)
- REG_FIFOSTATE, // read = FIFO status, write = sync offset
- REG_CTRL1, // read/write = control 1
- REG_CLOCKFCTR, // clock factor (write only)
- REG_TESTMODE, // test mode (write only)
- REG_CTRL2, // read/write = control 2
- REG_CTRL3, // read/write = control 3
- REG_CTRL4, // read/write = control 4
- REG_XFERCNTHI, // read = current xfer count hi byte, write = set xfer count hi byte
- REG_DATAALIGN // data alignment (write only)
- };
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
-private:
- static constexpr device_timer_id TIMER_TRANSFER = 0;
-
- uint8_t scsi_regs[32];
- uint8_t fifo[16];
- uint8_t fptr;
- uint8_t xfer_state;
- uint8_t last_id;
-
- emu_timer* m_transfer_timer;
- devcb_write_line m_irq_handler;
-};
-
-// device type definition
-DECLARE_DEVICE_TYPE(AM53CF96, am53cf96_device)
-
-#endif // MAME_MACHINE_AM53CF96_H
diff --git a/src/devices/machine/am79c30.cpp b/src/devices/machine/am79c30.cpp
index ed31a517398..9c041d8c383 100644
--- a/src/devices/machine/am79c30.cpp
+++ b/src/devices/machine/am79c30.cpp
@@ -95,18 +95,6 @@ am79c30a_device::am79c30a_device(const machine_config &mconfig, const char *tag,
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void am79c30a_device::device_resolve_objects()
-{
- m_int_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
diff --git a/src/devices/machine/am79c30.h b/src/devices/machine/am79c30.h
index 0188b2c9623..43164622000 100644
--- a/src/devices/machine/am79c30.h
+++ b/src/devices/machine/am79c30.h
@@ -78,8 +78,7 @@ public:
void bctb_w(u8 data);
protected:
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/am79c90.cpp b/src/devices/machine/am79c90.cpp
index c48a8cd8236..8c6a36221f3 100644
--- a/src/devices/machine/am79c90.cpp
+++ b/src/devices/machine/am79c90.cpp
@@ -44,7 +44,8 @@
#include "emu.h"
#include "am79c90.h"
-#define LOG_GENERAL (1U << 0)
+#include "multibyte.h"
+
#define LOG_REG (1U << 1)
#define LOG_INIT (1U << 2)
#define LOG_RXTX (1U << 3)
@@ -59,9 +60,9 @@ DEFINE_DEVICE_TYPE(AM79C90, am79c90_device, "am79c90", "Am79C90 C-LANCE Ethernet
am7990_device_base::am7990_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
- , device_network_interface(mconfig, *this, 10.0f)
+ , device_network_interface(mconfig, *this, 10)
, m_intr_out_cb(*this)
- , m_dma_in_cb(*this)
+ , m_dma_in_cb(*this, 0)
, m_dma_out_cb(*this)
, m_transmit_poll(nullptr)
, m_intr_out_state(1)
@@ -83,11 +84,7 @@ constexpr attotime am7990_device_base::TX_POLL_PERIOD;
void am7990_device_base::device_start()
{
- m_intr_out_cb.resolve_safe();
- m_dma_in_cb.resolve_safe(0);
- m_dma_out_cb.resolve_safe();
-
- m_transmit_poll = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(am7990_device_base::transmit_poll), this));
+ m_transmit_poll = timer_alloc(FUNC(am7990_device_base::transmit_poll), this);
m_transmit_poll->adjust(TX_POLL_PERIOD, 0, TX_POLL_PERIOD);
save_item(NAME(m_rap));
@@ -289,7 +286,7 @@ void am7990_device_base::recv_complete_cb(int result)
LOGMASKED(LOG_RXTX, "receive complete rmd1 0x%04x rmd3 %d\n", m_rx_md[1], result & RMD3_MCNT);
m_dma_out_cb(ring_address | 2, m_rx_md[1]);
- m_dma_out_cb(ring_address | 6, result & RMD3_MCNT);
+ m_dma_out_cb(ring_address | 6, (m_rx_md[1] & RMD1_ERR) ? 0 : (result & RMD3_MCNT));
// advance the ring
m_rx_ring_pos = (m_rx_ring_pos + 1) & m_rx_ring_mask;
@@ -302,7 +299,7 @@ void am7990_device_base::recv_complete_cb(int result)
update_interrupts();
}
-void am7990_device_base::transmit_poll(void *ptr, s32 param)
+void am7990_device_base::transmit_poll(s32 param)
{
// check transmitter enabled
if (m_csr[0] & CSR0_TXON)
@@ -442,10 +439,8 @@ void am7990_device_base::transmit()
u32 const crc = util::crc32_creator::simple(buf, length);
// insert the fcs
- buf[length++] = crc >> 0;
- buf[length++] = crc >> 8;
- buf[length++] = crc >> 16;
- buf[length++] = crc >> 24;
+ put_u32le(&buf[length], crc);
+ length += 4;
}
LOGMASKED(LOG_RXTX, "transmit sending packet length %d\n", length);
@@ -482,7 +477,7 @@ void am7990_device_base::transmit()
}
}
- send(buf, length);
+ send(buf, length, 4);
}
void am7990_device_base::send_complete_cb(int result)
@@ -696,13 +691,10 @@ void am7990_device_base::initialize()
set_promisc(m_mode & MODE_PROM);
- m_physical_addr[0] = init_block[1];
- m_physical_addr[1] = init_block[1] >> 8;
- m_physical_addr[2] = init_block[2];
- m_physical_addr[3] = init_block[2] >> 8;
- m_physical_addr[4] = init_block[3];
- m_physical_addr[5] = init_block[3] >> 8;
- set_mac((char *)m_physical_addr);
+ put_u16le(&m_physical_addr[0], init_block[1]);
+ put_u16le(&m_physical_addr[2], init_block[2]);
+ put_u16le(&m_physical_addr[4], init_block[3]);
+ set_mac(m_physical_addr);
m_logical_addr_filter = (u64(init_block[7]) << 48) | (u64(init_block[6]) << 32) | (u32(init_block[5]) << 16) | init_block[4];
@@ -749,15 +741,9 @@ void am7990_device_base::dma_in(u32 address, u8 *buf, int length)
u16 const word = m_dma_in_cb(address);
if (m_csr[3] & CSR3_BSWP)
- {
- buf[0] = word >> 8;
- buf[1] = word & 0xff;
- }
+ put_u16be(&buf[0], word);
else
- {
- buf[0] = word & 0xff;
- buf[1] = word >> 8;
- }
+ put_u16le(&buf[0], word);
buf += 2;
address += 2;
@@ -798,7 +784,7 @@ void am7990_device_base::dma_out(u32 address, u8 *buf, int length)
// word loop
while (length > 1)
{
- u16 const word = (m_csr[3] & CSR3_BSWP) ? (buf[0] << 8) | buf[1] : (buf[1] << 8) | buf[0];
+ u16 const word = (m_csr[3] & CSR3_BSWP) ? get_u16be(&buf[0]) : get_u16le(&buf[0]);
m_dma_out_cb(address, word);
diff --git a/src/devices/machine/am79c90.h b/src/devices/machine/am79c90.h
index 06ec00558b7..80c66ff58ce 100644
--- a/src/devices/machine/am79c90.h
+++ b/src/devices/machine/am79c90.h
@@ -6,7 +6,7 @@
#pragma once
-#include "hashing.h"
+#include "dinetwork.h"
class am7990_device_base : public device_t, public device_network_interface
{
diff --git a/src/devices/machine/am9513.cpp b/src/devices/machine/am9513.cpp
index 9e6a661b18b..34c5c5ec981 100644
--- a/src/devices/machine/am9513.cpp
+++ b/src/devices/machine/am9513.cpp
@@ -27,12 +27,11 @@
**********************************************************************/
#include "emu.h"
-#include "machine/am9513.h"
+#include "am9513.h"
-#define LOG_GENERAL (1U << 0)
-#define LOG_MODE (1U << 1)
+#define LOG_MODE (1U << 1)
#define LOG_INPUT (1U << 2)
-#define LOG_TC (1U << 3)
+#define LOG_TC (1U << 3)
//#define VERBOSE (LOG_GENERAL | LOG_MODE)
#include "logmacro.h"
@@ -79,10 +78,6 @@ am9513a_device::am9513a_device(const machine_config &mconfig, const char *tag, d
void am9513_device::device_start()
{
- // Resolve callbacks
- m_out_cb.resolve_all_safe();
- m_fout_cb.resolve();
-
// Power-on reset
m_dpr = 0x1f;
m_mmr = 0;
@@ -113,8 +108,8 @@ void am9513_device::device_start()
// Set up frequency timers
for (int f = 0; f < 5; f++)
{
- m_freq_timer[f] = timer_alloc(TIMER_F1 + f);
- m_freq_timer_selected[f] = (f == 0) ? (m_fout_cb.isnull() ? 0x3e : 0x3f) : 0;
+ m_freq_timer[f] = timer_alloc(FUNC(am9513_device::timer_tick), this);
+ m_freq_timer_selected[f] = (f == 0) ? (m_fout_cb.isunset() ? 0x3e : 0x3f) : 0;
m_freq_timer_cycle[f] = 0;
}
@@ -205,12 +200,12 @@ void am9513_device::init_freq_timer(int f)
attotime freq = clocks_to_attotime(scale);
if (m_freq_timer_cycle[f] == 0)
- m_freq_timer[f]->adjust(freq, 0, freq);
+ m_freq_timer[f]->adjust(freq, f, freq);
else
- m_freq_timer[f]->adjust(freq / 2, 0, freq / 2);
+ m_freq_timer[f]->adjust(freq / 2, f, freq / 2);
m_freq_timer[f]->enable(m_freq_timer_selected[f] != 0);
- LOGMASKED(LOG_GENERAL, "F%d = %f Hz (%s cycle emulation)\n", f + 1, double(clock()) / scale,
+ LOG("F%d = %f Hz (%s cycle emulation)\n", f + 1, double(clock()) / scale,
m_freq_timer_selected[f] == 0 ? "no" : m_freq_timer_cycle[f] == 0 ? "partial" : "full");
}
@@ -228,21 +223,18 @@ void am9513_device::device_clock_changed()
//-------------------------------------------------
-// device_timer - called whenever a device timer
-// fires
+// timer_tick - advance our counters
//-------------------------------------------------
-void am9513_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(am9513_device::timer_tick)
{
- assert(id >= TIMER_F1 && id <= TIMER_F5);
-
- int cycle = m_freq_timer_cycle[id - TIMER_F1] == 0 ? 2 : 1;
+ int cycle = m_freq_timer_cycle[param] == 0 ? 2 : 1;
while (cycle-- > 0)
{
- m_f ^= 1 << (id - TIMER_F1);
- bool level = BIT(m_f, id - TIMER_F1);
+ m_f ^= 1 << param;
+ bool level = BIT(m_f, param);
- int source = id - TIMER_F1 + 11;
+ int source = param + 11;
for (int c = 0; c < 5; c++)
{
if ((m_counter_mode[c] & 0x0f00) >> 8 == source && BIT(m_counter_mode[c], 12) == !level)
@@ -250,7 +242,7 @@ void am9513_device::device_timer(emu_timer &timer, device_timer_id id, int param
}
// FOUT Source = Fn
- if ((m_mmr & 0x00f0) >> 4 == source || ((m_mmr & 0x00f0) == 0 && id == TIMER_F1))
+ if ((m_mmr & 0x00f0) >> 4 == source || ((m_mmr & 0x00f0) == 0 && param == 0))
fout_tick();
}
}
@@ -329,7 +321,7 @@ void am9513_device::set_master_mode(u16 data)
if (source >= 11 && source <= 15)
{
LOGMASKED(LOG_MODE, "FOUT = F%d / %d\n", source - 10, divider);
- select_freq_timer(source - 11, 0, !m_fout_cb.isnull(), BIT(divider, 0));
+ select_freq_timer(source - 11, 0, !m_fout_cb.isunset(), BIT(divider, 0));
}
else if (source >= 6 && source <= 10)
LOGMASKED(LOG_MODE, "FOUT = GATE %d / %d\n", source - 5, divider);
@@ -521,7 +513,7 @@ void am9513_device::arm_counter(int c)
{
if (!m_counter_armed[c])
{
- LOGMASKED(LOG_GENERAL, "Counter %d: Arming counter\n", c + 1);
+ LOG("Counter %d: Arming counter\n", c + 1);
m_counter_armed[c] = true;
// Count starts upon first active gate edge after arming in Modes C, F, I, L, O, R, X
@@ -539,7 +531,7 @@ void am9513_device::disarm_counter(int c)
{
if (m_counter_armed[c])
{
- LOGMASKED(LOG_GENERAL, "Counter %d: Disarming counter\n", c + 1);
+ LOG("Counter %d: Disarming counter\n", c + 1);
m_counter_armed[c] = false;
m_counter_running[c] = false;
}
@@ -553,7 +545,7 @@ void am9513_device::disarm_counter(int c)
void am9513_device::save_counter(int c)
{
m_counter_hold[c] = m_count[c];
- LOGMASKED(LOG_GENERAL, "Counter %d: Count %u saved\n", c + 1, m_count[c]);
+ LOG("Counter %d: Count %u saved\n", c + 1, m_count[c]);
}
@@ -872,7 +864,7 @@ void am9513_device::step_counter(int c, bool force_load)
if (force_load)
{
m_count[c] = reload_from_hold(c) ? m_counter_hold[c] : m_counter_load[c];
- LOGMASKED(LOG_GENERAL, "Counter %d: %u loaded\n", c + 1, m_count[c]);
+ LOG("Counter %d: %u loaded\n", c + 1, m_count[c]);
}
}
@@ -1115,7 +1107,7 @@ void am9513_device::internal_write(u16 data)
case 0x07: // Alarm 1 register
case 0x0f: // Alarm 2 register
if (m_alarm[BIT(m_dpr, 3)] != data)
- LOGMASKED(LOG_GENERAL, "Counter %d: Alarm = %u\n", BIT(m_dpr, 3) ? 2 : 1, data);
+ LOG("Counter %d: Alarm = %u\n", BIT(m_dpr, 3) ? 2 : 1, data);
m_alarm[BIT(m_dpr, 3)] = data;
break;
case 0x01: // Counter 1 mode register
@@ -1124,7 +1116,7 @@ void am9513_device::internal_write(u16 data)
case 0x04: // Counter 4 mode register
case 0x05: // Counter 5 mode register
if (m_counter_mode[(m_dpr & 7) - 1] != data)
- LOGMASKED(LOG_GENERAL, "Counter %d: Mode = %04X\n", m_dpr & 7, data);
+ LOG("Counter %d: Mode = %04X\n", m_dpr & 7, data);
set_counter_mode((m_dpr & 7) - 1, data);
break;
case 0x09: // Counter 1 load register
@@ -1133,7 +1125,7 @@ void am9513_device::internal_write(u16 data)
case 0x0c: // Counter 4 load register
case 0x0d: // Counter 5 load register
if (m_counter_load[(m_dpr & 7) - 1] != data)
- LOGMASKED(LOG_GENERAL, "Counter %d: Load = %u\n", m_dpr & 7, data);
+ LOG("Counter %d: Load = %u\n", m_dpr & 7, data);
m_counter_load[(m_dpr & 7) - 1] = data;
break;
case 0x11: case 0x19: // Counter 1 hold register
@@ -1142,7 +1134,7 @@ void am9513_device::internal_write(u16 data)
case 0x14: case 0x1c: // Counter 4 hold register
case 0x15: case 0x1d: // Counter 5 hold register
if (m_counter_hold[(m_dpr & 7) - 1] != data)
- LOGMASKED(LOG_GENERAL, "Counter %d: Hold = %u\n", m_dpr & 7, data);
+ LOG("Counter %d: Hold = %u\n", m_dpr & 7, data);
m_counter_hold[(m_dpr & 7) - 1] = data;
break;
default: // Invalid register
@@ -1464,7 +1456,7 @@ void am9513_device::fout_tick()
m_fout = !m_fout;
// Check whether the FOUT gate is on
- if (!BIT(m_mmr, 12) && !m_fout_cb.isnull())
+ if (!BIT(m_mmr, 12) && !m_fout_cb.isunset())
m_fout_cb(m_fout);
// Reload the counter
diff --git a/src/devices/machine/am9513.h b/src/devices/machine/am9513.h
index 0ea22285b4e..b19de879739 100644
--- a/src/devices/machine/am9513.h
+++ b/src/devices/machine/am9513.h
@@ -63,25 +63,25 @@ public:
void write16(offs_t offset, u16 data);
// Source N inputs
- DECLARE_WRITE_LINE_MEMBER(source1_w) { write_source(0, state); }
- DECLARE_WRITE_LINE_MEMBER(source2_w) { write_source(1, state); }
- DECLARE_WRITE_LINE_MEMBER(source3_w) { write_source(2, state); }
- DECLARE_WRITE_LINE_MEMBER(source4_w) { write_source(3, state); }
- DECLARE_WRITE_LINE_MEMBER(source5_w) { write_source(4, state); }
+ void source1_w(int state) { write_source(0, state); }
+ void source2_w(int state) { write_source(1, state); }
+ void source3_w(int state) { write_source(2, state); }
+ void source4_w(int state) { write_source(3, state); }
+ void source5_w(int state) { write_source(4, state); }
// Gate N inputs
- DECLARE_WRITE_LINE_MEMBER(gate1_w) { write_gate(0, state); }
- DECLARE_WRITE_LINE_MEMBER(gate2_w) { write_gate(1, state); }
- DECLARE_WRITE_LINE_MEMBER(gate3_w) { write_gate(2, state); }
- DECLARE_WRITE_LINE_MEMBER(gate4_w) { write_gate(3, state); }
- DECLARE_WRITE_LINE_MEMBER(gate5_w) { write_gate(4, state); }
+ void gate1_w(int state) { write_gate(0, state); }
+ void gate2_w(int state) { write_gate(1, state); }
+ void gate3_w(int state) { write_gate(2, state); }
+ void gate4_w(int state) { write_gate(3, state); }
+ void gate5_w(int state) { write_gate(4, state); }
// Gate N alternate inputs (8-bit mode only; multiplexed with DB8-DB12)
- DECLARE_WRITE_LINE_MEMBER(gate1a_w) { write_gate_alt(0, state); }
- DECLARE_WRITE_LINE_MEMBER(gate2a_w) { write_gate_alt(1, state); }
- DECLARE_WRITE_LINE_MEMBER(gate3a_w) { write_gate_alt(2, state); }
- DECLARE_WRITE_LINE_MEMBER(gate4a_w) { write_gate_alt(3, state); }
- DECLARE_WRITE_LINE_MEMBER(gate5a_w) { write_gate_alt(4, state); }
+ void gate1a_w(int state) { write_gate_alt(0, state); }
+ void gate2a_w(int state) { write_gate_alt(1, state); }
+ void gate3a_w(int state) { write_gate_alt(2, state); }
+ void gate4a_w(int state) { write_gate_alt(3, state); }
+ void gate5a_w(int state) { write_gate_alt(4, state); }
// diagnostic helper
std::string describe_register() const;
@@ -93,11 +93,11 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_clock_changed() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
// internal helpers
TIMER_CALLBACK_MEMBER(clear_outputs);
+ TIMER_CALLBACK_MEMBER(timer_tick);
void master_reset();
void init_freq_timer(int f);
void select_freq_timer(int f, int c, bool selected, bool cycle);
@@ -161,14 +161,6 @@ private:
// frequency timer
u8 m_f;
- enum
- {
- TIMER_F1,
- TIMER_F2,
- TIMER_F3,
- TIMER_F4,
- TIMER_F5
- };
emu_timer *m_freq_timer[5];
u8 m_freq_timer_selected[5];
u8 m_freq_timer_cycle[5];
diff --git a/src/devices/machine/am9516.cpp b/src/devices/machine/am9516.cpp
new file mode 100644
index 00000000000..451a436511c
--- /dev/null
+++ b/src/devices/machine/am9516.cpp
@@ -0,0 +1,1027 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * Am9516 Universal DMA Controller (UDC)
+ *
+ * Am9516A appears to be identical to the Am9516 but available in faster
+ * clock speeds.
+ *
+ * It seems likely that the Am9516 was derived from the Z8016. The latter
+ * supports Z80-style interrupt daisy chains, and has some additional
+ * functionality for dealing with Z8000-family segmented memory.
+ *
+ *
+ * Sources:
+ * - Personal Computer Products Data Book, © 1989 Advanced Micro Devices
+ *
+ * TODO:
+ * - search modes
+ * - chain load abort
+ * - hardware masks
+ */
+
+#include "emu.h"
+#include "am9516.h"
+
+#define LOG_REGR (1U << 1)
+#define LOG_REGW (1U << 2)
+#define LOG_COMMAND (1U << 3)
+#define LOG_DMA (1U << 4)
+
+//#define VERBOSE (LOG_GENERAL|LOG_REGR|LOG_REGW|LOG_COMMAND|LOG_DMA)
+#include "logmacro.h"
+
+enum master_mode_mask : u8
+{
+ MM0 = 1, // chip enable
+ MM1 = 2, // cpu interleave enable
+ MM2 = 4, // wait line enable
+ MM3 = 8, // no vector on interrupt
+};
+
+enum chain_control_mask : u16
+{
+ CC_CA = 0x0001, // chain address
+ CC_CM = 0x0002, // channel mode
+ CC_IV = 0x0004, // interrupt vector
+ CC_PM = 0x0008, // pattern and mask
+ CC_BOC = 0x0010, // base operation count
+ CC_BAB = 0x0020, // base address b
+ CC_BAA = 0x0040, // base address a
+ CC_COC = 0x0080, // current operation count
+ CC_CAB = 0x0100, // current address b
+ CC_CAA = 0x0200, // current address a
+
+ CC_WM = 0x03ff,
+};
+
+enum status_mask : u16
+{
+ S_TC = 0x0001, // terminal count
+ S_EOP = 0x0002, // end of process
+ S_MC = 0x0004, // match condition
+ S_MCL = 0x0008, // match condition low
+ S_MCH = 0x0010, // match condition high
+ S_HRQ = 0x0020, // hardware request
+ S_HM = 0x0040, // hardware mask
+ // reserved
+ // reserved
+ S_SIP = 0x0200, // second interrupt pending
+ S_WFB = 0x0400, // waiting for bus
+ S_NAC = 0x0800, // no auto-reload or chaining
+ S_CA = 0x1000, // chaining abort
+ S_IP = 0x2000, // interrupt pending
+ // reserved
+ S_CIE = 0x8000, // channel interrupt enable
+};
+
+enum cmh_mask : u16
+{
+ CMH_MC = 0x0003, // match control
+ CMH_DC = 0x0004, // dack control
+ CMH_HM = 0x0008, // hardware mask
+ CMH_SR = 0x0010, // software request
+
+ CMH_WM = 0x001f,
+};
+
+enum cmh_mc_mask : u16
+{
+ MC_00 = 0x0000, // stop on no match
+ MC_01 = 0x0020, // stop on no match
+ MC_10 = 0x0040, // stop on word match
+ MC_11 = 0x0060, // stop on byte match
+};
+
+enum cml_mask : u16
+{
+ CML_OPER = 0x000f, // operation
+ CML_FLIP = 0x0010, // flip bit
+ CML_TT = 0x0060, // transfer type
+ CML_IEOP = 0x0080, // interrupt enable - end of process
+ CML_IMC = 0x0100, // interrupt enable - match condition
+ CML_ITC = 0x0200, // interrupt enable - terminal count
+ CML_REOP = 0x0400, // reload enable - end of process
+ CML_RMC = 0x0800, // reload enable - match condition
+ CML_RTC = 0x1000, // reload enable - terminal count
+ CML_CEOP = 0x2000, // chain enable - end of process
+ CML_CMC = 0x4000, // chain enable - match condition
+ CML_CTC = 0x8000, // chain enable - terminal count
+};
+
+enum cml_tt_mask : u16
+{
+ TT_00 = 0x0000, // single transfer
+ TT_01 = 0x0020, // demand dedicated bus hold
+ TT_10 = 0x0040, // demand dedicated bus release
+ TT_11 = 0x0060, // demand interleave
+};
+
+enum aru_mask : u16
+{
+ ARU_WC = 0x0006, // wait control
+ ARU_AC = 0x0018, // address control
+ ARU_MI = 0x0040, // memory or i/o space
+ ARU_NS = 0x0080, // normal or system space
+ ARU_AR = 0x00c0, // address reference
+ ARU_UA = 0xff00, // upper address
+
+ ARU_WM = 0xffde,
+};
+
+enum aru_ac_mask : u16
+{
+ AC_INC = 0x0000, // increment
+ AC_DEC = 0x0008, // decrement
+ AC_HLD = 0x0010, // hold
+};
+
+enum is_mask : u16
+{
+ IS_VEC = 0x00ff, // vector
+ IS_CHN = 0x0100, // channel
+ IS_TC = 0x0200, // terminal count
+ IS_EOP = 0x0400, // end of process
+ IS_MC = 0x0800, // match condition
+ IS_CA = 0x1000, // chain aborted
+ IS_MCL = 0x2000, // match condition low
+ IS_MCH = 0x4000, // match condition high
+ IS_HRQ = 0x8000, // hardware request
+};
+
+DEFINE_DEVICE_TYPE(AM9516, am9516_device, "am9516", "Am9516 Universal DMA Controller")
+
+am9516_device::am9516_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, AM9516, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , m_space_config{
+ { "system_io", ENDIANNESS_BIG, 16, 24 },
+ { "system_mem", ENDIANNESS_BIG, 16, 24 },
+ { "normal_io", ENDIANNESS_BIG, 16, 24 },
+ { "normal_mem", ENDIANNESS_BIG, 16, 24 } }
+ , m_int(*this)
+ , m_eop(*this)
+ , m_int_state(true)
+ , m_eop_out_state(true)
+ , m_eop_in_state(false)
+ , m_pointer(0)
+ , m_channel{ *this, *this }
+{
+}
+
+void am9516_device::device_start()
+{
+ save_item(NAME(m_int_state));
+ save_item(NAME(m_eop_out_state));
+ save_item(NAME(m_eop_in_state));
+
+ save_item(NAME(m_mode));
+ save_item(NAME(m_pointer));
+ save_item(NAME(m_temporary));
+
+ save_item(STRUCT_MEMBER(m_channel, cabl));
+ save_item(STRUCT_MEMBER(m_channel, babl));
+ save_item(STRUCT_MEMBER(m_channel, caal));
+ save_item(STRUCT_MEMBER(m_channel, baal));
+ save_item(STRUCT_MEMBER(m_channel, cabu));
+ save_item(STRUCT_MEMBER(m_channel, babu));
+ save_item(STRUCT_MEMBER(m_channel, caau));
+ save_item(STRUCT_MEMBER(m_channel, baau));
+ save_item(STRUCT_MEMBER(m_channel, cal));
+ save_item(STRUCT_MEMBER(m_channel, cau));
+ save_item(STRUCT_MEMBER(m_channel, is));
+ save_item(STRUCT_MEMBER(m_channel, status));
+ save_item(STRUCT_MEMBER(m_channel, coc));
+ save_item(STRUCT_MEMBER(m_channel, boc));
+ save_item(STRUCT_MEMBER(m_channel, pattern));
+ save_item(STRUCT_MEMBER(m_channel, mask));
+ save_item(STRUCT_MEMBER(m_channel, cml));
+ save_item(STRUCT_MEMBER(m_channel, cmh));
+ save_item(STRUCT_MEMBER(m_channel, iv));
+
+ for (channel &ch : m_channel)
+ {
+ ch.cabl = 0;
+ ch.babl = 0;
+ ch.caal = 0;
+ ch.baal = 0;
+ ch.cabu = 0;
+ ch.babu = 0;
+ ch.caau = 0;
+ ch.baau = 0;
+ ch.cal = 0;
+ ch.cau = 0;
+ ch.status = 0;
+ ch.coc = 0;
+ ch.boc = 0;
+ ch.pattern = 0;
+ ch.mask = 0;
+ ch.cml = 0;
+ ch.cmh = 0;
+ ch.iv = 0;
+ }
+
+ m_channel[0].is = 0;
+ m_channel[1].is = IS_CHN;
+
+ m_channel[0].run = timer_alloc(timer_expired_delegate(FUNC(am9516_device::operate<0>), this));
+ m_channel[1].run = timer_alloc(timer_expired_delegate(FUNC(am9516_device::operate<1>), this));
+}
+
+void am9516_device::device_reset()
+{
+ m_mode = 0;
+
+ for (channel &ch : m_channel)
+ {
+ ch.run->reset();
+
+ ch.status = S_CA | S_NAC;
+ ch.is &= IS_CHN;
+ }
+
+ if (m_eop_out_state)
+ {
+ m_eop_out_state = false;
+ eop_w(!m_eop_out_state);
+ }
+
+ interrupt();
+}
+
+device_memory_interface::space_config_vector am9516_device::memory_space_config() const
+{
+ return space_config_vector{
+ std::make_pair(SYSTEM_IO, &m_space_config[0]),
+ std::make_pair(SYSTEM_MEM, &m_space_config[1]),
+ std::make_pair(NORMAL_IO, &m_space_config[2]),
+ std::make_pair(NORMAL_MEM, &m_space_config[3]),
+ };
+}
+
+u16 am9516_device::data_r()
+{
+ switch (m_pointer)
+ {
+ // address b lower
+ case 0x00: return m_channel[1].cabl;
+ case 0x02: return m_channel[0].cabl;
+ case 0x04: return m_channel[1].babl;
+ case 0x06: return m_channel[0].babl;
+ // address a lower
+ case 0x08: return m_channel[1].caal;
+ case 0x0a: return m_channel[0].caal;
+ case 0x0c: return m_channel[1].baal;
+ case 0x0e: return m_channel[0].baal;
+ // address b upper
+ case 0x10: return m_channel[1].cabu;
+ case 0x12: return m_channel[0].cabu;
+ case 0x14: return m_channel[1].babu;
+ case 0x16: return m_channel[0].babu;
+ // address a upper
+ case 0x18: return m_channel[1].caau;
+ case 0x1a: return m_channel[0].caau;
+ case 0x1c: return m_channel[1].baau;
+ case 0x1e: return m_channel[0].baau;
+ // chain address
+ case 0x20: return m_channel[1].cal;
+ case 0x22: return m_channel[0].cal;
+ case 0x24: return m_channel[1].cau;
+ case 0x26: return m_channel[0].cau;
+ // interrupt save
+ case 0x28: return m_channel[1].is;
+ case 0x2a: return m_channel[0].is;
+ // status
+ case 0x2c: return m_channel[1].status;
+ case 0x2e: return m_channel[0].status;
+ // operation count
+ case 0x30: return m_channel[1].coc;
+ case 0x32: return m_channel[0].coc;
+ case 0x34: return m_channel[1].boc;
+ case 0x36: return m_channel[0].boc;
+ // master mode
+ case 0x38: return m_mode;
+ // pattern
+ case 0x48: return m_channel[1].pattern;
+ case 0x4a: return m_channel[0].pattern;
+ // mask
+ case 0x4c: return m_channel[1].mask;
+ case 0x4e: return m_channel[0].mask;
+ // channel mode
+ case 0x50: return m_channel[1].cml;
+ case 0x52: return m_channel[0].cml;
+ case 0x54: return m_channel[1].cmh;
+ case 0x56: return m_channel[0].cmh;
+ // interrupt vector
+ case 0x58: return m_channel[1].iv;
+ case 0x5a: return m_channel[0].iv;
+
+ default:
+ LOG("undefined register 0x%02 (%s)\n",
+ m_pointer, machine().describe_context());
+ return 0;
+ }
+}
+
+void am9516_device::data_w(u16 data)
+{
+ switch (m_pointer)
+ {
+ // address b lower
+ case 0x00: m_channel[1].cabl = data; break;
+ case 0x02: m_channel[0].cabl = data; break;
+ case 0x04: m_channel[1].babl = data; break;
+ case 0x06: m_channel[0].babl = data; break;
+ // address a lower
+ case 0x08: m_channel[1].caal = data; break;
+ case 0x0a: m_channel[0].caal = data; break;
+ case 0x0c: m_channel[1].baal = data; break;
+ case 0x0e: m_channel[0].baal = data; break;
+ // address b upper
+ case 0x10: m_channel[1].cabu = data & ARU_WM; break;
+ case 0x12: m_channel[0].cabu = data & ARU_WM; break;
+ case 0x14: m_channel[1].babu = data & ARU_WM; break;
+ case 0x16: m_channel[0].babu = data & ARU_WM; break;
+ // address a upper
+ case 0x18: m_channel[1].caau = data & ARU_WM; break;
+ case 0x1a: m_channel[0].caau = data & ARU_WM; break;
+ case 0x1c: m_channel[1].baau = data & ARU_WM; break;
+ case 0x1e: m_channel[0].baau = data & ARU_WM; break;
+ // chain address
+ case 0x20: m_channel[1].cal = data; break;
+ case 0x22: m_channel[0].cal = data; break;
+ case 0x24: m_channel[1].cau = data & (ARU_UA | ARU_WC); break;
+ case 0x26: m_channel[0].cau = data & (ARU_UA | ARU_WC); break;
+ // command
+ case 0x2c:
+ case 0x2e:
+ command(data);
+ return;
+ // operation count
+ case 0x30: m_channel[1].coc = data; break;
+ case 0x32: m_channel[0].coc = data; break;
+ case 0x34: m_channel[1].boc = data; break;
+ case 0x36: m_channel[0].boc = data; break;
+ // master mode
+ case 0x38:
+ LOGMASKED(LOG_REGW, "master mode 0x%04x (%s)\n",
+ data, machine().describe_context());
+ m_mode = data & 0xf;
+ return;
+ // pattern
+ case 0x48: m_channel[1].pattern = data; break;
+ case 0x4a: m_channel[0].pattern = data; break;
+ // mask
+ case 0x4c: m_channel[1].mask = data; break;
+ case 0x4e: m_channel[0].mask = data; break;
+ // channel mode
+ case 0x50: m_channel[1].cml = data; m_channel[1].log_mode(LOG_GENERAL); break;
+ case 0x52: m_channel[0].cml = data; m_channel[0].log_mode(LOG_GENERAL); break;
+ // interrupt vector
+ case 0x58: m_channel[1].iv = data; break;
+ case 0x5a: m_channel[0].iv = data; break;
+
+ default:
+ LOG("undefined register 0x%02 data 0x%04x (%s)\n",
+ m_pointer, data, machine().describe_context());
+ return;
+ }
+
+ if (VERBOSE & LOG_REGW)
+ {
+ static char const *const reg_name[] =
+ {
+ "current address b lower", "base address b lower",
+ "current address a lower", "base address a lower",
+ "current address b upper", "base address b upper",
+ "current address a upper", "base address a upper",
+ "chain address lower", "chain address upper",
+ "interrupt save", "status",
+ "current operation count", "base operation count",
+ nullptr, nullptr, nullptr, nullptr,
+ "pattern", "mask",
+ "channel mode low", "channel mode high",
+ "interrupt vector", nullptr,
+ };
+
+ LOGMASKED(LOG_REGW, "channel %d %s 0x%04x (%s)\n",
+ !(m_pointer & 2), reg_name[m_pointer >> 2], data, machine().describe_context());
+ }
+}
+
+void am9516_device::command(u8 data)
+{
+ channel &ch = m_channel[BIT(data, 0)];
+
+ switch (data & 0xe0)
+ {
+ case 0x00: // reset
+ LOGMASKED(LOG_COMMAND, "reset (%s)\n", machine().describe_context());
+
+ reset();
+ break;
+
+ case 0x20: // interrupt control
+ LOGMASKED(LOG_COMMAND, "channel %d %s%s%s (%s)\n", BIT(data, 0), BIT(data, 1) ? "set" : "clear",
+ BIT(data, 4) ? " CIE" : "", BIT(data, 2) ? " IP" : "", machine().describe_context());
+
+ // update channel interrupt enable
+ if (BIT(data, 4))
+ {
+ if (BIT(data, 1))
+ ch.status |= S_CIE;
+ else
+ ch.status &= ~S_CIE;
+ }
+
+ // update interrupt pending
+ if (BIT(data, 2))
+ ch.interrupt(BIT(data, 1));
+
+ interrupt();
+ break;
+
+ case 0x40: // software request
+ LOGMASKED(LOG_COMMAND, "channel %d %s software request bit (%s)\n",
+ BIT(data, 0), BIT(data, 1) ? "set" : "clear", machine().describe_context());
+
+ if (BIT(data, 1))
+ {
+ ch.cmh |= CMH_SR;
+ ch.run->adjust(attotime::zero);
+ }
+ else
+ ch.cmh &= ~CMH_SR;
+ break;
+
+ case 0x60: // set/clear flip bit
+ LOGMASKED(LOG_COMMAND, "channel %d %s flip bit (%s)\n",
+ BIT(data, 0), BIT(data, 1) ? "set" : "clear", machine().describe_context());
+
+ if (BIT(data, 1))
+ ch.cml |= CML_FLIP;
+ else
+ ch.cml &= ~CML_FLIP;
+ break;
+
+ case 0x80: // hardware mask
+ LOGMASKED(LOG_COMMAND, "channel %d %s hardware mask bit (%s)\n",
+ BIT(data, 0), BIT(data, 1) ? "set" : "clear", machine().describe_context());
+
+ if (BIT(data, 1))
+ ch.cmh |= CMH_HM;
+ else
+ ch.cmh &= ~CMH_HM;
+ break;
+
+ case 0xa0: // start chain
+ LOGMASKED(LOG_COMMAND, "channel %d start chain (%s)\n",
+ BIT(data, 0), machine().describe_context());
+
+ ch.chain();
+ break;
+
+ default:
+ LOGMASKED(LOG_COMMAND, "channel %d unrecognized command 0x%02x (%s)\n",
+ BIT(data, 0), data, machine().describe_context());
+ break;
+ }
+}
+
+void am9516_device::eop_w(int state)
+{
+ LOGMASKED(LOG_DMA, "eop %s\n", state ? "cleared" : "asserted");
+ m_eop_in_state = !state;
+}
+
+template <unsigned Channel> void am9516_device::dreq_w(int state)
+{
+ LOGMASKED(LOG_DMA, "channel %d dreq %s\n", Channel, state ? "cleared" : "asserted");
+ channel &ch = m_channel[Channel];
+
+ if (!state)
+ {
+ ch.status |= S_HRQ;
+
+ if (!(ch.status & S_HM) && ch.run->expire().is_never())
+ ch.run->adjust(attotime::zero);
+ }
+ else
+ ch.status &= ~S_HRQ;
+}
+
+template void am9516_device::dreq_w<0>(int state);
+template void am9516_device::dreq_w<1>(int state);
+
+template <unsigned Channel> void am9516_device::operate(s32 param)
+{
+ channel &ch = m_channel[Channel];
+
+ if (!(m_mode & MM0) || (ch.status & S_SIP))
+ {
+ LOGMASKED(LOG_DMA, "channel %d bus access disabled\n", Channel);
+ return;
+ }
+
+ if (!(ch.status & S_HRQ) && !(ch.cmh & CMH_SR))
+ {
+ LOGMASKED(LOG_DMA, "channel %d no request pending\n", Channel);
+ return;
+ }
+
+ u16 status = 0;
+ unsigned cycles = 0;
+
+ switch (ch.cml & CML_OPER)
+ {
+ // transfer
+ case 0x1:
+ // byte/byte flowthru
+ cycles = 6;
+ m_temporary = ch.read_byte(cycles, ch.cml & CML_FLIP);
+ ch.write_byte(u8(m_temporary), cycles, ch.cml & CML_FLIP);
+
+ ch.coc--;
+ break;
+ case 0x8:
+ case 0x9:
+ cycles = 9;
+ if (ch.cml & CML_FLIP)
+ {
+ // word/byte flowthru
+ m_temporary = ch.read_word(cycles, ch.cml & CML_FLIP);
+
+ unsigned const shift = ch.cabu & AC_DEC;
+ ch.write_byte(u8(m_temporary >> (8 - shift)), cycles, ch.cml & CML_FLIP);
+ ch.write_byte(u8(m_temporary >> shift), cycles, ch.cml & CML_FLIP);
+ }
+ else
+ {
+ // byte/word flowthru
+ unsigned const shift = ch.cabu & AC_DEC;
+ m_temporary = u16(ch.read_byte(cycles, ch.cml & CML_FLIP)) << (8 - shift);
+ m_temporary |= u16(ch.read_byte(cycles, ch.cml & CML_FLIP)) << shift;
+
+ ch.write_word(m_temporary, cycles, ch.cml & CML_FLIP);
+ }
+
+ ch.coc--;
+ break;
+ case 0x0:
+ // word/word flowthru
+ cycles = 6;
+ m_temporary = ch.read_word(cycles, ch.cml & CML_FLIP);
+ ch.write_word(m_temporary, cycles, ch.cml & CML_FLIP);
+
+ ch.coc--;
+ break;
+ case 0x3:
+ // byte/byte flyby
+ cycles = 3;
+ if (ch.cml & CML_FLIP)
+ // from flyby to arb
+ ch.write_byte(ch.flyby_byte_r(), cycles);
+ else
+ // from ara to flyby
+ ch.flyby_byte_w(ch.read_byte(cycles));
+
+ ch.coc--;
+ break;
+ case 0x2:
+ // word/word flyby
+ cycles = 3;
+ if (ch.cml & CML_FLIP)
+ // from flyby to arb
+ ch.write_word(ch.flyby_word_r(), cycles);
+ else
+ // from ara to flyby
+ ch.flyby_word_w(ch.read_word(cycles));
+
+ ch.coc--;
+ break;
+
+ // transfer and search
+ case 0x5:
+ // byte/byte flowthru
+ break;
+ case 0xc:
+ case 0xd:
+ // byte/word flowthru
+ break;
+ case 0x4:
+ // word/word flowthru
+ break;
+ case 0x7:
+ // byte/byte flyby
+ break;
+ case 0x6:
+ // word/word flyby
+ break;
+
+ // search
+ case 0xf:
+ // byte/byte
+ break;
+ case 0xe:
+ // word/word
+ break;
+ case 0xa:
+ case 0xb:
+ // illegal
+ break;
+ }
+
+ // check for terminal count
+ if (ch.coc == 0)
+ status |= S_TC;
+
+ // check for end of process
+ if (m_eop_in_state)
+ status |= S_EOP;
+
+ if (status & (S_MC | S_EOP | S_TC))
+ complete(param, status);
+ else if (ch.cml & CML_TT)
+ ch.run->adjust(attotime::from_ticks(cycles, clock()));
+}
+
+void am9516_device::complete(unsigned const c, u16 status)
+{
+ channel &ch = m_channel[c];
+
+ ch.status &= ~(S_MCH | S_MCL | S_MC | S_EOP | S_TC);
+ ch.status |= status | S_NAC;
+
+ LOGMASKED(LOG_DMA, "channel %d complete status 0x%04x\n", c, ch.status);
+
+ m_eop(0);
+ m_eop(1);
+
+ // completion interrupt
+ if (((ch.status & S_TC) && (ch.cml & CML_ITC))
+ || ((ch.status & S_EOP) && (ch.cml & CML_IEOP))
+ || ((ch.status & S_MC) && (ch.cml & CML_IMC)))
+ {
+ ch.interrupt(true);
+
+ interrupt();
+ }
+
+ if (!(ch.status & S_SIP))
+ ch.reload();
+}
+
+void am9516_device::interrupt()
+{
+ bool const int_state =
+ ((m_channel[0].status & S_CIE) && (m_channel[0].status & S_IP)) ||
+ ((m_channel[1].status & S_CIE) && (m_channel[1].status & S_IP));
+
+ if (m_int_state != int_state)
+ {
+ LOG("interrupt %s\n", int_state ? "asserted" : "cleared");
+ m_int_state = int_state;
+ m_int(!m_int_state);
+ }
+}
+
+u16 am9516_device::acknowledge()
+{
+ for (channel &ch : m_channel)
+ {
+ if ((ch.status & S_CIE) && (ch.status & S_IP))
+ {
+ u16 const data = (m_mode & MM3) ? 0 : ch.is;
+
+ ch.interrupt(false);
+ interrupt();
+
+ return data;
+ }
+ }
+
+ fatalerror("%s: interrupt acknowledge with no pending interrupts\n", tag());
+}
+
+#undef LOG_OUTPUT_FUNC
+#define LOG_OUTPUT_FUNC udc.logerror
+
+u32 am9516_device::channel::address(u16 &aru, u16 &arl, int delta)
+{
+ u32 const current = u32(aru & ARU_UA) << 8 | arl;
+
+ if (!delta || (aru & AC_HLD))
+ return current;
+
+ if (!(aru & ARU_MI))
+ delta = 2;
+
+ if (aru & AC_DEC)
+ delta = -delta;
+
+ u32 const adjusted = current + delta;
+
+ aru = ((adjusted >> 8) & ARU_UA) | (aru & ~ARU_UA);
+ arl = u16(adjusted);
+
+ return current;
+}
+
+u8 am9516_device::channel::read_byte(unsigned &cycles, bool flip)
+{
+ u16 &cau = flip ? cabu : caau;
+ u16 &cal = flip ? cabl : caal;
+
+ cycles += wait_states[BIT(cau, 1, 2)];
+
+ return udc.space((cau & ARU_AR) >> 6).read_byte(address(cau, cal, 1));
+}
+
+void am9516_device::channel::write_byte(u8 data, unsigned &cycles, bool flip)
+{
+ u16 &cau = flip ? caau : cabu;
+ u16 &cal = flip ? caal : cabl;
+
+ cycles += wait_states[BIT(cau, 1, 2)];
+
+ udc.space((cau & ARU_AR) >> 6).write_byte(address(cau, cal, 1), data);
+}
+
+u16 am9516_device::channel::read_word(unsigned &cycles, bool flip)
+{
+ u16 &cau = flip ? cabu : caau;
+ u16 &cal = flip ? cabl : caal;
+
+ cycles += wait_states[BIT(cau, 1, 2)];
+
+ return udc.space((cau & ARU_AR) >> 6).read_word(address(cau, cal, 2));
+}
+
+void am9516_device::channel::write_word(u16 data, unsigned &cycles, bool flip)
+{
+ u16 &cau = flip ? caau : cabu;
+ u16 &cal = flip ? caal : cabl;
+
+ cycles += wait_states[BIT(cau, 1, 2)];
+
+ udc.space((cau & ARU_AR) >> 6).write_word(address(cau, cal, 2), data);
+}
+
+void am9516_device::channel::interrupt(bool assert)
+{
+ if (assert && (status & S_IP))
+ {
+ LOG("second interrupt pending\n");
+ status |= S_SIP;
+ return;
+ }
+
+ if (!assert)
+ {
+ status &= ~S_IP;
+ is &= IS_CHN;
+
+ if (status & S_SIP)
+ {
+ LOG("second interrupt cleared\n");
+ status &= ~S_SIP;
+
+ reload();
+ }
+ else
+ return;
+ }
+
+ status |= S_IP;
+ is |= bitswap<u16>(status, 5, 4, 3, 12, 2, 1, 0) << 9 | iv;
+}
+
+void am9516_device::channel::reload()
+{
+ // reload base to current
+ if (((status & S_TC) && (cml & CML_RTC))
+ || ((status & S_EOP) && (cml & CML_REOP))
+ || ((status & S_MC) && (cml & CML_RMC)))
+ {
+ LOGMASKED(LOG_DMA, "reload base to current\n");
+ caau = baau;
+ caal = baal;
+ cabu = babu;
+ cabl = babl;
+ coc = boc;
+
+ log_addr(LOG_DMA, "current address a", caau, caal);
+ log_addr(LOG_DMA, "current address b", cabu, cabl);
+ LOGMASKED(LOG_DMA, "current operation count 0x%04x\n", coc);
+
+ status &= ~S_NAC;
+ }
+
+ // reload chain
+ if (((status & S_TC) && (cml & CML_CTC))
+ || ((status & S_EOP) && (cml & CML_CEOP))
+ || ((status & S_MC) && (cml & CML_CMC)))
+ {
+ LOGMASKED(LOG_DMA, "reload chain\n");
+ chain();
+ }
+}
+
+void am9516_device::channel::chain()
+{
+ address_space &s(udc.space(SYSTEM_MEM));
+
+ // TODO: abort on EOP
+
+ // fetch reload word
+ u32 chain_address = address(cau, cal);
+ u16 reload = s.read_word(chain_address) & CC_WM;
+ LOGMASKED(LOG_REGW, "chain address 0x%06x reload word 0x%04x\n", chain_address, reload);
+ chain_address += 2;
+
+ // current address a
+ if (reload & CC_CAA)
+ {
+ caau = s.read_word(chain_address + 0) & ARU_WM;
+ caal = s.read_word(chain_address + 2);
+
+ LOGMASKED(LOG_REGW, "current address a 0x%04x 0x%04x\n", caau, caal);
+ log_addr(LOG_DMA, "current address a", caau, caal);
+
+ chain_address += 4;
+ }
+
+ // current address b
+ if (reload & CC_CAB)
+ {
+ cabu = s.read_word(chain_address + 0) & ARU_WM;
+ cabl = s.read_word(chain_address + 2);
+
+ LOGMASKED(LOG_REGW, "current address b 0x%04x 0x%04x\n", cabu, cabl);
+ log_addr(LOG_DMA, "current address b", cabu, cabl);
+
+ chain_address += 4;
+ }
+
+ // current operation count
+ if (reload & CC_COC)
+ {
+ coc = s.read_word(chain_address);
+
+ LOGMASKED(LOG_DMA, "current operation count 0x%04x\n", coc);
+
+ chain_address += 2;
+ }
+
+ // base address a
+ if (reload & CC_BAA)
+ {
+ baau = s.read_word(chain_address + 0) & ARU_WM;
+ baal = s.read_word(chain_address + 2);
+
+ LOGMASKED(LOG_REGW, "base address a 0x%04x 0x%04x\n", baau, baal);
+
+ chain_address += 4;
+ }
+
+ // base address b
+ if (reload & CC_BAB)
+ {
+ babu = s.read_word(chain_address + 0) & ARU_WM;
+ babl = s.read_word(chain_address + 2);
+
+ LOGMASKED(LOG_REGW, "base address b 0x%04x 0x%04x\n", babu, babl);
+
+ chain_address += 4;
+ }
+
+ // base operation count
+ if (reload & CC_BOC)
+ {
+ boc = s.read_word(chain_address);
+
+ LOGMASKED(LOG_REGW, "base operation count 0x%04x\n", boc);
+
+ chain_address += 2;
+ }
+
+ // pattern and mask
+ if (reload & CC_PM)
+ {
+ pattern = s.read_word(chain_address + 0);
+ mask = s.read_word(chain_address + 2);
+
+ LOGMASKED(LOG_REGW, "pattern 0x%04x mask %04x\n", pattern, mask);
+
+ chain_address += 4;
+ }
+
+ // interrupt vector
+ if (reload & CC_IV)
+ {
+ iv = s.read_word(chain_address);
+
+ LOGMASKED(LOG_REGW, "interrupt vector 0x%04x\n", iv);
+
+ chain_address += 2;
+ }
+
+ // channel mode
+ if (reload & CC_CM)
+ {
+ cmh = s.read_word(chain_address + 0) & CMH_WM;
+ cml = s.read_word(chain_address + 2);
+
+ LOGMASKED(LOG_REGW, "channel mode 0x%04x %04x\n", cmh, cml);
+ log_mode(LOG_DMA, true);
+
+ chain_address += 4;
+ }
+
+ // chain address
+ if (reload & CC_CA)
+ {
+ cau = s.read_word(chain_address + 0) & (ARU_UA | ARU_WC);
+ cal = s.read_word(chain_address + 2);
+
+ LOGMASKED(LOG_REGW, "chain address 0x%04x %04x\n", cau, cal);
+
+ chain_address += 4;
+ }
+ else
+ {
+ // update chain address register
+ cau = ((chain_address >> 8) & ARU_UA) | u8(cau);
+ cal = u16(chain_address);
+ }
+
+ status &= ~(S_CA | S_NAC);
+
+ if ((status & S_HRQ) || (cmh & CMH_SR))
+ run->adjust(attotime::zero);
+}
+
+void am9516_device::channel::log_mode(unsigned mask, bool high) const
+{
+ if (VERBOSE & mask)
+ {
+ static const char *const match[] =
+ {
+ "no match", "no match", "word match", "byte match"
+ };
+ static const char *const operation[] =
+ {
+ "transfer, word/word flowthru",
+ "transfer, byte/byte flowthru",
+ "transfer, word/word flyby",
+ "transfer, byte/byte flyby",
+ "transfer/search, word/word flowthru",
+ "transfer/search, byte/byte flowthru",
+ "transfer/search, word/word flyby",
+ "transfer/search, byte/byte flyby",
+ "transfer, byte/word flowthru",
+ "transfer, byte/word flowthru",
+ "illegal",
+ "illegal",
+ "transfer/search, byte/word flowthru",
+ "transfer/search, byte/word flowthru",
+ "search, word/word",
+ "search, byte/byte",
+ };
+ static const char *const tt[] =
+ {
+ "single transfer", "demand dedicated/bus hold", "demand dedicated/bus release", "demand interleave"
+ };
+ static const char *const flags[] =
+ {
+ "-", "eop", "mc", "mc|eop", "tc", "tc|eop", "tc|mc", "tc|mc|eop"
+ };
+
+ LOGMASKED(mask, "channel mode %s, %s, complete(int:%s rld:%s chn:%s)\n",
+ operation[cml & CML_OPER], tt[BIT(cml, 5, 2)], flags[BIT(cml, 7, 3)], flags[BIT(cml, 10, 3)], flags[BIT(cml, 13, 3)]);
+
+ if (high)
+ LOGMASKED(mask, "channel mode stop:%s /dack:%d hm:%d sr:%d\n",
+ match[BIT(cmh, 0, 2)], BIT(cmh, 2), BIT(cmh, 3), BIT(cmh, 4));
+ }
+}
+
+void am9516_device::channel::log_addr(unsigned mask, const char *const name, u16 aru, u16 arl) const
+{
+ if (VERBOSE & mask)
+ {
+ static const char *const ar[] =
+ {
+ "system i/o", "system mem", "normal i/o", "normal mem"
+ };
+ static const char *const ac[] =
+ {
+ "inc", "dec", "hld", "hld"
+ };
+
+ LOGMASKED(mask, "%s %s 0x%06x %s wait:%d\n",
+ name, ar[BIT(aru, 6, 2)], u32(aru & ARU_UA) << 8 | arl,
+ ac[BIT(aru, 3, 2)], wait_states[BIT(aru, 1, 2)]);
+ }
+}
diff --git a/src/devices/machine/am9516.h b/src/devices/machine/am9516.h
new file mode 100644
index 00000000000..36583cc840f
--- /dev/null
+++ b/src/devices/machine/am9516.h
@@ -0,0 +1,135 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_AM9516_H
+#define MAME_MACHINE_AM9516_H
+
+#pragma once
+
+class am9516_device
+ : public device_t
+ , public device_memory_interface
+{
+public:
+ enum address_reference : unsigned
+ {
+ SYSTEM_IO = 0,
+ SYSTEM_MEM = 1,
+ NORMAL_IO = 2,
+ NORMAL_MEM = 3,
+ };
+
+ am9516_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // output lines
+ auto out_int() { return m_int.bind(); }
+ auto out_eop() { return m_eop.bind(); }
+
+ // input lines
+ void eop_w(int state);
+ template <unsigned Channel> void dreq_w(int state);
+
+ template <unsigned Channel> auto flyby_byte_r() { return m_channel[Channel].flyby_byte_r.bind(); }
+ template <unsigned Channel> auto flyby_byte_w() { return m_channel[Channel].flyby_byte_w.bind(); }
+ template <unsigned Channel> auto flyby_word_r() { return m_channel[Channel].flyby_word_r.bind(); }
+ template <unsigned Channel> auto flyby_word_w() { return m_channel[Channel].flyby_word_w.bind(); }
+
+ // register access
+ u16 addr_r() { return m_pointer; }
+ void addr_w(u16 data) { m_pointer = data; }
+ u16 data_r();
+ void data_w(u16 data);
+
+ u16 acknowledge();
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ void command(u8 data);
+ template <unsigned Channel> void operate(s32 param);
+ void complete(unsigned const c, u16 status);
+ void interrupt();
+
+ address_space_config m_space_config[4];
+
+ devcb_write_line m_int;
+ devcb_write_line m_eop;
+
+ // i/o line state
+ bool m_int_state;
+ bool m_eop_out_state;
+ bool m_eop_in_state;
+
+ // chip-level registers
+ u8 m_mode;
+ u8 m_pointer;
+ u16 m_temporary;
+
+ // channels
+ struct channel
+ {
+ channel(am9516_device &parent)
+ : udc(parent)
+ , flyby_byte_r(parent, 0)
+ , flyby_byte_w(parent)
+ , flyby_word_r(parent, 0)
+ , flyby_word_w(parent)
+ {}
+
+ u32 address(u16 &aru, u16 &arl, int delta = 0);
+
+ u8 read_byte(unsigned &cycles, bool flip = false);
+ void write_byte(u8 data, unsigned &cycles, bool flip = false);
+ u16 read_word(unsigned &cycles, bool flip = false);
+ void write_word(u16 data, unsigned &cycles, bool flip = false);
+
+ void interrupt(bool assert);
+ void chain();
+ void reload();
+
+ void log_mode(unsigned mask, bool high = false) const;
+ void log_addr(unsigned mask, const char *const name, u16 aru, u16 arl) const;
+
+ am9516_device &udc;
+
+ devcb_read8 flyby_byte_r;
+ devcb_write8 flyby_byte_w;
+ devcb_read16 flyby_word_r;
+ devcb_write16 flyby_word_w;
+
+ emu_timer *run;
+
+ u16 cabl; // current address b lower
+ u16 babl; // base address b lower
+ u16 caal; // current address a lower
+ u16 baal; // base address a lower
+ u16 cabu; // current address b upper
+ u16 babu; // base address b upper
+ u16 caau; // current address a upper
+ u16 baau; // base address a upper
+ u16 cal; // chain address lower
+ u16 cau; // chain address upper
+ u16 is; // interrupt save
+ u16 status; // status
+ u16 coc; // current operation count
+ u16 boc; // base operation count
+ u16 pattern; // pattern
+ u16 mask; // mask
+ u16 cml; // channel mode low
+ u16 cmh; // channel mode high
+ u8 iv; // interrupt vector
+
+ unsigned const wait_states[4] = { 0, 1, 2, 4 };
+ }
+ m_channel[2];
+};
+
+DECLARE_DEVICE_TYPE(AM9516, am9516_device)
+
+#endif // MAME_MACHINE_AM9516_H
diff --git a/src/devices/machine/am9517a.cpp b/src/devices/machine/am9517a.cpp
index a0015161b1e..c9e8a7b2944 100644
--- a/src/devices/machine/am9517a.cpp
+++ b/src/devices/machine/am9517a.cpp
@@ -145,29 +145,53 @@ enum
// dma_request -
//-------------------------------------------------
-void am9517a_device::dma_request(int channel, int state)
+void am9517a_device::dma_request(int channel, bool state)
{
LOG("AM9517A Channel %u DMA Request: %u\n", channel, state);
- if (state ^ COMMAND_DREQ_ACTIVE_LOW)
- {
+ if (state)
m_status |= (1 << (channel + 4));
- }
else
- {
m_status &= ~(1 << (channel + 4));
- }
+
trigger(1);
}
//-------------------------------------------------
+// mask_channel -
+//-------------------------------------------------
+
+void am9517a_device::mask_channel(int channel, bool state)
+{
+ LOG("AM9517A Channel %u Mask: %u\n", channel, state);
+
+ if (state)
+ m_mask |= 1 << channel;
+ else
+ m_mask &= ~(1 << channel);
+}
+
+
+//-------------------------------------------------
+// set_mask_register -
+//-------------------------------------------------
+
+void am9517a_device::set_mask_register(uint8_t mask)
+{
+ LOG("AM9517A Mask Register: %01x\n", mask);
+
+ m_mask = mask;
+}
+
+
+//-------------------------------------------------
// is_request_active -
//-------------------------------------------------
inline bool am9517a_device::is_request_active(int channel)
{
- return (BIT(m_status, channel + 4) & ~BIT(m_mask, channel)) ? true : false;
+ return (BIT(COMMAND_DREQ_ACTIVE_LOW ? ~m_status : m_status, channel + 4) && !BIT(m_mask, channel)) ? true : false;
}
@@ -417,41 +441,41 @@ void am9517a_device::end_of_process()
//-------------------------------------------------
-am9517a_device::am9517a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- device_execute_interface(mconfig, *this),
- m_icount(0),
- m_hack(0),
- m_ready(1),
- m_command(0),
- m_out_hreq_cb(*this),
- m_out_eop_cb(*this),
- m_in_memr_cb(*this),
- m_out_memw_cb(*this),
- m_in_ior_cb(*this),
- m_out_iow_cb(*this),
- m_out_dack_cb(*this)
+am9517a_device::am9517a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_hack(0),
+ m_ready(1),
+ m_command(0),
+ m_status(0),
+ m_out_hreq_cb(*this),
+ m_out_eop_cb(*this),
+ m_in_memr_cb(*this, 0),
+ m_out_memw_cb(*this),
+ m_in_ior_cb(*this, 0),
+ m_out_iow_cb(*this),
+ m_out_dack_cb(*this)
{
}
-am9517a_device::am9517a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : am9517a_device(mconfig, AM9517A, tag, owner, clock)
+am9517a_device::am9517a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ am9517a_device(mconfig, AM9517A, tag, owner, clock)
{
}
-v5x_dmau_device::v5x_dmau_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : am9517a_device(mconfig, V5X_DMAU, tag, owner, clock)
- , m_in_mem16r_cb(*this)
- , m_out_mem16w_cb(*this)
- , m_in_io16r_cb(*this)
- , m_out_io16w_cb(*this)
-
+v5x_dmau_device::v5x_dmau_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ am9517a_device(mconfig, V5X_DMAU, tag, owner, clock),
+ m_in_mem16r_cb(*this, 0),
+ m_out_mem16w_cb(*this),
+ m_in_io16r_cb(*this, 0),
+ m_out_io16w_cb(*this)
{
}
-pcxport_dmac_device::pcxport_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : am9517a_device(mconfig, PCXPORT_DMAC, tag, owner, clock)
+pcxport_dmac_device::pcxport_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ am9517a_device(mconfig, PCXPORT_DMAC, tag, owner, clock)
{
}
@@ -464,15 +488,6 @@ void am9517a_device::device_start()
// set our instruction counter
set_icountptr(m_icount);
- // resolve callbacks
- m_out_hreq_cb.resolve_safe();
- m_out_eop_cb.resolve_safe();
- m_in_memr_cb.resolve_safe(0);
- m_out_memw_cb.resolve_safe();
- m_in_ior_cb.resolve_all_safe(0);
- m_out_iow_cb.resolve_all_safe();
- m_out_dack_cb.resolve_all_safe();
-
for(auto &elem : m_channel)
{
elem.m_address = 0;
@@ -518,7 +533,7 @@ void am9517a_device::device_reset()
{
m_state = STATE_SI;
m_command = 0;
- m_status = 0;
+ m_status &= 0xf0;
m_request = 0;
m_mask = 0x0f;
m_temp = 0;
@@ -765,7 +780,8 @@ uint8_t am9517a_device::read(offs_t offset)
break;
}
- m_msb = !m_msb;
+ if (!machine().side_effects_disabled())
+ m_msb = !m_msb;
}
else
{
@@ -773,9 +789,12 @@ uint8_t am9517a_device::read(offs_t offset)
{
case REGISTER_STATUS:
data = m_status;
+ if (COMMAND_DREQ_ACTIVE_LOW)
+ data ^= 0xf0;
// clear TC bits
- m_status &= 0xf0;
+ if (!machine().side_effects_disabled())
+ m_status &= 0xf0;
break;
case REGISTER_TEMPORARY:
@@ -853,15 +872,11 @@ void am9517a_device::write(offs_t offset, uint8_t data)
if (BIT(data, 2))
{
- m_request |= (1 << (channel + 4));
- if (COMMAND_MEM_TO_MEM)
- {
- m_request |= (1 << channel);
- }
+ m_request |= (1 << channel);
}
else
{
- m_request &= ~(1 << (channel + 4));
+ m_request &= ~(1 << channel);
}
LOG("AM9517A Request Register: %01x\n", m_request);
@@ -871,17 +886,7 @@ void am9517a_device::write(offs_t offset, uint8_t data)
case REGISTER_SINGLE_MASK:
{
int channel = data & 0x03;
-
- if (BIT(data, 2))
- {
- m_mask |= (1 << channel);
- }
- else
- {
- m_mask &= ~(1 << channel);
- }
-
- LOG("AM9517A Mask Register: %01x\n", m_mask);
+ mask_channel(channel, BIT(data, 2));
}
break;
@@ -911,15 +916,11 @@ void am9517a_device::write(offs_t offset, uint8_t data)
break;
case REGISTER_CLEAR_MASK:
- LOG("AM9517A Clear Mask Register\n");
-
- m_mask = 0;
+ set_mask_register(0);
break;
case REGISTER_MASK:
- m_mask = data & 0x0f;
-
- LOG("AM9517A Mask Register: %01x\n", m_mask);
+ set_mask_register(data & 0x0f);
break;
}
}
@@ -931,7 +932,7 @@ void am9517a_device::write(offs_t offset, uint8_t data)
// hack_w - hold acknowledge
//-------------------------------------------------
-WRITE_LINE_MEMBER( am9517a_device::hack_w )
+void am9517a_device::hack_w(int state)
{
LOG("AM9517A Hold Acknowledge: %u\n", state);
@@ -944,7 +945,7 @@ WRITE_LINE_MEMBER( am9517a_device::hack_w )
// ready_w - ready
//-------------------------------------------------
-WRITE_LINE_MEMBER( am9517a_device::ready_w )
+void am9517a_device::ready_w(int state)
{
LOG("AM9517A Ready: %u\n", state);
@@ -956,7 +957,7 @@ WRITE_LINE_MEMBER( am9517a_device::ready_w )
// eop_w - end of process
//-------------------------------------------------
-WRITE_LINE_MEMBER( am9517a_device::eop_w )
+void am9517a_device::eop_w(int state)
{
LOG("AM9517A End of Process: %u\n", state);
}
@@ -966,7 +967,7 @@ WRITE_LINE_MEMBER( am9517a_device::eop_w )
// dreq0_w - DMA request for channel 0
//-------------------------------------------------
-WRITE_LINE_MEMBER( am9517a_device::dreq0_w )
+void am9517a_device::dreq0_w(int state)
{
dma_request(0, state);
}
@@ -976,7 +977,7 @@ WRITE_LINE_MEMBER( am9517a_device::dreq0_w )
// dreq0_w - DMA request for channel 1
//-------------------------------------------------
-WRITE_LINE_MEMBER( am9517a_device::dreq1_w )
+void am9517a_device::dreq1_w(int state)
{
dma_request(1, state);
}
@@ -986,7 +987,7 @@ WRITE_LINE_MEMBER( am9517a_device::dreq1_w )
// dreq1_w - DMA request for channel 2
//-------------------------------------------------
-WRITE_LINE_MEMBER( am9517a_device::dreq2_w )
+void am9517a_device::dreq2_w(int state)
{
dma_request(2, state);
}
@@ -996,7 +997,7 @@ WRITE_LINE_MEMBER( am9517a_device::dreq2_w )
// dreq3_w - DMA request for channel 3
//-------------------------------------------------
-WRITE_LINE_MEMBER( am9517a_device::dreq3_w )
+void am9517a_device::dreq3_w(int state)
{
dma_request(3, state);
}
@@ -1010,11 +1011,6 @@ void v5x_dmau_device::device_start()
am9517a_device::device_start();
m_address_mask = 0x00ffffff;
- m_in_mem16r_cb.resolve_safe(0);
- m_out_mem16w_cb.resolve_safe();
- m_in_io16r_cb.resolve_all_safe(0);
- m_out_io16w_cb.resolve_all_safe();
-
m_selected_channel = 0;
m_base = 0;
@@ -1094,7 +1090,8 @@ uint8_t v5x_dmau_device::read(offs_t offset)
case 0x0b: // Status
ret = m_status;
// clear TC bits
- m_status &= 0xf0;
+ if (!machine().side_effects_disabled())
+ m_status &= 0xf0;
break;
case 0x0c: // Temporary (low)
ret = m_temp & 0xff;
@@ -1267,7 +1264,7 @@ void pcxport_dmac_device::device_reset()
{
m_state = STATE_SI;
m_command = 0;
- m_status = 0;
+ m_status &= 0xf0;
m_request = 0;
m_mask = 0;
m_temp = 0;
diff --git a/src/devices/machine/am9517a.h b/src/devices/machine/am9517a.h
index 54afb057dae..67b10351290 100644
--- a/src/devices/machine/am9517a.h
+++ b/src/devices/machine/am9517a.h
@@ -61,18 +61,22 @@ public:
template <unsigned C> auto out_iow_callback() { return m_out_iow_cb[C].bind(); }
template <unsigned C> auto out_dack_callback() { return m_out_dack_cb[C].bind(); }
+ // define initial (inactive) state of DREQ inputs
+ void dreq_active_low() { assert(!configured()); m_status = 0xf0; }
+ void dreq_active_high() { assert(!configured()); m_status = 0; }
+
virtual uint8_t read(offs_t offset);
virtual void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( hack_w );
- DECLARE_WRITE_LINE_MEMBER( ready_w );
- DECLARE_WRITE_LINE_MEMBER( eop_w );
+ void hack_w(int state);
+ void ready_w(int state);
+ void eop_w(int state);
- template <unsigned C> DECLARE_WRITE_LINE_MEMBER( dreq_w ) { dma_request(C, state); }
- DECLARE_WRITE_LINE_MEMBER( dreq0_w );
- DECLARE_WRITE_LINE_MEMBER( dreq1_w );
- DECLARE_WRITE_LINE_MEMBER( dreq2_w );
- DECLARE_WRITE_LINE_MEMBER( dreq3_w );
+ template <unsigned C> void dreq_w(int state) { dma_request(C, state); }
+ void dreq0_w(int state);
+ void dreq1_w(int state);
+ void dreq2_w(int state);
+ void dreq3_w(int state);
protected:
am9517a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -116,7 +120,9 @@ protected:
uint8_t m_request;
private:
- void dma_request(int channel, int state);
+ void dma_request(int channel, bool state);
+ void mask_channel(int channel, bool state);
+ void set_mask_register(uint8_t mask);
inline bool is_request_active(int channel);
inline bool is_software_request_active(int channel);
inline void set_hreq(int state);
diff --git a/src/devices/machine/am9519.cpp b/src/devices/machine/am9519.cpp
index be0b8c3da10..9a5eb100773 100644
--- a/src/devices/machine/am9519.cpp
+++ b/src/devices/machine/am9519.cpp
@@ -4,14 +4,74 @@
//TODO: rotating priority, cascade
#include "emu.h"
-#include "machine/am9519.h"
-
-#define LOG_GENERAL (1U << 0)
+#include "am9519.h"
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
-void am9519_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+
+DEFINE_DEVICE_TYPE(AM9519, am9519_device, "am9519", "AMD AM9519 Universal Interrupt Controller")
+
+am9519_device::am9519_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, AM9519, tag, owner, clock)
+ , m_out_int_func(*this)
+ , m_irr(0)
+ , m_irq_lines(0)
+ , m_irq_check_timer(nullptr)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void am9519_device::device_start()
+{
+ // Register save state items
+ save_item(NAME(m_isr));
+ save_item(NAME(m_irr));
+ save_item(NAME(m_prio));
+ save_item(NAME(m_imr));
+ save_item(NAME(m_irq_lines));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_count));
+ save_item(NAME(m_resp));
+ save_item(NAME(m_aclear));
+ save_item(NAME(m_cmd));
+
+ m_irq_check_timer = timer_alloc(FUNC(am9519_device::check_irqs), this);
+ m_irq_check_timer->adjust(attotime::never);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void am9519_device::device_reset()
+{
+ m_isr = 0;
+ m_irr = 0;
+ m_irq_lines = 0;
+ m_prio = 0;
+ m_imr = 0xff;
+ m_mode = 0;
+ m_aclear = 0;
+ m_cmd = 0;
+ m_curcnt = 0;
+ for(int i = 0; i < 8; i++)
+ {
+ m_count[i] = 0;
+ m_resp[i][0] = 0;
+ m_resp[i][1] = 0;
+ m_resp[i][2] = 0;
+ m_resp[i][3] = 0;
+ }
+}
+
+
+TIMER_CALLBACK_MEMBER(am9519_device::check_irqs)
{
if(!BIT(m_mode, 7)) // chip disabled
return;
@@ -61,9 +121,8 @@ void am9519_device::set_irq_line(int irq, int state)
LOG("am9519_device::set_irq_line(): UIC cleared IRQ line #%d\n", irq);
m_irq_lines &= ~mask;
- m_irr &= ~mask;
}
- set_timer();
+ m_irq_check_timer->adjust(attotime::zero);
}
@@ -82,7 +141,7 @@ u32 am9519_device::acknowledge()
m_isr |= mask;
m_irr &= ~mask;
- set_timer();
+ m_irq_check_timer->adjust(attotime::zero);
u32 ret = 0;
int irqr = BIT(m_mode, 1) ? 0 : irq;
@@ -219,7 +278,7 @@ void am9519_device::cmd_w(u8 data)
m_curcnt = 0;
break;
}
- set_timer();
+ m_irq_check_timer->adjust(attotime::zero);
}
void am9519_device::data_w(u8 data)
@@ -246,63 +305,5 @@ void am9519_device::data_w(u8 data)
}
m_cmd = 0;
}
- set_timer();
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void am9519_device::device_start()
-{
- // resolve callbacks
- m_out_int_func.resolve_safe();
-
- // Register save state items
- save_item(NAME(m_isr));
- save_item(NAME(m_irr));
- save_item(NAME(m_prio));
- save_item(NAME(m_imr));
- save_item(NAME(m_irq_lines));
- save_item(NAME(m_mode));
- save_item(NAME(m_count));
- save_item(NAME(m_resp));
- save_item(NAME(m_aclear));
- save_item(NAME(m_cmd));
-}
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void am9519_device::device_reset()
-{
- m_isr = 0;
- m_irr = 0;
- m_irq_lines = 0;
- m_prio = 0;
- m_imr = 0xff;
- m_mode = 0;
- m_aclear = 0;
- m_cmd = 0;
- m_curcnt = 0;
- for(int i = 0; i < 8; i++)
- {
- m_count[i] = 0;
- m_resp[i][0] = 0;
- m_resp[i][1] = 0;
- m_resp[i][2] = 0;
- m_resp[i][3] = 0;
- }
-}
-
-DEFINE_DEVICE_TYPE(AM9519, am9519_device, "am9519", "AMD AM9519 Universal Interrupt Controller")
-
-am9519_device::am9519_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, AM9519, tag, owner, clock)
- , m_out_int_func(*this)
- , m_irr(0)
- , m_irq_lines(0)
-{
+ m_irq_check_timer->adjust(attotime::zero);
}
diff --git a/src/devices/machine/am9519.h b/src/devices/machine/am9519.h
index ec84cd50e52..20a76809070 100644
--- a/src/devices/machine/am9519.h
+++ b/src/devices/machine/am9519.h
@@ -42,14 +42,14 @@ public:
void data_w(u8 data);
u32 acknowledge();
- DECLARE_WRITE_LINE_MEMBER( ireq0_w ) { set_irq_line(0, state); }
- DECLARE_WRITE_LINE_MEMBER( ireq1_w ) { set_irq_line(1, state); }
- DECLARE_WRITE_LINE_MEMBER( ireq2_w ) { set_irq_line(2, state); }
- DECLARE_WRITE_LINE_MEMBER( ireq3_w ) { set_irq_line(3, state); }
- DECLARE_WRITE_LINE_MEMBER( ireq4_w ) { set_irq_line(4, state); }
- DECLARE_WRITE_LINE_MEMBER( ireq5_w ) { set_irq_line(5, state); }
- DECLARE_WRITE_LINE_MEMBER( ireq6_w ) { set_irq_line(6, state); }
- DECLARE_WRITE_LINE_MEMBER( ireq7_w ) { set_irq_line(7, state); }
+ void ireq0_w(int state) { set_irq_line(0, state); }
+ void ireq1_w(int state) { set_irq_line(1, state); }
+ void ireq2_w(int state) { set_irq_line(2, state); }
+ void ireq3_w(int state) { set_irq_line(3, state); }
+ void ireq4_w(int state) { set_irq_line(4, state); }
+ void ireq5_w(int state) { set_irq_line(5, state); }
+ void ireq6_w(int state) { set_irq_line(6, state); }
+ void ireq7_w(int state) { set_irq_line(7, state); }
IRQ_CALLBACK_MEMBER(iack_cb);
@@ -57,12 +57,10 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-private:
- static constexpr device_timer_id TIMER_CHECK_IRQ = 0;
+ TIMER_CALLBACK_MEMBER(check_irqs);
- inline void set_timer() { timer_set(attotime::zero, TIMER_CHECK_IRQ); }
+private:
void set_irq_line(int irq, int state);
devcb_write_line m_out_int_func;
@@ -79,6 +77,8 @@ private:
u8 m_aclear;
u8 m_count[8];
u8 m_resp[8][4];
+
+ emu_timer *m_irq_check_timer;
};
DECLARE_DEVICE_TYPE(AM9519, am9519_device)
diff --git a/src/devices/machine/amiga_copper.cpp b/src/devices/machine/amiga_copper.cpp
new file mode 100644
index 00000000000..df2cee3c2bb
--- /dev/null
+++ b/src/devices/machine/amiga_copper.cpp
@@ -0,0 +1,393 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, Angelo Salese
+/**************************************************************************************************
+
+ Amiga Copper
+
+ "Co-processor" contained inside Agnus,
+ it's a finite-state machine that either wait to a h/v video beam position or direct writes to
+ the Amiga chipset registers via program lists, ranging from "simple" video mode/color changes
+ to override sprite structures and beyond ...
+
+ TODO:
+ - Current handling is horizontally offset by several pixels, also cfr. amiga video notes
+ (screen geometry slightly incorrect?);
+ - Fix Bitplane offset corruption in some games (e.g. exile, zoola, AGA games).
+ Same as above?
+ - Fix missing/corrupt sprites in known nasty examples
+ (e.g. zoola status bar, parasol score layer on top, riskyw backgrounds);
+ - Find & verify cdang examples (especially for ECS/AGA);
+ - Find & verify examples that uses this non-canonically,
+ i.e. anything that may use this for controlling Paula, FDC or Blitter;
+ - Add debugger command for printing the current disassembler structure
+ (current live logging is painfully slow in places, cfr. lweapon);
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "amiga_copper.h"
+
+#define LOG_WARN (1U << 1) // Show warnings
+#define LOG_COPINS (1U << 2) // Show instruction fetches thru COPINS
+#define LOG_INST (1U << 3) // Show live instruction fetches
+#define LOG_PC (1U << 4) // Show PC fetches
+#define LOG_CHIPSET (1U << 5) // Show custom chipset writes
+
+#define VERBOSE (LOG_WARN)
+//#define VERBOSE (LOG_WARN | LOG_CHIPSET | LOG_PC | LOG_INST)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+
+#include "logmacro.h"
+
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+#define LOGCOPINS(...) LOGMASKED(LOG_COPINS, __VA_ARGS__)
+#define LOGINST(...) LOGMASKED(LOG_INST, __VA_ARGS__)
+#define LOGPC(...) LOGMASKED(LOG_PC, __VA_ARGS__)
+#define LOGCHIPSET(...) LOGMASKED(LOG_CHIPSET, __VA_ARGS__)
+
+// TODO: legacy inheritance, to be verified
+#define COPPER_CYCLES_TO_PIXELS(x) (4 * (x))
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+
+// device type definition
+DEFINE_DEVICE_TYPE(AMIGA_COPPER, amiga_copper_device, "amiga_copper", "Amiga Copper")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// amiga_copper_device - constructor
+//-------------------------------------------------
+
+
+amiga_copper_device::amiga_copper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, AMIGA_COPPER, tag, owner, clock)
+ , m_host_cpu(*this, finder_base::DUMMY_TAG)
+ , m_chipmem_r(*this, 0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+
+void amiga_copper_device::device_start()
+{
+ m_host_space = &m_host_cpu->space(AS_PROGRAM);
+
+ save_item(NAME(m_cdang_setting));
+ save_item(NAME(m_cdang_min_reg));
+ save_item(NAME(m_dma_master_enable));
+ save_item(NAME(m_dma_copen));
+ save_pointer(NAME(m_lc), 2);
+ save_item(NAME(m_pc));
+ save_item(NAME(m_state_waiting));
+ save_item(NAME(m_state_waitblit));
+ save_item(NAME(m_waitval));
+ save_item(NAME(m_waitmask));
+// save_item(NAME(m_wait_offset));
+ save_item(NAME(m_pending_data));
+ save_item(NAME(m_pending_offset));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+
+void amiga_copper_device::device_reset()
+{
+ m_cdang_setting = 0x40;
+ m_dma_master_enable = false;
+ m_dma_copen = false;
+ // TODO: latches states on soft reset
+}
+
+
+//**************************************************************************
+// I/Os
+//**************************************************************************
+
+// $dff080-8d memory map
+void amiga_copper_device::regs_map(address_map &map)
+{
+ // TODO: location addresses belongs to Agnus
+ map(0x00, 0x01).w(FUNC(amiga_copper_device::copxlch_w<0>));
+ map(0x02, 0x03).w(FUNC(amiga_copper_device::copxlcl_w<0>));
+ map(0x04, 0x05).w(FUNC(amiga_copper_device::copxlch_w<1>));
+ map(0x06, 0x07).w(FUNC(amiga_copper_device::copxlcl_w<1>));
+ map(0x08, 0x09).rw(FUNC(amiga_copper_device::copjmpx_r<0>), FUNC(amiga_copper_device::copjmpx_w<0>));
+ map(0x0a, 0x0b).rw(FUNC(amiga_copper_device::copjmpx_r<1>), FUNC(amiga_copper_device::copjmpx_w<1>));
+// map(0x0c, 0x0d).w(FUNC(amiga_copper_device::copins_w));
+}
+
+void amiga_copper_device::dmacon_set(u16 data)
+{
+ m_dma_master_enable = bool(BIT(data, 9));
+ m_dma_copen = bool(BIT(data, 7));
+}
+
+/*
+ * COPCON 02E W A Copper Control Register
+ *
+ * ---- ---- ---- --x- CDANG (Copper Danger Mode) setting
+ *
+ * Documentation is quite contradictory here.
+ * This bit is supposed to allow Copper access of the
+ * lowest registers. OriginaL HRM states that it gives
+ * access to the blitter HW therefore $dff080 is the
+ * minimum for non-cdang and $dff040 for cdang mode.
+ *
+ * In ECS and AGA the latter limitation is lifted so Copper
+ * can access $dff000-$dff03f too, which basically means the
+ * possibility of accessing disk block regs.
+ * (i.e. the other regs are either r/o or wouldn't have much
+ * sense to write via Copper).
+ *
+ */
+void amiga_copper_device::copcon_w(u16 data)
+{
+ bool cdang = bool(BIT(data, 1));
+
+ // TODO: is min_reg working even with BPLCON0 bit 0 unset?
+ m_cdang_setting = cdang ? m_cdang_min_reg : 0x40;
+ if (cdang)
+ LOGWARN("%s: cdang enabled\n", machine().describe_context());
+ if (data & 0xfffd)
+ LOGWARN("%s: COPCON undocumented setting write %04x\n", machine().describe_context(), data);
+}
+
+template <u8 ch> void amiga_copper_device::copxlch_w(u16 data)
+{
+ // TODO: chipmem mask
+ m_lc[ch] = (m_lc[ch] & 0x0000ffff) | ((data & 0x001f) << 16);
+}
+
+template <u8 ch> void amiga_copper_device::copxlcl_w(u16 data)
+{
+ m_lc[ch] = (m_lc[ch] & 0xffff0000) | ((data & 0xfffe) << 0);
+}
+
+/*
+ * COPJMP1 088 S A Copper restart at first location
+ * COPJMP2 08a S A Copper restart at second location
+ *
+ * Strobe register that loads the new PC into Copper.
+ * NB: Copper can use this to control its program flow and even
+ * do conditional branching by clever use of the skip opcode.
+ *
+ */
+template <u8 ch> void amiga_copper_device::copjmpx_w(u16 data)
+{
+ set_pc(ch, false);
+}
+
+template <u8 ch> u16 amiga_copper_device::copjmpx_r()
+{
+ if (!machine().side_effects_disabled())
+ set_pc(ch, false);
+ return m_host_space->unmap();
+}
+
+inline void amiga_copper_device::set_pc(u8 ch, bool is_sync)
+{
+ m_pc = m_lc[ch];
+ m_state_waiting = false;
+ LOGPC("%s: COPJMP%d new PC = %08x%s\n"
+ , machine().describe_context()
+ , ch + 1
+ , m_pc
+ , is_sync ? " (resync)" : ""
+ );
+}
+
+/*
+ * COPINS 08c W A Copper instruction fetch identify
+ *
+ * Apparently this register is pinged every time that
+ * the Copper internally decodes an instruction value.
+ * Shouldn't have any implementation detail connected,
+ * de-facto it's a mailbox that can be listened by external HW
+ * (such as our debugger ;=).
+ *
+ */
+void amiga_copper_device::copins_w(u16 data)
+{
+ LOGCOPINS("%s: COPINS %04x\n", machine().describe_context(), data);
+}
+
+//**************************************************************************
+// Implementation getters/setters
+//**************************************************************************
+
+// executed on scanline == 0
+void amiga_copper_device::vblank_sync()
+{
+ set_pc(0, true);
+}
+
+int amiga_copper_device::execute_next(int xpos, int ypos, bool is_blitter_busy)
+{
+ int word0, word1;
+
+ /* bail if not enabled */
+ if (!m_dma_master_enable || !m_dma_copen)
+ return 511;
+
+ /* flush any pending writes */
+ if (m_pending_offset)
+ {
+ //LOGCHIPSET("%02X.%02X: Write to %s = %04x\n", ypos, xpos / 2, s_custom_reg_names[m_copper_pending_offset & 0xff], m_copper_pending_data);
+ LOGCHIPSET("%02X.%02X: MOVE $dff%03x = %04x\n",
+ ypos,
+ xpos / 2,
+ (m_pending_offset << 1),
+ m_pending_data
+ );
+ m_host_space->write_word(0xdff000 | (m_pending_offset << 1), m_pending_data);
+ m_pending_offset = 0;
+ }
+
+ /* if we're waiting, check for a breakthrough */
+ if (m_state_waiting)
+ {
+ int curpos = (ypos << 8) | (xpos >> 1);
+
+ /* if we're past the wait time, stop it and hold up 2 cycles */
+ if ((curpos & m_waitmask) >= (m_waitval & m_waitmask) &&
+ (!m_state_waitblit || !(is_blitter_busy)))
+ {
+ m_state_waiting = false;
+//#if GUESS_COPPER_OFFSET
+// return xpos + COPPER_CYCLES_TO_PIXELS(1 + m_wait_offset);
+//#else
+ return xpos + COPPER_CYCLES_TO_PIXELS(1 + 3);
+//#endif
+ }
+
+ /* otherwise, see if this line is even a possibility; if not, punt */
+ if (((curpos | 0xff) & m_waitmask) < (m_waitval & m_waitmask))
+ return 511;
+
+ /* else just advance another pixel */
+ xpos += COPPER_CYCLES_TO_PIXELS(1);
+ return xpos;
+ }
+
+ /* fetch the first data word */
+ // TODO: swap between ir0 and ir1 is controlled thru a selins latch
+ // (which can't be this instant too)
+ word0 = m_chipmem_r(m_pc);
+ m_host_space->write_word(0xdff08c, word0);
+ m_pc += 2;
+ xpos += COPPER_CYCLES_TO_PIXELS(1);
+
+ /* fetch the second data word */
+ word1 = m_chipmem_r(m_pc);
+ m_host_space->write_word(0xdff08c, word1);
+ m_pc += 2;
+ xpos += COPPER_CYCLES_TO_PIXELS(1);
+
+ LOGINST("%02X.%02X: Copper inst @ %06x = %04x %04x\n",
+ ypos,
+ xpos / 2,
+ m_pc - 4,
+ word0,
+ word1
+ );
+
+ /* handle a move */
+ if ((word0 & 1) == 0)
+ {
+ /* do the write if we're allowed */
+ word0 = (word0 >> 1) & 0xff;
+ if (word0 >= m_cdang_setting)
+ {
+ if (delay[word0] == 0)
+ {
+ //LOGCHIPSET("%02X.%02X: Write to %s = %04x\n", ypos, xpos / 2, s_custom_reg_names[word0 & 0xff], word1);
+ LOGCHIPSET("%02X.%02X: MOVE $dff%03x = %04x\n",
+ ypos,
+ xpos / 2,
+ word0 << 1,
+ word1
+ );
+ m_host_space->write_word(0xdff000 | (word0 << 1), word1);
+ }
+ else // additional 2 cycles needed for non-Agnus registers
+ {
+ m_pending_offset = word0;
+ m_pending_data = word1;
+ }
+ }
+
+ /* illegal writes suspend until next frame */
+ else
+ {
+ LOGWARN("%02X.%02X: Aborting copper on illegal write\n", ypos, xpos / 2);
+
+ m_waitval = 0xffff;
+ m_waitmask = 0xffff;
+ m_state_waitblit = false;
+ m_state_waiting = true;
+
+ return 511;
+ }
+ }
+ else
+ {
+ /* extract common wait/skip values */
+ m_waitval = word0 & 0xfffe;
+
+ m_waitmask = word1 | 0x8001;
+ m_state_waitblit = (~word1 >> 15) & 1;
+
+ /* handle a wait */
+ if ((word1 & 1) == 0)
+ {
+ LOGINST(" WAIT %04x & %04x (currently %04x)\n",
+ m_waitval,
+ m_waitmask,
+ (ypos << 8) | (xpos >> 1)
+ );
+
+ m_state_waiting = true;
+ }
+
+ /* handle a skip */
+ else
+ {
+ int curpos = (ypos << 8) | (xpos >> 1);
+
+ LOGINST(" SKIP %04x & %04x (currently %04x)\n",
+ m_waitval,
+ m_waitmask,
+ (ypos << 8) | (xpos >> 1)
+ );
+
+ /* if we're past the wait time, stop it and hold up 2 cycles */
+ if ((curpos & m_waitmask) >= (m_waitval & m_waitmask) &&
+ (!m_state_waitblit || !(is_blitter_busy)))
+ {
+ LOGINST(" Skipped\n");
+
+ /* count the cycles it out have taken to fetch the next instruction */
+ m_pc += 4;
+ xpos += COPPER_CYCLES_TO_PIXELS(2);
+ }
+ }
+ }
+
+ /* advance and consume 8 cycles */
+ return xpos;
+}
diff --git a/src/devices/machine/amiga_copper.h b/src/devices/machine/amiga_copper.h
new file mode 100644
index 00000000000..15fe5c3cd00
--- /dev/null
+++ b/src/devices/machine/amiga_copper.h
@@ -0,0 +1,102 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, Angelo Salese
+/***************************************************************************
+
+ Amiga Copper
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_AMIGA_COPPER_H
+#define MAME_MACHINE_AMIGA_COPPER_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class amiga_copper_device : public device_t
+{
+public:
+ // construction/destruction
+ amiga_copper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // config
+ template<class T> void set_host_cpu_tag(T &&tag) { m_host_cpu.set_tag(std::forward<T>(tag)); }
+ auto mem_read_cb() { return m_chipmem_r.bind(); }
+ void set_ecs_mode(bool ecs_mode) { m_cdang_min_reg = ecs_mode ? 0x00 : 0x20; }
+
+ // I/O operations
+ void regs_map(address_map &map);
+ void dmacon_set(u16 data);
+ void copcon_w(u16 data);
+
+ // getters/setters
+ void vblank_sync();
+ int execute_next(int xpos, int ypos, bool is_blitter_busy);
+
+protected:
+ // device-level overrides
+ //virtual void device_validity_check(validity_checker &valid) const override;
+ //virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ required_device <cpu_device> m_host_cpu;
+ address_space *m_host_space = nullptr;
+ // callbacks
+ devcb_read16 m_chipmem_r;
+
+ bool m_dma_master_enable, m_dma_copen;
+ u16 m_cdang_setting, m_cdang_min_reg;
+ u32 m_lc[2], m_pc;
+
+ template <u8 ch> void copxlch_w(u16 data);
+ template <u8 ch> void copxlcl_w(u16 data);
+ template <u8 ch> void copjmpx_w(u16 data);
+ template <u8 ch> u16 copjmpx_r();
+public:
+ void copins_w(u16 data);
+private:
+ void set_pc(u8 ch, bool is_sync);
+
+ // internal state
+ bool m_state_waiting;
+ bool m_state_waitblit;
+ u16 m_waitval;
+ u16 m_waitmask;
+ u16 m_pending_offset;
+ u16 m_pending_data;
+// int m_wait_offset;
+
+ // waitstate delays for copper
+ // basically anything that doesn't belong to Angus has a penalty for Copper
+ static constexpr u16 delay[256] =
+ {
+ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 0x000 - 0x03e */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x040 - 0x05e */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x060 - 0x07e */
+ 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, /* 0x080 - 0x09e */
+ 1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0, /* 0x0a0 - 0x0de */
+ /* BPLxPTH/BPLxPTL */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x0e0 - 0x0fe */
+ /* BPLCON0-3,BPLMOD1-2 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x100 - 0x11e */
+ /* SPRxPTH/SPRxPTL */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x120 - 0x13e */
+ /* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x140 - 0x17e */
+ /* COLORxx */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x180 - 0x1be */
+ /* RESERVED */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0x1c0 - 0x1fe */
+ };
+
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(AMIGA_COPPER, amiga_copper_device)
+
+#endif // MAME_MACHINE_AMIGA_COPPER_H
diff --git a/src/devices/machine/amigafdc.cpp b/src/devices/machine/amigafdc.cpp
index 9db640db021..662a80dffe4 100644
--- a/src/devices/machine/amigafdc.cpp
+++ b/src/devices/machine/amigafdc.cpp
@@ -1,42 +1,72 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
-/***************************************************************************
+/**************************************************************************************************
- Amiga floppy disk controller emulation
+ Amiga floppy disk controller emulation "Trackdisk"
-***************************************************************************/
+ Contained inside MOS 8364 Paula device
+
+ TODO:
+ - Some games currently writes 2+ dsksync to the buffer (marked as "[FDC] dsksync" in SW list):
+ Current workaround:
+ 1. comment out dma_write in DMA_WAIT_START handling and change the dma_state *only*;
+ 2. remove all of the non-DMA_WAIT_START phase inside the dsksync sub-section;
+ NB: according to documentation syncing doesn't really write anything on the bus,
+ so technically this "workaround" is more correct.
+ However it unfortunately causes other SW regressions, most notably in Workbench.
+ - Other games trashes memory or refuses to boot, in a few instances randomly
+ (marked as "[FDC] with adkcon=1100", implies dsksync disabled):
+ they often uses the AmigaDOS trackdisk BIOS functions, which may be expecting a
+ different timing. May be worth testing this out with the SDK;
+ - "[FDC] format" or in general writing to disks doesn't work properly.
+ i.e. formatting a disk in any Workbench version will cause a system crash once it completes.
+ - Fix ready line read handling;
+ - FDC LED output callback;
+
+**************************************************************************************************/
#include "emu.h"
#include "formats/ami_dsk.h"
+#include "formats/ipf_dsk.h"
#include "amigafdc.h"
-DEFINE_DEVICE_TYPE(AMIGA_FDC, amiga_fdc_device, "amiga_fdc", "Amiga FDC")
+#define LOG_WARN (1U << 1) // Show warnings
+#define LOG_DMA (1U << 2) // Show DMA setups
+#define LOG_SYNC (1U << 3) // Show sync block setups
+
+#define VERBOSE (LOG_WARN | LOG_DMA | LOG_SYNC)
+
+#include "logmacro.h"
+
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__)
+#define LOGSYNC(...) LOGMASKED(LOG_SYNC, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(AMIGA_FDC, amiga_fdc_device, "amiga_fdc", "Amiga \"Trackdisk\" FDC")
-FLOPPY_FORMATS_MEMBER( amiga_fdc_device::floppy_formats )
- FLOPPY_ADF_FORMAT
-FLOPPY_FORMATS_END
+void amiga_fdc_device::floppy_formats(format_registration &fr)
+{
+ fr.add_mfm_containers();
+ fr.add(FLOPPY_ADF_FORMAT);
+ fr.add(FLOPPY_IPF_FORMAT);
+}
-amiga_fdc_device::amiga_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, AMIGA_FDC, tag, owner, clock),
- m_write_index(*this),
- m_read_dma(*this),
- m_write_dma(*this),
- m_write_dskblk(*this),
- m_write_dsksyn(*this),
- m_leds(*this, "led%u", 1U),
- m_fdc_led(*this, "fdc_led"),
- floppy(nullptr), t_gen(nullptr), dsklen(0), pre_dsklen(0), dsksync(0), dskbyt(0), adkcon(0), dmacon(0), dskpt(0), dma_value(0), dma_state(0)
+amiga_fdc_device::amiga_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, AMIGA_FDC, tag, owner, clock)
+ , m_write_index(*this)
+ , m_read_dma(*this, 0)
+ , m_write_dma(*this)
+ , m_write_dskblk(*this)
+ , m_write_dsksyn(*this)
+ , m_leds(*this, "led%u", 1U)
+ , m_fdc_led(*this, "fdc_led")
+ , floppy(nullptr), t_gen(nullptr), dsklen(0), pre_dsklen(0), dsksync(0), dskbyt(0), adkcon(0), dmacon(0), dskpt(0), dma_value(0), dma_state(0)
{
}
void amiga_fdc_device::device_start()
{
- m_write_index.resolve_safe();
- m_read_dma.resolve_safe(0);
- m_write_dma.resolve_safe();
- m_write_dskblk.resolve_safe();
- m_write_dsksyn.resolve_safe();
m_leds.resolve();
m_fdc_led.resolve();
@@ -51,10 +81,9 @@ void amiga_fdc_device::device_start()
floppy = nullptr;
- t_gen = timer_alloc(0);
+ t_gen = timer_alloc(FUNC(amiga_fdc_device::update_tick), this);
}
-
void amiga_fdc_device::device_reset()
{
floppy = nullptr;
@@ -206,7 +235,12 @@ void amiga_fdc_device::live_run(const attotime &limit)
}
if(cur_live.bit_counter > 8)
- fatalerror("amiga_fdc_device::live_run - cur_live.bit_counter > 8\n");
+ {
+ // CHECKME: abreed, ghoulsvf Ghouls'n Goblins and lastnin2 at very least throws this
+ // is it a side effect of something else not happening at the right time or the assumption is right?
+ cur_live.bit_counter = 0;
+ LOGWARN("%s: live_run - cur_live.bit_counter > 8\n", machine().describe_context());
+ }
if(cur_live.bit_counter == 8) {
live_delay(RUNNING_SYNCPOINT);
@@ -229,7 +263,10 @@ void amiga_fdc_device::live_run(const attotime &limit)
return;
cur_live.bit_counter++;
if(cur_live.bit_counter > 8)
- fatalerror("amiga_fdc_device::live_run - cur_live.bit_counter > 8\n");
+ {
+ cur_live.bit_counter = 0;
+ LOGWARN("%s: live_run - cur_live.bit_counter > 8\n", machine().describe_context());
+ }
if(cur_live.bit_counter == 8) {
live_delay(RUNNING_SYNCPOINT);
@@ -243,26 +280,17 @@ void amiga_fdc_device::live_run(const attotime &limit)
if(!(dskbyt & 0x2000)) {
if(cur_live.shift_reg == dsksync) {
if(adkcon & 0x0400) {
+ // FIXME: exact dsksync behaviour, cfr. note at top
if(dma_state == DMA_WAIT_START) {
cur_live.bit_counter = 0;
- if(!(dsklen & 0x3fff))
+ if(dsklen & 0x3fff)
+ dma_state = DMA_RUNNING_BYTE_0;
+ else
dma_done();
- else if(dsklen & 0x4000) {
- dskbyt |= 0x2000;
- cur_live.bit_counter = 0;
- dma_value = dma_read();
-
- } else
- dma_write(dsksync);
-
- } else if(dma_state != DMA_IDLE) {
- dma_write(dsksync);
- cur_live.bit_counter = 0;
-
- } else if(cur_live.bit_counter != 8)
- cur_live.bit_counter = 0;
+ }
}
+
dskbyt |= 0x1000;
m_write_dsksyn(1);
} else
@@ -282,12 +310,11 @@ void amiga_fdc_device::live_run(const attotime &limit)
dma_state = DMA_RUNNING_BYTE_1;
break;
- case DMA_RUNNING_BYTE_1: {
+ case DMA_RUNNING_BYTE_1:
dma_value |= cur_live.shift_reg & 0xff;
dma_write(dma_value);
break;
}
- }
}
} else {
if(cur_live.bit_counter != 8)
@@ -328,6 +355,11 @@ void amiga_fdc_device::dma_check()
bool was_writing = dskbyt & 0x2000;
dskbyt &= 0x9fff;
if(dma_enabled()) {
+ LOGDMA("%s: DMA start dskpt=%08x dsklen=%04x dir=%s adkcon=%04x dsksync=%04x state=%d\n",
+ machine().describe_context(),
+ dskpt, dsklen & 0x3fff, BIT(dsklen, 14) ? "RAM->disk" : "disk->RAM", adkcon, dsksync, dma_state
+ );
+
if(dma_state == IDLE) {
dma_state = adkcon & 0x0400 ? DMA_WAIT_START : DMA_RUNNING_BYTE_0;
if(dma_state == DMA_RUNNING_BYTE_0) {
@@ -340,7 +372,6 @@ void amiga_fdc_device::dma_check()
}
}
} else {
- dskbyt |= 0x4000;
if(dsklen & 0x4000)
dskbyt |= 0x2000;
}
@@ -351,7 +382,6 @@ void amiga_fdc_device::dma_check()
cur_live.pll.stop_writing(floppy, cur_live.tm);
if(!was_writing && (dskbyt & 0x2000))
cur_live.pll.start_writing(cur_live.tm);
-
}
void amiga_fdc_device::adkcon_set(uint16_t data)
@@ -405,6 +435,7 @@ uint16_t amiga_fdc_device::dskptl_r()
void amiga_fdc_device::dsksync_w(uint16_t data)
{
live_sync();
+ LOGSYNC("%s: DSKSYNC %04x\n", machine().describe_context(), data);
dsksync = data;
live_run();
}
@@ -412,6 +443,10 @@ void amiga_fdc_device::dsksync_w(uint16_t data)
void amiga_fdc_device::dmacon_set(uint16_t data)
{
live_sync();
+ // log changes only
+ // FIXME: needs better boilerplate code on top level
+ if ((data & 0x210) != (dmacon & 0x210))
+ LOGDMA("%s: DMACON set DSKEN %d DMAEN %d (%04x)\n", machine().describe_context(), BIT(data, 4), BIT(data, 9), data);
dmacon = data;
dma_check();
live_run();
@@ -419,12 +454,19 @@ void amiga_fdc_device::dmacon_set(uint16_t data)
uint16_t amiga_fdc_device::dskbytr_r()
{
- uint16_t res = dskbyt;
- dskbyt &= 0x7fff;
+ uint16_t res = (dskbyt & ~0x4000);
+ // check if DMA is on
+ // logica2 diagnostic BIOS floppy test requires this
+ bool dmaon = (dma_state != DMA_IDLE) && ((dmacon & 0x0210) == 0x0210);
+ res |= dmaon << 14;
+
+ // reset DSKBYT ready on read
+ if (!machine().side_effects_disabled())
+ dskbyt &= 0x7fff;
return res;
}
-void amiga_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(amiga_fdc_device::update_tick)
{
live_sync();
live_run();
@@ -450,6 +492,7 @@ void amiga_fdc_device::ciaaprb_w(uint8_t data)
live_sync();
+ // FIXME: several sources claims that multiple drive selects is really possible
if(!(data & 0x08))
floppy = floppy_devices[0];
else if(!(data & 0x10))
@@ -490,7 +533,8 @@ uint8_t amiga_fdc_device::ciaapra_r()
{
uint8_t ret = 0x3c;
if(floppy) {
- //if(!floppy->ready_r()) fixit: seems to not work well with multiple disk drives
+ // FIXME: seems to not work well with multiple disk drives
+ //if(!floppy->ready_r())
ret &= ~0x20;
if(!floppy->trk00_r())
ret &= ~0x10;
@@ -629,7 +673,7 @@ bool amiga_fdc_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_imag
uint16_t pre_counter = counter;
counter += increment;
if(bit && !(pre_counter & 0x400) && (counter & 0x400))
- if(write_position < ARRAY_LENGTH(write_buffer))
+ if(write_position < std::size(write_buffer))
write_buffer[write_position++] = etime;
slot++;
tm = etime;
diff --git a/src/devices/machine/amigafdc.h b/src/devices/machine/amigafdc.h
index b7965c49f6c..02e8c823539 100644
--- a/src/devices/machine/amigafdc.h
+++ b/src/devices/machine/amigafdc.h
@@ -32,12 +32,13 @@ public:
void dmacon_set(uint16_t data);
uint16_t adkcon_r(void);
- DECLARE_FLOPPY_FORMATS( floppy_formats );
+ static void floppy_formats(format_registration &fr);
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_tick);
private:
// Running states
diff --git a/src/devices/machine/appldriv.cpp b/src/devices/machine/appldriv.cpp
deleted file mode 100644
index 1d207a9ab0b..00000000000
--- a/src/devices/machine/appldriv.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-/*********************************************************************
-
- appldriv.c
-
- Apple 5.25" floppy drive emulation (to be interfaced with applefdc.c)
-
-*********************************************************************/
-#include "emu.h"
-#include "appldriv.h"
-#include "imagedev/flopdrv.h"
-#include "formats/ap2_dsk.h"
-
-// our parent's device is the Disk II card (Apple II) or main driver (Mac, IIgs)
-// either way, get the drive from there.
-#define PARENT_FLOPPY_0 "^floppy0"
-#define PARENT_FLOPPY_1 "^floppy1"
-#define PARENT_FLOPPY_2 "^floppy2"
-#define PARENT_FLOPPY_3 "^floppy3"
-
-static inline apple525_floppy_image_device *get_device(device_t *device)
-{
- assert(device != nullptr);
- assert(device->type() == FLOPPY_APPLE);
-
- return downcast<apple525_floppy_image_device *>(device);
-}
-
-static int apple525_enable_mask = 1;
-
-legacy_floppy_image_device *apple525_get_subdevice(device_t *device, int drive)
-{
- switch(drive) {
- case 0 : return device->subdevice<legacy_floppy_image_device>(PARENT_FLOPPY_0);
- case 1 : return device->subdevice<legacy_floppy_image_device>(PARENT_FLOPPY_1);
- case 2 : return device->subdevice<legacy_floppy_image_device>(PARENT_FLOPPY_2);
- case 3 : return device->subdevice<legacy_floppy_image_device>(PARENT_FLOPPY_3);
- }
- return nullptr;
-}
-
-device_t *apple525_get_device_by_type(device_t *device, int ftype, int drive)
-{
- int i;
- int cnt = 0;
- for (i=0;i<4;i++) {
- legacy_floppy_image_device *disk = apple525_get_subdevice(device, i);
- if (disk->floppy_get_drive_type()==ftype) {
- if (cnt==drive) {
- return disk;
- }
- cnt++;
- }
- }
- return nullptr;
-}
-
-void apple525_set_enable_lines(device_t *device, int enable_mask)
-{
- apple525_enable_mask = enable_mask;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void apple525_load_current_track(device_t *image)
-{
- int len;
- apple525_floppy_image_device *disk;
-
- disk = get_device(image);
- len = sizeof(disk->track_data);
-
- disk->floppy_drive_read_track_data_info_buffer(0, disk->track_data, &len);
- disk->track_loaded = 1;
- disk->track_dirty = 0;
-}
-
-static void apple525_save_current_track(device_t *image, int unload)
-{
- int len;
- apple525_floppy_image_device *disk;
-
- disk = get_device(image);
-
- if (disk->track_dirty)
- {
- len = sizeof(disk->track_data);
- disk->floppy_drive_write_track_data_info_buffer(0, disk->track_data, &len);
- disk->track_dirty = 0;
- }
- if (unload)
- disk->track_loaded = 0;
-}
-
-static void apple525_seek_disk(apple525_floppy_image_device *img, signed int step)
-{
- int track;
- int pseudo_track;
- apple525_floppy_image_device *disk;
-
- disk = get_device(img);
-
- apple525_save_current_track(img, false);
-
- track = img->floppy_drive_get_current_track();
- pseudo_track = (track * 2) + disk->tween_tracks;
-
- pseudo_track += step;
- if (pseudo_track < 0)
- pseudo_track = 0;
- else if (pseudo_track/2 >= APPLE2_TRACK_COUNT)
- pseudo_track = APPLE2_TRACK_COUNT*2-1;
-
- if (pseudo_track/2 != track)
- {
- img->floppy_drive_seek(pseudo_track/2 - img->floppy_drive_get_current_track());
- disk->track_loaded = 0;
- }
-
- if (pseudo_track & 1)
- disk->tween_tracks = 1;
- else
- disk->tween_tracks = 0;
-}
-
-static void apple525_disk_set_lines(device_t *device,device_t *image, uint8_t new_state)
-{
- apple525_floppy_image_device *cur_disk;
- uint8_t old_state;
- unsigned int phase;
-
- cur_disk = get_device(image);
-
- old_state = cur_disk->state;
- cur_disk->state = new_state;
-
- if ((new_state & 0x0F) > (old_state & 0x0F))
- {
- phase = 0;
- switch((old_state ^ new_state) & 0x0F)
- {
- case 1: phase = 0; break;
- case 2: phase = 1; break;
- case 4: phase = 2; break;
- case 8: phase = 3; break;
- }
-
- phase -= cur_disk->floppy_drive_get_current_track() * 2;
- if (cur_disk->tween_tracks)
- phase--;
- phase %= 4;
-
- switch(phase)
- {
- case 1:
- apple525_seek_disk(cur_disk, +1);
- break;
- case 3:
- apple525_seek_disk(cur_disk, -1);
- break;
- }
- }
-}
-
-int apple525_get_count(device_t *device)
-{
- int cnt = 0;
- if ((device->subdevice("^" FLOPPY_0)!=nullptr) && (device->subdevice<legacy_floppy_image_device>("^" FLOPPY_0)->floppy_get_drive_type() == FLOPPY_TYPE_APPLE) && (get_device(device->subdevice(PARENT_FLOPPY_0))!=nullptr)) cnt++;
- if ((device->subdevice("^" FLOPPY_1)!=nullptr) && (device->subdevice<legacy_floppy_image_device>("^" FLOPPY_1)->floppy_get_drive_type() == FLOPPY_TYPE_APPLE) && (get_device(device->subdevice(PARENT_FLOPPY_1))!=nullptr)) cnt++;
- if ((device->subdevice("^" FLOPPY_2)!=nullptr) && (device->subdevice<legacy_floppy_image_device>("^" FLOPPY_2)->floppy_get_drive_type() == FLOPPY_TYPE_APPLE) && (get_device(device->subdevice(PARENT_FLOPPY_2))!=nullptr)) cnt++;
- if ((device->subdevice("^" FLOPPY_3)!=nullptr) && (device->subdevice<legacy_floppy_image_device>("^" FLOPPY_3)->floppy_get_drive_type() == FLOPPY_TYPE_APPLE) && (get_device(device->subdevice(PARENT_FLOPPY_3))!=nullptr)) cnt++;
-
- return cnt;
-}
-
-void apple525_set_lines(device_t *device, uint8_t lines)
-{
- int i, count;
- device_t *image;
-
- count = apple525_get_count(device);
- for (i = 0; i < count; i++)
- {
- if (apple525_enable_mask & (1 << i))
- {
- image = apple525_get_device_by_type(device, FLOPPY_TYPE_APPLE, i);
- if (image)
- apple525_disk_set_lines(device,image, lines);
- }
- }
-}
-
-/* reads/writes a byte; write_value is -1 for read only */
-static uint8_t apple525_process_byte(device_t *img, int write_value)
-{
- uint8_t read_value;
- apple525_floppy_image_device *disk;
- int spinfract_divisor;
- int spinfract_dividend;
- apple525_floppy_image_device *config = get_device(img);
- device_image_interface *image = dynamic_cast<device_image_interface *>(img);
-
- disk = get_device(img);
- spinfract_dividend = config->get_dividend();
- spinfract_divisor = config->get_divisor();
-
- /* no image initialized for that drive ? */
- if (!image->exists())
- return 0xFF;
-
- /* check the spin count if reading*/
- if (write_value < 0)
- {
- disk->spin_count++;
- disk->spin_count %= spinfract_divisor;
- if (disk->spin_count >= spinfract_dividend)
- return 0x00;
- }
-
- /* load track if need be */
- if (disk->track_loaded == 0)
- apple525_load_current_track(img);
-
- /* perform the read */
- read_value = disk->track_data[disk->position];
-
- /* perform the write, if applicable */
- if (write_value >= 0)
- {
- disk->track_data[disk->position] = write_value;
- disk->track_dirty = 1;
- }
-
- disk->position++;
- disk->position %= ARRAY_LENGTH(disk->track_data);
-
- /* when writing; save the current track after every full sector write */
- if ((write_value >= 0) && ((disk->position % APPLE2_NIBBLE_SIZE) == 0))
- apple525_save_current_track(img, false);
-
- return read_value;
-}
-
-static device_t *apple525_selected_image(device_t *device)
-{
- int i,count;
-
- count = apple525_get_count(device);
-
- for (i = 0; i < count; i++)
- {
- if (apple525_enable_mask & (1 << i))
- return apple525_get_device_by_type(device, FLOPPY_TYPE_APPLE, i);
- }
- return nullptr;
-}
-
-uint8_t apple525_read_data(device_t *device)
-{
- device_t *image;
- image = apple525_selected_image(device);
- return image ? apple525_process_byte(image, -1) : 0xFF;
-}
-
-void apple525_write_data(device_t *device,uint8_t data)
-{
- device_t *image;
- image = apple525_selected_image(device);
- if (image)
- apple525_process_byte(image, data);
-}
-
-int apple525_read_status(device_t *device)
-{
- int i, count, result = 0;
- device_image_interface *image;
-
- count = apple525_get_count(device);
-
- for (i = 0; i < count; i++)
- {
- if (apple525_enable_mask & (1 << i))
- {
- image = dynamic_cast<device_image_interface *>(apple525_get_device_by_type(device, FLOPPY_TYPE_APPLE, i));
- if (image && image->is_readonly())
- result = 1;
- }
- }
- return result;
-}
-
-// device type definition
-DEFINE_DEVICE_TYPE(FLOPPY_APPLE, apple525_floppy_image_device, "floppy_apple", "Apple Disk II")
-
-//-------------------------------------------------
-// apple525_floppy_image_device - constructor
-//-------------------------------------------------
-
-apple525_floppy_image_device::apple525_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : legacy_floppy_image_device(mconfig, FLOPPY_APPLE, tag, owner, clock)
-{
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void apple525_floppy_image_device::device_start()
-{
- legacy_floppy_image_device::device_start();
- floppy_set_type(FLOPPY_TYPE_APPLE);
-
- state = 0;
- tween_tracks = 0;
- track_loaded = 0;
- track_dirty = 0;
- position = 0;
- spin_count = 0;
- memset(track_data, 0, sizeof(track_data));
-}
-
-image_init_result apple525_floppy_image_device::call_load()
-{
- image_init_result result = legacy_floppy_image_device::call_load();
- floppy_drive_seek(-999);
- floppy_drive_seek(+35/2);
- return result;
-}
-
-void apple525_floppy_image_device::call_unload()
-{
- apple525_save_current_track(this, true);
-
- legacy_floppy_image_device::call_unload();
-}
diff --git a/src/devices/machine/appldriv.h b/src/devices/machine/appldriv.h
deleted file mode 100644
index 86f7c1658bf..00000000000
--- a/src/devices/machine/appldriv.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-/*********************************************************************
-
- appldriv.h
-
- Apple 5.25" floppy drive emulation (to be interfaced with applefdc.c)
-
-*********************************************************************/
-
-#ifndef MAME_MACHINE_APPLDRIV_H
-#define MAME_MACHINE_APPLDRIV_H
-
-#pragma once
-
-#include "imagedev/flopdrv.h"
-#include "formats/ap2_dsk.h"
-
-#define FLOPPY_0 "floppy0"
-#define FLOPPY_1 "floppy1"
-#define FLOPPY_2 "floppy2"
-#define FLOPPY_3 "floppy3"
-
-void apple525_set_lines(device_t *device, uint8_t lines);
-void apple525_set_enable_lines(device_t *device, int enable_mask);
-
-uint8_t apple525_read_data(device_t *device);
-void apple525_write_data(device_t *device, uint8_t data);
-int apple525_read_status(device_t *device);
-int apple525_get_count(running_machine &machine);
-
-class apple525_floppy_image_device : public legacy_floppy_image_device
-{
-public:
- // construction/destruction
- apple525_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, const floppy_interface *config, int dividend, int divisor)
- : apple525_floppy_image_device(mconfig, tag, owner, (uint32_t)0)
- {
- set_floppy_config(config);
- set_params(dividend, divisor);
- }
- apple525_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
-
- virtual image_init_result call_load() override;
- virtual void call_unload() override;
- void set_params(int dividend, int divisor) { m_dividend = dividend; m_divisor = divisor; }
-
- int get_dividend() { return m_dividend; }
- int get_divisor() { return m_divisor; }
-
- // these elements should be private, but are not yet
- unsigned int state : 4; /* bits 0-3 are the phase */
- unsigned int tween_tracks : 1;
- unsigned int track_loaded : 1;
- unsigned int track_dirty : 1;
- int position;
- int spin_count; /* simulate drive spin to fool RWTS test at $BD34 */
- uint8_t track_data[APPLE2_NIBBLE_SIZE * APPLE2_SECTOR_COUNT];
-
-protected:
- virtual void device_start() override;
-
-private:
- int m_dividend;
- int m_divisor;
-};
-
-// device type definition
-DECLARE_DEVICE_TYPE(FLOPPY_APPLE, apple525_floppy_image_device)
-
-#endif // MAME_MACHINE_APPLDRIV_H
diff --git a/src/devices/machine/applefdc.cpp b/src/devices/machine/applefdc.cpp
deleted file mode 100644
index da817ccb1d8..00000000000
--- a/src/devices/machine/applefdc.cpp
+++ /dev/null
@@ -1,586 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Nathan Woods, Raphael Nabet, R. Belmont
-/*********************************************************************
-
- 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 "emu.h"
-#include "applefdc.h"
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-// logging
-#define LOG_APPLEFDC 0
-#define LOG_APPLEFDC_EXTRA 0
-
-// mask for FDC lines
-#define IWM_MOTOR 0x10
-#define IWM_DRIVE 0x20
-#define IWM_Q6 0x40
-#define IWM_Q7 0x80
-
-const device_timer_id TIMER_MOTOR_ONOFF = 1;
-
-
-
-
-
-/***************************************************************************
- 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
-};
-
-
-
-/***************************************************************************
- BASE DEVICE
-***************************************************************************/
-
-//-------------------------------------------------
-// ctor
-//-------------------------------------------------
-
-applefdc_base_device::applefdc_base_device(applefdc_base_device::applefdc_t fdc_type, const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- m_type(fdc_type),
- m_interface(nullptr)
-{
-}
-
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void applefdc_base_device::device_start()
-{
- // timer
- m_motor_timer = timer_alloc(TIMER_MOTOR_ONOFF);
-
- // state
- m_write_byte = 0x00;
- m_lines = 0x00;
- m_mode = 0x1F; // default value needed by Lisa 2 - no, I don't know if it is true
- m_handshake_hack = 0x00;
-
- // register save states
- save_item(NAME(m_write_byte));
- save_item(NAME(m_lines));
- save_item(NAME(m_mode));
- save_item(NAME(m_handshake_hack));
-}
-
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void applefdc_base_device::device_reset(void)
-{
- m_handshake_hack = 0x00;
- m_write_byte = 0x00;
- m_lines = 0x00;
- m_mode = 0x1F; /* default value needed by Lisa 2 - no, I don't know if it is true */
- m_motor_timer->reset();
-}
-
-
-
-//-------------------------------------------------
-// device_timer - device-specific timer callbacks
-//-------------------------------------------------
-
-void applefdc_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch(id)
- {
- case TIMER_MOTOR_ONOFF:
- turn_motor_onoff(param != 0);
- break;
- }
-}
-
-
-
-//-------------------------------------------------
-// get_interface - gets the interface
-//-------------------------------------------------
-
-const applefdc_interface *applefdc_base_device::get_interface()
-{
- static const applefdc_interface dummy_interface = {nullptr, };
-
- return (m_interface != nullptr) ? m_interface : &dummy_interface;
-}
-
-
-
-//-------------------------------------------------
-// iwm_enable2 - hackish function
-//-------------------------------------------------
-
-int applefdc_base_device::iwm_enable2()
-{
- /* 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 (m_lines & APPLEFDC_PH1) && (m_lines & APPLEFDC_PH3);
-}
-
-
-
-//-------------------------------------------------
-// iwm_readenable2handshake - hackish function
-//-------------------------------------------------
-
-uint8_t applefdc_base_device::iwm_readenable2handshake()
-{
- /* 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 */
- m_handshake_hack++;
- m_handshake_hack %= 4;
- return (m_handshake_hack != 0) ? 0xc0 : 0x80;
-}
-
-
-
-//-------------------------------------------------
-// statusreg_r - reads the status register
-//-------------------------------------------------
-
-uint8_t applefdc_base_device::statusreg_r()
-{
- uint8_t result;
- int status;
- const applefdc_interface *intf = get_interface();
-
- /* 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() ? 1 : (intf->read_status ? intf->read_status(this) : 0);
-
- result = (status ? 0x80 : 0x00);
-
- if (m_type != APPLEFDC_APPLE2)
- result |= (((m_lines & IWM_MOTOR) ? 1 : 0) << 5) | m_mode;
- return result;
-}
-
-
-
-//-------------------------------------------------
-// iwm_modereg_w - changes the mode register
-//-------------------------------------------------
-
-void applefdc_base_device::iwm_modereg_w(uint8_t data)
-{
- m_mode = data & 0x1f; /* write mode register */
-
- if (LOG_APPLEFDC_EXTRA)
- logerror("iwm_modereg_w: iwm_mode=0x%02x\n", (unsigned) m_mode);
-}
-
-
-
-//-------------------------------------------------
-// read_reg - reads a register
-//-------------------------------------------------
-
-uint8_t applefdc_base_device::read_reg(int lines)
-{
- const applefdc_interface *intf = get_interface();
- uint8_t result = 0;
-
- switch(lines)
- {
- case 0:
- // read data register
- if ((m_type != APPLEFDC_APPLE2) && (iwm_enable2() || !(m_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 ((m_mode & IWM_MODE_LATCHMODE) == 0x00)
- logerror("applefdc_read_reg(): latch mode off not implemented\n");
- }
-
- result = (intf->read_data ? intf->read_data(this) : 0x00);
- }
- break;
-
- case IWM_Q6:
- // read status register
- result = statusreg_r();
- break;
-
- case IWM_Q7:
- // Classic Apple II: Read status register
- // IWM: Read handshake register
- if (m_type == APPLEFDC_APPLE2)
- result = statusreg_r();
- else
- result = iwm_enable2() ? iwm_readenable2handshake() : 0x80;
- break;
- }
- return result;
-}
-
-
-
-//-------------------------------------------------
-// write_reg - writes a register
-//-------------------------------------------------
-
-void applefdc_base_device::write_reg(uint8_t data)
-{
- const applefdc_interface *intf = get_interface();
-
- switch(m_lines & (IWM_Q6 | IWM_Q7))
- {
- case IWM_Q6 | IWM_Q7:
- if (!(m_lines & IWM_MOTOR))
- {
- iwm_modereg_w(data);
- }
- else if (!iwm_enable2())
- {
- // 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 ((m_mode & IWM_MODE_LATCHMODE) == 0)
- logerror("applefdc_write_reg(): latch mode off not implemented\n");
- }
-
- if (intf->write_data != nullptr)
- intf->write_data(this, data);
- }
- break;
- }
-}
-
-
-
-//-------------------------------------------------
-// turn_motor_onoff - timer callback for turning
-// motor on or off
-//-------------------------------------------------
-
-void applefdc_base_device::turn_motor_onoff(bool status)
-{
- const applefdc_interface *intf = get_interface();
- int enable_lines;
-
- if (status)
- {
- m_lines |= IWM_MOTOR;
- enable_lines = (m_lines & IWM_DRIVE) ? 2 : 1;
- }
- else
- {
- m_lines &= ~IWM_MOTOR;
-
- if (m_type == APPLEFDC_APPLE2)
- enable_lines = (m_lines & IWM_DRIVE) ? 2 : 1;
- else
- enable_lines = 0;
- }
-
- /* invoke callback, if present */
- if (intf->set_enable_lines != nullptr)
- intf->set_enable_lines(this, enable_lines);
-
- if (LOG_APPLEFDC_EXTRA)
- logerror("iwm_turnmotor_onoff(): Turning motor %s\n", status ? "on" : "off");
-}
-
-
-
-//-------------------------------------------------
-// iwm_access
-//-------------------------------------------------
-
-void applefdc_base_device::iwm_access(int offset)
-{
- static const char *const lines[] =
- {
- "PH0",
- "PH1",
- "PH2",
- "PH3",
- "MOTOR",
- "DRIVE",
- "Q6",
- "Q7"
- };
-
- const applefdc_interface *intf = get_interface();
-
- if (offset & 1)
- m_lines |= (1 << (offset >> 1));
- else
- m_lines &= ~(1 << (offset >> 1));
-
- if (LOG_APPLEFDC_EXTRA)
- {
- logerror("iwm_access(): %s line %s => %02x\n",
- (offset & 1) ? "setting" : "clearing", lines[offset >> 1], m_lines);
- }
-
- if ((offset < 0x08) && (intf->set_lines != nullptr))
- intf->set_lines(this, m_lines & 0x0f);
-
- switch(offset)
- {
- case 0x08:
- /* turn off motor */
- m_motor_timer->adjust(
- (m_mode & IWM_MODE_MOTOROFFDELAY) ? attotime::zero : attotime::from_seconds(1), 0);
- break;
-
- case 0x09:
- /* turn on motor */
- m_motor_timer->adjust(attotime::zero, 1);
- break;
-
- case 0x0A:
- /* turn off IWM_DRIVE */
- if ((m_lines & IWM_MOTOR) && (intf->set_enable_lines != nullptr))
- intf->set_enable_lines(this, 1);
- break;
-
- case 0x0B:
- /* turn on IWM_DRIVE */
- if ((m_lines & IWM_MOTOR) && (intf->set_enable_lines != nullptr))
- intf->set_enable_lines(this, 2);
- break;
- }
-}
-
-
-
-//-------------------------------------------------
-// read - reads a byte from the FDC
-//-------------------------------------------------
-
-uint8_t applefdc_base_device::read(offs_t offset)
-{
- const applefdc_interface *intf = get_interface();
- uint8_t result = 0;
-
- // normalize offset
- offset &= 0xf;
-
- if (LOG_APPLEFDC_EXTRA)
- logerror("applefdc_r: offset=%i\n", offset);
-
- iwm_access(offset);
-
- switch(m_type)
- {
- case APPLEFDC_APPLE2:
- switch(offset)
- {
- case 0x0C:
- if (m_lines & IWM_Q7)
- {
- if (intf->write_data != nullptr)
- intf->write_data(this, m_write_byte);
- result = 0;
- }
- else
- result = read_reg(0);
- break;
-
- case 0x0D:
- result = read_reg(IWM_Q6);
- break;
-
- case 0x0E:
- result = read_reg(IWM_Q7);
- break;
-
- case 0x0F:
- result = read_reg(IWM_Q7 | IWM_Q6);
- break;
- }
- break;
-
- case APPLEFDC_IWM:
- if ((offset & 1) == 0)
- result = read_reg(m_lines & (IWM_Q6 | IWM_Q7));
- break;
-
- case APPLEFDC_SWIM:
- if ((offset & 1) == 0)
- result = read_reg(m_lines & (IWM_Q6 | IWM_Q7));
- break;
- }
-
- return result;
-}
-
-
-
-//-------------------------------------------------
-// write - writes a byte to the FDC
-//-------------------------------------------------
-
-void applefdc_base_device::write(offs_t offset, uint8_t data)
-{
- const applefdc_interface *intf = get_interface();
-
- /* normalize offset */
- offset &= 15;
-
- if (LOG_APPLEFDC_EXTRA)
- logerror("applefdc_w: offset=%i data=0x%02x\n", offset, data);
-
- iwm_access(offset);
-
- switch(m_type)
- {
- case APPLEFDC_APPLE2:
- switch(offset)
- {
- case 0x0C:
- if (m_lines & IWM_Q7)
- {
- if (intf->write_data != nullptr)
- intf->write_data(this, m_write_byte);
- }
- break;
-
- case 0x0D:
- m_write_byte = data;
- break;
- }
- break;
-
- case APPLEFDC_IWM:
- if (offset & 1)
- write_reg(data);
- break;
-
- case APPLEFDC_SWIM:
- if (offset & 1)
- write_reg(data);
- break;
- }
-}
-
-
-
-//-------------------------------------------------
-// get_lines - accessor
-//-------------------------------------------------
-
-uint8_t applefdc_base_device::get_lines()
-{
- return m_lines & 0x0f;
-}
-
-
-
-/***************************************************************************
- APPLE FDC - Used on Apple II
-***************************************************************************/
-
-DEFINE_DEVICE_TYPE(LEGACY_APPLEFDC, applefdc_device, "apple_fdcl", "Apple FDC (legacy)")
-
-applefdc_device::applefdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : applefdc_base_device(APPLEFDC_APPLE2, mconfig, LEGACY_APPLEFDC, tag, owner, clock)
-{
-}
-
-
-
-/***************************************************************************
- IWM - Used on early Macs
-***************************************************************************/
-
-DEFINE_DEVICE_TYPE(LEGACY_IWM, legacy_iwm_device, "iwml", "Apple IWM (Integrated Woz Machine) (legacy)")
-
-legacy_iwm_device::legacy_iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : applefdc_base_device(APPLEFDC_IWM, mconfig, LEGACY_IWM, tag, owner, clock)
-{
-}
diff --git a/src/devices/machine/applefdc.h b/src/devices/machine/applefdc.h
deleted file mode 100644
index cf8f06f4cb9..00000000000
--- a/src/devices/machine/applefdc.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Nathan Woods, Raphael Nabet, R. Belmont
-/*********************************************************************
-
- 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 MAME_MACHINE_APPLEFDC_H
-#define MAME_MACHINE_APPLEFDC_H
-
-#pragma once
-
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define APPLEFDC_PH0 0x01
-#define APPLEFDC_PH1 0x02
-#define APPLEFDC_PH2 0x04
-#define APPLEFDC_PH3 0x08
-
-DECLARE_DEVICE_TYPE(LEGACY_APPLEFDC, applefdc_device)
-DECLARE_DEVICE_TYPE(LEGACY_IWM, legacy_iwm_device)
-
-
-
-/***************************************************************************
- INTERFACE
-***************************************************************************/
-
-struct applefdc_interface
-{
- void (*set_lines)(device_t *device, uint8_t lines);
- void (*set_enable_lines)(device_t *device, int enable_mask);
-
- uint8_t (*read_data)(device_t *device);
- void (*write_data)(device_t *device, uint8_t data);
- int (*read_status)(device_t *device);
-};
-
-
-
-/***************************************************************************
- BASE DEVICE
-***************************************************************************/
-
-class applefdc_base_device : public device_t
-{
-public:
- // configuration helpers
- void set_config(const applefdc_interface *intrf) { m_interface = intrf; }
-
- // read/write handlers
- virtual uint8_t read(offs_t offset);
- virtual void write(offs_t offset, uint8_t data);
-
- // accessor
- uint8_t get_lines();
-
- virtual void device_reset() override;
-
-protected:
- enum applefdc_t
- {
- APPLEFDC_APPLE2, /* classic Apple II disk controller (pre-IWM) */
- APPLEFDC_IWM, /* Integrated Woz Machine */
- APPLEFDC_SWIM /* Sander/Woz Integrated Machine */
- };
-
- // constructor
- applefdc_base_device(applefdc_t fdc_type, const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
- // other protecteds
- virtual void iwm_modereg_w(uint8_t data);
-
-private:
- // data that is constant for the lifetime of the emulation
- emu_timer * m_motor_timer;
- applefdc_t m_type;
- const applefdc_interface *m_interface;
-
- // data that changes at emulation time
- uint8_t m_write_byte;
- uint8_t m_lines; /* flags from IWM_MOTOR - IWM_Q7 */
- uint8_t m_mode; /* 0-31; see above */
- uint8_t m_handshake_hack; /* not sure what this is for */
-
- // functions
- const applefdc_interface *get_interface();
- int iwm_enable2();
- uint8_t iwm_readenable2handshake();
- uint8_t statusreg_r();
- uint8_t read_reg(int lines);
- void write_reg(uint8_t data);
- void turn_motor_onoff(bool status);
- void iwm_access(int offset);
-};
-
-
-
-/***************************************************************************
- APPLE FDC - Used on Apple II
-***************************************************************************/
-
-class applefdc_device : public applefdc_base_device
-{
-public:
- applefdc_device(const machine_config &mconfig, const char *tag, device_t *owner, const applefdc_interface *intrf)
- : applefdc_device(mconfig, tag, owner, (uint32_t)0)
- {
- set_config(intrf);
- }
-
- applefdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-};
-
-
-
-/***************************************************************************
- IWM - Used on early Macs
-***************************************************************************/
-
-class legacy_iwm_device : public applefdc_base_device
-{
-public:
- legacy_iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, const applefdc_interface *intrf)
- : legacy_iwm_device(mconfig, tag, owner, (uint32_t)0)
- {
- set_config(intrf);
- }
-
- legacy_iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- static constexpr feature_type imperfect_features() { return feature::DISK; }
-};
-
-#endif // MAME_MACHINE_APPLEFDC_H
diff --git a/src/devices/machine/applefdintf.cpp b/src/devices/machine/applefdintf.cpp
index 3b1590720c1..1bb1007d6b8 100755..100644
--- a/src/devices/machine/applefdintf.cpp
+++ b/src/devices/machine/applefdintf.cpp
@@ -5,24 +5,39 @@
#include "applefdintf.h"
#include "formats/ap2_dsk.h"
#include "formats/ap_dsk35.h"
-#include "formats/pc_dsk.h"
+#include "formats/as_dsk.h"
+#include "formats/fs_prodos.h"
-FLOPPY_FORMATS_MEMBER(applefdintf_device::formats_525_13)
- FLOPPY_EDD_FORMAT,
- FLOPPY_WOZ_FORMAT
-FLOPPY_FORMATS_END
+void applefdintf_device::formats_525_13(format_registration &fr)
+{
+ fr.add(FLOPPY_EDD_FORMAT);
+ fr.add(FLOPPY_WOZ_FORMAT);
+ fr.add(FLOPPY_NIB_FORMAT);
+}
+
+void applefdintf_device::formats_525(format_registration &fr)
+{
+ fr.add(FLOPPY_A216S_DOS_FORMAT);
+ fr.add(FLOPPY_A216S_PRODOS_FORMAT);
+ fr.add(FLOPPY_RWTS18_FORMAT);
+ fr.add(FLOPPY_EDD_FORMAT);
+ fr.add(FLOPPY_WOZ_FORMAT);
+ fr.add(FLOPPY_NIB_FORMAT);
-FLOPPY_FORMATS_MEMBER(applefdintf_device::formats_525)
- FLOPPY_A216S_FORMAT,
- FLOPPY_RWTS18_FORMAT,
- FLOPPY_EDD_FORMAT,
- FLOPPY_WOZ_FORMAT
-FLOPPY_FORMATS_END
+ fr.add(fs::PRODOS);
+}
+
+void applefdintf_device::formats_35(format_registration &fr)
+{
+ fr.add_pc_formats();
+ fr.add(FLOPPY_DC42_FORMAT);
+ fr.add(FLOPPY_WOZ_FORMAT);
+ fr.add(FLOPPY_MOOF_FORMAT);
+ fr.add(FLOPPY_APPLE_GCR_FORMAT);
+ fr.add(FLOPPY_APPLE_2MG_FORMAT);
-FLOPPY_FORMATS_MEMBER(applefdintf_device::formats_35)
- FLOPPY_DC42_FORMAT,
- FLOPPY_PC_FORMAT
-FLOPPY_FORMATS_END
+ fr.add(fs::PRODOS);
+}
void applefdintf_device::floppies_525(device_slot_interface &device)
{
@@ -31,7 +46,9 @@ void applefdintf_device::floppies_525(device_slot_interface &device)
void applefdintf_device::floppies_35(device_slot_interface &device)
{
- device.option_add("35", FLOPPY_35_HD);
+ device.option_add("35sd", OAD34V);
+ device.option_add("35dd", MFD51W);
+ device.option_add("35hd", MFD75W);
}
applefdintf_device::applefdintf_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
@@ -39,16 +56,13 @@ applefdintf_device::applefdintf_device(const machine_config &mconfig, device_typ
m_phases_cb(*this),
m_devsel_cb(*this),
m_sel35_cb(*this),
- m_hdsel_cb(*this)
+ m_hdsel_cb(*this),
+ m_dat1byte_cb(*this)
{
}
void applefdintf_device::device_start()
{
- m_phases_cb.resolve_safe();
- m_devsel_cb.resolve_safe();
- m_sel35_cb.resolve_safe();
- m_hdsel_cb.resolve_safe();
save_item(NAME(m_phases));
save_item(NAME(m_phases_input));
}
diff --git a/src/devices/machine/applefdintf.h b/src/devices/machine/applefdintf.h
index c6cc7a2d451..97f5bc19b22 100755..100644
--- a/src/devices/machine/applefdintf.h
+++ b/src/devices/machine/applefdintf.h
@@ -39,6 +39,9 @@ public:
// hdsel line when present and in output mode (active high)
auto hdsel_cb() { return m_hdsel_cb.bind(); }
+ // dat1byte line when present (active high)
+ auto dat1byte_cb() { return m_dat1byte_cb.bind(); }
+
// floppy selection input, to be updated according to the previous callbacks,
// nullptr if none selected
virtual void set_floppy(floppy_image_device *floppy) = 0;
@@ -48,43 +51,53 @@ public:
// Floppy formats
// 13-sector 5.25
- DECLARE_FLOPPY_FORMATS(formats_525_13);
+ static void formats_525_13(format_registration &fr);
// 5.25
- DECLARE_FLOPPY_FORMATS(formats_525);
+ static void formats_525(format_registration &fr);
// 3.5
- DECLARE_FLOPPY_FORMATS(formats_35);
+ static void formats_35(format_registration &fr);
// Floppy drives slot-level
// 5.25
static void floppies_525(device_slot_interface &device);
template<typename T> static void add_525_13(machine_config &config, T &floppy) {
- FLOPPY_CONNECTOR(config, floppy, floppies_525, "525", formats_525_13);
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, "525", formats_525_13).enable_sound(true);
}
template<typename T> static void add_525_13_nc(machine_config &config, T &floppy) {
- FLOPPY_CONNECTOR(config, floppy, floppies_525, "", formats_525_13);
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, nullptr, formats_525_13).enable_sound(true);
}
template<typename T> static void add_525(machine_config &config, T &floppy) {
- FLOPPY_CONNECTOR(config, floppy, floppies_525, "525", formats_525);
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, "525", formats_525).enable_sound(true);
}
template<typename T> static void add_525_nc(machine_config &config, T &floppy) {
- FLOPPY_CONNECTOR(config, floppy, floppies_525, "", formats_525);
+ FLOPPY_CONNECTOR(config, floppy, floppies_525, nullptr, formats_525).enable_sound(true);
}
// 3.5
static void floppies_35(device_slot_interface &device);
template<typename T> static void add_35(machine_config &config, T &floppy) {
- FLOPPY_CONNECTOR(config, floppy, floppies_35, "35", formats_35);
+ FLOPPY_CONNECTOR(config, floppy, floppies_35, "35dd", formats_35).enable_sound(true);
+ }
+ template<typename T> static void add_35_sd(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_35, "35sd", formats_35).enable_sound(true);
+ }
+ template<typename T> static void add_35_hd(machine_config &config, T &floppy) {
+ FLOPPY_CONNECTOR(config, floppy, floppies_35, "35hd", formats_35).enable_sound(true);
}
template<typename T> static void add_35_nc(machine_config &config, T &floppy) {
- FLOPPY_CONNECTOR(config, floppy, floppies_35, "", formats_35);
+ FLOPPY_CONNECTOR(config, floppy, floppies_35, nullptr, formats_35).enable_sound(true);
}
+ // Sync the state when something external is going to change, like
+ // the floppy side or rpm.
+ virtual void sync() = 0;
+
protected:
devcb_write8 m_phases_cb, m_devsel_cb;
- devcb_write_line m_sel35_cb, m_hdsel_cb;
+ devcb_write_line m_sel35_cb, m_hdsel_cb, m_dat1byte_cb;
// Current phase value in the bottom bits, input/output flags in the top bits
u8 m_phases;
diff --git a/src/devices/machine/applepic.cpp b/src/devices/machine/applepic.cpp
new file mode 100644
index 00000000000..feb122140d4
--- /dev/null
+++ b/src/devices/machine/applepic.cpp
@@ -0,0 +1,434 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Apple Computer 343S1021 PIC (Peripheral Interface Controller)
+
+ NCR standard cell ASIC, 65CX02 CPU core
+
+**********************************************************************/
+
+#include "emu.h"
+#include "applepic.h"
+
+#define VERBOSE 0
+#include "logmacro.h"
+
+// device type definition
+DEFINE_DEVICE_TYPE(APPLEPIC, applepic_device, "applepic", "Apple 343S1021 PIC")
+
+const std::string_view applepic_device::s_interrupt_names[8] = { "0", "DMA 1", "DMA 2", "peripheral", "host", "timer", "6", "7" };
+
+applepic_device::applepic_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, APPLEPIC, tag, owner, clock)
+ , m_iopcpu(*this, "iopcpu")
+ , m_prd_callback(*this, 0)
+ , m_pwr_callback(*this)
+ , m_hint_callback(*this)
+ , m_gpin_callback(*this, 0)
+ , m_gpout_callback(*this)
+ , m_timer1(nullptr)
+ , m_timer_last_expired(attotime::zero)
+ , m_ram_address(0)
+ , m_status_reg(0x80)
+ , m_timer_latch(0)
+ , m_scc_control(0)
+ , m_io_control(0)
+ , m_timer_dpll_control(0)
+ , m_int_mask(0)
+ , m_int_reg(0)
+{
+ for (dma_channel &channel : m_dma_channel)
+ {
+ channel.control = 0;
+ channel.map = 0;
+ channel.tc = 0;
+ }
+}
+
+void applepic_device::internal_map(address_map &map)
+{
+ map(0x0000, 0x6fff).mirror(0x8000).ram();
+ map(0x7000, 0x77ff).ram();
+ map(0x7800, 0x7fff).mirror(0x8000).ram();
+ map(0xf010, 0xf013).rw(FUNC(applepic_device::timer_r), FUNC(applepic_device::timer_w));
+ map(0xf020, 0xf02f).rw(FUNC(applepic_device::dma_channel_r), FUNC(applepic_device::dma_channel_w));
+ map(0xf030, 0xf030).rw(FUNC(applepic_device::scc_control_r), FUNC(applepic_device::scc_control_w));
+ map(0xf031, 0xf031).rw(FUNC(applepic_device::io_control_r), FUNC(applepic_device::io_control_w));
+ map(0xf032, 0xf032).rw(FUNC(applepic_device::timer_dpll_control_r), FUNC(applepic_device::timer_dpll_control_w));
+ map(0xf033, 0xf033).rw(FUNC(applepic_device::int_mask_r), FUNC(applepic_device::int_mask_w));
+ map(0xf034, 0xf034).rw(FUNC(applepic_device::int_reg_r), FUNC(applepic_device::int_reg_w));
+ map(0xf035, 0xf035).rw(FUNC(applepic_device::host_reg_r), FUNC(applepic_device::host_reg_w));
+ map(0xf040, 0xf04f).rw(FUNC(applepic_device::device_reg_r), FUNC(applepic_device::device_reg_w));
+}
+
+void applepic_device::device_add_mconfig(machine_config &config)
+{
+ R65C02(config, m_iopcpu, DERIVED_CLOCK(1, 8));
+ m_iopcpu->set_addrmap(AS_PROGRAM, &applepic_device::internal_map);
+}
+
+void applepic_device::device_start()
+{
+ // Initialize timer
+ m_timer1 = timer_alloc(FUNC(applepic_device::timer1_callback), this);
+
+ // Save internal state
+ save_item(NAME(m_timer_last_expired));
+ save_item(NAME(m_ram_address));
+ save_item(NAME(m_status_reg));
+ save_item(NAME(m_timer_latch));
+ save_item(STRUCT_MEMBER(m_dma_channel, control));
+ save_item(STRUCT_MEMBER(m_dma_channel, map));
+ save_item(STRUCT_MEMBER(m_dma_channel, tc));
+ save_item(NAME(m_scc_control));
+ save_item(NAME(m_io_control));
+ save_item(NAME(m_timer_dpll_control));
+ save_item(NAME(m_int_mask));
+ save_item(NAME(m_int_reg));
+}
+
+void applepic_device::device_reset()
+{
+ m_status_reg &= 0xc3;
+ m_int_mask = 0;
+
+ m_iopcpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, CLEAR_LINE);
+ m_hint_callback(CLEAR_LINE);
+}
+
+u8 applepic_device::host_r(offs_t offset)
+{
+ if (BIT(offset, 4))
+ {
+ if (BIT(m_scc_control, 0))
+ return m_prd_callback(offset & 0x0f);
+ else
+ {
+ if (!machine().side_effects_disabled())
+ logerror("%s: Read from device register $%X in non-bypass mode\n", machine().describe_context(), offset & 0x0f);
+ return 0;
+ }
+ }
+ else if (BIT(offset, 2))
+ {
+ // Shared RAM read access
+ u8 data = m_iopcpu->space(AS_PROGRAM).read_byte(m_ram_address);
+ if (BIT(m_status_reg, 1) && !machine().side_effects_disabled())
+ ++m_ram_address;
+ return data;
+ }
+ else if (BIT(offset, 1))
+ {
+ // PINT (D6) and /REQ (D7) are used in bypass mode only
+ return BIT(m_scc_control, 0) ? m_status_reg | 0x01 : (m_status_reg & 0x3f) | 0x80;
+ }
+ else if (BIT(offset, 0))
+ return m_ram_address & 0x00ff;
+ else
+ return (m_ram_address & 0xff00) >> 8;
+}
+
+void applepic_device::host_w(offs_t offset, u8 data)
+{
+ if (BIT(offset, 4))
+ {
+ if (BIT(m_scc_control, 0))
+ m_pwr_callback(offset & 0x0f, data);
+ else
+ logerror("%s: Write $%02X to device register $%X in non-bypass mode\n", machine().describe_context(), data, offset & 0x0f);
+ }
+ else if (BIT(offset, 2))
+ {
+ // Shared RAM write access
+ m_iopcpu->space(AS_PROGRAM).write_byte(m_ram_address, data);
+ if (BIT(m_status_reg, 1))
+ ++m_ram_address;
+ }
+ else if (BIT(offset, 1))
+ {
+ if (BIT(m_status_reg, 2) != BIT(data, 2))
+ {
+ LOG("%s: /RSTPIC %dactive\n", machine().describe_context(), BIT(data, 2) ? "in" : "");
+ m_iopcpu->set_input_line(INPUT_LINE_RESET, BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE);
+ }
+ if (BIT(data, 3))
+ set_interrupt(4);
+ if ((m_status_reg & data & 0x30) != 0)
+ {
+ m_status_reg &= ~(data & 0x30);
+ if ((m_status_reg & 0x30) == 0)
+ {
+ LOG("%s: Host interrupts acknowledged\n", machine().describe_context());
+ m_hint_callback(CLEAR_LINE);
+ }
+ }
+ m_status_reg = (data & 0x06) | (m_status_reg & 0xf0);
+ }
+ else if (BIT(offset, 0))
+ m_ram_address = (m_ram_address & 0xff00) | data;
+ else
+ m_ram_address = u16(data) << 8 | (m_ram_address & 0x00ff);
+}
+
+void applepic_device::pint_w(int state)
+{
+ if (state == ASSERT_LINE)
+ {
+ m_status_reg |= 0x40;
+ if (!BIT(m_scc_control, 0))
+ set_interrupt(3);
+ }
+ else
+ {
+ m_status_reg &= 0xbf;
+ if (!BIT(m_scc_control, 0))
+ reset_interrupt(3);
+ }
+}
+
+void applepic_device::reqa_w(int state)
+{
+ if (state == ASSERT_LINE)
+ m_dma_channel[0].control |= 0x02;
+ else
+ m_dma_channel[0].control &= 0xfd;
+}
+
+void applepic_device::reqb_w(int state)
+{
+ if (state == ASSERT_LINE)
+ m_dma_channel[1].control |= 0x02;
+ else
+ m_dma_channel[1].control &= 0xfd;
+}
+
+u8 applepic_device::timer_r(offs_t offset)
+{
+ u16 reg = BIT(offset, 1) ? m_timer_latch : get_timer_count();
+ if (BIT(offset, 0))
+ return (reg & 0xff00) >> 8;
+ else
+ {
+ if (offset == 0 && !machine().side_effects_disabled())
+ reset_interrupt(5);
+ return reg & 0x00ff;
+ }
+}
+
+void applepic_device::timer_w(offs_t offset, u8 data)
+{
+ if (BIT(offset, 0))
+ {
+ m_timer_latch = u16(data) << 8 | (m_timer_latch & 0x00ff);
+ if (offset == 1)
+ {
+ reset_interrupt(5);
+ m_timer1->adjust(clocks_to_attotime(m_timer_latch * 8 + 12));
+ }
+ }
+ else
+ m_timer_latch = (m_timer_latch & 0xff00) | data;
+}
+
+u16 applepic_device::get_timer_count() const
+{
+ if (m_timer1->enabled())
+ return u16((attotime_to_clocks(m_timer1->remaining()) - 4) / 8);
+ else
+ return 0xffff - u16((attotime_to_clocks(machine().time() - m_timer_last_expired) + 4) / 8);
+}
+
+TIMER_CALLBACK_MEMBER(applepic_device::timer1_callback)
+{
+ set_interrupt(5);
+ if (BIT(m_timer_dpll_control, 0))
+ m_timer1->adjust(clocks_to_attotime((m_timer_latch + 2) * 8));
+ else
+ m_timer_last_expired = machine().time();
+}
+
+u8 applepic_device::dma_channel_r(offs_t offset)
+{
+ dma_channel &channel = m_dma_channel[BIT(offset, 3)];
+
+ switch (offset & 7)
+ {
+ case 0:
+ return channel.control;
+
+ case 1:
+ return channel.map & 0x00ff;
+
+ case 2:
+ return (channel.map & 0xff00) >> 8;
+
+ case 3:
+ return channel.tc & 0x0ff;
+
+ case 4:
+ return (channel.tc & 0x700) >> 8;
+
+ default:
+ if (!machine().side_effects_disabled())
+ logerror("%s: Read from undefined DMA register $%02X\n", machine().describe_context(), 0x20 + offset);
+ return 0;
+ }
+}
+
+void applepic_device::dma_channel_w(offs_t offset, u8 data)
+{
+ dma_channel &channel = m_dma_channel[BIT(offset, 3)];
+
+ switch (offset & 7)
+ {
+ case 0:
+ channel.control = (data & 0xfd) | (channel.control & 0x02);
+ break;
+
+ case 1:
+ channel.map = (channel.map & 0xff00) | data;
+ break;
+
+ case 2:
+ channel.map = u16(data) << 8 | (channel.map & 0x00ff);
+ break;
+
+ case 3:
+ channel.tc = (channel.tc & 0x700) | data;
+ break;
+
+ case 4:
+ channel.tc = (data & 0x07) | (channel.tc & 0x0ff);
+ break;
+
+ default:
+ logerror("%s: Write $%02X to undefined DMA register $%02X\n", machine().describe_context(), data, 0x20 + offset);
+ break;
+ }
+}
+
+u8 applepic_device::scc_control_r()
+{
+ return m_scc_control;
+}
+
+void applepic_device::scc_control_w(u8 data)
+{
+ m_scc_control = data;
+ if (!BIT(data, 0) && BIT(m_status_reg, 6))
+ set_interrupt(3);
+ else
+ reset_interrupt(3);
+ m_gpout_callback[1](BIT(data, 7));
+}
+
+u8 applepic_device::io_control_r()
+{
+ return m_io_control;
+}
+
+void applepic_device::io_control_w(u8 data)
+{
+ m_io_control = data;
+}
+
+u8 applepic_device::timer_dpll_control_r()
+{
+ return m_timer_dpll_control | (m_gpin_callback() & 3) << 2;
+}
+
+void applepic_device::timer_dpll_control_w(u8 data)
+{
+ m_timer_dpll_control = (m_timer_dpll_control & 0xa0) | (data & 0x53);
+ m_gpout_callback[0](BIT(data, 1));
+}
+
+u8 applepic_device::int_mask_r()
+{
+ return m_int_mask;
+}
+
+void applepic_device::int_mask_w(u8 data)
+{
+ for (int which = 1; which <= 5; which++)
+ if (BIT(m_int_mask, which) != BIT(data, which))
+ LOG("%s: %sabling %s interrupt\n", machine().describe_context(), BIT(data, which) ? "En" : "Dis", s_interrupt_names[which]);
+
+ m_int_mask = data & 0x3e;
+ m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, (m_int_mask & m_int_reg) != 0 ? ASSERT_LINE : CLEAR_LINE);
+}
+
+u8 applepic_device::int_reg_r()
+{
+ return m_int_reg;
+}
+
+void applepic_device::int_reg_w(u8 data)
+{
+ if ((m_int_reg & data) != 0)
+ {
+ m_int_reg &= ~data;
+ if ((m_int_mask & m_int_reg) == 0)
+ {
+ LOG("%s: 6502 interrupts acknowledged\n", machine().describe_context());
+ m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, CLEAR_LINE);
+ }
+ }
+}
+
+void applepic_device::set_interrupt(int which)
+{
+ if (!BIT(m_int_reg, which))
+ {
+ LOG("%s: Setting %s interrupt\n", machine().describe_context(), s_interrupt_names[which]);
+ m_int_reg |= (1 << which);
+ if ((m_int_reg & m_int_mask) == (1 << which))
+ m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, ASSERT_LINE);
+ }
+}
+
+void applepic_device::reset_interrupt(int which)
+{
+ if (BIT(m_int_reg, which))
+ {
+ LOG("%s: Resetting %s interrupt\n", machine().describe_context(), s_interrupt_names[which]);
+ if ((m_int_reg & m_int_mask) == (1 << which))
+ m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, CLEAR_LINE);
+ m_int_reg &= ~(1 << which);
+ }
+}
+
+u8 applepic_device::host_reg_r()
+{
+ return (m_status_reg & 0x30) >> 2;
+}
+
+void applepic_device::host_reg_w(u8 data)
+{
+ LOG("%s: INTHST0 %srequested, INTHST1 %srequested\n", machine().describe_context(), BIT(data, 2) ? "" : "not ", BIT(data, 3) ? "" : "not ");
+ m_status_reg |= (data & 0x0c) << 2;
+ if ((data & 0x0c) != 0)
+ m_hint_callback(ASSERT_LINE);
+}
+
+u8 applepic_device::device_reg_r(offs_t offset)
+{
+ if (BIT(m_scc_control, 0))
+ {
+ if (!machine().side_effects_disabled())
+ logerror("%s: Read from device register $%X in bypass mode\n", machine().describe_context(), offset & 0x0f);
+ return 0;
+ }
+ else
+ return m_prd_callback(offset & 0x0f);
+}
+
+void applepic_device::device_reg_w(offs_t offset, u8 data)
+{
+ if (BIT(m_scc_control, 0))
+ logerror("%s: Read from device register $%X in bypass mode\n", machine().describe_context(), offset & 0x0f);
+ else
+ m_pwr_callback(offset & 0x0f, data);
+}
diff --git a/src/devices/machine/applepic.h b/src/devices/machine/applepic.h
new file mode 100644
index 00000000000..37956492d76
--- /dev/null
+++ b/src/devices/machine/applepic.h
@@ -0,0 +1,108 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+
+#ifndef MAME_DEVICES_MACHINE_APPLEPIC_H
+#define MAME_DEVICES_MACHINE_APPLEPIC_H
+
+#pragma once
+
+#include "cpu/m6502/r65c02.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> applepic_device
+
+class applepic_device : public device_t
+{
+public:
+ // construction/destruction
+ applepic_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // callback configuration
+ auto prd_callback() { return m_prd_callback.bind(); }
+ auto pwr_callback() { return m_pwr_callback.bind(); }
+ auto hint_callback() { return m_hint_callback.bind(); }
+ auto gpin_callback() { return m_gpin_callback.bind(); }
+ auto gpout0_callback() { return m_gpout_callback[0].bind(); }
+ auto gpout1_callback() { return m_gpout_callback[1].bind(); }
+
+ // host interface
+ u8 host_r(offs_t offset);
+ void host_w(offs_t offset, u8 data);
+
+ // peripheral device requests
+ void pint_w(int state);
+ void reqa_w(int state);
+ void reqb_w(int state);
+
+protected:
+ // device_t implementation
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ static const std::string_view s_interrupt_names[8];
+
+ struct dma_channel
+ {
+ u8 control;
+ u16 map;
+ u16 tc;
+ };
+
+ u8 timer_r(offs_t offset);
+ void timer_w(offs_t offset, u8 data);
+ u16 get_timer_count() const;
+ TIMER_CALLBACK_MEMBER(timer1_callback);
+ u8 dma_channel_r(offs_t offset);
+ void dma_channel_w(offs_t offset, u8 data);
+ u8 scc_control_r();
+ void scc_control_w(u8 data);
+ u8 io_control_r();
+ void io_control_w(u8 data);
+ u8 timer_dpll_control_r();
+ void timer_dpll_control_w(u8 data);
+ u8 int_mask_r();
+ void int_mask_w(u8 data);
+ u8 int_reg_r();
+ void int_reg_w(u8 data);
+ void set_interrupt(int which);
+ void reset_interrupt(int which);
+ u8 host_reg_r();
+ void host_reg_w(u8 data);
+ u8 device_reg_r(offs_t offset);
+ void device_reg_w(offs_t offset, u8 data);
+
+ void internal_map(address_map &map);
+
+ // internal CPU
+ required_device<r65c02_device> m_iopcpu;
+
+ // callbacks for peripheral and host
+ devcb_read8 m_prd_callback;
+ devcb_write8 m_pwr_callback;
+ devcb_write_line m_hint_callback;
+ devcb_read8 m_gpin_callback;
+ devcb_write_line::array<2> m_gpout_callback;
+
+ // internal state
+ emu_timer *m_timer1;
+ attotime m_timer_last_expired;
+ u16 m_ram_address;
+ u8 m_status_reg;
+ u16 m_timer_latch;
+ dma_channel m_dma_channel[2];
+ u8 m_scc_control;
+ u8 m_io_control;
+ u8 m_timer_dpll_control;
+ u8 m_int_mask;
+ u8 m_int_reg;
+};
+
+// device type declaration
+DECLARE_DEVICE_TYPE(APPLEPIC, applepic_device)
+
+#endif // MAME_DEVICES_MACHINE_APPLEPIC_H
diff --git a/src/devices/machine/archimedes_keyb.cpp b/src/devices/machine/archimedes_keyb.cpp
new file mode 100644
index 00000000000..abd2778082b
--- /dev/null
+++ b/src/devices/machine/archimedes_keyb.cpp
@@ -0,0 +1,414 @@
+// license:LGPL-2.1+
+// copyright-holders:Angelo Salese, Sandro Ronco
+/**********************************************************************
+
+ Acorn Archimedes keyboard (A5000)
+
+ Keyboard variants:
+ A500 (external) 6500/11 MCU w/ 2732 ROM (dumped), see A500 Hardware Guide.
+ A3x0 (external) 8031 MCU w/ 2764 ROM (dumped), not documented.
+ A4x0 (external) 8031 MCU w/ 2764 ROM (dumped), same as A3x0.
+ A680 (external) unknown.
+ A3000 (internal) 8051 MCU (part 0280,022) w/ internal ROM (dumped), see A3000TRM.
+ A540 (external) 8051 MCU (part 0280,022) w/ internal ROM, see A500/R200TRM, same as A3000.
+ A5000 (external) 8051 MCU (part 0280,022) w/ internal ROM, see A5000TRM, same as A3000.
+ A4 (internal) 8051 MCU (part 0290,031) w/ internal ROM, see A4TRM. Supports PS/2 keyboard.
+ A30x0 (internal) 8051 MCU (part 0294,031) w/ internal ROM, see A3010TRM.
+ A4000 (external) likely same as A30x0, but not confirmed.
+
+ TODO:
+ - convert to slot device and move to bus/archimedes/keyboard.
+ - add other variants.
+
+*********************************************************************/
+
+#include "emu.h"
+#include "archimedes_keyb.h"
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+DEFINE_DEVICE_TYPE(ARCHIMEDES_KEYBOARD, archimedes_keyboard_device, "archimedes_keyboard", "Acorn Archimedes Keyboard")
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( archimedes_keyboard )
+ PORT_START("ROW.0")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK))
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(PGUP))
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PAUSE) PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) PORT_NAME("Break")
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK))
+ PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_OTHER) // Keyboard ID bit 4
+ PORT_BIT(0xfe00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.1")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_OTHER) // Keyboard ID bit 5
+ PORT_BIT(0xfe00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.2")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.3")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.4")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.5")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.6")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("Return")
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.7")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.8")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD))
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('#')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) PORT_NAME("Copy")
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGDN) PORT_CHAR(UCHAR_MAMEKEY(PGDN))
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_OTHER) // Keyboard ID bit 0
+ PORT_BIT(0xfe00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.9")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR('*')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR(0xa3) PORT_CHAR(0xa4)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE)) PORT_NAME("Back Space")
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
+ PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_OTHER) // Keyboard ID bit 1
+ PORT_BIT(0xfe00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.10")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.11")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR('/')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11))
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12))
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.12")
+ PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT(0xff00, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.13")
+ PORT_BIT(0x00ff, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT))
+ PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
+ PORT_BIT(0x0400, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT(0x0800, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT(0x1000, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PRTSCR) PORT_CHAR(UCHAR_MAMEKEY(PRTSCR)) PORT_NAME("Print")
+ PORT_BIT(0x2000, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT))
+ PORT_BIT(0x4000, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL))
+ PORT_BIT(0x8000, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT))
+
+ PORT_START("ROW.14")
+ PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_OTHER) // Keyboard ID bit 2
+ PORT_BIT(0xfeff, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW.15")
+ PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_OTHER) // Keyboard ID bit 3
+ PORT_BIT(0xfeff, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("MOUSE.0")
+ PORT_BIT(0xffff, IP_ACTIVE_HIGH, IPT_MOUSE_X) PORT_SENSITIVITY(100)
+
+ PORT_START("MOUSE.1")
+ PORT_BIT(0xffff, IP_ACTIVE_HIGH, IPT_MOUSE_Y) PORT_SENSITIVITY(100)
+
+ PORT_START("MOUSE.2")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Mouse Left")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(MOUSECODE_BUTTON3) PORT_NAME("Mouse Center")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Mouse Right")
+INPUT_PORTS_END
+
+
+ioport_constructor archimedes_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( archimedes_keyboard );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// archimedes_keyboard_device - constructor
+//-------------------------------------------------
+
+archimedes_keyboard_device::archimedes_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ARCHIMEDES_KEYBOARD, tag, owner, clock)
+ , m_mcu(*this, "mcu")
+ , m_kout(*this)
+ , m_keyboard(*this, "ROW.%u", 0U)
+ , m_mouse(*this, "MOUSE.%u", 0U)
+ , m_leds(*this, "keyb_led.%u", 0U)
+{
+}
+
+
+void archimedes_keyboard_device::device_resolve_objects()
+{
+ m_leds.resolve();
+}
+
+void archimedes_keyboard_device::device_start()
+{
+ m_mouse_timer = timer_alloc(FUNC(archimedes_keyboard_device::update_mouse), this);
+
+ save_item(NAME(m_mouse_x));
+ save_item(NAME(m_mouse_y));
+ save_item(NAME(m_mouse_xphase));
+ save_item(NAME(m_mouse_yphase));
+ save_item(NAME(m_mouse_xref));
+ save_item(NAME(m_mouse_xdir));
+ save_item(NAME(m_mouse_yref));
+ save_item(NAME(m_mouse_ydir));
+ save_item(NAME(m_mux));
+ save_item(NAME(m_kin));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void archimedes_keyboard_device::device_reset()
+{
+ m_mouse_x = 0;
+ m_mouse_y = 0;
+ m_mouse_xphase = 1;
+ m_mouse_xref = 1;
+ m_mouse_xdir = 1;
+ m_mouse_yphase = 1;
+ m_mouse_yref = 1;
+ m_mouse_ydir = 1;
+ m_mux = 0;
+ m_kin = false;
+
+ m_mouse_timer->adjust(attotime::from_hz(1000 * 4), 0, attotime::from_hz(1000 * 4));
+}
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void archimedes_keyboard_device::device_add_mconfig(machine_config &config)
+{
+ I8051(config, m_mcu, 12_MHz_XTAL); // Philips 8051AH-2
+ m_mcu->port_in_cb<0>().set([this]() { return m_keyboard[m_mux]->read() & 0xff; });
+ m_mcu->port_in_cb<1>().set([this]() { return (m_keyboard[m_mux]->read() >> 8) & 0xff; });
+ m_mcu->port_in_cb<2>().set(FUNC(archimedes_keyboard_device::mouse_r));
+ m_mcu->port_in_cb<3>().set([this]() { return (m_mouse[2]->read() & 0xfe) | m_kin; });
+ m_mcu->port_out_cb<2>().set([this](uint8_t data) { m_mux = data & 0x0f; });
+ m_mcu->port_out_cb<3>().set(FUNC(archimedes_keyboard_device::leds_w));
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( archimedes_keyboard )
+ ROM_REGION( 0x1000, "mcu", 0 )
+ ROM_LOAD("acorn_0280,022-01_philips_8051ah-2.bin", 0x0000, 0x1000, CRC(95095d38) SHA1(b9fd0000d77987f76fd48348fe2c6988818f40cb))
+ROM_END
+
+
+const tiny_rom_entry *archimedes_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( archimedes_keyboard );
+}
+
+TIMER_CALLBACK_MEMBER(archimedes_keyboard_device::update_mouse)
+{
+ // Mouse quadrature signals
+ // Increase Decrease
+ // REF DIR REF DIR
+ // 1 1 1 1
+ // 1 0 0 1
+ // 0 0 0 0
+ // 0 1 1 0
+
+ int16_t x = m_mouse[0]->read();
+ int16_t y = m_mouse[1]->read();
+
+ int16_t dx = x - m_mouse_x;
+ int16_t dy = y - m_mouse_y;
+
+ if (dx)
+ {
+ // Set the output pins according to the current phase
+ switch (m_mouse_xphase)
+ {
+ case 0:
+ m_mouse_xref = 1;
+ break;
+ case 1:
+ m_mouse_xdir = 1;
+ break;
+ case 2:
+ m_mouse_xref = 0;
+ break;
+ case 3:
+ m_mouse_xdir = 0;
+ break;
+ }
+
+ // Change phase
+ if (dx > 0)
+ m_mouse_xphase--;
+ else
+ m_mouse_xphase++;
+
+ // Range check the phase
+ m_mouse_xphase &= 3;
+ }
+
+ if (dy)
+ {
+ // Set the output pins according to the current phase
+ switch (m_mouse_yphase)
+ {
+ case 3:
+ m_mouse_yref = 0;
+ break;
+ case 2:
+ m_mouse_ydir = 0;
+ break;
+ case 1:
+ m_mouse_yref = 1;
+ break;
+ case 0:
+ m_mouse_ydir = 1;
+ break;
+ }
+
+ // Change phase
+ if (dy > 0)
+ m_mouse_yphase--;
+ else
+ m_mouse_yphase++;
+
+ // Range check the phase
+ m_mouse_yphase &= 3;
+ }
+
+ m_mouse_x = x;
+ m_mouse_y = y;
+}
+
+void archimedes_keyboard_device::leds_w(uint8_t data)
+{
+ // Keyboard LEDs
+ // --- --x- TXD
+ // --- -x-- Caps Lock
+ // --- x--- Scroll Lock
+ // --x ---- Num Lock
+
+ m_kout(BIT(data, 1));
+ for (int i = 0; i < 3; i++)
+ m_leds[i] = BIT(data, 2 + i);
+}
+
+uint8_t archimedes_keyboard_device::mouse_r()
+{
+ return (m_mouse_xref << 4) | (m_mouse_xdir << 5) | (m_mouse_yref << 6) | (m_mouse_ydir << 7);
+}
+
+void archimedes_keyboard_device::kin_w(int state)
+{
+ m_kin = state;
+}
diff --git a/src/devices/machine/archimedes_keyb.h b/src/devices/machine/archimedes_keyb.h
new file mode 100644
index 00000000000..82311124581
--- /dev/null
+++ b/src/devices/machine/archimedes_keyb.h
@@ -0,0 +1,73 @@
+// license:LGPL-2.1+
+// copyright-holders:Angelo Salese, Sandro Ronco
+/**********************************************************************
+
+ Acorn Archimedes keyboard
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_ARCHIMEDES_KEYB_H
+#define MAME_MACHINE_ARCHIMEDES_KEYB_H
+
+#pragma once
+
+#include "cpu/mcs51/mcs51.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> archimedes_keyboard_device
+
+class archimedes_keyboard_device : public device_t
+{
+public:
+ // construction/destruction
+ archimedes_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ auto kout() { return m_kout.bind(); }
+
+ void kin_w(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_resolve_objects() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // optional information overrides
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+
+ TIMER_CALLBACK_MEMBER(update_mouse);
+
+private:
+ uint8_t mouse_r();
+ void leds_w(uint8_t data);
+
+ required_device<mcs51_cpu_device> m_mcu;
+ devcb_write_line m_kout;
+ required_ioport_array<16> m_keyboard;
+ required_ioport_array<3> m_mouse;
+ output_finder<3> m_leds;
+
+ emu_timer *m_mouse_timer;
+ uint8_t m_mouse_xphase;
+ uint8_t m_mouse_xdir;
+ uint8_t m_mouse_xref;
+ uint8_t m_mouse_yphase;
+ uint8_t m_mouse_ydir;
+ uint8_t m_mouse_yref;
+ int16_t m_mouse_x;
+ int16_t m_mouse_y;
+ uint8_t m_mux;
+ bool m_kin;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(ARCHIMEDES_KEYBOARD, archimedes_keyboard_device)
+
+
+#endif // MAME_MACHINE_ARCHIMEDES_KEYB_H
diff --git a/src/devices/machine/arm_iomd.cpp b/src/devices/machine/arm_iomd.cpp
index d6ce9557716..39b41162734 100644
--- a/src/devices/machine/arm_iomd.cpp
+++ b/src/devices/machine/arm_iomd.cpp
@@ -141,10 +141,19 @@ arm_iomd_device::arm_iomd_device(const machine_config &mconfig, device_type type
, m_host_cpu(*this, finder_base::DUMMY_TAG)
, m_vidc(*this, finder_base::DUMMY_TAG)
, m_kbdc(*this, finder_base::DUMMY_TAG)
- , m_iocr_read_od_cb(*this)
+ , m_iocr_read_od_cb(*this, 1)
, m_iocr_write_od_cb(*this)
- , m_iocr_read_id_cb(*this)
+ , m_iocr_read_id_cb(*this, 1)
, m_iocr_write_id_cb(*this)
+ , m_sndcur(0)
+ , m_sndend(0)
+ , m_sndcur_reg{ 0, 0 }
+ , m_sndend_reg{ 0, 0 }
+ , m_sndstop_reg{ false, false }
+ , m_sndlast_reg{ false, false }
+ , m_sndbuffer_ok{ false, false }
+ , m_sound_dma_on(false)
+ , m_sndcur_buffer(0)
{
}
@@ -197,7 +206,7 @@ void arm7500fe_iomd_device::map(address_map &map)
arm7500fe_iomd_device::arm7500fe_iomd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: arm_iomd_device(mconfig, ARM7500FE_IOMD, tag, owner, clock)
- , m_iolines_read_cb(*this)
+ , m_iolines_read_cb(*this, 0xff)
, m_iolines_write_cb(*this)
{
m_id = 0xaa7c;
@@ -230,11 +239,6 @@ void arm7500fe_iomd_device::device_add_mconfig(machine_config &config)
void arm_iomd_device::device_start()
{
- m_iocr_read_od_cb.resolve_all_safe(1);
- m_iocr_write_od_cb.resolve_all_safe();
- m_iocr_read_id_cb.resolve_safe(1);
- m_iocr_write_id_cb.resolve_safe();
-
save_item(NAME(m_iocr_ddr));
save_item(NAME(m_video_enable));
save_item(NAME(m_vidinita));
@@ -243,30 +247,28 @@ void arm_iomd_device::device_start()
save_item(NAME(m_videqual));
save_item(NAME(m_cursor_enable));
save_item(NAME(m_cursinit));
- save_pointer(NAME(m_irq_mask), IRQ_SOURCES_SIZE);
- save_pointer(NAME(m_irq_status), IRQ_SOURCES_SIZE);
+ save_pointer(NAME(m_irq_mask), std::size(m_irq_mask));
+ save_pointer(NAME(m_irq_status), std::size(m_irq_status));
m_host_space = &m_host_cpu->space(AS_PROGRAM);
- m_timer[0] = timer_alloc(T0_TIMER);
- m_timer[1] = timer_alloc(T1_TIMER);
- save_pointer(NAME(m_timer_in), timer_ch_size);
- save_pointer(NAME(m_timer_out), timer_ch_size);
- save_pointer(NAME(m_timer_counter), timer_ch_size);
- save_pointer(NAME(m_timer_readinc), timer_ch_size);
+ m_timer[0] = timer_alloc(FUNC(arm_iomd_device::timer_elapsed), this);
+ m_timer[1] = timer_alloc(FUNC(arm_iomd_device::timer_elapsed), this);
+ save_pointer(NAME(m_timer_in), std::size(m_timer_in));
+ save_pointer(NAME(m_timer_out), std::size(m_timer_out));
+ save_pointer(NAME(m_timer_counter), std::size(m_timer_counter));
+ save_pointer(NAME(m_timer_readinc), std::size(m_timer_readinc));
save_item(NAME(m_sndcur));
save_item(NAME(m_sndend));
save_item(NAME(m_sound_dma_on));
save_item(NAME(m_sndcur_buffer));
- save_item(NAME(m_snd_overrun));
- save_item(NAME(m_snd_int));
- save_pointer(NAME(m_sndcur_reg), sounddma_ch_size);
- save_pointer(NAME(m_sndend_reg), sounddma_ch_size);
- save_pointer(NAME(m_sndstop_reg), sounddma_ch_size);
- save_pointer(NAME(m_sndlast_reg), sounddma_ch_size);
- save_pointer(NAME(m_sndbuffer_ok), sounddma_ch_size);
+ save_pointer(NAME(m_sndcur_reg), std::size(m_sndcur_reg));
+ save_pointer(NAME(m_sndend_reg), std::size(m_sndend_reg));
+ save_pointer(NAME(m_sndstop_reg), std::size(m_sndstop_reg));
+ save_pointer(NAME(m_sndlast_reg), std::size(m_sndlast_reg));
+ save_pointer(NAME(m_sndbuffer_ok), std::size(m_sndbuffer_ok));
// TODO: jumps to EASI space at $0c0016xx for RiscPC if POR is on?
}
@@ -275,8 +277,6 @@ void arm7500fe_iomd_device::device_start()
{
arm_iomd_device::device_start();
- m_iolines_read_cb.resolve_safe(0xff);
- m_iolines_write_cb.resolve_safe();
save_item(NAME(m_iolines_ddr));
save_item(NAME(m_cpuclk_divider));
@@ -290,28 +290,27 @@ void arm7500fe_iomd_device::device_start()
void arm_iomd_device::device_reset()
{
- int i;
m_iocr_ddr = 0x0b;
m_video_enable = false;
// TODO: defaults for these
m_vidinita = 0;
m_vidend = 0;
- for (i=0; i<IRQ_SOURCES_SIZE; i++)
- {
- m_irq_status[i] = 0;
- m_irq_mask[i] = 0;
- }
+ std::fill_n(m_irq_status, std::size(m_irq_status), 0);
+ std::fill_n(m_irq_mask, std::size(m_irq_mask), 0);
- for (i=0; i<timer_ch_size; i++)
+ for (int i = 0; i < std::size(m_timer); i++)
m_timer[i]->adjust(attotime::never);
+ m_sndcur = 0;
+ m_sndend = 0;
+ std::fill_n(m_sndcur_reg, std::size(m_sndcur_reg), 0);
+ std::fill_n(m_sndend_reg, std::size(m_sndend_reg), 0);
+ std::fill_n(m_sndstop_reg, std::size(m_sndstop_reg), false);
+ std::fill_n(m_sndlast_reg, std::size(m_sndlast_reg), false);
+ std::fill_n(m_sndbuffer_ok, std::size(m_sndbuffer_ok), false);
m_sound_dma_on = false;
- for (i=0; i<sounddma_ch_size; i++)
- {
- m_sndbuffer_ok[i] = false;
- m_sndcur_reg[i] = 0;
- }
+ m_sndcur_buffer = 0;
// ...
}
@@ -326,15 +325,9 @@ void arm7500fe_iomd_device::device_reset()
m_iolines_ddr = 0xff;
}
-void arm_iomd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(arm_iomd_device::timer_elapsed)
{
- switch(id)
- {
- case T0_TIMER:
- case T1_TIMER:
- trigger_irq<IRQA>(id == T1_TIMER ? 0x40 : 0x20);
- break;
- }
+ trigger_irq<IRQA>((uint8_t)param);
}
//**************************************************************************
@@ -502,7 +495,7 @@ inline void arm_iomd_device::trigger_timer(unsigned Which)
if(val==0)
m_timer[Which]->adjust(attotime::never);
else
- m_timer[Which]->adjust(attotime::from_usec(val), 0, attotime::from_usec(val));
+ m_timer[Which]->adjust(attotime::from_usec(val), Which ? 0x40 : 0x20, attotime::from_usec(val));
}
// TODO: live updates aren't really supported here
@@ -555,8 +548,6 @@ u32 arm_iomd_device::version_r()
return m_version;
}
-u32 version_r();
-
// sound DMA
template <unsigned Which> u32 arm_iomd_device::sdcur_r() { return m_sndcur_reg[Which]; }
@@ -572,6 +563,7 @@ template <unsigned Which> void arm_iomd_device::sdend_w(offs_t offset, u32 data,
m_sndend_reg[Which] &= 0x00fffff0;
m_sndstop_reg[Which] = BIT(data, 31);
m_sndlast_reg[Which] = BIT(data, 30);
+ m_sndbuffer_ok[Which] = true;
}
u32 arm_iomd_device::sdcr_r()
@@ -594,12 +586,19 @@ void arm_iomd_device::sdcr_w(u32 data)
// ...
}
- // TODO: bit 7 resets sound DMA
+ // TODO: sound DMA reset
+ // eats samples in ppcar
+// if (BIT(data, 7))
+// m_sndbuffer_ok[0] = m_sndbuffer_ok[1] = false;
}
u32 arm_iomd_device::sdst_r()
{
- return (m_snd_overrun << 2) | (m_snd_int << 1) | m_sndcur_buffer;
+ // TODO: confirm implementation
+ bool sound_overrun = m_sndbuffer_ok[0] == false && m_sndbuffer_ok[1] == false;
+ bool sound_int = m_sndbuffer_ok[0] == false || m_sndbuffer_ok[1] == false;
+
+ return (sound_overrun << 2) | (sound_int << 1) | m_sndcur_buffer;
}
// video DMA
@@ -665,7 +664,7 @@ void arm_iomd_device::vidinita_w(offs_t offset, u32 data, u32 mem_mask)
// IRQ/DRQ/Reset signals
//**************************************************************************
-WRITE_LINE_MEMBER( arm_iomd_device::vblank_irq )
+void arm_iomd_device::vblank_irq(int state)
{
if (!state)
return;
@@ -706,35 +705,31 @@ inline void arm_iomd_device::sounddma_swap_buffer()
{
m_sndcur = m_sndcur_reg[m_sndcur_buffer];
m_sndend = m_sndcur + (m_sndend_reg[m_sndcur_buffer] + 0x10);
- m_sndbuffer_ok[m_sndcur_buffer] = true;
-
- // TODO: actual condition for int
- m_snd_overrun = false;
- m_snd_int = false;
+// m_sndbuffer_ok[m_sndcur_buffer] = true;
}
-WRITE_LINE_MEMBER( arm_iomd_device::sound_drq )
+void arm_iomd_device::sound_drq(int state)
{
if (!state)
return;
if (m_vidc->get_dac_mode() == true)
{
- for (int ch=0;ch<2;ch++)
+ if (!m_sndbuffer_ok[m_sndcur_buffer])
+ return;
+
+ for (int ch = 0; ch < 2; ch++)
m_vidc->write_dac32(ch, (m_host_space->read_word(m_sndcur + ch*2)));
m_sndcur += 4;
if (m_sndcur >= m_sndend)
{
- // TODO: interrupt bit
-
m_vidc->update_sound_mode(m_sound_dma_on);
if (m_sound_dma_on)
{
m_sndbuffer_ok[m_sndcur_buffer] = false;
m_sndcur_buffer ^= 1;
- m_snd_overrun = (m_sndbuffer_ok[m_sndcur_buffer] == false);
sounddma_swap_buffer();
}
else
@@ -749,7 +744,7 @@ WRITE_LINE_MEMBER( arm_iomd_device::sound_drq )
}
}
-WRITE_LINE_MEMBER( arm_iomd_device::keyboard_irq )
+void arm_iomd_device::keyboard_irq(int state)
{
printf("IRQ %d\n",state);
if (!state)
@@ -758,7 +753,7 @@ WRITE_LINE_MEMBER( arm_iomd_device::keyboard_irq )
trigger_irq<IRQB>(0x80);
}
-WRITE_LINE_MEMBER( arm_iomd_device::keyboard_reset )
+void arm_iomd_device::keyboard_reset(int state)
{
printf("RST %d\n",state);
}
diff --git a/src/devices/machine/arm_iomd.h b/src/devices/machine/arm_iomd.h
index 482c06b8cbc..a6e371cfd6e 100644
--- a/src/devices/machine/arm_iomd.h
+++ b/src/devices/machine/arm_iomd.h
@@ -42,13 +42,13 @@ public:
auto iocr_read_id() { return m_iocr_read_id_cb.bind(); }
auto iocr_write_id() { return m_iocr_write_id_cb.bind(); }
// IRQA
- DECLARE_WRITE_LINE_MEMBER( vblank_irq );
+ void vblank_irq(int state);
// IRQB
- DECLARE_WRITE_LINE_MEMBER( keyboard_irq );
+ void keyboard_irq(int state);
// DRQs
- DECLARE_WRITE_LINE_MEMBER( sound_drq );
+ void sound_drq(int state);
// Reset
- DECLARE_WRITE_LINE_MEMBER( keyboard_reset );
+ void keyboard_reset(int state);
// I/O operations
virtual void map(address_map &map);
@@ -62,7 +62,8 @@ protected:
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(timer_elapsed);
void base_map(address_map &map);
u16 m_id;
@@ -117,14 +118,15 @@ private:
u32 cursinit_r();
void cursinit_w(offs_t offset, u32 data, u32 mem_mask = ~0);
- static constexpr int sounddma_ch_size = 2;
- u32 m_sndcur, m_sndend;
- u32 m_sndcur_reg[sounddma_ch_size], m_sndend_reg[sounddma_ch_size];
- bool m_sndstop_reg[sounddma_ch_size], m_sndlast_reg[sounddma_ch_size];
- bool m_sndbuffer_ok[sounddma_ch_size];
+ u32 m_sndcur;
+ u32 m_sndend;
+ u32 m_sndcur_reg[2];
+ u32 m_sndend_reg[2];
+ bool m_sndstop_reg[2];
+ bool m_sndlast_reg[2];
+ bool m_sndbuffer_ok[2];
bool m_sound_dma_on;
u8 m_sndcur_buffer;
- bool m_snd_overrun, m_snd_int;
inline void sounddma_swap_buffer();
template <unsigned Which> u32 sdcur_r();
template <unsigned Which> void sdcur_w(offs_t offset, u32 data, u32 mem_mask = ~0);
@@ -139,11 +141,6 @@ private:
inline void flush_irq(unsigned Which);
template <unsigned Which> inline void trigger_irq(u8 irq_type);
- static constexpr int timer_ch_size = 2;
- enum {
- T0_TIMER = 1,
- T1_TIMER
- };
inline void trigger_timer(unsigned Which);
u16 m_timer_in[2];
u16 m_timer_out[2];
diff --git a/src/devices/machine/at.cpp b/src/devices/machine/at.cpp
new file mode 100644
index 00000000000..e77c72af599
--- /dev/null
+++ b/src/devices/machine/at.cpp
@@ -0,0 +1,426 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol, Miodrag Milanovic, Carl
+/***************************************************************************
+
+ IBM AT Compatibles
+
+***************************************************************************/
+
+#include "emu.h"
+#include "at.h"
+
+#include "cpu/i86/i286.h"
+#include "cpu/i386/i386.h"
+
+#include "softlist_dev.h"
+#include "speaker.h"
+
+#define LOG_PORT80 (1U << 1)
+#define VERBOSE (0)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(AT_MB, at_mb_device, "at_mb", "PC/AT Motherboard")
+
+at_mb_device::at_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, AT_MB, tag, owner, clock),
+ m_maincpu(*this, ":maincpu"),
+ m_isabus(*this, "isabus"),
+ m_pic8259_slave(*this, "pic8259_slave"),
+ m_dma8237_1(*this, "dma8237_1"),
+ m_dma8237_2(*this, "dma8237_2"),
+ m_pit8254(*this, "pit8254"),
+ m_speaker(*this, "speaker"),
+ m_mc146818(*this, "rtc"),
+ m_keybc(*this, "keybc")
+{
+}
+
+void at_mb_device::device_reset()
+{
+ m_at_spkrdata = 0;
+ m_pit_out2 = 1;
+ m_dma_channel = -1;
+ m_cur_eop = false;
+}
+
+void at_mb_device::device_start()
+{
+ // FIXME: this is gross and should be done in machine configuration
+ if(!strncmp(m_maincpu->shortname(), "i80286", 6))
+ downcast<i80286_cpu_device *>(m_maincpu.target())->set_a20_callback(*this, FUNC(at_mb_device::a20_286));
+}
+
+void at_mb_device::at_softlists(machine_config &config)
+{
+ /* software lists */
+ SOFTWARE_LIST(config, "pc_disk_list").set_original("ibm5150");
+ SOFTWARE_LIST(config, "at_disk_list").set_original("ibm5170");
+ SOFTWARE_LIST(config, "at_cdrom_list").set_original("ibm5170_cdrom");
+ SOFTWARE_LIST(config, "at_hdd_list").set_original("ibm5170_hdd");
+ SOFTWARE_LIST(config, "midi_disk_list").set_compatible("midi_flop");
+}
+
+void at_mb_device::device_add_mconfig(machine_config &config)
+{
+ PIT8254(config, m_pit8254);
+ m_pit8254->set_clk<0>(4772720/4); /* heartbeat IRQ */
+ m_pit8254->out_handler<0>().set("pic8259_master", FUNC(pic8259_device::ir0_w));
+ m_pit8254->set_clk<1>(4772720/4); /* dram refresh */
+ m_pit8254->set_clk<2>(4772720/4); /* pio port c pin 4, and speaker polling enough */
+ m_pit8254->out_handler<2>().set(FUNC(at_mb_device::pit8254_out2_changed));
+
+ AM9517A(config, m_dma8237_1, 14.318181_MHz_XTAL / 3);
+ m_dma8237_1->out_hreq_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq0_w));
+ m_dma8237_1->out_eop_callback().set(FUNC(at_mb_device::dma8237_out_eop));
+ m_dma8237_1->in_memr_callback().set(FUNC(at_mb_device::dma_read_byte));
+ m_dma8237_1->out_memw_callback().set(FUNC(at_mb_device::dma_write_byte));
+ m_dma8237_1->in_ior_callback<0>().set(FUNC(at_mb_device::dma8237_0_dack_r));
+ m_dma8237_1->in_ior_callback<1>().set(FUNC(at_mb_device::dma8237_1_dack_r));
+ m_dma8237_1->in_ior_callback<2>().set(FUNC(at_mb_device::dma8237_2_dack_r));
+ m_dma8237_1->in_ior_callback<3>().set(FUNC(at_mb_device::dma8237_3_dack_r));
+ m_dma8237_1->out_iow_callback<0>().set(FUNC(at_mb_device::dma8237_0_dack_w));
+ m_dma8237_1->out_iow_callback<1>().set(FUNC(at_mb_device::dma8237_1_dack_w));
+ m_dma8237_1->out_iow_callback<2>().set(FUNC(at_mb_device::dma8237_2_dack_w));
+ m_dma8237_1->out_iow_callback<3>().set(FUNC(at_mb_device::dma8237_3_dack_w));
+ m_dma8237_1->out_dack_callback<0>().set(FUNC(at_mb_device::dack0_w));
+ m_dma8237_1->out_dack_callback<1>().set(FUNC(at_mb_device::dack1_w));
+ m_dma8237_1->out_dack_callback<2>().set(FUNC(at_mb_device::dack2_w));
+ m_dma8237_1->out_dack_callback<3>().set(FUNC(at_mb_device::dack3_w));
+
+ AM9517A(config, m_dma8237_2, 14.318181_MHz_XTAL / 3);
+ m_dma8237_2->out_hreq_callback().set(FUNC(at_mb_device::dma_hrq_changed));
+ m_dma8237_2->out_eop_callback().set(FUNC(at_mb_device::dma8237_2_out_eop));
+ m_dma8237_2->in_memr_callback().set(FUNC(at_mb_device::dma_read_word));
+ m_dma8237_2->out_memw_callback().set(FUNC(at_mb_device::dma_write_word));
+ m_dma8237_2->in_ior_callback<1>().set(FUNC(at_mb_device::dma8237_5_dack_r));
+ m_dma8237_2->in_ior_callback<2>().set(FUNC(at_mb_device::dma8237_6_dack_r));
+ m_dma8237_2->in_ior_callback<3>().set(FUNC(at_mb_device::dma8237_7_dack_r));
+ m_dma8237_2->out_iow_callback<1>().set(FUNC(at_mb_device::dma8237_5_dack_w));
+ m_dma8237_2->out_iow_callback<2>().set(FUNC(at_mb_device::dma8237_6_dack_w));
+ m_dma8237_2->out_iow_callback<3>().set(FUNC(at_mb_device::dma8237_7_dack_w));
+ m_dma8237_2->out_dack_callback<0>().set(FUNC(at_mb_device::dack4_w));
+ m_dma8237_2->out_dack_callback<1>().set(FUNC(at_mb_device::dack5_w));
+ m_dma8237_2->out_dack_callback<2>().set(FUNC(at_mb_device::dack6_w));
+ m_dma8237_2->out_dack_callback<3>().set(FUNC(at_mb_device::dack7_w));
+
+ pic8259_device &pic8259_master(PIC8259(config, "pic8259_master"));
+ pic8259_master.out_int_callback().set_inputline(":maincpu", 0);
+ pic8259_master.in_sp_callback().set_constant(1);
+ pic8259_master.read_slave_ack_callback().set(FUNC(at_mb_device::get_slave_ack));
+
+ PIC8259(config, m_pic8259_slave);
+ m_pic8259_slave->out_int_callback().set("pic8259_master", FUNC(pic8259_device::ir2_w));
+ m_pic8259_slave->in_sp_callback().set_constant(0);
+
+ ISA16(config, m_isabus, 0);
+ m_isabus->set_memspace(":maincpu", AS_PROGRAM);
+ m_isabus->set_iospace(":maincpu", AS_IO);
+ m_isabus->irq2_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir1_w)); // in place of irq 2 on at irq 9 is used
+ m_isabus->irq3_callback().set("pic8259_master", FUNC(pic8259_device::ir3_w));
+ m_isabus->irq4_callback().set("pic8259_master", FUNC(pic8259_device::ir4_w));
+ m_isabus->irq5_callback().set("pic8259_master", FUNC(pic8259_device::ir5_w));
+ m_isabus->irq6_callback().set("pic8259_master", FUNC(pic8259_device::ir6_w));
+ m_isabus->irq7_callback().set("pic8259_master", FUNC(pic8259_device::ir7_w));
+ m_isabus->irq10_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir3_w));
+ m_isabus->irq11_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir4_w));
+ m_isabus->irq12_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir5_w));
+ m_isabus->irq14_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir6_w));
+ m_isabus->irq15_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir7_w));
+ m_isabus->drq0_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq0_w));
+ m_isabus->drq1_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq1_w));
+ m_isabus->drq2_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq2_w));
+ m_isabus->drq3_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq3_w));
+ m_isabus->drq5_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq1_w));
+ m_isabus->drq6_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq2_w));
+ m_isabus->drq7_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq3_w));
+ m_isabus->iochck_callback().set(FUNC(at_mb_device::iochck_w));
+
+ MC146818(config, m_mc146818, 32.768_kHz_XTAL);
+ m_mc146818->irq().set(m_pic8259_slave, FUNC(pic8259_device::ir0_w));
+ m_mc146818->set_century_index(0x32);
+
+ /* sound hardware */
+ SPEAKER(config, "mono").front_center();
+ SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
+
+ at_keyboard_controller_device &keybc(AT_KEYBOARD_CONTROLLER(config, "keybc", 12_MHz_XTAL));
+ keybc.hot_res().set_inputline(":maincpu", INPUT_LINE_RESET);
+ keybc.gate_a20().set_inputline(":maincpu", INPUT_LINE_A20);
+ keybc.kbd_irq().set("pic8259_master", FUNC(pic8259_device::ir1_w));
+}
+
+
+void at_mb_device::map(address_map &map)
+{
+ map(0x0000, 0x001f).rw("dma8237_1", FUNC(am9517a_device::read), FUNC(am9517a_device::write)).umask16(0xffff);
+ map(0x0020, 0x003f).rw("pic8259_master", FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0xffff);
+ map(0x0040, 0x005f).rw(m_pit8254, FUNC(pit8254_device::read), FUNC(pit8254_device::write)).umask16(0xffff);
+ map(0x0061, 0x0061).rw(FUNC(at_mb_device::portb_r), FUNC(at_mb_device::portb_w));
+ map(0x0060, 0x0060).rw("keybc", FUNC(at_keyboard_controller_device::data_r), FUNC(at_keyboard_controller_device::data_w));
+ map(0x0064, 0x0064).rw("keybc", FUNC(at_keyboard_controller_device::status_r), FUNC(at_keyboard_controller_device::command_w));
+ map(0x0070, 0x007f).w(FUNC(at_mb_device::rtcas_nmi_w)).umask16(0x00ff);
+ map(0x0070, 0x007f).rw(m_mc146818, FUNC(mc146818_device::data_r), FUNC(mc146818_device::data_w)).umask16(0xff00);
+ map(0x0080, 0x009f).rw(FUNC(at_mb_device::page8_r), FUNC(at_mb_device::page8_w)).umask16(0xffff);
+ map(0x00a0, 0x00bf).rw("pic8259_slave", FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0xffff);
+ map(0x00c0, 0x00df).rw("dma8237_2", FUNC(am9517a_device::read), FUNC(am9517a_device::write)).umask16(0x00ff);
+}
+
+/*************************************************************
+ *
+ * pic8259 configuration
+ *
+ *************************************************************/
+uint8_t at_mb_device::get_slave_ack(offs_t offset)
+{
+ if (offset==2) // IRQ = 2
+ return m_pic8259_slave->acknowledge();
+
+ return 0x00;
+}
+
+/*************************************************************************
+ *
+ * PC Speaker related
+ *
+ *************************************************************************/
+
+void at_mb_device::speaker_set_spkrdata(uint8_t data)
+{
+ m_at_spkrdata = data ? 1 : 0;
+ m_speaker->level_w(m_at_spkrdata & m_pit_out2);
+}
+
+
+
+/*************************************************************
+ *
+ * pit8254 configuration
+ *
+ *************************************************************/
+
+void at_mb_device::pit8254_out2_changed(int state)
+{
+ m_pit_out2 = state ? 1 : 0;
+ m_speaker->level_w(m_at_spkrdata & m_pit_out2);
+}
+
+
+/*************************************************************************
+ *
+ * PC DMA stuff
+ *
+ *************************************************************************/
+
+uint8_t at_mb_device::page8_r(offs_t offset)
+{
+ uint8_t 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;
+}
+
+
+void at_mb_device::page8_w(offs_t offset, uint8_t data)
+{
+ m_at_pages[offset % 0x10] = data;
+
+ if (offset == 0)
+ {
+ LOGMASKED(LOG_PORT80, " at_page8_w(): Port 80h <== 0x%02x (PC=0x%08x)\n", data, m_maincpu->pc());
+ }
+
+ 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;
+ }
+}
+
+
+void at_mb_device::dma_hrq_changed(int state)
+{
+ m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ m_dma8237_2->hack_w(state);
+}
+
+uint8_t at_mb_device::dma_read_byte(offs_t offset)
+{
+ address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return 0xff;
+ uint8_t result;
+ offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;
+
+ result = prog_space.read_byte(page_offset + offset);
+ return result;
+}
+
+
+void at_mb_device::dma_write_byte(offs_t offset, uint8_t data)
+{
+ address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return;
+ offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;
+
+ prog_space.write_byte(page_offset + offset, data);
+}
+
+
+uint8_t at_mb_device::dma_read_word(offs_t offset)
+{
+ address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return 0xff;
+ uint16_t result;
+ offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;
+
+ result = prog_space.read_word((page_offset & 0xfe0000) | (offset << 1));
+ m_dma_high_byte = result & 0xff00;
+
+ return result & 0xff;
+}
+
+
+void at_mb_device::dma_write_word(offs_t offset, uint8_t data)
+{
+ address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return;
+ offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;
+
+ prog_space.write_word((page_offset & 0xfe0000) | (offset << 1), m_dma_high_byte | data);
+}
+
+uint8_t at_mb_device::dma8237_0_dack_r() { return m_isabus->dack_r(0); }
+uint8_t at_mb_device::dma8237_1_dack_r() { return m_isabus->dack_r(1); }
+uint8_t at_mb_device::dma8237_2_dack_r() { return m_isabus->dack_r(2); }
+uint8_t at_mb_device::dma8237_3_dack_r() { return m_isabus->dack_r(3); }
+uint8_t at_mb_device::dma8237_5_dack_r() { uint16_t ret = m_isabus->dack16_r(5); m_dma_high_byte = ret & 0xff00; return ret; }
+uint8_t at_mb_device::dma8237_6_dack_r() { uint16_t ret = m_isabus->dack16_r(6); m_dma_high_byte = ret & 0xff00; return ret; }
+uint8_t at_mb_device::dma8237_7_dack_r() { uint16_t ret = m_isabus->dack16_r(7); m_dma_high_byte = ret & 0xff00; return ret; }
+
+
+void at_mb_device::dma8237_0_dack_w(uint8_t data) { m_isabus->dack_w(0, data); }
+void at_mb_device::dma8237_1_dack_w(uint8_t data) { m_isabus->dack_w(1, data); }
+void at_mb_device::dma8237_2_dack_w(uint8_t data) { m_isabus->dack_w(2, data); }
+void at_mb_device::dma8237_3_dack_w(uint8_t data) { m_isabus->dack_w(3, data); }
+void at_mb_device::dma8237_5_dack_w(uint8_t data) { m_isabus->dack16_w(5, m_dma_high_byte | data); }
+void at_mb_device::dma8237_6_dack_w(uint8_t data) { m_isabus->dack16_w(6, m_dma_high_byte | data); }
+void at_mb_device::dma8237_7_dack_w(uint8_t data) { m_isabus->dack16_w(7, m_dma_high_byte | data); }
+
+void at_mb_device::dma8237_out_eop(int state)
+{
+ m_cur_eop = state == ASSERT_LINE;
+ if(m_dma_channel != -1)
+ m_isabus->eop_w(m_dma_channel, m_cur_eop ? ASSERT_LINE : CLEAR_LINE );
+}
+
+void at_mb_device::dma8237_2_out_eop(int state)
+{
+ m_cur_eop2 = state == ASSERT_LINE;
+ if(m_dma_channel != -1)
+ m_isabus->eop_w(m_dma_channel, m_cur_eop2 ? ASSERT_LINE : CLEAR_LINE );
+}
+
+void at_mb_device::set_dma_channel(int channel, int state)
+{
+ if(!state) {
+ m_dma_channel = channel;
+ if(m_cur_eop)
+ m_isabus->eop_w(channel, ASSERT_LINE );
+
+ } else if(m_dma_channel == channel) {
+ m_dma_channel = -1;
+ if(m_cur_eop)
+ m_isabus->eop_w(channel, CLEAR_LINE );
+ }
+}
+
+void at_mb_device::rtcas_nmi_w(uint8_t data)
+{
+ m_nmi_enabled = BIT(data,7);
+ if (!m_nmi_enabled)
+ m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+ m_mc146818->address_w(data);
+}
+
+uint32_t at_mb_device::a20_286(bool state)
+{
+ return (state ? 0xffffff : 0xefffff);
+}
+
+void at_mb_device::shutdown(int state)
+{
+ if(state)
+ m_maincpu->reset();
+}
+void at_mb_device::dack0_w(int state) { set_dma_channel(0, state); }
+void at_mb_device::dack1_w(int state) { set_dma_channel(1, state); }
+void at_mb_device::dack2_w(int state) { set_dma_channel(2, state); }
+void at_mb_device::dack3_w(int state) { set_dma_channel(3, state); }
+void at_mb_device::dack4_w(int state) { m_dma8237_1->hack_w(state ? 0 : 1); } // it's inverted
+void at_mb_device::dack5_w(int state) { set_dma_channel(5, state); }
+void at_mb_device::dack6_w(int state) { set_dma_channel(6, state); }
+void at_mb_device::dack7_w(int state) { set_dma_channel(7, state); }
+
+void at_mb_device::kbd_clk_w(int state) { m_keybc->kbd_clk_w(state); }
+void at_mb_device::kbd_data_w(int state) { m_keybc->kbd_data_w(state); }
+
+uint8_t at_mb_device::portb_r()
+{
+ uint8_t data = m_at_speaker;
+ data &= ~0xd0; /* AT BIOS don't likes this being set */
+
+ /* 0x10 is the dram refresh line bit, 15.085us. */
+ data |= (machine().time().as_ticks(110000) & 1) ? 0x10 : 0;
+
+ if (m_pit_out2)
+ data |= 0x20;
+ else
+ data &= ~0x20; /* ps2m30 wants this */
+
+ return data;
+}
+
+void at_mb_device::portb_w(uint8_t data)
+{
+ m_at_speaker = data;
+ m_pit8254->write_gate2(BIT(data, 0));
+ speaker_set_spkrdata( BIT(data, 1));
+ m_channel_check = BIT(data, 3);
+ if (m_channel_check)
+ m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+}
+
+void at_mb_device::iochck_w(int state)
+{
+ if (!state && m_nmi_enabled && !m_channel_check)
+ m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
+}
diff --git a/src/devices/machine/at.h b/src/devices/machine/at.h
new file mode 100644
index 00000000000..b6f98a06b45
--- /dev/null
+++ b/src/devices/machine/at.h
@@ -0,0 +1,107 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol, Miodrag Milanovic, Carl
+#ifndef MAME_MACHINE_AT_H
+#define MAME_MACHINE_AT_H
+
+#include "machine/mc146818.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "machine/am9517a.h"
+#include "machine/at_keybc.h"
+#include "bus/isa/isa.h"
+#include "sound/spkrdev.h"
+#include "softlist.h"
+
+class at_mb_device : public device_t
+{
+public:
+ at_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ void map(address_map &map);
+
+ auto kbd_clk() { return m_keybc.lookup()->kbd_clk(); }
+ auto kbd_data() { return m_keybc.lookup()->kbd_data(); }
+
+ uint8_t page8_r(offs_t offset);
+ void page8_w(offs_t offset, uint8_t data);
+ void kbd_clk_w(int state);
+ void kbd_data_w(int state);
+ uint8_t portb_r();
+ void portb_w(uint8_t data);
+ void rtcas_nmi_w(uint8_t data);
+ void iochck_w(int state);
+
+ void shutdown(int state);
+
+ uint32_t a20_286(bool state);
+
+ void at_softlists(machine_config &config);
+protected:
+ void device_start() override;
+ void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ void set_dma_channel(int channel, int state);
+ void speaker_set_spkrdata(uint8_t data);
+
+ required_device<cpu_device> m_maincpu;
+ required_device<isa16_device> m_isabus;
+ required_device<pic8259_device> m_pic8259_slave;
+ required_device<am9517a_device> m_dma8237_1;
+ required_device<am9517a_device> m_dma8237_2;
+ required_device<pit8254_device> m_pit8254;
+ required_device<speaker_sound_device> m_speaker;
+ required_device<mc146818_device> m_mc146818;
+ optional_device<at_keyboard_controller_device> m_keybc; // removed in mtouchxl.cpp and vis.cpp
+
+ uint8_t m_at_spkrdata = 0;
+ uint8_t m_pit_out2 = 0;
+ int m_dma_channel = 0;
+ bool m_cur_eop = false, m_cur_eop2 = false;
+ uint8_t m_dma_offset[2][4]{};
+ uint8_t m_at_pages[0x10]{};
+ uint16_t m_dma_high_byte = 0;
+ uint8_t m_at_speaker = 0;
+ uint8_t m_channel_check = 0;
+ uint8_t m_nmi_enabled = 0;
+
+ void pit8254_out2_changed(int state);
+
+ void dma8237_out_eop(int state);
+ void dma8237_2_out_eop(int state);
+ uint8_t dma8237_0_dack_r();
+ uint8_t dma8237_1_dack_r();
+ uint8_t dma8237_2_dack_r();
+ uint8_t dma8237_3_dack_r();
+ uint8_t dma8237_5_dack_r();
+ uint8_t dma8237_6_dack_r();
+ uint8_t dma8237_7_dack_r();
+ void dma8237_0_dack_w(uint8_t data);
+ void dma8237_1_dack_w(uint8_t data);
+ void dma8237_2_dack_w(uint8_t data);
+ void dma8237_3_dack_w(uint8_t data);
+ void dma8237_5_dack_w(uint8_t data);
+ void dma8237_6_dack_w(uint8_t data);
+ void dma8237_7_dack_w(uint8_t data);
+ void dack0_w(int state);
+ void dack1_w(int state);
+ void dack2_w(int state);
+ void dack3_w(int state);
+ void dack4_w(int state);
+ void dack5_w(int state);
+ void dack6_w(int state);
+ void dack7_w(int state);
+ uint8_t get_slave_ack(offs_t offset);
+ void dma_hrq_changed(int state);
+
+ uint8_t dma_read_byte(offs_t offset);
+ void dma_write_byte(offs_t offset, uint8_t data);
+ uint8_t dma_read_word(offs_t offset);
+ void dma_write_word(offs_t offset, uint8_t data);
+};
+
+DECLARE_DEVICE_TYPE(AT_MB, at_mb_device)
+
+
+#endif // MAME_MACHINE_AT_H
diff --git a/src/devices/machine/at28c16.cpp b/src/devices/machine/at28c16.cpp
index acbee4613eb..079649e0e95 100644
--- a/src/devices/machine/at28c16.cpp
+++ b/src/devices/machine/at28c16.cpp
@@ -8,7 +8,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/at28c16.h"
+#include "at28c16.h"
#define AT28C16_DATA_BYTES ( 0x800 )
#define AT28C16_ID_BYTES ( 0x20 )
@@ -72,7 +72,7 @@ device_memory_interface::space_config_vector at28c16_device::memory_space_config
void at28c16_device::device_start()
{
- m_write_timer = timer_alloc(0);
+ m_write_timer = timer_alloc( FUNC( at28c16_device::write_complete ), this );
save_item( NAME(m_a9_12v) );
save_item( NAME(m_oe_12v) );
@@ -107,16 +107,18 @@ void at28c16_device::nvram_default()
// .nv file
//-------------------------------------------------
-void at28c16_device::nvram_read( emu_file &file )
+bool at28c16_device::nvram_read(util::read_stream &file)
{
- std::vector<uint8_t> buffer( AT28C16_TOTAL_BYTES );
+ std::vector<uint8_t> buffer(AT28C16_TOTAL_BYTES);
- file.read( &buffer[0], AT28C16_TOTAL_BYTES );
+ auto const [err, actual] = util::read(file, &buffer[0], AT28C16_TOTAL_BYTES);
+ if (err || (actual != AT28C16_TOTAL_BYTES))
+ return false;
- for( offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++ )
- {
- space(AS_PROGRAM).write_byte( offs, buffer[ offs ] );
- }
+ for (offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++)
+ space(AS_PROGRAM).write_byte(offs, buffer[offs]);
+
+ return true;
}
//-------------------------------------------------
@@ -124,16 +126,15 @@ void at28c16_device::nvram_read( emu_file &file )
// .nv file
//-------------------------------------------------
-void at28c16_device::nvram_write( emu_file &file )
+bool at28c16_device::nvram_write( util::write_stream &file )
{
- std::vector<uint8_t> buffer ( AT28C16_TOTAL_BYTES );
+ std::vector<uint8_t> buffer(AT28C16_TOTAL_BYTES);
- for( offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++ )
- {
- buffer[ offs ] = space(AS_PROGRAM).read_byte( offs );
- }
+ for (offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++)
+ buffer[offs] = space(AS_PROGRAM).read_byte(offs);
- file.write( &buffer[0], AT28C16_TOTAL_BYTES );
+ auto const [err, actual] = util::write(file, &buffer[0], AT28C16_TOTAL_BYTES);
+ return !err;
}
@@ -202,7 +203,7 @@ uint8_t at28c16_device::read(offs_t offset)
}
-WRITE_LINE_MEMBER( at28c16_device::set_a9_12v )
+void at28c16_device::set_a9_12v(int state)
{
state &= 1;
if( m_a9_12v != state )
@@ -213,7 +214,7 @@ WRITE_LINE_MEMBER( at28c16_device::set_a9_12v )
}
-WRITE_LINE_MEMBER( at28c16_device::set_oe_12v )
+void at28c16_device::set_oe_12v(int state)
{
state &= 1;
if( m_oe_12v != state )
@@ -224,12 +225,7 @@ WRITE_LINE_MEMBER( at28c16_device::set_oe_12v )
}
-void at28c16_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER( at28c16_device::write_complete )
{
- switch( id )
- {
- case 0:
- m_last_write = -1;
- break;
- }
+ m_last_write = -1;
}
diff --git a/src/devices/machine/at28c16.h b/src/devices/machine/at28c16.h
index 54c87fccb4f..e7b564929c5 100644
--- a/src/devices/machine/at28c16.h
+++ b/src/devices/machine/at28c16.h
@@ -35,15 +35,14 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
// internal state
@@ -55,8 +54,9 @@ private:
optional_region_ptr<uint8_t> m_default_data;
// I/O operations
- DECLARE_WRITE_LINE_MEMBER( set_a9_12v );
- DECLARE_WRITE_LINE_MEMBER( set_oe_12v );
+ void set_a9_12v(int state);
+ void set_oe_12v(int state);
+ TIMER_CALLBACK_MEMBER( write_complete );
void at28c16_map8(address_map &map);
};
diff --git a/src/devices/machine/at28c64b.cpp b/src/devices/machine/at28c64b.cpp
new file mode 100644
index 00000000000..3fdc23a1c86
--- /dev/null
+++ b/src/devices/machine/at28c64b.cpp
@@ -0,0 +1,271 @@
+// license:BSD-3-Clause
+// copyright-holders:smf, R. Belmont
+/***************************************************************************
+ ATMEL AT28C64B
+
+ 64K ( 8K x 8 ) Parallel EEPROM with flash-like in-band signalling
+
+***************************************************************************/
+
+#include "emu.h"
+#include "at28c64b.h"
+
+static constexpr int AT28C64B_DATA_BYTES = 0x10000;
+static constexpr int AT28C64B_ID_BYTES = 0x40;
+static constexpr int AT28C64B_TOTAL_BYTES = AT28C64B_DATA_BYTES + AT28C64B_ID_BYTES;
+
+static constexpr int AT28C64B_ID_OFFSET = 0x1fc0;
+static constexpr int AT28C64B_SECTOR_SIZE = 0x40;
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+void at28c64b_device::at28c64b_map8(address_map &map)
+{
+ map(0x00000, 0x1003f).ram();
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(AT28C64B, at28c64b_device, "at28c64b", "AT28C64B 8Kx8 EEPROM")
+
+//-------------------------------------------------
+// at28c64b_device - constructor
+//-------------------------------------------------
+
+at28c64b_device::at28c64b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, AT28C64B, tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ device_nvram_interface(mconfig, *this),
+ m_space_config("at28c64b", ENDIANNESS_BIG, 8, 17, 0, address_map_constructor(FUNC(at28c64b_device::at28c64b_map8), this)),
+ m_a9_12v(0),
+ m_oe_12v(0),
+ m_last_write(-1),
+ m_state(0),
+ m_bytes_in_sector(0),
+ m_default_data(*this, DEVICE_SELF)
+{
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector at28c64b_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void at28c64b_device::device_start()
+{
+ m_write_timer = timer_alloc( FUNC( at28c64b_device::write_complete ), this );
+
+ save_item( NAME(m_a9_12v) );
+ save_item( NAME(m_oe_12v) );
+ save_item( NAME(m_last_write) );
+}
+
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void at28c64b_device::nvram_default()
+{
+ uint16_t const default_value = 0xff;
+ for (offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++)
+ space(AS_PROGRAM).write_byte(offs, default_value);
+
+ /* populate from a memory region if present */
+ if (m_default_data.found())
+ {
+ for (offs_t offs = 0; offs < AT28C64B_DATA_BYTES; offs++)
+ space(AS_PROGRAM).write_byte(offs, m_default_data[offs]);
+ }
+}
+
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+bool at28c64b_device::nvram_read(util::read_stream &file)
+{
+ std::vector<uint8_t> buffer(AT28C64B_TOTAL_BYTES);
+
+ auto const [err, actual] = util::read(file, &buffer[0], AT28C64B_TOTAL_BYTES);
+ if (err || (actual != AT28C64B_TOTAL_BYTES))
+ return false;
+
+ for (offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++)
+ space(AS_PROGRAM).write_byte(offs, buffer[offs]);
+
+ return true;
+}
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+bool at28c64b_device::nvram_write(util::write_stream &file)
+{
+ std::vector<uint8_t> buffer(AT28C64B_TOTAL_BYTES);
+
+ for (offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++)
+ buffer[offs] = space(AS_PROGRAM).read_byte(offs);
+
+ auto const [err, actual] = util::write(file, &buffer[0], AT28C64B_TOTAL_BYTES);
+ return !err;
+}
+
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void at28c64b_device::write(offs_t offset, uint8_t data)
+{
+ logerror("%s: AT28C64B: write( %04x, %02x ) state %d last_write %d\n", machine().describe_context(), offset, data, m_state, m_last_write);
+
+ if (m_state == STATE_SECTOR_WRITE)
+ {
+ logerror("SECTOR WRITE: %02x @ %x\n", data, offset);
+ this->space(AS_PROGRAM).write_byte(offset, data);
+ m_last_write = data;
+ m_write_timer->adjust(attotime::from_usec(10));
+ m_bytes_in_sector--;
+ if (m_bytes_in_sector == 0)
+ {
+ m_state = STATE_WRITE_PROTECT;
+ }
+ return;
+ }
+
+ if( m_last_write >= 0 )
+ {
+// logerror( "%s: AT28C64B: write( %04x, %02x ) busy\n", machine().describe_context(), offset, data );
+ }
+ else if( m_oe_12v )
+ {
+// logerror( "%s: AT28C64B: write( %04x, %02x ) erase\n", machine().describe_context(), offset, data );
+ if( m_last_write < 0 )
+ {
+ for( offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++ )
+ {
+ this->space(AS_PROGRAM).write_byte( offs, 0xff );
+ }
+
+ m_last_write = 0xff;
+ m_write_timer->adjust( attotime::from_usec( 10 ) );
+ }
+ }
+ else
+ {
+ if ((offset == 0x1555) && (data == 0xaa))
+ {
+ m_state = STATE_ID_1;
+ return;
+ }
+
+ if ((m_state == STATE_ID_1) && (offset == 0xaaa) && (data == 0x55))
+ {
+ m_state = STATE_ID_2;
+ return;
+ }
+
+ if ((m_state == STATE_ID_2) && (offset == 0x1555) && (data == 0xa0))
+ {
+ m_state = STATE_SECTOR_WRITE;
+ m_bytes_in_sector = AT28C64B_SECTOR_SIZE;
+ return;
+ }
+
+ if (m_state == STATE_WRITE_PROTECT)
+ {
+ logerror("%s: write %02x to %x while write protected\n", machine().describe_context(), data, offset);
+ return;
+ }
+
+ if ((m_a9_12v) && (offset >= AT28C64B_ID_OFFSET) && (offset < (AT28C64B_ID_OFFSET + AT28C64B_ID_BYTES)))
+ {
+ offset += AT28C64B_ID_BYTES;
+ }
+
+ if( m_last_write < 0 && this->space(AS_PROGRAM).read_byte( offset ) != data )
+ {
+ this->space(AS_PROGRAM).write_byte( offset, data );
+ m_last_write = data;
+ m_write_timer->adjust( attotime::from_usec( 10 ) );
+ }
+ }
+}
+
+
+uint8_t at28c64b_device::read(offs_t offset)
+{
+ if( m_last_write >= 0 )
+ {
+ uint8_t data = m_last_write ^ 0x80;
+// logerror( "%s: AT28C64B: read( %04x ) write status %02x\n", machine().describe_context(), offset, data );
+ return data;
+ }
+ else
+ {
+ if( m_a9_12v && offset >= AT28C64B_ID_OFFSET )
+ {
+ offset += AT28C64B_ID_BYTES;
+ }
+
+ uint8_t data = this->space(AS_PROGRAM).read_byte( offset );
+// logerror( "%s: AT28C64B: read( %04x ) data %02x\n", machine().describe_context(), offset, data );
+ return data;
+ }
+}
+
+
+void at28c64b_device::set_a9_12v(int state)
+{
+ state &= 1;
+ if( m_a9_12v != state )
+ {
+// logerror( "%s: AT28C64B: set_a9_12v( %d )\n", machine().describe_context(), state );
+ m_a9_12v = state;
+ }
+}
+
+
+void at28c64b_device::set_oe_12v(int state)
+{
+ state &= 1;
+ if( m_oe_12v != state )
+ {
+// logerror( "%s: AT28C64B: set_oe_12v( %d )\n", machine().describe_context(), state );
+ m_oe_12v = state;
+ }
+}
+
+
+TIMER_CALLBACK_MEMBER( at28c64b_device::write_complete )
+{
+ m_last_write = -1;
+}
diff --git a/src/devices/machine/at28c64b.h b/src/devices/machine/at28c64b.h
new file mode 100644
index 00000000000..f0c903e3952
--- /dev/null
+++ b/src/devices/machine/at28c64b.h
@@ -0,0 +1,80 @@
+// license:BSD-3-Clause
+// copyright-holders:smf
+/***************************************************************************
+
+ ATMEL AT28C64B
+
+ 64K ( 8K x 8 ) Parallel EEPROM
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_AT28C64B_H
+#define MAME_MACHINE_AT28C64B_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> at28c64b_device
+
+class at28c64b_device :
+ public device_t,
+ public device_memory_interface,
+ public device_nvram_interface
+{
+public:
+ // construction/destruction
+ at28c64b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void write(offs_t offset, u8 data);
+ u8 read(offs_t offset);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_nvram_interface overrides
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+private:
+ // internal state
+ enum
+ {
+ STATE_IDLE,
+ STATE_ID_1,
+ STATE_ID_2,
+ STATE_SECTOR_WRITE,
+ STATE_WRITE_PROTECT
+ };
+
+ address_space_config m_space_config;
+ emu_timer *m_write_timer;
+ int m_a9_12v;
+ int m_oe_12v;
+ int m_last_write;
+ int m_state;
+ int m_bytes_in_sector;
+
+ optional_region_ptr<uint8_t> m_default_data;
+
+ // I/O operations
+ void set_a9_12v(int state);
+ void set_oe_12v(int state);
+ TIMER_CALLBACK_MEMBER( write_complete );
+
+ void at28c64b_map8(address_map &map);
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(AT28C64B, at28c64b_device)
+
+#endif // MAME_MACHINE_AT28C64B_H
diff --git a/src/devices/machine/at29x.cpp b/src/devices/machine/at29x.cpp
index 3f31e44c0a8..232828b62bd 100644
--- a/src/devices/machine/at29x.cpp
+++ b/src/devices/machine/at29x.cpp
@@ -40,23 +40,18 @@
#include "emu.h"
#include "at29x.h"
-#define LOG_DETAIL (1U<<1) // More detail
-#define LOG_WARN (1U<<2) // Warning
-#define LOG_PRG (1U<<3) // Programming
-#define LOG_READ (1U<<4) // Reading
-#define LOG_WRITE (1U<<5) // Writing
-#define LOG_CONFIG (1U<<6) // Configuration
-#define LOG_STATE (1U<<7) // State machine
+#define LOG_DETAIL (1U << 1) // More detail
+#define LOG_WARN (1U << 2) // Warning
+#define LOG_PRG (1U << 3) // Programming
+#define LOG_READ (1U << 4) // Reading
+#define LOG_WRITE (1U << 5) // Writing
+#define LOG_CONFIG (1U << 6) // Configuration
+#define LOG_STATE (1U << 7) // State machine
-#define VERBOSE ( LOG_GENERAL | LOG_WARN )
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
#include "logmacro.h"
-enum
-{
- PRGTIMER = 1
-};
-
/*
Constructor for all variants
*/
@@ -114,9 +109,10 @@ void at29x_device::nvram_default()
// .nv file
//-------------------------------------------------
-void at29x_device::nvram_read(emu_file &file)
+bool at29x_device::nvram_read(util::read_stream &file)
{
- file.read(m_eememory.get(), m_memory_size+2);
+ auto const [err, actual] = util::read(file, m_eememory.get(), m_memory_size+2);
+ return !err && (actual == m_memory_size+2);
}
//-------------------------------------------------
@@ -124,18 +120,20 @@ void at29x_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void at29x_device::nvram_write(emu_file &file)
+bool at29x_device::nvram_write(util::write_stream &file)
{
// If we don't write (because there were no changes), the file will be wiped
LOGMASKED(LOG_PRG, "Write to NVRAM file\n");
m_eememory[0] = m_version;
- file.write(m_eememory.get(), m_memory_size+2);
+
+ auto const [err, actual] = util::write(file, m_eememory.get(), m_memory_size+2);
+ return !err;
}
/*
Programming timer callback
*/
-void at29x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(at29x_device::step_programming)
{
switch (m_pgm)
{
@@ -479,7 +477,7 @@ void at29x_device::device_start()
{
m_programming_buffer = std::make_unique<uint8_t[]>(m_sector_size);
m_eememory = std::make_unique<uint8_t[]>(m_memory_size+2);
- m_programming_timer = timer_alloc(PRGTIMER);
+ m_programming_timer = timer_alloc(FUNC(at29x_device::step_programming), this);
// TODO: Complete 16-bit handling
m_address_mask = m_memory_size/(m_word_width/8) - 1;
diff --git a/src/devices/machine/at29x.h b/src/devices/machine/at29x.h
index 265ef1587c2..5df3672877f 100644
--- a/src/devices/machine/at29x.h
+++ b/src/devices/machine/at29x.h
@@ -29,11 +29,12 @@ protected:
virtual void device_start(void) override;
virtual void device_reset(void) override;
virtual void device_stop(void) override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- void nvram_default() override;
- void nvram_read(emu_file &file) override;
- void nvram_write(emu_file &file) override;
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ TIMER_CALLBACK_MEMBER(step_programming);
int get_sector_number(offs_t address) { return address / m_sector_size; }
diff --git a/src/devices/machine/at45dbxx.cpp b/src/devices/machine/at45dbxx.cpp
index 74fc06b4413..1dffb79329e 100644
--- a/src/devices/machine/at45dbxx.cpp
+++ b/src/devices/machine/at45dbxx.cpp
@@ -15,8 +15,11 @@
#include "emu.h"
#include "at45dbxx.h"
-#define LOG_LEVEL 1
-#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+#define LOG_LEVEL0 (1U << 1)
+#define LOG_LEVEL1 (1U << 2)
+#define LOG_LEVEL2 (1U << 3)
+#define VERBOSE (LOG_LEVEL0)
+#include "logmacro.h"
#define FLASH_CMD_52 0x52
#define FLASH_CMD_57 0x57
@@ -101,8 +104,6 @@ void at45db041_device::device_start()
save_item(NAME(m_pin.wp));
save_item(NAME(m_pin.reset));
save_item(NAME(m_pin.busy));
-
- write_so.resolve_safe();
}
@@ -112,7 +113,7 @@ void at45db041_device::device_start()
void at45db041_device::device_reset()
{
- _logerror( 1, ("at45dbxx_reset\n"));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx_reset\n");
// mode
m_mode = FLASH_MODE_SI;
m_status = 0;
@@ -159,9 +160,10 @@ void at45db041_device::nvram_default()
// .nv file
//-------------------------------------------------
-void at45db041_device::nvram_read(emu_file &file)
+bool at45db041_device::nvram_read(util::read_stream &file)
{
- file.read(&m_data[0], m_size);
+ auto const [err, actual] = read(file, &m_data[0], m_size);
+ return !err && (actual == m_size);
}
//-------------------------------------------------
@@ -169,9 +171,10 @@ void at45db041_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void at45db041_device::nvram_write(emu_file &file)
+bool at45db041_device::nvram_write(util::write_stream &file)
{
- file.write(&m_data[0], m_size);
+ auto const [err, actual] = write(file, &m_data[0], m_size);
+ return !err;
}
uint8_t at45db041_device::read_byte()
@@ -181,7 +184,7 @@ uint8_t at45db041_device::read_byte()
if ((m_mode != FLASH_MODE_SO) || (!m_io.data)) return 0;
// read byte
data = m_io.data[m_io.pos++];
- _logerror( 2, ("at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, m_io.pos, m_io.size));
+ LOGMASKED(LOG_LEVEL2, "at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, m_io.pos, m_io.size);
if (m_io.pos == m_io.size) m_io.pos = 0;
return data;
}
@@ -226,7 +229,7 @@ void at45db041_device::write_byte(uint8_t data)
if (m_cmd.size < 8)
{
uint8_t opcode;
- _logerror( 2, ("at45dbxx_write_byte (%02X)\n", data));
+ LOGMASKED(LOG_LEVEL2, "at45dbxx_write_byte (%02X)\n", data);
// add to command buffer
m_cmd.data[m_cmd.size++] = data;
// check opcode
@@ -239,7 +242,7 @@ void at45db041_device::write_byte(uint8_t data)
// 8 bits command
if (m_cmd.size == 1)
{
- _logerror( 1, ("at45dbxx opcode %02X - status register read\n", opcode));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx opcode %02X - status register read\n", opcode);
m_status = (m_status & 0xC7) | device_id(); // 80 = busy / 40 = compare fail
flash_set_io(&m_status, 1, 0);
m_mode = FLASH_MODE_SO;
@@ -256,10 +259,10 @@ void at45db041_device::write_byte(uint8_t data)
uint32_t page;
uint8_t comp;
page = flash_get_page_addr();
- _logerror( 1, ("at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page);
comp = memcmp( &m_data[page * page_size()], &m_buffer1[0], page_size()) == 0 ? 0 : 1;
if (comp) m_status |= 0x40; else m_status &= ~0x40;
- _logerror( 1, ("at45dbxx page compare %s\n", comp ? "failure" : "success"));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx page compare %s\n", comp ? "failure" : "success");
m_mode = FLASH_MODE_SI;
m_cmd.size = 8;
}
@@ -274,7 +277,7 @@ void at45db041_device::write_byte(uint8_t data)
uint32_t page, byte;
page = flash_get_page_addr();
byte = flash_get_byte_addr();
- _logerror( 1, ("at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte);
flash_set_io(&m_data[page * page_size()], page_size(), byte);
m_mode = FLASH_MODE_SO;
m_cmd.size = 8;
@@ -290,7 +293,7 @@ void at45db041_device::write_byte(uint8_t data)
uint32_t page, byte;
page = flash_get_page_addr();
byte = flash_get_byte_addr();
- _logerror( 1, ("at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte);
flash_set_io(&m_buffer1[0], page_size(), byte);
memset(&m_buffer1[0], 0xff, m_buffer1.size());
m_mode = FLASH_MODE_SI;
@@ -301,7 +304,7 @@ void at45db041_device::write_byte(uint8_t data)
// other
default :
{
- _logerror( 1, ("at45dbxx opcode %02X - unknown\n", opcode));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx opcode %02X - unknown\n", opcode);
m_cmd.data[0] = 0;
m_cmd.size = 0;
}
@@ -310,7 +313,7 @@ void at45db041_device::write_byte(uint8_t data)
}
else
{
- _logerror( 2, ("at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, m_io.pos + 1, m_io.size));
+ LOGMASKED(LOG_LEVEL2, "at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, m_io.pos + 1, m_io.size);
// store byte
m_io.data[m_io.pos] = data;
m_io.pos++;
@@ -318,19 +321,19 @@ void at45db041_device::write_byte(uint8_t data)
}
}
-READ_LINE_MEMBER(at45db041_device::so_r)
+int at45db041_device::so_r()
{
if (m_pin.cs == 0) return 0;
return m_pin.so;
}
-WRITE_LINE_MEMBER(at45db041_device::si_w)
+void at45db041_device::si_w(int state)
{
if (m_pin.cs == 0) return;
m_pin.si = state;
}
-WRITE_LINE_MEMBER(at45db041_device::cs_w)
+void at45db041_device::cs_w(int state)
{
// check if changed
if (m_pin.cs == state) return;
@@ -343,7 +346,7 @@ WRITE_LINE_MEMBER(at45db041_device::cs_w)
uint32_t page, byte;
page = flash_get_page_addr();
byte = flash_get_byte_addr();
- _logerror( 1, ("at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte));
+ LOGMASKED(LOG_LEVEL1, "at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte);
memcpy( &m_data[page * page_size()], &m_buffer1[0], page_size());
}
// reset
@@ -353,7 +356,7 @@ WRITE_LINE_MEMBER(at45db041_device::cs_w)
m_pin.cs = state;
}
-WRITE_LINE_MEMBER(at45db041_device::sck_w)
+void at45db041_device::sck_w(int state)
{
// check if changed
if (m_pin.sck == state) return;
diff --git a/src/devices/machine/at45dbxx.h b/src/devices/machine/at45dbxx.h
index ecea6472c46..79f0a8aafd5 100644
--- a/src/devices/machine/at45dbxx.h
+++ b/src/devices/machine/at45dbxx.h
@@ -26,10 +26,10 @@ class at45db041_device : public device_t,
public:
at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER(cs_w);
- DECLARE_WRITE_LINE_MEMBER(sck_w);
- DECLARE_WRITE_LINE_MEMBER(si_w);
- DECLARE_READ_LINE_MEMBER(so_r);
+ void cs_w(int state);
+ void sck_w(int state);
+ void si_w(int state);
+ int so_r();
uint8_t *get_ptr() { return &m_data[0]; }
@@ -44,8 +44,8 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
virtual int num_pages() const { return 2048; }
virtual int page_size() const { return 264; }
diff --git a/src/devices/machine/at_keybc.cpp b/src/devices/machine/at_keybc.cpp
index a166ff234cb..a7d9ce8b9d4 100644
--- a/src/devices/machine/at_keybc.cpp
+++ b/src/devices/machine/at_keybc.cpp
@@ -90,7 +90,6 @@
#include "emu.h"
#include "at_keybc.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_COMMAND (1U << 1)
#define LOG_STATUS (1U << 2)
@@ -272,12 +271,12 @@ void at_kbc_device_base::command_w(uint8_t data)
machine().scheduler().synchronize(timer_expired_delegate(FUNC(at_kbc_device_base::write_command), this), unsigned(data));
}
-WRITE_LINE_MEMBER(at_kbc_device_base::kbd_clk_w)
+void at_kbc_device_base::kbd_clk_w(int state)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(at_kbc_device_base::set_kbd_clk_in), this), state);
}
-WRITE_LINE_MEMBER(at_kbc_device_base::kbd_data_w)
+void at_kbc_device_base::kbd_data_w(int state)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(at_kbc_device_base::set_kbd_data_in), this), state);
}
@@ -292,15 +291,6 @@ at_kbc_device_base::at_kbc_device_base(machine_config const &mconfig, device_typ
{
}
-void at_kbc_device_base::device_resolve_objects()
-{
- m_hot_res_cb.resolve_safe();
- m_gate_a20_cb.resolve_safe();
- m_kbd_irq_cb.resolve_safe();
- m_kbd_clk_cb.resolve_safe();
- m_kbd_data_cb.resolve_safe();
-}
-
void at_kbc_device_base::device_start()
{
save_item(NAME(m_hot_res));
@@ -442,12 +432,12 @@ uint8_t ps2_keyboard_controller_device::status_r()
return data;
}
-WRITE_LINE_MEMBER(ps2_keyboard_controller_device::aux_clk_w)
+void ps2_keyboard_controller_device::aux_clk_w(int state)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(ps2_keyboard_controller_device::set_aux_clk_in), this), state);
}
-WRITE_LINE_MEMBER(ps2_keyboard_controller_device::aux_data_w)
+void ps2_keyboard_controller_device::aux_data_w(int state)
{
machine().scheduler().synchronize(timer_expired_delegate(FUNC(ps2_keyboard_controller_device::set_aux_data_in), this), state);
}
@@ -478,15 +468,6 @@ void ps2_keyboard_controller_device::device_add_mconfig(machine_config &config)
m_mcu->t1_in_cb().set([this] () { return aux_clk_r(); });
}
-void ps2_keyboard_controller_device::device_resolve_objects()
-{
- at_kbc_device_base::device_resolve_objects();
-
- m_aux_irq_cb.resolve_safe();
- m_aux_clk_cb.resolve_safe();
- m_aux_data_cb.resolve_safe();
-}
-
void ps2_keyboard_controller_device::device_start()
{
at_kbc_device_base::device_start();
diff --git a/src/devices/machine/at_keybc.h b/src/devices/machine/at_keybc.h
index 9e769416cb2..d57ca81f565 100644
--- a/src/devices/machine/at_keybc.h
+++ b/src/devices/machine/at_keybc.h
@@ -36,15 +36,14 @@ public:
void command_w(uint8_t data);
// inputs from keyboard
- DECLARE_WRITE_LINE_MEMBER(kbd_clk_w);
- DECLARE_WRITE_LINE_MEMBER(kbd_data_w);
+ void kbd_clk_w(int state);
+ void kbd_data_w(int state);
protected:
// trampoline constructor
at_kbc_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
// device_t implementation
- virtual void device_resolve_objects() override;
virtual void device_start() override;
// host outputs - use 1 = asserted, 0 = deasserted
@@ -116,8 +115,8 @@ public:
virtual uint8_t status_r() override;
// inputs from aux
- DECLARE_WRITE_LINE_MEMBER(aux_clk_w);
- DECLARE_WRITE_LINE_MEMBER(aux_data_w);
+ void aux_clk_w(int state);
+ void aux_data_w(int state);
// standard constructor
ps2_keyboard_controller_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
@@ -126,7 +125,6 @@ protected:
// device_t implementation
virtual tiny_rom_entry const *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
- virtual void device_resolve_objects() override;
virtual void device_start() override;
private:
diff --git a/src/devices/machine/ataflash.cpp b/src/devices/machine/ataflash.cpp
index 464bd074cdf..54e7c841ace 100644
--- a/src/devices/machine/ataflash.cpp
+++ b/src/devices/machine/ataflash.cpp
@@ -11,22 +11,20 @@ ata_flash_pccard_device::ata_flash_pccard_device(const machine_config &mconfig,
}
ata_flash_pccard_device::ata_flash_pccard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : ide_hdd_device(mconfig, type, tag, owner, clock)
+ : cf_device_base(mconfig, type, tag, owner, clock)
, device_pccard_interface(mconfig, *this)
{
}
void ata_flash_pccard_device::device_reset()
{
- ide_hdd_device::device_reset();
+ cf_device_base::device_reset();
- uint32_t metalength;
- memset(m_cis, 0xff, 512);
-
- if (m_handle != nullptr)
+ if (m_image->exists())
{
- m_handle->read_metadata(PCMCIA_CIS_METADATA_TAG, 0, m_cis, 512, metalength);
+ m_image->get_cis_data(m_cis);
}
+ m_cis.resize(512, 0xff);
m_configuration_option = 0;
m_configuration_and_status = 0;
@@ -38,11 +36,11 @@ uint16_t ata_flash_pccard_device::read_memory(offs_t offset, uint16_t mem_mask)
if(offset <= 7)
{
m_8bit_data_transfers = !ACCESSING_BITS_8_15; // HACK
- return read_cs0(offset, mem_mask);
+ return command_r(offset);
}
else if(offset <= 15)
{
- return read_cs1(offset & 7, mem_mask);
+ return control_r(offset & 7);
}
else
{
@@ -55,11 +53,11 @@ void ata_flash_pccard_device::write_memory(offs_t offset, uint16_t data, uint16_
if(offset <= 7)
{
m_8bit_data_transfers = !ACCESSING_BITS_8_15; // HACK
- write_cs0(offset, data, mem_mask);
+ command_w(offset, data);
}
else if( offset <= 15)
{
- write_cs1(offset & 7, data, mem_mask);
+ control_w(offset & 7, data);
}
}
@@ -112,11 +110,6 @@ void ata_flash_pccard_device::write_reg(offs_t offset, uint16_t data, uint16_t m
}
}
-attotime ata_flash_pccard_device::seek_time()
-{
- return attotime::zero;
-}
-
DEFINE_DEVICE_TYPE(TAITO_PCCARD1, taito_pccard1_device, "taito_pccard1", "Taito PC Card (Type 1)")
@@ -137,13 +130,11 @@ void taito_pccard1_device::device_reset()
{
ata_flash_pccard_device::device_reset();
- uint32_t metalength;
- memset(m_key, 0, sizeof(m_key));
-
- if (m_handle != nullptr && m_handle->read_metadata(HARD_DISK_KEY_METADATA_TAG, 0, m_key, 5, metalength) == CHDERR_NONE)
+ if (m_image->exists() && !m_image->get_disk_key_data(m_key) && m_key.size() == 5)
{
m_locked = 0x1ff;
}
+ m_key.resize(5, 0);
}
uint16_t taito_pccard1_device::read_reg(offs_t offset, uint16_t mem_mask)
@@ -164,7 +155,7 @@ void taito_pccard1_device::write_reg(offs_t offset, uint16_t data, uint16_t mem_
{
uint8_t v = data;
int pos = offset - 0x280;
- uint8_t k = pos < sizeof(m_key) ? m_key[pos] : 0;
+ uint8_t k = pos < m_key.size() ? m_key[pos] : 0;
// TODO: find out if unlocking the key then using an incorrect key will re-lock the card.
if (v == k)
@@ -228,13 +219,11 @@ void taito_pccard2_device::device_reset()
{
ata_flash_pccard_device::device_reset();
- uint32_t metalength;
- memset(m_key, 0, sizeof(m_key));
-
- if (m_handle != nullptr && m_handle->read_metadata(HARD_DISK_KEY_METADATA_TAG, 0, m_key, 5, metalength) == CHDERR_NONE)
+ if (m_image->exists() && !m_image->get_disk_key_data(m_key) && m_key.size() == 5)
{
m_locked = true;
}
+ m_key.resize(5, 0);
}
void taito_pccard2_device::process_command()
@@ -327,13 +316,11 @@ void taito_compact_flash_device::device_reset()
{
ata_flash_pccard_device::device_reset();
- uint32_t metalength;
- memset(m_key, 0, sizeof(m_key));
-
- if (m_handle != nullptr && m_handle->read_metadata(HARD_DISK_KEY_METADATA_TAG, 0, m_key, 5, metalength) == CHDERR_NONE)
+ if (m_image->exists() && !m_image->get_disk_key_data(m_key) && m_key.size() == 5)
{
m_locked = true;
}
+ m_key.resize(5, 0);
}
void taito_compact_flash_device::process_command()
diff --git a/src/devices/machine/ataflash.h b/src/devices/machine/ataflash.h
index dad05081ff6..036c76b7909 100644
--- a/src/devices/machine/ataflash.h
+++ b/src/devices/machine/ataflash.h
@@ -6,11 +6,11 @@
#pragma once
#include "pccard.h"
-#include "bus/ata/idehd.h"
+#include "atastorage.h"
DECLARE_DEVICE_TYPE(ATA_FLASH_PCCARD, ata_flash_pccard_device)
-class ata_flash_pccard_device : public ide_hdd_device, public device_pccard_interface
+class ata_flash_pccard_device : public cf_device_base, public device_pccard_interface
{
public:
ata_flash_pccard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -23,14 +23,17 @@ public:
protected:
ata_flash_pccard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
+ // device_t implementation
virtual void device_reset() override;
- virtual attotime seek_time() override;
- uint8_t calculate_status() override { return ata_hle_device::calculate_status(); };
-
private:
- uint8_t m_cis[512];
+ // ata_hle_device_base implementation
+ virtual void set_irq_out(int state) override { }
+ virtual void set_dmarq_out(int state) override { }
+ virtual void set_dasp_out(int state) override { }
+ virtual void set_pdiag_out(int state) override { }
+
+ std::vector<uint8_t> m_cis;
uint8_t m_configuration_option;
uint8_t m_configuration_and_status;
uint8_t m_pin_replacement;
@@ -53,7 +56,7 @@ protected:
virtual bool is_ready() override;
private:
- uint8_t m_key[5];
+ std::vector<uint8_t> m_key;
uint16_t m_locked;
};
@@ -75,7 +78,7 @@ protected:
static const int IDE_COMMAND_TAITO_GNET_UNLOCK_2 = 0xfc;
private:
- uint8_t m_key[5];
+ std::vector<uint8_t> m_key;
bool m_locked;
};
@@ -95,7 +98,7 @@ protected:
static constexpr int IDE_COMMAND_TAITO_COMPACT_FLASH_UNLOCK = 0x0f;
private:
- uint8_t m_key[5];
+ std::vector<uint8_t> m_key;
bool m_locked;
};
diff --git a/src/devices/machine/atahle.cpp b/src/devices/machine/atahle.cpp
new file mode 100644
index 00000000000..6decde4cb9f
--- /dev/null
+++ b/src/devices/machine/atahle.cpp
@@ -0,0 +1,921 @@
+// license:BSD-3-Clause
+// copyright-holders:smf
+#include "emu.h"
+#include "atahle.h"
+
+#define VERBOSE 0
+#define PRINTF_IDE_COMMANDS 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOGPRINT(x) do { if (VERBOSE) logerror x; if (PRINTF_IDE_COMMANDS) osd_printf_debug x; } while (0)
+
+enum
+{
+ IDE_CS0_DATA_RW = 0,
+ IDE_CS0_ERROR_R = 1,
+ IDE_CS0_FEATURE_W = 1,
+ IDE_CS0_SECTOR_COUNT_RW = 2,
+ IDE_CS0_SECTOR_NUMBER_RW = 3,
+ IDE_CS0_CYLINDER_LOW_RW = 4,
+ IDE_CS0_CYLINDER_HIGH_RW = 5,
+ IDE_CS0_DEVICE_HEAD_RW = 6,
+ IDE_CS0_STATUS_R = 7,
+ IDE_CS0_COMMAND_W = 7
+};
+
+enum
+{
+ IDE_CS1_ALTERNATE_STATUS_R = 6,
+ IDE_CS1_DEVICE_CONTROL_W = 6,
+ IDE_CS1_ACTIVE_STATUS = 7
+};
+
+enum
+{
+ IDE_DEVICE_CONTROL_NIEN = 0x02,
+ IDE_DEVICE_CONTROL_SRST = 0x04
+};
+
+#define DETECT_DEVICE1_TIME (attotime::from_msec(2))
+#define DEVICE1_PDIAG_TIME (attotime::from_msec(2))
+#define DIAGNOSTIC_TIME (attotime::from_msec(2))
+
+ata_hle_device_base::ata_hle_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_buffer_offset(0),
+ m_buffer_size(0),
+ m_error(0),
+ m_feature(0),
+ m_sector_count(0),
+ m_sector_number(0),
+ m_cylinder_low(0),
+ m_cylinder_high(0),
+ m_device_head(0),
+ m_status(0),
+ m_command(0),
+ m_device_control(0),
+ m_revert_to_defaults(true),
+ m_8bit_data_transfers(false),
+ m_csel(0),
+ m_daspin(0),
+ m_daspout(0),
+ m_dmack(0),
+ m_dmarq(0),
+ m_irq(0),
+ m_pdiagin(0),
+ m_pdiagout(0),
+ m_single_device(0),
+ m_resetting(0), m_busy_timer(nullptr), m_buffer_empty_timer(nullptr)
+{
+}
+
+void ata_hle_device_base::device_start()
+{
+ MINIMUM_COMMAND_TIME = attotime::from_usec(10);
+
+ m_buffer.resize(sector_length());
+ save_item(NAME(m_buffer));
+ save_item(NAME(m_buffer_offset));
+ save_item(NAME(m_buffer_size));
+ save_item(NAME(m_error));
+ save_item(NAME(m_feature));
+ save_item(NAME(m_sector_count));
+ save_item(NAME(m_sector_number));
+ save_item(NAME(m_cylinder_low));
+ save_item(NAME(m_cylinder_high));
+ save_item(NAME(m_device_head));
+ save_item(NAME(m_status));
+ save_item(NAME(m_command));
+ save_item(NAME(m_device_control));
+ save_item(NAME(m_revert_to_defaults));
+ save_item(NAME(m_8bit_data_transfers));
+
+ save_item(NAME(m_single_device));
+ save_item(NAME(m_resetting));
+
+ save_item(NAME(m_csel));
+ save_item(NAME(m_daspin));
+ save_item(NAME(m_daspout));
+ save_item(NAME(m_dmack));
+ save_item(NAME(m_dmarq));
+ save_item(NAME(m_irq));
+ save_item(NAME(m_pdiagin));
+ save_item(NAME(m_pdiagout));
+
+ save_item(NAME(m_identify_buffer));
+
+ m_busy_timer = timer_alloc(FUNC(ata_hle_device_base::busy_tick), this);
+ m_buffer_empty_timer = timer_alloc(FUNC(ata_hle_device_base::empty_tick), this);
+}
+
+void ata_hle_device_base::device_reset()
+{
+ /* reset the drive state */
+ set_dasp(CLEAR_LINE);
+ set_dmarq(CLEAR_LINE);
+ set_irq(CLEAR_LINE);
+ set_pdiag(CLEAR_LINE);
+
+ m_status = 0;
+ m_device_control = 0;
+ m_resetting = true;
+
+ if (m_csel == 0)
+ {
+ start_busy(DETECT_DEVICE1_TIME, PARAM_DETECT_DEVICE1);
+ }
+ else
+ {
+ set_dasp(ASSERT_LINE);
+ soft_reset();
+ }
+}
+
+void ata_hle_device_base::soft_reset()
+{
+ m_buffer_offset = 0;
+ m_buffer_size = 0;
+ m_status = 0;
+
+ if (is_ready())
+ {
+ m_status |= IDE_STATUS_DRDY;
+ }
+
+ start_busy(DIAGNOSTIC_TIME, PARAM_DIAGNOSTIC);
+}
+
+TIMER_CALLBACK_MEMBER(ata_hle_device_base::busy_tick)
+{
+ m_status &= ~IDE_STATUS_BSY;
+ finished_busy(param);
+}
+
+TIMER_CALLBACK_MEMBER(ata_hle_device_base::empty_tick)
+{
+ m_buffer_empty_timer->enable(false);
+ fill_buffer();
+}
+
+void ata_hle_device_base::finished_busy(int32_t param)
+{
+ switch (param)
+ {
+ case PARAM_DETECT_DEVICE1:
+ m_single_device = (m_daspin == CLEAR_LINE);
+ soft_reset();
+ break;
+
+ case PARAM_DIAGNOSTIC:
+ start_diagnostic();
+ break;
+
+ case PARAM_WAIT_FOR_PDIAG:
+ m_error |= IDE_ERROR_DIAGNOSTIC_DEVICE1_FAILED;
+ finished_diagnostic();
+ break;
+
+ case PARAM_COMMAND:
+ finished_command();
+ break;
+ }
+}
+
+void ata_hle_device_base::process_command()
+{
+ switch (m_command)
+ {
+ case IDE_COMMAND_DIAGNOSTIC:
+ start_busy(DIAGNOSTIC_TIME, PARAM_COMMAND);
+ break;
+
+ case IDE_COMMAND_SET_FEATURES:
+ start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
+ break;
+
+ case IDE_COMMAND_CACHE_FLUSH:
+ start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
+ break;
+
+ default:
+ LOGPRINT(("IDE unknown command (%02X)\n", m_command));
+ m_status |= IDE_STATUS_ERR;
+ m_error = IDE_ERROR_ABRT;
+ set_irq(ASSERT_LINE);
+ //machine().debug_break();
+ break;
+ }
+}
+
+void ata_hle_device_base::finished_command()
+{
+ switch (m_command)
+ {
+ case IDE_COMMAND_DIAGNOSTIC:
+ start_diagnostic();
+
+ if (m_csel == 0)
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_SET_FEATURES:
+ if (!set_features())
+ {
+ LOGPRINT(("IDE Set features failed (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_sector_number, m_cylinder_low, m_cylinder_high));
+
+ m_status |= IDE_STATUS_ERR;
+ m_error = IDE_ERROR_ABRT;
+ }
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_CACHE_FLUSH:
+ m_status |= IDE_STATUS_DRDY;
+ break;
+
+ default:
+ logerror( "finished_command() unhandled command %02x\n", m_command );
+ break;
+ }
+}
+
+bool ata_hle_device_base::set_dma_mode(int word)
+{
+ if ((m_identify_buffer[word] >> (m_sector_count & 7)) & 1)
+ {
+ m_identify_buffer[62] &= 0xff;
+ m_identify_buffer[63] &= 0xff;
+ m_identify_buffer[88] &= 0xff;
+
+ m_identify_buffer[word] |= 0x100 << (m_sector_count & 7);
+ return true;
+ }
+
+ return false;
+}
+
+bool ata_hle_device_base::set_features()
+{
+ switch (m_feature)
+ {
+ case IDE_SET_FEATURES_ENABLE_8BIT_DATA_TRANSFERS:
+ m_8bit_data_transfers = true;
+ return true;
+
+ case IDE_SET_FEATURES_TRANSFER_MODE:
+ switch (m_sector_count & IDE_TRANSFER_TYPE_MASK)
+ {
+ case IDE_TRANSFER_TYPE_PIO_DEFAULT:
+ switch (m_sector_count & 7)
+ {
+ case 0:
+ case 1:
+ return true;
+ }
+ break;
+
+ case IDE_TRANSFER_TYPE_PIO_FLOW_CONTROL:
+ switch (m_sector_count & 7)
+ {
+ case 0:
+ case 1:
+ case 2:
+ return true;
+
+ default:
+ if ((m_identify_buffer[64] >> ((m_sector_count & 7) - 3)) & 1)
+ {
+ return true;
+ }
+ }
+ break;
+
+ case IDE_TRANSFER_TYPE_SINGLE_WORD_DMA:
+ return set_dma_mode(62);
+
+ case IDE_TRANSFER_TYPE_MULTI_WORD_DMA:
+ return set_dma_mode(63);
+
+ case IDE_TRANSFER_TYPE_ULTRA_DMA:
+ return set_dma_mode(88);
+ }
+ break;
+
+ case IDE_SET_FEATURES_DISABLE_REVERTING_TO_POWER_ON_DEFAULTS:
+ m_revert_to_defaults = false;
+ return true;
+
+ case IDE_SET_FEATURES_DISABLE_8BIT_DATA_TRANSFERS:
+ m_8bit_data_transfers = false;
+ return true;
+
+ case IDE_SET_FEATURES_ENABLE_REVERTING_TO_POWER_ON_DEFAULTS:
+ m_revert_to_defaults = true;
+ return true;
+
+ // not actually handled, but reply as if we did
+ case IDE_SET_FEATURES_ENABLE_ECC:
+ case IDE_SET_FEATURES_ENABLE_RETRIES:
+ case IDE_SET_FEATURES_ENABLE_READ_LOOK_AHEAD:
+ return true;
+ }
+
+ return false;
+}
+
+int ata_hle_device_base::bit_to_mode(uint16_t word)
+{
+ switch (word>>8)
+ {
+ case 0x01:
+ return 0;
+ case 0x02:
+ return 1;
+ case 0x04:
+ return 2;
+ case 0x08:
+ return 3;
+ case 0x10:
+ return 4;
+ case 0x20:
+ return 5;
+ case 0x40:
+ return 6;
+ case 0x080:
+ return 7;
+ }
+
+ return -1;
+}
+
+// Return the currently selected single word dma mode, -1 if none selected
+int ata_hle_device_base::single_word_dma_mode()
+{
+ return bit_to_mode(m_identify_buffer[62]);
+}
+
+// Return the currently selected multi word dma mode, -1 if none selected
+int ata_hle_device_base::multi_word_dma_mode()
+{
+ return bit_to_mode(m_identify_buffer[63]);
+}
+
+// Return the currently selected ultra dma mode, -1 if none selected
+int ata_hle_device_base::ultra_dma_mode()
+{
+ return bit_to_mode(m_identify_buffer[88]);
+}
+
+uint16_t ata_hle_device_base::read_data()
+{
+ /* fetch the correct amount of data */
+ uint16_t result = m_buffer[m_buffer_offset++];
+ if (!m_8bit_data_transfers)
+ result |= m_buffer[m_buffer_offset++] << 8;
+
+ /* if we're at the end of the buffer, handle it */
+ if (m_buffer_offset >= m_buffer_size)
+ {
+ LOG(("%s:IDE completed PIO read\n", machine().describe_context()));
+ read_buffer_empty();
+ }
+
+ return result;
+}
+
+void ata_hle_device_base::write_data(uint16_t data)
+{
+ /* store the correct amount of data */
+ m_buffer[m_buffer_offset++] = data;
+ if (!m_8bit_data_transfers)
+ m_buffer[m_buffer_offset++] = data >> 8;
+
+ /* if we're at the end of the buffer, handle it */
+ if (m_buffer_offset >= m_buffer_size)
+ {
+ LOG(("%s:IDE completed PIO write\n", machine().describe_context()));
+ write_buffer_full();
+ }
+}
+
+void ata_hle_device_base::update_irq()
+{
+ if (device_selected() && (m_device_control & IDE_DEVICE_CONTROL_NIEN) == 0)
+ set_irq_out(m_irq);
+ else
+ set_irq_out(CLEAR_LINE);
+}
+
+void ata_hle_device_base::start_busy(const attotime &time, int32_t param)
+{
+ m_status |= IDE_STATUS_BSY;
+ m_busy_timer->adjust(time, param);
+}
+
+void ata_hle_device_base::stop_busy()
+{
+ m_status &= ~IDE_STATUS_BSY;
+ m_busy_timer->adjust(attotime::never);
+}
+
+void ata_hle_device_base::read_buffer_empty()
+{
+ m_buffer_offset = 0;
+
+ m_status &= ~IDE_STATUS_DRQ;
+
+ // Doesn't matter if we're in dma or not, when the buffer is empty
+ // there's no more request to be had
+ set_dmarq(CLEAR_LINE);
+
+ if (ultra_dma_mode() >= 0) {
+ m_buffer_empty_timer->enable(true);
+ m_buffer_empty_timer->adjust(attotime::zero);
+ }
+ else
+ fill_buffer();
+}
+
+void ata_hle_device_base::write_buffer_full()
+{
+ m_buffer_offset = 0;
+
+ m_status &= ~IDE_STATUS_DRQ;
+
+ // Doesn't matter if we're in dma or not, when the buffer is full
+ // there's no more request to be had
+ set_dmarq(CLEAR_LINE);
+
+ process_buffer();
+}
+
+void ata_hle_device_base::start_diagnostic()
+{
+ m_error = IDE_ERROR_DIAGNOSTIC_FAILED;
+
+ perform_diagnostic();
+
+ if (m_csel == 1 && m_error == IDE_ERROR_DIAGNOSTIC_PASSED)
+ set_pdiag(ASSERT_LINE);
+
+ if (m_csel == 0 && !m_single_device && m_pdiagin == CLEAR_LINE)
+ start_busy(DEVICE1_PDIAG_TIME, PARAM_WAIT_FOR_PDIAG);
+ else
+ finished_diagnostic();
+}
+
+void ata_hle_device_base::finished_diagnostic()
+{
+ m_resetting = false;
+
+ signature();
+}
+
+
+void ata_hle_device_base::set_dmack_in(int state)
+{
+ if (state && !m_dmack && single_word_dma_mode() >= 0)
+ set_dmarq(CLEAR_LINE);
+
+ m_dmack = state;
+}
+
+void ata_hle_device_base::set_pdiag_in(int state)
+{
+ m_pdiagin = state;
+
+ if (m_pdiagin == ASSERT_LINE && m_busy_timer->param() == PARAM_WAIT_FOR_PDIAG)
+ {
+ stop_busy();
+ finished_diagnostic();
+ }
+}
+
+uint16_t ata_hle_device_base::dma_r()
+{
+ uint16_t result = 0xffff;
+
+ if (device_selected())
+ {
+ if (!m_dmack)
+ {
+ logerror( "%s: %s dev %d read_dma ignored (!DMACK)\n", machine().describe_context(), tag(), dev() );
+ }
+ else if (m_dmarq && single_word_dma_mode() >= 0)
+ {
+ logerror( "%s: %s dev %d read_dma ignored (DMARQ)\n", machine().describe_context(), tag(), dev() );
+ }
+ else if (!m_dmarq && multi_word_dma_mode() >= 0)
+ {
+ logerror( "%s: %s dev %d read_dma ignored (!DMARQ)\n", machine().describe_context(), tag(), dev() );
+ }
+ else if (!m_dmarq && ultra_dma_mode() >= 0)
+ {
+ logerror("%s: %s dev %d read_dma ignored (!DMARQ)\n", machine().describe_context(), tag(), dev());
+ }
+ else if (m_status & IDE_STATUS_BSY)
+ {
+ logerror( "%s: %s dev %d read_dma ignored (BSY)\n", machine().describe_context(), tag(), dev() );
+ }
+ else if (!(m_status & IDE_STATUS_DRQ))
+ {
+ logerror( "%s: %s dev %d read_dma ignored (!DRQ)\n", machine().describe_context(), tag(), dev() );
+ }
+ else
+ {
+ result = read_data();
+
+ if ((m_status & IDE_STATUS_DRQ) && single_word_dma_mode() >= 0)
+ set_dmarq(ASSERT_LINE);
+ }
+ }
+
+ return result;
+}
+
+uint16_t ata_hle_device_base::command_r(offs_t offset)
+{
+ uint16_t result = 0xffff;
+
+ if (device_selected() || m_single_device)
+ {
+ if (m_dmack)
+ {
+ logerror( "%s: %s dev %d read_cs0 %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset );
+ }
+ else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_STATUS_R)
+ {
+ // ATA5 spec says status reads should also go through here, but this breaks Primal Rage 2.
+ // Real hardware might work due to read ahead in the vt83c461.
+ if (device_selected())
+ {
+ switch (offset)
+ {
+ case IDE_CS0_DATA_RW:
+ logerror( "%s: %s dev %d read_cs0 %04x ignored (BSY)\n", machine().describe_context(), tag(), dev(), offset );
+ break;
+
+ default:
+ result = calculate_status();
+ break;
+ }
+ }
+ else
+ {
+ result = 0;
+ }
+ }
+ else
+ {
+ switch (offset)
+ {
+ /* read data if there's data to be read */
+ case IDE_CS0_DATA_RW:
+ if (device_selected())
+ {
+ if (!(m_status & IDE_STATUS_DRQ))
+ {
+ logerror( "%s: %s dev %d read_cs0 ignored (!DRQ)\n", machine().describe_context(), tag(), dev() );
+ }
+ else
+ {
+ result = read_data();
+ }
+ }
+ else
+ {
+ result = 0;
+ }
+ break;
+
+ /* return the current error */
+ case IDE_CS0_ERROR_R:
+ result = m_error;
+ break;
+
+ /* return the current sector count */
+ case IDE_CS0_SECTOR_COUNT_RW:
+ result = m_sector_count;
+ break;
+
+ /* return the current sector */
+ case IDE_CS0_SECTOR_NUMBER_RW:
+ result = m_sector_number;
+ break;
+
+ /* return the current cylinder LSB */
+ case IDE_CS0_CYLINDER_LOW_RW:
+ result = m_cylinder_low;
+ break;
+
+ /* return the current cylinder MSB */
+ case IDE_CS0_CYLINDER_HIGH_RW:
+ result = m_cylinder_high;
+ break;
+
+ /* return the current head */
+ case IDE_CS0_DEVICE_HEAD_RW:
+ result = m_device_head;
+ break;
+
+ /* return the current status and clear any pending interrupts */
+ case IDE_CS0_STATUS_R:
+ if (device_selected())
+ {
+ result = calculate_status();
+
+ if (!(m_status & IDE_STATUS_DRDY) && is_ready())
+ m_status |= IDE_STATUS_DRDY;
+
+ set_irq(CLEAR_LINE);
+ }
+ else
+ {
+ result = 0;
+ }
+ break;
+
+ /* log anything else */
+ default:
+ logerror("%s:unknown IDE cs0 read at %03X\n", machine().describe_context(), offset);
+ break;
+ }
+ }
+ }
+
+ /* logit */
+// if (offset != IDE_CS0_DATA_RW && offset != IDE_CS0_STATUS_R)
+ LOG(("%s:IDE cs0 read %X at %X (err: %X)\n", machine().describe_context(), result, offset, m_error));
+
+ /* return the result */
+ return result;
+}
+
+
+uint16_t ata_hle_device_base::control_r(offs_t offset)
+{
+ /* logit */
+// if (offset != IDE_CS1_ALTERNATE_STATUS_R)
+ LOG(("%s:IDE cs1 read at %X\n", machine().describe_context(), offset));
+
+ uint16_t result = 0xffff;
+
+ if (device_selected() || m_single_device)
+ {
+ if (m_dmack)
+ {
+ logerror( "%s: %s dev %d read_cs1 %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset );
+ }
+ else
+ {
+ switch (offset)
+ {
+ case IDE_CS1_ALTERNATE_STATUS_R:
+ if (device_selected())
+ {
+ result = calculate_status();
+ }
+ else
+ {
+ result = 0;
+ }
+ break;
+
+ case IDE_CS1_ACTIVE_STATUS:
+ /*
+
+ bit description
+
+ 0 master active
+ 1 slave active
+ 2 complement of active disk head bit 0
+ 3 complement of active disk head bit 1
+ 4 complement of active disk head bit 2
+ 5 complement of active disk head bit 3
+ 6 write in progress
+ 7 floppy present (unused)
+
+ */
+ if (device_selected())
+ {
+ result = 0x01;
+ }
+ else
+ {
+ result = 0;
+ }
+ break;
+
+ /* log anything else */
+ default:
+ logerror("%s:unknown IDE cs1 read at %03X\n", machine().describe_context(), offset);
+ break;
+ }
+ }
+ }
+
+ /* return the result */
+ return result;
+}
+
+void ata_hle_device_base::dma_w(uint16_t data)
+{
+ if (device_selected())
+ {
+ if (!m_dmack)
+ {
+ logerror( "%s: %s dev %d write_dma %04x ignored (!DMACK)\n", machine().describe_context(), tag(), dev(), data );
+ }
+ else if (m_dmarq && single_word_dma_mode() >= 0)
+ {
+ logerror( "%s: %s dev %d write_dma %04x ignored (DMARQ)\n", machine().describe_context(), tag(), dev(), data );
+ }
+ else if (!m_dmarq && multi_word_dma_mode() >= 0)
+ {
+ logerror( "%s: %s dev %d write_dma %04x ignored (!DMARQ)\n", machine().describe_context(), tag(), dev(), data );
+ }
+ else if (!m_dmarq && ultra_dma_mode() >= 0)
+ {
+ logerror("%s: %s dev %d write_dma %04x ignored (!DMARQ)\n", machine().describe_context(), tag(), dev(), data);
+ }
+ else if (m_status & IDE_STATUS_BSY)
+ {
+ logerror( "%s: %s dev %d write_dma %04x ignored (BSY)\n", machine().describe_context(), tag(), dev(), data );
+ }
+ else if (!(m_status & IDE_STATUS_DRQ))
+ {
+ logerror( "%s: %s dev %d write_dma %04x ignored (!DRQ)\n", machine().describe_context(), tag(), dev(), data );
+ }
+ else
+ {
+ write_data(data);
+
+ if ((m_status & IDE_STATUS_DRQ) && single_word_dma_mode() >= 0)
+ set_dmarq(ASSERT_LINE);
+ }
+ }
+}
+
+void ata_hle_device_base::command_w(offs_t offset, uint16_t data)
+{
+ /* logit */
+ if (offset != IDE_CS0_DATA_RW)
+ LOG(("%s:IDE cs0 write to %X = %04X\n", machine().describe_context(), offset, data));
+
+ if (m_dmack)
+ {
+ logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, data );
+ }
+ else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_COMMAND_W)
+ {
+ logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (BSY) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
+ }
+ else if ((m_status & IDE_STATUS_DRQ) && offset != IDE_CS0_DATA_RW && offset != IDE_CS0_COMMAND_W)
+ {
+ logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (DRQ) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
+ }
+ else
+ {
+ uint8_t old;
+
+ switch (offset)
+ {
+ /* write data */
+ case IDE_CS0_DATA_RW:
+ if (device_selected())
+ {
+ if (!(m_status & IDE_STATUS_DRQ))
+ {
+ logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (!DRQ)\n", machine().describe_context(), tag(), dev(), offset, data );
+ }
+ else
+ {
+ write_data(data);
+ }
+ }
+ break;
+
+ case IDE_CS0_FEATURE_W:
+ m_feature = data;
+ break;
+
+ /* sector count */
+ case IDE_CS0_SECTOR_COUNT_RW:
+ m_sector_count = (data & 0xff) ? (data & 0xff) : 0x100;
+ break;
+
+ /* current sector */
+ case IDE_CS0_SECTOR_NUMBER_RW:
+ m_sector_number = data;
+ break;
+
+ /* current cylinder LSB */
+ case IDE_CS0_CYLINDER_LOW_RW:
+ m_cylinder_low = data;
+ break;
+
+ /* current cylinder MSB */
+ case IDE_CS0_CYLINDER_HIGH_RW:
+ m_cylinder_high = data;
+ break;
+
+ /* current head */
+ case IDE_CS0_DEVICE_HEAD_RW:
+ old = m_device_head;
+ m_device_head = data;
+
+ if ((m_device_head ^ old) & IDE_DEVICE_HEAD_DRV)
+ update_irq();
+ break;
+
+ /* command */
+ case IDE_CS0_COMMAND_W:
+ // Packet devices can accept DEVICE RESET when BSY or DRQ is set.
+ if (m_status & IDE_STATUS_BSY)
+ {
+ logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (BSY) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
+ }
+ else if (m_status & IDE_STATUS_DRQ)
+ {
+ logerror( "%s: %s dev %d write_cs0 %04x %04x ignored (DRQ) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, m_command );
+ }
+ else if (device_selected() || m_command == IDE_COMMAND_DIAGNOSTIC)
+ {
+ m_command = data;
+ m_error = IDE_ERROR_NONE;
+
+ /* implicitly clear interrupts & dmarq here */
+ set_irq(CLEAR_LINE);
+ set_dmarq(CLEAR_LINE);
+
+ m_buffer_offset = 0;
+
+ set_dasp(CLEAR_LINE);
+ m_status &= ~IDE_STATUS_DRQ;
+ m_status &= ~IDE_STATUS_ERR;
+
+ process_command();
+ }
+ break;
+
+ default:
+ logerror("%s:unknown IDE cs0 write at %03X = %04x\n", machine().describe_context(), offset, data);
+ break;
+ }
+ }
+}
+
+void ata_hle_device_base::control_w(offs_t offset, uint16_t data)
+{
+ /* logit */
+ LOG(("%s:IDE cs1 write to %X = %08X\n", machine().describe_context(), offset, data));
+
+ if (m_dmack)
+ {
+ logerror( "%s: %s dev %d write_cs1 %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, data);
+ }
+ else
+ {
+ uint8_t old;
+
+ switch (offset)
+ {
+ /* adapter control */
+ case IDE_CS1_DEVICE_CONTROL_W:
+ old = m_device_control;
+ m_device_control = data;
+
+ if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_NIEN)
+ update_irq();
+
+ if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_SRST)
+ {
+ if (m_device_control & IDE_DEVICE_CONTROL_SRST)
+ {
+ if (m_resetting)
+ {
+ logerror( "%s: %s dev %d write_cs1 %04x %04x ignored (RESET)\n", machine().describe_context(), tag(), dev(), offset, data );
+ }
+ else
+ {
+ set_dasp(CLEAR_LINE);
+ set_dmarq(CLEAR_LINE);
+ set_irq(CLEAR_LINE);
+ set_pdiag(CLEAR_LINE);
+
+ start_busy(attotime::never, PARAM_RESET);
+ }
+ }
+ else if (m_busy_timer->param() == PARAM_RESET)
+ {
+ soft_reset();
+ }
+ }
+ break;
+
+ default:
+ logerror("%s:unknown IDE cs1 write at %03X = %04x\n", machine().describe_context(), offset, data);
+ break;
+ }
+ }
+}
diff --git a/src/devices/machine/atahle.h b/src/devices/machine/atahle.h
new file mode 100644
index 00000000000..63a176c51ed
--- /dev/null
+++ b/src/devices/machine/atahle.h
@@ -0,0 +1,261 @@
+// license:BSD-3-Clause
+// copyright-holders:smf
+/***************************************************************************
+
+ atahle.h
+
+ ATA Device HLE
+
+***************************************************************************/
+#ifndef MAME_MACHINE_ATAHLE_H
+#define MAME_MACHINE_ATAHLE_H
+
+#pragma once
+
+class ata_hle_device_base : public device_t
+{
+protected:
+ ata_hle_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ TIMER_CALLBACK_MEMBER(busy_tick);
+ TIMER_CALLBACK_MEMBER(empty_tick);
+
+ uint16_t dma_r();
+ uint16_t command_r(offs_t offset);
+ uint16_t control_r(offs_t offset);
+
+ void dma_w(uint16_t data);
+ void command_w(offs_t offset, uint16_t data);
+ void control_w(offs_t offset, uint16_t data);
+
+ void set_csel_in(int state) { m_csel = state; }
+ void set_dasp_in(int state) { m_daspin = state; }
+ void set_dmack_in(int state);
+ void set_pdiag_in(int state);
+
+ void set_irq(int state)
+ {
+ if (m_irq != state)
+ {
+ m_irq = state;
+ update_irq();
+ }
+ }
+
+ void set_dmarq(int state)
+ {
+ if (m_dmarq != state)
+ {
+ m_dmarq = state;
+ set_dmarq_out(state);
+ }
+ }
+
+ void set_dasp(int state)
+ {
+ if (m_daspout != state)
+ {
+ m_daspout = state;
+ set_dasp_out(state);
+ }
+ }
+
+ void set_pdiag(int state)
+ {
+ if (m_pdiagout != state)
+ {
+ m_pdiagout = state;
+ set_pdiag_out(state);
+ }
+ }
+
+ void start_busy(const attotime &time, int32_t param);
+ void stop_busy();
+
+ int dev() { return (m_device_head & IDE_DEVICE_HEAD_DRV) >> 4; }
+ bool device_selected() { return m_csel == dev(); }
+
+ virtual uint8_t calculate_status() { return m_status; }
+ virtual void soft_reset();
+ virtual void process_command();
+ virtual void finished_command();
+ virtual bool set_features();
+ virtual int sector_length() = 0;
+ virtual void process_buffer() = 0;
+ virtual void fill_buffer() = 0;
+ virtual bool is_ready() = 0;
+ virtual void perform_diagnostic() = 0;
+ virtual void signature() = 0;
+ virtual uint16_t read_data();
+ virtual void write_data(uint16_t data);
+
+ int bit_to_mode(uint16_t word);
+ int single_word_dma_mode();
+ int multi_word_dma_mode();
+ int ultra_dma_mode();
+
+ /// TODO: not sure this should be protected.
+ void read_buffer_empty();
+
+ enum
+ {
+ IDE_STATUS_ERR = 0x01, // Error
+ IDE_STATUS_IDX = 0x02, // Index
+ IDE_STATUS_CORR = 0x04, // Corrected Data
+ IDE_STATUS_DRQ = 0x08, // Data Request
+ IDE_STATUS_DSC = 0x10, // ATA Drive Seek Complete
+ IDE_STATUS_SERV = 0x10, // ATAPI Service
+ IDE_STATUS_DWF = 0x20, // ATA Drive Write Fault
+ IDE_STATUS_DMRD = 0x20, // ATAPI DMA Ready
+ IDE_STATUS_DRDY = 0x40, // Drive Ready
+ IDE_STATUS_BSY = 0x80 // Busy
+ };
+
+ enum
+ {
+ IDE_ERROR_NONE = 0x00,
+ IDE_ERROR_DIAGNOSTIC_OK = 0x01,
+ IDE_ERROR_TRACK0_NOT_FOUND = 0x02,
+ IDE_ERROR_ABRT = 0x04,
+ IDE_ERROR_BAD_LOCATION = 0x10,
+ IDE_ERROR_BAD_SECTOR = 0x80,
+ IDE_ERROR_DIAGNOSTIC_FAILED = 0x00,
+ IDE_ERROR_DIAGNOSTIC_PASSED = 0x01,
+ IDE_ERROR_DIAGNOSTIC_DEVICE1_FAILED = 0x80
+ };
+
+ enum
+ {
+ IDE_COMMAND_NOP = 0x00,
+ IDE_COMMAND_DEVICE_RESET = 0x08,
+ IDE_COMMAND_RECALIBRATE = 0x10,
+ IDE_COMMAND_READ_SECTORS = 0x20,
+ IDE_COMMAND_READ_SECTORS_NORETRY = 0x21,
+ IDE_COMMAND_WRITE_SECTORS = 0x30,
+ IDE_COMMAND_WRITE_SECTORS_NORETRY = 0x31,
+ IDE_COMMAND_VERIFY_SECTORS = 0x40,
+ IDE_COMMAND_VERIFY_SECTORS_NORETRY = 0x41,
+ IDE_COMMAND_SEEK = 0x70,
+ IDE_COMMAND_DIAGNOSTIC = 0x90,
+ IDE_COMMAND_SET_CONFIG = 0x91,
+ IDE_COMMAND_PACKET = 0xa0,
+ IDE_COMMAND_IDENTIFY_PACKET_DEVICE = 0xa1,
+ IDE_COMMAND_READ_MULTIPLE = 0xc4,
+ IDE_COMMAND_WRITE_MULTIPLE = 0xc5,
+ IDE_COMMAND_SET_BLOCK_COUNT = 0xc6,
+ IDE_COMMAND_READ_DMA = 0xc8,
+ IDE_COMMAND_WRITE_DMA = 0xca,
+ IDE_COMMAND_STANDBY_IMMEDIATE = 0xe0,
+ IDE_COMMAND_IDLE_IMMEDIATE = 0xe1,
+ IDE_COMMAND_STANDBY = 0xe2,
+ IDE_COMMAND_IDLE = 0xe3,
+ IDE_COMMAND_READ_BUFFER = 0xe4,
+ IDE_COMMAND_CHECK_POWER_MODE = 0xe5,
+ IDE_COMMAND_CACHE_FLUSH = 0xe7,
+ IDE_COMMAND_WRITE_BUFFER = 0xe8,
+ IDE_COMMAND_IDENTIFY_DEVICE = 0xec,
+ IDE_COMMAND_SET_FEATURES = 0xef,
+ IDE_COMMAND_SECURITY_UNLOCK = 0xf2,
+ IDE_COMMAND_SECURITY_DISABLE_PASSWORD = 0xf6,
+ IDE_COMMAND_READ_NATIVE_MAX_ADDRESS = 0xf8,
+ IDE_COMMAND_SET_MAX = 0xf9
+ };
+
+ enum
+ {
+ IDE_SET_FEATURES_ENABLE_8BIT_DATA_TRANSFERS = 0x01,
+ IDE_SET_FEATURES_TRANSFER_MODE = 0x03,
+ IDE_SET_FEATURES_DISABLE_REVERTING_TO_POWER_ON_DEFAULTS = 0x66,
+ IDE_SET_FEATURES_DISABLE_8BIT_DATA_TRANSFERS = 0x81,
+ IDE_SET_FEATURES_ENABLE_ECC = 0x88,
+ IDE_SET_FEATURES_ENABLE_RETRIES = 0x99,
+ IDE_SET_FEATURES_ENABLE_READ_LOOK_AHEAD = 0xaa,
+ IDE_SET_FEATURES_ENABLE_REVERTING_TO_POWER_ON_DEFAULTS = 0xcc
+ };
+
+ enum ide_transfer_type_t
+ {
+ IDE_TRANSFER_TYPE_PIO_DEFAULT = 0x00,
+ IDE_TRANSFER_TYPE_PIO_FLOW_CONTROL = 0x08,
+ IDE_TRANSFER_TYPE_SINGLE_WORD_DMA = 0x10,
+ IDE_TRANSFER_TYPE_MULTI_WORD_DMA = 0x20,
+ IDE_TRANSFER_TYPE_ULTRA_DMA = 0x40,
+ IDE_TRANSFER_TYPE_MASK = 0xf8
+ };
+
+ enum
+ {
+ IDE_DEVICE_HEAD_HS = 0x0f,
+ IDE_DEVICE_HEAD_DRV = 0x10,
+ IDE_DEVICE_HEAD_L = 0x40,
+ IDE_DEVICE_HEAD_OBSOLETE = 0x80 | 0x20
+ };
+
+ enum
+ {
+ TID_BUSY,
+ TID_BUFFER_EMPTY
+ };
+
+ enum
+ {
+ PARAM_RESET,
+ PARAM_DETECT_DEVICE1,
+ PARAM_DIAGNOSTIC,
+ PARAM_WAIT_FOR_PDIAG,
+ PARAM_COMMAND
+ };
+
+ attotime MINIMUM_COMMAND_TIME;
+
+ std::vector<uint8_t> m_buffer;
+ uint16_t m_buffer_offset;
+ uint16_t m_buffer_size;
+ uint8_t m_error;
+ uint8_t m_feature;
+ uint16_t m_sector_count;
+ uint8_t m_sector_number;
+ uint8_t m_cylinder_low;
+ uint8_t m_cylinder_high;
+ uint8_t m_device_head;
+ uint8_t m_status;
+ uint8_t m_command;
+ uint8_t m_device_control;
+
+ uint16_t m_identify_buffer[256];
+ bool m_revert_to_defaults;
+ bool m_8bit_data_transfers;
+
+private:
+ virtual void set_irq_out(int state) = 0;
+ virtual void set_dmarq_out(int state) = 0;
+ virtual void set_dasp_out(int state) = 0;
+ virtual void set_pdiag_out(int state) = 0;
+
+ void update_irq();
+ void write_buffer_full();
+ void start_diagnostic();
+ void finished_diagnostic();
+ void finished_busy(int32_t param);
+ bool set_dma_mode(int word);
+
+ int m_csel;
+ int m_daspin;
+ int m_daspout;
+ int m_dmack;
+ int m_dmarq;
+ int m_irq;
+ int m_pdiagin;
+ int m_pdiagout;
+
+ bool m_single_device;
+ bool m_resetting;
+
+ emu_timer *m_busy_timer;
+ emu_timer *m_buffer_empty_timer;
+};
+
+#endif // MAME_MACHINE_ATAHLE_H
diff --git a/src/devices/machine/atastorage.cpp b/src/devices/machine/atastorage.cpp
new file mode 100644
index 00000000000..96f9d58329c
--- /dev/null
+++ b/src/devices/machine/atastorage.cpp
@@ -0,0 +1,1000 @@
+// license:BSD-3-Clause
+// copyright-holders:smf
+#include "emu.h"
+#include "atastorage.h"
+
+#include "multibyte.h"
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE 0
+#define PRINTF_IDE_COMMANDS 0
+#define PRINTF_IDE_PASSWORD 0
+
+#define LOGPRINT(x) do { if (VERBOSE) logerror x; if (PRINTF_IDE_COMMANDS) osd_printf_debug x; } while (0)
+
+#define TIME_PER_SECTOR_WRITE (attotime::from_usec(100))
+#define TIME_PER_ROTATION (attotime::from_hz(5400/60))
+#define TIME_BETWEEN_SECTORS (attotime::from_nsec(400))
+
+#define TIME_FULL_STROKE_SEEK (attotime::from_usec(13000))
+#define TIME_AVERAGE_ROTATIONAL_LATENCY (attotime::from_usec(1300))
+
+ata_mass_storage_device_base::ata_mass_storage_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ ata_hle_device_base(mconfig, type, tag, owner, clock),
+ m_can_identify_device(0),
+ m_num_cylinders(0),
+ m_num_sectors(0),
+ m_num_heads(0), m_cur_lba(0), m_block_count(0), m_sectors_until_int(0), m_master_password_enable(0), m_user_password_enable(0),
+ m_master_password(nullptr),
+ m_user_password(nullptr),
+ m_dma_transfer_time(attotime::zero)
+{
+}
+
+/*************************************
+ *
+ * Compute the LBA address
+ *
+ *************************************/
+
+uint32_t ata_mass_storage_device_base::lba_address()
+{
+ /* LBA direct? */
+ if (m_device_head & IDE_DEVICE_HEAD_L)
+ return ((m_device_head & IDE_DEVICE_HEAD_HS) << 24) | (m_cylinder_high << 16) | (m_cylinder_low << 8) | m_sector_number;
+
+ /* standard CHS */
+ else
+ return (((((m_cylinder_high << 8) | m_cylinder_low) * m_num_heads) + (m_device_head & IDE_DEVICE_HEAD_HS)) * m_num_sectors) + m_sector_number - 1;
+}
+
+
+/*************************************
+ *
+ * Build a features page
+ *
+ *************************************/
+
+static void swap_strncpy(uint16_t *dst, const char *src, int field_size_in_words)
+{
+ for (int i = 0; i < field_size_in_words; i++)
+ {
+ uint16_t d;
+
+ if (*src)
+ {
+ d = *(src++) << 8;
+ }
+ else
+ {
+ d = ' ' << 8;
+ }
+
+ if (*src)
+ {
+ d |= *(src++);
+ }
+ else
+ {
+ d |= ' ';
+ }
+
+ dst[i] = d;
+ }
+
+ assert(*(src) == 0);
+}
+
+
+void ata_mass_storage_device_base::ide_build_identify_device()
+{
+ memset(m_identify_buffer, 0, sizeof(m_identify_buffer));
+ int total_sectors = m_num_cylinders * m_num_heads * m_num_sectors;
+
+ /* basic geometry */
+ m_identify_buffer[0] = 0x045a; /* 0: configuration bits */
+ m_identify_buffer[1] = m_num_cylinders; /* 1: logical cylinders */
+ m_identify_buffer[2] = 0; /* 2: reserved */
+ m_identify_buffer[3] = m_num_heads; /* 3: logical heads */
+ m_identify_buffer[4] = 0; /* 4: vendor specific (obsolete) */
+ m_identify_buffer[5] = 0; /* 5: vendor specific (obsolete) */
+ m_identify_buffer[6] = m_num_sectors; /* 6: logical sectors per logical track */
+ m_identify_buffer[7] = 0; /* 7: vendor-specific */
+ m_identify_buffer[8] = 0; /* 8: vendor-specific */
+ m_identify_buffer[9] = 0; /* 9: vendor-specific */
+ swap_strncpy(&m_identify_buffer[10], /* 10-19: serial number */
+ "00000000000000000000", 10);
+ m_identify_buffer[20] = 0; /* 20: vendor-specific */
+ m_identify_buffer[21] = 0; /* 21: vendor-specific */
+ m_identify_buffer[22] = 4; /* 22: # of vendor-specific bytes on read/write long commands */
+ swap_strncpy(&m_identify_buffer[23], /* 23-26: firmware revision */
+ "1.0", 4);
+ swap_strncpy(&m_identify_buffer[27], /* 27-46: model number */
+ "MAME Compressed Hard Disk", 20);
+ m_identify_buffer[47] = 0x8010; /* 47: read/write multiple support, value from Seagate Quantum Fireball */
+ m_identify_buffer[48] = 0; /* 48: reserved */
+ m_identify_buffer[49] = 0x0f03; /* 49: capabilities */
+ m_identify_buffer[50] = 0; /* 50: reserved */
+ m_identify_buffer[51] = 2; /* 51: PIO data transfer cycle timing mode */
+ m_identify_buffer[52] = 2; /* 52: single word DMA transfer cycle timing mode */
+ m_identify_buffer[53] = 3; /* 53: field validity */
+ m_identify_buffer[54] = m_num_cylinders; /* 54: number of current logical cylinders */
+ m_identify_buffer[55] = m_num_heads; /* 55: number of current logical heads */
+ m_identify_buffer[56] = m_num_sectors; /* 56: number of current logical sectors per track */
+ m_identify_buffer[57] = total_sectors & 0xffff; /* 57-58: current capacity in sectors (ATA-1 through ATA-5; obsoleted in ATA-6) */
+ m_identify_buffer[58] = total_sectors >> 16;
+ m_identify_buffer[59] = 0; /* 59: multiple sector timing */
+ m_identify_buffer[60] = total_sectors & 0xffff; /* 60-61: total user addressable sectors for LBA mode (ATA-1 through ATA-7) */
+ m_identify_buffer[61] = total_sectors >> 16;
+ m_identify_buffer[62] = 0x0007; /* 62: single word dma transfer */
+ m_identify_buffer[63] = 0x0407; /* 63: multiword DMA transfer */
+ m_identify_buffer[64] = 0x0003; /* 64: flow control PIO transfer modes supported */
+ m_identify_buffer[65] = 0x78; /* 65: minimum multiword DMA transfer cycle time per word */
+ m_identify_buffer[66] = 0x78; /* 66: mfr's recommended multiword DMA transfer cycle time */
+ m_identify_buffer[67] = 0x014d; /* 67: minimum PIO transfer cycle time without flow control */
+ m_identify_buffer[68] = 0x78; /* 68: minimum PIO transfer cycle time with IORDY */
+ m_identify_buffer[69] = 0x00; /* 69-70: reserved */
+ m_identify_buffer[71] = 0x00; /* 71: reserved for IDENTIFY PACKET command */
+ m_identify_buffer[72] = 0x00; /* 72: reserved for IDENTIFY PACKET command */
+ m_identify_buffer[73] = 0x00; /* 73: reserved for IDENTIFY PACKET command */
+ m_identify_buffer[74] = 0x00; /* 74: reserved for IDENTIFY PACKET command */
+ m_identify_buffer[75] = 0x00; /* 75: queue depth */
+ m_identify_buffer[76] = 0x00; /* 76-79: reserved */
+ m_identify_buffer[80] = 0x00; /* 80: major version number */
+ m_identify_buffer[81] = 0x00; /* 81: minor version number */
+ m_identify_buffer[82] = 0x00; /* 82: command set supported */
+ m_identify_buffer[83] = 0x00; /* 83: command sets supported */
+ m_identify_buffer[84] = 0x00; /* 84: command set/feature supported extension */
+ m_identify_buffer[85] = 0x00; /* 85: command set/feature enabled */
+ m_identify_buffer[86] = 0x00; /* 86: command set/feature enabled */
+ m_identify_buffer[87] = 0x00; /* 87: command set/feature default */
+ m_identify_buffer[88] = 0x00; /* 88: additional DMA modes (ultra dma) */
+ m_identify_buffer[89] = 0x00; /* 89: time required for security erase unit completion */
+ m_identify_buffer[90] = 0x00; /* 90: time required for enhanced security erase unit completion */
+ m_identify_buffer[91] = 0x00; /* 91: current advanced power management value */
+ m_identify_buffer[92] = 0x00; /* 92: master password revision code */
+ m_identify_buffer[93] = 0x00; /* 93: hardware reset result */
+ m_identify_buffer[94] = 0x00; /* 94: acoustic management values */
+ m_identify_buffer[95] = 0x00; /* 95-99: reserved */
+ m_identify_buffer[100] = total_sectors & 0xffff; /* 100-103: maximum 48-bit LBA */
+ m_identify_buffer[101] = total_sectors >> 16;
+ m_identify_buffer[102] = 0x00;
+ m_identify_buffer[103] = 0x00;
+ m_identify_buffer[104] = 0x00; /* 104-126: reserved */
+ m_identify_buffer[127] = 0x00; /* 127: removable media status notification */
+ m_identify_buffer[128] = 0x00; /* 128: security status */
+ m_identify_buffer[129] = 0x00; /* 129-159: vendor specific */
+ m_identify_buffer[160] = 0x00; /* 160: CFA power mode 1 */
+ m_identify_buffer[161] = 0x00; /* 161-175: reserved for CompactFlash */
+ m_identify_buffer[176] = 0x00; /* 176-205: current media serial number */
+ m_identify_buffer[206] = 0x00; /* 206-254: reserved */
+ m_identify_buffer[255] = 0x00; /* 255: integrity word */
+
+ if (total_sectors >= 16514064)
+ {
+ /// CHS limit
+ m_identify_buffer[1] = 16383; /* 1: logical cylinders */
+ m_identify_buffer[3] = 16; /* 3: logical heads */
+ m_identify_buffer[6] = 63; /* 6: logical sectors per logical track */
+ m_identify_buffer[54] = 16383; /* 54: number of current logical cylinders */
+ m_identify_buffer[55] = 16; /* 55: number of current logical heads */
+ m_identify_buffer[56] = 63; /* 56: number of current logical sectors per track */
+ m_identify_buffer[57] = 16514064 & 0xffff; /* 57-58: current capacity in sectors (ATA-1 through ATA-5; obsoleted in ATA-6) */
+ m_identify_buffer[58] = 16514064 >> 16;
+ }
+
+ if (total_sectors > 268435455)
+ {
+ /// LBA limit
+ m_identify_buffer[60] = 268435455 & 0xffff; /* 60-61: total user addressable sectors for LBA mode (ATA-1 through ATA-7) */
+ m_identify_buffer[61] = 268435455 >> 16;
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ata_mass_storage_device_base::device_start()
+{
+ ata_hle_device_base::device_start();
+
+ save_item(NAME(m_can_identify_device));
+ save_item(NAME(m_num_cylinders));
+ save_item(NAME(m_num_sectors));
+ save_item(NAME(m_num_heads));
+
+ save_item(NAME(m_cur_lba));
+ save_item(NAME(m_sectors_until_int));
+ save_item(NAME(m_master_password_enable));
+ save_item(NAME(m_user_password_enable));
+ save_item(NAME(m_block_count));
+}
+
+void ata_mass_storage_device_base::soft_reset()
+{
+ ata_hle_device_base::soft_reset();
+
+ m_cur_lba = 0;
+ m_status |= IDE_STATUS_DSC;
+
+ m_master_password_enable = (m_master_password != nullptr);
+ m_user_password_enable = (m_user_password != nullptr);
+}
+
+void ata_mass_storage_device_base::perform_diagnostic()
+{
+ if (m_can_identify_device)
+ m_error = IDE_ERROR_DIAGNOSTIC_PASSED;
+}
+
+void ata_mass_storage_device_base::signature()
+{
+ m_sector_count = 1;
+ m_sector_number = 1;
+ m_cylinder_low = 0;
+ m_cylinder_high = 0;
+ m_device_head = 0;
+}
+
+void ata_mass_storage_device_base::finished_command()
+{
+ int total_sectors = m_num_cylinders * m_num_heads * m_num_sectors;
+
+ switch (m_command)
+ {
+ case IDE_COMMAND_IDENTIFY_DEVICE:
+ if (m_can_identify_device)
+ {
+ for( int w = 0; w < 256; w++ )
+ put_u16le(&m_buffer[w * 2], m_identify_buffer[ w ]);
+
+ m_status |= IDE_STATUS_DRQ;
+ }
+ else
+ {
+ m_status |= IDE_STATUS_ERR;
+ m_error = IDE_ERROR_NONE;
+ }
+
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_SET_CONFIG:
+ set_geometry(m_sector_count,(m_device_head & IDE_DEVICE_HEAD_HS) + 1);
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_READ_SECTORS:
+ case IDE_COMMAND_READ_SECTORS_NORETRY:
+ case IDE_COMMAND_READ_MULTIPLE:
+ case IDE_COMMAND_VERIFY_SECTORS:
+ case IDE_COMMAND_VERIFY_SECTORS_NORETRY:
+ case IDE_COMMAND_READ_DMA:
+ case IDE_COMMAND_READ_BUFFER:
+ finished_read();
+ break;
+
+ case IDE_COMMAND_WRITE_SECTORS:
+ case IDE_COMMAND_WRITE_SECTORS_NORETRY:
+ case IDE_COMMAND_WRITE_MULTIPLE:
+ case IDE_COMMAND_WRITE_DMA:
+ case IDE_COMMAND_WRITE_BUFFER:
+ finished_write();
+ break;
+
+ case IDE_COMMAND_RECALIBRATE:
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_READ_NATIVE_MAX_ADDRESS:
+ put_u32be(&m_buffer[0], total_sectors);
+ set_irq(ASSERT_LINE);
+ break;
+
+ default:
+ ata_hle_device_base::finished_command();
+ break;
+ }
+}
+
+/*************************************
+ *
+ * Advance to the next sector
+ *
+ *************************************/
+
+void ata_mass_storage_device_base::next_sector()
+{
+ uint8_t cur_head = m_device_head & IDE_DEVICE_HEAD_HS;
+
+ /* LBA direct? */
+ if (m_device_head & IDE_DEVICE_HEAD_L)
+ {
+ m_sector_number++;
+ if (m_sector_number == 0)
+ {
+ m_cylinder_low++;
+ if (m_cylinder_low == 0)
+ {
+ m_cylinder_high++;
+ if (m_cylinder_high == 0)
+ cur_head++;
+ }
+ }
+ }
+
+ /* standard CHS */
+ else
+ {
+ /* sectors are 1-based */
+ m_sector_number++;
+ if (m_sector_number > m_num_sectors)
+ {
+ /* heads are 0 based */
+ m_sector_number = 1;
+ cur_head++;
+ if (cur_head >= m_num_heads)
+ {
+ cur_head = 0;
+ m_cylinder_low++;
+ if (m_cylinder_low == 0)
+ m_cylinder_high++;
+ }
+ }
+ }
+
+ m_device_head = (m_device_head & ~IDE_DEVICE_HEAD_HS) | cur_head;
+
+ m_cur_lba = lba_address();
+}
+
+
+
+/*************************************
+ *
+ * security error handling
+ *
+ *************************************/
+
+void ata_mass_storage_device_base::security_error()
+{
+ /* set error state */
+ m_status |= IDE_STATUS_ERR;
+ m_error = IDE_ERROR_NONE;
+ m_status &= ~IDE_STATUS_DRDY;
+}
+
+
+
+/*************************************
+ *
+ * Sector reading
+ *
+ *************************************/
+
+attotime ata_mass_storage_device_base::seek_time()
+{
+ int sectors_per_cylinder = m_num_heads * m_num_sectors;
+
+ if (sectors_per_cylinder == 0 || m_num_cylinders == 0)
+ return attotime::zero;
+
+ int new_lba = lba_address();
+ int old_cylinder = m_cur_lba / sectors_per_cylinder;
+ int new_cylinder = new_lba / sectors_per_cylinder;
+ int diff = abs(old_cylinder - new_cylinder);
+
+ m_cur_lba = new_lba;
+
+ if (diff == 0)
+ {
+ return TIME_BETWEEN_SECTORS;
+ }
+
+ attotime seek_time = (TIME_FULL_STROKE_SEEK * diff) / m_num_cylinders;
+
+ return seek_time + TIME_AVERAGE_ROTATIONAL_LATENCY;
+}
+
+void ata_mass_storage_device_base::fill_buffer()
+{
+ switch (m_command)
+ {
+ case IDE_COMMAND_IDENTIFY_DEVICE:
+ break;
+
+ case IDE_COMMAND_READ_MULTIPLE:
+ /* if there is more data to read, keep going */
+ if (m_sector_count > 0)
+ m_sector_count--;
+
+ if (m_sector_count > 0)
+ {
+ // Read the next sector with no delay
+ finished_read();
+ }
+ break;
+
+ case IDE_COMMAND_READ_BUFFER:
+ set_irq(ASSERT_LINE);
+ break;
+
+ default:
+ /* if there is more data to read, keep going */
+ if (m_sector_count > 0)
+ m_sector_count--;
+
+ if (m_sector_count > 0)
+ {
+ set_dasp(ASSERT_LINE);
+ if (m_command == IDE_COMMAND_READ_DMA)
+ start_busy(TIME_BETWEEN_SECTORS + m_dma_transfer_time, PARAM_COMMAND);
+ else
+ start_busy(TIME_BETWEEN_SECTORS, PARAM_COMMAND);
+ }
+ break;
+ }
+}
+
+
+void ata_mass_storage_device_base::finished_read()
+{
+ int lba = lba_address(), read_status;
+
+ set_dasp(CLEAR_LINE);
+
+ /* now do the read */
+ if (m_command == IDE_COMMAND_READ_BUFFER)
+ {
+ read_status = 1;
+ }
+ else
+ {
+ read_status = read_sector(lba, &m_buffer[0]);
+ }
+
+ /* if we succeeded, advance to the next sector and set the nice bits */
+ if (read_status)
+ {
+ /* advance the pointers, unless this is the last sector */
+ /* Gauntlet: Dark Legacy checks to make sure we stop on the last sector */
+ if (m_sector_count != 1)
+ next_sector();
+
+ /* signal an interrupt, IDE_COMMAND_READ_MULTIPLE sets the interrupt at the start the block */
+ if (--m_sectors_until_int == 0 || (m_sector_count == 1 && m_command != IDE_COMMAND_READ_MULTIPLE))
+ {
+ m_sectors_until_int = ((m_command == IDE_COMMAND_READ_MULTIPLE) ? m_block_count : 1);
+ set_irq(ASSERT_LINE);
+ }
+
+ /* if we're just verifying we can read the next sector */
+ if (m_command == IDE_COMMAND_VERIFY_SECTORS ||
+ m_command == IDE_COMMAND_VERIFY_SECTORS_NORETRY )
+ {
+ read_buffer_empty();
+ }
+ else
+ {
+ m_status |= IDE_STATUS_DRQ;
+
+ if (m_command == IDE_COMMAND_READ_DMA)
+ set_dmarq(ASSERT_LINE);
+ }
+ }
+
+ /* if we got an error, we need to report it */
+ else
+ {
+ /* set the error flag and the error */
+ m_status |= IDE_STATUS_ERR;
+ m_error = IDE_ERROR_BAD_SECTOR;
+
+ /* signal an interrupt */
+ set_irq(ASSERT_LINE);
+ }
+}
+
+
+void ata_mass_storage_device_base::read_first_sector()
+{
+ if (m_master_password_enable || m_user_password_enable)
+ {
+ security_error();
+ }
+ else
+ {
+ set_dasp(ASSERT_LINE);
+
+ if (m_command == IDE_COMMAND_READ_BUFFER)
+ {
+ // don't call seek_time() here (that will trash m_cur_lba), just give a nominal delay
+ start_busy(TIME_BETWEEN_SECTORS, PARAM_COMMAND);
+ }
+ else
+ {
+ start_busy(seek_time(), PARAM_COMMAND);
+ }
+ }
+}
+
+/*************************************
+ *
+ * Sector writing
+ *
+ *************************************/
+
+void ata_mass_storage_device_base::process_buffer()
+{
+ if (m_command == IDE_COMMAND_SECURITY_UNLOCK)
+ {
+ if (m_user_password_enable && memcmp(&m_buffer[0], m_user_password, 2 + 32) == 0)
+ {
+ LOGPRINT(("IDE Unlocked user password\n"));
+ m_user_password_enable = 0;
+ }
+ if (m_master_password_enable && memcmp(&m_buffer[0], m_master_password, 2 + 32) == 0)
+ {
+ LOGPRINT(("IDE Unlocked master password\n"));
+ m_master_password_enable = 0;
+ }
+ if (PRINTF_IDE_PASSWORD)
+ {
+ int i;
+
+ for (i = 0; i < 34; i += 2)
+ {
+ if (i % 8 == 2)
+ osd_printf_debug("\n");
+
+ osd_printf_debug("0x%02x, 0x%02x, ", m_buffer[i], m_buffer[i + 1]);
+ //osd_printf_debug("0x%02x%02x, ", m_buffer[i], m_buffer[i + 1]);
+ }
+ osd_printf_debug("\n");
+ }
+
+ if (m_master_password_enable || m_user_password_enable)
+ security_error();
+ }
+ else if (m_command == IDE_COMMAND_SECURITY_DISABLE_PASSWORD)
+ {
+ LOGPRINT(("IDE Done unimplemented SECURITY_DISABLE_PASSWORD command\n"));
+ }
+ else if (m_command == IDE_COMMAND_WRITE_BUFFER)
+ {
+ set_irq(ASSERT_LINE);
+ }
+ else
+ {
+ set_dasp(ASSERT_LINE);
+
+ if (m_command == IDE_COMMAND_WRITE_MULTIPLE)
+ {
+ if (m_sectors_until_int != 1)
+ {
+ /* ready to write now */
+ finished_write();
+ }
+ else
+ {
+ /* set a timer to do the write */
+ start_busy(TIME_PER_SECTOR_WRITE, PARAM_COMMAND);
+ }
+ }
+ else
+ {
+ /* set a timer to do the write */
+ start_busy(TIME_PER_SECTOR_WRITE, PARAM_COMMAND);
+ }
+ }
+}
+
+
+void ata_mass_storage_device_base::finished_write()
+{
+ int lba = lba_address(), count;
+
+ set_dasp(CLEAR_LINE);
+
+ /* now do the write */
+ if (m_command == IDE_COMMAND_WRITE_BUFFER)
+ {
+ count = 1;
+ }
+ else
+ {
+ count = write_sector(lba, &m_buffer[0]);
+ }
+
+ /* if we succeeded, advance to the next sector and set the nice bits */
+ if (count == 1)
+ {
+ /* advance the pointers, unless this is the last sector */
+ /* Gauntlet: Dark Legacy checks to make sure we stop on the last sector */
+ if (m_sector_count != 1)
+ next_sector();
+
+ /* signal an interrupt */
+ if (--m_sectors_until_int == 0 || m_sector_count == 1)
+ {
+ m_sectors_until_int = ((m_command == IDE_COMMAND_WRITE_MULTIPLE) ? m_block_count : 1);
+ set_irq(ASSERT_LINE);
+ }
+
+ /* signal an interrupt if there's more data needed */
+ if (m_sector_count > 0)
+ m_sector_count--;
+
+ if (m_sector_count > 0)
+ {
+ m_status |= IDE_STATUS_DRQ;
+
+ if (m_command == IDE_COMMAND_WRITE_DMA)
+ set_dmarq(ASSERT_LINE);
+ }
+ }
+
+ /* if we got an error, we need to report it */
+ else
+ {
+ /* set the error flag and the error */
+ m_status |= IDE_STATUS_ERR;
+ m_error = IDE_ERROR_BAD_SECTOR;
+
+ /* signal an interrupt */
+ set_irq(ASSERT_LINE);
+ }
+}
+
+
+/*************************************
+ *
+ * Handle IDE commands
+ *
+ *************************************/
+
+void ata_mass_storage_device_base::process_command()
+{
+ m_sectors_until_int = 0;
+ m_buffer_size = IDE_DISK_SECTOR_SIZE;
+
+ switch (m_command)
+ {
+ case IDE_COMMAND_READ_SECTORS:
+ case IDE_COMMAND_READ_SECTORS_NORETRY:
+ LOGPRINT(("IDE Read multiple: C=%u H=%d S=%u LBA=%u count=%u\n",
+ (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
+
+ m_sectors_until_int = 1;
+
+ /* start the read going */
+ read_first_sector();
+ break;
+
+ case IDE_COMMAND_READ_BUFFER:
+ LOGPRINT(("IDE Read Buffer\n"));
+
+ m_sectors_until_int = 1;
+ m_buffer_offset = 0;
+
+ /* start the read going */
+ read_first_sector();
+ break;
+
+ case IDE_COMMAND_READ_MULTIPLE:
+ LOGPRINT(("IDE Read multiple block: C=%u H=%u S=%u LBA=%u count=%u\n",
+ (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
+
+ m_sectors_until_int = 1;
+
+ /* start the read going */
+ read_first_sector();
+ break;
+
+ case IDE_COMMAND_VERIFY_SECTORS:
+ case IDE_COMMAND_VERIFY_SECTORS_NORETRY:
+ LOGPRINT(("IDE Read verify multiple with/without retries: C=%u H=%u S=%u LBA=%u count=%u\n",
+ (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
+
+ /* reset the buffer */
+ m_sectors_until_int = m_sector_count;
+
+ /* start the read going */
+ read_first_sector();
+ break;
+
+ case IDE_COMMAND_READ_DMA:
+ LOGPRINT(("IDE Read multiple DMA: C=%u H=%u S=%u LBA=%u count=%u\n",
+ (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
+
+ /* reset the buffer */
+ m_sectors_until_int = m_sector_count;
+
+ /* start the read going */
+ read_first_sector();
+ break;
+
+ case IDE_COMMAND_WRITE_SECTORS:
+ case IDE_COMMAND_WRITE_SECTORS_NORETRY:
+ LOGPRINT(("IDE Write multiple: C=%u H=%u S=%u LBA=%u count=%u\n",
+ (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
+
+ /* reset the buffer */
+ m_sectors_until_int = 1;
+
+ /* mark the buffer ready */
+ m_status |= IDE_STATUS_DRQ;
+ break;
+
+ case IDE_COMMAND_WRITE_BUFFER:
+ LOGPRINT(("IDE Write Buffer\n"));
+
+ /* reset the buffer */
+ m_sectors_until_int = 1;
+ m_buffer_offset = 0;
+
+ /* mark the buffer ready */
+ m_status |= IDE_STATUS_DRQ;
+ break;
+
+ case IDE_COMMAND_WRITE_MULTIPLE:
+ LOGPRINT(("IDE Write multiple block: C=%u H=%u S=%u LBA=%u count=%u\n",
+ (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
+
+ /* reset the buffer */
+ m_sectors_until_int = m_block_count;
+
+ /* mark the buffer ready */
+ m_status |= IDE_STATUS_DRQ;
+ break;
+
+ case IDE_COMMAND_WRITE_DMA:
+ LOGPRINT(("IDE Write multiple DMA: C=%u H=%u S=%u LBA=%u count=%u\n",
+ (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
+
+ /* reset the buffer */
+ m_sectors_until_int = m_sector_count;
+
+ /* mark the buffer ready */
+ m_status |= IDE_STATUS_DRQ;
+
+ /* start the read going */
+ set_dmarq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_SECURITY_UNLOCK:
+ LOGPRINT(("IDE Security Unlock\n"));
+
+ /* mark the buffer ready */
+ m_status |= IDE_STATUS_DRQ;
+
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_SECURITY_DISABLE_PASSWORD:
+ LOGPRINT(("IDE Unimplemented SECURITY DISABLE PASSWORD command\n"));
+
+ /* mark the buffer ready */
+ m_status |= IDE_STATUS_DRQ;
+
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_IDENTIFY_DEVICE:
+ LOGPRINT(("IDE Identify device\n"));
+
+ start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
+ break;
+
+ case IDE_COMMAND_RECALIBRATE:
+ start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
+ break;
+
+ case IDE_COMMAND_IDLE:
+ /* signal an interrupt */
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_SET_CONFIG:
+ LOGPRINT(("IDE Set configuration (%u heads, %u sectors)\n", (m_device_head & IDE_DEVICE_HEAD_HS) + 1, m_sector_count));
+
+ start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
+ break;
+
+ case IDE_COMMAND_SET_MAX:
+ LOGPRINT(("IDE Set max (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_sector_number, m_cylinder_low, m_cylinder_high));
+
+ /* signal an interrupt */
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_SET_BLOCK_COUNT:
+ LOGPRINT(("IDE Set block count (%u)\n", m_sector_count));
+
+ m_block_count = m_sector_count;
+
+ /* signal an interrupt */
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_SEEK:
+ /* signal an interrupt */
+ set_irq(ASSERT_LINE);
+ break;
+
+ case IDE_COMMAND_READ_NATIVE_MAX_ADDRESS:
+ start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
+ break;
+
+ default:
+ ata_hle_device_base::process_command();
+ break;
+ }
+}
+
+//**************************************************************************
+// IDE HARD DISK DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ide_hdd_device_base - constructor
+//-------------------------------------------------
+
+ide_hdd_device_base::ide_hdd_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ ata_mass_storage_device_base(mconfig, type, tag, owner, clock),
+ m_image(*this, "image")
+{
+}
+
+void ide_hdd_device_base::device_start()
+{
+ ata_mass_storage_device_base::device_start();
+
+ /* create a timer for timing status */
+ m_last_status_timer = machine().scheduler().timer_alloc(timer_expired_delegate());
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void ide_hdd_device_base::device_reset()
+{
+ if (m_image->exists() && !m_can_identify_device)
+ {
+ const auto &hdinfo = m_image->get_info();
+ if (hdinfo.sectorbytes == IDE_DISK_SECTOR_SIZE)
+ {
+ m_num_cylinders = hdinfo.cylinders;
+ m_num_sectors = hdinfo.sectors;
+ m_num_heads = hdinfo.heads;
+ if (PRINTF_IDE_COMMANDS) osd_printf_debug("CHS: %u %u %u\n", m_num_cylinders, m_num_heads, m_num_sectors);
+ osd_printf_debug("CHS: %u %u %u\n", m_num_cylinders, m_num_heads, m_num_sectors);
+ }
+
+ // build the features page
+ std::vector<u8> ident;
+ m_image->get_inquiry_data(ident);
+ if (ident.size() == 512)
+ {
+ for( int w = 0; w < 256; w++ )
+ m_identify_buffer[w] = get_u16le(&ident[w * 2]);
+ }
+ else
+ {
+ ide_build_identify_device();
+ }
+
+ m_can_identify_device = 1;
+ }
+
+ ata_mass_storage_device_base::device_reset();
+}
+
+uint8_t ide_hdd_device_base::calculate_status()
+{
+ uint8_t result = ata_hle_device_base::calculate_status();
+
+ if (m_last_status_timer->elapsed() > TIME_PER_ROTATION)
+ {
+ result |= IDE_STATUS_IDX;
+ m_last_status_timer->adjust(attotime::never);
+ }
+
+ return result;
+}
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void ide_hdd_device_base::device_add_mconfig(machine_config &config)
+{
+ HARDDISK(config, "image", "ide_hdd,hdd");
+}
+
+//**************************************************************************
+// ATA COMPACTFLASH CARD DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// cf_device_base - constructor
+//-------------------------------------------------
+
+cf_device_base::cf_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ ide_hdd_device_base(mconfig, type, tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void cf_device_base::device_add_mconfig(machine_config &config)
+{
+ HARDDISK(config, "image", "ata_cf");
+}
+
+//-------------------------------------------------
+// ide_build_identify_device
+//-------------------------------------------------
+
+void cf_device_base::ide_build_identify_device()
+{
+ memset(m_identify_buffer, 0, sizeof(m_identify_buffer));
+ int total_sectors = m_num_cylinders * m_num_heads * m_num_sectors;
+
+ /* basic geometry */
+ m_identify_buffer[0] = 0x848a; /* 0: configuration bits */
+ m_identify_buffer[1] = m_num_cylinders; /* 1: logical cylinders */
+ m_identify_buffer[2] = 0; /* 2: reserved */
+ m_identify_buffer[3] = m_num_heads; /* 3: logical heads */
+ m_identify_buffer[4] = 0; /* 4: number of unformatted bytes per track */
+ m_identify_buffer[5] = 0; /* 5: number of unformatted bytes per sector */
+ m_identify_buffer[6] = m_num_sectors; /* 6: logical sectors per logical track */
+ m_identify_buffer[7] = total_sectors >> 16; /* 7: number of sectors per card MSW */
+ m_identify_buffer[8] = total_sectors & 0xffff; /* 8: number of sectors per card LSW */
+ m_identify_buffer[9] = 0; /* 9: vendor-specific */
+ swap_strncpy(&m_identify_buffer[10], /* 10-19: serial number */
+ "00000000000000000000", 10);
+ m_identify_buffer[20] = 0; /* 20: buffer type */
+ m_identify_buffer[21] = 0; /* 21: buffer size in 512 byte increments */
+ m_identify_buffer[22] = 4; /* 22: # of vendor-specific bytes on read/write long commands */
+ swap_strncpy(&m_identify_buffer[23], /* 23-26: firmware revision */
+ "1.0", 4);
+ swap_strncpy(&m_identify_buffer[27], /* 27-46: model number */
+ "MAME Compressed CompactFlash", 20);
+ m_identify_buffer[47] = 0x0001; /* 47: read/write multiple support */
+ m_identify_buffer[48] = 0; /* 48: double word not supported */
+ m_identify_buffer[49] = 0x0200; /* 49: capabilities */
+ m_identify_buffer[50] = 0; /* 50: reserved */
+ m_identify_buffer[51] = 0x0200; /* 51: PIO data transfer cycle timing mode */
+ m_identify_buffer[52] = 0x0000; /* 52: single word DMA transfer cycle timing mode */
+ m_identify_buffer[53] = 0x0003; /* 53: translation parameters are valid */
+ m_identify_buffer[54] = m_num_cylinders; /* 54: number of current logical cylinders */
+ m_identify_buffer[55] = m_num_heads; /* 55: number of current logical heads */
+ m_identify_buffer[56] = m_num_sectors; /* 56: number of current logical sectors per track */
+ m_identify_buffer[57] = total_sectors & 0xffff; /* 57-58: current capacity in sectors */
+ m_identify_buffer[58] = total_sectors >> 16;
+ m_identify_buffer[59] = 0; /* 59: multiple sector timing */
+ m_identify_buffer[60] = total_sectors & 0xffff; /* 60-61: total user addressable sectors for LBA mode */
+ m_identify_buffer[61] = total_sectors >> 16;
+ m_identify_buffer[62] = 0x00; /* 62-127: reserved */
+ m_identify_buffer[128] = 0x00; /* 128: security status */
+ m_identify_buffer[129] = 0x00; /* 129-159: vendor specific */
+ m_identify_buffer[160] = 0x00; /* 160: Power requirement description*/
+ m_identify_buffer[161] = 0x00; /* 161-255: reserved */
+}
+
+//-------------------------------------------------
+// seek_time
+//-------------------------------------------------
+
+attotime cf_device_base::seek_time()
+{
+ return attotime::zero;
+}
diff --git a/src/devices/machine/atastorage.h b/src/devices/machine/atastorage.h
new file mode 100644
index 00000000000..c3dc9aec416
--- /dev/null
+++ b/src/devices/machine/atastorage.h
@@ -0,0 +1,131 @@
+// license:BSD-3-Clause
+// copyright-holders:smf
+/***************************************************************************
+
+ idehd.h
+
+ IDE hard disk
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_ATASTORAGE_H
+#define MAME_MACHINE_ATASTORAGE_H
+
+#pragma once
+
+#include "atahle.h"
+
+#include "imagedev/harddriv.h"
+
+#include "harddisk.h"
+
+
+class ata_mass_storage_device_base : public ata_hle_device_base
+{
+public:
+ uint16_t *identify_device_buffer() { return m_identify_buffer; }
+
+ void set_master_password(const uint8_t *password)
+ {
+ m_master_password = password;
+ m_master_password_enable = (password != nullptr);
+ }
+
+ void set_user_password(const uint8_t *password)
+ {
+ m_user_password = password;
+ m_user_password_enable = (password != nullptr);
+ }
+
+ void set_dma_transfer_time(const attotime time) { m_dma_transfer_time = time; }
+
+protected:
+ ata_mass_storage_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+
+ virtual int read_sector(uint32_t lba, void *buffer) = 0;
+ virtual int write_sector(uint32_t lba, const void *buffer) = 0;
+ virtual attotime seek_time();
+
+ virtual void ide_build_identify_device();
+
+ static const int IDE_DISK_SECTOR_SIZE = 512;
+ virtual int sector_length() override { return IDE_DISK_SECTOR_SIZE; }
+ virtual void process_buffer() override;
+ virtual void fill_buffer() override;
+ virtual bool is_ready() override { return true; }
+ virtual void process_command() override;
+ virtual void finished_command() override;
+ virtual void perform_diagnostic() override;
+ virtual void signature() override;
+
+ int m_can_identify_device;
+ uint16_t m_num_cylinders;
+ uint8_t m_num_sectors;
+ uint8_t m_num_heads;
+
+ virtual uint32_t lba_address();
+
+private:
+ void set_geometry(uint8_t sectors, uint8_t heads) { m_num_sectors = sectors; m_num_heads = heads; }
+ void finished_read();
+ void finished_write();
+ void next_sector();
+ void security_error();
+ void read_first_sector();
+ void soft_reset() override;
+
+ uint32_t m_cur_lba;
+ uint16_t m_block_count;
+ uint16_t m_sectors_until_int;
+
+ uint8_t m_master_password_enable;
+ uint8_t m_user_password_enable;
+ const uint8_t * m_master_password;
+ const uint8_t * m_user_password;
+ // DMA data transfer time for 1 sector
+ attotime m_dma_transfer_time;
+};
+
+// ======================> ide_hdd_device_base
+
+class ide_hdd_device_base : public ata_mass_storage_device_base
+{
+protected:
+ // construction/destruction
+ ide_hdd_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ virtual int read_sector(uint32_t lba, void *buffer) override { return !m_image->exists() ? 0 : m_image->read(lba, buffer); }
+ virtual int write_sector(uint32_t lba, const void *buffer) override { return !m_image->exists() ? 0 : m_image->write(lba, buffer); }
+ virtual uint8_t calculate_status() override;
+
+ required_device<harddisk_image_device> m_image;
+
+private:
+ emu_timer *m_last_status_timer;
+};
+
+
+// ======================> cf_device_base
+
+class cf_device_base : public ide_hdd_device_base
+{
+protected:
+ // construction/destruction
+ cf_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_t implementation
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ virtual void ide_build_identify_device() override;
+ virtual attotime seek_time() override;
+ virtual uint8_t calculate_status() override { return ata_hle_device_base::calculate_status(); }
+};
+
+#endif // MAME_MACHINE_ATASTORAGE_H
diff --git a/src/devices/machine/atmel_arm_aic.cpp b/src/devices/machine/atmel_arm_aic.cpp
index 258bb3ae438..948c370fbe9 100644
--- a/src/devices/machine/atmel_arm_aic.cpp
+++ b/src/devices/machine/atmel_arm_aic.cpp
@@ -53,7 +53,7 @@ uint32_t arm_aic_device::irq_vector_r()
int midx = -1;
do
{
- uint8_t idx = 31 - count_leading_zeros(mask);
+ uint8_t idx = 31 - count_leading_zeros_32(mask);
if ((int)(m_aic_smr[idx] & 7) >= pri)
{
midx = idx;
@@ -86,8 +86,6 @@ uint32_t arm_aic_device::firq_vector_r()
void arm_aic_device::device_start()
{
- m_irq_out.resolve_safe();
-
save_item(NAME(m_irqs_enabled));
save_item(NAME(m_irqs_pending));
save_item(NAME(m_current_irq_vector));
@@ -146,7 +144,7 @@ void arm_aic_device::check_irqs()
int pri = get_level();
do
{
- uint8_t idx = 31 - count_leading_zeros(mask);
+ uint8_t idx = 31 - count_leading_zeros_32(mask);
if ((int)(m_aic_smr[idx] & 7) > pri)
{
m_core_status |= 2;
diff --git a/src/devices/machine/atmel_arm_aic.h b/src/devices/machine/atmel_arm_aic.h
index cc0388d21f3..72659841f3a 100644
--- a/src/devices/machine/atmel_arm_aic.h
+++ b/src/devices/machine/atmel_arm_aic.h
@@ -46,35 +46,35 @@ private:
devcb_write_line m_irq_out;
void check_irqs();
- void set_lines() { m_irq_out((m_core_status & ~m_debug & 2) ? ASSERT_LINE : CLEAR_LINE); }; // TODO FIQ
+ void set_lines() { m_irq_out((m_core_status & ~m_debug & 2) ? ASSERT_LINE : CLEAR_LINE); } // TODO FIQ
- void push_level(int lvl) { m_level_stack[++m_lvlidx] = lvl; };
- void pop_level() { if (m_lvlidx) --m_lvlidx; };
- int get_level() { return m_level_stack[m_lvlidx]; };
+ void push_level(int lvl) { m_level_stack[++m_lvlidx] = lvl; }
+ void pop_level() { if (m_lvlidx) --m_lvlidx; }
+ int get_level() { return m_level_stack[m_lvlidx]; }
uint32_t irq_vector_r();
uint32_t firq_vector_r();
- uint32_t aic_isr_r() { return m_status; };
- uint32_t aic_cisr_r() { return m_core_status; };
- uint32_t aic_ipr_r() { return m_irqs_pending; };
- uint32_t aic_imr_r() { return m_irqs_enabled; };
- uint32_t aic_ffsr_r() { return m_fast_irqs; };
+ uint32_t aic_isr_r() { return m_status; }
+ uint32_t aic_cisr_r() { return m_core_status; }
+ uint32_t aic_ipr_r() { return m_irqs_pending; }
+ uint32_t aic_imr_r() { return m_irqs_enabled; }
+ uint32_t aic_ffsr_r() { return m_fast_irqs; }
// can't use ram() and share() in device submaps
- uint32_t aic_smr_r(offs_t offset) { return m_aic_smr[offset]; };
- uint32_t aic_svr_r(offs_t offset) { return m_aic_svr[offset]; };
- void aic_smr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_aic_smr[offset]); };
- void aic_svr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_aic_svr[offset]); };
- void aic_spu_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_spurious_vector); };
- void aic_dcr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_debug); check_irqs(); };
- void aic_ffer_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_fast_irqs |= data & mem_mask; check_irqs(); };
- void aic_ffdr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_fast_irqs &= ~(data & mem_mask) | 1; check_irqs(); };
-
- void aic_iecr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_enabled |= data & mem_mask; check_irqs(); };
- void aic_idcr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_enabled &= ~(data & mem_mask); check_irqs(); };
- void aic_iccr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_pending &= ~(data & mem_mask); check_irqs(); };
- void aic_iscr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_pending |= data & mem_mask; check_irqs(); };
- void aic_eoicr_w(uint32_t data) { m_status = 0; pop_level(); check_irqs(); };
+ uint32_t aic_smr_r(offs_t offset) { return m_aic_smr[offset]; }
+ uint32_t aic_svr_r(offs_t offset) { return m_aic_svr[offset]; }
+ void aic_smr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_aic_smr[offset]); }
+ void aic_svr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_aic_svr[offset]); }
+ void aic_spu_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_spurious_vector); }
+ void aic_dcr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { COMBINE_DATA(&m_debug); check_irqs(); }
+ void aic_ffer_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_fast_irqs |= data & mem_mask; check_irqs(); }
+ void aic_ffdr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_fast_irqs &= ~(data & mem_mask) | 1; check_irqs(); }
+
+ void aic_iecr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_enabled |= data & mem_mask; check_irqs(); }
+ void aic_idcr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_enabled &= ~(data & mem_mask); check_irqs(); }
+ void aic_iccr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_pending &= ~(data & mem_mask); check_irqs(); }
+ void aic_iscr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0) { m_irqs_pending |= data & mem_mask; check_irqs(); }
+ void aic_eoicr_w(uint32_t data) { m_status = 0; pop_level(); check_irqs(); }
};
#endif
diff --git a/src/devices/machine/ay31015.cpp b/src/devices/machine/ay31015.cpp
index a3cbbe456aa..732470d1b9f 100644
--- a/src/devices/machine/ay31015.cpp
+++ b/src/devices/machine/ay31015.cpp
@@ -104,8 +104,8 @@ Start bit (low), Bit 0, Bit 1... highest bit, Parity bit (if enabled), 1-2 stop
DEFINE_DEVICE_TYPE(AY31015, ay31015_device, "ay31015", "AY-3-1015 UART")
DEFINE_DEVICE_TYPE(AY51013, ay51013_device, "ay51013", "AY-5-1013 UART")
-ay31015_device::ay31015_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
+ay31015_device::ay31015_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
m_control_reg(0),
m_status_reg(0),
m_second_stop_bit(0),
@@ -120,7 +120,7 @@ ay31015_device::ay31015_device(const machine_config &mconfig, device_type type,
m_tx_buffer(0),
m_tx_parity(0),
m_tx_pulses(0),
- m_read_si_cb(*this),
+ m_read_si_cb(*this, 0),
m_write_so_cb(*this),
m_write_pe_cb(*this),
m_write_fe_cb(*this),
@@ -145,25 +145,6 @@ ay51013_device::ay51013_device(const machine_config &mconfig, const char *tag, d
}
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void ay31015_device::device_resolve_objects()
-{
- m_read_si_cb.resolve();
- m_write_so_cb.resolve();
-
- m_write_tbmt_cb.resolve();
- m_write_dav_cb.resolve();
- m_write_or_cb.resolve();
- m_write_fe_cb.resolve();
- m_write_pe_cb.resolve();
- m_write_eoc_cb.resolve();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -208,7 +189,7 @@ void ay31015_device::device_reset()
inline uint8_t ay31015_device::get_si()
{
- if (!m_read_si_cb.isnull())
+ if (!m_read_si_cb.isunset())
m_pins[SI] = m_read_si_cb();
return m_pins[SI];
@@ -218,9 +199,7 @@ inline uint8_t ay31015_device::get_si()
inline void ay31015_device::set_so( int data )
{
m_pins[SO] = data ? 1 : 0;
-
- if (!m_write_so_cb.isnull())
- m_write_so_cb(m_pins[SO]);
+ m_write_so_cb(m_pins[SO]);
}
@@ -231,8 +210,7 @@ inline void ay31015_device::update_status_pin(uint8_t reg_bit, ay31015_device::o
if (new_value != m_pins[pin])
{
m_pins[pin] = new_value;
- if (!write_cb.isnull())
- write_cb(new_value);
+ write_cb(new_value);
}
}
diff --git a/src/devices/machine/ay31015.h b/src/devices/machine/ay31015.h
index 4e27bc8e11f..beaac297765 100644
--- a/src/devices/machine/ay31015.h
+++ b/src/devices/machine/ay31015.h
@@ -32,27 +32,27 @@ public:
auto write_eoc_callback() { return m_write_eoc_cb.bind(); }
/* Set an input pin */
- DECLARE_WRITE_LINE_MEMBER(write_swe) { set_input_pin(SWE, state); }
- DECLARE_WRITE_LINE_MEMBER(write_rcp) { set_input_pin(RCP, state); }
- DECLARE_WRITE_LINE_MEMBER(write_rdav) { set_input_pin(RDAV, state); }
- DECLARE_WRITE_LINE_MEMBER(write_si) { set_input_pin(SI, state); }
- DECLARE_WRITE_LINE_MEMBER(write_xr) { set_input_pin(XR, state); }
- DECLARE_WRITE_LINE_MEMBER(write_cs) { set_input_pin(CS, state); }
- DECLARE_WRITE_LINE_MEMBER(write_np) { set_input_pin(NP, state); }
- DECLARE_WRITE_LINE_MEMBER(write_tsb) { set_input_pin(TSB, state); }
- DECLARE_WRITE_LINE_MEMBER(write_nb2) { set_input_pin(NB2, state); }
- DECLARE_WRITE_LINE_MEMBER(write_nb1) { set_input_pin(NB1, state); }
- DECLARE_WRITE_LINE_MEMBER(write_eps) { set_input_pin(EPS, state); }
- DECLARE_WRITE_LINE_MEMBER(write_tcp) { set_input_pin(TCP, state); }
+ void write_swe(int state) { set_input_pin(SWE, state); }
+ void write_rcp(int state) { set_input_pin(RCP, state); }
+ void write_rdav(int state) { set_input_pin(RDAV, state); }
+ void write_si(int state) { set_input_pin(SI, state); }
+ void write_xr(int state) { set_input_pin(XR, state); }
+ void write_cs(int state) { set_input_pin(CS, state); }
+ void write_np(int state) { set_input_pin(NP, state); }
+ void write_tsb(int state) { set_input_pin(TSB, state); }
+ void write_nb2(int state) { set_input_pin(NB2, state); }
+ void write_nb1(int state) { set_input_pin(NB1, state); }
+ void write_eps(int state) { set_input_pin(EPS, state); }
+ void write_tcp(int state) { set_input_pin(TCP, state); }
/* Get an output pin */
- DECLARE_READ_LINE_MEMBER(pe_r) { return get_output_pin(PE); }
- DECLARE_READ_LINE_MEMBER(fe_r) { return get_output_pin(FE); }
- DECLARE_READ_LINE_MEMBER(or_r) { return get_output_pin(OR); }
- DECLARE_READ_LINE_MEMBER(dav_r) { return get_output_pin(DAV); }
- DECLARE_READ_LINE_MEMBER(tbmt_r) { return get_output_pin(TBMT); }
- DECLARE_READ_LINE_MEMBER(eoc_r) { return get_output_pin(EOC); }
- DECLARE_READ_LINE_MEMBER(so_r) { return get_output_pin(SO); }
+ int pe_r() { return get_output_pin(PE); }
+ int fe_r() { return get_output_pin(FE); }
+ int or_r() { return get_output_pin(OR); }
+ int dav_r() { return get_output_pin(DAV); }
+ int tbmt_r() { return get_output_pin(TBMT); }
+ int eoc_r() { return get_output_pin(EOC); }
+ int so_r() { return get_output_pin(SO); }
/* Read the received data */
/* The received data is available on RD8-RD1 (pins 5-12) */
@@ -103,8 +103,7 @@ protected:
ay31015_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/bacta_datalogger.cpp b/src/devices/machine/bacta_datalogger.cpp
new file mode 100644
index 00000000000..1b00a051314
--- /dev/null
+++ b/src/devices/machine/bacta_datalogger.cpp
@@ -0,0 +1,217 @@
+// license:BSD-3-Clause
+// copyright-holders:James Wallace
+#include "emu.h"
+#include "bacta_datalogger.h"
+
+#define LOG_DATA (1U << 1)
+
+//#define VERBOSE (LOG_DATA)
+//#define LOG_OUTPUT_STREAM std::cout
+
+#include "logmacro.h"
+
+#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__)
+
+/***********************************************************************************************************
+ BACTA Datalogger emulation
+ The British Amusement and Catering Trade Association created a standard for the tracking of statistics
+ and other features on British AWPs across hardware manufacturers.
+ The specification is very simple, a 1200 Baud null modem connection via RS232, with the logger sending an
+ ACK command (0x06) on receipt of a valid character, and NAK (0x15) on error.
+ In this emulation, the simplest possible device is simulated here, derived from the RS232 null_modem.
+ We only handle the feedback for acknowledgment, and limited logging.
+************************************************************************************************************/
+
+// device type definition
+DEFINE_DEVICE_TYPE(BACTA_DATALOGGER, bacta_datalogger_device, "bacta_datalogger", "BACTA Datalogger")
+
+//-------------------------------------------------
+// bacta_datalogger_device - constructor
+//-------------------------------------------------
+
+bacta_datalogger_device::bacta_datalogger_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ bacta_datalogger_device(mconfig, BACTA_DATALOGGER, tag, owner, clock)
+{
+}
+
+bacta_datalogger_device::bacta_datalogger_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, BACTA_DATALOGGER, tag, owner, clock),
+ device_serial_interface(mconfig, *this),
+ m_rxd_handler(*this),
+ m_last_input(-1),
+ m_output_char(0)
+{
+}
+
+void bacta_datalogger_device::device_start()
+{
+}
+
+void bacta_datalogger_device::device_reset()
+{
+ int startbits = 1;
+ int databits = 8;
+ parity_t parity = device_serial_interface::PARITY_ODD;
+ stop_bits_t stopbits = device_serial_interface::STOP_BITS_1;
+
+ set_data_frame(startbits, databits, parity, stopbits);
+
+ set_tra_rate(1200);
+
+ set_rcv_rate(1200);
+
+ output_rxd(1);
+}
+
+void bacta_datalogger_device::tx_queue()
+{
+ if (is_transmit_register_empty())
+ {
+ if (m_output_char != 255)
+ {
+ set_tra_rate(1200);
+ transmit_register_setup(m_output_char);
+ m_output_char = 255;
+ }
+ }
+}
+
+void bacta_datalogger_device::tra_callback()
+{
+ output_rxd(transmit_register_get_data_bit());
+}
+
+void bacta_datalogger_device::tra_complete()
+{
+ // Shut down transmitter until there's a character
+ set_tra_rate(attotime::never);
+ tx_queue();
+}
+
+void bacta_datalogger_device::rcv_complete()
+{
+ u8 data;
+
+ receive_register_extract();
+
+ data = get_received_char();
+ if (data != 0x00)
+ {
+ if (data > 0x80)
+ {
+ data &= ~0x80;
+ if ( data == m_last_input)
+ {
+ LOGDATA("Retransmission of %x\n",data);
+ }
+ m_last_input = data;
+ }
+ switch (data)
+ {
+ case 0x01:
+ LOGDATA("(%c) Prize 1 vend or 0x01\n",data);
+ break;
+ case 0x02:
+ LOGDATA("(%c) Prize 2 vend or 0x02\n",data);
+ break;
+ case 0x03:
+ LOGDATA("(%c) Prize 3 vend or 0x03\n",data);
+ break;
+ case 0x04:
+ LOGDATA("(%c) Prize 4 vend or 0x04\n",data);
+ break;
+ case 0x05:
+ LOGDATA("(%c) Remote Credit or 0x05\n",data);
+ break;
+ case 0x07:
+ LOGDATA("(%c) Idle or 0x07\n",data);
+ break;
+ case 0x08:
+ LOGDATA("(%c) Change or 0x08\n",data);
+ break;
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ LOGDATA("(%c) User defined message or 0x0%x\n",data,data);
+ break;
+ case 0x2b:
+ LOGDATA("(%c) Cashbox door open 0x2b\n",data);
+ break;
+ case 0x2c:
+ LOGDATA("(%c) Cashbox door closed 0x2c\n",data);
+ break;
+ case 0x2d:
+ LOGDATA("(%c) Service door open 0x2d\n",data);
+ break;
+ case 0x2e:
+ LOGDATA("(%c) Service door closed 0x2e\n",data);
+ break;
+ case 0x60:
+ LOGDATA("(%c) Primary message (0x%x), next byte is message length\n",data,data);
+ break;
+ case 0x61:
+ LOGDATA("(%c) Coin Tube / Hopper Levels 0x61 \n",data);
+ break;
+ case 0x62:
+ LOGDATA("(%c) Secondary message (0x%x), next byte is message length\n",data,data);
+ break;
+ case 0x63:
+ LOGDATA("(%c) Critical Fault 0x63\n",data);
+ break;
+ case 0x64:
+ LOGDATA("(%c) Non Critical Fault 0x64\n",data);
+ break;
+ case 0x65:
+ LOGDATA("(%c) Manufacturer Message Header 0x65, next byte is message length\n",data);
+ break;
+ case 0x66:
+ LOGDATA("(%c) Potential Parameter Data request 0x66, not currently supported\n",data);
+ break;
+ case 0x67:
+ LOGDATA("(%c) Potential Parameter Report request 0x67, not currently supported\n",data);
+ break;
+ case 0x68:
+ LOGDATA("(%c) Multi-Stake Multi-Game message 0x68\n",data);
+ break;
+ case 0x69:
+ LOGDATA("(%c) Cashless source 0x69\n",data);
+ break;
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f:
+ LOGDATA("(%c) User defined message (0x%x), next byte is message length\n",data,data);
+ break;
+
+ default:
+ LOGDATA("(%c) Received: %02x\n",data, data);
+ break;
+ }
+ m_output_char = 0x06;//ACK
+ tx_queue();
+ }
+ else
+ {
+ if (data != 0x00)
+ {
+ m_output_char = 0x15;//NAK
+ tx_queue();
+ }
+ }
+}
diff --git a/src/devices/machine/bacta_datalogger.h b/src/devices/machine/bacta_datalogger.h
new file mode 100644
index 00000000000..a2592a0d183
--- /dev/null
+++ b/src/devices/machine/bacta_datalogger.h
@@ -0,0 +1,39 @@
+// license:BSD-3-Clause
+// copyright-holders:James Wallace
+#ifndef MAME_MACHINE_BACTA_DATALOGGER_H
+#define MAME_MACHINE_BACTA_DATALOGGER_H
+
+#include "diserial.h"
+
+class bacta_datalogger_device : public device_t,
+ public device_serial_interface
+{
+public:
+ bacta_datalogger_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ virtual void write_txd(int state) {device_serial_interface::rx_w(state); }
+ auto rxd_handler() { return m_rxd_handler.bind(); }
+
+ void output_rxd(int state) { m_rxd_handler(state); }
+
+protected:
+ bacta_datalogger_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void tra_callback() override;
+ virtual void tra_complete() override;
+ virtual void rcv_complete() override;
+
+private:
+ void tx_queue();
+
+ devcb_write_line m_rxd_handler;
+ uint8_t m_last_input;
+ uint8_t m_output_char;
+};
+
+DECLARE_DEVICE_TYPE(BACTA_DATALOGGER, bacta_datalogger_device)
+
+#endif // MAME_MACHINE_BACTA_DATALOGGER_H
diff --git a/src/devices/machine/bitmap_printer.cpp b/src/devices/machine/bitmap_printer.cpp
new file mode 100644
index 00000000000..ca552a14694
--- /dev/null
+++ b/src/devices/machine/bitmap_printer.cpp
@@ -0,0 +1,484 @@
+// license:BSD-3-Clause
+// copyright-holders: Golden Child
+/*********************************************************************
+
+ bitmap_printer.cpp
+
+ Implementation of Bitmap Printer
+
+**********************************************************************/
+
+#include "emu.h"
+#include "video.h"
+#include "screen.h"
+#include "emuopts.h"
+#include "fileio.h"
+#include "png.h"
+#include "bitmap_printer.h"
+#include "corestr.h"
+
+/***************************************************************************
+ DEVICE DECLARATION
+***************************************************************************/
+
+DEFINE_DEVICE_TYPE(BITMAP_PRINTER, bitmap_printer_device, "bitmap_printer", "Bitmap Printer Device")
+
+//**************************************************************************
+// INPUT PORTS
+//**************************************************************************
+
+#define PORT_ADJUSTER_16MASK(_default, _name) \
+ configurer.field_alloc(IPT_ADJUSTER, (_default), 0xffff, (_name)); \
+ configurer.field_set_min_max(0, 100);
+
+INPUT_PORTS_START(bitmap_printer)
+ PORT_START("DRAWMARKS")
+ PORT_CONFNAME(0x3, 0x02, "Draw Inch Marks")
+ PORT_CONFSETTING(0x0, "Off")
+ PORT_CONFSETTING(0x1, "with marks")
+ PORT_CONFSETTING(0x2, "with numbers")
+
+ PORT_START("TOPMARGIN")
+ PORT_ADJUSTER_16MASK(18, "Printer Top Margin")
+ PORT_MINMAX(0,500)
+
+ PORT_START("BOTTOMMARGIN")
+ PORT_ADJUSTER_16MASK(18, "Printer Bottom Margin")
+ PORT_MINMAX(0,500)
+
+INPUT_PORTS_END
+
+
+ioport_constructor bitmap_printer_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(bitmap_printer);
+}
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void bitmap_printer_device::device_add_mconfig(machine_config &config)
+{
+ // video hardware (simulates paper)
+ screen_device &screen(SCREEN(config, m_screen, SCREEN_TYPE_RASTER));
+ screen.set_refresh_hz(60);
+ screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ screen.set_size(m_paper_width, PAPER_SCREEN_HEIGHT);
+ screen.set_visarea(0, m_paper_width - 1, 0, PAPER_SCREEN_HEIGHT - 1);
+ screen.set_screen_update(FUNC(bitmap_printer_device::screen_update_bitmap));
+
+ STEPPER(config, m_pf_stepper, (uint8_t) 0xa);
+ STEPPER(config, m_cr_stepper, (uint8_t) 0xa);
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+bitmap_printer_device::bitmap_printer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_cr_direction(1),
+ m_xpos(0),
+ m_ypos(0),
+ m_screen(*this, "screen"),
+ m_pf_stepper(*this, "pf_stepper"),
+ m_cr_stepper(*this, "cr_stepper"),
+ m_top_margin_ioport(*this, "TOPMARGIN"),
+ m_bottom_margin_ioport(*this, "BOTTOMMARGIN"),
+ m_draw_marks_ioport(*this, "DRAWMARKS"),
+ m_printhead_color(0x00EE00),
+ m_printhead_bordercolor(0xEE0000),
+ m_printhead_bordersize(2),
+ m_printhead_xsize(10),
+ m_printhead_ysize(20),
+ m_page_dirty(0),
+ m_paper_width(0),
+ m_paper_height(0),
+ m_hdpi(0),
+ m_vdpi(0),
+ m_clear_pos(0),
+ m_newpage_flag(0),
+ m_led_state{0,1,1,1,1},
+ m_num_leds(1),
+ m_pf_stepper_ratio0(1),
+ m_pf_stepper_ratio1(1),
+ m_cr_stepper_ratio0(1),
+ m_cr_stepper_ratio1(1)
+{
+}
+
+bitmap_printer_device::bitmap_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ bitmap_printer_device(mconfig, BITMAP_PRINTER, tag, owner, clock)
+{
+}
+
+bitmap_printer_device::bitmap_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, int paper_width, int paper_height, int hdpi, int vdpi) :
+ bitmap_printer_device(mconfig, tag, owner, u32(0))
+{
+ m_paper_width = paper_width;
+ m_paper_height = paper_height;
+ m_hdpi = hdpi;
+ m_vdpi = vdpi;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void bitmap_printer_device::device_start()
+{
+ m_page_bitmap.allocate(m_paper_width, m_paper_height);
+ m_page_bitmap.fill(0xffffff); // Start with a white piece of paper
+
+ save_item(NAME(m_page_bitmap));
+ save_item(NAME(m_xpos));
+ save_item(NAME(m_ypos));
+ save_item(NAME(m_cr_direction));
+ save_item(NAME(m_pf_stepper_ratio0));
+ save_item(NAME(m_pf_stepper_ratio1));
+ save_item(NAME(m_cr_stepper_ratio0));
+ save_item(NAME(m_cr_stepper_ratio1));
+ save_item(NAME(m_printhead_color));
+ save_item(NAME(m_printhead_bordercolor));
+ save_item(NAME(m_printhead_bordersize));
+ save_item(NAME(m_printhead_xsize));
+ save_item(NAME(m_printhead_ysize));
+ save_item(NAME(m_page_dirty));
+ save_item(NAME(m_paper_width));
+ save_item(NAME(m_paper_height));
+ save_item(NAME(m_hdpi));
+ save_item(NAME(m_vdpi));
+ save_item(NAME(m_clear_pos));
+ save_item(NAME(m_newpage_flag));
+}
+
+void bitmap_printer_device::device_reset_after_children()
+{
+ m_ypos = get_top_margin();
+}
+
+void bitmap_printer_device::device_reset()
+{
+}
+
+//-------------------------------------------------
+// SCREEN UPDATE FUNCTIONS
+//-------------------------------------------------
+
+int bitmap_printer_device::calc_scroll_y(bitmap_rgb32& bitmap)
+{
+ return bitmap.height() - m_distfrombottom - m_ypos;
+}
+
+uint32_t bitmap_printer_device::screen_update_bitmap(screen_device &screen,
+ bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ static constexpr u32 top_edge_color = 0xEEE8AA;
+ static constexpr u32 bottom_edge_color = 0xEE8844;
+ static constexpr u32 coverup_color = 0xDDDDDD;
+
+ int scrolly = calc_scroll_y(bitmap);
+
+ copyscrollbitmap(bitmap, m_page_bitmap, 0, nullptr, 1, &scrolly, cliprect);
+
+ // draw a line on the very top of the top edge of page
+ bitmap.plot_box(0, bitmap.height() - m_distfrombottom - m_ypos, m_paper_width, 2, top_edge_color);
+ // draw a line on the bottom edge of page
+ bitmap.plot_box(0, bitmap.height() - m_distfrombottom - m_ypos + m_paper_height, m_paper_width, 2, bottom_edge_color);
+ // cover up visible parts of current page at the bottom
+ bitmap.plot_box(0, bitmap.height() - m_distfrombottom - m_ypos + m_paper_height + 2, m_paper_width, m_distfrombottom, coverup_color);
+
+ draw_printhead(bitmap, std::max(m_xpos, 0) , bitmap.height() - m_distfrombottom);
+
+ draw_inch_marks(bitmap);
+
+ return 0;
+}
+
+//-------------------------------------------------
+// BITMAP CLEARING FUNCTIONS
+//-------------------------------------------------
+
+void bitmap_printer_device::clear_to_pos(int to_line, u32 color)
+{
+ int from_line = m_clear_pos;
+ to_line = std::min(m_page_bitmap.height(), to_line);
+ if (to_line >= from_line)
+ {
+ bitmap_clear_band(m_page_bitmap, from_line, to_line, color);
+ }
+ m_clear_pos = std::max(m_clear_pos, to_line + 1);
+}
+
+void bitmap_printer_device::bitmap_clear_band(int from_line, int to_line, u32 color)
+{
+ bitmap_clear_band(m_page_bitmap, from_line, to_line, color);
+}
+
+void bitmap_printer_device::bitmap_clear_band(bitmap_rgb32 &bitmap, int from_line, int to_line, u32 color)
+{
+ bitmap.plot_box(0, from_line, m_paper_width, to_line - from_line + 1, color);
+}
+
+//-------------------------------------------------
+// PRINTHEAD FUNCTIONS
+//-------------------------------------------------
+
+void bitmap_printer_device::set_printhead_color(int headcolor, int bordcolor)
+{
+ m_printhead_color = headcolor;
+ m_printhead_bordercolor = bordcolor;
+}
+
+void bitmap_printer_device::set_printhead_size(int xsize, int ysize, int bordersize)
+{
+ m_printhead_xsize = xsize;
+ m_printhead_ysize = ysize;
+ m_printhead_bordersize = bordersize;
+}
+
+void bitmap_printer_device::set_led_state(int led, int value)
+{
+ m_led_state[led] = value;
+ m_num_leds = std::max(m_num_leds, led);
+}
+
+void bitmap_printer_device::setheadpos(int x, int y)
+{
+ if (m_xpos != x)
+ {
+ m_newpage_flag = 0;
+ }
+ m_xpos = x;
+ m_ypos = y;
+}
+
+u32 bitmap_printer_device::dimcolor(u32 incolor, int factor)
+{
+ return (((incolor & 0xff0000) >> 16) / factor << 16) |
+ (((incolor & 0xff00) >> 8) / factor << 8) |
+ (((incolor & 0xff) >> 0) / factor);
+}
+
+void bitmap_printer_device::draw_printhead(bitmap_rgb32 &bitmap, int x, int y)
+{
+ int bordx = m_printhead_bordersize;
+ int bordy = m_printhead_bordersize;
+ int offy = 9 + bordy;
+ int sizex = m_printhead_xsize;
+ int sizey = m_printhead_ysize;
+ bitmap.plot_box(x - sizex / 2- bordx, y + offy - bordy, sizex + 2 * bordx, sizey + bordy * 2,
+ m_led_state[0] ? m_printhead_bordercolor : dimcolor(m_printhead_bordercolor, 4));
+
+ for (int i = 1; i <= m_num_leds; i++)
+ bitmap.plot_box(x - sizex / 2, y + offy + ((i -1) * sizey / m_num_leds), sizex,
+ ((i+1) * sizey / m_num_leds) - (i * sizey / m_num_leds),
+ m_led_state[i] ? m_printhead_color : dimcolor(m_printhead_color, 4));
+}
+
+//-------------------------------------------------
+// DRAW INCH MARKS AND NUMBERS
+//-------------------------------------------------
+
+void bitmap_printer_device::draw7seg(u8 data, bool is_digit, int x0, int y0, int width, int height, int thick, bitmap_rgb32 &bitmap, u32 color, u32 erasecolor)
+{
+ // pass nonzero erasecolor to erase blank segments
+ const u8 pat[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 };
+ u8 seg = is_digit ? pat[data & 0xf] : data;
+
+ if (BIT(seg,0) || erasecolor) bitmap.plot_box(x0, y0, width, thick, BIT(seg,0) ? color : erasecolor);
+ if (BIT(seg,1) || erasecolor) bitmap.plot_box(x0+width, y0+thick, thick, height, BIT(seg,1) ? color : erasecolor);
+ if (BIT(seg,2) || erasecolor) bitmap.plot_box(x0+width, y0+2*thick+height, thick, height, BIT(seg,2) ? color : erasecolor);
+ if (BIT(seg,3) || erasecolor) bitmap.plot_box(x0, y0+2*thick+2*height, width, thick, BIT(seg,3) ? color : erasecolor);
+ if (BIT(seg,4) || erasecolor) bitmap.plot_box(x0-thick, y0+2*thick+height, thick, height, BIT(seg,4) ? color : erasecolor);
+ if (BIT(seg,5) || erasecolor) bitmap.plot_box(x0-thick, y0+thick, thick, height, BIT(seg,5) ? color : erasecolor);
+ if (BIT(seg,6) || erasecolor) bitmap.plot_box(x0, y0+thick+height, width, thick, BIT(seg,6) ? color : erasecolor);
+ if (BIT(seg,7) || erasecolor) bitmap.plot_box(x0+width+thick, y0+2*thick+2*height, thick, thick, BIT(seg,7) ? color : erasecolor); // draw dot
+}
+
+void bitmap_printer_device::draw_number(int number, int x, int y, bitmap_rgb32& bitmap)
+{
+ std::string s(std::to_string(number));
+
+ int width = std::max(m_hdpi / 15, 1); // 1/10 of inch
+ int height = std::max(m_vdpi / 30, 1);
+ int thick = std::max(m_vdpi / 72, 1);
+
+ for (int i = s.length() - 1; i >= 0; i--)
+ draw7seg( s.at(i) - 0x30, true,
+ x + ( i - s.length()) * (3 * width) - (width), y + height * 3 / 2,
+ width, height, thick, bitmap, 0x000000, 0);
+}
+
+void bitmap_printer_device::draw_inch_marks(bitmap_rgb32& bitmap)
+{
+ static constexpr u32 dark_grey_color = 0x202020;
+ static constexpr u32 light_grey_color = 0xc0c0c0;
+
+ int drawmarks = m_draw_marks_ioport->read();
+ if (!drawmarks) return;
+
+ for (int i = 0; i < m_vdpi * 11; i += m_vdpi / 4)
+ {
+ int adj_i = i + calc_scroll_y(bitmap) % m_paper_height;
+ int barbase = m_vdpi / 6;
+ int barwidth = ((i % m_vdpi) == 0) ? barbase * 2 : barbase;
+ int barcolor = ((i % m_vdpi) == 0) ? dark_grey_color : light_grey_color;
+ if (adj_i < bitmap.height())
+ {
+ bitmap.plot_box(bitmap.width() - 1 - barwidth, adj_i, barwidth, 1, barcolor);
+ if ((i % m_vdpi) == 0)
+ {
+ if (drawmarks & 2)
+ draw_number(i / m_vdpi, bitmap.width(), adj_i, bitmap);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------
+// DRAW PIXEL FUNCTIONS
+//-------------------------------------------------
+
+void bitmap_printer_device::draw_pixel(int x, int y, int pixelval)
+{
+ if (y >= m_page_bitmap.height()) y = m_page_bitmap.height() - 1;
+ if (x >= m_page_bitmap.width()) x = m_page_bitmap.width() - 1;
+
+ m_page_bitmap.pix(y, x) = pixelval;
+
+ m_page_dirty = 1;
+};
+
+int bitmap_printer_device::get_pixel(int x, int y)
+{
+ if (y >= m_page_bitmap.height()) y = m_page_bitmap.height() - 1;
+ if (x >= m_page_bitmap.width()) x = m_page_bitmap.width() - 1;
+
+ return m_page_bitmap.pix(y, x);
+};
+
+unsigned int& bitmap_printer_device::pix(int y, int x) // reversed y x
+{
+ if (y >= m_page_bitmap.height()) y = m_page_bitmap.height() - 1;
+ if (x >= m_page_bitmap.width()) x = m_page_bitmap.width() - 1;
+
+ return m_page_bitmap.pix(y,x);
+};
+
+//-------------------------------------------------
+// WRITE SNAPSHOT TO FILE
+//-------------------------------------------------
+
+void bitmap_printer_device::write_snapshot_to_file()
+{
+ machine().popmessage("writing printer snapshot");
+
+ emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ std::error_condition const filerr = machine().video().open_next(file, "png");
+
+ if (!filerr)
+ {
+ static const rgb_t png_palette[] = { rgb_t::white(), rgb_t::black() };
+
+ // save the paper into a png
+ util::png_write_bitmap(file, nullptr, m_page_bitmap, 2, png_palette);
+ }
+}
+
+//-------------------------------------------------
+// STEPPER AND MARGIN FUNCTIONS
+//-------------------------------------------------
+
+int bitmap_printer_device::get_top_margin() { return m_top_margin_ioport->read(); }
+int bitmap_printer_device::get_bottom_margin() { return m_bottom_margin_ioport->read(); }
+
+bool bitmap_printer_device::check_new_page()
+{
+ bool retval = false;
+
+ // idea here is that you update the position, then check the page, this will do the saving of the page
+ // if this routine returns true, means there's a new page and you should clear the yposition
+ if (m_newpage_flag == 1)
+ {
+ // if you change m_ypos you have to change the stepper abs position too
+ m_ypos = get_top_margin(); // lock to the top of page until we seek horizontally
+ m_pf_stepper->set_absolute_position(get_top_margin() / m_pf_stepper_ratio0 * m_pf_stepper_ratio1);
+ }
+
+ // If we are at the bottom of the page we will
+ // write the page to a file, then erase the top part of the page
+ // so we can still see the last page printed.
+ if (m_ypos > m_page_bitmap.height() - 1 - get_bottom_margin())
+ {
+ // clear paper to bottom from current position
+ clear_to_pos(m_paper_height - 1, rgb_t::white());
+
+ // save a snapshot
+ write_snapshot_to_file();
+
+ m_newpage_flag = 1;
+
+ // clear page down to visible area, starting from the top of page
+ m_clear_pos = 0;
+ clear_to_pos(m_paper_height - 1 - PAPER_SCREEN_HEIGHT),
+
+ m_ypos = get_top_margin(); // lock to the top of page until we seek horizontally
+ m_pf_stepper->set_absolute_position(get_top_margin() / m_pf_stepper_ratio0 * m_pf_stepper_ratio1);
+ retval = true;
+ }
+ else
+ {
+ clear_to_pos ( m_ypos + m_distfrombottom);
+ }
+ return retval;
+}
+
+int bitmap_printer_device::update_stepper_delta(stepper_device * stepper, uint8_t pattern)
+{
+ int lastpos = stepper->get_absolute_position();
+ stepper->update(pattern);
+ int delta = stepper->get_absolute_position() - lastpos;
+ return delta;
+}
+
+// When sending patterns to the update_cr_stepper and update_pf_stepper
+// functions, the stepper device uses a "standard drive table"
+// so you have to match that drive table by using a bitswap function.
+// If the stepper drive is in the opposite direction, just reverse the
+// bits in the bitswap.
+
+void bitmap_printer_device::update_cr_stepper(int pattern)
+{
+ int delta = update_stepper_delta(m_cr_stepper, pattern);
+
+ if (delta != 0)
+ {
+ m_newpage_flag = 0;
+
+ if (delta > 0) {m_cr_direction = 1;}
+ else if (delta < 0) {m_cr_direction = -1;}
+ }
+ m_xpos = m_cr_stepper->get_absolute_position() * m_cr_stepper_ratio0 / m_cr_stepper_ratio1;
+}
+
+void bitmap_printer_device::update_pf_stepper(int pattern)
+{
+ update_stepper_delta(m_pf_stepper, pattern);
+ m_ypos = m_pf_stepper->get_absolute_position() * m_pf_stepper_ratio0 / m_pf_stepper_ratio1;
+ check_new_page();
+}
+
+void bitmap_printer_device::set_pf_stepper_ratio(int ratio0, int ratio1)
+{
+ m_pf_stepper_ratio0 = ratio0;
+ m_pf_stepper_ratio1 = ratio1;
+}
+
+void bitmap_printer_device::set_cr_stepper_ratio(int ratio0, int ratio1)
+{
+ m_cr_stepper_ratio0 = ratio0;
+ m_cr_stepper_ratio1 = ratio1;
+}
+
diff --git a/src/devices/machine/bitmap_printer.h b/src/devices/machine/bitmap_printer.h
new file mode 100644
index 00000000000..7b05f0e8c15
--- /dev/null
+++ b/src/devices/machine/bitmap_printer.h
@@ -0,0 +1,124 @@
+// license:BSD-3-Clause
+// copyright-holders: Golden Child
+/*
+ bitmap printer (dot printer)
+
+ * provides a page bitmap to draw on
+ * reads and writes pixels (representing printer dots)
+ * function to save the bitmap
+ * updates the bitmap to screen and draws the printhead
+ * printhead position given in m_xpos and m_ypos
+ * also provides a cr_stepper and a pf_stepper
+ * moving the cr_stepper/pf_stepper will update m_xpos/m_ypos according to ratio specified
+
+ */
+
+#include "screen.h"
+#include "machine/steppers.h"
+
+#ifndef MAME_MACHINE_BITMAP_PRINTER_H
+#define MAME_MACHINE_BITMAP_PRINTER_H
+
+#pragma once
+
+class bitmap_printer_device : public device_t
+{
+public:
+ bitmap_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ bitmap_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, int paper_width, int paper_height, int hdpi, int vdpi);
+
+ enum
+ {
+ LED_ERROR,
+ LED_READY,
+ LED_ONLINE
+ };
+
+ void set_led_state(int led, int value);
+ void set_printhead_color(int headcolor, int bordcolor);
+ void set_printhead_size(int xsize, int ysize, int bordersize);
+ void setheadpos(int x, int y);
+
+ void write_snapshot_to_file();
+
+ void draw_pixel(int x, int y, int pixelval);
+ int get_pixel(int x, int y);
+ unsigned int &pix(int y, int x);
+
+ void bitmap_clear_band(bitmap_rgb32 &bitmap, int from_line, int to_line, u32 color);
+ void bitmap_clear_band(int from_line, int to_line, u32 color);
+ void clear_to_pos(int to_line, u32 color = 0xffffff);
+
+ int get_top_margin();
+ int get_bottom_margin();
+ bool check_new_page();
+
+ int update_stepper_delta(stepper_device *stepper, uint8_t pattern);
+ void update_cr_stepper(int pattern);
+ void update_pf_stepper(int pattern);
+
+ void set_pf_stepper_ratio(int ratio0, int ratio1);
+ void set_cr_stepper_ratio(int ratio0, int ratio1);
+
+ int m_cr_direction; // direction of carriage
+ int m_xpos;
+ int m_ypos;
+
+protected:
+ bitmap_printer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_reset_after_children() override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ required_device<screen_device> m_screen;
+ required_device<stepper_device> m_pf_stepper;
+ required_device<stepper_device> m_cr_stepper;
+
+ required_ioport m_top_margin_ioport;
+ required_ioport m_bottom_margin_ioport;
+ required_ioport m_draw_marks_ioport;
+
+ bitmap_rgb32 m_page_bitmap; // page bitmap
+
+ static constexpr int PAPER_SCREEN_HEIGHT = 384; // match the height of the apple II driver
+ static constexpr int m_distfrombottom = 50; // print position from bottom of screen
+ static constexpr int MAX_LEDS = 5;
+
+ int m_printhead_color;
+ int m_printhead_bordercolor;
+ int m_printhead_bordersize;
+ int m_printhead_xsize;
+ int m_printhead_ysize;
+ int m_page_dirty;
+ int m_paper_width;
+ int m_paper_height;
+ int m_hdpi;
+ int m_vdpi;
+ int m_clear_pos;
+ int m_newpage_flag; // used to keep printhead at the top of page until actual printing
+ int m_led_state[MAX_LEDS];
+ int m_num_leds;
+ int m_pf_stepper_ratio0;
+ int m_pf_stepper_ratio1;
+ int m_cr_stepper_ratio0;
+ int m_cr_stepper_ratio1;
+
+ void draw_printhead(bitmap_rgb32 &bitmap, int x, int y);
+ u32 dimcolor(u32 incolor, int factor);
+
+ int calc_scroll_y(bitmap_rgb32& bitmap);
+ uint32_t screen_update_bitmap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ void draw7seg(u8 data, bool is_digit, int x0, int y0, int width, int height, int thick, bitmap_rgb32 &bitmap, u32 color, u32 erasecolor);
+ void draw_number(int number, int x, int y, bitmap_rgb32& bitmap);
+ void draw_inch_marks(bitmap_rgb32& bitmap);
+};
+
+DECLARE_DEVICE_TYPE(BITMAP_PRINTER, bitmap_printer_device)
+
+#endif // MAME_MACHINE_BITMAP_PRINTER_H
diff --git a/src/devices/machine/bl_handhelds_menucontrol.cpp b/src/devices/machine/bl_handhelds_menucontrol.cpp
index 18982731069..703ce996324 100644
--- a/src/devices/machine/bl_handhelds_menucontrol.cpp
+++ b/src/devices/machine/bl_handhelds_menucontrol.cpp
@@ -4,7 +4,7 @@
// Menu controller, stores / increments menu position etc. used on handhelds that typically have BL on the boot screen (BaoBaoLong?)
#include "emu.h"
-#include "machine/bl_handhelds_menucontrol.h"
+#include "bl_handhelds_menucontrol.h"
DEFINE_DEVICE_TYPE(BL_HANDHELDS_MENUCONTROL, bl_handhelds_menucontrol_device, "blhandheldmenu", "BaoBaoLong Handhelds Menu Controller")
@@ -14,12 +14,12 @@ bl_handhelds_menucontrol_device::bl_handhelds_menucontrol_device(const machine_c
{
}
-READ_LINE_MEMBER(bl_handhelds_menucontrol_device::status_r)
+int bl_handhelds_menucontrol_device::status_r()
{
return m_clockstate;
}
-READ_LINE_MEMBER(bl_handhelds_menucontrol_device::data_r)
+int bl_handhelds_menucontrol_device::data_r()
{
return m_responsebit;
}
@@ -156,7 +156,7 @@ void bl_handhelds_menucontrol_device::handle_command()
}
}
-WRITE_LINE_MEMBER(bl_handhelds_menucontrol_device::clock_w)
+void bl_handhelds_menucontrol_device::clock_w(int state)
{
if (state)
{
@@ -178,12 +178,12 @@ WRITE_LINE_MEMBER(bl_handhelds_menucontrol_device::clock_w)
}
}
-WRITE_LINE_MEMBER(bl_handhelds_menucontrol_device::data_w)
+void bl_handhelds_menucontrol_device::data_w(int state)
{
m_commandbit = state;
}
-WRITE_LINE_MEMBER(bl_handhelds_menucontrol_device::reset_w)
+void bl_handhelds_menucontrol_device::reset_w(int state)
{
m_datashifterpos = 0;
}
diff --git a/src/devices/machine/bl_handhelds_menucontrol.h b/src/devices/machine/bl_handhelds_menucontrol.h
index 747a60db76b..8b3e52b4f48 100644
--- a/src/devices/machine/bl_handhelds_menucontrol.h
+++ b/src/devices/machine/bl_handhelds_menucontrol.h
@@ -17,11 +17,11 @@ public:
// the chip is the same between systems, but there's some logic not fully understood that is causing off-by-1 errors on some calcs
void set_is_unsp_type_hack() { m_is_unsp_type_hack = true; }
- DECLARE_READ_LINE_MEMBER(status_r);
- DECLARE_READ_LINE_MEMBER(data_r);
- DECLARE_WRITE_LINE_MEMBER(clock_w);
- DECLARE_WRITE_LINE_MEMBER(data_w);
- DECLARE_WRITE_LINE_MEMBER(reset_w);
+ int status_r();
+ int data_r();
+ void clock_w(int state);
+ void data_w(int state);
+ void reset_w(int state);
protected:
virtual void device_start() override;
diff --git a/src/devices/machine/bq4847.cpp b/src/devices/machine/bq4847.cpp
index 7dd9031c814..d2618f03f53 100644
--- a/src/devices/machine/bq4847.cpp
+++ b/src/devices/machine/bq4847.cpp
@@ -21,16 +21,17 @@
#include "emu.h"
#include "bq4847.h"
-#define LOG_WARN (1U<<1) // Warnings
-#define LOG_CLOCK (1U<<2) // Clock operation
-#define LOG_REG (1U<<3) // Register write
-#define LOG_WATCHDOG (1U<<4) // Watchdog
-#define LOG_TRANSFER (1U<<5) // Transfer
+#define LOG_WARN (1U << 1) // Warnings
+#define LOG_CLOCK (1U << 2) // Clock operation
+#define LOG_REG (1U << 3) // Register write
+#define LOG_WATCHDOG (1U << 4) // Watchdog
+#define LOG_TRANSFER (1U << 5) // Transfer
-#define VERBOSE ( LOG_GENERAL | LOG_WARN )
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
#include "logmacro.h"
// device type definition
+DEFINE_DEVICE_TYPE(BQ4845, bq4845_device, "bq4845", "Benchmarq BQ4845 RTC")
DEFINE_DEVICE_TYPE(BQ4847, bq4847_device, "bq4847", "Benchmarq BQ4847 RTC")
enum
@@ -55,60 +56,84 @@ enum
enum
{
- FLAG_AIE = 0x08,
- FLAG_PIE = 0x04,
- FLAG_PWRIE = 0x02,
- FLAG_ABE = 0x01,
+ INTERRUPT_AIE = 0x08,
+ INTERRUPT_PIE = 0x04,
+ INTERRUPT_PWRIE = 0x02,
+ INTERRUPT_ABE = 0x01,
FLAG_AF = 0x08,
FLAG_PF = 0x04,
FLAG_PWRF = 0x02,
FLAG_BVF = 0x01,
- FLAG_UTI = 0x08,
- FLAG_STOP = 0x04,
- FLAG_24 = 0x02,
- FLAG_DSE = 0x01
+ CONTROL_UTI = 0x08,
+ CONTROL_STOP = 0x04,
+ CONTROL_24 = 0x02,
+ CONTROL_DSE = 0x01
};
//-------------------------------------------------
// Constructors for basetype
//-------------------------------------------------
-bq4847_device::bq4847_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, BQ4847, tag, owner, clock),
- device_nvram_interface(mconfig, *this),
- device_rtc_interface(mconfig, *this),
- m_interrupt_cb(*this),
- m_wdout_cb(*this),
- m_watchdog_active(false),
- m_writing(false)
+bq4847_device::bq4847_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock),
+ device_nvram_interface(mconfig, *this),
+ device_rtc_interface(mconfig, *this),
+ m_region(*this, DEVICE_SELF),
+ m_wdo_handler(*this),
+ m_int_handler(*this),
+ m_rst_handler(*this),
+ m_periodic_timer(nullptr),
+ m_watchdog_timer(nullptr),
+ m_wdo_state(1),
+ m_int_state(1),
+ m_rst_state(1),
+ m_wdi_state(-1),
+ m_writing(false)
{
}
-/*
- Inherited from device_rtc_interface. The date and time is given as integer
- and must be converted to BCD.
-*/
+bq4847_device::bq4847_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock)
+ : bq4847_device(mconfig, BQ4847, tag, owner, clock)
+{
+}
+
+bq4845_device::bq4845_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock)
+ : bq4847_device(mconfig, BQ4845, tag, owner, clock)
+{
+}
+
+// device_rtc_interface
+
void bq4847_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
{
- m_intreg[reg_hours] = convert_to_bcd(hour);
- m_intreg[reg_minutes] = convert_to_bcd(minute);
- m_intreg[reg_seconds] = convert_to_bcd(second);
- m_intreg[reg_year] = convert_to_bcd(year);
- m_intreg[reg_month] = convert_to_bcd(month);
- m_intreg[reg_date] = convert_to_bcd(day);
- m_intreg[reg_days] = convert_to_bcd(day_of_week);
+ if ((m_register[reg_control] & CONTROL_STOP) != 0)
+ {
+ m_register[reg_hours] = ((m_register[reg_control] & CONTROL_24) != 0) ? convert_to_bcd(hour) :
+ (((hour % 24) >= 12) ? 0x80 : 0x00) | convert_to_bcd((hour % 12) ? (hour % 12) : 12);
+ m_register[reg_minutes] = convert_to_bcd(minute);
+ m_register[reg_seconds] = convert_to_bcd(second);
+ m_register[reg_year] = convert_to_bcd(year);
+ m_register[reg_month] = convert_to_bcd(month);
+ m_register[reg_date] = convert_to_bcd(day);
+ m_register[reg_days] = convert_to_bcd(day_of_week);
+ }
+
+ // Clear the saved flags (TODO: check that flags set before power down, or during battery backup are lost)
+ m_register[reg_flags] = 0x00;
+
+ // Interrupts must be re-enabled on power-up (TODO: check, datasheet does not explicitly say ABE & PIE are cleared)
+ m_register[reg_interrupts] = 0x00;
+
+ // TODO: check if user buffer is battery backed
+ // TODO: What if UTI is set?
+ std::copy_n(m_register, std::size(m_register), m_userbuffer);
+
// What about the DSE flag?
}
bool bq4847_device::increment_bcd(uint8_t& bcdnumber, uint8_t limit, uint8_t min)
{
-/* if (!valid_bcd(bcdnumber, min, limit))
- {
- bcdnumber = min;
- return false;
- }
-*/
- if (bcdnumber>=limit)
+ if (bcdnumber >= limit)
{
bcdnumber = min;
return true;
@@ -118,7 +143,7 @@ bool bq4847_device::increment_bcd(uint8_t& bcdnumber, uint8_t limit, uint8_t min
uint8_t dig0 = bcdnumber & 0x0f;
uint8_t dig1 = bcdnumber & 0xf0;
- if (dig0==9)
+ if (dig0 == 9)
{
bcdnumber = dig1 + 0x10;
}
@@ -127,16 +152,6 @@ bool bq4847_device::increment_bcd(uint8_t& bcdnumber, uint8_t limit, uint8_t min
return false;
}
-// TODO: Remove; the real clock cannot verify BCD numbers.
-bool bq4847_device::valid_bcd(uint8_t value, uint8_t min, uint8_t max)
-{
- bool valid = ((value>=min) && (value<=max) && ((value&0x0f)<=9));
- if (!valid) LOGMASKED(LOG_WARN, "Invalid BCD number %02x\n", value);
- return valid;
-}
-
-// ----------------------------------------------------
-
/*
Update cycle, called every second
The BQ RTCs use BCD representation
@@ -144,7 +159,7 @@ bool bq4847_device::valid_bcd(uint8_t value, uint8_t min, uint8_t max)
TODO: We may not be able to use the parent class advance methods, since we
have to work with BCD (even with invalid values). Check this.
*/
-TIMER_CALLBACK_MEMBER(bq4847_device::rtc_clock_cb)
+TIMER_CALLBACK_MEMBER(bq4847_device::update_callback)
{
// Just for debugging
static const char* dow[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
@@ -154,43 +169,41 @@ TIMER_CALLBACK_MEMBER(bq4847_device::rtc_clock_cb)
if (carry)
{
- carry = increment_bcd(m_intreg[reg_seconds], 0x59, 0);
+ carry = increment_bcd(m_register[reg_seconds], 0x59, 0);
newsec = true;
}
if (carry)
- carry = increment_bcd(m_intreg[reg_minutes], 0x59, 0);
+ carry = increment_bcd(m_register[reg_minutes], 0x59, 0);
if (carry)
- {
carry = advance_hours_bcd();
- }
if (carry)
- {
advance_days_bcd();
- }
LOGMASKED(LOG_CLOCK, "%s 20%02x-%02x-%02x %02x:%02x:%02x\n",
- dow[m_intreg[reg_days]-1], m_intreg[reg_year], m_intreg[reg_month], m_intreg[reg_date],
- m_intreg[reg_hours], m_intreg[reg_minutes], m_intreg[reg_seconds]);
+ dow[m_register[reg_days] - 1], m_register[reg_year], m_register[reg_month], m_register[reg_date],
+ m_register[reg_hours], m_register[reg_minutes], m_register[reg_seconds]);
- // Copy into memory registers if the UTI bit is reset
if (newsec)
{
- if (!is_set(reg_control, FLAG_UTI))
+ if ((m_register[reg_control] & CONTROL_UTI) == 0)
{
- // Copy values from internal registers to accessible registers
- transfer_to_access();
+ LOGMASKED(LOG_TRANSFER, "Transfer to external regs\n");
+ for (int i = reg_seconds; i < reg_unused; i++)
+ {
+ if (is_clock_register(i)) m_userbuffer[i] = m_register[i];
+ }
}
- if (check_match(reg_date, reg_alarmdate) &&
- check_match(reg_hours, reg_alarmhours) &&
- check_match(reg_minutes, reg_alarmminutes) &&
- check_match(reg_seconds, reg_alarmseconds))
+ if (check_alarm(reg_date, reg_alarmdate) &&
+ check_alarm(reg_hours, reg_alarmhours) &&
+ check_alarm(reg_minutes, reg_alarmminutes) &&
+ check_alarm(reg_seconds, reg_alarmseconds))
{
- set_register(reg_flags, FLAG_AF, true);
- m_interrupt_cb(intrq_r());
+ m_userbuffer[reg_flags] |= FLAG_AF;
+ update_int();
}
}
}
@@ -199,46 +212,45 @@ bool bq4847_device::advance_hours_bcd()
{
bool carry = false;
// Handle DST
- if (is_set(reg_control, FLAG_DSE)
- && (m_intreg[reg_month]==4) && (m_intreg[reg_days]==0) && (m_intreg[reg_date] < 8) // first Sunday in April
- && (m_intreg[reg_hours]==0x01))
- m_intreg[reg_hours] = 0x03;
+ if ((m_register[reg_control] & CONTROL_DSE) != 0
+ && (m_register[reg_month] == 4) && (m_register[reg_days] == 0) && (m_register[reg_date] < 8) // first Sunday in April
+ && (m_register[reg_hours] == 0x01))
+ m_register[reg_hours] = 0x03;
else
{
// Increment hour unless the DSE bit is set and we are at 1:59 on the last Sunday in October
- if (!is_set(reg_control, FLAG_DSE)
- || (m_intreg[reg_month]!=10) || (m_intreg[reg_days]!=0) || (m_intreg[reg_date] <= 23) // last Sunday in October
- || (m_intreg[reg_hours]!=0x01))
+ if ((m_register[reg_control] & CONTROL_DSE) == 0
+ || (m_register[reg_month] != 10) || (m_register[reg_days] != 0) || (m_register[reg_date] <= 23) // last Sunday in October
+ || (m_register[reg_hours] != 0x01))
{
- if (is_set(reg_control, FLAG_24))
+ if ((m_register[reg_control] & CONTROL_24) != 0)
{
// 24h: 0->1->...->23->0(+1)
- increment_bcd(m_intreg[reg_hours], 0xff, 0);
- if (m_intreg[reg_hours] == 0x24)
+ increment_bcd(m_register[reg_hours], 0xff, 0);
+ if (m_register[reg_hours] == 0x24)
{
- m_intreg[reg_hours] = 0;
+ m_register[reg_hours] = 0;
carry = true;
}
}
-
else
{
// 12h: 12->1->2->...->11->12'->1'->...->11'->12(+1)
- increment_bcd(m_intreg[reg_hours], 0xff, 0);
- switch (m_intreg[reg_hours])
+ increment_bcd(m_register[reg_hours], 0xff, 0);
+ switch (m_register[reg_hours])
{
case 0x12:
- m_intreg[reg_hours]=0x92; // 11:59 am -> 12:00 pm
+ m_register[reg_hours] = 0x92; // 11:59 am -> 12:00 pm
break;
case 0x93:
- m_intreg[reg_hours]=0x81; // 12:59 pm -> 01:00 pm
+ m_register[reg_hours] = 0x81; // 12:59 pm -> 01:00 pm
break;
case 0x92:
- m_intreg[reg_hours]=0x12; // 11:59 pm -> 12:00 am
+ m_register[reg_hours] = 0x12; // 11:59 pm -> 12:00 am
carry = true;
break;
case 0x13:
- m_intreg[reg_hours]=0x01; // 12:59 am -> 01:00 am
+ m_register[reg_hours] = 0x01; // 12:59 am -> 01:00 am
break;
}
}
@@ -258,64 +270,55 @@ void bq4847_device::advance_days_bcd()
0x31, 0x31, 0x30, 0x31, 0x30, 0x31
};
- uint8_t month = bcd_to_integer(m_intreg[reg_month]);
+ uint8_t month = bcd_to_integer(m_register[reg_month]);
if (month > 12) month = 12;
- // if (!valid_bcd(month, 0x01, 0x12)) month = 1;
- uint8_t days = days_in_month_table[month-1];
+ uint8_t days = days_in_month_table[month - 1];
// Leap years are indeed handled (but the year is only 2-digit)
- if ((month==2) && ((m_intreg[reg_year]%4)==0))
+ if ((month == 2) && ((bcd_to_integer(m_register[reg_year]) % 4) == 0))
days = 0x29;
- increment_bcd(m_intreg[reg_days], 7, 1); // Increment the day-of-week (without carry)
- carry = increment_bcd(m_intreg[reg_date], days, 1);
+ increment_bcd(m_register[reg_days], 7, 1); // Increment the day-of-week (without carry)
+ carry = increment_bcd(m_register[reg_date], days, 1);
if (carry)
{
- increment_bcd(m_intreg[reg_month], 0xff, 1);
- if (m_intreg[reg_month] == 0x13)
+ increment_bcd(m_register[reg_month], 0xff, 1);
+ if (m_register[reg_month] == 0x13)
{
- m_intreg[reg_month] = 0x01;
- increment_bcd(m_intreg[reg_year], 0xff, 0);
+ m_register[reg_month] = 0x01;
+ increment_bcd(m_register[reg_year], 0xff, 0);
}
}
}
-bool bq4847_device::check_match(int now, int alarm)
+bool bq4847_device::check_alarm(int now, int alarm)
{
- // The ignore feature is active once the alarm has set in
- // Will lead to a periodic alarm
- bool ignore = (is_set(m_reg[alarm], 0x80) && is_set(m_reg[alarm], 0x40)) && is_set(reg_flags, FLAG_AF);
- return ignore || (m_intreg[now] == (m_reg[alarm] & 0x3f));
+ return (m_register[alarm] & 0xc0) == 0xc0 || (m_register[alarm] == m_register[now]);
}
-// =========================================================
-
-/*
- Read from registers
-*/
uint8_t bq4847_device::read(offs_t address)
{
int regnum = address & 0x0f;
- uint8_t value = m_reg[regnum];
+ uint8_t value = m_userbuffer[regnum];
if (regnum == reg_flags)
{
- set_register(reg_flags, 0xff, false);
- m_interrupt_cb(intrq_r());
+ value &= 0x7f;
+ m_userbuffer[reg_flags] = 0x00;
+ update_int();
}
- else
- if (regnum == reg_unused) value = 0; // Reg 15 is locked to 0 in BQ4847
+ else if (regnum >= reg_interrupts && regnum <= reg_control)
+ value &= 0xf;
+ else if (regnum == reg_unused)
+ value = 0; // Reg 15 is locked to 0 in BQ4847
LOGMASKED(LOG_REG, "Reg %d -> %02x\n", regnum, value);
return value;
}
-/*
- Write to the registers
-*/
void bq4847_device::write(offs_t address, uint8_t data)
{
int regnum = address & 0x0f;
@@ -328,226 +331,181 @@ void bq4847_device::write(offs_t address, uint8_t data)
return;
}
- bool uti_set = is_set(reg_control, FLAG_UTI); // Get it before we change the flag
+ bool uti_set = (m_register[reg_control] & CONTROL_UTI) != 0;
- m_reg[regnum] = data;
+ m_userbuffer[regnum] = data;
+
+ // If inhibit is not set, any write to the time/date registers
+ // is immediately set
+ if (uti_set && is_clock_register(regnum))
+ m_writing = true;
+ else
+ m_register[regnum] = m_userbuffer[regnum];
if (regnum == reg_rates)
{
- set_watchdog_timer(true);
+ set_watchdog_timer();
set_periodic_timer();
}
- else
+ else if (regnum == reg_control)
{
- if (regnum == reg_control)
- {
- LOGMASKED(LOG_TRANSFER, "Update transfer %s\n", ((data & FLAG_UTI)!=0)? "inhibit" : "enable");
-
- // After we have written to the registers, transfer to the internal regs
- if (uti_set && ((data & FLAG_UTI)==0) && m_writing)
- {
- LOGMASKED(LOG_TRANSFER, "Transfer to internal regs\n");
- for (int i=reg_seconds; i < reg_unused; i++)
- {
- if (is_internal_register(i)) m_intreg[i] = m_reg[i];
- }
- // The real device does not auto-convert hours according to AM/PM
- }
+ bool uti_set_now = (m_register[reg_control] & CONTROL_UTI) != 0;
+ LOGMASKED(LOG_TRANSFER, "Update transfer %s\n", uti_set_now ? "inhibit" : "enable");
- // We ignore the STOP* flag, since it only covers behaviour on power-off
- // We ignore the 24h/12h flag here; it requires reloading the registers anyway
- // The DSE flag will have effect on update
- }
- else
+ // After we have written to the registers, transfer to the internal regs
+ if (uti_set && !uti_set_now && m_writing)
{
- m_writing = true;
- // If inhibit is not set, any write to the time/date registers
- // is immediately set
- if (!uti_set && is_internal_register(regnum))
+ LOGMASKED(LOG_TRANSFER, "Transfer to internal regs\n");
+ for (int i = reg_seconds; i < reg_unused; i++)
{
- m_intreg[regnum] = m_reg[regnum];
+ if (is_clock_register(i)) m_register[i] = m_userbuffer[i];
}
+
+ m_writing = false;
}
}
}
-bool bq4847_device::is_internal_register(int regnum)
+bool bq4847_device::is_clock_register(int regnum)
{
return (regnum == reg_seconds || regnum == reg_minutes || regnum == reg_hours ||
- regnum == reg_date || regnum == reg_days || regnum == reg_month
- || regnum == reg_year);
+ regnum == reg_date || regnum == reg_days || regnum == reg_month
+ || regnum == reg_year);
}
-void bq4847_device::set_register(int number, uint8_t bits, bool set)
+void bq4847_device::set_periodic_timer()
{
- if (set)
- m_reg[number] |= bits;
- else
- m_reg[number] &= ~bits;
-}
+ uint8_t rs = m_register[reg_rates] & 0x0f;
+ attotime period = rs ? clocks_to_attotime(1 << (rs - 1)) : attotime::never;
-bool bq4847_device::is_set(int number, uint8_t flag)
-{
- return (m_reg[number] & flag)!=0;
+ if (m_periodic_timer)
+ m_periodic_timer->adjust(period, 0, period);
}
-void bq4847_device::transfer_to_access()
+void bq4847_device::set_watchdog_timer(int rst_state)
{
- LOGMASKED(LOG_TRANSFER, "Transfer to external regs\n");
- for (int i=reg_seconds; i < reg_unused; i++)
+ if (m_rst_state == rst_state)
{
- if (is_internal_register(i)) m_reg[i] = m_intreg[i];
+ int wd = (m_register[reg_rates] & 0x70) >> 4;
+ u32 t = (wd == 7) ? 16384 : (wd == 0) ? 8192 : 64 << wd;
+ if (m_rst_state) t *= 6;
+ attotime timeout = m_wdi_state >= 0 ? clocks_to_attotime(t) : attotime::never;
+
+ if (m_watchdog_timer)
+ m_watchdog_timer->adjust(timeout);
}
- // Clear the flag
- m_writing = false;
}
-void bq4847_device::set_periodic_timer()
+void bq4847_device::set_wdo(int state)
{
- uint8_t rateval = m_reg[reg_rates] & 0x0f;
- int rate = 1<<(16-rateval);
-
- if (rateval == 0)
- m_periodic_timer->reset();
- else
- m_periodic_timer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate));
+ if (m_wdo_state != state)
+ {
+ m_wdo_state = state;
+ m_wdo_handler(m_wdo_state);
+ }
}
-void bq4847_device::set_watchdog_timer(bool on)
+void bq4847_device::write_wdi(int state)
{
- int val = (m_reg[reg_rates] & 0x70)>>4;
-
- // val = 0 -> 1.5 sec
- // val = 1 -> 3/128 sec
- // val = 2 -> 3/64 sec
- // ...
- // val = 6 -> 3/4 sec
- // val = 7 -> 3 sec
-
- s64 time = 250000000L; // 250 ms
- if (val > 0)
+ if (m_wdi_state != state)
{
- time <<= 1;
- if (val < 7)
- time = time / (4<<(6-val));
- }
-
- if (on) time *= 6; // delay to on is 6 times the delay to off
+ m_wdi_state = state;
- if (m_watchdog_active)
- m_watchdog_timer->adjust(attotime::from_nsec(time)); // single shot
+ set_wdo(1);
+ set_watchdog_timer();
+ }
}
-void bq4847_device::set_watchdog_active(bool active)
+TIMER_CALLBACK_MEMBER(bq4847_device::periodic_callback)
{
- m_watchdog_active = active;
+ m_userbuffer[reg_flags] |= FLAG_PF;
+ update_int();
}
-void bq4847_device::retrigger_watchdog()
+TIMER_CALLBACK_MEMBER(bq4847_device::watchdog_callback)
{
- m_wdout_cb(CLEAR_LINE);
- m_watchdog_asserted = false;
- set_watchdog_timer(true);
-}
+ m_rst_state = !m_rst_state;
+ set_watchdog_timer(m_rst_state); // force timer update during reset
-/*
- Periodic cycle (called at defined intervals)
-*/
-TIMER_CALLBACK_MEMBER(bq4847_device::rtc_periodic_cb)
-{
- set_register(reg_flags, FLAG_PF, true);
- if (intrq_r())
- m_interrupt_cb(ASSERT_LINE);
+ m_rst_handler(m_rst_state);
+
+ if (!m_rst_state)
+ set_wdo(0);
+
+ LOGMASKED(LOG_WATCHDOG, "wdo %s rst %s\n", !m_wdo_state ? "asserted" : "cleared", !m_rst_state ? "asserted" : "cleared");
}
-/*
- Watchdog callback (BQ4847)
-*/
-TIMER_CALLBACK_MEMBER(bq4847_device::rtc_watchdog_cb)
+void bq4847_device::update_int()
{
- if (m_watchdog_active)
+ // TODO: check what happens if reg_interrupts is changed after the flag is set.
+ int int_state = !(m_register[reg_interrupts] & m_userbuffer[reg_flags] & (FLAG_AF | FLAG_PF | FLAG_PWRF));
+ if (m_int_state != int_state)
{
- m_wdout_cb(m_watchdog_asserted? CLEAR_LINE : ASSERT_LINE);
- set_watchdog_timer(!m_watchdog_asserted);
- m_watchdog_asserted = !m_watchdog_asserted;
- LOGMASKED(LOG_WATCHDOG, "Watchdog %s\n", m_watchdog_asserted? "asserted" : "cleared");
+ m_int_state = int_state;
+ m_int_handler(m_int_state);
}
}
-READ_LINE_MEMBER(bq4847_device::intrq_r)
-{
- bool alarm = is_set(reg_interrupts, FLAG_AIE) && is_set(reg_flags, FLAG_AF);
- bool period = is_set(reg_interrupts, FLAG_PIE) && is_set(reg_flags, FLAG_PF);
+// device_t
- // We ignore interrupts from power fail or battery low
- return (alarm || period)? ASSERT_LINE : CLEAR_LINE;
+void bq4847_device::device_start()
+{
+ m_update_timer = timer_alloc(FUNC(bq4847_device::update_callback), this);
+ m_periodic_timer = timer_alloc(FUNC(bq4847_device::periodic_callback), this);
+ m_watchdog_timer = timer_alloc(FUNC(bq4847_device::watchdog_callback), this);
+
+ m_wdo_handler(m_wdo_state);
+ m_int_handler(m_int_state);
+ m_rst_handler(m_rst_state);
+
+ save_pointer(NAME(m_userbuffer), 16);
+ save_pointer(NAME(m_register), 16);
+ save_item(NAME(m_wdo_state));
+ save_item(NAME(m_int_state));
+ save_item(NAME(m_rst_state));
+ save_item(NAME(m_wdi_state));
+ save_item(NAME(m_writing));
}
-void bq4847_device::connect_osc(bool conn)
+void bq4847_device::device_reset()
{
- if (conn)
- {
- // The internal update cycle is 1 sec
- m_clock_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
- set_periodic_timer();
- }
- else
- {
- // Turn off completely
- m_clock_timer->reset();
- m_watchdog_timer->reset();
- m_periodic_timer->reset();
- }
+ device_clock_changed();
}
-void bq4847_device::device_start()
+void bq4847_device::device_clock_changed()
{
- m_clock_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq4847_device::rtc_clock_cb), this));
-
- // Periodic timer
- m_periodic_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq4847_device::rtc_periodic_cb), this));
-
- // Watchdog timer
- m_watchdog_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq4847_device::rtc_watchdog_cb), this));
-
- // Interrupt line
- m_interrupt_cb.resolve_safe();
-
- // Watchdog output
- m_wdout_cb.resolve_safe();
-
- // Interrupt enables are cleared on powerup
- set_register(reg_interrupts, 0xff, false);
-
- // State save
- save_pointer(NAME(m_reg), 16);
- save_pointer(NAME(m_intreg), 16);
-
- // Start clock
- connect_osc(true);
+ m_update_timer->adjust(clocks_to_attotime(32768), 0, clocks_to_attotime(32768));
+ set_watchdog_timer();
+ set_periodic_timer();
}
-// ----------------------------------------------------
+// device_nvram_interface
void bq4847_device::nvram_default()
{
- std::fill_n(m_reg, 16, 0);
-}
+ if (m_region.found())
+ {
+ if (m_region->bytes() != std::size(m_register))
+ fatalerror("%s incorrect region size", tag());
-void bq4847_device::nvram_read(emu_file &file)
-{
- file.read(m_reg, 16);
- transfer_to_access();
+ std::copy_n(m_region->base(), std::size(m_register), m_register);
+ }
+ else
+ {
+ std::fill_n(m_register, std::size(m_register), 0);
- // Clear the saved flags
- set_register(reg_flags, 0xff, false);
+ m_register[reg_control] = CONTROL_STOP | CONTROL_24;
+ }
+}
- // Interrupts must be re-enabled on power-up
- set_register(reg_interrupts, 0xff, false);
+bool bq4847_device::nvram_read(util::read_stream& file)
+{
+ auto const [err, actual] = util::read(file, m_register, std::size(m_register));
+ return !err && (actual == std::size(m_register));
}
-void bq4847_device::nvram_write(emu_file &file)
+bool bq4847_device::nvram_write(util::write_stream& file)
{
- transfer_to_access();
- file.write(m_reg, 16);
+ auto const [err, actual] = util::write(file, m_register, std::size(m_register));
+ return !err;
}
diff --git a/src/devices/machine/bq4847.h b/src/devices/machine/bq4847.h
index 56551d74e1c..50cee115be5 100644
--- a/src/devices/machine/bq4847.h
+++ b/src/devices/machine/bq4847.h
@@ -15,8 +15,6 @@
#include "dirtc.h"
-// ======================> bq4874_device
-
class bq4847_device : public device_t,
public device_nvram_interface,
public device_rtc_interface
@@ -24,100 +22,77 @@ class bq4847_device : public device_t,
public:
bq4847_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- // The watchdog is inactive when the pin is not connected; we offer
- // a method to activate it
- void set_watchdog_active(bool active);
-
- auto interrupt_cb() { return m_interrupt_cb.bind(); }
- auto watchdog_cb() { return m_wdout_cb.bind(); }
-
- // Retrigger the watchdog
- void retrigger_watchdog();
+ auto wdo_handler() { return m_wdo_handler.bind(); }
+ auto int_handler() { return m_int_handler.bind(); }
+ auto rst_handler() { return m_rst_handler.bind(); }
uint8_t read(offs_t address);
void write(offs_t address, uint8_t data);
- DECLARE_READ_LINE_MEMBER(intrq_r);
-
- // Mainly used to disconnect from oscillator
- void connect_osc(bool conn);
-
-private:
- // Inherited from device_rtc_interface
- void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
- bool rtc_feature_y2k() const override { return false; }
- bool rtc_feature_leap_year() const override { return true; }
- bool rtc_battery_backed() const override { return true; }
+ void write_wdi(int state); // watchdog disabled if wdi pin is left floating
- // callback called when interrupt pin state changes (may be nullptr)
- devcb_write_line m_interrupt_cb;
+protected:
+ bq4847_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 32768);
- // callback called when watchdog times out changes (may be nullptr)
- devcb_write_line m_wdout_cb;
+ // device_t
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_clock_changed() override;
- // Accessible registers
- uint8_t m_reg[16];
+ // device_nvram_interface
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream& file) override;
+ virtual bool nvram_write(util::write_stream& file) override;
- // Internal clock registers
- // The clock operates on these registers and copies them to the
- // accessible registers
- uint8_t m_intreg[16];
+ // device_rtc_interface
+ virtual bool rtc_feature_y2k() const override { return false; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual bool rtc_battery_backed() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
- TIMER_CALLBACK_MEMBER(rtc_clock_cb);
- TIMER_CALLBACK_MEMBER(rtc_periodic_cb);
- TIMER_CALLBACK_MEMBER(rtc_watchdog_cb);
-
- void nvram_default() override;
- void nvram_read(emu_file &file) override;
- void nvram_write(emu_file &file) override;
-
- void device_start() override;
+private:
+ optional_memory_region m_region;
- // Sanity-check BCD number
- bool valid_bcd(uint8_t value, uint8_t min, uint8_t max);
+ devcb_write_line m_wdo_handler;
+ devcb_write_line m_int_handler;
+ devcb_write_line m_rst_handler;
- // Check bits in register
- bool is_set(int number, uint8_t flag);
+ TIMER_CALLBACK_MEMBER(update_callback);
+ TIMER_CALLBACK_MEMBER(periodic_callback);
+ TIMER_CALLBACK_MEMBER(watchdog_callback);
- // Increment BCD number
bool increment_bcd(uint8_t& bcdnumber, uint8_t limit, uint8_t min);
- // Set/Reset one or more bits in the register
- void set_register(int number, uint8_t bits, bool set);
-
- // Copy register contents from the internal registers to SRAM
- void transfer_to_access();
-
- // Check matching registers of time and alarm
- bool check_match(int regint, int regalarm);
-
- // Check whether this register is internal
- bool is_internal_register(int regnum);
-
- // Advance
+ bool check_alarm(int now, int alarm);
+ bool is_clock_register(int regnum);
bool advance_hours_bcd();
void advance_days_bcd();
+ void update_int();
+ void set_wdo(int state);
- // Timers
- emu_timer *m_clock_timer;
+ emu_timer *m_update_timer;
emu_timer *m_periodic_timer;
emu_timer *m_watchdog_timer;
- // Set timers
void set_periodic_timer();
- void set_watchdog_timer(bool on);
-
- // Get time from system
- void get_system_time();
-
- // Get the delay until the next second
- int get_delay();
-
- // Flags
- bool m_watchdog_active;
- bool m_watchdog_asserted;
+ void set_watchdog_timer(int rst_state = 1);
+
+ uint8_t m_userbuffer[16];
+ uint8_t m_register[16];
+ int m_wdo_state;
+ int m_int_state;
+ int m_rst_state;
+ int m_wdi_state;
bool m_writing;
};
+class bq4845_device : public bq4847_device
+{
+public:
+ bq4845_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock);
+};
+
+DECLARE_DEVICE_TYPE(BQ4845, bq4845_device)
DECLARE_DEVICE_TYPE(BQ4847, bq4847_device)
+
#endif
diff --git a/src/devices/machine/bq48x2.cpp b/src/devices/machine/bq48x2.cpp
index 40bfde5a754..a4524367d3c 100644
--- a/src/devices/machine/bq48x2.cpp
+++ b/src/devices/machine/bq48x2.cpp
@@ -8,13 +8,13 @@
#include "emu.h"
#include "bq48x2.h"
-#define LOG_WARN (1U<<1) // Warnings
-#define LOG_CLOCK (1U<<2) // Clock operation
-#define LOG_REGW (1U<<3) // Register write
-#define LOG_WATCHDOG (1U<<4) // Watchdog
-#define LOG_SRAM (1U<<5) // SRAM
+#define LOG_WARN (1U << 1) // Warnings
+#define LOG_CLOCK (1U << 2) // Clock operation
+#define LOG_REGW (1U << 3) // Register write
+#define LOG_WATCHDOG (1U << 4) // Watchdog
+#define LOG_SRAM (1U << 5) // SRAM
-#define VERBOSE ( LOG_GENERAL | LOG_WARN )
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
#include "logmacro.h"
// device type definition
@@ -474,7 +474,7 @@ TIMER_CALLBACK_MEMBER(bq48x2_device::rtc_watchdog_cb)
Indicates that there is an interrupt condition. Also used to drive the
outgoing line.
*/
-READ_LINE_MEMBER(bq48x2_device::intrq_r)
+int bq48x2_device::intrq_r()
{
bool alarm = (is_set(reg_interrupts, FLAG_AIE) && is_set(reg_flags, FLAG_AF));
bool period = (is_set(reg_interrupts, FLAG_PIE) && is_set(reg_flags, FLAG_PF));
@@ -507,19 +507,13 @@ int bq48x2_device::get_delay()
void bq48x2_device::device_start()
{
- m_clock_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq48x2_device::rtc_clock_cb), this));
+ m_clock_timer = timer_alloc(FUNC(bq48x2_device::rtc_clock_cb), this);
// Periodic timer
- m_periodic_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq48x2_device::rtc_periodic_cb), this));
+ m_periodic_timer = timer_alloc(FUNC(bq48x2_device::rtc_periodic_cb), this);
// Watchdog timer
- m_watchdog_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq48x2_device::rtc_watchdog_cb), this));
-
- // Interrupt line
- m_interrupt_cb.resolve_safe();
-
- // Reset output
- m_resetout_cb.resolve_safe();
+ m_watchdog_timer = timer_alloc(FUNC(bq48x2_device::rtc_watchdog_cb), this);
m_sram = std::make_unique<u8 []>(m_memsize);
@@ -541,18 +535,24 @@ void bq48x2_device::nvram_default()
std::fill_n(m_sram.get(), m_memsize, 0);
}
-void bq48x2_device::nvram_read(emu_file &file)
+bool bq48x2_device::nvram_read(util::read_stream &file)
{
- file.read(m_sram.get(), m_memsize);
+ auto const [err, actual] = util::read(file, m_sram.get(), m_memsize);
+ if (err || (actual != m_memsize))
+ return false;
transfer_to_access(); // Transfer the system time into the readable registers
// Clear the saved flags
set_register(reg_flags, 0xf8, true);
+
+ return true;
}
-void bq48x2_device::nvram_write(emu_file &file)
+bool bq48x2_device::nvram_write(util::write_stream &file)
{
transfer_to_access();
- file.write(m_sram.get(), m_memsize);
+
+ auto const [err, actual] = util::write(file, m_sram.get(), m_memsize);
+ return !err;
}
diff --git a/src/devices/machine/bq48x2.h b/src/devices/machine/bq48x2.h
index ddf4505b44f..6a25cc45b5f 100644
--- a/src/devices/machine/bq48x2.h
+++ b/src/devices/machine/bq48x2.h
@@ -28,7 +28,7 @@ public:
virtual uint8_t read(offs_t address);
virtual void write(offs_t address, uint8_t data);
- DECLARE_READ_LINE_MEMBER(intrq_r);
+ int intrq_r();
// Mainly used to disconnect from oscillator
void connect_osc(bool conn);
@@ -56,8 +56,8 @@ protected:
TIMER_CALLBACK_MEMBER(rtc_watchdog_cb);
void nvram_default() override;
- void nvram_read(emu_file &file) override;
- void nvram_write(emu_file &file) override;
+ bool nvram_read(util::read_stream &file) override;
+ bool nvram_write(util::write_stream &file) override;
void device_start() override;
diff --git a/src/devices/machine/buffer.h b/src/devices/machine/buffer.h
index 5df28af6c6b..e3f3c3bdd83 100644
--- a/src/devices/machine/buffer.h
+++ b/src/devices/machine/buffer.h
@@ -10,14 +10,14 @@ public:
uint8_t read() { return m_input_data; }
- DECLARE_WRITE_LINE_MEMBER(write_bit0) { if (state) m_input_data |= 0x01; else m_input_data &= ~0x01; }
- DECLARE_WRITE_LINE_MEMBER(write_bit1) { if (state) m_input_data |= 0x02; else m_input_data &= ~0x02; }
- DECLARE_WRITE_LINE_MEMBER(write_bit2) { if (state) m_input_data |= 0x04; else m_input_data &= ~0x04; }
- DECLARE_WRITE_LINE_MEMBER(write_bit3) { if (state) m_input_data |= 0x08; else m_input_data &= ~0x08; }
- DECLARE_WRITE_LINE_MEMBER(write_bit4) { if (state) m_input_data |= 0x10; else m_input_data &= ~0x10; }
- DECLARE_WRITE_LINE_MEMBER(write_bit5) { if (state) m_input_data |= 0x20; else m_input_data &= ~0x20; }
- DECLARE_WRITE_LINE_MEMBER(write_bit6) { if (state) m_input_data |= 0x40; else m_input_data &= ~0x40; }
- DECLARE_WRITE_LINE_MEMBER(write_bit7) { if (state) m_input_data |= 0x80; else m_input_data &= ~0x80; }
+ void write_bit0(int state) { if (state) m_input_data |= 0x01; else m_input_data &= ~0x01; }
+ void write_bit1(int state) { if (state) m_input_data |= 0x02; else m_input_data &= ~0x02; }
+ void write_bit2(int state) { if (state) m_input_data |= 0x04; else m_input_data &= ~0x04; }
+ void write_bit3(int state) { if (state) m_input_data |= 0x08; else m_input_data &= ~0x08; }
+ void write_bit4(int state) { if (state) m_input_data |= 0x10; else m_input_data &= ~0x10; }
+ void write_bit5(int state) { if (state) m_input_data |= 0x20; else m_input_data &= ~0x20; }
+ void write_bit6(int state) { if (state) m_input_data |= 0x40; else m_input_data &= ~0x40; }
+ void write_bit7(int state) { if (state) m_input_data |= 0x80; else m_input_data &= ~0x80; }
protected:
virtual void device_start() override;
diff --git a/src/devices/machine/busmouse.cpp b/src/devices/machine/busmouse.cpp
index 2c06045d127..285e62051b4 100644
--- a/src/devices/machine/busmouse.cpp
+++ b/src/devices/machine/busmouse.cpp
@@ -24,8 +24,6 @@
#include "machine/i8255.h"
-#define LOG_GENERAL (1U << 0)
-
//#define VERBOSE (LOG_GENERAL)
//#define LOG_OUTPUT_FUNC printf
#include "logmacro.h"
@@ -141,10 +139,7 @@ void bus_mouse_device::device_add_mconfig(machine_config &config)
void bus_mouse_device::device_start()
{
- // resolve callbacks
- m_write_extint.resolve_safe();
-
- m_irq_timer = timer_alloc(0);
+ m_irq_timer = timer_alloc(FUNC(bus_mouse_device::irq_timer_tick), this);
}
@@ -165,7 +160,7 @@ void bus_mouse_device::device_reset()
LOG("irq rate: %d Hz\n", hz);
}
-void bus_mouse_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(bus_mouse_device::irq_timer_tick)
{
irq = !irq;
diff --git a/src/devices/machine/busmouse.h b/src/devices/machine/busmouse.h
index 787c80e399b..29c20d236ee 100644
--- a/src/devices/machine/busmouse.h
+++ b/src/devices/machine/busmouse.h
@@ -28,7 +28,6 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_add_mconfig(machine_config &config) override;
// optional information overrides
@@ -38,6 +37,8 @@ protected:
uint8_t ppi_c_r();
void ppi_c_w(uint8_t data);
+ TIMER_CALLBACK_MEMBER(irq_timer_tick);
+
private:
emu_timer *m_irq_timer;
bool irq, irq_disabled;
diff --git a/src/devices/machine/cammu.cpp b/src/devices/machine/cammu.cpp
new file mode 100644
index 00000000000..38c4bb2a311
--- /dev/null
+++ b/src/devices/machine/cammu.cpp
@@ -0,0 +1,814 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * An implementation of the Fairchild/Intergraph Cache and Memory Management
+ * Unit (CAMMU) designed for use with the CLIPPER CPU family.
+ *
+ * The C100 and C300 designs used a pair of identical CAMMU devices, each
+ * containing a cache, TLB and dynamic translation unit. One device was
+ * configured and used for instruction memory, the other for data. It is
+ * possible to write to multiple CAMMU devices sharing a common system bus by
+ * using "global" register addresses.
+ *
+ * C400 designs initially implemented the memory management and cache functions
+ * using discrete logic, later using a more highly integrated memory management
+ * implementation, but still using discrete cache memory. In these systems, the
+ * mmu is consolidated into a single logical unit handling both instruction and
+ * data memory, with distinctly different program-visible architectures on the
+ * C4I and C4E/T devices. Almost no documentation for these has been located.
+ *
+ * Primary reference: http://bitsavers.org/pdf/fairchild/clipper/CLIPPER%20C300%2032-Bit%20Compute%20Engine.pdf
+ * Another reference: http://www.eecs.berkeley.edu/Pubs/TechRpts/1986/CSD-86-289.pdf
+ *
+ * TODO
+ * - c4 variants
+ * - fault register values
+ * - cache
+ * - bus errors
+ */
+
+#include "emu.h"
+#include "cammu.h"
+
+#include <algorithm>
+
+#define LOG_ACCESS (1U << 1)
+#define LOG_DTU (1U << 2)
+#define LOG_TLB (1U << 3)
+
+//#define VERBOSE (LOG_GENERAL | LOG_ACCESS | LOG_DTU)
+#include "logmacro.h"
+
+// each variant of the cammu has different registers and a different addressing map
+void cammu_c4t_device::map(address_map &map)
+{
+ map(0x008, 0x00b).rw(FUNC(cammu_c4t_device::ram_line_r), FUNC(cammu_c4t_device::ram_line_w));
+ map(0x010, 0x013).rw(FUNC(cammu_c4t_device::s_pdo_r), FUNC(cammu_c4t_device::s_pdo_w));
+ map(0x018, 0x01b).rw(FUNC(cammu_c4t_device::u_pdo_r), FUNC(cammu_c4t_device::u_pdo_w));
+ map(0x020, 0x023).rw(FUNC(cammu_c4t_device::htlb_offset_r), FUNC(cammu_c4t_device::htlb_offset_w));
+ map(0x028, 0x02b).rw(FUNC(cammu_c4t_device::i_fault_r), FUNC(cammu_c4t_device::i_fault_w));
+ map(0x030, 0x033).rw(FUNC(cammu_c4t_device::fault_address_1_r), FUNC(cammu_c4t_device::fault_address_1_w));
+ map(0x038, 0x03b).rw(FUNC(cammu_c4t_device::fault_address_2_r), FUNC(cammu_c4t_device::fault_address_2_w));
+ map(0x040, 0x043).rw(FUNC(cammu_c4t_device::fault_data_1_lo_r), FUNC(cammu_c4t_device::fault_data_1_lo_w));
+ map(0x048, 0x04b).rw(FUNC(cammu_c4t_device::fault_data_1_hi_r), FUNC(cammu_c4t_device::fault_data_1_hi_w));
+ map(0x050, 0x053).rw(FUNC(cammu_c4t_device::fault_data_2_lo_r), FUNC(cammu_c4t_device::fault_data_2_lo_w));
+ map(0x058, 0x05b).rw(FUNC(cammu_c4t_device::fault_data_2_hi_r), FUNC(cammu_c4t_device::fault_data_2_hi_w));
+ map(0x060, 0x063).rw(FUNC(cammu_c4t_device::c4_bus_poll_r), FUNC(cammu_c4t_device::c4_bus_poll_w));
+ map(0x068, 0x06b).rw(FUNC(cammu_c4t_device::control_r), FUNC(cammu_c4t_device::control_w));
+ map(0x070, 0x073).rw(FUNC(cammu_c4t_device::bio_control_r), FUNC(cammu_c4t_device::bio_control_w));
+ map(0x078, 0x07b).rw(FUNC(cammu_c4t_device::bio_address_tag_r), FUNC(cammu_c4t_device::bio_address_tag_w));
+
+ map(0x100, 0x103).rw(FUNC(cammu_c4t_device::cache_data_lo_r), FUNC(cammu_c4t_device::cache_data_lo_w));
+ map(0x104, 0x107).rw(FUNC(cammu_c4t_device::cache_data_hi_r), FUNC(cammu_c4t_device::cache_data_hi_w));
+ map(0x108, 0x10b).rw(FUNC(cammu_c4t_device::cache_cpu_tag_r), FUNC(cammu_c4t_device::cache_cpu_tag_w));
+ map(0x10c, 0x10f).rw(FUNC(cammu_c4t_device::cache_system_tag_valid_r), FUNC(cammu_c4t_device::cache_system_tag_valid_w));
+ map(0x110, 0x113).rw(FUNC(cammu_c4t_device::cache_system_tag_r), FUNC(cammu_c4t_device::cache_system_tag_w));
+ map(0x118, 0x11b).rw(FUNC(cammu_c4t_device::tlb_va_line_r), FUNC(cammu_c4t_device::tlb_va_line_w));
+ map(0x11c, 0x11f).rw(FUNC(cammu_c4t_device::tlb_ra_line_r), FUNC(cammu_c4t_device::tlb_ra_line_w));
+}
+
+void cammu_c4i_device::map(address_map &map)
+{
+ map(0x000, 0x003).rw(FUNC(cammu_c4i_device::reset_r), FUNC(cammu_c4i_device::reset_w));
+ map(0x010, 0x013).rw(FUNC(cammu_c4i_device::s_pdo_r), FUNC(cammu_c4i_device::s_pdo_w));
+ map(0x018, 0x01b).rw(FUNC(cammu_c4i_device::u_pdo_r), FUNC(cammu_c4i_device::u_pdo_w));
+ map(0x020, 0x023).rw(FUNC(cammu_c4i_device::clr_s_data_tlb_r), FUNC(cammu_c4i_device::clr_s_data_tlb_w));
+ map(0x028, 0x02b).rw(FUNC(cammu_c4i_device::clr_u_data_tlb_r), FUNC(cammu_c4i_device::clr_u_data_tlb_w));
+ map(0x030, 0x033).rw(FUNC(cammu_c4i_device::clr_s_insn_tlb_r), FUNC(cammu_c4i_device::clr_s_insn_tlb_w));
+ map(0x038, 0x03b).rw(FUNC(cammu_c4i_device::clr_u_insn_tlb_r), FUNC(cammu_c4i_device::clr_u_insn_tlb_w));
+
+ map(0x068, 0x06b).rw(FUNC(cammu_c4i_device::control_r), FUNC(cammu_c4i_device::control_w));
+
+ map(0x080, 0x083).rw(FUNC(cammu_c4i_device::test_data_r), FUNC(cammu_c4i_device::test_data_w));
+ map(0x088, 0x08b).rw(FUNC(cammu_c4i_device::i_fault_r), FUNC(cammu_c4i_device::i_fault_w));
+ map(0x090, 0x093).rw(FUNC(cammu_c4i_device::fault_address_1_r), FUNC(cammu_c4i_device::fault_address_1_w));
+ map(0x098, 0x09b).rw(FUNC(cammu_c4i_device::fault_address_2_r), FUNC(cammu_c4i_device::fault_address_2_w));
+ map(0x0a0, 0x0a3).rw(FUNC(cammu_c4i_device::fault_data_1_lo_r), FUNC(cammu_c4i_device::fault_data_1_lo_w));
+ map(0x0a8, 0x0ab).rw(FUNC(cammu_c4i_device::fault_data_1_hi_r), FUNC(cammu_c4i_device::fault_data_1_hi_w));
+ map(0x0b0, 0x0b3).rw(FUNC(cammu_c4i_device::fault_data_2_lo_r), FUNC(cammu_c4i_device::fault_data_2_lo_w));
+ map(0x0b8, 0x0bb).rw(FUNC(cammu_c4i_device::fault_data_2_hi_r), FUNC(cammu_c4i_device::fault_data_2_hi_w));
+ map(0x0c0, 0x0c3).rw(FUNC(cammu_c4i_device::test_address_r), FUNC(cammu_c4i_device::test_address_w));
+}
+
+DEFINE_DEVICE_TYPE(CAMMU_C4T, cammu_c4t_device, "c4t", "C4E/C4T CAMMU")
+DEFINE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device, "c4i", "C4I CAMMU")
+DEFINE_DEVICE_TYPE(CAMMU_C3, cammu_c3_device, "c3", "C1/C3 CAMMU")
+
+cammu_c4t_device::cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cammu_c4_device(mconfig, CAMMU_C4T, tag, owner, clock)
+ , m_ram_line(0)
+ , m_htlb_offset(0)
+ , m_c4_bus_poll(0)
+ , m_bio_control(0)
+ , m_bio_address_tag(0)
+ , m_cache_data_lo(0)
+ , m_cache_data_hi(0)
+ , m_cache_cpu_tag(0)
+ , m_cache_system_tag_valid(0)
+ , m_cache_system_tag(0)
+ , m_tlb_va_line(0)
+ , m_tlb_ra_line(0)
+{
+}
+
+cammu_c4i_device::cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cammu_c4_device(mconfig, CAMMU_C4I, tag, owner, clock)
+ , m_reset(0)
+ , m_clr_s_data_tlb(0)
+ , m_clr_u_data_tlb(0)
+ , m_clr_s_insn_tlb(0)
+ , m_clr_u_insn_tlb(0)
+ , m_test_data(0)
+ , m_test_address(0)
+{
+}
+
+cammu_c4_device::cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : cammu_device(mconfig, type, tag, owner, clock)
+ , m_s_pdo(0)
+ , m_u_pdo(0)
+ , m_control(0)
+ , m_i_fault(0)
+ , m_fault_address_1(0)
+ , m_fault_address_2(0)
+ , m_fault_data_1_lo(0)
+ , m_fault_data_1_hi(0)
+ , m_fault_data_2_lo(0)
+ , m_fault_data_2_hi(0)
+{
+}
+
+cammu_c3_device::cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cammu_device(mconfig, CAMMU_C3, tag, owner, clock)
+ , m_linked{ this }
+ , m_s_pdo(0)
+ , m_u_pdo(0)
+ , m_fault(0)
+ , m_control(CID_C3)
+{
+}
+
+cammu_device::cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_exception_func(*this)
+{
+}
+
+void cammu_device::device_start()
+{
+}
+
+void cammu_device::device_reset()
+{
+}
+
+void cammu_c4_device::device_start()
+{
+ cammu_device::device_start();
+
+ save_item(NAME(m_s_pdo));
+ save_item(NAME(m_u_pdo));
+ save_item(NAME(m_control));
+
+ save_item(NAME(m_i_fault));
+ save_item(NAME(m_fault_address_1));
+ save_item(NAME(m_fault_address_2));
+ save_item(NAME(m_fault_data_1_lo));
+ save_item(NAME(m_fault_data_1_hi));
+ save_item(NAME(m_fault_data_2_lo));
+ save_item(NAME(m_fault_data_2_hi));
+}
+
+void cammu_c4i_device::device_start()
+{
+ cammu_c4_device::device_start();
+
+ save_item(NAME(m_reset));
+ save_item(NAME(m_clr_s_data_tlb));
+ save_item(NAME(m_clr_u_data_tlb));
+ save_item(NAME(m_clr_s_insn_tlb));
+ save_item(NAME(m_clr_u_insn_tlb));
+ save_item(NAME(m_test_data));
+ save_item(NAME(m_test_address));
+}
+
+void cammu_c4t_device::device_start()
+{
+ cammu_c4_device::device_start();
+
+ save_item(NAME(m_ram_line));
+ save_item(NAME(m_htlb_offset));
+ save_item(NAME(m_c4_bus_poll));
+ save_item(NAME(m_bio_control));
+ save_item(NAME(m_bio_address_tag));
+
+ save_item(NAME(m_cache_data_lo));
+ save_item(NAME(m_cache_data_hi));
+ save_item(NAME(m_cache_cpu_tag));
+ save_item(NAME(m_cache_system_tag_valid));
+ save_item(NAME(m_cache_system_tag));
+ save_item(NAME(m_tlb_va_line));
+ save_item(NAME(m_tlb_ra_line));
+}
+
+void cammu_c3_device::device_start()
+{
+ cammu_device::device_start();
+
+ save_item(NAME(m_s_pdo));
+ save_item(NAME(m_u_pdo));
+ save_item(NAME(m_fault));
+ save_item(NAME(m_control));
+
+ for (tlb_set_t &tlb_set : m_tlb)
+ {
+ tlb_set.u = false;
+
+ tlb_set.w.ra = tlb_set.w.va = 0;
+ m_memory[ST0].space->cache(tlb_set.w.cache);
+
+ tlb_set.x.ra = tlb_set.x.va = 0;
+ m_memory[ST0].space->cache(tlb_set.x.cache);
+ }
+}
+
+void cammu_c3_device::device_reset()
+{
+ cammu_device::device_reset();
+
+ m_control = (m_control & CNTL_CID) | (CNTL_ATE | UST_3 | CNTL_EWIR | CNTL_EWIW | CNTL_EWCW | CNTL_EP);
+}
+
+void cammu_device::set_spaces(address_space &main_space, address_space &io_space, address_space &boot_space)
+{
+ m_memory[ST0].space = &main_space;
+ m_memory[ST1].space = &main_space;
+ m_memory[ST2].space = &main_space;
+ m_memory[ST3].space = &main_space;
+
+ m_memory[ST4].space = &io_space;
+ m_memory[ST5].space = &boot_space;
+ m_memory[ST6].space = &main_space;
+
+ // FIXME: this tag is probably not used, but if it is, need to figure
+ // out how to implement it properly.
+ m_memory[ST7].space = &main_space;
+
+ for (memory_t &memory : m_memory)
+ memory.space->cache(memory.cache);
+}
+
+bool cammu_device::memory_translate(const u32 ssw, const int spacenum, const int intention, offs_t &address, address_space *&target_space)
+{
+ // translate the address
+ translated_t translated = translate_address(ssw, address, BYTE,
+ intention == device_memory_interface::TR_READ ? READ :
+ intention == device_memory_interface::TR_WRITE ? WRITE :
+ EXECUTE);
+
+ target_space = &translated.cache->space();
+
+ // check that the requested space number matches the mapped space
+ if (translated.cache && translated.cache->space().spacenum() == spacenum)
+ {
+ address = translated.address;
+
+ return true;
+ }
+
+ return false;
+}
+
+cammu_device::translated_t cammu_device::translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode)
+{
+ // get effective user/supervisor mode
+ const bool user = (mode == EXECUTE) ? (ssw & SSW_U) : (ssw & (SSW_U | SSW_UU));
+
+ // check for alignment faults
+ if (!machine().side_effects_disabled() && get_alignment())
+ {
+ if ((mode == EXECUTE && (virtual_address & 0x1)) || (mode != EXECUTE && virtual_address & (size - 1)))
+ {
+ set_fault(virtual_address, mode == EXECUTE ? EXCEPTION_I_ALIGNMENT_FAULT : EXCEPTION_D_ALIGNMENT_FAULT);
+
+ return { nullptr, 0 };
+ }
+ }
+
+ // in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb
+ if (!user && (virtual_address & ~0x7fff) == 0)
+ {
+ switch (virtual_address & 0x7000)
+ {
+ // pages 0-3: main space pages 0-3
+ case 0x0000: return { &m_memory[ST1].cache, virtual_address & 0x3fff };
+ case 0x1000: return { &m_memory[ST2].cache, virtual_address & 0x3fff };
+ case 0x2000: return { &m_memory[ST3].cache, virtual_address & 0x3fff };
+ case 0x3000: return { &m_memory[ST3].cache, virtual_address & 0x3fff };
+
+ // pages 4-5: i/o space pages 0-1
+ case 0x4000: return { &m_memory[ST4].cache, virtual_address & 0x1fff };
+ case 0x5000: return { &m_memory[ST4].cache, virtual_address & 0x1fff };
+
+ // pages 6-7: boot space pages 0-1
+ case 0x6000: return { &m_memory[ST5].cache, virtual_address & 0x1fff };
+ case 0x7000: return { &m_memory[ST5].cache, virtual_address & 0x1fff };
+ }
+ }
+
+ // if not in mapped mode, use unmapped system tag
+ if ((ssw & SSW_M) == 0)
+ return { &m_memory[get_ust_space()].cache, virtual_address };
+
+ // get the page table entry
+ pte_t pte = get_pte(virtual_address, user);
+
+ // check for page faults
+ if (pte.entry & PTE_F)
+ {
+ if (!machine().side_effects_disabled())
+ {
+ LOG("%s page fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n",
+ mode == EXECUTE ? "instruction" : "data",
+ virtual_address, ssw, pte.entry, machine().describe_context());
+
+ set_fault(virtual_address, mode == EXECUTE ? EXCEPTION_I_PAGE_FAULT : EXCEPTION_D_PAGE_FAULT);
+ }
+
+ return { nullptr, 0 };
+ }
+
+ // check for protection level faults
+ if (!machine().side_effects_disabled())
+ {
+ if ((mode == EXECUTE) && !get_access(mode, pte.entry, ssw))
+ {
+ LOGMASKED(LOG_ACCESS, "execute protection fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n",
+ virtual_address, ssw, pte.entry, machine().describe_context());
+
+ set_fault(virtual_address, EXCEPTION_I_EXECUTE_PROTECT_FAULT);
+
+ return { nullptr, 0 };
+ }
+
+ if ((mode & READ) && !get_access(READ, pte.entry, ssw))
+ {
+ LOGMASKED(LOG_ACCESS, "read protection fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n",
+ virtual_address, ssw, pte.entry, machine().describe_context());
+
+ set_fault(virtual_address, EXCEPTION_D_READ_PROTECT_FAULT);
+
+ return { nullptr, 0 };
+ }
+
+ if ((mode & WRITE) && !get_access(WRITE, pte.entry, ssw))
+ {
+ LOGMASKED(LOG_ACCESS, "write protection fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n",
+ virtual_address, ssw, pte.entry, machine().describe_context());
+
+ set_fault(virtual_address, EXCEPTION_D_WRITE_PROTECT_FAULT);
+
+ return { nullptr, 0 };
+ }
+ }
+
+ // set pte referenced and dirty flags
+ if ((mode & WRITE) && !(pte.entry & PTE_D))
+ m_memory[ST0].cache.write_dword(pte.address, pte.entry | PTE_D | PTE_R);
+ else if (!(pte.entry & PTE_R))
+ m_memory[ST0].cache.write_dword(pte.address, pte.entry | PTE_R);
+
+ // translate the address
+ LOGMASKED(LOG_DTU, "%s address translated 0x%08x\n", mode == EXECUTE ? "instruction" : "data",
+ (pte.entry & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK));
+
+ // return the system tag and translated address
+ return { &m_memory[(pte.entry & PTE_ST) >> ST_SHIFT].cache, (pte.entry & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK) };
+}
+
+cammu_c3_device::tlb_line_t &cammu_c3_device::tlb_lookup(const bool user, const u32 virtual_address, const access_type mode)
+{
+ const u8 set = (virtual_address >> 12) & 0x3f;
+ tlb_set_t &tlb_set = m_tlb[set];
+
+ // check w compartment
+ if ((tlb_set.w.va & TLB_VA_VA) == (virtual_address & TLB_VA_VA) && (((user && (tlb_set.w.va & TLB_VA_UV)) || (!user && (tlb_set.w.va & TLB_VA_SV)))))
+ {
+ LOGMASKED(LOG_TLB, "tlb_lookup 0x%08x set %2d line W hit 0x%08x\n", virtual_address, set, tlb_set.w.ra);
+
+ // mark x line least recently used
+ tlb_set.u = true;
+
+ return tlb_set.w;
+ }
+
+ // check x compartment
+ if ((tlb_set.x.va & TLB_VA_VA) == (virtual_address & TLB_VA_VA) && (((user && (tlb_set.x.va & TLB_VA_UV))) || (!user && (tlb_set.x.va & TLB_VA_SV))))
+ {
+ LOGMASKED(LOG_TLB, "tlb_lookup 0x%08x set %2d line X hit 0x%08x\n", virtual_address, set, tlb_set.x.ra);
+
+ // mark w line least recently used
+ tlb_set.u = false;
+
+ return tlb_set.x;
+ }
+
+ // return the least recently used line
+ if (tlb_set.u)
+ {
+ LOGMASKED(LOG_TLB, "tlb_lookup 0x%08x set %2d line X miss\n", virtual_address, set);
+
+ tlb_set.u = false;
+ tlb_set.x.ra &= ~TLB_RA_R;
+
+ return tlb_set.x;
+ }
+ else
+ {
+ LOGMASKED(LOG_TLB, "tlb_lookup 0x%08x set %2d line W miss\n", virtual_address, set);
+
+ tlb_set.u = true;
+ tlb_set.w.ra &= ~TLB_RA_R;
+
+ return tlb_set.w;
+ }
+}
+
+cammu_device::translated_t cammu_c3_device::translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode)
+{
+ // get effective user/supervisor mode
+ const bool user = (mode == EXECUTE) ? (ssw & SSW_U) : (ssw & (SSW_U | SSW_UU));
+
+ // check for alignment faults
+ if (!machine().side_effects_disabled() && get_alignment())
+ {
+ if ((mode == EXECUTE && (virtual_address & 0x1)) || (mode != EXECUTE && virtual_address & (size - 1)))
+ {
+ set_fault(virtual_address, mode == EXECUTE ? EXCEPTION_I_ALIGNMENT_FAULT : EXCEPTION_D_ALIGNMENT_FAULT);
+
+ return { nullptr, 0 };
+ }
+ }
+
+ // in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb
+ if (!user && (virtual_address & ~0x7fff) == 0)
+ {
+ switch (virtual_address & 0x7000)
+ {
+ // pages 0-3: main space pages 0-3
+ case 0x0000: return { &m_memory[ST1].cache, virtual_address & 0x3fff };
+ case 0x1000: return { &m_memory[ST2].cache, virtual_address & 0x3fff };
+ case 0x2000: return { &m_memory[ST3].cache, virtual_address & 0x3fff };
+ case 0x3000: return { &m_memory[ST3].cache, virtual_address & 0x3fff };
+
+ // pages 4-5: i/o space pages 0-1
+ case 0x4000: return { &m_memory[ST4].cache, virtual_address & 0x1fff };
+ case 0x5000: return { &m_memory[ST4].cache, virtual_address & 0x1fff };
+
+ // pages 6-7: boot space pages 0-1
+ case 0x6000: return { &m_memory[ST5].cache, virtual_address & 0x1fff };
+ case 0x7000: return { &m_memory[ST5].cache, virtual_address & 0x1fff };
+ }
+ }
+
+ // if not in mapped mode, use unmapped system tag
+ if ((ssw & SSW_M) == 0)
+ return { &m_memory[get_ust_space()].cache, virtual_address };
+
+ // check translation lookaside buffer
+ tlb_line_t &tlbl = tlb_lookup(user, virtual_address, mode);
+
+ pte_t pte = { PTE_F, 0 };
+
+ // handle translation lookaside buffer miss
+ if (!(tlbl.ra & TLB_RA_R))
+ {
+ // get the page table entry
+ pte = get_pte(virtual_address, user);
+
+ // check for page faults
+ if (pte.entry & PTE_F)
+ {
+ if (!machine().side_effects_disabled())
+ {
+ LOG("%s page fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n",
+ mode == EXECUTE ? "instruction" : "data",
+ virtual_address, ssw, pte.entry, machine().describe_context());
+
+ set_fault(virtual_address, mode == EXECUTE ? EXCEPTION_I_PAGE_FAULT : EXCEPTION_D_PAGE_FAULT);
+ }
+
+ return { nullptr, 0 };
+ }
+
+ // update tlb line from page table entry
+ // FIXME: not sure if user/supervisor valid follow actual or effective mode?
+ tlbl.va = (virtual_address & TLB_VA_VA) | (user ? TLB_VA_UV : TLB_VA_SV);
+ tlbl.ra = pte.entry;
+ }
+
+ // check protection level
+ if (!machine().side_effects_disabled())
+ {
+ if ((mode == EXECUTE) && !get_access(EXECUTE, tlbl.ra, ssw))
+ {
+ LOGMASKED(LOG_ACCESS, "execute protection fault address 0x%08x ssw 0x%08x (%s)\n",
+ virtual_address, ssw, machine().describe_context());
+
+ set_fault(virtual_address, EXCEPTION_I_EXECUTE_PROTECT_FAULT);
+
+ return { nullptr, 0 };
+ }
+ if ((mode & READ) && !get_access(READ, tlbl.ra, ssw))
+ {
+ LOGMASKED(LOG_ACCESS, "read protection fault address 0x%08x ssw 0x%08x (%s)\n",
+ virtual_address, ssw, machine().describe_context());
+
+ set_fault(virtual_address, EXCEPTION_D_READ_PROTECT_FAULT);
+
+ return { nullptr, 0 };
+ }
+ if ((mode & WRITE) && !get_access(WRITE, tlbl.ra, ssw))
+ {
+ LOGMASKED(LOG_ACCESS, "write protection fault address 0x%08x ssw 0x%08x (%s)\n",
+ virtual_address, ssw, machine().describe_context());
+
+ set_fault(virtual_address, EXCEPTION_D_WRITE_PROTECT_FAULT);
+
+ return { nullptr, 0 };
+ }
+ }
+
+ // update dirty flag
+ if ((mode & WRITE) && !(tlbl.ra & TLB_RA_D))
+ {
+ // fetch the page table entry if needed
+ if (pte.entry & PTE_F)
+ pte = get_pte(virtual_address, user);
+
+ // set page table entry dirty flag
+ if (!(pte.entry & PTE_D))
+ {
+ pte.entry |= PTE_D | PTE_R;
+ m_memory[ST0].cache.write_dword(pte.address, pte.entry);
+ }
+
+ tlbl.ra |= TLB_RA_D | TLB_RA_R;
+ }
+
+ // update referenced flag
+ if (!(tlbl.ra & TLB_RA_R))
+ {
+ // fetch the page table entry if needed
+ if (pte.entry & PTE_F)
+ pte = get_pte(virtual_address, user);
+
+ // set page table entry referenced flag
+ if (!(pte.entry & PTE_R))
+ {
+ pte.entry |= PTE_R;
+ m_memory[ST0].cache.write_dword(pte.address, pte.entry);
+ }
+
+ tlbl.ra |= TLB_RA_R;
+ }
+
+ // return the system tag and translated address
+ LOGMASKED(LOG_DTU, "%s address translated 0x%08x\n", mode == EXECUTE ? "instruction" : "data",
+ (tlbl.ra & TLB_RA_RA) | (virtual_address & CAMMU_PAGE_MASK));
+
+ if (tlbl.ra & 0x800)
+ return { &m_memory[(tlbl.ra & TLB_RA_ST) >> ST_SHIFT].cache, (tlbl.ra & TLB_RA_RA) | (virtual_address & CAMMU_PAGE_MASK) };
+ else
+ return { &tlbl.cache, (tlbl.ra & TLB_RA_RA) | (virtual_address & CAMMU_PAGE_MASK) };
+}
+
+// return the page table entry for a given virtual address
+cammu_device::pte_t cammu_device::get_pte(const u32 va, const bool user)
+{
+ // get page table directory origin from user or supervisor pdo register
+ const u32 pdo = get_pdo(user);
+
+ // get page table directory index from top 12 bits of virtual address
+ const u32 ptdi = (va & VA_PTDI) >> 20;
+
+ // fetch page table directory entry
+ const u32 ptde = m_memory[ST0].cache.read_dword(pdo | ptdi);
+
+ LOGMASKED(LOG_DTU, "get_pte pdo 0x%08x ptdi 0x%08x ptde 0x%08x\n", pdo, ptdi, ptde);
+
+ // check for page table directory entry fault
+ if (ptde & PTDE_F)
+ return { PTE_F, pdo | ptdi };
+
+ // get the page table origin from the page table directory entry
+ const u32 pto = ptde & PTDE_PTO;
+
+ // get the page table index from the middle 12 bits of the virtual address
+ const u32 pti = (va & VA_PTI) >> 10;
+
+ // fetch page table entry
+ pte_t pte = { m_memory[ST0].cache.read_dword(pto | pti), pto | pti };
+
+ LOGMASKED(LOG_DTU, "get_pte pto 0x%08x pti 0x%08x pte 0x%08x\n", pto, pti, pte.entry);
+
+ // check for page table entry fault
+ if (!(pte.entry & PTE_F))
+ LOGMASKED(LOG_DTU, "get_pte address 0x%08x pte 0x%08x (%s)\n", va, pte.entry, machine().describe_context());
+
+ return pte;
+}
+
+bool cammu_c4_device::get_access(const access_type mode, const u32 pte, const u32 ssw) const
+{
+ switch (mode)
+ {
+ case READ: return pte & 0x20;
+ case WRITE: return pte & 0x10;
+ case EXECUTE: return pte & 0x08;
+
+ default: return false;
+ }
+}
+
+bool cammu_c3_device::get_access(const access_type mode, const u32 pte, const u32 ssw) const
+{
+ const u8 pl = (pte & PTE_PL) >> 3;
+
+ // special case for user data mode
+ if ((mode != EXECUTE) && !(ssw & SSW_U) && (ssw & SSW_UU))
+ return protection_matrix[(ssw & SSW_KU) ? 2 : 3][pl] & mode;
+ else
+ return protection_matrix[((ssw ^ SSW_K) & (SSW_U | SSW_K)) >> 29][pl] & mode;
+}
+
+// C100/C300 CAMMU protection level matrix
+const u8 cammu_c3_device::protection_matrix[4][16] =
+{
+ { RW, RW, RW, RW, RW, RW, RW, RWE, RE, R, R, R, N, N, N, N },
+ { N, RW, RW, RW, RW, RW, R, RWE, N, RE, R, R, RE, N, N, N },
+ { N, N, RW, RW, RW, R, R, RWE, N, N, RE, RE, N, RE, N, N },
+ { N, N, N, RW, R, R, R, RWE, N, N, N, RE, RE, N, RE, N }
+};
+
+void cammu_c3_device::reset_w(const u32 data)
+{
+ // translation lookaside buffer reset operations
+ if (data & (RESET_RSV | RESET_RUV | RESET_RD | RESET_RR))
+ {
+ LOGMASKED(LOG_TLB, "reset_w%s%s%s%s (%s)\n",
+ (data & RESET_RSV) ? " RSV" : "",
+ (data & RESET_RUV) ? " RUV" : "",
+ (data & RESET_RD) ? " RD" : "",
+ (data & RESET_RR) ? " RR" : "",
+ machine().describe_context());
+
+ const u32 va_mask = ((data & RESET_RSV) ? TLB_VA_SV : 0) | ((data & RESET_RUV) ? TLB_VA_UV : 0);
+ const u32 ra_mask = ((data & RESET_RD) ? TLB_RA_D : 0) | ((data & RESET_RR) ? TLB_RA_R : 0);
+
+ for (tlb_set_t &tlb_set : m_tlb)
+ {
+ tlb_set.w.va &= ~va_mask;
+ tlb_set.w.ra &= ~ra_mask;
+ tlb_set.x.va &= ~va_mask;
+ tlb_set.x.ra &= ~ra_mask;
+ }
+ }
+}
+
+u32 cammu_c3_device::tlb_r(const u8 address) const
+{
+ const u8 set = address >> 2;
+ u32 result = 0;
+
+ switch (address & 0x3)
+ {
+ case 0x0: result = m_tlb[set].w.ra | (m_tlb[set].u ? TLB_RA_U : 0); break;
+ case 0x1: result = m_tlb[set].w.va; break;
+ case 0x2: result = m_tlb[set].x.ra | (m_tlb[set].u ? TLB_RA_U : 0); break;
+ case 0x3: result = m_tlb[set].x.va; break;
+ }
+
+ LOGMASKED(LOG_TLB, "tlb_r set %2d line %c %s 0x%08x (%s)\n",
+ set, (address & 0x2) ? 'X' : 'W', (address & 0x1) ? "va" : "ra",
+ result, machine().describe_context());
+
+ return result;
+}
+
+void cammu_c3_device::tlb_w(const u8 address, const u32 data)
+{
+ const u32 mem_mask = ~TLB_RA_U;
+ const u8 set = address >> 2;
+
+ LOGMASKED(LOG_TLB, "tlb_w set %2d line %c %s 0x%08x (%s)\n",
+ set, (address & 0x2) ? 'X' : 'W', (address & 0x1) ? "va" : "ra",
+ data, machine().describe_context());
+
+ switch (address & 0x3)
+ {
+ case 0x0: COMBINE_DATA(&m_tlb[set].w.ra); break;
+ case 0x1: COMBINE_DATA(&m_tlb[set].w.va); break;
+ case 0x2: COMBINE_DATA(&m_tlb[set].x.ra); break;
+ case 0x3: COMBINE_DATA(&m_tlb[set].x.va); break;
+ }
+}
+
+u32 cammu_c3_device::cammu_r(const u32 address)
+{
+ switch (address & CAMMU_SELECT)
+ {
+ case CAMMU_D_TLB:
+ return tlb_r(address);
+
+ case CAMMU_D_REG:
+ switch (address & 0xff)
+ {
+ case CAMMU_REG_SPDO: return s_pdo_r();
+ case CAMMU_REG_UPDO: return u_pdo_r();
+ case CAMMU_REG_FAULT: return fault_r();
+ case CAMMU_REG_CONTROL: return control_r();
+ }
+ break;
+
+ case CAMMU_I_TLB:
+ return m_linked[1]->tlb_r(address);
+
+ case CAMMU_I_REG:
+ switch (address & 0xff)
+ {
+ case CAMMU_REG_SPDO: return m_linked[1]->s_pdo_r();
+ case CAMMU_REG_UPDO: return m_linked[1]->u_pdo_r();
+ case CAMMU_REG_FAULT: return m_linked[1]->fault_r();
+ case CAMMU_REG_CONTROL: return m_linked[1]->control_r();
+ }
+ break;
+ }
+
+ LOG("cammu_r unknown address 0x%08x\n", address);
+ return 0;
+}
+
+void cammu_c3_device::cammu_w(const u32 address, const u32 data)
+{
+ switch (address & CAMMU_SELECT)
+ {
+ case CAMMU_D_TLB:
+ tlb_w(address, data);
+ break;
+
+ case CAMMU_D_REG:
+ switch (address & 0xff)
+ {
+ case CAMMU_REG_SPDO: s_pdo_w(data); break;
+ case CAMMU_REG_UPDO: u_pdo_w(data); break;
+ case CAMMU_REG_FAULT: fault_w(data); break;
+ case CAMMU_REG_CONTROL: control_w(data); break;
+ case CAMMU_REG_RESET: reset_w(data); break;
+ default:
+ break;
+ }
+ break;
+
+ case CAMMU_I_TLB:
+ m_linked[1]->tlb_w(address, data);
+ break;
+
+ case CAMMU_I_REG:
+ switch (address & 0xff)
+ {
+ case CAMMU_REG_SPDO: m_linked[1]->s_pdo_w(data); break;
+ case CAMMU_REG_UPDO: m_linked[1]->u_pdo_w(data); break;
+ case CAMMU_REG_FAULT: m_linked[1]->fault_w(data); break;
+ case CAMMU_REG_CONTROL: m_linked[1]->control_w(data); break;
+ case CAMMU_REG_RESET: m_linked[1]->reset_w(data); break;
+ default:
+ break;
+ }
+ break;
+
+ case CAMMU_G_TLB:
+ for (cammu_c3_device *cammu : m_linked)
+ cammu->tlb_w(address, data);
+ break;
+
+ case CAMMU_G_REG:
+ for (cammu_c3_device *cammu : m_linked)
+ switch (address & 0xff)
+ {
+ case CAMMU_REG_SPDO: cammu->s_pdo_w(data); break;
+ case CAMMU_REG_UPDO: cammu->u_pdo_w(data); break;
+ case CAMMU_REG_FAULT: cammu->fault_w(data); break;
+ case CAMMU_REG_CONTROL: cammu->control_w(data); break;
+ case CAMMU_REG_RESET: cammu->reset_w(data); break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ LOG("cammu_w unknown address 0x%08x data 0x%08x\n", address, data);
+ break;
+ }
+}
diff --git a/src/devices/machine/cammu.h b/src/devices/machine/cammu.h
new file mode 100644
index 00000000000..ee697c1126f
--- /dev/null
+++ b/src/devices/machine/cammu.h
@@ -0,0 +1,665 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_CAMMU_H
+#define MAME_MACHINE_CAMMU_H
+
+#pragma once
+
+#include "cpu/clipper/common.h"
+
+class cammu_device : public device_t
+{
+public:
+ auto exception_callback() { return m_exception_func.bind(); }
+
+ static const u32 CAMMU_PAGE_SIZE = 0x1000;
+ static const u32 CAMMU_PAGE_MASK = (CAMMU_PAGE_SIZE - 1);
+
+ enum pdo_mask : u32
+ {
+ PDO_MASK = 0xfffff000
+ };
+
+ enum ptde_mask : u32
+ {
+ PTDE_F = 0x00000001, // page fault
+ PTDE_PTO = 0xfffff000 // page table origin
+ };
+
+ enum pte_mask : u32
+ {
+ PTE_F = 0x00000001, // page fault
+ PTE_R = 0x00000002, // referenced flag
+ PTE_D = 0x00000004, // dirty flag
+ PTE_PL = 0x00000078, // protection level
+ PTE_S = 0x00000180, // system reserved
+ PTE_ST = 0x00000e00, // system tag
+ PTE_RA = 0xfffff000, // real address
+
+ PTE_CW = 0x00000040, // copy on write (c400)
+ PTE_NDREF = 0x00000080, // secondary reference (software) / copy on write (fault)?
+ PTE_LOCK = 0x00000100 // page lock (software)
+ };
+
+ static constexpr int PL_SHIFT = 3;
+ static constexpr int ST_SHIFT = 9;
+
+ enum va_mask : u32
+ {
+ VA_POFS = 0x00000fff, // page offset
+ VA_PTI = 0x003ff000, // page table index
+ VA_PTDI = 0xffc00000 // page table directory index
+ };
+
+ enum system_tag_t : u8
+ {
+ ST0 = 0, // private, write-through, main memory space
+ ST1 = 1, // shared, write-through, main memory space
+ ST2 = 2, // private, copy-back, main memory space
+ ST3 = 3, // noncacheable, main memory space
+ ST4 = 4, // noncacheable, i/o space
+ ST5 = 5, // noncacheable, boot space
+ ST6 = 6, // cache purge
+ ST7 = 7 // slave i/o
+ };
+
+ void set_spaces(address_space &main_space, address_space &io_space, address_space &boot_space);
+
+ // translation lookaside buffer and register access
+ virtual u32 cammu_r(const u32 address) = 0;
+ virtual void cammu_w(const u32 address, const u32 data) = 0;
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(const u32 ssw, const u32 address, U &&apply)
+ {
+ // check for cammu access
+ if ((ssw & (SSW_UU | SSW_U)) || ((address & ~0x7ff) != 0x00004800))
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), READ);
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 1: apply(T(t.cache->read_byte(t.address))); break;
+ case 2: apply(T(t.cache->read_word(t.address))); break;
+ case 4: apply(T(t.cache->read_dword(t.address))); break;
+ case 8: apply(T(t.cache->read_qword(t.address))); break;
+ default:
+ fatalerror("unhandled load 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+ }
+ else if (sizeof(T) == 4)
+ apply(cammu_r(address));
+ else
+ fatalerror("unhandled cammu load 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+
+ return true;
+ }
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(const u32 ssw, const u32 address, U data)
+ {
+ // check for cammu access
+ if ((ssw & (SSW_UU | SSW_U)) || ((address & ~0x7ff) != 0x00004800))
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), WRITE);
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 1: t.cache->write_byte(t.address, T(data)); break;
+ case 2: t.cache->write_word(t.address, T(data)); break;
+ case 4: t.cache->write_dword(t.address, T(data)); break;
+ case 8: t.cache->write_qword(t.address, T(data)); break;
+ default:
+ fatalerror("unhandled store 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+ }
+ else if (sizeof(T) == 4)
+ cammu_w(address, data);
+ else
+ fatalerror("unhandled cammu store 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+
+ return true;
+ }
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<T(T)>>::value, bool> modify(const u32 ssw, const u32 address, U &&apply)
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), access_type(READ | WRITE));
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 4: t.cache->write_dword(t.address, apply(T(t.cache->read_dword(t.address)))); break;
+ default:
+ fatalerror("unhandled modify 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+
+ return true;
+ }
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> fetch(const u32 ssw, const u32 address, U &&apply)
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), EXECUTE);
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 2: apply(T(t.cache->read_word(t.address))); break;
+ case 4:
+ {
+ // check for unaligned access
+ if (address & 0x2)
+ {
+ // check for page span
+ if ((address & CAMMU_PAGE_MASK) == (CAMMU_PAGE_SIZE - 2))
+ {
+ translated_t u = translate_address(ssw, address + 2, access_size(sizeof(u16)), EXECUTE);
+ if (u.cache)
+ {
+ const u16 lsw = t.cache->read_word(t.address);
+ const u16 msw = t.cache->read_word(u.address);
+
+ apply((T(msw) << 16) | lsw);
+ }
+ else
+ return false;
+ }
+ else
+ apply(T(t.cache->read_dword_unaligned(t.address)));
+ }
+ else
+ apply(T(t.cache->read_dword(t.address)));
+ }
+ break;
+ default:
+ fatalerror("unhandled fetch 0x%08x size %d (%s)\n",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+
+ return true;
+ }
+
+ // address translation for debugger
+ bool memory_translate(const u32 ssw, const int spacenum, const int intention, offs_t &address, address_space *&target_space);
+
+protected:
+ cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ enum access_size : u8
+ {
+ BYTE = 1,
+ WORD = 2,
+ DWORD = 4,
+ QWORD = 8
+ };
+
+ enum access_type : u8
+ {
+ READ = 1,
+ WRITE = 2,
+ EXECUTE = 4,
+
+ // matrix abbreviations and combinations
+ N = 0,
+ R = READ,
+ W = WRITE,
+ RW = READ | WRITE,
+ RE = READ | EXECUTE,
+ RWE = READ | WRITE | EXECUTE,
+ };
+
+ struct translated_t
+ {
+ memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache *const cache;
+ const u32 address;
+ };
+
+ struct pte_t
+ {
+ u32 entry;
+ u32 address;
+ };
+
+ struct memory_t
+ {
+ address_space *space = nullptr;
+ memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache cache;
+ };
+
+ // address translation
+ virtual translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode);
+ pte_t get_pte(const u32 va, const bool user);
+
+ // helpers
+ virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const = 0;
+ virtual bool get_alignment() const = 0;
+ virtual u32 get_pdo(const bool user) const = 0;
+ virtual system_tag_t get_ust_space() const = 0;
+ virtual void set_fault(const u32 address, const exception_vector type) = 0;
+
+ // device state
+ devcb_write16 m_exception_func;
+ memory_t m_memory[8];
+};
+
+class cammu_c4_device : public cammu_device
+{
+public:
+ // TODO: translation lookaside buffer and register access
+ virtual void map(address_map &map) = 0;
+ virtual u32 cammu_r(const u32 address) override { return 0; }
+ virtual void cammu_w(const u32 address, const u32 data) override {}
+
+ void set_cammu_id(const u32 cammu_id) { m_control = cammu_id; }
+
+ u32 s_pdo_r() { return m_s_pdo; }
+ void s_pdo_w(offs_t offset, u32 data, u32 mem_mask = ~0) { m_s_pdo = ((m_s_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
+ u32 u_pdo_r() { return m_u_pdo; }
+ void u_pdo_w(offs_t offset, u32 data, u32 mem_mask = ~0) { m_u_pdo = ((m_u_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
+
+ virtual u32 control_r() = 0;
+ virtual void control_w(offs_t offset, u32 data, u32 mem_mask = ~0) = 0;
+
+ u32 i_fault_r() { return m_i_fault; }
+ void i_fault_w(u32 data) { m_i_fault = data; }
+ u32 fault_address_1_r() { return m_fault_address_1; }
+ void fault_address_1_w(u32 data) { m_fault_address_1 = data; }
+ u32 fault_address_2_r() { return m_fault_address_2; }
+ void fault_address_2_w(u32 data) { m_fault_address_2 = data; }
+ u32 fault_data_1_lo_r() { return m_fault_data_1_lo; }
+ void fault_data_1_lo_w(u32 data) { m_fault_data_1_lo = data; }
+ u32 fault_data_1_hi_r() { return m_fault_data_1_hi; }
+ void fault_data_1_hi_w(u32 data) { m_fault_data_1_hi = data; }
+ u32 fault_data_2_lo_r() { return m_fault_data_2_lo; }
+ void fault_data_2_lo_w(u32 data) { m_fault_data_2_lo = data; }
+ u32 fault_data_2_hi_r() { return m_fault_data_2_hi; }
+ void fault_data_2_hi_w(u32 data) { m_fault_data_2_hi = data; }
+
+protected:
+ cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+
+ virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
+ virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }
+
+ virtual void set_fault(const u32 address, const exception_vector type) override { m_fault_address_1 = address; m_exception_func(type); }
+
+ u32 m_s_pdo;
+ u32 m_u_pdo;
+ u32 m_control;
+
+ u32 m_i_fault;
+ u32 m_fault_address_1;
+ u32 m_fault_address_2;
+ u32 m_fault_data_1_lo;
+ u32 m_fault_data_1_hi;
+ u32 m_fault_data_2_lo;
+ u32 m_fault_data_2_hi;
+};
+
+class cammu_c4t_device : public cammu_c4_device
+{
+public:
+ cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+
+ u32 ram_line_r() { return m_ram_line; }
+ void ram_line_w(u32 data) { m_ram_line = data; }
+
+ u32 htlb_offset_r() { return m_htlb_offset; }
+ void htlb_offset_w(u32 data) { m_htlb_offset = data; }
+
+ u32 c4_bus_poll_r() { return m_c4_bus_poll; }
+ void c4_bus_poll_w(u32 data) { m_c4_bus_poll = data; }
+
+ enum control_mask : u32
+ {
+ CNTL_RUV = 0x00000001, // reset user valid
+ CNTL_RSV = 0x00000002, // reset supervisor valid
+ CNTL_DBWR = 0x00000004, // disable bus watch read
+ CNTL_ATD = 0x00000008, // alignment trap disable
+ CNTL_UST = 0x00000030, // unmapped system tag
+ CNTL_IOTS = 0x00000040, // i/o tag select
+ CNTL_UVS = 0x00000080, // user valid status
+ CNTL_PB = 0x00000100, // purge busy
+ CNTL_CICT = 0x00000200, // clear i-side cache tags
+ CNTL_CFR = 0x00000400, // clear trap registers
+ CNTL_HTLBD = 0x00000800, // htlb disable
+ CNTL_CDCT = 0x00001000, // clear d-side cache tags
+ CNTL_CID = 0xff000000 // cammu id
+ };
+
+ enum control_ust_mask : u32
+ {
+ UST_NCA = 0x00, // unmapped system tag, noncacheable
+ UST_PWT = 0x10, // unmapped system tag, write through
+ UST_PCB = 0x20, // unmapped system tag, copy back
+ UST_PGE = 0x30 // unmapped system tag, purge mode
+ };
+
+ enum control_cid_mask : u32
+ {
+ CID_C4T = 0x00000000 // unknown
+ };
+
+ virtual u32 control_r() override { return m_control; }
+ virtual void control_w(offs_t offset, u32 data, u32 mem_mask = ~0) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
+ u32 bio_control_r() { return m_bio_control; }
+ void bio_control_w(u32 data) { m_bio_control = data; }
+ u32 bio_address_tag_r() { return m_bio_address_tag; }
+ void bio_address_tag_w(u32 data) { m_bio_address_tag = data; }
+
+ u32 cache_data_lo_r() { return m_cache_data_lo; }
+ void cache_data_lo_w(u32 data) { m_cache_data_lo = data; }
+ u32 cache_data_hi_r() { return m_cache_data_hi; }
+ void cache_data_hi_w(u32 data) { m_cache_data_hi = data; }
+ u32 cache_cpu_tag_r() { return m_cache_cpu_tag; }
+ void cache_cpu_tag_w(u32 data) { m_cache_cpu_tag = data; }
+ u32 cache_system_tag_valid_r() { return m_cache_system_tag_valid; }
+ void cache_system_tag_valid_w(u32 data) { m_cache_system_tag_valid = data; }
+ u32 cache_system_tag_r() { return m_cache_system_tag; }
+ void cache_system_tag_w(u32 data) { m_cache_system_tag = data; }
+ u32 tlb_va_line_r() { return m_tlb_va_line; }
+ void tlb_va_line_w(u32 data) { m_tlb_va_line = data; }
+ u32 tlb_ra_line_r() { return m_tlb_ra_line; }
+ void tlb_ra_line_w(u32 data) { m_tlb_ra_line = data; }
+
+protected:
+ virtual void device_start() override;
+
+ virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
+ virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & (CNTL_IOTS | CNTL_UST)) >> 4); }
+
+private:
+ u32 m_ram_line;
+ u32 m_htlb_offset;
+ u32 m_c4_bus_poll;
+ u32 m_bio_control;
+ u32 m_bio_address_tag;
+
+ u32 m_cache_data_lo;
+ u32 m_cache_data_hi;
+ u32 m_cache_cpu_tag;
+ u32 m_cache_system_tag_valid;
+ u32 m_cache_system_tag;
+ u32 m_tlb_va_line;
+ u32 m_tlb_ra_line;
+};
+
+class cammu_c4i_device : public cammu_c4_device
+{
+public:
+ cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+
+ enum control_mask : u32
+ {
+ CNTL_LRAS = 0x00000001, // tlb line replacement
+ CNTL_BWWD = 0x00000002, // buswatch write disable
+ CNTL_BWRD = 0x00000004, // buswatch read disable
+ CNTL_FSR = 0x00000010, // fake system response
+ CNTL_ATD = 0x00000100, // alignment trap disable
+ CNTL_UMM = 0x00003000, // unmapped mode address space select
+ CNTL_POLL = 0x00030000, // poll bus signals
+ CNTL_BM = 0x00040000, // burst mode address space select
+ CNTL_PZBS = 0x00080000, // page 0 boot select
+ CNTL_CRR = 0x00700000, // cache memory refresh rate
+ CNTL_CID = 0xff000000 // cammu identification
+ };
+
+ enum control_umm_mask : u32
+ {
+ UMM_MM = 0x00000000, // mm space, noncacheable
+ UMM_MMRIO = 0x00001000, // mm or i/o space, noncacheable
+ UMM_IO = 0x00002000 // i/o space noncacheable
+ };
+
+ enum control_crr_mask : u32
+ {
+ CRR_GT131 = 0x00000000, // clock rate over 131 MHz
+ CRR_GT66 = 0x00100000, // clock rate over 66 MHz
+ CRR_GT33 = 0x00200000, // clock rate over 33 MHz
+ CRR_GT8 = 0x00300000, // clock rate over 8 MHz
+ CRR_GT2 = 0x00400000, // clock rate over 2 MHz
+ CRR_GT1 = 0x00500000, // clock rate over 1 MHz
+ CRR_GTHALF = 0x00600000, // clock rate over 0.5 MHz
+ CRR_OFF = 0x00700000, // refresh off
+ };
+
+ // c4i cammu identification (rev 2 and rev 3 known to have existed)
+ enum control_cid_mask : u32
+ {
+ CID_C4IR0 = 0x00000000,
+ CID_C4IR2 = 0x02000000
+ };
+
+ virtual u32 control_r() override { return m_control; }
+ virtual void control_w(offs_t offset, u32 data, u32 mem_mask) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
+
+ enum reset_mask : u32
+ {
+ RESET_CDCT = 0x00000001, // clear data cache tags
+ RESET_RDUV = 0x00000100, // reset all d-side uv flags
+ RESET_RDSV = 0x00001000, // reset all d-side sv flags
+ RESET_CICT = 0x00010000, // clear ins. cache tags
+ RESET_RIUV = 0x01000000, // reset all i-side uv flags
+ RESET_RISV = 0x10000000, // reset all i-side sv flags
+ RESET_FLUSH = 0x40000000, // flush out burst io buffer
+ RESET_CFR = 0x80000000 // clear fault registers
+ };
+ u32 reset_r() { return m_reset; }
+ void reset_w(u32 data) { m_reset = data; }
+
+ u32 clr_s_data_tlb_r() { return m_clr_s_data_tlb; }
+ void clr_s_data_tlb_w(u32 data) { m_clr_s_data_tlb = data; }
+ u32 clr_u_data_tlb_r() { return m_clr_u_data_tlb; }
+ void clr_u_data_tlb_w(u32 data) { m_clr_u_data_tlb = data; }
+ u32 clr_s_insn_tlb_r() { return m_clr_s_insn_tlb; }
+ void clr_s_insn_tlb_w(u32 data) { m_clr_s_insn_tlb = data; }
+ u32 clr_u_insn_tlb_r() { return m_clr_u_insn_tlb; }
+ void clr_u_insn_tlb_w(u32 data) { m_clr_u_insn_tlb = data; }
+
+ u32 test_data_r() { return m_test_data; }
+ void test_data_w(u32 data) { m_test_data = data; }
+
+ u32 test_address_r() { return m_test_address; }
+ void test_address_w(u32 data) { m_test_address = data; }
+
+protected:
+ virtual void device_start() override;
+
+ virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
+ // FIXME: don't really know how unmapped mode works on c4i
+ virtual system_tag_t get_ust_space() const override { return (m_control & UMM_IO) ? ST4 : ST3; }
+
+private:
+ u32 m_reset;
+ u32 m_clr_s_data_tlb;
+ u32 m_clr_u_data_tlb;
+ u32 m_clr_s_insn_tlb;
+ u32 m_clr_u_insn_tlb;
+ u32 m_test_data;
+ u32 m_test_address;
+};
+
+class cammu_c3_device : public cammu_device
+{
+public:
+ cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void add_linked(cammu_c3_device *child) { m_linked.push_back(child); }
+
+protected:
+ // device-level overrides
+ virtual void device_reset() override;
+ virtual void device_start() override;
+
+ // translation lookaside buffer and register access
+ virtual u32 cammu_r(const u32 address) override;
+ virtual void cammu_w(const u32 address, const u32 data) override;
+
+ // address translation
+ virtual translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode) override;
+
+private:
+ enum cammu_address_mask : u32
+ {
+ CAMMU_TLB_VA = 0x00000001, // tlb va/ra select
+ CAMMU_TLB_X = 0x00000002, // tlb x/w line select
+ CAMMU_TLB_SET = 0x000000fc, // tlb set select
+ CAMMU_REG = 0x000000ff, // register select
+ CAMMU_SELECT = 0x00000700, // cammu select
+ };
+ enum tlb_ra_mask : u32
+ {
+ TLB_RA_U = 0x00000001, // used flag
+ TLB_RA_R = 0x00000002, // referenced flag
+ TLB_RA_D = 0x00000004, // dirty flag
+ TLB_RA_PL = 0x00000078, // protection level
+ TLB_RA_ST = 0x00000e00, // system tag
+ TLB_RA_RA = 0xfffff000, // real address
+ };
+ enum tlb_va_mask : u32
+ {
+ TLB_VA_UV = 0x00000002, // user valid flag
+ TLB_VA_SV = 0x00000004, // supervisor valid flag
+ TLB_VA_VA = 0xfffc0000, // virtual address tag
+ };
+
+ /*
+ * The C1/C3 CAMMU has 64-entry, two-way set associative TLB, with lines
+ * grouped into W and X compartments. The associated U flag is set to
+ * indicate that the W line of the set was most recently accessed, and
+ * cleared when the X line was most recently accessed. On TLB miss, the
+ * least recently used line as indicated by this flag is replaced.
+ *
+ * Each line consists of a real address field and a virtual address field.
+ * The real address field format is practically identical to the page table
+ * entry format.
+ */
+ struct tlb_line_t
+ {
+ u32 ra; // real address field
+ u32 va; // virtual address field
+
+ memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache cache;
+ };
+ struct tlb_set_t
+ {
+ tlb_line_t w;
+ tlb_line_t x;
+ bool u;
+ };
+
+ enum cammu_select_mask : u32
+ {
+ CAMMU_D_TLB = 0x000, // d-cammu tlb
+ CAMMU_D_REG = 0x100, // d-cammu register
+ CAMMU_I_TLB = 0x200, // i-cammu tlb
+ CAMMU_I_REG = 0x300, // i-cammu register
+ CAMMU_G_TLB = 0x400, // global tlb
+ CAMMU_G_REG = 0x500, // global register
+ };
+ enum cammu_register_mask : u8
+ {
+ CAMMU_REG_SPDO = 0x04, // supervisor pdo register
+ CAMMU_REG_UPDO = 0x08, // user pdo register
+ CAMMU_REG_FAULT = 0x10, // fault register
+ CAMMU_REG_CONTROL = 0x40, // control register
+ CAMMU_REG_RESET = 0x80, // reset register
+ };
+
+ enum control_mask : u32
+ {
+ CNTL_EP = 0x00000001, // enable prefetch
+ CNTL_EWCW = 0x00000002, // enable watch cpu writes
+ CNTL_EWIW = 0x00000004, // enable watch i/o writes
+ CNTL_EWIR = 0x00000008, // enable watch i/o reads
+ CNTL_UST = 0x00000030, // unmapped system tag
+ CNTL_CV = 0x00000100, // clear valid
+ CNTL_ATE = 0x00000200, // alignment trap enable
+ CNTL_CID = 0xff000000 // cammu id
+ };
+ enum control_ust_mask : u32
+ {
+ UST_0 = 0x00000000, // private, write-through, main memory space
+ UST_1 = 0x00000010, // shared, write-through, main memory space
+ UST_2 = 0x00000020, // private, copy-back, main memory space
+ UST_3 = 0x00000030 // noncacheable, main memory space
+ };
+ enum control_cid_mask : u32
+ {
+ CID_C3 = 0x00000000 // unknown
+ };
+
+ enum reset_mask : u32
+ {
+ RESET_RLVW = 0x00000001, // reset all W line LV flags in cache
+ RESET_RLVX = 0x00000002, // reset all X line LV flags in cache
+ RESET_RSV = 0x00000004, // reset all SV flags in tlb
+ RESET_RUV = 0x00000008, // reset all UV flags in tlb
+ RESET_RD = 0x00000010, // reset all D flags in tlb
+ RESET_RR = 0x00000020, // reset all R flags in tlb
+ RESET_RU = 0x00000040, // reset all U flags in cache
+ };
+
+ u32 tlb_r(const u8 address) const;
+ void tlb_w(const u8 address, const u32 data);
+ tlb_line_t &tlb_lookup(const bool user, const u32 virtual_address, const access_type mode);
+
+ u32 s_pdo_r() const { return m_s_pdo; }
+ void s_pdo_w(const u32 data) { m_s_pdo = data & PDO_MASK; }
+ u32 u_pdo_r() const { return m_u_pdo; }
+ void u_pdo_w(const u32 data) { m_u_pdo = data & PDO_MASK; }
+ u32 fault_r() const { return m_fault; }
+ void fault_w(const u32 data) { m_fault = data; }
+ u32 control_r() const { return m_control; }
+ void control_w(const u32 data) { m_control = (m_control & CNTL_CID) | (data & ~CNTL_CID); }
+ void reset_w(const u32 data);
+
+ virtual bool get_alignment() const override { return m_control & CNTL_ATE; }
+ virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & CNTL_UST) >> 4); }
+ virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
+ virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }
+
+ virtual void set_fault(const u32 address, const exception_vector type) override { m_fault = address; m_exception_func(type); }
+
+ static const u8 protection_matrix[4][16];
+
+ // device state
+ std::vector<cammu_c3_device *> m_linked;
+
+ u32 m_s_pdo;
+ u32 m_u_pdo;
+ u32 m_fault;
+ u32 m_control;
+
+ tlb_set_t m_tlb[64];
+};
+
+// device type definitions
+DECLARE_DEVICE_TYPE(CAMMU_C4T, cammu_c4t_device)
+DECLARE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device)
+DECLARE_DEVICE_TYPE(CAMMU_C3, cammu_c3_device)
+
+#endif // MAME_MACHINE_CAMMU_H
diff --git a/src/devices/machine/cat702.cpp b/src/devices/machine/cat702.cpp
new file mode 100644
index 00000000000..80e548bb871
--- /dev/null
+++ b/src/devices/machine/cat702.cpp
@@ -0,0 +1,310 @@
+// license:BSD-3-Clause
+// copyright-holders:smf
+/*
+
+ CAT702 ZN security chip
+
+ A serial magic latch.
+
+ It's a DIP20 chip with a sticker of the form XXnn, where XX is the
+ company and nn a number:
+ AC = Acclaim
+ AT = Atlus
+ CP = Capcom
+ ET = Raizing
+ KN = Konami
+ MG = Tecmo
+ TT = Taito
+ TW = Atari
+
+ There usually are 2 of them, one on the cpu board and one on the rom
+ board. The cpu board one is usually numbered 01.
+
+ Pinout: GND -11 10- GND
+ ? -12 9- +5V
+ +5V -13 8- Data in
+ Data out- 14 7- Clock
+ +5V -15 6- Select
+ ? -16 5- Select
+ +5V -17 4- +5V
+ +5V -18 3- +5V
+ +5V -19 2- +5V
+ +5V -20 1- ?
+
+ The chip works with the '?' lines left unconnected.
+
+ The communication protocol is serial, and in practice the standard
+ psx controller communication protocol minus the ack. Drive both
+ select to ground to start a communication, send bits and get the
+ results on the raising clock. Put both select back to +5V when
+ finished. The bios seems to use two communication clock speeds,
+ ~300KHz (standard psx) and ~2MHz. Driving it with lower clocks
+ works reasonably, at least at 1KHz.
+
+ The data is divided in bytes but there is no signal for end-of-byte.
+ In all of the following the data will be considered coming and going
+ lower-bit first.
+
+ Internally the chip has a 8-bit state, initialized at communication
+ start to 0xfc. The structure is simple:
+
+
+ +---------+ bit number +--------+
+ Clock ------->| bit |-----+-------------------->| bit |---------> Data out
+ | counter | | | select |
+ +---------+ v +-------+ out | |
+ | +-----+ | 8bit |=====>| |
+ Data in ------------|------->| TF1 |<=>| state | +--------+
+ | +-----+ | |
+ | | |
+ | start +-----+ | |
+ +------->| TF2 |<=>| |
+ +-----+ +-------+
+
+ The chip starts by tranforming the state with TF2. Then, for each
+ input bit from 0 to 7:
+ - the nth bit from the state is sent to the output
+ - the state is transformed by TF1 if the input bit is 0
+
+ TF2 is a fixed linear substitution box (* = and, + = xor):
+ o = ff*s0 + fe*s1 + fc*s2 + f8*s3 + f0*s4 + e0*s5 + c0*s6 + 7f*s7
+
+ TF1 is a chip-dependent set of 8 linear sboxes, one per bit number.
+ In practice, only the sbox for bit 0 is defined for the chip, the 7
+ other are derived from it. Defining the byte transformation Shift
+ as:
+ Shift(i7..i0) = i6..i0, i7^i6
+
+ and noting the sboxes as:
+ Sbox(n, i7..i0) = Xor( c[n, bit]*i[bit])
+ 0<=bit<=7
+ then
+ c[n, bit=0..6] = Shift(c[n-1, (bit-1)&7])
+ c[n, 7] = Shift(c[n-1, 6])^c[n, 0]
+ = Shift(c[n-1, 6])^Shift(c[n-1, 7])
+*/
+
+#include "emu.h"
+#include "cat702.h"
+
+static constexpr uint8_t initial_sbox[8] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x7f };
+
+DEFINE_DEVICE_TYPE(CAT702, cat702_device, "cat702", "CAT702")
+DEFINE_DEVICE_TYPE(CAT702_PIU, cat702_piu_device, "cat702_piu", "CAT702_PIU")
+
+cat702_device_base::cat702_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_select(1),
+ m_clock(1),
+ m_datain(1),
+ m_state(0),
+ m_bit(0),
+ m_dataout_handler(*this),
+ m_region(*this, DEVICE_SELF)
+{
+}
+
+void cat702_device_base::device_start()
+{
+ memset(m_transform, 0xff, sizeof(m_transform));
+
+ if (!m_region.found())
+ {
+ logerror("cat702(%s):region not found\n", tag());
+ }
+ else if (m_region->bytes() != sizeof(m_transform))
+ {
+ logerror("cat702(%s):region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), sizeof(m_transform));
+ }
+ else
+ {
+ memcpy(m_transform, m_region->base(), sizeof(m_transform));
+ }
+
+ save_item(NAME(m_select));
+ save_item(NAME(m_clock));
+ save_item(NAME(m_datain));
+ save_item(NAME(m_state));
+ save_item(NAME(m_bit));
+
+ m_dataout_handler(1);
+}
+
+// Given the value for x7..x0 and linear transform coefficients a7..a0
+// compute the value of the transform
+#if 0
+static int c_linear(uint8_t x, uint8_t a)
+{
+ x &= a;
+ uint8_t r = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(x, i))
+ r = !r;
+ }
+ return r;
+}
+#endif
+
+// Derive the sbox xor mask for a given input and select bit
+uint8_t cat702_device_base::compute_sbox_coef(int sel, int bit)
+{
+ if (!sel)
+ return m_transform[bit];
+
+ uint8_t r = compute_sbox_coef((sel - 1) & 7, (bit - 1) & 7);
+ r = (r << 1) | (BIT(r, 7) ^ BIT(r, 6));
+ if (bit != 7)
+ return r;
+
+ return r ^ compute_sbox_coef(sel, 0);
+}
+
+// Apply the sbox for a input 0 bit
+void cat702_device_base::apply_bit_sbox(int sel)
+{
+ uint8_t r = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_state, i))
+ r ^= compute_sbox_coef(sel, i);
+ }
+ m_state = r;
+}
+
+// Apply a sbox
+void cat702_device_base::apply_sbox(const uint8_t *sbox)
+{
+ uint8_t r = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_state, i))
+ r ^= sbox[i];
+ }
+ m_state = r;
+}
+
+void cat702_device_base::write_datain(int state)
+{
+ m_datain = state;
+}
+
+
+///////////////
+
+
+cat702_device::cat702_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ cat702_device_base(mconfig, CAT702, tag, owner, clock)
+{
+}
+
+
+void cat702_device::write_select(int state)
+{
+ if (m_select != state)
+ {
+ if (!state)
+ {
+ m_state = 0xfc;
+ m_bit = 0;
+ }
+ else
+ {
+ m_dataout_handler(1);
+ }
+
+ m_select = state;
+ }
+}
+
+void cat702_device::write_clock(int state)
+{
+ if (!state && m_clock && !m_select)
+ {
+ if (m_bit==0)
+ {
+ // Apply the initial sbox
+ apply_sbox(initial_sbox);
+ }
+
+ // Compute the output and change the state
+ m_dataout_handler(BIT(m_state, m_bit));
+ }
+
+ if (state && !m_clock && !m_select)
+ {
+ if (!m_datain)
+ apply_bit_sbox(m_bit);
+
+ m_bit = (m_bit + 1) & 7;
+ }
+
+ m_clock = state;
+}
+
+
+///////////////
+
+cat702_piu_device::cat702_piu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ cat702_device_base(mconfig, CAT702_PIU, tag, owner, clock)
+{
+}
+
+void cat702_piu_device::write_select(int state)
+{
+ if (m_select != state)
+ {
+ if (!state)
+ {
+ m_state = 0xfc;
+ m_bit = 0;
+
+ apply_sbox(initial_sbox);
+ }
+ else
+ {
+ m_dataout_handler(1);
+ }
+
+ m_select = state;
+ }
+}
+
+void cat702_piu_device::write_clock(int state)
+{
+ /*
+ Pump It Up uses a CAT702 but accesses it directly and in a way that
+ seems conflicting with how the ZN uses it through the PS1's SIO.
+
+ This is the sequence performed with clock and data lines write and read data:
+ write unkbit 0
+ write unkbit 1
+ write select 0
+ loop for all bits that need to be transferred:
+ write clk = 0, data = x
+ write clk = x, data = 0/1
+ write clk = 1, data = x
+ read data
+ write select 1
+
+ Modifying the old code to work with PIU breaks ZN games.
+ */
+ if (state && !m_clock && !m_select)
+ {
+ // Compute the output and change the state
+ if (!m_datain)
+ apply_bit_sbox(m_bit);
+
+ m_bit = (m_bit + 1) & 7;
+
+ if (m_bit == 0)
+ {
+ // Apply the initial sbox
+ apply_sbox(initial_sbox);
+ }
+
+ m_dataout_handler(BIT(m_state, m_bit));
+ }
+
+ m_clock = state;
+}
diff --git a/src/devices/machine/cat702.h b/src/devices/machine/cat702.h
new file mode 100644
index 00000000000..306ca94abf5
--- /dev/null
+++ b/src/devices/machine/cat702.h
@@ -0,0 +1,63 @@
+// license:BSD-3-Clause
+// copyright-holders:smf
+/* CAT702 security chip */
+
+#ifndef MAME_MACHINE_CAT702_H
+#define MAME_MACHINE_CAT702_H
+
+#pragma once
+
+
+DECLARE_DEVICE_TYPE(CAT702, cat702_device)
+DECLARE_DEVICE_TYPE(CAT702_PIU, cat702_piu_device)
+
+class cat702_device_base : public device_t
+{
+public:
+ // configuration helpers
+ auto dataout_handler() { return m_dataout_handler.bind(); }
+
+ void write_datain(int state);
+
+protected:
+ cat702_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+
+ void apply_bit_sbox(int sel);
+ void apply_sbox(const uint8_t *sbox);
+
+ int m_select;
+ int m_clock;
+ int m_datain;
+ uint8_t m_state;
+ uint8_t m_bit;
+
+ devcb_write_line m_dataout_handler;
+
+private:
+ uint8_t compute_sbox_coef(int sel, int bit);
+
+ optional_memory_region m_region;
+ uint8_t m_transform[8];
+};
+
+class cat702_device : public cat702_device_base
+{
+public:
+ cat702_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void write_select(int state);
+ void write_clock(int state);
+};
+
+class cat702_piu_device : public cat702_device_base
+{
+public:
+ cat702_piu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void write_select(int state);
+ void write_clock(int state);
+};
+
+#endif // MAME_MACHINE_CAT702_H
diff --git a/src/devices/machine/cdp1852.cpp b/src/devices/machine/cdp1852.cpp
index b98b9a34fef..caa4f2517ad 100644
--- a/src/devices/machine/cdp1852.cpp
+++ b/src/devices/machine/cdp1852.cpp
@@ -41,9 +41,9 @@ enum
cdp1852_device::cdp1852_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, CDP1852, tag, owner, clock),
- m_read_mode(*this),
+ m_read_mode(*this, 0),
m_write_sr(*this),
- m_read_data(*this),
+ m_read_data(*this, 0),
m_write_data(*this),
m_new_data(false), m_data(0),
m_clock_active(true), m_sr(false), m_next_sr(false),
@@ -59,15 +59,9 @@ cdp1852_device::cdp1852_device(const machine_config &mconfig, const char *tag, d
void cdp1852_device::device_start()
{
- // resolve callbacks
- m_read_mode.resolve_safe(0);
- m_write_sr.resolve_safe();
- m_read_data.resolve_safe(0);
- m_write_data.resolve_safe();
-
// allocate timers
- m_update_do_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdp1852_device::update_do), this));
- m_update_sr_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdp1852_device::update_sr), this));
+ m_update_do_timer = timer_alloc(FUNC(cdp1852_device::update_do), this);
+ m_update_sr_timer = timer_alloc(FUNC(cdp1852_device::update_sr), this);
// register for state saving
save_item(NAME(m_new_data));
@@ -107,7 +101,7 @@ void cdp1852_device::device_reset()
// clock_w - clock write
//-------------------------------------------------
-WRITE_LINE_MEMBER(cdp1852_device::clock_w)
+void cdp1852_device::clock_w(int state)
{
if (m_clock_active != bool(state))
return;
diff --git a/src/devices/machine/cdp1852.h b/src/devices/machine/cdp1852.h
index 4f4bec622f9..2ccb214a632 100644
--- a/src/devices/machine/cdp1852.h
+++ b/src/devices/machine/cdp1852.h
@@ -40,7 +40,7 @@ public:
uint8_t read();
void write(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(clock_w);
+ void clock_w(int state);
uint8_t do_r() { return m_data; }
diff --git a/src/devices/machine/cdp1871.cpp b/src/devices/machine/cdp1871.cpp
index 36ce4b77892..ffe61b7340c 100644
--- a/src/devices/machine/cdp1871.cpp
+++ b/src/devices/machine/cdp1871.cpp
@@ -98,17 +98,17 @@ const uint8_t cdp1871_device::key_codes[4][11][8] =
cdp1871_device::cdp1871_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, CDP1871, tag, owner, clock),
- m_read_d1(*this),
- m_read_d2(*this),
- m_read_d3(*this),
- m_read_d4(*this),
- m_read_d5(*this),
- m_read_d6(*this),
- m_read_d7(*this),
- m_read_d8(*this),
- m_read_d9(*this),
- m_read_d10(*this),
- m_read_d11(*this),
+ m_read_d1(*this, 0xff),
+ m_read_d2(*this, 0xff),
+ m_read_d3(*this, 0xff),
+ m_read_d4(*this, 0xff),
+ m_read_d5(*this, 0xff),
+ m_read_d6(*this, 0xff),
+ m_read_d7(*this, 0xff),
+ m_read_d8(*this, 0xff),
+ m_read_d9(*this, 0xff),
+ m_read_d10(*this, 0xff),
+ m_read_d11(*this, 0xff),
m_write_da(*this),
m_write_rpt(*this),
m_inhibit(false),
@@ -133,26 +133,11 @@ cdp1871_device::cdp1871_device(const machine_config &mconfig, const char *tag, d
void cdp1871_device::device_start()
{
- // resolve callbacks
- m_read_d1.resolve_safe(0xff);
- m_read_d2.resolve_safe(0xff);
- m_read_d3.resolve_safe(0xff);
- m_read_d4.resolve_safe(0xff);
- m_read_d5.resolve_safe(0xff);
- m_read_d6.resolve_safe(0xff);
- m_read_d7.resolve_safe(0xff);
- m_read_d8.resolve_safe(0xff);
- m_read_d9.resolve_safe(0xff);
- m_read_d10.resolve_safe(0xff);
- m_read_d11.resolve_safe(0xff);
- m_write_da.resolve_safe();
- m_write_rpt.resolve_safe();
-
// set initial values
change_output_lines();
// allocate timers
- m_scan_timer = timer_alloc();
+ m_scan_timer = timer_alloc(FUNC(cdp1871_device::perform_scan), this);
m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
// register for state saving
@@ -172,10 +157,10 @@ void cdp1871_device::device_start()
//-------------------------------------------------
-// device_timer - handler timer events
+// perform_scan - periodically scan for keys
//-------------------------------------------------
-void cdp1871_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(cdp1871_device::perform_scan)
{
change_output_lines();
clock_scan_counters();
diff --git a/src/devices/machine/cdp1871.h b/src/devices/machine/cdp1871.h
index 50c0aaefdc9..4c560396dfb 100644
--- a/src/devices/machine/cdp1871.h
+++ b/src/devices/machine/cdp1871.h
@@ -56,22 +56,23 @@ public:
uint8_t read();
- DECLARE_READ_LINE_MEMBER( da_r ) { return m_da; }
- DECLARE_READ_LINE_MEMBER( rpt_r ) { return m_rpt; }
+ int da_r() { return m_da; }
+ int rpt_r() { return m_rpt; }
- DECLARE_WRITE_LINE_MEMBER( shift_w ) { m_shift = state; }
- DECLARE_WRITE_LINE_MEMBER( control_w ) { m_control = state; }
- DECLARE_WRITE_LINE_MEMBER( alpha_w ) { m_alpha = state; }
+ void shift_w(int state) { m_shift = state; }
+ void control_w(int state) { m_control = state; }
+ void alpha_w(int state) { m_alpha = state; }
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
void change_output_lines();
void clock_scan_counters();
void detect_keypress();
+ TIMER_CALLBACK_MEMBER(perform_scan);
+
private:
devcb_read8 m_read_d1;
devcb_read8 m_read_d2;
diff --git a/src/devices/machine/cdp1879.cpp b/src/devices/machine/cdp1879.cpp
index 1ecf168b3d5..7d843bcbc17 100644
--- a/src/devices/machine/cdp1879.cpp
+++ b/src/devices/machine/cdp1879.cpp
@@ -21,10 +21,10 @@ DEFINE_DEVICE_TYPE(CDP1879, cdp1879_device, "cdp1879", "RCA CDP1879 RTC")
// cdp1879_device - constructor
//-------------------------------------------------
-cdp1879_device::cdp1879_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, CDP1879, tag, owner, clock),
- device_rtc_interface(mconfig, *this),
- m_irq_w(*this)
+cdp1879_device::cdp1879_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, CDP1879, tag, owner, clock),
+ device_rtc_interface(mconfig, *this),
+ m_irq_w(*this)
{
}
@@ -36,11 +36,9 @@ cdp1879_device::cdp1879_device(const machine_config &mconfig, const char *tag, d
void cdp1879_device::device_start()
{
// allocate timers
- m_clock_timer = timer_alloc();
+ m_clock_timer = timer_alloc(FUNC(cdp1879_device::clock_tick), this);
m_clock_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
- m_irq_w.resolve_safe();
-
// state saving
save_item(NAME(m_regs));
save_item(NAME(m_comparator_state));
@@ -61,10 +59,10 @@ void cdp1879_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// clock_tick - advance the clock
//-------------------------------------------------
-void cdp1879_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(cdp1879_device::clock_tick)
{
advance_seconds();
diff --git a/src/devices/machine/cdp1879.h b/src/devices/machine/cdp1879.h
index 2f2740df32a..4dc761b5fd7 100644
--- a/src/devices/machine/cdp1879.h
+++ b/src/devices/machine/cdp1879.h
@@ -29,7 +29,6 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
@@ -38,6 +37,8 @@ protected:
void set_irq(int bit);
void update_rtc();
+ TIMER_CALLBACK_MEMBER(clock_tick);
+
private:
// registers
enum
diff --git a/src/devices/machine/ch376.cpp b/src/devices/machine/ch376.cpp
new file mode 100644
index 00000000000..6f971de7186
--- /dev/null
+++ b/src/devices/machine/ch376.cpp
@@ -0,0 +1,527 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ ch376.cpp
+
+ "File manage and control chip CH376"
+ https://www.mpja.com/download/ch376ds1.pdf
+ https://github.com/djuseeq/Ch376msc/blob/master/src/CommDef.h
+
+ This is a module intended to offload USB and USB mass storage
+ I/O from a small microcontroller or microprocessor.
+
+ It has 3 host interfaces:
+ 1) A regular 8-bit bus with 8 data lines, an address line,
+ chip select, read enable, and write enable lines
+ 2) An SPI bus interface (SCS, SCK, MOSI, MISO lines)
+ 3) An asynchronous serial interface (TxD and RxD lines)
+
+ And 2 guest interfaces: USB 2.0 and a second 4-wire SPI bus for SD/MMC/TF cards.
+
+ The module can give high level directory/open/close/read/write access to
+ files on a FAT12, FAT16, or FAT32 filesystem.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "ch376.h"
+
+#include "multibyte.h"
+
+#include "logmacro.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(CH376, ch376_device, "ch376", "CH376 USB/file manager module")
+
+static constexpr u8 STATUS_USB_INT_SUCCESS = 0x14;
+static constexpr u8 STATUS_USB_INT_CONNECT = 0x15;
+static constexpr u8 STATUS_USB_INT_DISK_READ = 0x1d;
+static constexpr u8 STATUS_USB_INT_DISK_WRITE = 0x1e;
+static constexpr u8 STATUS_USB_INT_DISK_ERR = 0x1f;
+static constexpr u8 STATUS_ERR_MISS_FILE = 0x42;
+
+// despite the name, this isn't a command
+static constexpr u8 CMD_RET_SUCCESS = 0x51;
+
+static constexpr u8 CMD_GET_IC_VER = 0x01;
+static constexpr u8 CMD_CHECK_EXIST = 0x06;
+static constexpr u8 CMD_GET_FILE_SIZE = 0x0c;
+static constexpr u8 CMD_SET_USB_MODE = 0x15;
+static constexpr u8 CMD_GET_STATUS = 0x22;
+static constexpr u8 CMD_RD_USB_DATA0 = 0x27;
+static constexpr u8 CMD_WR_REQ_DATA = 0x2d;
+static constexpr u8 CMD_SET_FILE_NAME = 0x2f;
+static constexpr u8 CMD_DISK_MOUNT = 0x31;
+static constexpr u8 CMD_FILE_OPEN = 0x32;
+static constexpr u8 CMD_FILE_ENUM_GO = 0x33;
+static constexpr u8 CMD_FILE_CLOSE = 0x36;
+static constexpr u8 CMD_BYTE_LOCATE = 0x39;
+static constexpr u8 CMD_BYTE_READ = 0x3a;
+static constexpr u8 CMD_BYTE_READ_GO = 0x3b;
+static constexpr u8 CMD_BYTE_WRITE = 0x3c;
+static constexpr u8 CMD_BYTE_WR_GO = 0x3d;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ch376_device - constructor
+//-------------------------------------------------
+
+ch376_device::ch376_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, CH376, tag, owner, clock),
+ m_state(0),
+ m_status(0),
+ m_int_status(0),
+ m_data(0),
+ m_last_command(0),
+ m_pointer(0),
+ m_file_pos(0),
+ m_dataPtr(0),
+ m_dataLen(0),
+ m_readLen(0),
+ m_cur_file_size(0)
+{
+ std::fill_n(&m_file_name[0], sizeof(m_file_name), 0);
+ std::fill_n(&m_dataBuffer[0], sizeof(m_dataBuffer), 0);
+ m_current_directory.clear();
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ch376_device::device_start()
+{
+ save_item(NAME(m_state));
+ save_item(NAME(m_status));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_data));
+ save_item(NAME(m_file_name));
+ save_item(NAME(m_pointer));
+ save_item(NAME(m_dataPtr));
+ save_item(NAME(m_dataLen));
+ save_item(NAME(m_readLen));
+
+ m_directory.reset();
+ m_file.reset();
+}
+
+u8 ch376_device::read(offs_t offset)
+{
+ if (offset & 1)
+ {
+ return m_status;
+ }
+
+ switch (m_state)
+ {
+ case STATE_GET_STATUS:
+ m_state = STATE_IDLE;
+ return m_int_status;
+
+ case STATE_WRITE_SIZE_REPLY:
+ m_state = STATE_READ_WRITE_DATA;
+ m_dataPtr = 0;
+ return m_data;
+ }
+
+ if ((m_dataLen > 0) && (m_dataPtr < m_dataLen))
+ {
+ return m_dataBuffer[m_dataPtr++];
+ }
+
+ return m_data;
+}
+
+void ch376_device::write(offs_t offset, u8 data)
+{
+ if (offset & 1) // write command
+ {
+ //printf("CH376: write command %02x\n", data);
+ m_last_command = data;
+ switch (data)
+ {
+ case 0x16: // not a documented valid command, but apparently used by the BBC Micro software
+ m_dataBuffer[0] = m_int_status = STATUS_USB_INT_CONNECT;
+ m_dataPtr = 0;
+ m_dataLen = 1;
+ break;
+
+ case CMD_CHECK_EXIST:
+ m_state = STATE_CHECK_EXIST;
+ break;
+
+ case CMD_GET_IC_VER:
+ m_dataBuffer[0] = 0x41;
+ m_dataPtr = 0;
+ m_dataLen = 1;
+ break;
+
+ case CMD_GET_FILE_SIZE:
+ m_state = STATE_GET_FILE_SIZE;
+ break;
+
+ case CMD_SET_USB_MODE:
+ m_state = STATE_USB_MODE_SET;
+ break;
+
+ case CMD_GET_STATUS:
+ m_state = STATE_GET_STATUS;
+ break;
+
+ case CMD_RD_USB_DATA0:
+ m_int_status = STATUS_USB_INT_DISK_READ;
+ break;
+
+ case CMD_WR_REQ_DATA:
+ {
+ int lenToWrite = (m_readLen >= 255) ? 255 : m_readLen;
+ m_data = (lenToWrite & 0xff);
+ m_readLen -= lenToWrite;
+ m_state = STATE_WRITE_SIZE_REPLY;
+ m_dataLen = lenToWrite;
+ }
+ break;
+
+ case CMD_SET_FILE_NAME:
+ m_state = STATE_SET_FILE_NAME;
+ m_pointer = 0;
+ break;
+
+ case CMD_DISK_MOUNT:
+ m_int_status = STATUS_USB_INT_SUCCESS;
+ break;
+
+ case CMD_FILE_OPEN:
+ /*
+ CH376 allows paths with a leading / or \ to indicate the root of the SD card.
+ Directories are chained by an unusual method: start with the root dir (leading path separator),
+ then open each subdirectory without a leading path separator, and finally open the file without
+ a leading path separator.
+
+ The BOOTI card ignores directories entirely, so the implmentation here is not tested with that
+ scenario but it should work.
+ */
+ if (m_file_name[strlen(m_file_name) - 1] == '*')
+ {
+ // it's a directory
+ // remove the wildcard
+ m_file_name[strlen(m_file_name) - 1] = '\0';
+ std::string tmpPath(machine().options().share_directory());
+ tmpPath.append(PATH_SEPARATOR);
+ if ((m_file_name[0] == '/') || (m_file_name[0] == '\\'))
+ {
+ tmpPath.append(&m_file_name[1]);
+ m_current_directory.clear();
+ m_current_directory = tmpPath;
+ }
+ else
+ {
+ tmpPath.append(m_file_name);
+ m_current_directory.append(PATH_SEPARATOR);
+ m_current_directory.append(tmpPath);
+ }
+ m_directory = osd::directory::open(tmpPath);
+ if (generateNextDirEntry())
+ {
+ m_int_status = STATUS_USB_INT_DISK_READ;
+ }
+ else
+ {
+ m_int_status = STATUS_USB_INT_DISK_ERR;
+ }
+ }
+ else
+ {
+ std::string tmpPath = m_current_directory;
+ u64 size;
+
+ // compose this name with the last directory opened, unless it starts with a path separator
+ tmpPath.append(PATH_SEPARATOR);
+ if ((m_file_name[0] == '/') || (m_file_name[0] == '\\'))
+ {
+ tmpPath.append(&m_file_name[1]);
+ }
+ else
+ {
+ tmpPath.append(m_file_name);
+ }
+
+ if (!osd_file::open(tmpPath, OPEN_FLAG_READ|OPEN_FLAG_WRITE, m_file, size))
+ {
+ m_int_status = STATUS_USB_INT_SUCCESS;
+ m_cur_file_size = size & 0xffffffff;
+ }
+ else
+ {
+ m_int_status = STATUS_USB_INT_DISK_ERR;
+ m_cur_file_size = 0;
+ }
+ }
+ break;
+
+ case CMD_FILE_ENUM_GO:
+ if (generateNextDirEntry())
+ {
+ m_int_status = STATUS_USB_INT_DISK_READ;
+ }
+ else // end of directory
+ {
+ m_int_status = STATUS_ERR_MISS_FILE;
+ }
+ break;
+
+ case CMD_FILE_CLOSE:
+ m_directory.reset();
+ m_file.reset();
+ m_int_status = STATUS_USB_INT_DISK_READ;
+ break;
+
+ case CMD_BYTE_LOCATE:
+ m_state = STATE_SEEK;
+ break;
+
+ case CMD_BYTE_READ:
+ m_state = STATE_READ_SIZE;
+ break;
+
+ case CMD_BYTE_READ_GO:
+ if (m_readLen > 0)
+ {
+ doNextFileRead();
+ m_int_status = STATUS_USB_INT_DISK_READ;
+ }
+ else
+ {
+ m_dataBuffer[0] = 0;
+ m_dataLen = 0;
+ m_int_status = STATUS_USB_INT_SUCCESS;
+ }
+ break;
+
+ case CMD_BYTE_WRITE:
+ m_state = STATE_READ_SIZE;
+ break;
+
+ case CMD_BYTE_WR_GO:
+ if (m_dataPtr > 0)
+ {
+ u32 actual;
+ m_state = STATE_IDLE;
+ m_file->write(&m_dataBuffer[0], m_file_pos, m_dataLen, actual);
+ m_file_pos += m_dataLen;
+ if (m_readLen > 0)
+ {
+ m_int_status = STATUS_USB_INT_DISK_WRITE;
+ }
+ else
+ {
+ m_int_status = STATUS_USB_INT_SUCCESS;
+ }
+ }
+ else
+ {
+ m_int_status = STATUS_USB_INT_SUCCESS;
+ }
+ break;
+
+ default:
+ logerror("CH376: unhandled command %02x\n", data);
+ break;
+ }
+ }
+ else
+ {
+ switch (m_state)
+ {
+ case STATE_CHECK_EXIST:
+ m_data = (data ^ 0xff);
+ m_state = STATE_IDLE;
+ break;
+
+ case STATE_USB_MODE_SET:
+ m_state = STATE_IDLE;
+ if ((data == 0x6) || (data == 0x7))
+ {
+ m_data = CMD_RET_SUCCESS;
+ }
+ break;
+
+ case STATE_SET_FILE_NAME:
+ m_file_name[m_pointer++] = data;
+ if (m_pointer == 14)
+ {
+ m_state = STATE_IDLE;
+ // is this shorter than 8.3?
+ if (m_file_name[8] == '\0')
+ {
+ int idx = 8;
+ while (m_file_name[idx] == '\0')
+ {
+ idx--;
+ }
+ idx++;
+ for (int i = 0; i < 5; i++)
+ {
+ m_file_name[idx + i] = m_file_name[9 + i];
+ }
+ }
+ }
+ break;
+
+ case STATE_SEEK:
+ case STATE_SEEK1:
+ case STATE_SEEK2:
+ m_file_pos >>= 8;
+ m_file_pos |= (data << 24);
+ m_state++;
+ break;
+
+ case STATE_SEEK3:
+ m_file_pos >>= 8;
+ m_file_pos |= (data << 24);
+ m_state = STATE_IDLE;
+ m_int_status = STATUS_USB_INT_SUCCESS;
+ break;
+
+ case STATE_READ_SIZE:
+ m_readLen = data;
+ m_state++;
+ break;
+
+ case STATE_READ_SIZE2:
+ m_readLen |= (data << 8);
+ m_state = STATE_IDLE;
+ m_int_status = STATUS_USB_INT_DISK_READ;
+
+ if (m_last_command == 0x3a)
+ {
+ doNextFileRead();
+ }
+ break;
+
+ case STATE_READ_WRITE_DATA:
+ m_dataBuffer[m_dataPtr++] = data;
+ break;
+
+ case STATE_GET_FILE_SIZE:
+ // the host must write 0x68 here; it's unclear what the real chip does if the value doesn't match.
+ // reply with the size of the currently open file.
+ put_u32le(m_dataBuffer, m_cur_file_size);
+ m_dataPtr = 0;
+ m_dataLen = 4;
+ break;
+ }
+ }
+}
+
+bool ch376_device::generateNextDirEntry()
+{
+ const osd::directory::entry *ourEntry;
+
+ m_dataPtr = 0;
+ m_dataLen = 0;
+
+ // no directory?
+ if (m_directory == nullptr)
+ {
+ return false;
+ }
+
+ // is there an entry?
+ if ((ourEntry = m_directory->read()) == nullptr)
+ {
+ return false;
+ }
+
+ std::fill_n(&m_dataBuffer[0], sizeof(m_dataBuffer), 0);
+ m_dataBuffer[0] = 32;
+ if (ourEntry->type == osd::directory::entry::entry_type::DIR)
+ {
+ strncpy(reinterpret_cast<char *>(&m_dataBuffer[1]), ourEntry->name, 8);
+ m_dataBuffer[0xc] = 0x10; // directory type
+ }
+ else if (ourEntry->type == osd::directory::entry::entry_type::FILE)
+ {
+ int dotIdx = 8;
+ for (int idx = (strlen(ourEntry->name) - 1); idx >= 0; idx--)
+ {
+ if (ourEntry->name[idx] == '.')
+ {
+ dotIdx = idx;
+ break;
+ }
+ }
+
+ // is this an 8.3 filename? CH376 can only really cope with 8.3, so
+ // skip this entry and recurse to get the next one.
+ if (dotIdx > 8)
+ {
+ return generateNextDirEntry();
+ }
+
+ std::fill_n(&m_dataBuffer[1], 11, 0x20);
+
+ int baseLen = std::min(8, dotIdx);
+ for (int idx = 0; idx < baseLen; idx++)
+ {
+ m_dataBuffer[idx + 1] = toupper(ourEntry->name[idx]);
+ if (ourEntry->name[idx] == '\0')
+ {
+ baseLen = idx;
+ break;
+ }
+ }
+
+ // copy the extension (up to 3 chars, if we found one)
+ if (ourEntry->name[dotIdx] == '.')
+ {
+ dotIdx++;
+ for (int idx = 0; idx < 3; idx++)
+ {
+ if ((idx + dotIdx) >= strlen(ourEntry->name))
+ {
+ break;
+ }
+ m_dataBuffer[idx + 8 + 1] = toupper(ourEntry->name[idx + dotIdx]);
+ }
+ }
+
+ m_dataBuffer[0xc] = 0; // no attributes
+
+ if (ourEntry->size >= u64(0x100000000))
+ std::fill_n(&m_dataBuffer[0x1d], 4, 0xff);
+ else
+ put_u32le(&m_dataBuffer[0x1d], ourEntry->size);
+ }
+ else // not a file or directory, recurse and hope the next one's better
+ {
+ return generateNextDirEntry();
+ }
+
+ m_dataLen = 32;
+ return true;
+}
+
+void ch376_device::doNextFileRead()
+{
+ int lenToRead = (m_readLen >= 255) ? 255 : m_readLen;
+ u32 actualRead;
+
+ m_readLen -= lenToRead;
+ m_file->read(&m_dataBuffer[1], m_file_pos, lenToRead, actualRead);
+ m_dataBuffer[0] = (lenToRead & 0xff);
+ m_file_pos += actualRead;
+ m_dataLen = 256;
+ m_dataPtr = 0;
+}
diff --git a/src/devices/machine/ch376.h b/src/devices/machine/ch376.h
new file mode 100644
index 00000000000..d00586b1503
--- /dev/null
+++ b/src/devices/machine/ch376.h
@@ -0,0 +1,81 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/***************************************************************************
+
+ ch376.h
+
+ "File manage and control chip CH376"
+ This is a module intended to offload USB and USB mass storage
+ I/O from a small microcontroller or microprocessor.
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_CH376_H
+#define MAME_MACHINE_CH376_H
+
+#pragma once
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> ch376_device
+
+class ch376_device : public device_t
+{
+public:
+ // construction/destruction
+ ch376_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+private:
+ enum
+ {
+ STATE_IDLE = 0,
+ STATE_USB_MODE_SET,
+ STATE_GET_STATUS,
+ STATE_SET_FILE_NAME,
+ STATE_SEEK,
+ STATE_SEEK1,
+ STATE_SEEK2,
+ STATE_SEEK3,
+ STATE_READ_SIZE,
+ STATE_READ_SIZE2,
+ STATE_WRITE_SIZE_REPLY,
+ STATE_READ_WRITE_DATA,
+ STATE_GET_FILE_SIZE,
+ STATE_CHECK_EXIST
+ };
+
+ bool generateNextDirEntry();
+ void doNextFileRead();
+
+ int m_state;
+ u8 m_status, m_int_status, m_data, m_last_command;
+ char m_file_name[16];
+ int m_pointer;
+ std::string m_current_directory;
+ osd::directory::ptr m_directory;
+ osd_file::ptr m_file;
+ u32 m_file_pos;
+
+ u8 m_dataBuffer[512];
+ int m_dataPtr, m_dataLen;
+ u16 m_readLen;
+ u32 m_cur_file_size;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(CH376, ch376_device)
+
+#endif // MAME_MACHINE_CH376_H
diff --git a/src/devices/machine/chessmachine.cpp b/src/devices/machine/chessmachine.cpp
index ce0d358f183..a7db23f99fd 100644
--- a/src/devices/machine/chessmachine.cpp
+++ b/src/devices/machine/chessmachine.cpp
@@ -10,14 +10,15 @@ This is the 2nd (1992) version of The ChessMachine, it is used in:
- The ChessMachine EC2, Amiga external module
- Mephisto Risc 1MB/II, chess computer
-Unlike the SR model (devices/bus/isa/chessmsr.*), RAM size and CPU type
-are the same on every known device.
-
+Hardware notes:
- VLSI-ARM VY86C010-12QC (ARM2 CPU)
- 1MB RAM (8*Siemens HYB514256B-60)
- 128 bytes PROM (4*DM74S288AN)
- 2 GALs for I/O handling
+Unlike the SR model (devices/bus/isa/chessmsr.*), RAM size and CPU type
+are the same on every known device.
+
Only 4 lines for I/O, so that part is much slower than the SR model.
There is no XTAL, it looks like there's a variable resistor for tweaking
@@ -25,14 +26,13 @@ CPU speed. It should be around 14-16MHz. The ARM CPU is rated 12MHz, they
probably went for this solution to get optimum possible speed for each module.
TODO:
-- PC version still gives a sync error on boot sometimes, probably related to quantum
- is interrupt handling correct?
-- timer shouldn't be needed for disabling bootstrap, real ARM has already read the next opcode
+- timer shouldn't be needed for disabling bootrom, real ARM has already read the next opcode
*/
#include "emu.h"
-#include "machine/chessmachine.h"
+#include "chessmachine.h"
DEFINE_DEVICE_TYPE(CHESSMACHINE, chessmachine_device, "chessmachine", "Tasc ChessMachine")
@@ -44,9 +44,9 @@ DEFINE_DEVICE_TYPE(CHESSMACHINE, chessmachine_device, "chessmachine", "Tasc Ches
chessmachine_device::chessmachine_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, CHESSMACHINE, tag, owner, clock),
m_maincpu(*this, "maincpu"),
- m_bootstrap(*this, "bootstrap"),
+ m_bootrom(*this, "bootrom"),
m_ram(*this, "ram"),
- m_disable_bootstrap(*this, "disable_bootstrap"),
+ m_disable_bootrom(*this, "disable_bootrom"),
m_data_out(*this)
{ }
@@ -58,15 +58,12 @@ chessmachine_device::chessmachine_device(const machine_config &mconfig, const ch
void chessmachine_device::device_start()
{
- // resolve callbacks
- m_data_out.resolve_safe();
-
// zerofill
- m_bootstrap_enabled = false;
- m_latch[0] = m_latch[1] = 0;
+ m_bootrom_enabled = false;
+ memset(m_latch, 0, sizeof(m_latch));
// register for savestates
- save_item(NAME(m_bootstrap_enabled));
+ save_item(NAME(m_bootrom_enabled));
save_item(NAME(m_latch));
}
@@ -76,35 +73,48 @@ void chessmachine_device::device_start()
// external handlers
//-------------------------------------------------
-void chessmachine_device::sync0_callback(void *ptr, s32 param)
+void chessmachine_device::data0_w_sync(s32 param)
{
- m_latch[0] = (m_latch[0] & 0x80) | param;
+ if ((m_latch[0] & 1) != param)
+ {
+ machine().scheduler().perfect_quantum(attotime::from_usec(50));
+ m_latch[0] = (m_latch[0] & 0x80) | param;
+ }
}
void chessmachine_device::data0_w(int state)
{
- machine().scheduler().synchronize(timer_expired_delegate(FUNC(chessmachine_device::sync0_callback), this), state ? 1 : 0);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(chessmachine_device::data0_w_sync), this), state ? 1 : 0);
}
-void chessmachine_device::sync1_callback(void *ptr, s32 param)
+void chessmachine_device::data1_w_sync(s32 param)
{
- m_latch[0] = (m_latch[0] & 1) | param;
-
- // cause interrupt?
- m_maincpu->set_input_line(ARM_FIRQ_LINE, param ? ASSERT_LINE : CLEAR_LINE);
+ if ((m_latch[0] & 0x80) != param)
+ {
+ machine().scheduler().perfect_quantum(attotime::from_usec(50));
+ m_latch[0] = (m_latch[0] & 1) | param;
+
+ // cause interrupt?
+ m_maincpu->set_input_line(ARM_FIRQ_LINE, param ? ASSERT_LINE : CLEAR_LINE);
+ }
}
void chessmachine_device::data1_w(int state)
{
- machine().scheduler().synchronize(timer_expired_delegate(FUNC(chessmachine_device::sync1_callback), this), state ? 0x80 : 0);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(chessmachine_device::data1_w_sync), this), state ? 0x80 : 0);
}
-void chessmachine_device::reset_w(int state)
+void chessmachine_device::reset_w_sync(s32 param)
{
- m_maincpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
+ m_maincpu->set_input_line(INPUT_LINE_RESET, param ? ASSERT_LINE : CLEAR_LINE);
- if (state)
- m_bootstrap_enabled = true;
+ if (!m_bootrom_enabled && param)
+ install_bootrom(true);
+}
+
+void chessmachine_device::reset_w(int state)
+{
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(chessmachine_device::reset_w_sync), this), state ? 1 : 0);
}
@@ -113,16 +123,24 @@ void chessmachine_device::reset_w(int state)
// internal
//-------------------------------------------------
-u32 chessmachine_device::bootstrap_r(offs_t offset)
+void chessmachine_device::install_bootrom(bool enable)
{
- return (m_bootstrap_enabled) ? m_bootstrap[offset] : m_ram[offset];
+ address_space &program = m_maincpu->space(AS_PROGRAM);
+ program.unmap_readwrite(0, m_bootrom.bytes() - 1);
+
+ if (enable)
+ program.install_rom(0, m_bootrom.bytes() - 1, m_bootrom);
+ else
+ program.install_ram(0, m_ram.bytes() - 1, m_ram);
+
+ m_bootrom_enabled = enable;
}
-u32 chessmachine_device::disable_bootstrap_r()
+u32 chessmachine_device::disable_bootrom_r()
{
- // disconnect bootstrap rom from the bus after next opcode
- if (m_bootstrap_enabled && !m_disable_bootstrap->enabled() && !machine().side_effects_disabled())
- m_disable_bootstrap->adjust(m_maincpu->cycles_to_attotime(5));
+ // disconnect bootrom from the bus after next opcode
+ if (m_bootrom_enabled && !m_disable_bootrom->enabled() && !machine().side_effects_disabled())
+ m_disable_bootrom->adjust(m_maincpu->cycles_to_attotime(5));
return 0;
}
@@ -130,9 +148,8 @@ u32 chessmachine_device::disable_bootstrap_r()
void chessmachine_device::main_map(address_map &map)
{
map(0x00000000, 0x000fffff).ram().share("ram");
- map(0x00000000, 0x0000007f).r(FUNC(chessmachine_device::bootstrap_r));
map(0x00400000, 0x00400003).mirror(0x003ffffc).rw(FUNC(chessmachine_device::internal_r), FUNC(chessmachine_device::internal_w)).umask32(0x000000ff);
- map(0x01800000, 0x01800003).r(FUNC(chessmachine_device::disable_bootstrap_r));
+ map(0x01800000, 0x01800003).r(FUNC(chessmachine_device::disable_bootrom_r));
}
void chessmachine_device::device_add_mconfig(machine_config &config)
@@ -141,7 +158,7 @@ void chessmachine_device::device_add_mconfig(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &chessmachine_device::main_map);
m_maincpu->set_copro_type(arm_cpu_device::copro_type::VL86C020);
- TIMER(config, "disable_bootstrap").configure_generic(FUNC(chessmachine_device::disable_bootstrap));
+ TIMER(config, "disable_bootrom").configure_generic(FUNC(chessmachine_device::disable_bootrom));
}
@@ -151,7 +168,7 @@ void chessmachine_device::device_add_mconfig(machine_config &config)
//-------------------------------------------------
ROM_START( chessmachine )
- ROM_REGION32_LE( 0x80, "bootstrap", 0 )
+ ROM_REGION32_LE( 0x80, "bootrom", 0 )
ROM_LOAD32_BYTE( "74s288.1", 0x00, 0x20, CRC(284114e2) SHA1(df4037536d505d7240bb1d70dc58f59a34ab77b4) )
ROM_LOAD32_BYTE( "74s288.2", 0x01, 0x20, CRC(9f239c75) SHA1(aafaf30dac90f36b01f9ee89903649fc4ea0480d) )
ROM_LOAD32_BYTE( "74s288.3", 0x02, 0x20, CRC(0455360b) SHA1(f1486142330f2c39a4d6c479646030d31443d1c8) )
diff --git a/src/devices/machine/chessmachine.h b/src/devices/machine/chessmachine.h
index 4d589fc97c3..d07ac764e5b 100644
--- a/src/devices/machine/chessmachine.h
+++ b/src/devices/machine/chessmachine.h
@@ -34,25 +34,28 @@ protected:
virtual void device_start() override;
virtual void device_reset_after_children() override { reset_w(1); }
virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_post_load() override { install_bootrom(m_bootrom_enabled); }
virtual const tiny_rom_entry *device_rom_region() const override;
private:
required_device<arm_cpu_device> m_maincpu;
- required_region_ptr<u32> m_bootstrap;
+ required_region_ptr<u32> m_bootrom;
required_shared_ptr<u32> m_ram;
- required_device<timer_device> m_disable_bootstrap;
+ required_device<timer_device> m_disable_bootrom;
devcb_write_line m_data_out;
u8 m_latch[2];
- void sync0_callback(void *ptr, s32 param);
- void sync1_callback(void *ptr, s32 param);
+ bool m_bootrom_enabled;
- bool m_bootstrap_enabled;
- TIMER_DEVICE_CALLBACK_MEMBER(disable_bootstrap) { m_bootstrap_enabled = false; }
- u32 disable_bootstrap_r();
- u32 bootstrap_r(offs_t offset);
+ void data0_w_sync(s32 param);
+ void data1_w_sync(s32 param);
+ void reset_w_sync(s32 param);
+
+ void install_bootrom(bool enable);
+ TIMER_DEVICE_CALLBACK_MEMBER(disable_bootrom) { install_bootrom(false); }
+ u32 disable_bootrom_r();
u8 internal_r() { return m_latch[0]; }
void internal_w(u8 data) { m_latch[1] = data & 1; m_data_out(m_latch[1]); }
diff --git a/src/devices/machine/clock.cpp b/src/devices/machine/clock.cpp
index 374dc8a16a8..670dfba09aa 100644
--- a/src/devices/machine/clock.cpp
+++ b/src/devices/machine/clock.cpp
@@ -1,46 +1,131 @@
// license:BSD-3-Clause
-// copyright-holders:smf
+// copyright-holders:smf, hap
+/*
+
+Generic clock signal device
+
+Set the period either with device_t m_clock, or with set_period if it needs
+to be more fine-tuned (m_clock has higher priority).
+
+The duty cycle can be changed with set_duty_cycle (default is 50%), or the
+pulse width (active time) can be set directly with set_pulse_width.
+
+Output signal at machine start is right after falling edge.
+
+*/
+
#include "emu.h"
#include "clock.h"
DEFINE_DEVICE_TYPE(CLOCK, clock_device, "clock", "Clock")
-clock_device::clock_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, CLOCK, tag, owner, clock),
+clock_device::clock_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, CLOCK, tag, owner, clock),
m_signal(0),
- m_timer(nullptr),
+ m_output(-1),
+ m_duty(0.5),
+ m_period(attotime::never),
+ m_pw(attotime::never),
+ m_timer_init(nullptr),
+ m_timer_tick(nullptr),
m_signal_handler(*this)
{
}
void clock_device::device_start()
{
- m_signal_handler.resolve();
-
save_item(NAME(m_signal));
+ save_item(NAME(m_output));
+ save_item(NAME(m_duty));
+ save_item(NAME(m_period));
+ save_item(NAME(m_pw));
+ save_item(NAME(m_thigh));
+ save_item(NAME(m_tlow));
+
+ m_timer_init = timer_alloc(FUNC(clock_device::clock_init), this);
+ m_timer_tick = timer_alloc(FUNC(clock_device::clock_tick), this);
+ reinit();
+}
+
+void clock_device::reinit()
+{
+ if (!m_timer_init)
+ return;
+
+ // not using synchronize(), that may retrigger more than once
+ m_timer_init->adjust(attotime::zero);
}
-void clock_device::device_clock_changed()
+void clock_device::output()
{
- if (!m_signal_handler.isnull() && m_clock > 0)
+ if (m_signal != m_output)
{
- if (m_timer == nullptr)
- m_timer = timer_alloc(0);
+ m_output = m_signal;
+ m_signal_handler(m_output);
+ }
+}
- const attotime period(attotime::from_hz(m_clock * 2));
+TIMER_CALLBACK_MEMBER(clock_device::clock_init)
+{
+ attotime period = (m_clock > 0) ? attotime::from_hz(m_clock) : m_period;
+ assert(!period.is_zero());
- attotime next = period - m_timer->elapsed();
- if (next < attotime::zero)
- next = attotime::zero;
+ if (period.is_never())
+ {
+ m_timer_tick->adjust(attotime::never);
+ return;
+ }
- m_timer->adjust(next, 0, period);
+ if (!m_pw.is_never())
+ {
+ // set timing via pulse width
+ attotime pw = m_pw;
+ if (pw > period)
+ pw = period;
+
+ m_thigh = pw;
+ m_tlow = period - pw;
+ }
+ else
+ {
+ // set timing via duty cycle
+ if (m_duty == 0.5)
+ {
+ m_thigh = period / 2;
+ m_tlow = m_thigh;
+ }
+ else if (m_duty == 0.0)
+ {
+ m_thigh = attotime::zero;
+ m_tlow = period;
+ }
+ else if (m_duty == 1.0)
+ {
+ m_thigh = period;
+ m_tlow = attotime::zero;
+ }
+ else
+ {
+ double p = period.as_double();
+ m_thigh = attotime::from_double(m_duty * p);
+ m_tlow = attotime::from_double((1.0 - m_duty) * p);
+ }
}
- else if (m_timer != nullptr)
- m_timer->adjust(attotime::never);
+
+ attotime next = m_signal ? m_thigh : m_tlow;
+ if (next < m_timer_tick->remaining())
+ m_timer_tick->adjust(next);
}
-void clock_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(clock_device::clock_tick)
{
- m_signal = !m_signal;
- m_signal_handler(m_signal);
+ if (m_thigh.is_zero())
+ m_signal = 0;
+ else if (m_tlow.is_zero())
+ m_signal = 1;
+ else
+ m_signal ^= 1;
+
+ m_timer_tick->adjust(m_signal ? m_thigh : m_tlow);
+ output();
}
diff --git a/src/devices/machine/clock.h b/src/devices/machine/clock.h
index 4bf0bed47a0..0fceeb7d9cd 100644
--- a/src/devices/machine/clock.h
+++ b/src/devices/machine/clock.h
@@ -1,27 +1,50 @@
// license:BSD-3-Clause
-// copyright-holders:smf
+// copyright-holders:smf, hap
+/*
+
+ Generic clock signal device
+
+*/
+
#ifndef MAME_MACHINE_CLOCK_H
#define MAME_MACHINE_CLOCK_H
#pragma once
-
class clock_device : public device_t
{
public:
+ clock_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
auto signal_handler() { return m_signal_handler.bind(); }
- DECLARE_READ_LINE_MEMBER(signal_r) { return m_signal; }
+ auto &set_period(attotime period) { m_period = period; reinit(); return *this; }
+ auto &set_pulse_width(attotime pw) { assert(!pw.is_never()); m_pw = pw; reinit(); return *this; }
+ auto &set_duty_cycle(double duty) { assert(duty >= 0.0 && duty <= 1.0); m_duty = duty; m_pw = attotime::never; reinit(); return *this; }
- clock_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ int signal_r() { return m_signal; }
protected:
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void device_clock_changed() override;
+ virtual void device_reset() override { output(); }
+ virtual void device_clock_changed() override { reinit(); }
+
+ TIMER_CALLBACK_MEMBER(clock_init);
+ TIMER_CALLBACK_MEMBER(clock_tick);
private:
+ void reinit();
+ void output();
+
int m_signal;
- emu_timer *m_timer;
+ int m_output;
+ double m_duty;
+ attotime m_period;
+ attotime m_pw;
+ attotime m_thigh;
+ attotime m_tlow;
+
+ emu_timer *m_timer_init;
+ emu_timer *m_timer_tick;
devcb_write_line m_signal_handler;
};
diff --git a/src/devices/machine/com52c50.cpp b/src/devices/machine/com52c50.cpp
new file mode 100644
index 00000000000..7f4ad470c01
--- /dev/null
+++ b/src/devices/machine/com52c50.cpp
@@ -0,0 +1,157 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/***************************************************************************
+
+ Standard Microsystems Corp. COM52C50 Twinax Interface Circuit (TIC)
+
+ Skeleton device.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "com52c50.h"
+
+
+// device type definition
+DEFINE_DEVICE_TYPE(COM52C50, com52c50_device, "com52c50", "SMC COM52C50 TIC")
+
+com52c50_device::com52c50_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, COM52C50, tag, owner, clock)
+ , m_int1_callback(*this)
+ , m_int2_callback(*this)
+ , m_rx_dma_callback(*this)
+ , m_tx_dma_callback(*this)
+ , m_int_mask(0)
+ , m_int_status(0)
+ , m_zero_fill(0)
+ , m_present_address(0)
+ , m_rx_status(0)
+ , m_tx_status(0)
+ , m_control(0)
+ , m_mode(0)
+{
+}
+
+void com52c50_device::map(address_map &map)
+{
+ map(0, 0).w(FUNC(com52c50_device::mode_w));
+ map(1, 1).rw(FUNC(com52c50_device::int_status_r), FUNC(com52c50_device::int_mask_w));
+ map(2, 2).rw(FUNC(com52c50_device::rx_status_r), FUNC(com52c50_device::address_select_w));
+ map(3, 3).rw(FUNC(com52c50_device::rx_buffer_r), FUNC(com52c50_device::control_w));
+ map(4, 4).w(FUNC(com52c50_device::zero_fill_w));
+ map(5, 5).rw(FUNC(com52c50_device::present_address_r), FUNC(com52c50_device::present_address_w));
+ map(6, 6).mirror(1).r(FUNC(com52c50_device::tx_status_r));
+ map(6, 6).w(FUNC(com52c50_device::tx_buffer_w));
+ map(7, 7).w(FUNC(com52c50_device::tx_buffer_eom_w));
+}
+
+void com52c50_device::device_start()
+{
+ save_item(NAME(m_int_mask));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_zero_fill));
+ save_item(NAME(m_present_address));
+ save_item(NAME(m_rx_status));
+ save_item(NAME(m_tx_status));
+ save_item(NAME(m_control));
+ save_item(NAME(m_mode));
+}
+
+void com52c50_device::device_reset()
+{
+ m_int_mask = 0;
+ m_int_status = 0;
+ m_zero_fill = 0;
+ m_rx_status = 0;
+ m_tx_status = 0;
+ m_control = 0x01;
+ m_mode = 0;
+
+ m_int1_callback(CLEAR_LINE);
+ m_int2_callback(CLEAR_LINE);
+}
+
+u8 com52c50_device::rx_buffer_r()
+{
+ if (!machine().side_effects_disabled())
+ logerror("%s: Reading data from RX buffer\n", machine().describe_context());
+ return 0;
+}
+
+void com52c50_device::tx_buffer_w(u8 data)
+{
+ logerror("%s: Writing %02X to TX buffer\n", machine().describe_context(), data);
+}
+
+void com52c50_device::tx_buffer_eom_w(u8 data)
+{
+ logerror("%s: Writing %02X to TX buffer EOM\n", machine().describe_context(), data);
+}
+
+void com52c50_device::zero_fill_w(u8 data)
+{
+ logerror("%s: Writing %02X to zero fill register\n", machine().describe_context(), data);
+ m_zero_fill = data;
+}
+
+void com52c50_device::int_mask_w(u8 data)
+{
+ logerror("%s: Writing %02X to interrupt mask register\n", machine().describe_context(), data);
+ m_int_mask = data;
+}
+
+void com52c50_device::address_select_w(u8 data)
+{
+ logerror("%s: Writing %02X to address select register\n", machine().describe_context(), data);
+}
+
+u8 com52c50_device::present_address_r()
+{
+ return m_present_address;
+}
+
+void com52c50_device::present_address_w(u8 data)
+{
+ logerror("%s: Writing %02X to present address register\n", machine().describe_context(), data);
+ m_present_address = data & 0x07;
+}
+
+u8 com52c50_device::int_status_r()
+{
+ return m_int_status;
+}
+
+u8 com52c50_device::rx_status_r()
+{
+ return m_rx_status | (m_present_address << 1);
+}
+
+u8 com52c50_device::tx_status_r()
+{
+ return m_tx_status;
+}
+
+void com52c50_device::control_w(u8 data)
+{
+ if (!BIT(data, 0))
+ {
+ logerror("%s: Software reset\n", machine().describe_context());
+
+ m_int_mask = 0;
+ m_int_status = 0;
+ m_zero_fill = 0;
+ m_rx_status = 0;
+ m_tx_status = 0;
+ m_mode = 0;
+ }
+
+ logerror("%s: Writing %02X to control register\n", machine().describe_context(), data);
+ m_control = data;
+}
+
+void com52c50_device::mode_w(u8 data)
+{
+ logerror("%s: Writing %02X to mode register\n", machine().describe_context(), data);
+ m_mode = data;
+}
+
diff --git a/src/devices/machine/com52c50.h b/src/devices/machine/com52c50.h
new file mode 100644
index 00000000000..f3e197e803c
--- /dev/null
+++ b/src/devices/machine/com52c50.h
@@ -0,0 +1,88 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/***************************************************************************
+
+ Standard Microsystems Corp. COM52C50 Twinax Interface Circuit (TIC)
+
+****************************************************************************
+ _____ _____
+ D2 1 |* \__/ | 28 Vcc
+ D3 2 | | 27 D1
+ /WR 3 | | 26 D0
+ /TXEN 4 | | 25 /CS
+ /DTX 5 | | 24 /RD
+ TX 6 | | 23 A0
+ TX DMA 7 | | 22 A1
+ RX 8 | COM52C50 | 21 A2
+ D4 9 | | 20 /INT1
+ D5 10 | | 19 /INT2
+ /RESET 11 | | 18 RX DMA
+ XTAL2 12 | | 17 CLKOUT
+ XTAL1 13 | | 16 D7
+ GND 14 |______________| 15 D6
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_COM52C50_H
+#define MAME_MACHINE_COM52C50_H
+
+#pragma once
+
+
+// ======================> com52c50_device
+
+class com52c50_device : public device_t
+{
+public:
+ // device type constructor
+ com52c50_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // callback configuration
+ auto int1_callback() { return m_int1_callback.bind(); }
+ auto int2_callback() { return m_int2_callback.bind(); }
+ auto rx_dma_callback() { return m_rx_dma_callback.bind(); }
+ auto tx_dma_callback() { return m_tx_dma_callback.bind(); }
+
+ // bus interface
+ u8 rx_buffer_r();
+ void tx_buffer_w(u8 data);
+ void tx_buffer_eom_w(u8 data);
+ void zero_fill_w(u8 data);
+ void int_mask_w(u8 data);
+ void address_select_w(u8 data);
+ u8 present_address_r();
+ void present_address_w(u8 data);
+ u8 int_status_r();
+ u8 rx_status_r();
+ u8 tx_status_r();
+ void control_w(u8 data);
+ void mode_w(u8 data);
+ void map(address_map &map);
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ // device callbacks
+ devcb_write_line m_int1_callback;
+ devcb_write_line m_int2_callback;
+ devcb_write_line m_rx_dma_callback;
+ devcb_write_line m_tx_dma_callback;
+
+ // internal state
+ u8 m_int_mask;
+ u8 m_int_status;
+ u8 m_zero_fill;
+ u8 m_present_address;
+ u8 m_rx_status;
+ u8 m_tx_status;
+ u8 m_control;
+ u8 m_mode;
+};
+
+// device type declaration
+DECLARE_DEVICE_TYPE(COM52C50, com52c50_device)
+
+#endif // MAME_MACHINE_COM52C50_H
diff --git a/src/devices/machine/com8116.cpp b/src/devices/machine/com8116.cpp
index 9942234a640..ca268f0ed81 100644
--- a/src/devices/machine/com8116.cpp
+++ b/src/devices/machine/com8116.cpp
@@ -9,8 +9,8 @@
#include "emu.h"
#include "com8116.h"
-#define LOG_SELECTED (1 << 0)
-#define LOG_TABLE (1 << 1)
+#define LOG_SELECTED (1U << 1)
+#define LOG_TABLE (1U << 2)
//#define VERBOSE (LOG_TABLE)
#include "logmacro.h"
@@ -134,19 +134,14 @@ k1135ab_device::k1135ab_device(const machine_config &mconfig, const char *tag, d
void com8116_device::device_start()
{
- // resolve callbacks
- m_fx4_handler.resolve();
- m_fr_handler.resolve_safe();
- m_ft_handler.resolve_safe();
-
// allocate timers
- if (!m_fx4_handler.isnull())
+ if (!m_fx4_handler.isunset())
{
- m_fx4_timer = timer_alloc(TIMER_FX4);
+ m_fx4_timer = timer_alloc(FUNC(com8116_device::fx4_tick), this);
m_fx4_timer->adjust(attotime::from_hz((clock() / 4) * 2), 0, attotime::from_hz((clock() / 4)) * 2);
}
- m_fr_timer = timer_alloc(TIMER_FR);
- m_ft_timer = timer_alloc(TIMER_FT);
+ m_fr_timer = timer_alloc(FUNC(com8116_device::fr_tick), this);
+ m_ft_timer = timer_alloc(FUNC(com8116_device::ft_tick), this);
for (int i = 0; i < 16; i++)
LOGMASKED(LOG_TABLE, "Output Frequency %01X: 16X %f Hz\n", i, double(clock()) / m_divisors[i] / 16.0);
@@ -171,28 +166,35 @@ void com8116_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// fx4_tick - toggle the FX4 timer output
//-------------------------------------------------
-void com8116_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(com8116_device::fx4_tick)
{
- switch (id)
- {
- case TIMER_FX4:
- m_fx4 = !m_fx4;
- m_fx4_handler(m_fx4);
- break;
-
- case TIMER_FR:
- m_fr = !m_fr;
- m_fr_handler(m_fr);
- break;
-
- case TIMER_FT:
- m_ft = !m_ft;
- m_ft_handler(m_ft);
- break;
- }
+ m_fx4 = !m_fx4;
+ m_fx4_handler(m_fx4);
+}
+
+
+//-------------------------------------------------
+// fr_tick - toggle the FR timer output
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(com8116_device::fr_tick)
+{
+ m_fr = !m_fr;
+ m_fr_handler(m_fr);
+}
+
+
+//-------------------------------------------------
+// ft_tick - toggle the FT timer output
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(com8116_device::ft_tick)
+{
+ m_ft = !m_ft;
+ m_ft_handler(m_ft);
}
diff --git a/src/devices/machine/com8116.h b/src/devices/machine/com8116.h
index c881d08312d..908d7c782d2 100644
--- a/src/devices/machine/com8116.h
+++ b/src/devices/machine/com8116.h
@@ -63,16 +63,12 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int m_param, void *ptr) override;
-private:
- enum
- {
- TIMER_FX4,
- TIMER_FR,
- TIMER_FT
- };
+ TIMER_CALLBACK_MEMBER(fx4_tick);
+ TIMER_CALLBACK_MEMBER(fr_tick);
+ TIMER_CALLBACK_MEMBER(ft_tick);
+private:
devcb_write_line m_fx4_handler;
devcb_write_line m_fr_handler;
devcb_write_line m_ft_handler;
diff --git a/src/devices/machine/cop452.cpp b/src/devices/machine/cop452.cpp
index 09e31df2c82..f55c055e301 100644
--- a/src/devices/machine/cop452.cpp
+++ b/src/devices/machine/cop452.cpp
@@ -20,12 +20,12 @@
DEFINE_DEVICE_TYPE(COP452, cop452_device, "cop452", "National Semiconductor COP452 frequency generator")
cop452_device::cop452_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
-: device_t(mconfig , COP452 , tag , owner , clock)
+ : device_t(mconfig, COP452, tag, owner, clock)
, m_out_handlers(*this)
{
}
-WRITE_LINE_MEMBER(cop452_device::cs_w)
+void cop452_device::cs_w(int state)
{
m_cs = state;
if (m_cs) {
@@ -35,11 +35,11 @@ WRITE_LINE_MEMBER(cop452_device::cs_w)
}
}
-WRITE_LINE_MEMBER(cop452_device::sk_w)
+void cop452_device::sk_w(int state)
{
if (!m_cs && !m_sk && state) {
// Rising edge on SK
- LOG("bit %d %u\n" , m_di , m_spi_state);
+ LOG("bit %d %u\n", m_di, m_spi_state);
if (m_spi_state == 0 && m_di) {
// Got start bit
m_spi_state = 1;
@@ -48,31 +48,31 @@ WRITE_LINE_MEMBER(cop452_device::sk_w)
m_sr = (m_sr << 1) | m_di;
m_spi_state++;
if (m_spi_state == 6) {
- LOG("Inst = %x\n" , m_sr);
+ LOG("Inst = %x\n", m_sr);
m_spi_state = 22;
- unsigned idx = !BIT(m_sr , 0);
+ unsigned idx = !BIT(m_sr, 0);
char reg = idx ? 'B' : 'A';
switch (m_sr) {
case 0b00000:
case 0b00001:
// LDRA/B
- LOG("LDR%c\n" , reg);
+ LOG("LDR%c\n", reg);
m_spi_state = 6;
- m_reg[ idx ] = 0;
+ m_reg[idx] = 0;
break;
case 0b00010:
case 0b00011:
// RDRA/B
// TODO: not implemented ATM
- LOG("RDR%c\n" , reg);
+ LOG("RDR%c\n", reg);
break;
case 0b00100:
case 0b00101:
// TRCA/B
- LOG("TRC%c\n" , reg);
- m_cnt[ idx ] = m_reg[ idx ];
+ LOG("TRC%c\n", reg);
+ m_cnt[idx] = m_reg[idx];
set_timer(idx);
break;
@@ -80,7 +80,7 @@ WRITE_LINE_MEMBER(cop452_device::sk_w)
case 0b00111:
// TCRA/B
// TODO:
- LOG("TCR%c\n" , reg);
+ LOG("TCR%c\n", reg);
break;
case 0b01000:
@@ -99,17 +99,17 @@ WRITE_LINE_MEMBER(cop452_device::sk_w)
if (m_sr & 0b10000) {
// LDM
m_mode = m_sr & 0b01111;
- LOG("LDM %x\n" , m_mode);
+ LOG("LDM %x\n", m_mode);
set_timer(0);
set_timer(1);
if (m_mode == MODE_NUMBER_PULSES) {
// Always start with OA = 1
- set_output(0 , true);
+ set_output(0, true);
} else if (m_mode == MODE_WHITE_NOISE ||
m_mode == MODE_GATED_WHITE) {
// Preset bit 15 & 16 of register A when entering
// white noise modes
- m_reg[ 0 ] |= 0x8000;
+ m_reg[0] |= 0x8000;
m_regA_b16 = true;
}
} else {
@@ -121,24 +121,23 @@ WRITE_LINE_MEMBER(cop452_device::sk_w)
}
} else if (m_spi_state >= 6 && m_spi_state < 22) {
// Loading A/B register
- unsigned idx = !BIT(m_sr , 0);
- char reg = idx ? 'B' : 'A';
- m_reg[ idx ] = (m_reg[ idx ] << 1) | m_di;
+ unsigned idx = !BIT(m_sr, 0);
+ m_reg[idx] = (m_reg[idx] << 1) | m_di;
m_spi_state++;
if (m_spi_state == 22) {
- LOG("REG%c = %04x\n" , reg , m_reg[ idx ]);
+ LOG("REG%c = %04x\n", idx ? 'B' : 'A', m_reg[idx]);
}
}
}
m_sk = state;
}
-WRITE_LINE_MEMBER(cop452_device::di_w)
+void cop452_device::di_w(int state)
{
m_di = state;
}
-READ_LINE_MEMBER(cop452_device::do_r)
+int cop452_device::do_r()
{
// TODO:
return 0;
@@ -146,10 +145,8 @@ READ_LINE_MEMBER(cop452_device::do_r)
void cop452_device::device_start()
{
- m_out_handlers.resolve_all_safe();
-
- m_timers[ 0 ] = timer_alloc(0);
- m_timers[ 1 ] = timer_alloc(1);
+ m_timers[0] = timer_alloc(FUNC(cop452_device::timer_tick), this);
+ m_timers[1] = timer_alloc(FUNC(cop452_device::timer_tick), this);
save_item(NAME(m_mode));
save_item(NAME(m_clk_div_4));
@@ -169,20 +166,20 @@ void cop452_device::device_reset()
// Set reset mode
m_mode = MODE_RESET;
m_clk_div_4 = true;
- m_out[ 0 ] = m_out[ 1 ] = true;
- set_output(0 , false);
- set_output(1 , false);
+ m_out[0] = m_out[1] = true;
+ set_output(0, false);
+ set_output(1, false);
m_spi_state = 0;
m_sr = 0;
- m_timers[ 0 ]->reset();
- m_timers[ 1 ]->reset();
+ m_timers[0]->reset();
+ m_timers[1]->reset();
}
-void cop452_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(cop452_device::timer_tick)
{
switch (m_mode) {
case MODE_DUAL_FREQ:
- toggle_n_reload(id);
+ toggle_n_reload(param);
break;
case MODE_TRIG_PULSE:
@@ -190,12 +187,12 @@ void cop452_device::device_timer(emu_timer &timer, device_timer_id id, int param
break;
case MODE_NUMBER_PULSES:
- if (id == 0) {
+ if (param == 0) {
toggle_n_reload(0);
- if (!m_out[ 0 ]) {
+ if (!m_out[0]) {
// It seems that cnt B decrements each time OA goes low
- if (m_cnt[ 1 ] != 0) {
- m_cnt[ 1 ]--;
+ if (m_cnt[1] != 0) {
+ m_cnt[1]--;
} else {
// End of pulse train
toggle_n_reload(1);
@@ -228,22 +225,22 @@ void cop452_device::device_timer(emu_timer &timer, device_timer_id id, int param
case MODE_WHITE_NOISE:
case MODE_GATED_WHITE:
{
- if (id == 0) {
+ if (param == 0) {
// Reg A & its 17th bit (m_regA_b16) form a 17-bit LFSR
// LFSR uses X^17+X^14+1 polynomial to generate a pseudo-random
// maximal-length sequence
- bool feedback = m_regA_b16 ^ BIT(m_reg[ 0 ] , 13);
- m_regA_b16 = BIT(m_reg[ 0 ] , 15);
- m_reg[ 0 ] <<= 1;
- m_reg[ 0 ] |= feedback;
+ bool feedback = m_regA_b16 ^ BIT(m_reg[0], 13);
+ m_regA_b16 = BIT(m_reg[0], 15);
+ m_reg[0] <<= 1;
+ m_reg[0] |= feedback;
} else {
toggle_n_reload(1);
}
bool new_out_0 = m_regA_b16;
if (m_mode == MODE_GATED_WHITE) {
- new_out_0 &= m_out[ 1 ];
+ new_out_0 &= m_out[1];
}
- set_output(0 , new_out_0);
+ set_output(0, new_out_0);
}
break;
@@ -251,7 +248,7 @@ void cop452_device::device_timer(emu_timer &timer, device_timer_id id, int param
break;
}
- set_timer(id);
+ set_timer(param);
}
attotime cop452_device::counts_to_attotime(unsigned counts) const
@@ -270,7 +267,7 @@ void cop452_device::set_timer(unsigned idx)
switch (m_mode) {
case MODE_DUAL_FREQ:
// Cnt A & B count independently
- target = counts_to_attotime(m_cnt[ idx ]);
+ target = counts_to_attotime(m_cnt[idx]);
break;
case MODE_TRIG_PULSE:
@@ -281,7 +278,7 @@ void cop452_device::set_timer(unsigned idx)
// Cnt A generates OA frequency
// Cnt B counts the periods to output
if (idx == 0) {
- target = counts_to_attotime(m_cnt[ 0 ]);
+ target = counts_to_attotime(m_cnt[0]);
}
break;
@@ -312,7 +309,7 @@ void cop452_device::set_timer(unsigned idx)
if (idx == 0) {
target = counts_to_attotime(0);
} else {
- target = counts_to_attotime(m_cnt[ 1 ]);
+ target = counts_to_attotime(m_cnt[1]);
}
break;
@@ -320,26 +317,26 @@ void cop452_device::set_timer(unsigned idx)
break;
}
- m_timers[ idx ]->adjust(target);
+ m_timers[idx]->adjust(target, idx);
}
-void cop452_device::set_output(unsigned idx , bool state)
+void cop452_device::set_output(unsigned idx, bool state)
{
- if (m_out[ idx ] != state) {
- m_out[ idx ] = state;
- LOG("OUT %u=%d @%s\n" , idx , state , machine().time().as_string());
- m_out_handlers[ idx ](state);
+ if (m_out[idx] != state) {
+ m_out[idx] = state;
+ LOG("OUT %u=%d @%s\n", idx, state, machine().time().as_string());
+ m_out_handlers[idx](state);
}
}
void cop452_device::toggle_output(unsigned idx)
{
- set_output(idx , !m_out[ idx ]);
+ set_output(idx, !m_out[idx]);
}
void cop452_device::toggle_n_reload(unsigned idx)
{
// Toggle output OA/OB and reload its associated counter
toggle_output(idx);
- m_cnt[ idx ] = m_reg[ idx ];
+ m_cnt[idx] = m_reg[idx];
}
diff --git a/src/devices/machine/cop452.h b/src/devices/machine/cop452.h
index f4981be72f3..7aaaa668b4c 100644
--- a/src/devices/machine/cop452.h
+++ b/src/devices/machine/cop452.h
@@ -29,27 +29,28 @@ public:
cop452_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
// SPI I/O
- DECLARE_WRITE_LINE_MEMBER(cs_w);
- DECLARE_WRITE_LINE_MEMBER(sk_w);
- DECLARE_WRITE_LINE_MEMBER(di_w);
- DECLARE_READ_LINE_MEMBER(do_r);
+ void cs_w(int state);
+ void sk_w(int state);
+ void di_w(int state);
+ int do_r();
// Signal outputs
- auto oa_w() { return m_out_handlers[ 0 ].bind(); }
- auto ob_w() { return m_out_handlers[ 1 ].bind(); }
+ auto oa_w() { return m_out_handlers[0].bind(); }
+ auto ob_w() { return m_out_handlers[1].bind(); }
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(timer_tick);
private:
// Index 0 is for "A" side, 1 is for "B" side
devcb_write_line::array<2> m_out_handlers;
// Timers
- emu_timer *m_timers[ 2 ];
+ emu_timer *m_timers[2];
// State
uint8_t m_mode;
@@ -57,10 +58,10 @@ private:
bool m_cs;
bool m_sk;
bool m_di;
- bool m_out[ 2 ];
+ bool m_out[2];
bool m_regA_b16;
- uint16_t m_reg[ 2 ];
- uint16_t m_cnt[ 2 ];
+ uint16_t m_reg[2];
+ uint16_t m_cnt[2];
// 0 : idle
// 1..5 : shifting instruction in
// 6..21: shifting register in
@@ -70,22 +71,22 @@ private:
// Operating modes
enum : uint8_t {
- MODE_DUAL_FREQ, // 0000 Dual frequency
- MODE_TRIG_PULSE, // 0001 Triggered pulse
- MODE_NUMBER_PULSES, // 0010 Number of pulses
- MODE_DUTY_CYCLE, // 0011 Duty cycle
- MODE_FREQ_COUNT, // 0100 Frequency and count
- MODE_DUAL_COUNT, // 0101 Dual count
- MODE_WAVE_MEAS, // 0110 Waveform measurement
- MODE_TRIG_COUNT, // 0111 Triggered pulse and count
- MODE_WHITE_NOISE, // 1000 White noise & frequency
- MODE_GATED_WHITE, // 1001 Gated white noise
- MODE_RESET = 15 // 1111 Reset
+ MODE_DUAL_FREQ, // 0000 Dual frequency
+ MODE_TRIG_PULSE, // 0001 Triggered pulse
+ MODE_NUMBER_PULSES, // 0010 Number of pulses
+ MODE_DUTY_CYCLE, // 0011 Duty cycle
+ MODE_FREQ_COUNT, // 0100 Frequency and count
+ MODE_DUAL_COUNT, // 0101 Dual count
+ MODE_WAVE_MEAS, // 0110 Waveform measurement
+ MODE_TRIG_COUNT, // 0111 Triggered pulse and count
+ MODE_WHITE_NOISE, // 1000 White noise & frequency
+ MODE_GATED_WHITE, // 1001 Gated white noise
+ MODE_RESET = 15 // 1111 Reset
};
attotime counts_to_attotime(unsigned counts) const;
void set_timer(unsigned idx);
- void set_output(unsigned idx , bool state);
+ void set_output(unsigned idx, bool state);
void toggle_output(unsigned idx);
void toggle_n_reload(unsigned idx);
};
diff --git a/src/devices/machine/corvushd.cpp b/src/devices/machine/corvushd.cpp
index 07b959d9fba..62c376249e3 100644
--- a/src/devices/machine/corvushd.cpp
+++ b/src/devices/machine/corvushd.cpp
@@ -65,8 +65,12 @@
//
#include "emu.h"
-#include "machine/corvushd.h"
+#include "corvushd.h"
+#define LOG_RESPONSES (1U << 1)
+
+#define VERBOSE (0)
+#include "logmacro.h"
//
// Controller Commands
@@ -241,8 +245,6 @@ corvus_hdc_device::corvus_hdc_device(const machine_config &mconfig, const char *
{
}
-#define VERBOSE 0
-#define VERBOSE_RESPONSES 0
#define ROM_VERSION 1 // Controller ROM version
#define MAX_COMMAND_SIZE 4096 // The maximum size of a command packet (the controller only has 5K of RAM...)
#define SPARE_TRACKS 7 // This is a Rev B drive, so 7 it is
@@ -254,8 +256,7 @@ corvus_hdc_device::corvus_hdc_device(const machine_config &mconfig, const char *
#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)
+#define LOG_BUFFER(p,s) do { if (VERBOSE & LOG_RESPONSES) dump_buffer(p,s); } while (0)
@@ -272,26 +273,26 @@ corvus_hdc_device::corvus_hdc_device(const machine_config &mconfig, const char *
// nada
//
void corvus_hdc_device::dump_buffer(uint8_t *buffer, uint16_t length) {
- uint16_t 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));
+ LOGMASKED(LOG_RESPONSES, "dump_buffer: Dump of %d bytes:\n", length);
+ LOGMASKED(LOG_RESPONSES, "Base 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ASCII\n");
+ LOGMASKED(LOG_RESPONSES, "---- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ----------------");
+
+ char data_buf[128];
+ char ascii_buf[17];
+ for(uint16_t offset = 0; offset < length; offset += 16) {
+ int buf_offset = 0;
+ for(uint8_t byte_idx = 0; byte_idx < 16 && (offset + byte_idx) < length; byte_idx++) {
+ snprintf(data_buf + buf_offset, 128 - buf_offset, "%02x ", *(buffer + offset));
+ ascii_buf[byte_idx] = isprint(*(buffer + offset)) ? *(buffer + offset) : '.';
}
- ascii_dump[offset % 16] = isprint(*(buffer + offset)) ? *(buffer + offset) : '.';
+ if((length - offset) < 16) {
+ memset(data_buf + buf_offset, 0, (length - offset) * 3);
+ buf_offset += (length - offset) * 3;
+ }
+ data_buf[buf_offset] = '\0';
+ ascii_buf[16] = '\0';
+ LOGMASKED(LOG_RESPONSES, "%04x: %s%s", offset, data_buf, ascii_buf);
}
- if(offset % 16)
- logerror("%.*s", (16 - (offset % 16)) * 3, " ");
- logerror("%.*s\n", (offset % 16) ? (offset % 16) : 16, ascii_dump);
}
@@ -314,7 +315,7 @@ void corvus_hdc_device::dump_buffer(uint8_t *buffer, uint16_t length) {
bool corvus_hdc_device::parse_hdc_command(uint8_t data) {
m_awaiting_modifier = false; // This is the case by definition
- LOG(("parse_hdc_command: Called with data: 0x%2.2x, Prep mode is: %d\n", data, m_prep_mode));
+ LOG("parse_hdc_command: Called with data: 0x%2.2x, Prep mode is: %d\n", data, m_prep_mode);
if(!m_prep_mode) {
switch(data) {
@@ -340,8 +341,8 @@ bool corvus_hdc_device::parse_hdc_command(uint8_t data) {
case PREP_MODE_SELECT:
m_recv_bytes = corvus_cmd[data][0].recv_bytes;
m_xmit_bytes = corvus_cmd[data][0].xmit_bytes;
- LOG(("parse_hdc_command: Single byte command recognized: 0x%2.2x, to recv: %d, to xmit: %d\n", data,
- m_recv_bytes, m_xmit_bytes));
+ LOG("parse_hdc_command: Single byte command recognized: 0x%2.2x, to recv: %d, to xmit: %d\n", data,
+ m_recv_bytes, m_xmit_bytes);
break;
//
// Double-byte commands
@@ -363,13 +364,13 @@ bool corvus_hdc_device::parse_hdc_command(uint8_t data) {
// case DELACTIVENUM_OMNI_CODE:
// case FINDACTIVE_CODE:
m_awaiting_modifier = true;
- LOG(("parse_hdc_command: Double byte command recognized: 0x%2.2x\n", data));
+ LOG("parse_hdc_command: Double byte command recognized: 0x%2.2x\n", data);
break;
default: // This is an INVALID command
m_recv_bytes = 1;
m_xmit_bytes = 1;
- LOG(("parse_hdc_command: Invalid command detected: 0x%2.2x\n", data));
+ LOG("parse_hdc_command: Invalid command detected: 0x%2.2x\n", data);
return true;
}
} else {
@@ -386,14 +387,14 @@ bool corvus_hdc_device::parse_hdc_command(uint8_t data) {
case PREP_WRITE_FIRMWARE:
m_recv_bytes = corvus_prep_cmd[data].recv_bytes;
m_xmit_bytes = corvus_prep_cmd[data].xmit_bytes;
- LOG(("parse_hdc_command: Prep command recognized: 0x%2.2x, to recv: %d, to xmit: %d\n", data,
- m_recv_bytes, m_xmit_bytes));
+ LOG("parse_hdc_command: Prep command recognized: 0x%2.2x, to recv: %d, to xmit: %d\n", data,
+ m_recv_bytes, m_xmit_bytes);
break;
default: // This is an INVALID prep command
m_recv_bytes = 1;
m_xmit_bytes = 1;
- LOG(("parse_hdc_command: Invalid Prep command detected: 0x%2.2x\n", data));
+ LOG("parse_hdc_command: Invalid Prep command detected: 0x%2.2x\n", data);
return true;
}
} // if(!prep_mode)
@@ -418,12 +419,12 @@ bool corvus_hdc_device::parse_hdc_command(uint8_t data) {
// status: Command status
//
uint8_t corvus_hdc_device::corvus_write_sector(uint8_t drv, uint32_t sector, uint8_t *buffer, int len) {
- hard_disk_file
+ harddisk_image_device
*disk; // Structures for interface to CHD routines
uint8_t tbuffer[512]; // Buffer to hold an entire sector
uint16_t cylinder; // Cylinder this sector resides on
- LOG(("corvus_write_sector: Write Drive: %d, physical sector: 0x%5.5x\n", drv, sector));
+ LOG("corvus_write_sector: Write Drive: %d, physical sector: 0x%5.5x\n", drv, sector);
disk = corvus_hdc_file(drv);
if(!disk) {
@@ -444,17 +445,17 @@ uint8_t corvus_hdc_device::corvus_write_sector(uint8_t drv, uint32_t sector, uin
// wonderful functionality.
//
if(len == 512) {
- hard_disk_write(disk, sector, buffer);
+ disk->write(sector, buffer);
} else {
- hard_disk_read(disk, sector, tbuffer); // Read the existing data into our temporary buffer
+ disk->read(sector, tbuffer); // Read the existing data into our temporary buffer
memcpy(tbuffer, buffer, len); // Overlay the data with the buffer passed
m_delay += INTERSECTOR_DELAY; // Add another delay because of the Read / Write
- hard_disk_write(disk, sector, tbuffer); // Re-write the data
+ disk->write(sector, tbuffer); // Re-write the data
}
m_last_cylinder = cylinder;
- LOG(("corvus_write_sector: Full sector dump on a write of %d bytes follows:\n", len));
+ LOG("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;
@@ -491,8 +492,8 @@ uint8_t corvus_hdc_device::corvus_write_logical_sector(dadr_t *dadr, uint8_t *bu
drv = (dadr->address_msn_and_drive & 0x0f);
sector = (dadr->address_msn_and_drive & 0xf0 << 12) | (dadr->address_mid << 8) | dadr->address_lsb;
- LOG(("corvus_write_logical_sector: Writing based on DADR: 0x%6.6x, logical sector: 0x%5.5x, drive: %d\n",
- dadr->address_msn_and_drive << 16 | dadr->address_lsb << 8 | dadr->address_mid, sector, drv));
+ LOG("corvus_write_logical_sector: Writing based on DADR: 0x%6.6x, logical sector: 0x%5.5x, drive: %d\n",
+ dadr->address_msn_and_drive << 16 | dadr->address_lsb << 8 | dadr->address_mid, sector, drv);
// Set m_tracks_per_cylinder and m_sectors_per_track
corvus_hdc_file(drv);
@@ -526,12 +527,12 @@ uint8_t corvus_hdc_device::corvus_write_logical_sector(dadr_t *dadr, uint8_t *bu
// status: Corvus status
//
uint8_t corvus_hdc_device::corvus_read_sector(uint8_t drv, uint32_t sector, uint8_t *buffer, int len) {
- hard_disk_file
+ harddisk_image_device
*disk; // Structures for interface to CHD routines
uint8_t tbuffer[512]; // Buffer to store full sector results in
uint16_t cylinder;
- LOG(("corvus_read_sector: Read Drive: %d, physical sector: 0x%5.5x\n", drv, sector));
+ LOG("corvus_read_sector: Read Drive: %d, physical sector: 0x%5.5x\n", drv, sector);
disk = corvus_hdc_file(drv);
if(!disk) {
@@ -545,13 +546,13 @@ uint8_t corvus_hdc_device::corvus_read_sector(uint8_t drv, uint32_t sector, uint
cylinder = (double) sector / (double) m_sectors_per_track / (double) m_tracks_per_cylinder;
m_delay = abs(m_last_cylinder - cylinder) * TRACK_SEEK_TIME + INTERSECTOR_DELAY;
- hard_disk_read(disk, sector, tbuffer);
+ disk->read(sector, tbuffer);
memcpy(buffer, tbuffer, len);
m_last_cylinder = cylinder;
- LOG(("corvus_read_sector: Data read follows:\n"));
+ LOG("corvus_read_sector: Data read follows:\n");
LOG_BUFFER(tbuffer, len);
return STAT_SUCCESS;
@@ -588,8 +589,8 @@ uint8_t corvus_hdc_device::corvus_read_logical_sector(dadr_t *dadr, uint8_t *buf
drv = (dadr->address_msn_and_drive & 0x0f);
sector = (dadr->address_msn_and_drive & 0xf0 << 12) | (dadr->address_mid << 8) | dadr->address_lsb;
- LOG(("corvus_read_logical_sector: Reading based on DADR: 0x%6.6x, logical sector: 0x%5.5x, drive: %d\n",
- dadr->address_msn_and_drive << 16 | dadr->address_lsb << 8 | dadr->address_mid, sector, drv));
+ LOG("corvus_read_logical_sector: Reading based on DADR: 0x%6.6x, logical sector: 0x%5.5x, drive: %d\n",
+ dadr->address_msn_and_drive << 16 | dadr->address_lsb << 8 | dadr->address_mid, sector, drv);
// Set up m_tracks_per_cylinder and m_sectors_per_track
corvus_hdc_file(drv);
@@ -887,7 +888,7 @@ uint8_t corvus_hdc_device::corvus_get_drive_parameters(uint8_t drv) {
m_buffer.drive_param_response.physical_capacity.midb = (raw_capacity & 0x00ff00) >> 8;
m_buffer.drive_param_response.physical_capacity.lsb = (raw_capacity & 0x0000ff);
- LOG(("corvus_get_drive_parameters: Drive Parameter packet follows:\n"));
+ LOG("corvus_get_drive_parameters: Drive Parameter packet follows:\n");
LOG_BUFFER(m_buffer.raw_data, 110);
return STAT_SUCCESS;
@@ -907,7 +908,7 @@ uint8_t corvus_hdc_device::corvus_get_drive_parameters(uint8_t drv) {
// status: Status of read operation
//
uint8_t corvus_hdc_device::corvus_read_boot_block(uint8_t block) {
- LOG(("corvus_read_boot_block: Reading boot block: %d\n", block));
+ LOG("corvus_read_boot_block: Reading boot block: %d\n", block);
return corvus_read_sector(1, 25 + block, m_buffer.read_512_response.data, 512);
}
@@ -957,7 +958,7 @@ uint8_t corvus_hdc_device::corvus_enter_prep_mode(uint8_t drv, uint8_t *prep_blo
return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE;
}
- LOG(("corvus_enter_prep_mode: Prep mode entered for drive %d, prep block follows:\n", drv));
+ LOG("corvus_enter_prep_mode: Prep mode entered for drive %d, prep block follows:\n", drv);
LOG_BUFFER(prep_block, 512);
m_prep_mode = true;
@@ -976,7 +977,7 @@ uint8_t corvus_hdc_device::corvus_enter_prep_mode(uint8_t drv, uint8_t *prep_blo
// Status of command (always success)
//
uint8_t corvus_hdc_device::corvus_exit_prep_mode() {
- LOG(("corvus_exit_prep_mode: Prep mode exited\n"));
+ LOG("corvus_exit_prep_mode: Prep mode exited\n");
m_prep_mode = false;
m_prep_drv = 0;
return STAT_SUCCESS;
@@ -1002,8 +1003,8 @@ uint8_t corvus_hdc_device::corvus_read_firmware_block(uint8_t head, uint8_t sect
relative_sector = head * m_sectors_per_track + sector;
- LOG(("corvus_read_firmware_block: Reading firmware head: 0x%2.2x, sector: 0x%2.2x, relative_sector: 0x%2.2x\n",
- head, sector, relative_sector));
+ LOG("corvus_read_firmware_block: Reading firmware head: 0x%2.2x, sector: 0x%2.2x, relative_sector: 0x%2.2x\n",
+ head, sector, relative_sector);
status = corvus_read_sector(m_prep_drv, relative_sector, m_buffer.read_512_response.data, 512);
return status;
@@ -1030,8 +1031,8 @@ uint8_t corvus_hdc_device::corvus_write_firmware_block(uint8_t head, uint8_t sec
relative_sector = head * m_sectors_per_track + sector;
- LOG(("corvus_write_firmware_block: Writing firmware head: 0x%2.2x, sector: 0x%2.2x, relative_sector: 0x%2.2x\n",
- head, sector, relative_sector));
+ LOG("corvus_write_firmware_block: Writing firmware head: 0x%2.2x, sector: 0x%2.2x, relative_sector: 0x%2.2x\n",
+ head, sector, relative_sector);
status = corvus_write_sector(m_prep_drv, relative_sector, buffer, 512);
return status;
@@ -1069,7 +1070,7 @@ uint8_t corvus_hdc_device::corvus_format_drive(uint8_t *pattern, uint16_t len) {
pattern = tbuffer;
}
- LOG(("corvus_format_drive: Formatting drive with 0x%5.5x sectors, pattern buffer (passed length: %d) follows\n", max_sector, 512));
+ 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++) {
@@ -1089,15 +1090,15 @@ uint8_t corvus_hdc_device::corvus_format_drive(uint8_t *pattern, uint16_t len) {
//
// Corvus_HDC_File
//
-// Returns a hard_disk_file object for a given virtual hard drive device in the concept
+// Returns a harddisk_image_device object for a given virtual hard drive device in the concept
//
// Pass:
// drv: Corvus drive id (1..15)
//
// Returns:
-// hard_disk_file object
+// harddisk_image_device object
//
-hard_disk_file *corvus_hdc_device::corvus_hdc_file(int drv) {
+harddisk_image_device *corvus_hdc_device::corvus_hdc_file(int drv) {
static const char *const tags[] = {
"harddisk1", "harddisk2", "harddisk3", "harddisk4"
};
@@ -1118,15 +1119,14 @@ hard_disk_file *corvus_hdc_device::corvus_hdc_file(int drv) {
return nullptr;
// Pick up the Head/Cylinder/Sector info
- hard_disk_file *file = img->get_hard_disk_file();
- hard_disk_info *info = hard_disk_get_info(file);
- m_sectors_per_track = info->sectors;
- m_tracks_per_cylinder = info->heads;
- m_cylinders_per_drive = info->cylinders;
+ const auto &info = img->get_info();
+ m_sectors_per_track = info.sectors;
+ m_tracks_per_cylinder = info.heads;
+ m_cylinders_per_drive = info.cylinders;
- LOG(("corvus_hdc_file: Attached to drive %u image: H:%d, C:%d, S:%d\n", drv, info->heads, info->cylinders, info->sectors));
+ LOG("corvus_hdc_file: Attached to drive %u image: H:%d, C:%d, S:%d\n", drv, info.heads, info.cylinders, info.sectors);
- return file;
+ return img;
}
@@ -1143,11 +1143,8 @@ hard_disk_file *corvus_hdc_device::corvus_hdc_file(int drv) {
// Nothing
//
void corvus_hdc_device::corvus_process_command_packet(bool invalid_command_flag) {
- if (VERBOSE_RESPONSES)
- {
- LOG(("corvus_hdc_data_w: Complete packet received. Dump follows:\n"));
- LOG_BUFFER(m_buffer.raw_data, m_offset);
- }
+ LOGMASKED(LOG_RESPONSES, "corvus_hdc_data_w: Complete packet received. Dump follows:\n");
+ LOG_BUFFER(m_buffer.raw_data, m_offset);
if(!invalid_command_flag) {
if(!m_prep_mode) {
@@ -1266,12 +1263,9 @@ void corvus_hdc_device::corvus_process_command_packet(bool invalid_command_flag)
logerror("corvus_hdc_data_w: Unimplemented Prep command %02x, returning FATAL FAULT status!\n", m_buffer.command.code);
}
}
- if (VERBOSE_RESPONSES)
- {
- LOG(("corvus_hdc_data_w: Command execution complete, status: 0x%2.2x. Response dump follows:\n",
- m_buffer.single_byte_response.status));
- LOG_BUFFER(m_buffer.raw_data, m_xmit_bytes);
- }
+ LOGMASKED(LOG_RESPONSES, "corvus_hdc_data_w: Command execution complete, status: 0x%2.2x. Response dump follows:\n",
+ m_buffer.single_byte_response.status);
+ LOG_BUFFER(m_buffer.raw_data, m_xmit_bytes);
} // if(!invalid_command_flag)
@@ -1292,12 +1286,11 @@ void corvus_hdc_device::corvus_process_command_packet(bool invalid_command_flag)
//
m_offset = 0; // Point to beginning of buffer for response
- LOG(("corvus_hdc_data_w: Setting one-time mame timer of %d microseconds to simulate disk function\n", m_delay));
+ LOG("corvus_hdc_data_w: Setting one-time mame timer of %d microseconds to simulate disk function\n", m_delay);
//
// Set up timers for command completion and timeout from host
//
- //machine.scheduler().timer_set(attotime::from_usec(m_delay), FUNC(corvus_hdc_callback), CALLBACK_CTH_MODE);
m_cmd_timer->adjust(attotime::from_usec(m_delay), CALLBACK_CTH_MODE);
m_timeout_timer->enable(0); // We've received enough data, disable the timeout timer
@@ -1305,54 +1298,51 @@ void corvus_hdc_device::corvus_process_command_packet(bool invalid_command_flag)
}
+//-------------------------------------------------
+// process_timeout - handle a command timeout
+//-------------------------------------------------
-//
-// Corvus_HDC_Callback
-//
-// Callback routine for completion of controller functions
-//
-// Pass:
-// Callback Function
-//
-// Returns:
-// Nothing
-//
-void corvus_hdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
+TIMER_CALLBACK_MEMBER(corvus_hdc_device::process_timeout) {
+ if(m_offset < m_recv_bytes || (m_offset > m_recv_bytes && m_recv_bytes != 0)) {
+ m_buffer.single_byte_response.status = STAT_TIMEOUT;
+ m_status |= CONTROLLER_DIRECTION;
+ m_status &= ~(CONTROLLER_BUSY);
+ m_recv_bytes = 0;
+ m_xmit_bytes = 1;
+ logerror("corvus_hdc_callback: Exceeded four-second timeout for data from host, resetting communications\n");
+ } else { // if(m_recv_bytes == 0) This was a variable-size command
+ LOG("corvus_hdc_callback: Executing variable-length command via four-second timeout\n");
+ corvus_process_command_packet(0); // Process the command
+ }
+}
+
+//-------------------------------------------------
+// complete_function - callback to complete a
+// controller function
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(corvus_hdc_device::complete_function) {
int function = param;
- switch(function) {
+ switch (param) {
case CALLBACK_CTH_MODE:
m_status |= CONTROLLER_DIRECTION; // Set to Controller-to-Host, Ready mode
m_status &= ~(CONTROLLER_BUSY);
- LOG(("corvus_hdc_callback: Callback executed with function CALLBACK_CTH_MODE\n"));
-
+ LOG("corvus_hdc_callback: Callback executed with function CALLBACK_CTH_MODE\n");
break;
+
case CALLBACK_HTC_MODE:
m_status &= ~(CONTROLLER_DIRECTION |
CONTROLLER_BUSY); // Set to Host-to-Controller, Ready mode
- LOG(("corvus_hdc_callback: Callback executed with function CALLBACK_HTC_MODE\n"));
-
+ LOG("corvus_hdc_callback: Callback executed with function CALLBACK_HTC_MODE\n");
break;
+
case CALLBACK_SAME_MODE:
m_status &= ~(CONTROLLER_BUSY); // Set the controller to Ready mode
-
- break;
- case CALLBACK_TIMEOUT: // We reached a four-second timeout threshold
- if(m_offset < m_recv_bytes || (m_offset > m_recv_bytes && m_recv_bytes != 0)) {
- m_buffer.single_byte_response.status = STAT_TIMEOUT;
- m_status |= CONTROLLER_DIRECTION;
- m_status &= ~(CONTROLLER_BUSY);
- m_recv_bytes = 0;
- m_xmit_bytes = 1;
- logerror("corvus_hdc_callback: Exceeded four-second timeout for data from host, resetting communications\n");
- } else { // if(m_recv_bytes == 0) This was a variable-size command
- LOG(("corvus_hdc_callback: Executing variable-length command via four-second timeout\n"));
- corvus_process_command_packet(0); // Process the command
- }
break;
+
default:
logerror("corvus_hdc_callback: FATAL ERROR -- Unknown callback function: %d\n", function);
assert(0);
@@ -1383,11 +1373,12 @@ void corvus_hdc_device::device_start() {
m_xmit_bytes = 0; // We don't have anything to say to the host
m_recv_bytes = 0; // We aren't waiting on additional data from the host
- m_timeout_timer = timer_alloc(TIMER_TIMEOUT); // Set up a timer to handle the four-second host-to-controller timeout
- m_timeout_timer->adjust(attotime::from_seconds(4), CALLBACK_TIMEOUT);
+ // Set up a timer to handle the four-second host-to-controller timeout
+ m_timeout_timer = timer_alloc(FUNC(corvus_hdc_device::process_timeout), this);
+ m_timeout_timer->adjust(attotime::from_seconds(4));
m_timeout_timer->enable(0); // Start this timer out disabled
- m_cmd_timer = timer_alloc(TIMER_COMMAND);
+ m_cmd_timer = timer_alloc(FUNC(corvus_hdc_device::complete_function), this);
//
// Define all of the packet sizes for the commands
@@ -1487,7 +1478,7 @@ void corvus_hdc_device::device_start() {
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"));
+ LOG("corvus_hdc_init: Drive structures initialized\n");
}
@@ -1537,7 +1528,7 @@ uint8_t corvus_hdc_device::read() {
result = m_buffer.raw_data[m_offset++];
if(m_offset == m_xmit_bytes) {
- LOG(("corvus_hdc_data_r: Finished transmitting %d bytes of data. Returning to idle mode.\n", m_xmit_bytes));
+ LOG("corvus_hdc_data_r: Finished transmitting %d bytes of data. Returning to idle mode.\n", m_xmit_bytes);
m_offset = 0; // We've reached the end of valid data
m_xmit_bytes = 0; // We don't have anything more to say
@@ -1589,12 +1580,12 @@ void corvus_hdc_device::write(uint8_t data) {
// We're supposed to be paying attention. Make a decision about the data received
//
if(m_offset == 0) { // First byte of a packet
- LOG(("corvus_hdc_data_w: Received a byte with m_offset == 0. Processing as command: 0x%2.2x\n", data));
+ LOG("corvus_hdc_data_w: Received a byte with m_offset == 0. Processing as command: 0x%2.2x\n", data);
m_invalid_command_flag = parse_hdc_command(data);
m_timeout_timer->reset((attotime::from_seconds(4)));
m_timeout_timer->enable(1); // Start our four-second timer
} else if(m_offset == 1 && m_awaiting_modifier) { // Second byte of a packet
- LOG(("corvus_hdc_data_w: Received a byte while awaiting modifier with m_offset == 0. Processing as modifier: 0x%2.2x\n", data));
+ LOG("corvus_hdc_data_w: Received a byte while awaiting modifier with m_offset == 0. Processing as modifier: 0x%2.2x\n", data);
m_awaiting_modifier = false;
m_recv_bytes = corvus_cmd[m_buffer.command.code][data].recv_bytes;
m_xmit_bytes = corvus_cmd[m_buffer.command.code][data].xmit_bytes;
diff --git a/src/devices/machine/corvushd.h b/src/devices/machine/corvushd.h
index fddffa0e432..9f2d4910599 100644
--- a/src/devices/machine/corvushd.h
+++ b/src/devices/machine/corvushd.h
@@ -37,17 +37,13 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(process_timeout);
+ TIMER_CALLBACK_MEMBER(complete_function);
private:
static constexpr unsigned MAX_COMMAND_SIZE = 4096; // The maximum size of a command packet (the controller only has 5K of RAM...)
- enum
- {
- TIMER_TIMEOUT,
- TIMER_COMMAND
- };
-
// Sector addressing scheme for Rev B/H drives used in various commands (Called a DADR in the docs)
struct dadr_t {
uint8_t address_msn_and_drive;// Most significant nibble: Most significant nibble of sector address, Least significant nibble: Drive #
@@ -56,18 +52,22 @@ private:
};
uint8_t m_status; // Controller status byte (DIRECTION + BUSY/READY)
+
// Prep mode
bool m_prep_mode; // Whether the controller is in Prep Mode or not
uint8_t m_prep_drv; // If in prep mode, Corvus drive id (1..15) being prepped
+
// Physical drive info
uint8_t m_sectors_per_track; // Number of sectors per track for this drive
uint8_t m_tracks_per_cylinder;// Number of tracks per cylinder (heads)
uint16_t m_cylinders_per_drive;// Number of cylinders per drive
+
// Command Processing
uint16_t m_offset; // Current offset into raw_data buffer
bool m_awaiting_modifier; // We've received a two-byte command and we're waiting for the mod
uint16_t m_recv_bytes; // Number of bytes expected to be received from Host
uint16_t m_xmit_bytes; // Number of bytes expected to be transmitted to host
+
// Timing-related values
uint16_t m_last_cylinder; // Last cylinder accessed - for calculating seek times
uint32_t m_delay; // Delay in microseconds for callback
@@ -364,7 +364,7 @@ private:
uint8_t corvus_read_firmware_block(uint8_t head, uint8_t sector);
uint8_t corvus_write_firmware_block(uint8_t head, uint8_t sector, uint8_t *buffer);
uint8_t corvus_format_drive(uint8_t *pattern, uint16_t len);
- hard_disk_file *corvus_hdc_file(int id);
+ harddisk_image_device *corvus_hdc_file(int id);
void corvus_process_command_packet(bool local_invalid_command_flag);
corvus_cmd_t corvus_cmd[0xf5][0xc1]; // Command sizes and their return sizes
diff --git a/src/devices/machine/cr511b.cpp b/src/devices/machine/cr511b.cpp
index 5ff2decd5d5..3ac800c1db7 100644
--- a/src/devices/machine/cr511b.cpp
+++ b/src/devices/machine/cr511b.cpp
@@ -29,6 +29,7 @@ void cr511b_device::device_add_mconfig(machine_config &config)
CDDA(config, m_cdda);
m_cdda->add_route(0, ":lspeaker", 1.0);
m_cdda->add_route(1, ":rspeaker", 1.0);
+ m_cdda->set_cdrom_tag("cdrom");
}
@@ -50,7 +51,6 @@ cr511b_device::cr511b_device(const machine_config &mconfig, const char *tag, dev
m_dten_handler(*this),
m_scor_handler(*this),
m_xaen_handler(*this),
- m_frame_timer(nullptr),
//m_motor(false),
m_enabled(-1),
m_cmd(-1)
@@ -63,16 +63,6 @@ cr511b_device::cr511b_device(const machine_config &mconfig, const char *tag, dev
void cr511b_device::device_start()
{
- // resolve callbacks
- m_stch_handler.resolve_safe();
- m_sten_handler.resolve_safe();
- m_drq_handler.resolve_safe();
- m_dten_handler.resolve_safe();
- m_scor_handler.resolve_safe();
- m_xaen_handler.resolve_safe();
-
- m_frame_timer = timer_alloc(0, nullptr);
- m_frame_timer->adjust(attotime::never);
}
//-------------------------------------------------
@@ -83,15 +73,6 @@ void cr511b_device::device_reset()
{
}
-//-------------------------------------------------
-// device_timer - device-specific timer events
-//-------------------------------------------------
-
-void cr511b_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
-{
-}
-
-
//**************************************************************************
// IMPLEMENTATION
//**************************************************************************
@@ -105,12 +86,12 @@ void cr511b_device::write(uint8_t data)
{
}
-WRITE_LINE_MEMBER( cr511b_device::enable_w )
+void cr511b_device::enable_w(int state)
{
m_enabled = state;
}
-WRITE_LINE_MEMBER( cr511b_device::cmd_w )
+void cr511b_device::cmd_w(int state)
{
m_cmd = state;
}
diff --git a/src/devices/machine/cr511b.h b/src/devices/machine/cr511b.h
index ab70be1eb9c..034423c29b4 100644
--- a/src/devices/machine/cr511b.h
+++ b/src/devices/machine/cr511b.h
@@ -35,7 +35,7 @@
#pragma once
-#include "imagedev/chd_cd.h"
+#include "imagedev/cdromimg.h"
#include "sound/cdda.h"
class cr511b_device : public device_t
@@ -55,15 +55,14 @@ public:
uint8_t read();
void write(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( enable_w );
- DECLARE_WRITE_LINE_MEMBER( cmd_w );
+ void enable_w(int state);
+ void cmd_w(int state);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
enum
@@ -88,8 +87,6 @@ private:
devcb_write_line m_scor_handler;
devcb_write_line m_xaen_handler;
- emu_timer *m_frame_timer;
-
//bool m_motor;
// state of lines
diff --git a/src/devices/machine/cs4031.cpp b/src/devices/machine/cs4031.cpp
index b8919cca609..30712c02059 100644
--- a/src/devices/machine/cs4031.cpp
+++ b/src/devices/machine/cs4031.cpp
@@ -16,7 +16,7 @@
- 2x 8257 DMA controller
- 2x 8259 interrupt controller
- 8254 timer
- - MC14818 RTC
+ - MC146818 RTC
TODO:
- No emulation of memory parity checks
@@ -26,11 +26,8 @@
***************************************************************************/
#include "emu.h"
-#include "machine/cs4031.h"
+#include "cs4031.h"
-#include "machine/ram.h"
-
-#define LOG_GENERAL (1U << 0)
#define LOG_REGISTER (1U << 1)
#define LOG_MEMORY (1U << 2)
#define LOG_IO (1U << 3)
@@ -164,7 +161,7 @@ void cs4031_device::device_add_mconfig(machine_config &config)
cs4031_device::cs4031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, CS4031, tag, owner, clock),
- m_read_ior(*this),
+ m_read_ior(*this, 0),
m_write_iow(*this),
m_write_tc(*this),
m_write_hold(*this),
@@ -186,6 +183,7 @@ cs4031_device::cs4031_device(const machine_config &mconfig, const char *tag, dev
m_intc2(*this, "intc2"),
m_ctc(*this, "ctc"),
m_rtc(*this, "rtc"),
+ m_ram_dev(*this, finder_base::DUMMY_TAG),
m_dma_eop(0),
m_dma_high_byte(0xff),
m_dma_channel(-1),
@@ -211,23 +209,10 @@ cs4031_device::cs4031_device(const machine_config &mconfig, const char *tag, dev
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())
+ if (!m_ram_dev->started())
throw device_missing_dependencies();
- // resolve callbacks
- m_read_ior.resolve_safe(0);
- m_write_iow.resolve_safe();
- m_write_tc.resolve_safe();
- m_write_hold.resolve_safe();
- m_write_nmi.resolve_safe();
- m_write_intr.resolve_safe();
- m_write_cpureset.resolve_safe();
- m_write_a20m.resolve_safe();
- m_write_spkr.resolve_safe();
-
// register for state saving
save_item(NAME(m_dma_eop));
save_item(NAME(m_dma_page));
@@ -249,8 +234,8 @@ void cs4031_device::device_start()
m_space = &m_cpu->memory().space(AS_PROGRAM);
m_space_io = &m_cpu->memory().space(AS_IO);
- m_ram = ram_dev->pointer();
- uint32_t ram_size = ram_dev->size();
+ m_ram = m_ram_dev->pointer();
+ uint32_t ram_size = m_ram_dev->size();
// install base memory
m_space->install_ram(0x000000, 0x09ffff, m_ram);
@@ -271,7 +256,8 @@ void cs4031_device::device_start()
m_space_io->install_readwrite_handler(0x0060, 0x0063, read8smo_delegate(*this, FUNC(cs4031_device::keyb_data_r)), write8smo_delegate(*this, FUNC(cs4031_device::keyb_data_w)), 0x000000ff);
m_space_io->install_readwrite_handler(0x0060, 0x0063, read8smo_delegate(*this, FUNC(cs4031_device::portb_r)), write8smo_delegate(*this, FUNC(cs4031_device::portb_w)), 0x0000ff00);
m_space_io->install_readwrite_handler(0x0064, 0x0067, read8smo_delegate(*this, FUNC(cs4031_device::keyb_status_r)), write8smo_delegate(*this, FUNC(cs4031_device::keyb_command_w)), 0x000000ff);
- m_space_io->install_readwrite_handler(0x0070, 0x0073, read8sm_delegate(*m_rtc, FUNC(mc146818_device::read)), write8sm_delegate(*this, FUNC(cs4031_device::rtc_w)), 0x0000ffff);
+ m_space_io->install_write_handler(0x0070, 0x0073, write8smo_delegate(*this, FUNC(cs4031_device::rtc_nmi_w)), 0x000000ff); // RTC address (84035) and NMI mask (84031) are both write-only
+ m_space_io->install_readwrite_handler(0x0070, 0x0073, read8smo_delegate(*m_rtc, FUNC(mc146818_device::data_r)), write8smo_delegate(*m_rtc, FUNC(mc146818_device::data_w)), 0x0000ff00);
m_space_io->install_readwrite_handler(0x0080, 0x008f, read8sm_delegate(*this, FUNC(cs4031_device::dma_page_r)), write8sm_delegate(*this, FUNC(cs4031_device::dma_page_w)), 0xffffffff);
m_space_io->install_readwrite_handler(0x0090, 0x0093, read8smo_delegate(*this, FUNC(cs4031_device::sysctrl_r)), write8smo_delegate(*this, FUNC(cs4031_device::sysctrl_w)), 0x00ff0000);
m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8sm_delegate(*m_intc2, FUNC(pic8259_device::read)), write8sm_delegate(*m_intc2, FUNC(pic8259_device::write)), 0x0000ffff);
@@ -363,12 +349,12 @@ void cs4031_device::dma_write_word(offs_t offset, uint8_t data)
m_space->write_word((page_offset() & 0xfe0000) | (offset << 1), (m_dma_high_byte << 8) | data);
}
-WRITE_LINE_MEMBER( cs4031_device::dma2_dack0_w )
+void cs4031_device::dma2_dack0_w(int state)
{
m_dma1->hack_w(state ? 0 : 1); // inverted?
}
-WRITE_LINE_MEMBER( cs4031_device::dma1_eop_w )
+void cs4031_device::dma1_eop_w(int state)
{
m_dma_eop = state;
if (m_dma_channel != -1)
@@ -439,7 +425,7 @@ uint8_t cs4031_device::intc1_slave_ack_r(offs_t offset)
return 0x00;
}
-WRITE_LINE_MEMBER( cs4031_device::iochck_w )
+void cs4031_device::iochck_w(int state)
{
LOGIO("cs4031_device::iochck_w: %u\n", state);
@@ -461,13 +447,13 @@ WRITE_LINE_MEMBER( cs4031_device::iochck_w )
// TIMER
//**************************************************************************
-WRITE_LINE_MEMBER( cs4031_device::ctc_out1_w )
+void cs4031_device::ctc_out1_w(int state)
{
m_refresh_toggle ^= state;
m_portb = (m_portb & 0xef) | (m_refresh_toggle << 4);
}
-WRITE_LINE_MEMBER( cs4031_device::ctc_out2_w )
+void cs4031_device::ctc_out2_w(int state)
{
m_write_spkr(!(state & BIT(m_portb, 1)));
m_portb = (m_portb & 0xdf) | (state << 5);
@@ -798,14 +784,14 @@ void cs4031_device::keyb_data_w(uint8_t data)
}
}
-WRITE_LINE_MEMBER( cs4031_device::gatea20_w )
+void cs4031_device::gatea20_w(int state)
{
LOGKEYBOARD("cs4031_device::gatea20_w: %u\n", state);
keyboard_gatea20(state);
}
-WRITE_LINE_MEMBER( cs4031_device::kbrst_w )
+void cs4031_device::kbrst_w(int state)
{
LOGKEYBOARD("cs4031_device::kbrst_w: %u\n", state);
@@ -913,16 +899,13 @@ void cs4031_device::portb_w(uint8_t data)
7 - NMI mask
6:0 - RTC address
*/
-void cs4031_device::rtc_w(offs_t offset, uint8_t data)
+void cs4031_device::rtc_nmi_w(uint8_t data)
{
if (0)
- logerror("cs4031_device::rtc_w: %02x\n", data);
+ logerror("cs4031_device::rtc_nmi_w: %02x\n", data);
- if (offset == 0)
- {
- m_nmi_mask = !BIT(data, 7);
- data &= 0x7f;
- }
+ m_nmi_mask = !BIT(data, 7);
+ data &= 0x7f;
- m_rtc->write(offset, data);
+ m_rtc->address_w(data);
}
diff --git a/src/devices/machine/cs4031.h b/src/devices/machine/cs4031.h
index b8540380679..4a98721861b 100644
--- a/src/devices/machine/cs4031.h
+++ b/src/devices/machine/cs4031.h
@@ -4,20 +4,6 @@
Chips & Technologies CS4031 chipset
- Chipset for 486 based PC/AT compatible systems. Consists of two
- individual chips:
-
- * F84031
- - DRAM controller
- - ISA-bus controller
- - VESA VL-BUS controller
-
- * F84035 (82C206 IPC core)
- - 2x 8257 DMA controller
- - 2x 8259 interrupt controller
- - 8254 timer
- - MC14818 RTC
-
***************************************************************************/
#ifndef MAME_MACHINE_CS4031_H
@@ -30,19 +16,21 @@
#include "machine/pit8253.h"
#include "machine/ds128x.h"
#include "machine/at_keybc.h"
+#include "machine/ram.h"
class cs4031_device : public device_t
{
public:
// construction/destruction
- template <typename T, typename U, typename V, typename W>
- cs4031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cputag, U &&isatag, V &&biostag, W &&keybctag)
+ template <typename T, typename U, typename V, typename W, typename X>
+ cs4031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cputag, U &&isatag, V &&biostag, W &&keybctag, X &&ramtag)
: cs4031_device(mconfig, tag, owner, clock)
{
set_cputag(std::forward<T>(cputag));
set_isatag(std::forward<U>(isatag));
set_biostag(std::forward<V>(biostag));
set_keybctag(std::forward<W>(keybctag));
+ set_ramtag(std::forward<X>(ramtag));
}
cs4031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -64,7 +52,7 @@ public:
void config_data_w(uint8_t data);
uint8_t portb_r();
void portb_w(uint8_t data);
- void rtc_w(offs_t offset, uint8_t data);
+ void rtc_nmi_w(uint8_t data);
void sysctrl_w(uint8_t data);
uint8_t sysctrl_r();
uint8_t dma_page_r(offs_t offset) { return m_dma_page[offset]; }
@@ -78,30 +66,30 @@ public:
void keyb_command_blocked_w(uint8_t data);
// input lines
- DECLARE_WRITE_LINE_MEMBER( irq01_w ) { m_intc1->ir1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq03_w ) { m_intc1->ir3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq04_w ) { m_intc1->ir4_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq05_w ) { m_intc1->ir5_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq06_w ) { m_intc1->ir6_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq07_w ) { m_intc1->ir7_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq09_w ) { m_intc2->ir1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq10_w ) { m_intc2->ir2_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq11_w ) { m_intc2->ir3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq12_w ) { m_intc2->ir4_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq13_w ) { m_intc2->ir5_w(state); } // also FERR#
- DECLARE_WRITE_LINE_MEMBER( irq14_w ) { m_intc2->ir6_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq15_w ) { m_intc2->ir7_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq0_w ) { m_dma1->dreq0_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq1_w ) { m_dma1->dreq1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq2_w ) { m_dma1->dreq2_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq3_w ) { m_dma1->dreq3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq5_w ) { m_dma2->dreq1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq6_w ) { m_dma2->dreq2_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq7_w ) { m_dma2->dreq3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( hlda_w ) { m_dma2->hack_w(state); }
- DECLARE_WRITE_LINE_MEMBER( iochck_w );
- DECLARE_WRITE_LINE_MEMBER( gatea20_w );
- DECLARE_WRITE_LINE_MEMBER( kbrst_w );
+ void irq01_w(int state) { m_intc1->ir1_w(state); }
+ void irq03_w(int state) { m_intc1->ir3_w(state); }
+ void irq04_w(int state) { m_intc1->ir4_w(state); }
+ void irq05_w(int state) { m_intc1->ir5_w(state); }
+ void irq06_w(int state) { m_intc1->ir6_w(state); }
+ void irq07_w(int state) { m_intc1->ir7_w(state); }
+ void irq09_w(int state) { m_intc2->ir1_w(state); }
+ void irq10_w(int state) { m_intc2->ir2_w(state); }
+ void irq11_w(int state) { m_intc2->ir3_w(state); }
+ void irq12_w(int state) { m_intc2->ir4_w(state); }
+ void irq13_w(int state) { m_intc2->ir5_w(state); } // also FERR#
+ void irq14_w(int state) { m_intc2->ir6_w(state); }
+ void irq15_w(int state) { m_intc2->ir7_w(state); }
+ void dreq0_w(int state) { m_dma1->dreq0_w(state); }
+ void dreq1_w(int state) { m_dma1->dreq1_w(state); }
+ void dreq2_w(int state) { m_dma1->dreq2_w(state); }
+ void dreq3_w(int state) { m_dma1->dreq3_w(state); }
+ void dreq5_w(int state) { m_dma2->dreq1_w(state); }
+ void dreq6_w(int state) { m_dma2->dreq2_w(state); }
+ void dreq7_w(int state) { m_dma2->dreq3_w(state); }
+ void hlda_w(int state) { m_dma2->hack_w(state); }
+ void iochck_w(int state);
+ void gatea20_w(int state);
+ void kbrst_w(int state);
IRQ_CALLBACK_MEMBER(int_ack_r) { return m_intc1->acknowledge(); }
@@ -110,6 +98,7 @@ public:
template <typename T> void set_isatag(T &&tag) { m_isa.set_tag(std::forward<T>(tag)); }
template <typename T> void set_biostag(T &&tag) { m_bios.set_tag(std::forward<T>(tag)); }
template <typename T> void set_keybctag(T &&tag) { m_keybc.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_ramtag(T &&tag) { m_ram_dev.set_tag(std::forward<T>(tag)); }
protected:
// device-level overrides
@@ -164,6 +153,7 @@ private:
required_device<pic8259_device> m_intc2;
required_device<pit8254_device> m_ctc;
required_device<ds12885_device> m_rtc;
+ required_device<ram_device> m_ram_dev;
int m_dma_eop;
uint8_t m_dma_page[0x10];
@@ -209,7 +199,7 @@ private:
void dma_write_byte(offs_t offset, uint8_t data);
uint8_t dma_read_word(offs_t offset);
void dma_write_word(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( dma1_eop_w );
+ void dma1_eop_w(int state);
uint8_t dma1_ior0_r() { return m_read_ior(0); }
uint8_t dma1_ior1_r() { return m_read_ior(1); }
uint8_t dma1_ior2_r() { return m_read_ior(2); }
@@ -224,19 +214,19 @@ private:
void dma2_iow1_w(uint8_t data) { m_write_iow(5, (m_dma_high_byte << 8) | data, 0xffff); }
void dma2_iow2_w(uint8_t data) { m_write_iow(6, (m_dma_high_byte << 8) | data, 0xffff); }
void dma2_iow3_w(uint8_t data) { m_write_iow(7, (m_dma_high_byte << 8) | data, 0xffff); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack0_w ) { set_dma_channel(0, state); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack1_w ) { set_dma_channel(1, state); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack2_w ) { set_dma_channel(2, state); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack3_w ) { set_dma_channel(3, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_dack0_w );
- DECLARE_WRITE_LINE_MEMBER( dma2_dack1_w ) { set_dma_channel(5, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_dack2_w ) { set_dma_channel(6, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_dack3_w ) { set_dma_channel(7, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_hreq_w ) { m_write_hold(state); }
- DECLARE_WRITE_LINE_MEMBER( intc1_int_w ) { m_write_intr(state); }
+ void dma1_dack0_w(int state) { set_dma_channel(0, state); }
+ void dma1_dack1_w(int state) { set_dma_channel(1, state); }
+ void dma1_dack2_w(int state) { set_dma_channel(2, state); }
+ void dma1_dack3_w(int state) { set_dma_channel(3, state); }
+ void dma2_dack0_w(int state);
+ void dma2_dack1_w(int state) { set_dma_channel(5, state); }
+ void dma2_dack2_w(int state) { set_dma_channel(6, state); }
+ void dma2_dack3_w(int state) { set_dma_channel(7, state); }
+ void dma2_hreq_w(int state) { m_write_hold(state); }
+ void intc1_int_w(int state) { m_write_intr(state); }
uint8_t intc1_slave_ack_r(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER( ctc_out1_w );
- DECLARE_WRITE_LINE_MEMBER( ctc_out2_w );
+ void ctc_out1_w(int state);
+ void ctc_out2_w(int state);
};
DECLARE_DEVICE_TYPE(CS4031, cs4031_device)
diff --git a/src/devices/machine/cs8221.cpp b/src/devices/machine/cs8221.cpp
index e57f181e383..64887cafc6b 100644
--- a/src/devices/machine/cs8221.cpp
+++ b/src/devices/machine/cs8221.cpp
@@ -16,10 +16,10 @@
***************************************************************************/
#include "emu.h"
-#include "machine/cs8221.h"
+#include "cs8221.h"
+
#include "machine/ram.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_REGISTER (1U << 1)
#define LOG_MEMORY (1U << 2)
diff --git a/src/devices/machine/cs8900a.cpp b/src/devices/machine/cs8900a.cpp
index 6f6535150f7..5efab09a5ad 100644
--- a/src/devices/machine/cs8900a.cpp
+++ b/src/devices/machine/cs8900a.cpp
@@ -1,5 +1,4 @@
// license:GPL-2.0+
-
// copyright-holders:Spiro Trikaliotis, Rhett Aultman
/*************************************************************************
@@ -13,24 +12,24 @@
**************************************************************************/
#include "emu.h"
-#include "machine/cs8900a.h"
+#include "cs8900a.h"
#include <cstring>
DEFINE_DEVICE_TYPE(CS8900A, cs8900a_device, "cs8900a", "CS8900A Crystal LAN 10Base-T Ethernet MAC")
/* warn illegal behaviour */
-#define CS8900_DEBUG_WARN_REG (1 << 1U) /* warn about invalid register accesses */
-#define CS8900_DEBUG_WARN_RXTX (1 << 2U) /* warn about invalid rx or tx conditions */
-
-#define CS8900_DEBUG (1 << 3U) /* enable to see port reads */
-#define CS8900_DEBUG_INIT (1 << 4U)
-#define CS8900_DEBUG_LOAD (1 << 5U) /* enable to see port reads */
-#define CS8900_DEBUG_STORE (1 << 6U) /* enable to see port writes */
-#define CS8900_DEBUG_REGISTERS (1 << 7U) /* enable to see CS8900a register I/O */
-#define CS8900_DEBUG_RXTX_STATE (1 << 8U) /* enable to see tranceiver state changes */
-#define CS8900_DEBUG_RXTX_DATA (1 << 9U) /* enable to see data in/out flow */
-#define CS8900_DEBUG_FRAMES (1 << 10U) /* enable to see arch frame send/recv */
+#define CS8900_DEBUG_WARN_REG (1U << 1) /* warn about invalid register accesses */
+#define CS8900_DEBUG_WARN_RXTX (1U << 2) /* warn about invalid rx or tx conditions */
+
+#define CS8900_DEBUG (1U << 3) /* enable to see port reads */
+#define CS8900_DEBUG_INIT (1U << 4)
+#define CS8900_DEBUG_LOAD (1U << 5) /* enable to see port reads */
+#define CS8900_DEBUG_STORE (1U << 6) /* enable to see port writes */
+#define CS8900_DEBUG_REGISTERS (1U << 7) /* enable to see CS8900a register I/O */
+#define CS8900_DEBUG_RXTX_STATE (1U << 8) /* enable to see tranceiver state changes */
+#define CS8900_DEBUG_RXTX_DATA (1U << 9) /* enable to see data in/out flow */
+#define CS8900_DEBUG_FRAMES (1U << 10) /* enable to see arch frame send/recv */
/** #define CS8900_DEBUG_IGNORE_RXEVENT 1 **/ /* enable to ignore RXEVENT in DEBUG_REGISTERS */
#define VERBOSE 0
@@ -377,7 +376,7 @@ void cs8900a_device::device_start()
cs8900a_device::cs8900a_device(const machine_config& mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
- , device_network_interface(mconfig, *this, 10.0f)
+ , device_network_interface(mconfig, *this, 10)
, cs8900_ia_mac{0, 0, 0, 0, 0, 0}
, cs8900_packetpage_ptr(0)
, cs8900_recv_control(0) /* copy of CC_RXCTL (contains all bits below) */
@@ -923,7 +922,7 @@ void cs8900a_device::cs8900_sideeffects_write_pp(u16 ppaddress, int odd_address)
/* the MAC address has been changed */
cs8900_ia_mac[ppaddress - CS8900_PP_ADDR_MAC_ADDR + odd_address] = GET_PP_8(ppaddress + odd_address);
- set_mac((char *)cs8900_ia_mac);
+ set_mac(cs8900_ia_mac);
if (odd_address && (ppaddress == CS8900_PP_ADDR_MAC_ADDR + 4))
LOGMASKED(CS8900_DEBUG, "set MAC address: %02x:%02x:%02x:%02x:%02x:%02x",
diff --git a/src/devices/machine/cs8900a.h b/src/devices/machine/cs8900a.h
index 74e4c8b20b3..a0a6f88dbb4 100644
--- a/src/devices/machine/cs8900a.h
+++ b/src/devices/machine/cs8900a.h
@@ -16,6 +16,8 @@
#pragma once
+#include "dinetwork.h"
+
#include <queue>
/***************************************************************************
diff --git a/src/devices/machine/cxd1095.cpp b/src/devices/machine/cxd1095.cpp
index 1f78ca628a1..7819751e573 100644
--- a/src/devices/machine/cxd1095.cpp
+++ b/src/devices/machine/cxd1095.cpp
@@ -17,7 +17,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/cxd1095.h"
+#include "cxd1095.h"
//**************************************************************************
// GLOBAL VARIABLES
@@ -35,7 +35,7 @@ DEFINE_DEVICE_TYPE(CXD1095, cxd1095_device, "cxd1095", "CXD1095 I/O Expander")
cxd1095_device::cxd1095_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, CXD1095, tag, owner, clock)
- , m_input_cb(*this)
+ , m_input_cb(*this, 0)
, m_output_cb(*this)
{
}
@@ -46,10 +46,6 @@ cxd1095_device::cxd1095_device(const machine_config &mconfig, const char *tag, d
void cxd1095_device::device_start()
{
- // resolve callbacks
- m_input_cb.resolve_all();
- m_output_cb.resolve_all();
-
std::fill(std::begin(m_data_latch), std::end(m_data_latch), 0);
// save state
@@ -80,7 +76,7 @@ u8 cxd1095_device::read(offs_t offset)
input_mask &= 0x0f;
// read through callback if port not configured entirely for output
- if (input_mask != 0 && !m_input_cb[offset].isnull())
+ if (input_mask != 0 && !m_input_cb[offset].isunset())
input_data = m_input_cb[offset](0, input_mask) & input_mask;
else if (m_data_dir[offset] == 0xff)
logerror("Reading from undefined input port %c\n", 'A' + offset);
@@ -111,7 +107,7 @@ void cxd1095_device::write(offs_t offset, u8 data)
// send output through callback
u8 dataout = data & ~m_data_dir[offset];
- if (!m_output_cb[offset].isnull())
+ if (!m_output_cb[offset].isunset())
m_output_cb[offset](0, dataout, ~m_data_dir[offset]);
else
logerror("Writing %02X to undefined output port %c\n", dataout, 'A' + offset);
diff --git a/src/devices/machine/cxd1185.cpp b/src/devices/machine/cxd1185.cpp
index b599d307783..8b24126b662 100644
--- a/src/devices/machine/cxd1185.cpp
+++ b/src/devices/machine/cxd1185.cpp
@@ -16,7 +16,6 @@
#include "emu.h"
#include "cxd1185.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_CMD (1U << 1)
#define LOG_REG (1U << 2)
#define LOG_STATE (1U << 3)
@@ -74,10 +73,6 @@ void cxd1185_device::map(address_map &map)
void cxd1185_device::device_start()
{
- m_irq_out_cb.resolve_safe();
- m_drq_out_cb.resolve_safe();
- m_port_out_cb.resolve_safe();
-
save_item(NAME(m_state));
save_item(NAME(m_irq_asserted));
save_item(NAME(m_drq_asserted));
@@ -100,7 +95,7 @@ void cxd1185_device::device_start()
save_item(NAME(m_scsi_ctrl));
save_item(NAME(m_ioport));
- m_state_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cxd1185_device::state_timer), this));
+ m_state_timer = timer_alloc(FUNC(cxd1185_device::state_timer), this);
m_state = IDLE;
m_irq_asserted = false;
@@ -482,7 +477,7 @@ void cxd1185_device::ioport_w(u8 data)
m_port_out_cb(0, m_ioport & mask, mask);
}
-void cxd1185_device::state_timer(void *ptr, s32 param)
+void cxd1185_device::state_timer(s32 param)
{
// step state machine
int delay = state_step();
@@ -902,7 +897,7 @@ void cxd1185_device::port_w(u8 data)
{
u8 const mask = ~(PCN | ((m_ioport & PCN) >> 4));
- LOGMASKED(LOG_GENERAL, "port_w 0x%02x mask 0x%02x\n", data, mask);
+ LOG("port_w 0x%02x mask 0x%02x\n", data, mask);
m_ioport &= ~mask;
m_ioport |= data & mask;
diff --git a/src/devices/machine/cxd1185.h b/src/devices/machine/cxd1185.h
index a064c9e5c23..f1d6732b26d 100644
--- a/src/devices/machine/cxd1185.h
+++ b/src/devices/machine/cxd1185.h
@@ -62,7 +62,7 @@ protected:
void ioport_w(u8 data);
// state machine
- void state_timer(void *ptr, s32 param);
+ void state_timer(s32 param);
int state_step();
// other logic
diff --git a/src/devices/machine/dc7085.cpp b/src/devices/machine/dc7085.cpp
deleted file mode 100644
index 4918cc1fcce..00000000000
--- a/src/devices/machine/dc7085.cpp
+++ /dev/null
@@ -1,449 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-
-/*
- * An emulation of the Digital Equipment Corporation DC7085 (also called "DZ") quad-UART
- *
- * Used in:
- *
- * Several models of MIPS DECstation
- * Some VAXstations
- *
- * Sources:
- *
- * http://www.vanade.com/~blc/DS3100/pmax/DS3100.func.spec.pdf
- *
- */
-
-#include "emu.h"
-#include "dc7085.h"
-
-#define LOG_GENERAL (1U << 0)
-#define LOG_REG (1U << 1)
-#define LOG_RX (1U << 2)
-#define LOG_TX (1U << 3)
-#define LOG_IRQ (1U << 4)
-
-//#define VERBOSE (LOG_GENERAL|LOG_REG|LOG_RX|LOG_TX|LOG_IRQ)
-
-#include "logmacro.h"
-
-DEFINE_DEVICE_TYPE(DC7085, dc7085_device, "dc7085", "Digital Equipment Corporation DC7085 Quad UART")
-DEFINE_DEVICE_TYPE(DC7085_CHANNEL, dc7085_channel, "dc7085_channel", "DC7085 UART channel")
-
-dc7085_device::dc7085_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DC7085, tag, owner, clock),
- m_chan0(*this, "ch0"),
- m_chan1(*this, "ch1"),
- m_chan2(*this, "ch2"),
- m_chan3(*this, "ch3"),
- m_int_cb(*this),
- write_0_tx(*this),
- write_1_tx(*this),
- write_2_tx(*this),
- write_3_tx(*this)
-{
- std::fill_n(&rx_fifo[0], DC7085_RX_FIFO_SIZE, 0);
- rx_fifo_num = 0;
-}
-
-void dc7085_device::device_add_mconfig(machine_config &config)
-{
- DC7085_CHANNEL(config, m_chan0, 0);
- DC7085_CHANNEL(config, m_chan1, 0);
- DC7085_CHANNEL(config, m_chan2, 0);
- DC7085_CHANNEL(config, m_chan3, 0);
-}
-
-void dc7085_device::map(address_map &map)
-{
- map(0x00, 0x01).rw(FUNC(dc7085_device::status_r), FUNC(dc7085_device::control_w));
- map(0x04, 0x05).rw(FUNC(dc7085_device::rxbuffer_r), FUNC(dc7085_device::lineparams_w));
- map(0x08, 0x09).rw(FUNC(dc7085_device::txparams_r), FUNC(dc7085_device::txparams_w));
- map(0x0c, 0x0d).rw(FUNC(dc7085_device::modem_status_r), FUNC(dc7085_device::txdata_w));
-}
-
-void dc7085_device::device_start()
-{
- m_int_cb.resolve_safe();
- write_0_tx.resolve_safe();
- write_1_tx.resolve_safe();
- write_2_tx.resolve_safe();
- write_3_tx.resolve_safe();
-
- save_item(NAME(m_status));
- save_item(NAME(rx_fifo));
- save_item(NAME(rx_fifo_read_ptr));
- save_item(NAME(rx_fifo_write_ptr));
- save_item(NAME(rx_fifo_num));
-}
-
-void dc7085_device::device_reset()
-{
- m_chan0->clear();
- m_chan1->clear();
- m_chan2->clear();
- m_chan3->clear();
- m_status = 0;
- std::fill_n(&rx_fifo[0], DC7085_RX_FIFO_SIZE, 0);
- rx_fifo_write_ptr = rx_fifo_read_ptr = 0;
- rx_fifo_num = 0;
-}
-
-u16 dc7085_device::status_r()
-{
- return m_status;
-}
-
-u16 dc7085_device::rxbuffer_r()
-{
- u16 rv;
-
- LOGMASKED(LOG_RX, "rxbuffer_r: rx_fifo_num %d\n", rx_fifo_num);
-
- if (rx_fifo_num == 0)
- {
- LOGMASKED(LOG_RX, "rx fifo underflow\n");
- m_status &= ~CTRL_RX_DONE;
- recalc_irqs();
- return 0;
- }
-
- rv = rx_fifo[rx_fifo_read_ptr++];
- if (rx_fifo_read_ptr == DC7085_RX_FIFO_SIZE)
- {
- rx_fifo_read_ptr = 0;
- }
-
- rx_fifo_num--;
- if (rx_fifo_num == 0)
- {
- m_status &= ~CTRL_RX_DONE;
- }
-
- recalc_irqs();
-
- //printf("Rx read %02x\n", rv);
-
- return rv;
-}
-
-u16 dc7085_device::txparams_r()
-{
- return 0;
-}
-
-u16 dc7085_device::modem_status_r()
-{
- return 0;
-}
-
-void dc7085_device::control_w(u16 data)
-{
- LOGMASKED(LOG_REG, "control_w %04x\n", data);
- LOGMASKED(LOG_REG, "\tTx IRQ %d Rx IRQ %d\n", (data & CTRL_TX_IRQ_ENABLE) ? "1" : "0", (data & CTRL_RX_IRQ_ENABLE) ? "1" : "0");
- LOGMASKED(LOG_REG, "\tScan enable %d Master clear %d\n", (data & CTRL_MASTER_SCAN) ? "1" : "0", (data & CTRL_MASTER_CLEAR) ? "1" : "0");
- LOGMASKED(LOG_REG, "\tLocal loopback %d\n", (data & CTRL_LOOPBACK) ? "1" : "0");
-
- if (data & CTRL_MASTER_CLEAR)
- {
- m_chan0->clear();
- m_chan1->clear();
- m_chan2->clear();
- m_chan3->clear();
- m_status = 0;
- rx_fifo_write_ptr = rx_fifo_read_ptr = 0;
- rx_fifo_num = 0;
- return;
- }
-
- data &= (CTRL_TX_IRQ_ENABLE|CTRL_RX_IRQ_ENABLE|CTRL_MASTER_SCAN|CTRL_LOOPBACK);
- m_status &= ~(CTRL_TX_IRQ_ENABLE|CTRL_RX_IRQ_ENABLE|CTRL_MASTER_SCAN|CTRL_LOOPBACK);
- m_status |= data;
-}
-
-void dc7085_device::lineparams_w(u16 data)
-{
- static const int bauds[] = { 50, 75, 110, 134, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19800 };
-
- LOGMASKED(LOG_REG, "lineparams_w %04x\n", data);
- LOGMASKED(LOG_REG, "\tline %d baud %d rx enabled %d\n", data & 3, bauds[(data>>8) & 0x0f], (data & 0x1000) ? 1 : 0);
- LOGMASKED(LOG_REG, "\tline %d %d data bits, %d stop bits\n", data & 3, ((data>>3) & 3) + 5, ((data>>5) & 1));
- LOGMASKED(LOG_REG, "\tline %d parity %s %s\n", data & 3, (data & LPARAM_ODD_PARITY) ? "odd" : "even", (data & LPARAM_PARITY_ENB) ? "enabled" : "disabled");
-
- int parity = -1;
- if (data & LPARAM_PARITY_ENB)
- {
- parity = (data & LPARAM_ODD_PARITY) ? 1 : 0;
- }
-
- switch (data & 3)
- {
- case 0:
- m_chan0->set_format(((data>>3) & 3) + 5, parity, ((data>>5) & 1));
- m_chan0->set_baud_rate(bauds[(data>>8) & 0x0f]);
- m_chan0->set_rx_enable(data & LPARAM_RX_ENABLE);
- break;
- case 1:
- m_chan1->set_format(((data>>3) & 3) + 5, parity, ((data>>5) & 1));
- m_chan1->set_baud_rate(bauds[(data>>8) & 0x0f]);
- m_chan1->set_rx_enable(data & LPARAM_RX_ENABLE);
- break;
- case 2:
- m_chan2->set_format(((data>>3) & 3) + 5, parity, ((data>>5) & 1));
- m_chan2->set_baud_rate(bauds[(data>>8) & 0x0f]);
- m_chan2->set_rx_enable(data & LPARAM_RX_ENABLE);
- break;
- case 3:
- m_chan3->set_format(((data>>3) & 3) + 5, parity, ((data>>5) & 1));
- m_chan3->set_baud_rate(bauds[(data>>8) & 0x0f]);
- m_chan3->set_rx_enable(data & LPARAM_RX_ENABLE);
- break;
- }
-}
-
-void dc7085_device::txparams_w(u16 data)
-{
- LOGMASKED(LOG_REG, "txparams_w %04x\n", data);
-
- m_chan0->set_tx_enable(data & TXCTRL_LINE0_ENB);
- m_chan1->set_tx_enable(data & TXCTRL_LINE1_ENB);
- m_chan2->set_tx_enable(data & TXCTRL_LINE2_ENB);
- m_chan3->set_tx_enable(data & TXCTRL_LINE3_ENB);
- recalc_irqs();
-}
-
-void dc7085_device::txdata_w(u16 data)
-{
- LOGMASKED(LOG_REG, "txdata_w %04x\n", data);
- switch ((m_status >> 8) & 3)
- {
- case 0:
- m_chan0->write_TX(data&0xff);
- break;
- case 1:
- m_chan1->write_TX(data&0xff);
- break;
- case 2:
- m_chan2->write_TX(data&0xff);
- break;
- case 3:
- m_chan3->write_TX(data&0xff);
- break;
- }
-}
-
-void dc7085_device::recalc_irqs()
-{
- bool bIRQ = false;
-
- LOGMASKED(LOG_IRQ, "recalc_irqs enter\n");
- if (m_chan0->is_tx_ready())
- {
- m_status |= CTRL_TRDY;
- m_status &= ~CTRL_LINE_MASK;
- LOGMASKED(LOG_IRQ, "ch 0: set TRDY\n");
- }
- else if (m_chan1->is_tx_ready())
- {
- m_status |= CTRL_TRDY;
- m_status &= ~CTRL_LINE_MASK;
- m_status |= (1 << 8);
- LOGMASKED(LOG_IRQ, "ch 1: set TRDY\n");
- }
- else if (m_chan2->is_tx_ready())
- {
- m_status |= CTRL_TRDY;
- m_status &= ~CTRL_LINE_MASK;
- m_status |= (2 << 8);
- LOGMASKED(LOG_IRQ, "ch 2: set TRDY\n");
- }
- else if (m_chan3->is_tx_ready())
- {
- m_status |= CTRL_TRDY;
- m_status &= ~CTRL_LINE_MASK;
- m_status |= (3 << 8);
- LOGMASKED(LOG_IRQ, "ch 3: set TRDY\n");
- }
-
- if ((m_status & CTRL_TRDY) && (m_status & CTRL_TX_IRQ_ENABLE))
- {
- bIRQ = true;
- }
- else if ((m_status & CTRL_RX_DONE) && (m_status & CTRL_RX_IRQ_ENABLE))
- {
- bIRQ = true;
- }
-
- if (bIRQ)
- {
- m_int_cb(ASSERT_LINE);
- }
- else
- {
- m_int_cb(CLEAR_LINE);
- }
-}
-
-void dc7085_device::rx_fifo_push(uint16_t data, uint16_t errors)
-{
- if (rx_fifo_num >= DC7085_RX_FIFO_SIZE)
- {
- LOGMASKED(LOG_RX, "DC7085: FIFO overflow\n");
- data |= dc7085_device::RXMASK_OVERRUN_ERR;
- return;
- }
-
- rx_fifo[rx_fifo_write_ptr++] = data | errors;
- if (rx_fifo_write_ptr == DC7085_RX_FIFO_SIZE)
- rx_fifo_write_ptr = 0;
-
- rx_fifo_num++;
-
- LOGMASKED(LOG_RX, "ch %d, got %02x, fifo_num %d\n", (data>>8) & 3, data&0xff, rx_fifo_num);
-
- m_status |= dc7085_device::CTRL_RX_DONE;
- recalc_irqs();
-}
-
-// UART channel class stuff
-
-dc7085_channel::dc7085_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DC7085_CHANNEL, tag, owner, clock)
- , device_serial_interface(mconfig, *this)
- , rx_enabled(0)
- , tx_enabled(0)
-{
-}
-
-void dc7085_channel::device_start()
-{
- m_base = downcast<dc7085_device *>(owner());
- m_ch = m_base->get_ch(this); // get our channel number
-
- save_item(NAME(baud_rate));
- save_item(NAME(rx_enabled));
- save_item(NAME(tx_enabled));
- save_item(NAME(tx_data));
- save_item(NAME(tx_ready));
-}
-
-void dc7085_channel::device_reset()
-{
- set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
-
- baud_rate = 0;
- rx_enabled = 0;
- tx_enabled = 0;
- tx_ready = 1;
-}
-
-// serial device virtual overrides
-void dc7085_channel::rcv_complete()
-{
- receive_register_extract();
-
- //printf("%s ch %d rcv complete\n", tag(), m_ch);
-
- if (rx_enabled)
- {
- uint16_t errors = 0;
- if (is_receive_framing_error())
- errors |= dc7085_device::RXMASK_FRAMING_ERR;
- if (is_receive_parity_error())
- errors |= dc7085_device::RXMASK_PARITY_ERR;
-
- m_base->rx_fifo_push(get_received_char() | (m_ch << 8) | dc7085_device::RXMASK_DATA_VALID, errors);
- }
-}
-
-void dc7085_channel::tra_complete()
-{
- LOGMASKED(LOG_TX, "ch %d Tx complete\n", m_ch);
- tx_ready = 1;
-
- // if local loopback is on, write the transmitted data as if a byte had been received
- if (m_base->m_status & dc7085_device::CTRL_LOOPBACK)
- m_base->rx_fifo_push(tx_data | (m_ch << 8) | dc7085_device::RXMASK_DATA_VALID, 0);
-
- m_base->recalc_irqs();
-}
-
-void dc7085_channel::tra_callback()
-{
- int bit = transmit_register_get_data_bit();
-
- LOGMASKED(LOG_TX, "transmit %d\n", bit);
- switch (m_ch)
- {
- case 0: m_base->write_0_tx(bit); break;
- case 1: m_base->write_1_tx(bit); break;
- case 2: m_base->write_2_tx(bit); break;
- case 3: m_base->write_3_tx(bit); break;
- }
-}
-
-void dc7085_channel::set_baud_rate(int baud)
-{
- set_tra_rate(baud);
- set_rcv_rate(baud);
- baud_rate = baud;
-}
-
-void dc7085_channel::set_format(int data_bits, int parity, int stop_bits)
-{
- switch (parity)
- {
- case -1:
- set_data_frame(1, data_bits, PARITY_NONE, stop_bits ? STOP_BITS_1 : STOP_BITS_0);
- break;
-
- case 0:
- set_data_frame(1, data_bits, PARITY_EVEN, stop_bits ? STOP_BITS_1 : STOP_BITS_0);
- break;
-
- case 1:
- set_data_frame(1, data_bits, PARITY_ODD, stop_bits ? STOP_BITS_1 : STOP_BITS_0);
- break;
- }
-}
-
-// called on a master clear
-void dc7085_channel::clear()
-{
- transmit_register_reset();
- set_baud_rate(0);
- rx_enabled = 0;
- tx_enabled = 0;
- tx_ready = 1;
-}
-
-void dc7085_channel::set_tx_enable(bool bEnabled)
-{
- LOGMASKED(LOG_TX, "ch %d set_tx_enable %s\n", m_ch, bEnabled ? "true" : "false");
- tx_enabled = bEnabled ? 1 : 0;
-}
-
-void dc7085_channel::set_rx_enable(bool bEnabled)
-{
- rx_enabled = bEnabled ? 1 : 0;
-}
-
-void dc7085_channel::write_TX(uint8_t data)
-{
- tx_data = data;
-
- if (!tx_ready)
- {
- LOGMASKED(LOG_TX, "Write %02x to TX when TX not ready!\n", data);
- }
-
- LOGMASKED(LOG_TX, "ch %d Tx [%02x] (%d baud)\n", m_ch, data, baud_rate);
-
- tx_ready = 0;
-
- // send tx_data
- transmit_register_setup(tx_data);
-
- m_base->recalc_irqs();
-}
diff --git a/src/devices/machine/dc7085.h b/src/devices/machine/dc7085.h
deleted file mode 100644
index 282683ac2df..00000000000
--- a/src/devices/machine/dc7085.h
+++ /dev/null
@@ -1,186 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-
-#ifndef MAME_MACHINE_DC7085_H
-#define MAME_MACHINE_DC7085_H
-
-#pragma once
-
-#include "diserial.h"
-
-#define DC7085_RX_FIFO_SIZE (64)
-
-// forward declaration
-class dc7085_device;
-
-class dc7085_channel : public device_t, public device_serial_interface
-{
-public:
- dc7085_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
- // device_serial overrides
- virtual void rcv_complete() override; // Rx completed receiving byte
- virtual void tra_complete() override; // Tx completed sending byte
- virtual void tra_callback() override; // Tx send bit
-
- void set_baud_rate(int baud);
- void set_format(int data_bits, int parity, int stop_bits);
- void clear();
- void set_tx_enable(bool bEnabled);
- void set_rx_enable(bool bEnabled);
- void write_TX(uint8_t data);
- bool is_tx_ready()
- {
- if (!tx_enabled)
- {
- return false;
- }
-
- return tx_ready ? true : false;
- }
-
-private:
- /* Receiver */
- u8 rx_enabled;
-
- /* Shared */
- int baud_rate;
- int m_ch;
-
- /* Transmitter */
- u8 tx_enabled;
- u8 tx_data;
- u8 tx_ready;
-
- dc7085_device *m_base;
-};
-
-class dc7085_device : public device_t
-{
- friend class dc7085_channel;
-
-public:
- required_device<dc7085_channel> m_chan0, m_chan1, m_chan2, m_chan3;
-
- dc7085_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- void map(address_map &map);
-
- auto int_cb() { return m_int_cb.bind(); }
- auto ch0_tx_cb() { return write_0_tx.bind(); }
- auto ch1_tx_cb() { return write_1_tx.bind(); }
- auto ch2_tx_cb() { return write_2_tx.bind(); }
- auto ch3_tx_cb() { return write_3_tx.bind(); }
-
-protected:
- // standard device_interface overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_add_mconfig(machine_config &config) override;
-
- void rx_fifo_push(uint16_t data, uint16_t errors);
- void recalc_irqs();
-
- devcb_write_line m_int_cb;
- devcb_write_line write_0_tx, write_1_tx, write_2_tx, write_3_tx;
-
- u16 m_status;
-
- u16 status_r();
- u16 rxbuffer_r();
- u16 txparams_r();
- u16 modem_status_r();
- void control_w(u16 data);
- void lineparams_w(u16 data);
- void txparams_w(u16 data);
- void txdata_w(u16 data);
-
- int get_ch(dc7085_channel *ch)
- {
- if (ch == m_chan0)
- {
- return 0;
- }
- else if (ch == m_chan1)
- {
- return 1;
- }
- else if (ch == m_chan2)
- {
- return 2;
- }
-
- return 3;
- }
-
-private:
- u16 rx_fifo[DC7085_RX_FIFO_SIZE];
- int rx_fifo_read_ptr;
- int rx_fifo_write_ptr;
- int rx_fifo_num;
-
- enum control_status_mask : u16
- {
- CTRL_TRDY = 0x8000,
- CTRL_TX_IRQ_ENABLE = 0x4000,
- CTRL_LINE_MASK = 0x0300,
- CTRL_RX_DONE = 0x0080,
- CTRL_RX_IRQ_ENABLE = 0x0040,
- CTRL_MASTER_SCAN = 0x0020,
- CTRL_MASTER_CLEAR = 0x0010,
- CTRL_LOOPBACK = 0x0008
- };
-
- enum rx_buffer_mask : u16
- {
- RXMASK_DATA_VALID = 0x8000,
- RXMASK_OVERRUN_ERR = 0x4000,
- RXMASK_FRAMING_ERR = 0x2000,
- RXMASK_PARITY_ERR = 0x1000,
- RXMASK_LINE_MASK = 0x0300,
- RXMASK_DATA_MASK = 0x00ff
- };
-
- enum line_param_mask : u16
- {
- LPARAM_RX_ENABLE = 0x1000,
- LPARAM_BAUD_MASK = 0x0f00,
- LPARAM_ODD_PARITY = 0x0080,
- LPARAM_PARITY_ENB = 0x0040,
- LPARAM_STOP_BITS = 0x0020,
- LPARAM_CHARLEN_MASK = 0x0018,
- LPARAM_LINE_MASK = 0x0003
- };
-
- enum tx_control_mask : u16
- {
- TXCTRL_DTR2 = 0x0400,
- TXCTRL_LINE3_ENB = 0x0008,
- TXCTRL_LINE2_ENB = 0x0004,
- TXCTRL_LINE1_ENB = 0x0002,
- TXCTRL_LINE0_ENB = 0x0001
- };
-
- enum modem_status_mask : u16
- {
- MSTAT_DSR2 = 0x0400
- };
-
- enum tx_data_mask : u16
- {
- TXDATA_LINE3_BREAK = 0x0800,
- TXDATA_LINE2_BREAK = 0x0400,
- TXDATA_LINE1_BREAK = 0x0200,
- TXDATA_LINE0_BREAK = 0x0100,
- TXDATA_DATA_MASK = 0x00ff
- };
-};
-
-DECLARE_DEVICE_TYPE(DC7085, dc7085_device)
-DECLARE_DEVICE_TYPE(DC7085_CHANNEL, dc7085_channel)
-
-#endif // MAME_MACHINE_DC7085_H
diff --git a/src/devices/machine/diablo_hd.cpp b/src/devices/machine/diablo_hd.cpp
index 938173a945b..2ce1707058c 100644
--- a/src/devices/machine/diablo_hd.cpp
+++ b/src/devices/machine/diablo_hd.cpp
@@ -102,7 +102,6 @@ diablo_hd_device::diablo_hd_device(const machine_config &mconfig, const char *ta
m_sector_callback(nullptr),
m_timer(nullptr),
m_image(nullptr),
- m_handle(nullptr),
m_disk(nullptr)
{
memset(m_description, 0x00, sizeof(m_description));
@@ -312,7 +311,7 @@ void diablo_hd_device::read_sector()
// allocate a buffer for this page
m_cache[m_page] = std::make_unique<uint8_t[]>(sizeof(diablo_sector_t));
// and read the page from the hard_disk image
- if (hard_disk_read(m_disk, m_page, m_cache[m_page].get())) {
+ if (m_disk->read(m_page, m_cache[m_page].get())) {
LOG_DRIVE(2,"[DHD%u] CHS:%03d/%d/%02d => page:%d loaded\n", m_unit, m_cylinder, m_head, m_sector, m_page);
} else {
LOG_DRIVE(0,"[DHD%u] CHS:%03d/%d/%02d => page:%d read failed\n", m_unit, m_cylinder, m_head, m_sector, m_page);
@@ -770,7 +769,7 @@ void diablo_hd_device::squeeze_sector()
m_bits[m_page].reset();
if (m_disk) {
- if (!hard_disk_write(m_disk, m_page, m_cache[m_page].get())) {
+ if (!m_disk->write(m_page, m_cache[m_page].get())) {
LOG_DRIVE(0,"[DHD%u] write failed for page #%d\n", m_unit, m_page);
}
} else {
@@ -1317,7 +1316,7 @@ void diablo_hd_device::device_start()
m_packs = 1; // FIXME: get from configuration?
m_unit = strstr(m_image->tag(), "diablo0") ? 0 : 1;
- m_timer = timer_alloc(1, nullptr);
+ m_timer = timer_alloc(FUNC(diablo_hd_device::sector_mark_tick), this);
}
void diablo_hd_device::device_reset()
@@ -1328,8 +1327,7 @@ void diablo_hd_device::device_reset()
m_cache[page] = nullptr;
// free previous bits cache
m_bits.reset();
- m_handle = m_image->get_chd_file();
- m_diablo31 = true; // FIXME: get from m_handle meta data?
+ m_diablo31 = true; // FIXME: get from disk meta data?
m_disk = m_image->get_hard_disk_file();
if (m_diablo31) {
snprintf(m_description, sizeof(m_description), "DIABLO31");
@@ -1350,7 +1348,6 @@ void diablo_hd_device::device_reset()
m_cylinders = 2 * DIABLO_CYLINDERS;
m_pages = 2 * DIABLO_PAGES;
}
- LOG_DRIVE(0,"[DHD%u] m_handle : %p\n", m_unit, reinterpret_cast<void const *>(m_handle));
LOG_DRIVE(0,"[DHD%u] m_disk : %p\n", m_unit, reinterpret_cast<void const *>(m_disk));
LOG_DRIVE(0,"[DHD%u] rotation time : %.0fns\n", m_unit, m_rotation_time.as_double() * ATTOSECONDS_PER_NANOSECOND);
LOG_DRIVE(0,"[DHD%u] sector time : %.0fns\n", m_unit, m_sector_time.as_double() * ATTOSECONDS_PER_NANOSECOND);
@@ -1385,11 +1382,11 @@ void diablo_hd_device::device_reset()
m_rdfirst = -1;
m_rdlast = -1;
- if (!m_handle)
+ if (!m_image)
return;
// for units with a CHD assigned to them start the timer
m_bits = std::make_unique<std::unique_ptr<uint32_t[]>[]>(m_pages);
- timer_set(m_sector_time - m_sector_mark_0_time, 1, 0);
+ m_timer->adjust(m_sector_time - m_sector_mark_0_time);
read_sector();
}
@@ -1404,9 +1401,9 @@ void diablo_hd_device::device_reset()
* @param id timer id
* @param arg argument supplied to timer_insert (unused)
*/
-void diablo_hd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(diablo_hd_device::sector_mark_tick)
{
- LOG_DRIVE(9,"[DHD%u] TIMER id=%d param=%d ptr=%p @%.0fns\n", m_unit, id, param, ptr, timer.elapsed().as_double() * ATTOSECONDS_PER_NANOSECOND);
+ LOG_DRIVE(9, "[DHD%u] TIMER param=%d @%.0fns\n", m_unit, param, m_timer->elapsed().as_double() * ATTOSECONDS_PER_NANOSECOND);
if (!m_disk)
return;
@@ -1415,20 +1412,20 @@ void diablo_hd_device::device_timer(emu_timer &timer, device_timer_id id, int pa
// assert sector mark
sector_mark_0();
// next sector timer event is in the middle between sector_mark going 0 and back to 1
- timer.adjust(m_sector_mark_0_time, 1);
+ m_timer->adjust(m_sector_mark_0_time, 1);
break;
case 1:
/* call the sector_callback, if any */
if (m_sector_callback)
(void)(*m_sector_callback)(m_sector_callback_cookie, m_unit);
// next sector timer event is deassert of sector_mark_0 (set to 1)
- timer.adjust(m_sector_mark_1_time, 2);
+ m_timer->adjust(m_sector_mark_1_time, 2);
break;
case 2:
// deassert sector mark
sector_mark_1();
// next sector timer event is sector_mark_0 for next sector
- timer.adjust(m_sector_time - m_sector_mark_0_time, 0);
+ m_timer->adjust(m_sector_time - m_sector_mark_0_time, 0);
break;
}
}
diff --git a/src/devices/machine/diablo_hd.h b/src/devices/machine/diablo_hd.h
index ea96d2c4c70..43524706967 100644
--- a/src/devices/machine/diablo_hd.h
+++ b/src/devices/machine/diablo_hd.h
@@ -67,9 +67,10 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_add_mconfig(machine_config &config) override;
+ TIMER_CALLBACK_MEMBER(sector_mark_tick);
+
private:
template <typename Format, typename... Params> void logprintf(int level, Format &&fmt, Params &&... args);
@@ -110,7 +111,6 @@ private:
void (*m_sector_callback)(void*,int); //!< callback to call at the start of each sector
emu_timer* m_timer; //!< sector timer
diablo_image_device* m_image; //!< diablo_image_device interfacing the CHD
- chd_file* m_handle; //!< underlying CHD handle
hard_disk_file* m_disk; //!< underlying hard disk file
//! translate C/H/S to a page and read the sector
diff --git a/src/devices/machine/dimm_spd.cpp b/src/devices/machine/dimm_spd.cpp
new file mode 100644
index 00000000000..b6736e71ade
--- /dev/null
+++ b/src/devices/machine/dimm_spd.cpp
@@ -0,0 +1,328 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*
+ DIMM serial presence detect (SPD) readback device
+ by R. Belmont
+
+ Each DIMM contains a small EEPROM with information about the capacity and
+ timings of the module. The EEPROM speaks a version of I2C called SMBus.
+
+ This does not attempt to be a generalized I2C/SMBus solution.
+*/
+
+
+#include "emu.h"
+#include "dimm_spd.h"
+
+#define LOG_DATAOUT (1U << 1)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(DIMM_SPD, dimm_spd_device, "dimm_spd", "DIMM Serial Presence Detect")
+
+constexpr int STATE_IDLE = 0;
+constexpr int STATE_GET_ADDRESS = 1;
+constexpr int STATE_GET_SUBADDRESS = 2;
+constexpr int STATE_READ_DATA = 3;
+constexpr int STATE_WAIT_ACK = 4;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// dimm_spd_device - constructor
+//-------------------------------------------------
+
+dimm_spd_device::dimm_spd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, DIMM_SPD, tag, owner, clock),
+ write_sda(*this)
+{
+ m_data_offset = 0;
+ m_sda = m_scl = 1;
+ m_state = m_state_next = STATE_IDLE;
+ m_last_address = 0;
+ m_just_acked = false;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void dimm_spd_device::device_start()
+{
+ std::fill(std::begin(m_data), std::end(m_data), 0);
+
+ m_data[0] = 128; // # of bytes in EEPROM
+ m_data[1] = 8; // log2 of EEPROM size
+ m_data[2] = 4; // 4 is SDRAM, 7 is DDR SDRAM, 8 is DDR2, 11 is DDR3, 12 is DDR4
+ m_data[3] = 12; // # of rows
+ m_data[4] = 8; // # of columns
+ m_data[5] = 1; // # of banks (12/8/1 = 32 MiB)
+ m_data[6] = 64; // data bus width low byte
+ m_data[7] = 0; // data bus width high byte
+ m_data[11] = 0; // non-ECC (1=parity, 2=ECC)
+ m_data[62] = 0x12; // SPD version 1.2
+
+ m_latch = m_bit = 0;
+ m_state = STATE_IDLE;
+ m_sda = m_scl = 1;
+ m_last_address = 0;
+ m_data_offset = 0;
+
+ save_item(NAME(m_latch));
+ save_item(NAME(m_bit));
+ save_item(NAME(m_state));
+ save_item(NAME(m_state_next));
+ save_item(NAME(m_data_offset));
+ save_item(NAME(m_just_acked));
+
+ write_sda(1);
+}
+
+void dimm_spd_device::set_dimm_size(dimm_size_t size)
+{
+ m_size = size;
+
+ switch (size)
+ {
+ case SIZE_4_MIB:
+ m_data[3] = 12; // # of rows
+ m_data[4] = 5; // # of columns
+ m_data[5] = 1; // # of banks
+ break;
+
+ case SIZE_8_MIB:
+ m_data[3] = 12;
+ m_data[4] = 6;
+ m_data[5] = 1;
+ break;
+
+ case SIZE_16_MIB:
+ m_data[3] = 12;
+ m_data[4] = 7;
+ m_data[5] = 1;
+ break;
+
+ case SIZE_32_MIB:
+ m_data[3] = 12;
+ m_data[4] = 8;
+ m_data[5] = 1;
+ break;
+
+ case SIZE_64_MIB:
+ m_data[3] = 12;
+ m_data[4] = 9;
+ m_data[5] = 1;
+ break;
+
+ case SIZE_128_MIB:
+ m_data[3] = 12;
+ m_data[4] = 10;
+ m_data[5] = 1;
+ break;
+
+ case SIZE_256_MIB:
+ m_data[3] = 12;
+ m_data[4] = 10;
+ m_data[5] = 2;
+ break;
+
+ case SIZE_SLOT_EMPTY:
+ break;
+ }
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void dimm_spd_device::device_reset()
+{
+}
+
+void dimm_spd_device::sda_write(int state)
+{
+ if (m_size == SIZE_SLOT_EMPTY)
+ {
+ return;
+ }
+
+ if (m_sda != state)
+ {
+ m_sda = state & 1;
+
+ if (m_scl)
+ {
+ if (m_sda)
+ {
+ LOG("%s: stop\n", tag());
+ m_state = STATE_IDLE;
+ m_last_address = 0;
+ m_just_acked = false;
+ m_data_offset = 0;
+ }
+ else
+ {
+ LOG("%s: start\n", tag());
+ m_state = STATE_GET_ADDRESS;
+ m_bit = 0;
+ m_latch = 0;
+ m_just_acked = false;
+ }
+ }
+ }
+}
+
+void dimm_spd_device::scl_write(int state)
+{
+ if (m_size == SIZE_SLOT_EMPTY)
+ {
+ return;
+ }
+
+ if (m_scl != state)
+ {
+ m_scl = state & 1;
+
+ switch (m_state)
+ {
+ case STATE_IDLE:
+ // just ignore everything until a START
+ break;
+
+ case STATE_GET_ADDRESS:
+ case STATE_GET_SUBADDRESS:
+ if (m_bit < 8)
+ {
+ if (m_scl)
+ {
+ m_latch <<= 1;
+ m_latch |= m_sda;
+ m_bit++;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ m_bit++;
+ }
+ else
+ {
+ if (m_bit == 8)
+ {
+ if (m_state == STATE_GET_ADDRESS)
+ {
+ LOG("%s: Got address %02x (ours is %02x r/w %d)\n", tag(), m_latch >> 1, m_address, m_latch & 1);
+ // check if reading
+ if (m_latch & 1)
+ {
+ if ((m_latch >> 1) == m_address)
+ {
+ LOG("%s: address matches, ACKing\n", tag());
+ write_sda(0);
+ m_bit = 0;
+ m_latch = 0;
+ m_state_next = STATE_READ_DATA;
+ m_state = STATE_WAIT_ACK;
+ }
+ else
+ {
+ LOG("%s: address doesn't match, ignoring\n", tag());
+ m_state = STATE_IDLE;
+ write_sda(1);
+ }
+ }
+ else
+ {
+ LOGMASKED(LOG_DATAOUT, "%s: write: getting subaddress\n", tag());
+ m_last_address = m_latch >> 1;
+ write_sda(0);
+ m_bit = 0;
+ m_latch = 0;
+ m_state_next = STATE_GET_SUBADDRESS;
+ m_state = STATE_WAIT_ACK;
+ }
+ }
+ else if (m_state == STATE_GET_SUBADDRESS)
+ {
+ LOGMASKED(LOG_DATAOUT, "%s: subaddress is %02x\n", tag(), m_latch);
+ m_data_offset = m_latch;
+ write_sda(0);
+ m_bit = 0;
+ m_latch = 0;
+ m_state_next = STATE_IDLE; // is this correct?
+ m_state = STATE_WAIT_ACK;
+ }
+ }
+ }
+ }
+ break;
+
+ case STATE_WAIT_ACK:
+ if (!m_scl)
+ {
+ m_state = m_state_next;
+ write_sda(1);
+ }
+ break;
+
+ case STATE_READ_DATA:
+ if (m_bit < 8)
+ {
+ if (!m_scl)
+ {
+ m_bit++;
+ write_sda(1);
+ }
+ else
+ {
+ if (m_bit == 0)
+ {
+ m_latch = m_data[m_data_offset++];
+ m_data_offset &= 0xff;
+ LOGMASKED(LOG_DATAOUT, "%s: outputting byte %02x\n", tag(), m_latch);
+ }
+
+ write_sda(BIT(m_latch, 7));
+ m_latch <<= 1;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ // did the master ACK or NACK?
+ if (m_sda)
+ {
+ LOGMASKED(LOG_DATAOUT, "%s: master NACK\n", tag());
+ m_state = STATE_IDLE;
+ write_sda(1);
+ }
+ else
+ {
+ LOGMASKED(LOG_DATAOUT, "%s: master ACK\n", tag());
+ m_just_acked = true;
+ }
+ }
+ else
+ {
+ write_sda(1);
+ if (m_just_acked)
+ {
+ m_bit = 0;
+ m_just_acked = false;
+ }
+ }
+ }
+ break;
+ }
+
+ }
+}
diff --git a/src/devices/machine/dimm_spd.h b/src/devices/machine/dimm_spd.h
new file mode 100644
index 00000000000..7fc42844bd5
--- /dev/null
+++ b/src/devices/machine/dimm_spd.h
@@ -0,0 +1,70 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+#ifndef MAME_MACHINE_DIMM_SPD_H
+#define MAME_MACHINE_DIMM_SPD_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> dimm_spd_device
+
+class dimm_spd_device : public device_t
+{
+public:
+ // construction/destruction
+ dimm_spd_device(const machine_config &mconfig, const char *tag, device_t *owner)
+ : dimm_spd_device(mconfig, tag, owner, (uint32_t)0)
+ {
+ }
+
+ dimm_spd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // inline configuration helpers
+ void set_address(u16 address) { m_address = address; }
+
+ auto sda_callback() { return write_sda.bind(); }
+
+ void sda_write(int state);
+ void scl_write(int state);
+
+ devcb_write_line write_sda;
+
+ typedef enum
+ {
+ SIZE_SLOT_EMPTY = 0,
+ SIZE_4_MIB,
+ SIZE_8_MIB,
+ SIZE_16_MIB,
+ SIZE_32_MIB,
+ SIZE_64_MIB,
+ SIZE_128_MIB,
+ SIZE_256_MIB
+ } dimm_size_t;
+
+ void set_dimm_size(dimm_size_t size);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ u8 m_data[256];
+ u8 m_latch;
+ u8 m_bit;
+ u16 m_address;
+ u16 m_last_address;
+ int m_sda, m_scl;
+ u32 m_state, m_state_next;
+ u16 m_data_offset;
+ bool m_just_acked;
+ dimm_size_t m_size;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(DIMM_SPD, dimm_spd_device)
+
+#endif // MAME_MACHINE_DIMM_SPD_H
diff --git a/src/devices/machine/dl11.cpp b/src/devices/machine/dl11.cpp
new file mode 100644
index 00000000000..ef81cf5911e
--- /dev/null
+++ b/src/devices/machine/dl11.cpp
@@ -0,0 +1,283 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/***************************************************************************
+
+ DEC DL11-type SLU (serial line unit).
+
+ Frame format is not software-configurable; hardcoded to 8N1 for now.
+
+ http://www.ibiblio.org/pub/academic/computer-science/history/pdp-11/hardware/micronotes/numerical/micronote33.txt
+
+***************************************************************************/
+
+#include "emu.h"
+#include "dl11.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(DL11, dl11_device, "dl11", "DEC DL11-type SLU")
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+enum
+{
+ DLRCSR = 0,
+ DLRBUF,
+ DLTCSR,
+ DLTBUF
+};
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// dl11_device - constructor
+//-------------------------------------------------
+
+dl11_device::dl11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, DL11, tag, owner, clock)
+ , device_serial_interface(mconfig, *this)
+ , device_z80daisy_interface(mconfig, *this)
+ , m_write_txd(*this)
+ , m_write_rxrdy(*this)
+ , m_write_txrdy(*this)
+ , m_rxc(0)
+ , m_txc(0)
+ , m_rxvec(0)
+ , m_txvec(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void dl11_device::device_start()
+{
+ // save state
+ save_item(NAME(m_rcsr));
+ save_item(NAME(m_rbuf));
+ save_item(NAME(m_tcsr));
+ save_item(NAME(m_tbuf));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void dl11_device::device_reset()
+{
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
+
+ // create the timers
+ if (m_rxc > 0)
+ set_rcv_rate(m_rxc);
+
+ if (m_txc > 0)
+ set_tra_rate(m_txc);
+
+ m_rcsr = m_rbuf = m_tbuf = 0;
+ m_tcsr = CSR_DONE;
+ m_rxrdy = m_txrdy = CLEAR_LINE;
+
+ m_write_txd(1);
+ m_write_rxrdy(m_rxrdy);
+ m_write_txrdy(m_txrdy);
+}
+
+int dl11_device::z80daisy_irq_state()
+{
+ if (m_rxrdy == ASSERT_LINE || m_txrdy == ASSERT_LINE)
+ return Z80_DAISY_INT;
+ else
+ return 0;
+}
+
+int dl11_device::z80daisy_irq_ack()
+{
+ int vec = -1;
+
+ if (m_rxrdy == ASSERT_LINE)
+ {
+ m_rxrdy = CLEAR_LINE;
+ vec = m_rxvec;
+ }
+ else if (m_txrdy == ASSERT_LINE)
+ {
+ m_txrdy = CLEAR_LINE;
+ vec = m_txvec;
+ }
+
+ return vec;
+}
+
+void dl11_device::z80daisy_irq_reti()
+{
+}
+
+
+//-------------------------------------------------
+// tra_callback -
+//-------------------------------------------------
+
+void dl11_device::tra_callback()
+{
+ if (m_tcsr & DLTCSR_XBRK)
+ {
+ m_write_txd(0);
+ }
+ else if (!is_transmit_register_empty())
+ {
+ m_write_txd(transmit_register_get_data_bit());
+ }
+}
+
+
+//-------------------------------------------------
+// tra_complete -
+//-------------------------------------------------
+
+void dl11_device::tra_complete()
+{
+ m_tcsr |= CSR_DONE;
+ raise_virq(m_write_txrdy, m_tcsr, CSR_IE, m_txrdy);
+}
+
+
+//-------------------------------------------------
+// rcv_complete -
+//-------------------------------------------------
+
+void dl11_device::rcv_complete()
+{
+ receive_register_extract();
+ if (is_receive_framing_error())
+ {
+ m_rbuf = DLRBUF_ERR | DLRBUF_RBRK;
+ }
+ else
+ {
+ m_rbuf = get_received_char();
+ }
+ if (is_receive_parity_error())
+ {
+ m_rbuf |= DLRBUF_ERR | DLRBUF_PERR;
+ }
+ if (m_rcsr & CSR_DONE)
+ {
+ m_rbuf |= DLRBUF_ERR | DLRBUF_OVR;
+ }
+ else
+ {
+ m_rcsr |= CSR_DONE;
+ }
+ raise_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
+}
+
+
+//-------------------------------------------------
+// read - register read
+//-------------------------------------------------
+
+uint16_t dl11_device::read(offs_t offset)
+{
+ uint16_t data = 0;
+
+ switch (offset & 3)
+ {
+ case DLRCSR:
+ data = m_rcsr & DLRCSR_RD;
+ break;
+
+ case DLRBUF:
+ data = m_rbuf;
+ m_rcsr &= ~CSR_DONE;
+ clear_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
+ break;
+
+ case DLTCSR:
+ data = m_tcsr & DLTCSR_RD;
+ break;
+
+ case DLTBUF:
+ data = m_tbuf;
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write - register write
+//-------------------------------------------------
+
+void dl11_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ switch (offset & 3)
+ {
+ case DLRCSR:
+ if ((data & CSR_IE) == 0)
+ {
+ clear_virq(m_write_rxrdy, 1, 1, m_rxrdy);
+ }
+ else if ((m_rcsr & (CSR_DONE + CSR_IE)) == CSR_DONE)
+ {
+ raise_virq(m_write_rxrdy, 1, 1, m_rxrdy);
+ }
+ m_rcsr = ((m_rcsr & ~DLRCSR_WR) | (data & DLRCSR_WR));
+ break;
+
+ case DLRBUF:
+ break;
+
+ case DLTCSR:
+ if ((data & CSR_IE) == 0)
+ {
+ clear_virq(m_write_txrdy, 1, 1, m_txrdy);
+ }
+ else if ((m_tcsr & (CSR_DONE + CSR_IE)) == CSR_DONE)
+ {
+ raise_virq(m_write_txrdy, 1, 1, m_txrdy);
+ }
+ m_tcsr = ((m_tcsr & ~DLTCSR_WR) | (data & DLTCSR_WR));
+ break;
+
+ case DLTBUF:
+ m_tbuf = data;
+ m_tcsr &= ~CSR_DONE;
+ clear_virq(m_write_txrdy, m_tcsr, CSR_IE, m_txrdy);
+ transmit_register_setup(data & 0xff);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// rxrdy_r - receiver ready
+//-------------------------------------------------
+
+int dl11_device::rxrdy_r()
+{
+ return ((m_rcsr & (CSR_DONE | CSR_IE)) == (CSR_DONE | CSR_IE)) ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+//-------------------------------------------------
+// txrdy_r - transmitter empty
+//-------------------------------------------------
+
+int dl11_device::txrdy_r()
+{
+ return ((m_tcsr & (CSR_DONE | CSR_IE)) == (CSR_DONE | CSR_IE)) ? ASSERT_LINE : CLEAR_LINE;
+}
diff --git a/src/devices/machine/dl11.h b/src/devices/machine/dl11.h
new file mode 100644
index 00000000000..d3120f5e6af
--- /dev/null
+++ b/src/devices/machine/dl11.h
@@ -0,0 +1,103 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/***************************************************************************
+
+ DEC DL11-type SLU (serial line unit)
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_DL11_H
+#define MAME_MACHINE_DL11_H
+
+#pragma once
+
+#include "machine/pdp11.h"
+#include "machine/z80daisy.h"
+
+#include "diserial.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> dl11_device
+
+class dl11_device : public device_t,
+ public device_serial_interface,
+ public device_z80daisy_interface
+{
+public:
+ // construction/destruction
+ dl11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void set_rxc(int clock) { m_rxc = clock; }
+ void set_txc(int clock) { m_txc = clock; }
+ void set_rxvec(int vec) { m_rxvec = vec; }
+ void set_txvec(int vec) { m_txvec = vec; }
+
+ auto txd_wr_callback() { return m_write_txd.bind(); }
+ auto txrdy_wr_callback() { return m_write_txrdy.bind(); }
+ auto rxrdy_wr_callback() { return m_write_rxrdy.bind(); }
+
+ uint16_t read(offs_t offset);
+ void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+
+ int rxrdy_r();
+ int txrdy_r();
+
+ void rx_w(int state) { device_serial_interface::rx_w(state); }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_serial_interface overrides
+ virtual void tra_callback() override;
+ virtual void tra_complete() override;
+ virtual void rcv_complete() override;
+
+ // device_z80daisy_interface overrides
+ virtual int z80daisy_irq_state() override;
+ virtual int z80daisy_irq_ack() override;
+ virtual void z80daisy_irq_reti() override;
+
+private:
+ /* registers */
+
+ static constexpr uint16_t DLRCSR_RD = CSR_DONE | CSR_IE;
+ static constexpr uint16_t DLRCSR_WR = CSR_IE;
+
+ static constexpr uint16_t DLRBUF_ERR = 0100000;
+ static constexpr uint16_t DLRBUF_OVR = 0040000;
+ static constexpr uint16_t DLRBUF_RBRK = 0020000;
+ static constexpr uint16_t DLRBUF_PERR = 0020000;
+
+ static constexpr uint16_t DLTCSR_XBRK = 0000001;
+ static constexpr uint16_t DLTCSR_RD = CSR_DONE | CSR_IE | DLTCSR_XBRK;
+ static constexpr uint16_t DLTCSR_WR = CSR_IE | DLTCSR_XBRK;
+
+ devcb_write_line m_write_txd;
+ devcb_write_line m_write_rxrdy;
+ devcb_write_line m_write_txrdy;
+
+ line_state m_rxrdy;
+ line_state m_txrdy;
+
+ int m_rxc;
+ int m_txc;
+ int m_rxvec;
+ int m_txvec;
+
+ uint16_t m_rcsr;
+ uint16_t m_rbuf;
+ uint16_t m_tcsr;
+ uint16_t m_tbuf;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(DL11, dl11_device)
+
+#endif
diff --git a/src/devices/machine/dmac.cpp b/src/devices/machine/dmac.cpp
index 0705f28c060..fd939c981c4 100644
--- a/src/devices/machine/dmac.cpp
+++ b/src/devices/machine/dmac.cpp
@@ -40,9 +40,9 @@ amiga_dmac_device::amiga_dmac_device(const machine_config &mconfig, const char *
m_cfgout_handler(*this),
m_int_handler(*this),
m_xdack_handler(*this),
- m_scsi_read_handler(*this),
+ m_scsi_read_handler(*this, 0),
m_scsi_write_handler(*this),
- m_io_read_handler(*this),
+ m_io_read_handler(*this, 0),
m_io_write_handler(*this),
m_space(nullptr),
m_rom(nullptr),
@@ -64,14 +64,6 @@ amiga_dmac_device::amiga_dmac_device(const machine_config &mconfig, const char *
void amiga_dmac_device::device_start()
{
- // resolve callbacks
- m_cfgout_handler.resolve_safe();
- m_int_handler.resolve_safe();
- m_xdack_handler.resolve_safe();
- m_scsi_read_handler.resolve_safe(0);
- m_scsi_write_handler.resolve_safe();
- m_io_read_handler.resolve_safe(0);
- m_io_write_handler.resolve_safe();
}
//-------------------------------------------------
@@ -333,7 +325,7 @@ void amiga_dmac_device::register_write(offs_t offset, uint16_t data, uint16_t me
}
// this signal tells us to expose our autoconfig values
-WRITE_LINE_MEMBER( amiga_dmac_device::configin_w )
+void amiga_dmac_device::configin_w(int state)
{
LOG("%s('%s'): configin_w (%d)\n", shortname(), basetag(), state);
@@ -388,7 +380,7 @@ WRITE_LINE_MEMBER( amiga_dmac_device::configin_w )
}
// this sets the ram size depending on the line voltage
-WRITE_LINE_MEMBER( amiga_dmac_device::ramsz_w )
+void amiga_dmac_device::ramsz_w(int state)
{
LOG("%s('%s'): ramsz_w (%d)\n", shortname(), basetag(), state);
@@ -402,7 +394,7 @@ WRITE_LINE_MEMBER( amiga_dmac_device::ramsz_w )
}
// reset the device
-WRITE_LINE_MEMBER( amiga_dmac_device::rst_w )
+void amiga_dmac_device::rst_w(int state)
{
LOG("%s('%s'): rst_w (%d)\n", shortname(), basetag(), state);
@@ -413,7 +405,7 @@ WRITE_LINE_MEMBER( amiga_dmac_device::rst_w )
}
// external interrupt
-WRITE_LINE_MEMBER( amiga_dmac_device::intx_w )
+void amiga_dmac_device::intx_w(int state)
{
LOG("%s('%s'): intx_w (%d)\n", shortname(), basetag(), state);
@@ -426,7 +418,7 @@ WRITE_LINE_MEMBER( amiga_dmac_device::intx_w )
}
// data request
-WRITE_LINE_MEMBER( amiga_dmac_device::xdreq_w )
+void amiga_dmac_device::xdreq_w(int state)
{
LOG("%s('%s'): xdreq_w (%d)\n", shortname(), basetag(), state);
diff --git a/src/devices/machine/dmac.h b/src/devices/machine/dmac.h
index 47c5f9f93d3..e6af4efa049 100644
--- a/src/devices/machine/dmac.h
+++ b/src/devices/machine/dmac.h
@@ -40,11 +40,11 @@ public:
void set_ram(uint8_t *ram) { m_ram = ram; }
// input lines
- DECLARE_WRITE_LINE_MEMBER( configin_w );
- DECLARE_WRITE_LINE_MEMBER( ramsz_w );
- DECLARE_WRITE_LINE_MEMBER( rst_w );
- DECLARE_WRITE_LINE_MEMBER( intx_w );
- DECLARE_WRITE_LINE_MEMBER( xdreq_w );
+ void configin_w(int state);
+ void ramsz_w(int state);
+ void rst_w(int state);
+ void intx_w(int state);
+ void xdreq_w(int state);
// dmac register access
uint16_t register_read(address_space &space, offs_t offset, uint16_t mem_mask = ~0);
diff --git a/src/devices/machine/dp8390.cpp b/src/devices/machine/dp8390.cpp
index 75217661215..2ed12551e78 100644
--- a/src/devices/machine/dp8390.cpp
+++ b/src/devices/machine/dp8390.cpp
@@ -19,13 +19,13 @@ rtl8019a_device::rtl8019a_device(const machine_config &mconfig, const char *tag,
{
}
-dp8390_device::dp8390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, TYPE variant, float bandwidth)
+dp8390_device::dp8390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, TYPE variant, u32 bandwidth)
: device_t(mconfig, type, tag, owner, clock)
, device_network_interface(mconfig, *this, bandwidth)
, m_variant(variant)
, m_irq_cb(*this)
, m_breq_cb(*this)
- , m_mem_read_cb(*this)
+ , m_mem_read_cb(*this, 0)
, m_mem_write_cb(*this)
, m_reset(0)
, m_rdma_active(0)
@@ -33,10 +33,6 @@ dp8390_device::dp8390_device(const machine_config &mconfig, device_type type, co
}
void dp8390_device::device_start() {
- m_irq_cb.resolve_safe();
- m_breq_cb.resolve_safe();
- m_mem_read_cb.resolve_safe(0);
- m_mem_write_cb.resolve_safe();
}
void dp8390_device::stop() {
@@ -171,7 +167,7 @@ void dp8390_device::recv_cb(uint8_t *buf, int len) {
if(!LOOPBACK) recv(buf, len);
}
-WRITE_LINE_MEMBER(dp8390_device::dp8390_reset) {
+void dp8390_device::dp8390_reset(int state) {
if(!state) device_reset();
}
@@ -426,7 +422,7 @@ void dp8390_device::cs_write(offs_t offset, uint8_t data) {
case 0x45:
case 0x46:
m_regs.par[(offset & 0x7)-1] = data;
- set_mac((const char *)m_regs.par);
+ set_mac(m_regs.par);
break;
case 0x47:
m_regs.curr = data;
diff --git a/src/devices/machine/dp8390.h b/src/devices/machine/dp8390.h
index 64bc6436733..0f484c5e45f 100644
--- a/src/devices/machine/dp8390.h
+++ b/src/devices/machine/dp8390.h
@@ -5,6 +5,8 @@
#pragma once
+#include "dinetwork.h"
+
// device stuff
@@ -20,7 +22,7 @@ public:
void cs_write(offs_t offset, uint8_t data);
uint16_t remote_read();
uint8_t cs_read(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER( dp8390_reset );
+ void dp8390_reset(int state);
void recv_cb(uint8_t *buf, int len) override;
protected:
@@ -30,7 +32,7 @@ protected:
};
// construction/destruction
- dp8390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, TYPE varian, float bandwidth);
+ dp8390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, TYPE varian, u32 bandwidth);
// device-level overrides
virtual void device_start() override;
diff --git a/src/devices/machine/dp83932c.cpp b/src/devices/machine/dp83932c.cpp
index c08a16b655c..3d35d80a9dd 100644
--- a/src/devices/machine/dp83932c.cpp
+++ b/src/devices/machine/dp83932c.cpp
@@ -22,9 +22,10 @@
#include "emu.h"
#include "dp83932c.h"
+
#include "hashing.h"
+#include "multibyte.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_COMMAND (1U << 1)
#define LOG_FILTER (1U << 2)
#define LOG_PACKETS (1U << 3)
@@ -66,7 +67,7 @@ static u16 const regmask[] =
dp83932c_device::dp83932c_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, DP83932C, tag, owner, clock)
- , device_network_interface(mconfig, *this, 10.0f)
+ , device_network_interface(mconfig, *this, 10)
, m_bus(*this, finder_base::DUMMY_TAG, 0)
, m_out_int(*this)
, m_int_state(false)
@@ -80,9 +81,7 @@ void dp83932c_device::map(address_map &map)
void dp83932c_device::device_start()
{
- m_out_int.resolve();
-
- m_command = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp83932c_device::command), this));
+ m_command = timer_alloc(FUNC(dp83932c_device::command), this);
save_item(NAME(m_int_state));
save_item(NAME(m_reg));
@@ -113,11 +112,19 @@ void dp83932c_device::device_reset()
int dp83932c_device::recv_start_cb(u8 *buf, int length)
{
- unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
-
- if (!(m_reg[CR] & CR_RXEN))
+ // check for receiver disabled or overflow condition
+ if (!(m_reg[CR] & CR_RXEN) || (m_reg[ISR] & (ISR_RDE | ISR_RBE)))
return -1;
+ // reload receive descriptor address after end of list encountered
+ if (BIT(m_reg[CRDA], 0))
+ {
+ m_reg[CRDA] = read_bus_word(EA(m_reg[URDA], m_reg[LLFA]));
+
+ if (BIT(m_reg[CRDA], 0))
+ return -2;
+ }
+
m_reg[RCR] &= ~(RCR_MC | RCR_BC | RCR_LPKT | RCR_CRCR | RCR_FAER | RCR_LBK | RCR_PRX);
// address filter
@@ -138,25 +145,12 @@ int dp83932c_device::recv_start_cb(u8 *buf, int length)
else
m_reg[RCR] |= RCR_PRX;
- LOG("recv_start_cb %d\n", length);
-
// loopback
if (m_reg[RCR] & RCR_LB)
m_reg[RCR] |= RCR_LBK;
dump_bytes(buf, length);
- if (m_reg[CRDA] & 1)
- {
- // re-read the previous descriptor link field
- m_reg[CRDA] = m_bus->read_word(EA(m_reg[URDA], m_reg[LLFA]));
- if (m_reg[CRDA] & 1)
- {
- logerror("no receive descriptor available\n");
- return -2;
- }
- }
-
// save rba pointer registers
m_reg[TRBA0] = m_reg[CRBA0];
m_reg[TRBA1] = m_reg[CRBA1];
@@ -173,6 +167,7 @@ int dp83932c_device::recv_start_cb(u8 *buf, int length)
// update remaining buffer word count
u32 const rbwc = ((u32(m_reg[RBWC1]) << 16) | m_reg[RBWC0]) - (length + 1) / 2;
+ LOG("recv_start_cb length %d buffer %d remaining %d\n", length, ((u32(m_reg[RBWC1]) << 16) | m_reg[RBWC0]) * 2, rbwc * 2);
m_reg[RBWC1] = rbwc >> 16;
m_reg[RBWC0] = u16(rbwc);
@@ -181,20 +176,24 @@ int dp83932c_device::recv_start_cb(u8 *buf, int length)
// write status to rda
// TODO: don't write the rda if rba limit exceeded (buffer overflow)
+ unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
offs_t const rda = EA(m_reg[URDA], m_reg[CRDA]);
- m_bus->write_word(rda + 0 * width, m_reg[RCR]);
- m_bus->write_word(rda + 1 * width, length);
- m_bus->write_word(rda + 2 * width, m_reg[CRBA0]);
- m_bus->write_word(rda + 3 * width, m_reg[CRBA1]);
- m_bus->write_word(rda + 4 * width, m_reg[RSC]);
+ write_bus_word(rda + 0 * width, m_reg[RCR]);
+ write_bus_word(rda + 1 * width, length);
+ write_bus_word(rda + 2 * width, m_reg[CRBA0]);
+ write_bus_word(rda + 3 * width, m_reg[CRBA1]);
+ write_bus_word(rda + 4 * width, m_reg[RSC]);
m_reg[LLFA] = m_reg[CRDA] + 5 * width;
- m_reg[CRDA] = m_bus->read_word(rda + 5 * width);
+ m_reg[CRDA] = read_bus_word(rda + 5 * width);
// check for end of list
- if (m_reg[CRDA] & 1)
+ if (BIT(m_reg[CRDA], 0))
+ {
+ LOG("recv_start_cb end of list\n");
m_reg[ISR] |= ISR_RDE;
+ }
else
- m_bus->write_word(rda + 6 * width, 0);
+ write_bus_word(rda + 6 * width, 0);
// handle buffer exhaustion
if (rbwc < m_reg[EOBC])
@@ -210,6 +209,7 @@ void dp83932c_device::recv_complete_cb(int result)
if (result > 0)
{
m_reg[ISR] |= ISR_PKTRX;
+
update_interrupts();
}
}
@@ -231,11 +231,8 @@ void dp83932c_device::reg_w(offs_t offset, u16 data)
m_reg[CR] &= ~CR_RST;
}
-
- return;
}
-
- if (data & CR_RST)
+ else if (data & CR_RST)
{
LOGMASKED(LOG_COMMAND, "enter software reset\n");
@@ -243,12 +240,22 @@ void dp83932c_device::reg_w(offs_t offset, u16 data)
m_reg[CR] &= ~(CR_LCAM | CR_RRRA | CR_TXP | CR_HTX);
m_reg[CR] |= (CR_RST | CR_RXDIS);
-
- return;
}
-
- m_reg[offset] |= data & regmask[offset];
- m_command->adjust(attotime::zero, data & regmask[offset]);
+ else
+ {
+ u16 cmd_to_run = data & regmask[offset];
+ if (m_reg[CR] & CR_TXP)
+ {
+ // Per section 3.5.4 in the datasheet, TDAs can be dynamically added.
+ // The TXP command will be re-sent by the host, but doesn't do anything
+ // unless the SONIC finished the last commmand right before the TDA was
+ // appended to the list. So, null the CR_TXP bit if it was already set
+ // so we don't smash the currently running transmission.
+ cmd_to_run &= ~CR_TXP;
+ }
+ m_reg[offset] |= data & regmask[offset];
+ m_command->adjust(attotime::zero, cmd_to_run);
+ }
break;
case RCR:
@@ -262,8 +269,11 @@ void dp83932c_device::reg_w(offs_t offset, u16 data)
break;
case ISR:
+ // reload rra when rbe is cleared
+ if ((m_reg[offset] & ISR_RBE) && (data & ISR_RBE))
+ read_rra();
+
m_reg[offset] &= ~(data & regmask[offset]);
- // TODO: reload rra after RBE cleared
update_interrupts();
break;
@@ -284,7 +294,7 @@ void dp83932c_device::reg_w(offs_t offset, u16 data)
}
}
-void dp83932c_device::command(void *ptr, s32 param)
+void dp83932c_device::command(s32 param)
{
if (param & CR_HTX)
{
@@ -349,9 +359,11 @@ void dp83932c_device::transmit()
// read control information from tda and load registers
u16 const tcr = m_reg[TCR];
- m_reg[TCR] = m_bus->read_word(tda + word++ * width) & TCR_TPC;
- m_reg[TPS] = m_bus->read_word(tda + word++ * width);
- m_reg[TFC] = m_bus->read_word(tda + word++ * width);
+ m_reg[TCR] = read_bus_word(tda + word++ * width) & TCR_TPC;
+ m_reg[TPS] = read_bus_word(tda + word++ * width);
+ m_reg[TFC] = read_bus_word(tda + word++ * width);
+
+ LOG("transmit tda 0x%08x tps %d tfc %d\n", tda, m_reg[TPS], m_reg[TFC]);
// check for programmable interrupt
if ((m_reg[TCR] & TCR_PINT) && !(tcr & TCR_PINT))
@@ -365,11 +377,12 @@ void dp83932c_device::transmit()
for (unsigned fragment = 0; fragment < m_reg[TFC]; fragment++)
{
// read fragment address and size
- m_reg[TSA0] = m_bus->read_word(tda + word++ * width);
- m_reg[TSA1] = m_bus->read_word(tda + word++ * width);
- m_reg[TFS] = m_bus->read_word(tda + word++ * width);
+ m_reg[TSA0] = read_bus_word(tda + word++ * width);
+ m_reg[TSA1] = read_bus_word(tda + word++ * width);
+ m_reg[TFS] = read_bus_word(tda + word++ * width);
offs_t const tsa = EA(m_reg[TSA1], m_reg[TSA0]);
+ LOG("transmit tsa 0x%08x tfs %d\n", tsa, m_reg[TFS]);
// FIXME: word/dword transfers (allow unaligned)
for (unsigned byte = 0; byte < m_reg[TFS]; byte++)
@@ -382,18 +395,18 @@ void dp83932c_device::transmit()
u32 const crc = util::crc32_creator::simple(buf, length);
// insert the fcs
- buf[length++] = crc >> 0;
- buf[length++] = crc >> 8;
- buf[length++] = crc >> 16;
- buf[length++] = crc >> 24;
+ put_u32le(&buf[length], crc);
+ length += 4;
}
// advance ctda to the link field
m_reg[CTDA] += word * width;
+ LOG("transmit length %d word %d tda 0x%08x\n", length, word, EA(m_reg[UTDA], m_reg[CTDA]));
+
// transmit data
dump_bytes(buf, length);
- send(buf, length);
+ send(buf, length, 4);
}
void dp83932c_device::send_complete_cb(int result)
@@ -407,16 +420,16 @@ void dp83932c_device::send_complete_cb(int result)
}
// write descriptor status
- m_bus->write_word(EA(m_reg[UTDA], m_reg[TTDA]), m_reg[TCR] & TCR_TPS);
+ write_bus_word(EA(m_reg[UTDA], m_reg[TTDA]), m_reg[TCR] & TCR_TPS);
// check for halt
if (!(m_reg[CR] & CR_HTX))
{
// load next descriptor address
- m_reg[CTDA] = m_bus->read_word(EA(m_reg[UTDA], m_reg[CTDA]));
+ m_reg[CTDA] = read_bus_word(EA(m_reg[UTDA], m_reg[CTDA]));
// check for end of list
- if (m_reg[CTDA] & 1)
+ if (BIT(m_reg[CTDA], 0))
{
m_reg[ISR] |= ISR_TXDN;
m_reg[CR] &= ~CR_TXP;
@@ -440,10 +453,10 @@ void dp83932c_device::read_rra(bool command)
offs_t const rrp = EA(m_reg[URRA], m_reg[RRP]);
- m_reg[CRBA0] = m_bus->read_word(rrp + 0 * width);
- m_reg[CRBA1] = m_bus->read_word(rrp + 1 * width);
- m_reg[RBWC0] = m_bus->read_word(rrp + 2 * width);
- m_reg[RBWC1] = m_bus->read_word(rrp + 3 * width);
+ m_reg[CRBA0] = read_bus_word(rrp + 0 * width);
+ m_reg[CRBA1] = read_bus_word(rrp + 1 * width);
+ m_reg[RBWC0] = read_bus_word(rrp + 2 * width);
+ m_reg[RBWC1] = read_bus_word(rrp + 3 * width);
LOG("read_rra crba 0x%08x rbwc 0x%08x\n",
EA(m_reg[CRBA1], m_reg[CRBA0]), EA(m_reg[RBWC1], m_reg[RBWC0]));
@@ -472,10 +485,10 @@ void dp83932c_device::load_cam()
{
offs_t const cdp = EA(m_reg[URRA], m_reg[CDP]);
- u16 const cep = m_bus->read_word(cdp + 0 * width) & 0xf;
- u16 const cap0 = m_bus->read_word(cdp + 1 * width);
- u16 const cap1 = m_bus->read_word(cdp + 2 * width);
- u16 const cap2 = m_bus->read_word(cdp + 3 * width);
+ u16 const cep = read_bus_word(cdp + 0 * width) & 0xf;
+ u16 const cap0 = read_bus_word(cdp + 1 * width);
+ u16 const cap1 = read_bus_word(cdp + 2 * width);
+ u16 const cap2 = read_bus_word(cdp + 3 * width);
// FIXME: documented byte/word order doesn't match emulation
@@ -483,15 +496,16 @@ void dp83932c_device::load_cam()
cep, u8(cap0), cap0 >> 8, u8(cap1), cap1 >> 8, u8(cap2), cap2 >> 8);
m_cam[cep] =
- (u64(u8(cap0 >> 0)) << 40) | (u64(u8(cap0 >> 8)) << 32) | (u64(u8(cap1 >> 0)) << 24) |
- (u64(u8(cap1 >> 8)) << 16) | (u64(u8(cap2 >> 0)) << 8) | (u64(u8(cap2 >> 8)) << 0);
+ (u64(swapendian_int16(cap0)) << 32) |
+ (u64(swapendian_int16(cap1)) << 16) |
+ (u64(swapendian_int16(cap2)) << 0);
m_reg[CDP] += 4 * width;
m_reg[CDC]--;
}
// read cam enable
- m_reg[CE] = m_bus->read_word(EA(m_reg[URRA], m_reg[CDP]));
+ m_reg[CE] = read_bus_word(EA(m_reg[URRA], m_reg[CDP]));
LOG("load_cam enable 0x%04x\n", m_reg[CE]);
m_reg[CR] &= ~CR_LCAM;
@@ -518,9 +532,7 @@ bool dp83932c_device::address_filter(u8 *buf)
return true;
}
- u64 const address =
- (u64(buf[0]) << 40) | (u64(buf[1]) << 32) | (u64(buf[2]) << 24) |
- (u64(buf[3]) << 16) | (u64(buf[4]) << 8) | (u64(buf[5]) << 0);
+ u64 const address = get_u48be(buf);
// broadcast
if ((address == 0xffff'ffffffffULL) && (m_reg[RCR] & (RCR_AMC | RCR_BRD)))
@@ -572,3 +584,16 @@ void dp83932c_device::dump_bytes(u8 *buf, int length)
buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]);
}
}
+
+u16 dp83932c_device::read_bus_word(offs_t address)
+{
+ return (m_reg[DCR] & DCR_DW) ? m_bus->read_dword(address) : m_bus->read_word(address);
+}
+
+void dp83932c_device::write_bus_word(offs_t address, u16 data)
+{
+ if (m_reg[DCR] & DCR_DW)
+ m_bus->write_dword(address, data);
+ else
+ m_bus->write_word(address, data);
+}
diff --git a/src/devices/machine/dp83932c.h b/src/devices/machine/dp83932c.h
index 054bb9e28cd..2a7d271eb11 100644
--- a/src/devices/machine/dp83932c.h
+++ b/src/devices/machine/dp83932c.h
@@ -6,6 +6,8 @@
#pragma once
+#include "dinetwork.h"
+
class dp83932c_device
: public device_t
, public device_network_interface
@@ -33,7 +35,7 @@ protected:
virtual void recv_complete_cb(int result) override;
// command helpers
- void command(void *ptr, s32 param);
+ void command(s32 param);
void transmit();
void read_rra(bool command = false);
void load_cam();
@@ -207,6 +209,10 @@ private:
bool m_int_state;
u16 m_reg[64];
u64 m_cam[16];
+
+ // These wrappers handle 16-bit data stored on 32-bit word boundaries when in 32-bit mode
+ u16 read_bus_word(offs_t address);
+ void write_bus_word(offs_t address, u16 data);
};
DECLARE_DEVICE_TYPE(DP83932C, dp83932c_device)
diff --git a/src/devices/machine/dp8573.cpp b/src/devices/machine/dp8573.cpp
deleted file mode 100644
index d110ffa0656..00000000000
--- a/src/devices/machine/dp8573.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/***************************************************************************
-
- DP8573 Real Time Clock (RTC)
-
-***************************************************************************/
-
-#include "emu.h"
-#include "machine/dp8573.h"
-#include "machine/timehelp.h"
-
-#define LOG_GENERAL (1 << 0)
-#define LOG_TICKS (1 << 1)
-#define LOG_ALL (LOG_GENERAL | LOG_TICKS)
-
-#define VERBOSE (0)
-#include "logmacro.h"
-
-// device type definition
-DEFINE_DEVICE_TYPE(DP8573, dp8573_device, "dp8573", "DP8573 Real-Time Clock")
-
-dp8573_device::dp8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DP8573, tag, owner, clock)
- , device_nvram_interface(mconfig, *this)
- , m_intr_cb(*this)
- , m_mfo_cb(*this)
-{
-}
-
-void dp8573_device::device_start()
-{
- save_item(NAME(m_ram));
- save_item(NAME(m_tscr));
- save_item(NAME(m_pfr));
- save_item(NAME(m_millis));
-
- m_timer = timer_alloc(TIMER_ID);
- m_timer->adjust(attotime::never);
-
- m_intr_cb.resolve_safe();
- m_mfo_cb.resolve_safe();
-
- memset(m_ram, 0, 32);
- sync_time();
-
- m_tscr = 0;
-
- m_timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1));
-}
-
-void dp8573_device::sync_time()
-{
- system_time systime;
- machine().base_datetime(systime);
-
- m_millis = 0;
- m_ram[REG_HUNDREDTH] = 0;
- m_ram[REG_SECOND] = time_helper::make_bcd(systime.utc_time.second);
- m_ram[REG_MINUTE] = time_helper::make_bcd(systime.utc_time.minute);
- m_ram[REG_HOUR] = time_helper::make_bcd(systime.utc_time.hour);
- m_ram[REG_DAY] = time_helper::make_bcd(systime.utc_time.mday);
- m_ram[REG_MONTH] = time_helper::make_bcd(systime.utc_time.month + 1);
- m_ram[REG_YEAR] = time_helper::make_bcd(systime.utc_time.year % 100);
- m_ram[REG_DAYOFWEEK] = time_helper::make_bcd(systime.utc_time.weekday + 1);
-
- m_pfr = 0;
-
- // FIXME: should probably rely on nvram start/stop state
- m_ram[REG_RTMR] = RTMR_CSS;
-}
-
-void dp8573_device::save_registers()
-{
- m_ram[REG_SAVE_SECOND] = m_ram[REG_SECOND];
- m_ram[REG_SAVE_MINUTE] = m_ram[REG_MINUTE];
- m_ram[REG_SAVE_HOUR] = m_ram[REG_HOUR];
- m_ram[REG_SAVE_DAY] = m_ram[REG_DAY];
- m_ram[REG_SAVE_MONTH] = m_ram[REG_MONTH];
-}
-
-void dp8573_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- if ((m_pfr & PFR_OSF) || !(m_ram[REG_RTMR] & RTMR_CSS))
- {
- LOGMASKED(LOG_TICKS, "Tick suppressed due to OSF or !CSS\n");
- return;
- }
-
- m_pfr |= PFR_1MS;
-
- bool carry = false;
- bool tens_carry = false;
- time_helper::inc_bcd(&m_millis, 0xff, 0x00, 0x09, &tens_carry);
- if (tens_carry)
- {
- m_pfr |= PFR_10MS;
- carry = time_helper::inc_bcd(&m_ram[REG_HUNDREDTH], 0xff, 0x00, 0x99, &tens_carry);
- if (tens_carry)
- m_pfr |= PFR_100MS;
- }
- if (carry)
- {
- m_pfr |= PFR_1S;
- carry = time_helper::inc_bcd(&m_ram[REG_SECOND], 0xff, 0x00, 0x59, &tens_carry);
- if (tens_carry)
- m_pfr |= PFR_10S;
- }
- if (carry)
- {
- m_pfr |= PFR_1MIN;
- carry = time_helper::inc_bcd(&m_ram[REG_MINUTE], 0xff, 0x00, 0x59);
- }
- if (carry)
- {
- if (m_ram[REG_RTMR] & RTMR_12H)
- {
- carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x01, 0x12);
- if (carry)
- {
- m_ram[REG_HOUR] |= 0x20;
- carry = !(m_ram[REG_HOUR] & 0x20);
- }
- }
- else
- {
- carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x00, 0x23);
- }
- }
- if (carry)
- {
- static const uint8_t daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 };
-
- time_helper::inc_bcd(&m_ram[REG_DAYOFWEEK], 0xff, 0x01, 0x07);
-
- uint8_t month = time_helper::from_bcd(m_ram[REG_MONTH]);
-
- uint8_t maxdays;
- if (month == 2 && (m_ram[REG_RTMR] & RTMR_LY) == 0)
- {
- maxdays = 0x29;
- }
- else if (month >= 1 && month <= 12)
- {
- maxdays = daysinmonth[month - 1];
- }
- else
- {
- maxdays = 0x31;
- }
-
- carry = time_helper::inc_bcd(&m_ram[REG_DAY], 0xff, 0x01, maxdays);
- }
- if (carry)
- {
- carry = time_helper::inc_bcd(&m_ram[REG_MONTH], 0xff, 0x01, 0x12);
- }
- if (carry)
- {
- carry = time_helper::inc_bcd(&m_ram[REG_YEAR], 0xff, 0x00, 0x99);
- }
- if (carry)
- {
- // Advance the leap-year counter
- uint8_t leap = m_ram[REG_RTMR] & RTMR_LY;
- leap = (leap + 1) & RTMR_LY;
- m_ram[REG_RTMR] &= ~RTMR_LY;
- m_ram[REG_RTMR] |= leap;
- }
-
- // Check for Time Save mode
- if (m_tscr & TSCR_TS)
- {
- save_registers();
- }
-
- // Check for periodic interrupts
- const uint8_t icr0 = m_ram[REG_PFR_ICR0] & ~ICR0_RAM_MASK;
- const uint8_t pfr = m_pfr & ~ICR0_RAM_MASK;
- if (icr0 & pfr)
- {
- set_interrupt(MSR_PER);
- }
-
- const uint8_t icr1 = m_ram[REG_TSCR_ICR1] & ICR1_COMPARE_MASK;
- if (icr1)
- {
- if (m_ram[REG_SECOND] == m_ram[REG_COMP_SECOND] ||
- m_ram[REG_MINUTE] == m_ram[REG_COMP_MINUTE] ||
- m_ram[REG_HOUR] == m_ram[REG_COMP_HOUR] ||
- m_ram[REG_DAY] == m_ram[REG_COMP_DAY] ||
- m_ram[REG_MONTH] == m_ram[REG_COMP_MONTH] ||
- m_ram[REG_DAYOFWEEK] == m_ram[REG_COMP_DAYOFWEEK])
- {
- set_interrupt(MSR_AL);
- }
- }
-}
-
-void dp8573_device::set_interrupt(uint8_t mask)
-{
- bool was_intr = m_ram[REG_MSR] & MSR_INT;
- m_ram[REG_MSR] |= mask;
-
- if (m_ram[REG_MSR] & MSR_INT_MASK)
- m_ram[REG_MSR] |= MSR_INT;
-
- if (!was_intr && (m_ram[REG_MSR] & MSR_INT))
- m_intr_cb(0);
-}
-
-void dp8573_device::clear_interrupt(uint8_t mask)
-{
- bool was_intr = m_ram[REG_MSR] & MSR_INT;
- m_ram[REG_MSR] &= ~mask;
-
- if (was_intr && !(m_ram[REG_MSR] & MSR_INT))
- m_intr_cb(1);
-}
-
-void dp8573_device::write(offs_t offset, u8 data)
-{
- LOGMASKED(LOG_GENERAL, "%s: DP8573 - Register Write: %02x = %02x\n", machine().describe_context(), offset, data);
-
- switch (offset)
- {
- case REG_MSR: // Main Status Register
- m_ram[offset] &= ~MSR_RAM_MASK;
- m_ram[offset] |= data & MSR_RAM_MASK;
- if (data & MSR_CLEARABLE_MASK)
- clear_interrupt(data & MSR_CLEARABLE_MASK);
- break;
-
- case REG_RTMR: // Not Applicable / Real-Time Mode Register
- if (m_ram[REG_MSR] & MSR_RS)
- {
- const uint8_t old = m_ram[offset];
- m_ram[offset] = data;
- if ((old ^ data) & RTMR_12H)
- {
- uint8_t hour;
- if (old & RTMR_12H)
- hour = time_helper::from_bcd(m_ram[REG_HOUR] & 0x1f) + (BIT(m_ram[REG_HOUR], 5) ? 12 : 0);
- else
- hour = time_helper::from_bcd(m_ram[REG_HOUR]);
-
- if (data & RTMR_12H)
- {
- m_ram[REG_HOUR] = time_helper::make_bcd(hour % 12);
- m_ram[REG_HOUR] |= (hour > 11) ? 0x20 : 0;
- }
- else
- {
- m_ram[REG_HOUR] = time_helper::make_bcd(hour);
- }
- }
- }
- break;
-
- case REG_OMR: // Not Applicable / Output Mode Register
- if (m_ram[REG_MSR] & MSR_RS)
- {
- // Not yet implemented: Buffered Crystal Oscillator output on MFO pin
- m_ram[offset] = data;
- }
- break;
-
- case REG_PFR_ICR0: // Periodic Flag Register / Interrupt Control Register 0
- if (m_ram[REG_MSR] & MSR_RS)
- {
- m_ram[offset] = data;
- }
- else
- {
- m_pfr &= ~PFR_TM;
- m_pfr |= data & PFR_TM;
- }
- break;
-
- case REG_TSCR_ICR1: // Time Save Control Register / Interrupt Control Register 1
- if (m_ram[REG_MSR] & MSR_RS)
- {
- m_ram[offset] = data;
- }
- else
- {
- m_tscr = data & ~TSCR_NA;
- if (data & TSCR_TS)
- save_registers();
- }
- break;
-
- case REG_RAM_D1D0: // RAM, D1/D0 bits only
- m_ram[offset] = data & 3;
- break;
-
- case REG_NA_0FH:
- case REG_NA_10H:
- case REG_NA_11H:
- case REG_NA_12H:
- break;
-
- default:
- m_ram[offset] = data;
- break;
- }
-}
-
-u8 dp8573_device::read(offs_t offset)
-{
- uint8_t ret = m_ram[offset];
-
- if (offset >= REG_RTMR && offset <= REG_TSCR_ICR1)
- {
- if (m_ram[REG_MSR] & MSR_RS)
- {
- }
- else
- {
- switch (offset)
- {
- case REG_RTMR:
- case REG_OMR:
- ret = 0;
- break;
- case REG_PFR_ICR0:
- ret = m_pfr;
- m_pfr &= ~PFR_READ_CLEAR_MASK;
- break;
- case REG_TSCR_ICR1:
- ret = m_tscr;
- break;
- default:
- break;
- }
- }
- }
-
- LOGMASKED(LOG_GENERAL, "%s: DP8573 - Register Read: %02x = %02x\n", machine().describe_context(), offset, ret);
- return ret;
-}
-
-void dp8573_device::nvram_default()
-{
- memset(m_ram, 0, 32);
- sync_time();
-}
-
-void dp8573_device::nvram_read(emu_file &file)
-{
- file.read(m_ram, 32);
- sync_time();
-}
-
-void dp8573_device::nvram_write(emu_file &file)
-{
- file.write(m_ram, 32);
-}
diff --git a/src/devices/machine/dp8573.h b/src/devices/machine/dp8573.h
deleted file mode 100644
index 1cb1300dedf..00000000000
--- a/src/devices/machine/dp8573.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/***************************************************************************
-
- DP8573 Real Time Clock (RTC)
-
-***************************************************************************/
-
-#ifndef DEVICES_MACHINE_DP8573_H
-#define DEVICES_MACHINE_DP8573_H
-
-#pragma once
-
-class dp8573_device : public device_t, public device_nvram_interface
-{
-public:
- dp8573_device(const machine_config &mconfig, const char *tag, device_t *owner)
- : dp8573_device(mconfig, tag, owner, 32768)
- {
- }
-
- dp8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- void write(offs_t offset, u8 data);
- u8 read(offs_t offset);
- void pfail_w(int state) {}
-
- auto intr() { return m_intr_cb.bind(); }
- auto mfo() { return m_mfo_cb.bind(); }
-
-protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
- // device_nvram_interface overrides
- virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
-
- void sync_time();
- void save_registers();
- void set_interrupt(uint8_t mask);
- void clear_interrupt(uint8_t mask);
-
- static const device_timer_id TIMER_ID = 0;
-
- enum
- {
- REG_MSR = 0x00, // Main Status Register
- REG_RTMR = 0x01, // Not Applicable / Real-Time Mode Register
- REG_OMR = 0x02, // Not Applicable / Output Mode Register
- REG_PFR_ICR0 = 0x03, // Periodic Flag Register / Interrupt Control Register 0
- REG_TSCR_ICR1 = 0x04, // Time Save Control Register / Interrupt Control Register 1
- REG_HUNDREDTH = 0x05, // Hundredths and Tenths of a Second (0-99)
- REG_SECOND = 0x06, // Seconds (0-59)
- REG_MINUTE = 0x07, // Minutes (0-59)
- REG_HOUR = 0x08, // Hours (1-12, 0-23)
- REG_DAY = 0x09, // Day of Month (1-28/29/30/31)
- REG_MONTH = 0x0a, // Month (1-12)
- REG_YEAR = 0x0b, // Year (0-99)
- // 0x0c - RAM
- REG_RAM_D1D0 = 0x0d, // RAM, D1/D0 bits only
- REG_DAYOFWEEK = 0x0e, // Day of Week (1-7)
- REG_NA_0FH = 0x0f,
- REG_NA_10H = 0x10,
- REG_NA_11H = 0x11,
- REG_NA_12H = 0x12,
- REG_COMP_SECOND = 0x13, // Seconds Compare RAM (0-59)
- REG_COMP_MINUTE = 0x14, // Minutes Compare RAM (0-59)
- REG_COMP_HOUR = 0x15, // Hours Compare RAM (1-12, 0-23)
- REG_COMP_DAY = 0x16, // Day of Month Compare RAM (1-28/29/30/31)
- REG_COMP_MONTH = 0x17, // Month Compare RAM (1-12)
- REG_COMP_DAYOFWEEK = 0x18, // Day of Week Compare RAM (1-7)
- REG_SAVE_SECOND = 0x19, // Seconds Time Save RAM
- REG_SAVE_MINUTE = 0x1a, // Minutes Time Save RAM
- REG_SAVE_HOUR = 0x1b, // Hours Time Save RAM
- REG_SAVE_DAY = 0x1c, // Day of Month Time Save RAM
- REG_SAVE_MONTH = 0x1d, // Month Time Save RAM
- // 0x1e - RAM
- REG_TEST = 0x1f, // RAM / Test Mode Register
-
- MSR_INT = 0x01, // Interrupt Status
- MSR_PF = 0x02, // Power Fail Interrupt
- MSR_PER = 0x04, // Period Interrupt
- MSR_AL = 0x08, // Alarm Interrupt
- MSR_RS = 0x40, // Register Select Bit
- MSR_RAM_MASK = 0xf0,
- MSR_INT_MASK = 0x0e,
- MSR_CLEARABLE_MASK = 0x0c,
-
- PFR_1MIN = 0x01, // Minutes flag
- PFR_10S = 0x02, // 10-second flag
- PFR_1S = 0x04, // Seconds flag
- PFR_100MS = 0x08, // 100-millisecond flag
- PFR_10MS = 0x10, // 10-millisecond flag
- PFR_1MS = 0x20, // Millisecond flag
- PFR_OSF = 0x40, // Oscillator Failed / Single Supply Bit
- PFR_TM = 0x80, // Test Mode Enable
- PFR_READ_CLEAR_MASK = 0x3f,
-
- TSCR_RAM_MASK = 0x3f,
- TSCR_NA = 0x40, // N/A
- TSCR_TS = 0x80, // Time Save Enable
-
- RTMR_LY0 = 0x01, // Leap Year LSB
- RTMR_LY1 = 0x02, // Leap Year MSB
- RTMR_LY = 0x03,
- RTMR_12H = 0x04, // 12/!24 hour mode
- RTMR_CSS = 0x08, // Clock Start/!Stop
- RTMR_IPF = 0x10, // Interrupt PF Operation
- RTMR_RAM_MASK = 0xe0,
-
- OMR_RAM_MASK = 0x7f,
- OMR_MO = 0x80, // MFO Pin as Oscillator
-
- ICR0_MN = 0x01, // Minutes enable
- ICR0_TS = 0x02, // 10-second enable
- ICR0_S = 0x04, // Seconds enable
- ICR0_HM = 0x08, // 100 millisecond enable
- ICR0_TM = 0x10, // 10 millisecond enable
- ICR0_1M = 0x20, // Milliseconds enable
- ICR0_RAM_MASK = 0xc0,
-
- ICR1_SC = 0x01, // Second compare enable
- ICR1_MN = 0x02, // Minute compare enable
- ICR1_HR = 0x04, // Hour compare enable
- ICR1_DOM = 0x08, // Day of month compare enable
- ICR1_MO = 0x10, // Month compare enable
- ICR1_DOW = 0x20, // Day of week compare enable
- ICR1_ALE = 0x40, // Alarm interrupt enable
- ICR1_PFE = 0x80, // Power fail interrupt enable
- ICR1_COMPARE_MASK = 0x3f
- };
-
- uint8_t m_ram[32];
- uint8_t m_tscr;
- uint8_t m_pfr;
- uint8_t m_millis;
-
- emu_timer *m_timer;
-
- devcb_write_line m_intr_cb;
- devcb_write_line m_mfo_cb;
-};
-
-DECLARE_DEVICE_TYPE(DP8573, dp8573_device)
-
-#endif // DEVICES_MACHINE_DP8573_H
diff --git a/src/devices/machine/dp8573a.cpp b/src/devices/machine/dp8573a.cpp
new file mode 100644
index 00000000000..c0af28637ab
--- /dev/null
+++ b/src/devices/machine/dp8573a.cpp
@@ -0,0 +1,486 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+
+/*
+ * DP8572A/DP8573A Real Time Clock (RTC)
+ *
+ * The DP8572A has several enhancements over the DP8573A:
+ * - additional page of 32 bytes of RAM
+ * - programmable prescaler (allows choice of 32.768KHz, 4.194304MHz, 4.9152MHz
+ * and 32.0KHz oscillators)
+ * - power fail delay
+ *
+ * TODO:
+ * - dp8572a programmable prescaler
+ */
+
+#include "emu.h"
+#include "dp8573a.h"
+
+#include "machine/timehelp.h"
+
+#include <algorithm>
+#include <iterator>
+
+#define LOG_TICKS (1U << 1)
+#define LOG_ALL (LOG_GENERAL | LOG_TICKS)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+enum : uint8_t
+{
+ REG_MSR = 0x00, // Main Status Register
+ REG_RTMR = 0x01, // Not Applicable / Real-Time Mode Register
+ REG_OMR = 0x02, // Not Applicable / Output Mode Register
+ REG_PFR_ICR0 = 0x03, // Periodic Flag Register / Interrupt Control Register 0
+ REG_TSCR_ICR1 = 0x04, // Time Save Control Register / Interrupt Control Register 1
+ REG_HUNDREDTH = 0x05, // Hundredths and Tenths of a Second (0-99)
+ REG_SECOND = 0x06, // Seconds (0-59)
+ REG_MINUTE = 0x07, // Minutes (0-59)
+ REG_HOUR = 0x08, // Hours (1-12, 0-23)
+ REG_DAY = 0x09, // Day of Month (1-28/29/30/31)
+ REG_MONTH = 0x0a, // Month (1-12)
+ REG_YEAR = 0x0b, // Year (0-99)
+ // 0x0c - RAM
+ REG_RAM_D1D0 = 0x0d, // RAM, D1/D0 bits only
+ REG_DAYOFWEEK = 0x0e, // Day of Week (1-7)
+ REG_NA_0FH = 0x0f,
+ REG_NA_10H = 0x10,
+ REG_NA_11H = 0x11,
+ REG_NA_12H = 0x12,
+ REG_COMP_SECOND = 0x13, // Seconds Compare RAM (0-59)
+ REG_COMP_MINUTE = 0x14, // Minutes Compare RAM (0-59)
+ REG_COMP_HOUR = 0x15, // Hours Compare RAM (1-12, 0-23)
+ REG_COMP_DAY = 0x16, // Day of Month Compare RAM (1-28/29/30/31)
+ REG_COMP_MONTH = 0x17, // Month Compare RAM (1-12)
+ REG_COMP_DAYOFWEEK = 0x18, // Day of Week Compare RAM (1-7)
+ REG_SAVE_SECOND = 0x19, // Seconds Time Save RAM
+ REG_SAVE_MINUTE = 0x1a, // Minutes Time Save RAM
+ REG_SAVE_HOUR = 0x1b, // Hours Time Save RAM
+ REG_SAVE_DAY = 0x1c, // Day of Month Time Save RAM
+ REG_SAVE_MONTH = 0x1d, // Month Time Save RAM
+ // 0x1e - RAM
+ REG_TEST = 0x1f, // RAM / Test Mode Register
+
+ MSR_INT = 0x01, // Interrupt Status
+ MSR_PF = 0x02, // Power Fail Interrupt
+ MSR_PER = 0x04, // Period Interrupt
+ MSR_AL = 0x08, // Alarm Interrupt
+ MSR_RS = 0x40, // Register Select Bit
+ MSR_PS = 0x80, // Page Select (DP8572A)
+ MSR_RAM_MASK = 0xf0,
+ MSR_INT_MASK = 0x0e,
+ MSR_CLEARABLE_MASK = 0x0c,
+
+ PFR_1MIN = 0x01, // Minutes flag
+ PFR_10S = 0x02, // 10-second flag
+ PFR_1S = 0x04, // Seconds flag
+ PFR_100MS = 0x08, // 100-millisecond flag
+ PFR_10MS = 0x10, // 10-millisecond flag
+ PFR_1MS = 0x20, // Millisecond flag
+ PFR_OSF = 0x40, // Oscillator Failed / Single Supply Bit
+ PFR_TM = 0x80, // Test Mode Enable
+ PFR_READ_CLEAR_MASK = 0x3f,
+
+ TSCR_RAM_MASK = 0x3f,
+ TSCR_PFDE = 0x20, // Power Fail Delay Enable (DP8572A)
+ TSCR_NA = 0x40, // N/A
+ TSCR_LBF = 0x40, // Low Battery Flag (DP8572A)
+ TSCR_TS = 0x80, // Time Save Enable
+
+ RTMR_LY0 = 0x01, // Leap Year LSB
+ RTMR_LY1 = 0x02, // Leap Year MSB
+ RTMR_LY = 0x03,
+ RTMR_12H = 0x04, // 12/!24 hour mode
+ RTMR_CSS = 0x08, // Clock Start/!Stop
+ RTMR_IPF = 0x10, // Interrupt PF Operation
+ RTMR_XT0 = 0x40, // Crystal Freq. XT0 (DP8572A)
+ RTMR_XT1 = 0x80, // Crystal Freq. XT1 (DP8572A)
+ RTMR_RAM_MASK = 0xe0,
+
+ OMR_RAM_MASK = 0x7f,
+ OMR_MO = 0x80, // MFO Pin as Oscillator
+
+ ICR0_MN = 0x01, // Minutes enable
+ ICR0_TS = 0x02, // 10-second enable
+ ICR0_S = 0x04, // Seconds enable
+ ICR0_HM = 0x08, // 100 millisecond enable
+ ICR0_TM = 0x10, // 10 millisecond enable
+ ICR0_1M = 0x20, // Milliseconds enable
+ ICR0_RAM_MASK = 0xc0,
+
+ ICR1_SC = 0x01, // Second compare enable
+ ICR1_MN = 0x02, // Minute compare enable
+ ICR1_HR = 0x04, // Hour compare enable
+ ICR1_DOM = 0x08, // Day of month compare enable
+ ICR1_MO = 0x10, // Month compare enable
+ ICR1_DOW = 0x20, // Day of week compare enable
+ ICR1_ALE = 0x40, // Alarm interrupt enable
+ ICR1_PFE = 0x80, // Power fail interrupt enable
+ ICR1_COMPARE_MASK = 0x3f
+};
+
+// device type definition
+DEFINE_DEVICE_TYPE(DP8572A, dp8572a_device, "dp8572a", "DP8572A Real Time Clock")
+DEFINE_DEVICE_TYPE(DP8573A, dp8573a_device, "dp8573a", "DP8573A Real Time Clock")
+
+dp8573a_device::dp8573a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_nvram_interface(mconfig, *this)
+ , device_rtc_interface(mconfig, *this)
+ , m_intr_cb(*this)
+ , m_mfo_cb(*this)
+{
+}
+
+dp8573a_device::dp8573a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : dp8573a_device(mconfig, DP8573A, tag, owner, clock)
+{
+}
+
+dp8572a_device::dp8572a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : dp8573a_device(mconfig, DP8572A, tag, owner, clock)
+{
+}
+
+void dp8573a_device::device_start()
+{
+ m_ram = std::make_unique<uint8_t[]>(ram_size());
+
+ save_pointer(NAME(m_ram), ram_size());
+ save_item(NAME(m_tscr));
+ save_item(NAME(m_pfr));
+ save_item(NAME(m_millis));
+
+ m_timer = timer_alloc(FUNC(dp8573a_device::msec_tick), this);
+ m_timer->adjust(attotime::never);
+
+ m_tscr = 0;
+
+ m_timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1));
+}
+
+void dp8573a_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ m_millis = 0;
+ m_ram[REG_HUNDREDTH] = 0;
+ m_ram[REG_SECOND] = time_helper::make_bcd(second);
+ m_ram[REG_MINUTE] = time_helper::make_bcd(minute);
+ m_ram[REG_HOUR] = time_helper::make_bcd(hour);
+ m_ram[REG_DAY] = time_helper::make_bcd(day);
+ m_ram[REG_MONTH] = time_helper::make_bcd(month);
+ m_ram[REG_YEAR] = time_helper::make_bcd(year);
+ m_ram[REG_DAYOFWEEK] = time_helper::make_bcd(day_of_week);
+
+ m_pfr = 0;
+
+ // FIXME: should probably rely on nvram start/stop state
+ m_ram[REG_RTMR] = RTMR_CSS;
+}
+
+void dp8573a_device::save_registers()
+{
+ m_ram[REG_SAVE_SECOND] = m_ram[REG_SECOND];
+ m_ram[REG_SAVE_MINUTE] = m_ram[REG_MINUTE];
+ m_ram[REG_SAVE_HOUR] = m_ram[REG_HOUR];
+ m_ram[REG_SAVE_DAY] = m_ram[REG_DAY];
+ m_ram[REG_SAVE_MONTH] = m_ram[REG_MONTH];
+}
+
+TIMER_CALLBACK_MEMBER(dp8573a_device::msec_tick)
+{
+ if ((m_pfr & PFR_OSF) || !(m_ram[REG_RTMR] & RTMR_CSS))
+ {
+ LOGMASKED(LOG_TICKS, "Tick suppressed due to OSF or !CSS\n");
+ return;
+ }
+
+ m_pfr |= PFR_1MS;
+
+ bool carry = false;
+ bool tens_carry = false;
+ time_helper::inc_bcd(&m_millis, 0xff, 0x00, 0x09, &tens_carry);
+ if (tens_carry)
+ {
+ m_pfr |= PFR_10MS;
+ carry = time_helper::inc_bcd(&m_ram[REG_HUNDREDTH], 0xff, 0x00, 0x99, &tens_carry);
+ if (tens_carry)
+ m_pfr |= PFR_100MS;
+ }
+ if (carry)
+ {
+ m_pfr |= PFR_1S;
+ carry = time_helper::inc_bcd(&m_ram[REG_SECOND], 0xff, 0x00, 0x59, &tens_carry);
+ if (tens_carry)
+ m_pfr |= PFR_10S;
+ }
+ if (carry)
+ {
+ m_pfr |= PFR_1MIN;
+ carry = time_helper::inc_bcd(&m_ram[REG_MINUTE], 0xff, 0x00, 0x59);
+ }
+ if (carry)
+ {
+ if (m_ram[REG_RTMR] & RTMR_12H)
+ {
+ carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x01, 0x12);
+ if (carry)
+ {
+ m_ram[REG_HOUR] |= 0x20;
+ carry = !(m_ram[REG_HOUR] & 0x20);
+ }
+ }
+ else
+ {
+ carry = time_helper::inc_bcd(&m_ram[REG_HOUR], 0xff, 0x00, 0x23);
+ }
+ }
+ if (carry)
+ {
+ static const uint8_t daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 };
+
+ time_helper::inc_bcd(&m_ram[REG_DAYOFWEEK], 0xff, 0x01, 0x07);
+
+ uint8_t month = time_helper::from_bcd(m_ram[REG_MONTH]);
+
+ uint8_t maxdays;
+ if (month == 2 && (m_ram[REG_RTMR] & RTMR_LY) == 0)
+ {
+ maxdays = 0x29;
+ }
+ else if (month >= 1 && month <= 12)
+ {
+ maxdays = daysinmonth[month - 1];
+ }
+ else
+ {
+ maxdays = 0x31;
+ }
+
+ carry = time_helper::inc_bcd(&m_ram[REG_DAY], 0xff, 0x01, maxdays);
+ }
+ if (carry)
+ {
+ carry = time_helper::inc_bcd(&m_ram[REG_MONTH], 0xff, 0x01, 0x12);
+ }
+ if (carry)
+ {
+ carry = time_helper::inc_bcd(&m_ram[REG_YEAR], 0xff, 0x00, 0x99);
+ }
+ if (carry)
+ {
+ // Advance the leap-year counter
+ uint8_t leap = m_ram[REG_RTMR] & RTMR_LY;
+ leap = (leap + 1) & RTMR_LY;
+ m_ram[REG_RTMR] &= ~RTMR_LY;
+ m_ram[REG_RTMR] |= leap;
+ }
+
+ // Check for Time Save mode
+ if (m_tscr & TSCR_TS)
+ {
+ save_registers();
+ }
+
+ // Check for periodic interrupts
+ const uint8_t icr0 = m_ram[REG_PFR_ICR0] & ~ICR0_RAM_MASK;
+ const uint8_t pfr = m_pfr & ~ICR0_RAM_MASK;
+ if (icr0 & pfr)
+ {
+ set_interrupt(MSR_PER);
+ }
+
+ const uint8_t icr1 = m_ram[REG_TSCR_ICR1] & ICR1_COMPARE_MASK;
+ if (icr1)
+ {
+ if (m_ram[REG_SECOND] == m_ram[REG_COMP_SECOND] ||
+ m_ram[REG_MINUTE] == m_ram[REG_COMP_MINUTE] ||
+ m_ram[REG_HOUR] == m_ram[REG_COMP_HOUR] ||
+ m_ram[REG_DAY] == m_ram[REG_COMP_DAY] ||
+ m_ram[REG_MONTH] == m_ram[REG_COMP_MONTH] ||
+ m_ram[REG_DAYOFWEEK] == m_ram[REG_COMP_DAYOFWEEK])
+ {
+ set_interrupt(MSR_AL);
+ }
+ }
+}
+
+void dp8573a_device::set_interrupt(uint8_t mask)
+{
+ bool was_intr = m_ram[REG_MSR] & MSR_INT;
+ m_ram[REG_MSR] |= mask;
+
+ if (m_ram[REG_MSR] & MSR_INT_MASK)
+ m_ram[REG_MSR] |= MSR_INT;
+
+ if (!was_intr && (m_ram[REG_MSR] & MSR_INT))
+ m_intr_cb(0);
+}
+
+void dp8573a_device::clear_interrupt(uint8_t mask)
+{
+ bool was_intr = m_ram[REG_MSR] & MSR_INT;
+ m_ram[REG_MSR] &= ~mask;
+
+ if (was_intr && !(m_ram[REG_MSR] & MSR_INT))
+ m_intr_cb(1);
+}
+
+void dp8573a_device::write(offs_t offset, uint8_t data)
+{
+ LOG("%s: Register Write: %02x = %02x\n", machine().describe_context(), offset, data);
+
+ switch (offset)
+ {
+ case REG_MSR: // Main Status Register
+ m_ram[offset] &= ~MSR_RAM_MASK;
+ m_ram[offset] |= data & MSR_RAM_MASK;
+ if (data & MSR_CLEARABLE_MASK)
+ clear_interrupt(data & MSR_CLEARABLE_MASK);
+ break;
+
+ case REG_RTMR: // Not Applicable / Real-Time Mode Register
+ if (m_ram[REG_MSR] & MSR_RS)
+ {
+ const uint8_t old = m_ram[offset];
+ m_ram[offset] = data;
+ if ((old ^ data) & RTMR_12H)
+ {
+ uint8_t hour;
+ if (old & RTMR_12H)
+ hour = time_helper::from_bcd(m_ram[REG_HOUR] & 0x1f) + (BIT(m_ram[REG_HOUR], 5) ? 12 : 0);
+ else
+ hour = time_helper::from_bcd(m_ram[REG_HOUR]);
+
+ if (data & RTMR_12H)
+ {
+ m_ram[REG_HOUR] = time_helper::make_bcd(hour % 12);
+ m_ram[REG_HOUR] |= (hour > 11) ? 0x20 : 0;
+ }
+ else
+ {
+ m_ram[REG_HOUR] = time_helper::make_bcd(hour);
+ }
+ }
+ }
+ break;
+
+ case REG_OMR: // Not Applicable / Output Mode Register
+ if (m_ram[REG_MSR] & MSR_RS)
+ {
+ // Not yet implemented: Buffered Crystal Oscillator output on MFO pin
+ m_ram[offset] = data;
+ }
+ break;
+
+ case REG_PFR_ICR0: // Periodic Flag Register / Interrupt Control Register 0
+ if (m_ram[REG_MSR] & MSR_RS)
+ {
+ m_ram[offset] = data;
+ }
+ else
+ {
+ m_pfr &= ~PFR_TM;
+ m_pfr |= data & PFR_TM;
+ }
+ break;
+
+ case REG_TSCR_ICR1: // Time Save Control Register / Interrupt Control Register 1
+ if (m_ram[REG_MSR] & MSR_RS)
+ {
+ m_ram[offset] = data;
+ }
+ else
+ {
+ m_tscr = data & ~TSCR_NA;
+ if (data & TSCR_TS)
+ save_registers();
+ }
+ break;
+
+ case REG_RAM_D1D0: // RAM, D1/D0 bits only
+ m_ram[offset] = data & 3;
+ break;
+
+ case REG_NA_0FH:
+ case REG_NA_10H:
+ case REG_NA_11H:
+ case REG_NA_12H:
+ break;
+
+ default:
+ m_ram[offset] = data;
+ break;
+ }
+}
+
+uint8_t dp8573a_device::read(offs_t offset)
+{
+ uint8_t ret = m_ram[offset];
+
+ if (offset >= REG_RTMR && offset <= REG_TSCR_ICR1)
+ {
+ if (m_ram[REG_MSR] & MSR_RS)
+ {
+ }
+ else
+ {
+ switch (offset)
+ {
+ case REG_RTMR:
+ case REG_OMR:
+ ret = 0;
+ break;
+ case REG_PFR_ICR0:
+ ret = m_pfr;
+ m_pfr &= ~PFR_READ_CLEAR_MASK;
+ break;
+ case REG_TSCR_ICR1:
+ ret = m_tscr;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ LOG("%s: Register Read: %02x = %02x\n", machine().describe_context(), offset, ret);
+ return ret;
+}
+
+void dp8573a_device::nvram_default()
+{
+ std::fill_n(m_ram.get(), ram_size(), 0);
+}
+
+bool dp8573a_device::nvram_read(util::read_stream &file)
+{
+ auto const [err, actual] = util::read(file, m_ram.get(), ram_size());
+ if (err || (actual != ram_size()))
+ return false;
+
+ return true;
+}
+
+bool dp8573a_device::nvram_write(util::write_stream &file)
+{
+ auto const [err, actual] = util::write(file, m_ram.get(), ram_size());
+ return !err;
+}
+
+void dp8572a_device::write(offs_t offset, uint8_t data)
+{
+ if (offset && (m_ram[REG_MSR] & MSR_PS))
+ m_ram[offset + 32] = data;
+ else
+ dp8573a_device::write(offset, data);
+}
+
+uint8_t dp8572a_device::read(offs_t offset)
+{
+ if (offset && (m_ram[REG_MSR] & MSR_PS))
+ return m_ram[offset + 32];
+ else
+ return dp8573a_device::read(offset);
+}
diff --git a/src/devices/machine/dp8573a.h b/src/devices/machine/dp8573a.h
new file mode 100644
index 00000000000..5851c9a65ab
--- /dev/null
+++ b/src/devices/machine/dp8573a.h
@@ -0,0 +1,73 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+
+#ifndef DEVICES_MACHINE_DP8573_H
+#define DEVICES_MACHINE_DP8573_H
+
+#pragma once
+
+#include "dirtc.h"
+
+class dp8573a_device : public device_t, public device_nvram_interface, public device_rtc_interface
+{
+public:
+ dp8573a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 32'768);
+
+ virtual void write(offs_t offset, uint8_t data);
+ virtual uint8_t read(offs_t offset);
+ void pfail_w(int state) {}
+
+ auto intr() { return m_intr_cb.bind(); }
+ auto mfo() { return m_mfo_cb.bind(); }
+
+protected:
+ dp8573a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_t implementation
+ virtual void device_start() override;
+
+ // device_nvram_interface implementation
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ // device_rtc_interface implementation
+ virtual bool rtc_feature_y2k() const override { return false; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+
+ void save_registers();
+ void set_interrupt(uint8_t mask);
+ void clear_interrupt(uint8_t mask);
+
+ TIMER_CALLBACK_MEMBER(msec_tick);
+
+ virtual unsigned const ram_size() { return 32; }
+
+ std::unique_ptr<uint8_t[]> m_ram;
+ uint8_t m_tscr;
+ uint8_t m_pfr;
+ uint8_t m_millis;
+
+ emu_timer *m_timer;
+
+ devcb_write_line m_intr_cb;
+ devcb_write_line m_mfo_cb;
+};
+
+class dp8572a_device : public dp8573a_device
+{
+public:
+ dp8572a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void write(offs_t offset, uint8_t data) override;
+ virtual uint8_t read(offs_t offset) override;
+
+protected:
+ virtual unsigned const ram_size() override { return 64; }
+};
+
+DECLARE_DEVICE_TYPE(DP8572A, dp8572a_device)
+DECLARE_DEVICE_TYPE(DP8573A, dp8573a_device)
+
+#endif // DEVICES_MACHINE_DP8573_H
diff --git a/src/devices/machine/ds1204.cpp b/src/devices/machine/ds1204.cpp
index ba86725df66..df4600e82d1 100644
--- a/src/devices/machine/ds1204.cpp
+++ b/src/devices/machine/ds1204.cpp
@@ -10,7 +10,9 @@
#include "emu.h"
#include "ds1204.h"
+#include <cstdarg>
#include <cstdio>
+#include <tuple>
#define VERBOSE_LEVEL ( 0 )
@@ -20,7 +22,7 @@ inline void ATTR_PRINTF( 3, 4 ) ds1204_device::verboselog( int n_level, const ch
if( VERBOSE_LEVEL >= n_level )
{
va_list v;
- char buf[ 32768 ];
+ char buf[32768];
va_start( v, s_fmt );
vsprintf( buf, s_fmt, v );
va_end( v );
@@ -91,20 +93,46 @@ void ds1204_device::nvram_default()
}
}
-void ds1204_device::nvram_read( emu_file &file )
+bool ds1204_device::nvram_read( util::read_stream &file )
{
- file.read( m_unique_pattern, sizeof( m_unique_pattern ) );
- file.read( m_identification, sizeof( m_identification ) );
- file.read( m_security_match, sizeof( m_security_match ) );
- file.read( m_secure_memory, sizeof( m_secure_memory ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = read( file, m_unique_pattern, sizeof( m_unique_pattern ) );
+ if( err || ( sizeof( m_unique_pattern ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_identification, sizeof( m_identification ) );
+ if( err || ( sizeof( m_identification ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_security_match, sizeof( m_security_match ) );
+ if( err || ( sizeof( m_security_match ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_secure_memory, sizeof( m_secure_memory ) );
+ if( err || ( sizeof( m_secure_memory ) != actual ) )
+ return false;
+
+ return true;
}
-void ds1204_device::nvram_write( emu_file &file )
+bool ds1204_device::nvram_write( util::write_stream &file )
{
- file.write( m_unique_pattern, sizeof( m_unique_pattern ) );
- file.write( m_identification, sizeof( m_identification ) );
- file.write( m_security_match, sizeof( m_security_match ) );
- file.write( m_secure_memory, sizeof( m_secure_memory ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = write( file, m_unique_pattern, sizeof( m_unique_pattern ) );
+ if( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_identification, sizeof( m_identification ) );
+ if( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_security_match, sizeof( m_security_match ) );
+ if( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_secure_memory, sizeof( m_secure_memory ) );
+ if( err )
+ return false;
+
+ return true;
}
void ds1204_device::new_state( int state )
@@ -122,11 +150,11 @@ void ds1204_device::writebit( uint8_t *buffer )
if( m_dqw )
{
- buffer[ index ] |= mask;
+ buffer[index] |= mask;
}
else
{
- buffer[ index ] &= ~mask;
+ buffer[index] &= ~mask;
}
m_bit++;
@@ -140,7 +168,7 @@ void ds1204_device::readbit( uint8_t *buffer )
int index = m_bit / 8;
int mask = 1 << ( m_bit % 8 );
- if( buffer[ index ] & mask )
+ if( buffer[index] & mask )
{
m_dqr = 1;
}
@@ -155,7 +183,7 @@ void ds1204_device::readbit( uint8_t *buffer )
}
}
-WRITE_LINE_MEMBER( ds1204_device::write_rst )
+void ds1204_device::write_rst(int state)
{
if( m_rst != state )
{
@@ -187,7 +215,7 @@ WRITE_LINE_MEMBER( ds1204_device::write_rst )
}
}
-WRITE_LINE_MEMBER( ds1204_device::write_clk )
+void ds1204_device::write_clk(int state)
{
if( m_clk != state )
{
@@ -207,17 +235,17 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
if( m_bit == 24 )
{
verboselog( 1, "-> command %02x %02x %02x (%02x %02x)\n",
- m_command[ 0 ], m_command[ 1 ], m_command[ 2 ], m_unique_pattern[ 0 ], m_unique_pattern[ 1 ] );
+ m_command[0], m_command[1], m_command[2], m_unique_pattern[0], m_unique_pattern[1] );
- if( m_command[ 0 ] == COMMAND_READ && m_command[ 1 ] == ( m_unique_pattern[ 0 ] | CYCLE_NORMAL ) && m_command[ 2 ] == m_unique_pattern[ 1 ] )
+ if( m_command[0] == COMMAND_READ && m_command[1] == ( m_unique_pattern[0] | CYCLE_NORMAL ) && m_command[2] == m_unique_pattern[1] )
{
new_state( STATE_READ_IDENTIFICATION );
}
- else if( m_command[ 0 ] == COMMAND_WRITE && m_command[ 1 ] == ( m_unique_pattern[ 0 ] | CYCLE_NORMAL ) && m_command[ 2 ] == m_unique_pattern[ 1 ] )
+ else if( m_command[0] == COMMAND_WRITE && m_command[1] == ( m_unique_pattern[0] | CYCLE_NORMAL ) && m_command[2] == m_unique_pattern[1] )
{
new_state( STATE_READ_IDENTIFICATION );
}
- else if( m_command[ 0 ] == COMMAND_WRITE && m_command[ 1 ] == ( m_unique_pattern[ 0 ] | CYCLE_PROGRAM ) && m_command[ 2 ] == m_unique_pattern[ 1 ] )
+ else if( m_command[0] == COMMAND_WRITE && m_command[1] == ( m_unique_pattern[0] | CYCLE_PROGRAM ) && m_command[2] == m_unique_pattern[1] )
{
new_state( STATE_WRITE_IDENTIFICATION );
}
@@ -234,8 +262,8 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
if( m_bit == 64 )
{
verboselog( 1, "<- identification %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ],
- m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ] );
+ m_identification[0], m_identification[1], m_identification[2], m_identification[3],
+ m_identification[4], m_identification[5], m_identification[6], m_identification[7] );
new_state( STATE_WRITE_COMPARE_REGISTER );
}
@@ -247,14 +275,14 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
if( m_bit == 64 )
{
verboselog( 1, "-> compare register %02x %02x %02x %02x %02x %02x %02x %02x (%02x %02x %02x %02x %02x %02x %02x %02x)\n",
- m_compare_register[ 0 ], m_compare_register[ 1 ], m_compare_register[ 2 ], m_compare_register[ 3 ],
- m_compare_register[ 4 ], m_compare_register[ 5 ], m_compare_register[ 6 ], m_compare_register[ 7 ],
- m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ],
- m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ] );
+ m_compare_register[0], m_compare_register[1], m_compare_register[2], m_compare_register[3],
+ m_compare_register[4], m_compare_register[5], m_compare_register[6], m_compare_register[7],
+ m_security_match[0], m_security_match[1], m_security_match[2], m_security_match[3],
+ m_security_match[4], m_security_match[5], m_security_match[6], m_security_match[7] );
if( memcmp( m_compare_register, m_security_match, sizeof( m_compare_register ) ) == 0 )
{
- if( m_command[ 0 ] == COMMAND_READ )
+ if( m_command[0] == COMMAND_READ )
{
new_state( STATE_READ_SECURE_MEMORY );
}
@@ -276,10 +304,10 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
if( m_bit == 128 )
{
verboselog( 1, "<- secure memory %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_secure_memory[ 0 ], m_secure_memory[ 1 ], m_secure_memory[ 2 ], m_secure_memory[ 3 ],
- m_secure_memory[ 4 ], m_secure_memory[ 5 ], m_secure_memory[ 6 ], m_secure_memory[ 7 ],
- m_secure_memory[ 8 ], m_secure_memory[ 9 ], m_secure_memory[ 10 ], m_secure_memory[ 11 ],
- m_secure_memory[ 12 ], m_secure_memory[ 13 ], m_secure_memory[ 14 ], m_secure_memory[ 15 ] );
+ m_secure_memory[0], m_secure_memory[1], m_secure_memory[2], m_secure_memory[3],
+ m_secure_memory[4], m_secure_memory[5], m_secure_memory[6], m_secure_memory[7],
+ m_secure_memory[8], m_secure_memory[9], m_secure_memory[10], m_secure_memory[11],
+ m_secure_memory[12], m_secure_memory[13], m_secure_memory[14], m_secure_memory[15] );
new_state( STATE_STOP );
}
@@ -291,10 +319,10 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
if( m_bit == 128 )
{
verboselog( 1, "-> secure memory %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_secure_memory[ 0 ], m_secure_memory[ 1 ], m_secure_memory[ 2 ], m_secure_memory[ 3 ],
- m_secure_memory[ 4 ], m_secure_memory[ 5 ], m_secure_memory[ 6 ], m_secure_memory[ 7 ],
- m_secure_memory[ 8 ], m_secure_memory[ 9 ], m_secure_memory[ 10 ], m_secure_memory[ 11 ],
- m_secure_memory[ 12 ], m_secure_memory[ 13 ], m_secure_memory[ 14 ], m_secure_memory[ 15 ] );
+ m_secure_memory[0], m_secure_memory[1], m_secure_memory[2], m_secure_memory[3],
+ m_secure_memory[4], m_secure_memory[5], m_secure_memory[6], m_secure_memory[7],
+ m_secure_memory[8], m_secure_memory[9], m_secure_memory[10], m_secure_memory[11],
+ m_secure_memory[12], m_secure_memory[13], m_secure_memory[14], m_secure_memory[15] );
new_state( STATE_STOP );
}
@@ -306,8 +334,8 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
if( m_bit == 64 )
{
verboselog( 1, "-> identification %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ],
- m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ] );
+ m_identification[0], m_identification[1], m_identification[2], m_identification[3],
+ m_identification[4], m_identification[5], m_identification[6], m_identification[7] );
new_state( STATE_WRITE_SECURITY_MATCH );
}
@@ -319,27 +347,27 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
if( m_bit == 64 )
{
verboselog( 1, ">- security match %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ],
- m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ] );
+ m_security_match[0], m_security_match[1], m_security_match[2], m_security_match[3],
+ m_security_match[4], m_security_match[5], m_security_match[6], m_security_match[7] );
new_state( STATE_STOP );
}
break;
case STATE_OUTPUT_GARBLED_DATA:
- if( !m_clk && m_command[ 0 ] == COMMAND_READ )
+ if( !m_clk && m_command[0] == COMMAND_READ )
{
m_dqr = machine().rand() & 1;
m_bit++;
}
- else if( m_clk && m_command[ 0 ] == COMMAND_WRITE )
+ else if( m_clk && m_command[0] == COMMAND_WRITE )
{
m_bit++;
}
if( m_bit == 64 )
{
- if( m_command[ 0 ] == COMMAND_READ )
+ if( m_command[0] == COMMAND_READ )
{
verboselog( 1, "<- random\n" );
}
@@ -355,7 +383,7 @@ WRITE_LINE_MEMBER( ds1204_device::write_clk )
}
}
-WRITE_LINE_MEMBER( ds1204_device::write_dq )
+void ds1204_device::write_dq(int state)
{
if( m_dqw != state )
{
@@ -365,7 +393,7 @@ WRITE_LINE_MEMBER( ds1204_device::write_dq )
}
}
-READ_LINE_MEMBER( ds1204_device::read_dq )
+int ds1204_device::read_dq()
{
if( m_dqr == DQ_HIGH_IMPEDANCE )
{
diff --git a/src/devices/machine/ds1204.h b/src/devices/machine/ds1204.h
index 59dc5718989..fd7b9f8b39f 100644
--- a/src/devices/machine/ds1204.h
+++ b/src/devices/machine/ds1204.h
@@ -19,10 +19,10 @@ public:
// construction/destruction
ds1204_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0 );
- DECLARE_WRITE_LINE_MEMBER( write_rst );
- DECLARE_WRITE_LINE_MEMBER( write_clk );
- DECLARE_WRITE_LINE_MEMBER( write_dq );
- DECLARE_READ_LINE_MEMBER( read_dq );
+ void write_rst(int state);
+ void write_clk(int state);
+ void write_dq(int state);
+ int read_dq();
protected:
// device-level overrides
@@ -30,8 +30,8 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read( emu_file &file ) override;
- virtual void nvram_write( emu_file &file ) override;
+ virtual bool nvram_read( util::read_stream &file ) override;
+ virtual bool nvram_write( util::write_stream &file ) override;
private:
inline void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, const char *s_fmt, ... );
diff --git a/src/devices/machine/ds1205.cpp b/src/devices/machine/ds1205.cpp
index 460d267928a..034b99719f5 100644
--- a/src/devices/machine/ds1205.cpp
+++ b/src/devices/machine/ds1205.cpp
@@ -10,7 +10,9 @@
#include "emu.h"
#include "ds1205.h"
+#include <cstdarg>
#include <cstdio>
+#include <tuple>
#define VERBOSE_LEVEL ( 0 )
@@ -20,7 +22,7 @@ inline void ATTR_PRINTF( 3, 4 ) ds1205_device::verboselog( int n_level, const ch
if( VERBOSE_LEVEL >= n_level )
{
va_list v;
- char buf[ 32768 ];
+ char buf[32768];
va_start( v, s_fmt );
vsprintf( buf, s_fmt, v );
va_end( v );
@@ -93,24 +95,46 @@ void ds1205_device::nvram_default()
}
}
-void ds1205_device::nvram_read( emu_file &file )
+bool ds1205_device::nvram_read( util::read_stream &file )
{
+ std::error_condition err;
+ size_t actual;
+
for(int i = 0; i < 3; i++)
{
- file.read( m_identification[i], sizeof( m_identification[i] ) );
- file.read( m_security_match[i], sizeof( m_security_match[i] ) );
- file.read( m_secure_memory[i], sizeof( m_secure_memory[i] ) );
+ std::tie( err, actual ) = read( file, m_identification[i], sizeof( m_identification[i] ) );
+ if( err || ( sizeof( m_identification[i] ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_security_match[i], sizeof( m_security_match[i] ) );
+ if( err || ( sizeof( m_security_match[i] ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_secure_memory[i], sizeof( m_secure_memory[i] ) );
+ if( err || ( sizeof( m_secure_memory[i] ) != actual ) )
+ return false;
}
+
+ return true;
}
-void ds1205_device::nvram_write( emu_file &file )
+bool ds1205_device::nvram_write( util::write_stream &file )
{
+ std::error_condition err;
+ size_t actual;
+
for(int i = 0; i < 3; i++)
{
- file.write( m_identification[i], sizeof( m_identification[i] ) );
- file.write( m_security_match[i], sizeof( m_security_match[i] ) );
- file.write( m_secure_memory[i], sizeof( m_secure_memory[i] ) );
+ std::tie( err, actual ) = write( file, m_identification[i], sizeof( m_identification[i] ) );
+ if( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_security_match[i], sizeof( m_security_match[i] ) );
+ if( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_secure_memory[i], sizeof( m_secure_memory[i] ) );
+ if( err )
+ return false;
}
+
+ return true;
}
void ds1205_device::new_state( int state )
@@ -128,11 +152,11 @@ void ds1205_device::writebit( u8 *buffer )
if( m_dqw )
{
- buffer[ index ] |= mask;
+ buffer[index] |= mask;
}
else
{
- buffer[ index ] &= ~mask;
+ buffer[index] &= ~mask;
}
m_bit++;
@@ -146,7 +170,7 @@ void ds1205_device::readbit( u8 *buffer )
int index = m_bit / 8;
int mask = 1 << ( m_bit % 8 );
- if( buffer[ index ] & mask )
+ if( buffer[index] & mask )
{
m_dqr = 1;
}
@@ -161,7 +185,7 @@ void ds1205_device::readbit( u8 *buffer )
}
}
-WRITE_LINE_MEMBER( ds1205_device::write_rst )
+void ds1205_device::write_rst(int state)
{
if( m_rst != state )
{
@@ -193,7 +217,7 @@ WRITE_LINE_MEMBER( ds1205_device::write_rst )
}
}
-WRITE_LINE_MEMBER( ds1205_device::write_clk )
+void ds1205_device::write_clk(int state)
{
if( m_clk != state )
{
@@ -213,17 +237,17 @@ WRITE_LINE_MEMBER( ds1205_device::write_clk )
if( m_bit == 24 )
{
verboselog( 1, "-> command %02x %02x %02x\n",
- m_command[ 0 ], m_command[ 1 ], m_command[ 2 ] );
+ m_command[0], m_command[1], m_command[2] );
- if( m_command[ 0 ] == COMMAND_GET_SCRATCHPAD && (m_command[ 1 ] & 0xc0) == 0xc0 && m_command[ 1 ] == ( ~m_command[ 2 ] & 0xff ) )
+ if( m_command[0] == COMMAND_GET_SCRATCHPAD && (m_command[1] & 0xc0) == 0xc0 && m_command[1] == ( ~m_command[2] & 0xff ) )
{
new_state( STATE_READ_SCRATCH );
}
- else if( m_command[ 0 ] == COMMAND_GET_DATA && (m_command[ 1 ] & 0xc0) != 0xc0 && (m_command[ 1 ] & 0x3f) >= 0x10 && m_command[ 1 ] == ( ~m_command[ 2 ] & 0xff ) )
+ else if( m_command[0] == COMMAND_GET_DATA && (m_command[1] & 0xc0) != 0xc0 && (m_command[1] & 0x3f) >= 0x10 && m_command[1] == ( ~m_command[2] & 0xff ) )
{
new_state( STATE_READ_IDENTIFICATION );
}
- else if( m_command[ 0 ] == COMMAND_SET_SECURITY && (m_command[ 1 ] & 0xc0) != 0xc0 && !(m_command [ 1 ] & 0x3f) && m_command[ 1 ] == ( ~m_command[ 2 ] & 0xff ) )
+ else if( m_command[0] == COMMAND_SET_SECURITY && (m_command[1] & 0xc0) != 0xc0 && !(m_command[1] & 0x3f) && m_command[1] == ( ~m_command[2] & 0xff ) )
{
new_state( STATE_READ_IDENTIFICATION );
}
@@ -235,14 +259,14 @@ WRITE_LINE_MEMBER( ds1205_device::write_clk )
break;
case STATE_READ_IDENTIFICATION:
- readbit( m_identification[ m_command[ 1 ] >> 6 ] );
+ readbit( m_identification[m_command[1] >> 6] );
if( m_bit == 64 )
{
- int page = m_command [ 1 ] >> 6;
+ int page = m_command [1] >> 6;
verboselog( 1, "<- identification %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_identification[ page ][ 0 ], m_identification[ page ][ 1 ], m_identification[ page ][ 2 ], m_identification[ page ][ 3 ],
- m_identification[ page ][ 4 ], m_identification[ page ][ 5 ], m_identification[ page ][ 6 ], m_identification[ page ][ 7 ] );
+ m_identification[page][0], m_identification[page][1], m_identification[page][2], m_identification[page][3],
+ m_identification[page][4], m_identification[page][5], m_identification[page][6], m_identification[page][7] );
new_state( STATE_WRITE_COMPARE_REGISTER );
}
@@ -253,24 +277,24 @@ WRITE_LINE_MEMBER( ds1205_device::write_clk )
if( m_bit == 64 )
{
- int page = m_command[ 1 ] >> 6;
+ int page = m_command[1] >> 6;
verboselog( 1, "-> compare register %02x %02x %02x %02x %02x %02x %02x %02x (%02x %02x %02x %02x %02x %02x %02x %02x)\n",
- m_compare_register[ 0 ], m_compare_register[ 1 ], m_compare_register[ 2 ], m_compare_register[ 3 ],
- m_compare_register[ 4 ], m_compare_register[ 5 ], m_compare_register[ 6 ], m_compare_register[ 7 ],
- m_security_match[ page ][ 0 ], m_security_match[ page ][ 1 ], m_security_match[ page ][ 2 ], m_security_match[ page ][ 3 ],
- m_security_match[ page ][ 4 ], m_security_match[ page ][ 5 ], m_security_match[ page ][ 6 ], m_security_match[ page ][ 7 ] );
+ m_compare_register[0], m_compare_register[1], m_compare_register[2], m_compare_register[3],
+ m_compare_register[4], m_compare_register[5], m_compare_register[6], m_compare_register[7],
+ m_security_match[page][0], m_security_match[page][1], m_security_match[page][2], m_security_match[page][3],
+ m_security_match[page][4], m_security_match[page][5], m_security_match[page][6], m_security_match[page][7] );
- if( memcmp( m_compare_register, m_security_match[ page ], sizeof( m_compare_register ) ) == 0 )
+ if( memcmp( m_compare_register, m_security_match[page], sizeof( m_compare_register ) ) == 0 )
{
- if( m_command[ 0 ] == COMMAND_GET_DATA )
+ if( m_command[0] == COMMAND_GET_DATA )
{
new_state( STATE_READ_DATA );
}
- else if( m_command[ 0 ] == COMMAND_GET_SCRATCHPAD)
+ else if( m_command[0] == COMMAND_GET_SCRATCHPAD)
{
new_state( STATE_READ_SCRATCH );
}
- else if( m_command[ 0 ] == COMMAND_SET_SECURITY)
+ else if( m_command[0] == COMMAND_SET_SECURITY)
{
new_state( STATE_WRITE_IDENTIFICATION );
}
@@ -283,16 +307,16 @@ WRITE_LINE_MEMBER( ds1205_device::write_clk )
break;
case STATE_READ_DATA:
- readbit( m_secure_memory[ m_command[ 1 ] >> 6 ] );
+ readbit( m_secure_memory[m_command[1] >> 6] );
if( m_bit == 384 )
{
- int page = m_command [ 1 ] >> 6;
+ int page = m_command[1] >> 6;
verboselog( 1, "<- secure memory %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_secure_memory[ page ][ 0 ], m_secure_memory[ page ][ 1 ], m_secure_memory[ page ][ 2 ], m_secure_memory[ page ][ 3 ],
- m_secure_memory[ page ][ 4 ], m_secure_memory[ page ][ 5 ], m_secure_memory[ page ][ 6 ], m_secure_memory[ page ][ 7 ],
- m_secure_memory[ page ][ 8 ], m_secure_memory[ page ][ 9 ], m_secure_memory[ page ][ 10 ], m_secure_memory[ page ][ 11 ],
- m_secure_memory[ page ][ 12 ], m_secure_memory[ page ][ 13 ], m_secure_memory[ page ][ 14 ], m_secure_memory[ page ][ 15 ] );
+ m_secure_memory[page][0], m_secure_memory[page][1], m_secure_memory[page][2], m_secure_memory[page][3],
+ m_secure_memory[page][4], m_secure_memory[page][5], m_secure_memory[page][6], m_secure_memory[page][7],
+ m_secure_memory[page][8], m_secure_memory[page][9], m_secure_memory[page][10], m_secure_memory[page][11],
+ m_secure_memory[page][12], m_secure_memory[page][13], m_secure_memory[page][14], m_secure_memory[page][15] );
new_state( STATE_STOP );
}
@@ -304,57 +328,57 @@ WRITE_LINE_MEMBER( ds1205_device::write_clk )
if( m_bit == 512 )
{
verboselog( 1, "<- scratchpad %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_scratchpad[ 0 ], m_scratchpad[ 1 ], m_scratchpad[ 2 ], m_scratchpad[ 3 ],
- m_scratchpad[ 4 ], m_scratchpad[ 5 ], m_scratchpad[ 6 ], m_scratchpad[ 7 ],
- m_scratchpad[ 8 ], m_scratchpad[ 9 ], m_scratchpad[ 10 ], m_scratchpad[ 11 ],
- m_scratchpad[ 12 ], m_scratchpad[ 13 ], m_scratchpad[ 14 ], m_scratchpad[ 15 ] );
+ m_scratchpad[0], m_scratchpad[1], m_scratchpad[2], m_scratchpad[3],
+ m_scratchpad[4], m_scratchpad[5], m_scratchpad[6], m_scratchpad[7],
+ m_scratchpad[8], m_scratchpad[9], m_scratchpad[10], m_scratchpad[11],
+ m_scratchpad[12], m_scratchpad[13], m_scratchpad[14], m_scratchpad[15] );
new_state( STATE_STOP );
}
break;
case STATE_WRITE_IDENTIFICATION:
- writebit( m_identification[ m_command[ 1 ] >> 6 ] );
+ writebit( m_identification[m_command[1] >> 6] );
if( m_bit == 64 )
{
- int page = m_command[ 1 ] >> 6;
+ int page = m_command[1] >> 6;
verboselog( 1, "-> identification %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_identification[ page ][ 0 ], m_identification[ page ][ 1 ], m_identification[ page ][ 2 ], m_identification[ page ][ 3 ],
- m_identification[ page ][ 4 ], m_identification[ page ][ 5 ], m_identification[ page ][ 6 ], m_identification[ page ][ 7 ] );
+ m_identification[page][0], m_identification[page][1], m_identification[page][2], m_identification[page][3],
+ m_identification[page][4], m_identification[page][5], m_identification[page][6], m_identification[page][7] );
new_state( STATE_WRITE_SECURITY_MATCH );
}
break;
case STATE_WRITE_SECURITY_MATCH:
- writebit( m_security_match[ m_command[ 1 ] >> 6 ] );
+ writebit( m_security_match[m_command[1] >> 6] );
if( m_bit == 64 )
{
- int page = m_command[ 1 ] >> 6;
+ int page = m_command[1] >> 6;
verboselog( 1, ">- security match %02x %02x %02x %02x %02x %02x %02x %02x\n",
- m_security_match[ page ][ 0 ], m_security_match[ page ][ 1 ], m_security_match[ page ][ 2 ], m_security_match[ page ][ 3 ],
- m_security_match[ page ][ 4 ], m_security_match[ page ][ 5 ], m_security_match[ page ][ 6 ], m_security_match[ page ][ 7 ] );
+ m_security_match[page][0], m_security_match[page][1], m_security_match[page][2], m_security_match[page][3],
+ m_security_match[page][4], m_security_match[page][5], m_security_match[page][6], m_security_match[page][7] );
new_state( STATE_STOP );
}
break;
case STATE_OUTPUT_GARBLED_DATA:
- if( !m_clk && m_command[ 0 ] == COMMAND_GET_DATA )
+ if( !m_clk && m_command[0] == COMMAND_GET_DATA )
{
m_dqr = machine().rand() & 1;
m_bit++;
}
- else if( m_clk && m_command[ 0 ] == COMMAND_SET_DATA )
+ else if( m_clk && m_command[0] == COMMAND_SET_DATA )
{
m_bit++;
}
if( m_bit == 64 )
{
- if( m_command[ 0 ] == COMMAND_GET_DATA )
+ if( m_command[0] == COMMAND_GET_DATA )
{
verboselog( 1, "<- random\n" );
}
@@ -370,7 +394,7 @@ WRITE_LINE_MEMBER( ds1205_device::write_clk )
}
}
-WRITE_LINE_MEMBER( ds1205_device::write_dq )
+void ds1205_device::write_dq(int state)
{
if( m_dqw != state )
{
@@ -380,7 +404,7 @@ WRITE_LINE_MEMBER( ds1205_device::write_dq )
}
}
-READ_LINE_MEMBER( ds1205_device::read_dq )
+int ds1205_device::read_dq()
{
if( m_dqr == DQ_HIGH_IMPEDANCE )
{
diff --git a/src/devices/machine/ds1205.h b/src/devices/machine/ds1205.h
index ad7432e1ac7..f406fa428ca 100644
--- a/src/devices/machine/ds1205.h
+++ b/src/devices/machine/ds1205.h
@@ -19,10 +19,10 @@ public:
// construction/destruction
ds1205_device( const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
- DECLARE_WRITE_LINE_MEMBER( write_rst );
- DECLARE_WRITE_LINE_MEMBER( write_clk );
- DECLARE_WRITE_LINE_MEMBER( write_dq );
- DECLARE_READ_LINE_MEMBER( read_dq );
+ void write_rst(int state);
+ void write_clk(int state);
+ void write_dq(int state);
+ int read_dq();
protected:
// device-level overrides
@@ -30,8 +30,8 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read( emu_file &file ) override;
- virtual void nvram_write( emu_file &file ) override;
+ virtual bool nvram_read( util::read_stream &file ) override;
+ virtual bool nvram_write( util::write_stream &file ) override;
private:
inline void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, const char *s_fmt, ... );
diff --git a/src/devices/machine/ds1207.cpp b/src/devices/machine/ds1207.cpp
new file mode 100644
index 00000000000..805f15c730d
--- /dev/null
+++ b/src/devices/machine/ds1207.cpp
@@ -0,0 +1,682 @@
+// license:BSD-3-Clause
+// copyright-holders:Paul-Arnold
+/*
+ * ds1207.c
+ *
+ * Time Key
+ *
+ * Based on ds1204 by smf.
+ *
+ * File format is as follows:
+ * 00-01 unique command pattern
+ * 02-09 identification pattern
+ * 0a-11 security match
+ * 12-41 secure memory data
+ * 42-43 days left
+ * 44-4b start time (from time_t)
+ * 4c control
+ *
+ * Control bits:
+ * bit 0 - OSC ENABLED
+ * bit 1 - OSC RUNNING
+ * bit 2 - DAYS LOCKED
+ * bit 3 - DAYS EXPIRED
+ *
+ * The unique command pattern can be user specific but a number of off the shelf devices exist.
+ * For these devices the pattern should be as follows:
+ * DS1207-G01 0x00 0xb0
+ * DS1207-G02 0x04 0xb0
+ * DS1207-G03 0x08 0xb0
+ * DS1207-G04 0x0c 0xb0
+ * DS1207-G05 0x10 0xb0
+ */
+#include "emu.h"
+#include "ds1207.h"
+
+#include <tuple>
+
+#define LOG_LINES (1U << 1)
+#define LOG_STATE (1U << 2)
+#define LOG_DATA (1U << 3)
+
+//#define VERBOSE (LOG_LINES | LOG_STATE | LOG_DATA)
+#include "logmacro.h"
+
+#define LOGLINES(...) LOGMASKED(LOG_LINES, __VA_ARGS__)
+#define LOGSTATE(...) LOGMASKED(LOG_STATE, __VA_ARGS__)
+#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__)
+
+// device type definition
+DEFINE_DEVICE_TYPE(DS1207, ds1207_device, "ds1207", "DS1207 Time Key")
+
+ds1207_device::ds1207_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, DS1207, tag, owner, clock),
+ device_nvram_interface(mconfig, *this),
+ device_rtc_interface(mconfig, *this),
+ m_region(*this, DEVICE_SELF),
+ m_rst(0),
+ m_clk(0),
+ m_dqw(0), m_dqr(0), m_state(0), m_bit(0)
+{
+}
+
+void ds1207_device::device_reset()
+{
+ adjust_days_left(); // compensate for time machine has been turned off
+}
+
+void ds1207_device::device_start()
+{
+ new_state(STATE_STOP);
+ m_dqr = DQ_HIGH_IMPEDANCE;
+
+ std::fill_n(m_command, std::size(m_command), 0);
+ std::fill_n(m_compare_register, std::size(m_compare_register), 0);
+ m_last_update_time = 0;
+ m_startup_time = 0;
+ std::fill_n(m_day_clock, std::size(m_day_clock), 0);
+
+ save_item(NAME(m_rst));
+ save_item(NAME(m_clk));
+ save_item(NAME(m_dqw));
+ save_item(NAME(m_dqr));
+ save_item(NAME(m_state));
+ save_item(NAME(m_bit));
+ save_item(NAME(m_command));
+ save_item(NAME(m_compare_register));
+ save_item(NAME(m_unique_pattern));
+ save_item(NAME(m_identification));
+ save_item(NAME(m_security_match));
+ save_item(NAME(m_secure_memory));
+ save_item(NAME(m_day_clock));
+ save_item(NAME(m_days_left));
+ save_item(NAME(m_start_time));
+ save_item(NAME(m_device_state));
+ save_item(NAME(m_startup_time));
+ save_item(NAME(m_last_update_time));
+}
+
+void ds1207_device::nvram_default()
+{
+ std::fill_n(m_unique_pattern, std::size(m_unique_pattern), 0);
+ std::fill_n(m_identification, std::size(m_identification), 0);
+ std::fill_n(m_security_match, std::size(m_security_match), 0);
+ std::fill_n(m_secure_memory, std::size(m_secure_memory), 0);
+ std::fill_n(m_days_left, std::size(m_days_left), 0);
+ std::fill_n(m_start_time, std::size(m_start_time), 0);
+ m_device_state = 0;
+
+ int expected_bytes = sizeof(m_unique_pattern) + sizeof(m_identification) + sizeof(m_security_match) + sizeof(m_secure_memory)
+ + sizeof(m_days_left) + sizeof(m_start_time) + sizeof(m_device_state);
+
+ if(!m_region.found())
+ {
+ logerror("ds1207(%s) region not found\n", tag());
+ }
+ else if(m_region->bytes() != expected_bytes)
+ {
+ logerror("ds1207(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_bytes);
+ }
+ else
+ {
+ uint8_t *region = m_region->base();
+
+ memcpy(m_unique_pattern, region, sizeof(m_unique_pattern));
+ region += sizeof(m_unique_pattern);
+ memcpy(m_identification, region, sizeof(m_identification));
+ region += sizeof(m_identification);
+ memcpy(m_security_match, region, sizeof(m_security_match));
+ region += sizeof(m_security_match);
+ memcpy(m_secure_memory, region, sizeof(m_secure_memory));
+ region += sizeof(m_secure_memory);
+ memcpy(m_days_left, region, sizeof(m_days_left));
+ region += sizeof(m_days_left);
+ memcpy(m_start_time, region, sizeof(m_start_time));
+ region += sizeof(m_start_time);
+ memcpy(&m_device_state, region, sizeof(m_device_state));
+ region += sizeof(m_device_state);
+ }
+}
+
+bool ds1207_device::nvram_read(util::read_stream &file)
+{
+ std::error_condition err;
+ size_t actual;
+
+ std::tie(err, actual) = read(file, m_unique_pattern, sizeof(m_unique_pattern));
+ if (err || (sizeof(m_unique_pattern) != actual))
+ return false;
+ std::tie(err, actual) = read(file, m_identification, sizeof(m_identification));
+ if (err || (sizeof(m_identification) != actual))
+ return false;
+ std::tie(err, actual) = read(file, m_security_match, sizeof(m_security_match));
+ if (err || (sizeof(m_security_match) != actual))
+ return false;
+ std::tie(err, actual) = read(file, m_secure_memory, sizeof(m_secure_memory));
+ if (err || (sizeof(m_secure_memory) != actual))
+ return false;
+ std::tie(err, actual) = read(file, m_days_left, sizeof(m_days_left));
+ if (err || (sizeof(m_days_left) != actual))
+ return false;
+ std::tie(err, actual) = read(file, m_start_time, sizeof(m_start_time));
+ if (err || (sizeof(m_start_time) != actual))
+ return false;
+ std::tie(err, actual) = read(file, &m_device_state, sizeof(m_device_state));
+ if (err || (sizeof(m_device_state) != actual))
+ return false;
+
+ return true;
+}
+
+bool ds1207_device::nvram_write(util::write_stream &file)
+{
+ std::error_condition err;
+ size_t actual;
+
+ std::tie(err, actual) = write(file, m_unique_pattern, sizeof(m_unique_pattern));
+ if (err)
+ return false;
+ std::tie(err, actual) = write(file, m_identification, sizeof(m_identification));
+ if (err)
+ return false;
+ std::tie(err, actual) = write(file, m_security_match, sizeof(m_security_match));
+ if (err)
+ return false;
+ std::tie(err, actual) = write(file, m_secure_memory, sizeof(m_secure_memory));
+ if (err)
+ return false;
+ std::tie(err, actual) = write(file, m_days_left, sizeof(m_days_left));
+ if (err)
+ return false;
+ std::tie(err, actual) = write(file, m_start_time, sizeof(m_start_time));
+ if (err)
+ return false;
+ std::tie(err, actual) = write(file, &m_device_state, sizeof(m_device_state));
+ if (err)
+ return false;
+
+ return true;
+}
+
+void ds1207_device::new_state(uint8_t state)
+{
+ m_state = state;
+ m_bit = 0;
+}
+
+void ds1207_device::writebit(uint8_t *buffer)
+{
+ if(m_clk)
+ {
+ uint16_t index = m_bit / 8;
+ uint8_t mask = 1 << (m_bit % 8);
+
+ if(m_dqw)
+ {
+ buffer[ index ] |= mask;
+ }
+ else
+ {
+ buffer[ index ] &= ~mask;
+ }
+
+ m_bit++;
+ }
+}
+
+void ds1207_device::readbit(uint8_t *buffer)
+{
+ if(!m_clk)
+ {
+ uint16_t index = m_bit / 8;
+ uint8_t mask = 1 << (m_bit % 8);
+
+ if(buffer[ index ] & mask)
+ {
+ m_dqr = 1;
+ }
+ else
+ {
+ m_dqr = 0;
+ }
+ }
+ else
+ {
+ m_bit++;
+ }
+}
+
+void ds1207_device::write_rst(int state)
+{
+ const uint8_t this_state = state ? 1 : 0;
+ if(m_rst != this_state)
+ {
+ m_rst = this_state;
+ LOGLINES("%s: DS1207 rst=%d\n", machine().describe_context(), m_rst);
+
+ if(m_rst)
+ {
+ new_state(STATE_PROTOCOL);
+ }
+ else
+ {
+ switch(m_state)
+ {
+ case STATE_WRITE_IDENTIFICATION:
+ LOGSTATE("%s: DS1207 reset during write identification (bit=%u)\n", machine().describe_context(), m_bit);
+ break;
+
+ case STATE_WRITE_SECURITY_MATCH:
+ LOGSTATE("%s: DS1207 reset during write security match (bit=%u)\n", machine().describe_context(), m_bit);
+ break;
+
+ case STATE_WRITE_SECURE_MEMORY:
+ LOGSTATE("%s: DS1207 reset during write secure memory (bit=%u)\n", machine().describe_context(), m_bit);
+ break;
+ }
+
+ new_state(STATE_STOP);
+ m_dqr = DQ_HIGH_IMPEDANCE;
+ }
+ }
+}
+
+void ds1207_device::write_clk(int state)
+{
+ const uint8_t this_state = state ? 1 : 0;
+ if(m_clk != this_state)
+ {
+ m_clk = this_state;
+ LOGLINES("%s: DS1207 clk=%d (bit=%u)\n", machine().describe_context(), m_clk, m_bit);
+
+ if(m_clk)
+ {
+ m_dqr = DQ_HIGH_IMPEDANCE;
+ }
+
+ switch(m_state)
+ {
+ case STATE_PROTOCOL:
+ writebit(m_command);
+
+ if(m_bit == 24)
+ {
+ LOGDATA("%s: DS1207 -> command %02x %02x %02x (%02x %02x)\n", machine().describe_context(),
+ m_command[ 0 ], m_command[ 1 ], m_command[ 2 ], m_unique_pattern[ 0 ], m_unique_pattern[ 1 ]);
+
+ if(m_command[ 2 ] == m_unique_pattern[ 1 ] && (m_command[ 1 ] & ~3) == m_unique_pattern[ 0 ])
+ {
+ set_start_time();
+ adjust_time_into_day();
+
+ if(m_command[ 0 ] == COMMAND_READ && (m_command[ 1 ] & 3) == CYCLE_NORMAL)
+ {
+ new_state(STATE_READ_IDENTIFICATION);
+ }
+ else if(m_command[ 0 ] == COMMAND_READ_DAY_CLOCK && (m_command[ 1 ] & 3) == CYCLE_PROGRAM)
+ {
+ new_state(STATE_READ_DAY_CLOCK);
+ }
+ else if(m_command[ 0 ] == COMMAND_READ_DAYS_REMAINING && (m_command[ 1 ] & 3) == CYCLE_PROGRAM)
+ {
+ new_state(STATE_READ_DAYS_REMAINING);
+ }
+ else if(!(m_device_state & DAYS_EXPIRED))
+ {
+ if(m_command[ 0 ] == COMMAND_WRITE && (m_command[ 1 ] & 3) == CYCLE_NORMAL)
+ {
+ new_state(STATE_READ_IDENTIFICATION);
+ }
+ else if((m_command[ 1 ] & 3) == CYCLE_PROGRAM)
+ {
+ if(m_command[ 0 ] == COMMAND_WRITE)
+ {
+ new_state(STATE_WRITE_IDENTIFICATION);
+ }
+ else if(m_command[ 0 ] == COMMAND_WRITE_DAYS_REMAINING)
+ {
+ if(!(m_device_state & DAYS_LOCKED))
+ {
+ new_state(STATE_WRITE_DAYS_REMAINING);
+ }
+ else
+ {
+ new_state(STATE_STOP);
+ }
+ }
+ else if(m_command[ 0 ] == COMMAND_LOCK_DAYS_COUNT)
+ {
+ m_device_state |= DAYS_LOCKED;
+
+ new_state(STATE_STOP);
+ }
+ else if(m_command[ 0 ] == COMMAND_STOP_OSCILLATOR)
+ {
+ if(!(m_device_state & DAYS_LOCKED))
+ {
+ m_device_state &= ~(OSC_ENABLED | OSC_RUNNING);
+ }
+
+ new_state(STATE_STOP);
+ }
+ else if(m_command[ 0 ] == COMMAND_ARM_OSCILLATOR)
+ {
+ m_device_state |= OSC_ENABLED;
+ }
+ else
+ {
+ new_state(STATE_STOP);
+ }
+ }
+ else
+ {
+ new_state(STATE_STOP);
+ }
+ }
+ else
+ {
+ new_state(STATE_STOP);
+ }
+ }
+ else
+ {
+ new_state(STATE_STOP);
+ }
+ }
+ break;
+
+ case STATE_READ_IDENTIFICATION:
+ readbit(m_identification);
+
+ if(m_bit == 64)
+ {
+ LOGDATA("%s: DS1207 <- identification %02x %02x %02x %02x %02x %02x %02x %02x\n", machine().describe_context(),
+ m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ],
+ m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ]);
+
+ new_state(STATE_WRITE_COMPARE_REGISTER);
+ }
+ break;
+
+ case STATE_WRITE_COMPARE_REGISTER:
+ writebit(m_compare_register);
+
+ if(m_bit == 64)
+ {
+ LOGDATA("%s: DS1207 -> compare register %02x %02x %02x %02x %02x %02x %02x %02x (%02x %02x %02x %02x %02x %02x %02x %02x)\n", machine().describe_context(),
+ m_compare_register[ 0 ], m_compare_register[ 1 ], m_compare_register[ 2 ], m_compare_register[ 3 ],
+ m_compare_register[ 4 ], m_compare_register[ 5 ], m_compare_register[ 6 ], m_compare_register[ 7 ],
+ m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ],
+ m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ]);
+
+ if(memcmp(m_compare_register, m_security_match, sizeof(m_compare_register)) == 0)
+ {
+ if(m_command[ 0 ] == COMMAND_READ)
+ {
+ new_state(STATE_READ_SECURE_MEMORY);
+ }
+ else
+ {
+ new_state(STATE_WRITE_SECURE_MEMORY);
+ }
+ }
+ else
+ {
+ new_state(STATE_OUTPUT_GARBLED_DATA);
+ }
+ }
+ break;
+
+ case STATE_READ_SECURE_MEMORY:
+ readbit(m_secure_memory);
+
+ if(m_bit == 384)
+ {
+ new_state(STATE_STOP);
+ }
+ break;
+
+ case STATE_WRITE_SECURE_MEMORY:
+ writebit(m_secure_memory);
+
+ if(m_bit == 384)
+ {
+ new_state(STATE_STOP);
+ }
+ break;
+
+ case STATE_WRITE_IDENTIFICATION:
+ writebit(m_identification);
+
+ if(m_bit == 64)
+ {
+ LOGDATA("%s: DS1207 -> identification %02x %02x %02x %02x %02x %02x %02x %02x\n", machine().describe_context(),
+ m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ],
+ m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ]);
+
+ new_state(STATE_WRITE_SECURITY_MATCH);
+ }
+ break;
+
+ case STATE_WRITE_SECURITY_MATCH:
+ writebit(m_security_match);
+
+ if(m_bit == 64)
+ {
+ LOGDATA("%s: DS1207 >- security match %02x %02x %02x %02x %02x %02x %02x %02x\n", machine().describe_context(),
+ m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ],
+ m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ]);
+
+ new_state(STATE_STOP);
+ }
+ break;
+
+ case STATE_OUTPUT_GARBLED_DATA:
+ if(!m_clk && m_command[ 0 ] == COMMAND_READ)
+ {
+ m_dqr = machine().rand() & 1;
+ m_bit++;
+ }
+ else if(m_clk && m_command[ 0 ] == COMMAND_WRITE)
+ {
+ m_bit++;
+ }
+
+ if(m_bit == 64)
+ {
+ if(m_command[ 0 ] == COMMAND_READ)
+ {
+ LOGDATA("%s: DS1207 <- random\n", machine().describe_context());
+ }
+ else
+ {
+ LOGDATA("%s: DS1207 -> ignore\n", machine().describe_context());
+ }
+
+ new_state(STATE_STOP);
+ }
+ break;
+
+ case STATE_READ_DAY_CLOCK:
+ readbit(m_day_clock);
+
+ if(m_bit == 20)
+ {
+ new_state(STATE_STOP);
+ }
+ break;
+
+ case STATE_READ_DAYS_REMAINING:
+ readbit(m_days_left);
+
+ if(m_bit == 9)
+ {
+ new_state(STATE_STOP);
+ }
+ break;
+
+ case STATE_WRITE_DAYS_REMAINING:
+ writebit(m_days_left);
+
+ if(m_bit == 9)
+ {
+ new_state(STATE_STOP);
+ }
+ break;
+ }
+ }
+}
+
+void ds1207_device::write_dq(int state)
+{
+ const uint8_t this_state = state ? 1 : 0;
+ if(m_dqw != this_state)
+ {
+ m_dqw = this_state;
+
+ LOGLINES("%s: DS1207 dqw=%u\n", machine().describe_context(), m_dqw);
+ }
+}
+
+int ds1207_device::read_dq()
+{
+ if(m_dqr == DQ_HIGH_IMPEDANCE)
+ {
+ LOGLINES("%s: DS1207 dqr=high impedance\n", machine().describe_context());
+ return 0;
+ }
+
+ LOGLINES("%s: DS1207 dqr=%d (bit=%u)\n", machine().describe_context(), m_dqr, m_bit);
+ return m_dqr;
+}
+
+void ds1207_device::adjust_time_into_day()
+{
+ if(!(m_device_state & DAYS_EXPIRED) && (m_device_state & OSC_ENABLED) && (m_device_state & OSC_RUNNING))
+ {
+ uint64_t day_clock = ((uint64_t)m_day_clock[ 0 ]) | (((uint64_t)m_day_clock[ 1 ]) << 8) | (((uint64_t)m_day_clock[ 2 ]) << 16);
+
+ const uint64_t cur_time = machine().time().as_ticks(32768) / 2700;
+ const uint64_t diff_time = cur_time - m_last_update_time;
+ m_last_update_time = cur_time;
+
+ day_clock += diff_time;
+
+ m_day_clock[ 0 ] = day_clock & 0xff;
+ m_day_clock[ 1 ] = (day_clock >> 8) & 0xff;
+ m_day_clock[ 2 ] = (day_clock >> 16) & 0xff;
+
+ if(day_clock >= 1048576)
+ {
+ adjust_days_left();
+ }
+ }
+}
+
+void ds1207_device::adjust_days_left()
+{
+ if(!(m_device_state & DAYS_EXPIRED) && (m_device_state & OSC_ENABLED) && (m_device_state & OSC_RUNNING))
+ {
+ const uint64_t current_time = m_startup_time + machine().time().as_ticks(1);
+
+ uint64_t start_time = 0;
+
+ for(int i = 0; i < 8 ; i++)
+ {
+ start_time <<= 8;
+ start_time |= m_start_time[ 7 - i ];
+ }
+
+ if(current_time > start_time)
+ {
+ uint64_t time_diff = current_time - start_time;
+
+ const uint16_t days_elapsed = time_diff / (24*60*60);
+
+ time_diff %= (24*60*60);// seconds into day
+
+ const uint32_t day_clock = (time_diff * 32768)/2700;// time into day
+
+ m_day_clock[ 0 ] = day_clock & 0xff;
+ m_day_clock[ 1 ] = (day_clock >> 8) & 0xff;
+ m_day_clock[ 2 ] = (day_clock >> 16) & 0xff;
+
+ if(days_elapsed > 0)
+ {
+ uint16_t days_left = m_days_left[ 0 ] | (m_days_left[ 1 ] << 8);
+
+ if(days_elapsed > days_left)
+ {
+ days_left = 0xffff;
+ m_device_state |= DAYS_EXPIRED;
+ }
+ else
+ {
+ days_left -= days_elapsed;
+ }
+
+ m_days_left[ 0 ] = days_left & 0xff;
+ m_days_left[ 1 ] = (days_left >> 8) & 0x1;
+
+ start_time += days_elapsed * 24 * 60 * 60;
+
+ for(int i = 0; i < 8 ; i++)
+ {
+ m_start_time[ i ] = (start_time >> (i * 8)) & 0xff;
+ }
+ }
+ }
+ }
+}
+
+void ds1207_device::set_start_time()
+{
+ if(!(m_device_state & DAYS_EXPIRED) && m_device_state & OSC_ENABLED && !(m_device_state & OSC_RUNNING))
+ {
+ const uint64_t current_time = m_startup_time + machine().time().as_ticks(1);
+
+ for(int i = 0; i < 8 ; i++)
+ {
+ m_start_time[ i ] = (current_time >> (i * 8)) & 0xff;
+ }
+ m_day_clock [ 0 ] = m_day_clock[ 1 ] = m_day_clock[ 2 ] = 0;
+
+ m_device_state |= OSC_RUNNING;
+ }
+}
+
+void ds1207_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ const int month_to_day_conversion[ 12 ] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+ // put the seconds
+ m_startup_time = second;
+
+ // put the minutes
+ m_startup_time += minute * 60;
+
+ // put the hours
+ m_startup_time += hour * 60 * 60;
+
+ // put the days (note -1) */
+ m_startup_time += (day - 1) * 60 * 60 * 24;
+
+ // take the months - despite popular beliefs, leap years aren't just evenly divisible by 4 */
+ if(((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)) && month > 2)
+ {
+ m_startup_time += (month_to_day_conversion[ month - 1 ] + 1) * 60 * 60 * 24;
+ }
+ else
+ {
+ m_startup_time += (month_to_day_conversion[ month - 1 ]) * 60 * 60 * 24;
+ }
+
+ // put the years
+ int year_count = (year - 1969);
+
+ for(int i = 0; i < year_count - 1 ; i++)
+ {
+ m_startup_time += (((((i+1970) % 4) == 0) && (((i+1970) % 100) != 0)) || (((i+1970) % 400) == 0)) ? 60*60*24*366 : 60*60*24*365;
+ }
+}
+
diff --git a/src/devices/machine/ds1207.h b/src/devices/machine/ds1207.h
new file mode 100644
index 00000000000..8afdeeb755d
--- /dev/null
+++ b/src/devices/machine/ds1207.h
@@ -0,0 +1,122 @@
+// license:BSD-3-Clause
+// copyright-holders:Paul-Arnold
+/*
+ * ds1207.h
+ *
+ * Time Key
+ *
+ */
+
+#ifndef MAME_MACHINE_DS1207_H
+#define MAME_MACHINE_DS1207_H
+
+#pragma once
+
+#include "dirtc.h"
+
+class ds1207_device : public device_t, public device_nvram_interface, public device_rtc_interface
+{
+public:
+ // construction/destruction
+ ds1207_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ void write_rst(int state);
+ void write_clk(int state);
+ void write_dq(int state);
+ int read_dq();
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_nvram_interface overrides
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return true; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+
+private:
+ void new_state(uint8_t state);
+ void writebit(uint8_t *buffer);
+ void readbit(uint8_t *buffer);
+ void set_start_time();
+ void adjust_days_left();
+ void adjust_time_into_day();
+
+ enum state_t
+ {
+ STATE_STOP,
+ STATE_PROTOCOL,
+ STATE_READ_IDENTIFICATION,
+ STATE_WRITE_IDENTIFICATION,
+ STATE_WRITE_COMPARE_REGISTER,
+ STATE_WRITE_SECURITY_MATCH,
+ STATE_READ_SECURE_MEMORY,
+ STATE_WRITE_SECURE_MEMORY,
+ STATE_OUTPUT_GARBLED_DATA,
+ STATE_READ_DAY_CLOCK,
+ STATE_READ_DAYS_REMAINING,
+ STATE_WRITE_DAYS_REMAINING
+ };
+
+ enum command_t
+ {
+ COMMAND_READ = 0x62,
+ COMMAND_WRITE = 0x9d,
+ COMMAND_READ_DAY_CLOCK = 0xf1,
+ COMMAND_WRITE_DAYS_REMAINING = 0xf2,
+ COMMAND_READ_DAYS_REMAINING = 0xf3,
+ COMMAND_STOP_OSCILLATOR = 0xf4,
+ COMMAND_ARM_OSCILLATOR = 0xf5,
+ COMMAND_LOCK_DAYS_COUNT = 0xf6
+ };
+
+ enum cycle_t
+ {
+ CYCLE_NORMAL = 1,
+ CYCLE_PROGRAM = 2,
+ CYCLE_MASK = 3
+ };
+
+ enum device_state_t
+ {
+ OSC_ENABLED = 1,
+ OSC_RUNNING = 2,
+ DAYS_LOCKED = 4,
+ DAYS_EXPIRED = 8
+ };
+
+ static const int8_t DQ_HIGH_IMPEDANCE = -1;
+
+ optional_memory_region m_region;
+
+ uint8_t m_rst;
+ uint8_t m_clk;
+ uint8_t m_dqw;
+ int8_t m_dqr;
+ uint8_t m_state;
+ uint16_t m_bit;
+ uint64_t m_startup_time;
+ uint64_t m_last_update_time;
+ uint8_t m_command[3];
+ uint8_t m_day_clock[3];
+ uint8_t m_compare_register[8];
+ uint8_t m_unique_pattern[2];
+ uint8_t m_identification[8];
+ uint8_t m_security_match[8];
+ uint8_t m_secure_memory[48];
+ uint8_t m_days_left[2];
+ uint8_t m_start_time[8];
+ uint8_t m_device_state;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(DS1207, ds1207_device)
+
+#endif // MAME_MACHINE_DS1207_H
diff --git a/src/devices/machine/ds128x.cpp b/src/devices/machine/ds128x.cpp
index 8292e5237f2..a4ff2c19228 100644
--- a/src/devices/machine/ds128x.cpp
+++ b/src/devices/machine/ds128x.cpp
@@ -49,12 +49,11 @@ uint8_t ds12885ext_device::read_extended(offs_t offset)
switch (offset)
{
case 0:
- case 1:
- return read(offset);
- break;
case 2:
+ return get_address();
+ case 1:
case 3:
- return read(offset - 2);
+ return data_r();
break;
default:
return 0xff;
@@ -66,16 +65,16 @@ void ds12885ext_device::write_extended(offs_t offset, uint8_t data)
switch (offset)
{
case 0:
- write(offset, data & 127);
+ address_w(data & 127);
break;
case 1:
- write(offset, data);
+ data_w(data);
break;
case 2:
- write(offset - 2, data);
+ address_w(data);
break;
case 3:
- write(offset - 2, data);
+ data_w(data);
break;
}
}
diff --git a/src/devices/machine/ds1302.cpp b/src/devices/machine/ds1302.cpp
index 57ec63f78db..5c2b90955cf 100644
--- a/src/devices/machine/ds1302.cpp
+++ b/src/devices/machine/ds1302.cpp
@@ -26,9 +26,6 @@
// MACROS / CONSTANTS
//**************************************************************************
-#define RAM_SIZE 0x1f // 31 bytes
-
-
enum
{
STATE_COMMAND,
@@ -56,7 +53,7 @@ enum
#define COMMAND_BURST (((m_cmd >> 1) & 0x1f) == 0x1f)
#define CLOCK_HALT (m_reg[REGISTER_SECONDS] & 0x80)
#define WRITE_PROTECT (m_reg[REGISTER_CONTROL] & 0x80)
-#define BURST_END (COMMAND_RAM ? 0x1f : 0x09)
+#define BURST_END (COMMAND_RAM ? m_ram_size : 0x09)
@@ -65,17 +62,34 @@ enum
//**************************************************************************
// device type definition
-DEFINE_DEVICE_TYPE(DS1302, ds1302_device, "ds1302", "DS1302 Timekeeper")
+DEFINE_DEVICE_TYPE(DS1202, ds1202_device, "ds1202", "Dallas DS1202 Serial Timekeeping Chip")
+DEFINE_DEVICE_TYPE(DS1302, ds1302_device, "ds1302", "Dallas DS1302 Trickle-Charge Timekeeping Chip")
//-------------------------------------------------
// ds1302_device - constructor
//-------------------------------------------------
-ds1302_device::ds1302_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DS1302, tag, owner, clock),
+ds1302_device::ds1302_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t ram_size)
+ : device_t(mconfig, type, tag, owner, clock),
device_rtc_interface(mconfig, *this),
- device_nvram_interface(mconfig, *this)
+ device_nvram_interface(mconfig, *this),
+ m_ram_size(ram_size)
+{
+}
+
+ds1302_device::ds1302_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ds1302_device(mconfig, DS1302, tag, owner, clock, 0x1f)
+{
+}
+
+
+//-------------------------------------------------
+// ds1202_device - constructor
+//-------------------------------------------------
+
+ds1202_device::ds1202_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ds1302_device(mconfig, DS1202, tag, owner, clock, 0x18)
{
}
@@ -87,9 +101,15 @@ ds1302_device::ds1302_device(const machine_config &mconfig, const char *tag, dev
void ds1302_device::device_start()
{
// allocate timers
- m_clock_timer = timer_alloc();
+ m_clock_timer = timer_alloc(FUNC(ds1302_device::clock_tick), this);
m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
+ m_clk = 0;
+ m_ce = 0;
+ m_state = STATE_COMMAND;
+ m_bits = 0;
+ m_cmd = 0;
+
for (auto & elem : m_reg)
elem = 0;
@@ -104,28 +124,15 @@ void ds1302_device::device_start()
save_item(NAME(m_addr));
save_item(NAME(m_reg));
save_item(NAME(m_user));
+ save_pointer(NAME(m_ram), m_ram_size);
}
//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void ds1302_device::device_reset()
-{
- m_clk = 0;
- m_ce = 0;
- m_state = STATE_COMMAND;
- m_bits = 0;
- m_cmd = 0;
-}
-
-
-//-------------------------------------------------
-// device_timer - handler timer events
+// clock_tick - advance the clock if enabled
//-------------------------------------------------
-void ds1302_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ds1302_device::clock_tick)
{
if (!CLOCK_HALT)
{
@@ -141,7 +148,7 @@ void ds1302_device::device_timer(emu_timer &timer, device_timer_id id, int param
void ds1302_device::nvram_default()
{
- memset(m_ram, 0, RAM_SIZE);
+ std::fill_n(&m_ram[0], m_ram_size, 0);
}
@@ -150,9 +157,10 @@ void ds1302_device::nvram_default()
// .nv file
//-------------------------------------------------
-void ds1302_device::nvram_read(emu_file &file)
+bool ds1302_device::nvram_read(util::read_stream &file)
{
- file.read(m_ram, RAM_SIZE);
+ auto const [err, actual] = read(file, &m_ram[0], m_ram_size);
+ return !err && (actual == m_ram_size);
}
@@ -161,9 +169,10 @@ void ds1302_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void ds1302_device::nvram_write(emu_file &file)
+bool ds1302_device::nvram_write(util::write_stream &file)
{
- file.write(m_ram, RAM_SIZE);
+ auto const [err, actual] = write(file, &m_ram[0], m_ram_size);
+ return !err;
}
@@ -187,11 +196,11 @@ void ds1302_device::rtc_clock_updated(int year, int month, int day, int day_of_w
// ce_w - chip enable write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds1302_device::ce_w )
+void ds1302_device::ce_w(int state)
{
if (state && !m_ce)
{
- LOG("DS1302 CE: 1\n");
+ LOG("Data Transfer Initiated\n");
// synchronize user buffers
for (int i = 0; i < 9; i++)
@@ -201,7 +210,7 @@ WRITE_LINE_MEMBER( ds1302_device::ce_w )
}
else if (!state && m_ce)
{
- LOG("DS1302 CE: 0\n");
+ LOG("Data Transfer Terminated\n");
// terminate data transfer
m_state = STATE_COMMAND;
@@ -222,28 +231,29 @@ void ds1302_device::load_shift_register()
{
if (COMMAND_RAM)
{
- m_data = m_ram[m_addr];
+ m_data = m_addr < m_ram_size ? m_ram[m_addr] : 0;
- LOG("DS1302 Read RAM %u:%02x\n", m_addr, m_data);
+ LOG("Read RAM %u: %02x\n", m_addr, m_data);
}
else
{
- m_data = m_user[m_addr];
+ m_data = m_addr < 9 ? m_user[m_addr] : 0;
- LOG("DS1302 Read Clock %u:%02x\n", m_addr, m_data);
+ LOG("Read Clock %u: %02x\n", m_addr, m_data);
}
}
else
{
if (COMMAND_RAM)
{
- LOG("DS1302 Write RAM %u:%02x\n", m_addr, m_data);
+ LOG("Write RAM %u: %02x\n", m_addr, m_data);
- m_ram[m_addr] = m_data;
+ if (m_addr < m_ram_size)
+ m_ram[m_addr] = m_data;
}
else if (m_addr < 9)
{
- LOG("DS1302 Write Clock %u:%02x\n", m_addr, m_data);
+ LOG("Write Clock %u: %02x\n", m_addr, m_data);
m_reg[m_addr] = m_data;
}
@@ -264,11 +274,11 @@ void ds1302_device::input_bit()
m_cmd |= (m_io << 7);
m_bits++;
- LOG("DS1302 Input Bit: %u\n", m_io);
+ LOG("Serial Input Bit: %u\n", m_io);
if (m_bits == 8)
{
- LOG("DS1302 Command: %02x\n", m_cmd);
+ LOG("Command Received: %02x\n", m_cmd);
m_bits = 0;
m_addr = (m_cmd >> 1) & 0x1f;
@@ -303,11 +313,11 @@ void ds1302_device::input_bit()
m_data |= (m_io << 7);
m_bits++;
- LOG("DS1302 Input Bit: %u\n", m_io);
+ LOG("Serial Input Bit: %u\n", m_io);
if (m_bits == 8)
{
- LOG("DS1302 Data: %02x\n", m_data);
+ LOG("Data Received: %02x\n", m_data);
m_bits = 0;
@@ -370,7 +380,7 @@ void ds1302_device::output_bit()
}
}
- LOG("DS1302 Output Bit: %u\n", m_io);
+ LOG("Serial Output Bit: %u\n", m_io);
}
@@ -378,9 +388,9 @@ void ds1302_device::output_bit()
// sclk_w - serial clock write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds1302_device::sclk_w )
+void ds1302_device::sclk_w(int state)
{
- //LOG("DS1302 CLK: %u\n", state);
+ //LOG("Serial CLK: %u\n", state);
if (m_ce)
{
@@ -398,9 +408,9 @@ WRITE_LINE_MEMBER( ds1302_device::sclk_w )
// io_w - I/O write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds1302_device::io_w )
+void ds1302_device::io_w(int state)
{
- //LOG("DS1302 I/O: %u\n", state);
+ //LOG("Serial I/O: %u\n", state);
m_io = state;
}
@@ -410,7 +420,7 @@ WRITE_LINE_MEMBER( ds1302_device::io_w )
// io_r - I/O read
//-------------------------------------------------
-READ_LINE_MEMBER( ds1302_device::io_r )
+int ds1302_device::io_r()
{
return m_io;
}
diff --git a/src/devices/machine/ds1302.h b/src/devices/machine/ds1302.h
index 1ad43bd0d35..6d79cbb2c11 100644
--- a/src/devices/machine/ds1302.h
+++ b/src/devices/machine/ds1302.h
@@ -36,31 +36,35 @@ public:
// construction/destruction
ds1302_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER( ce_w );
- DECLARE_WRITE_LINE_MEMBER( sclk_w );
- DECLARE_WRITE_LINE_MEMBER( io_w );
- DECLARE_READ_LINE_MEMBER( io_r );
+ void ce_w(int state);
+ void sclk_w(int state);
+ void io_w(int state);
+ int io_r();
protected:
+ ds1302_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t ram_size);
+
// device-level overrides
virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
// 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) override;
virtual bool rtc_feature_leap_year() const override { return true; }
private:
+ TIMER_CALLBACK_MEMBER(clock_tick);
+
void load_shift_register();
void input_bit();
void output_bit();
+ const uint8_t m_ram_size;
+
int m_ce;
int m_clk;
int m_io;
@@ -72,14 +76,24 @@ private:
uint8_t m_reg[9];
uint8_t m_user[9];
- uint8_t m_ram[0x20];
+ uint8_t m_ram[31];
// timers
emu_timer *m_clock_timer;
};
+// ======================> ds1202_device
+
+class ds1202_device : public ds1302_device
+{
+public:
+ // construction/destruction
+ ds1202_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
-// device type definition
+// device type declarations
+DECLARE_DEVICE_TYPE(DS1202, ds1202_device)
DECLARE_DEVICE_TYPE(DS1302, ds1302_device)
#endif // MAME_MACHINE_DS1302_H
diff --git a/src/devices/machine/ds1315.cpp b/src/devices/machine/ds1315.cpp
index 2a574dca399..812f39dffba 100644
--- a/src/devices/machine/ds1315.cpp
+++ b/src/devices/machine/ds1315.cpp
@@ -32,9 +32,9 @@
DEFINE_DEVICE_TYPE(DS1315, ds1315_device, "ds1315", "Dallas DS1315 Phantom Time Chip")
-ds1315_device::ds1315_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DS1315, tag, owner, clock),
- m_backing_read(*this),
+ds1315_device::ds1315_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, DS1315, tag, owner, clock),
+ m_backing_read(*this, 0xff),
m_mode(),
m_count(0)
{
@@ -46,8 +46,6 @@ ds1315_device::ds1315_device(const machine_config &mconfig, const char *tag, dev
void ds1315_device::device_start()
{
- m_backing_read.resolve_safe(0xff);
-
save_item(NAME(m_count));
save_item(NAME(m_mode));
save_item(NAME(m_raw_data));
diff --git a/src/devices/machine/ds1386.cpp b/src/devices/machine/ds1386.cpp
index 4333a6bcc5c..413d598c8b8 100644
--- a/src/devices/machine/ds1386.cpp
+++ b/src/devices/machine/ds1386.cpp
@@ -12,20 +12,6 @@
#include "ds1386.h"
#include "machine/timehelp.h"
-#define DISABLE_OSC (0x80)
-#define DISABLE_SQW (0x40)
-
-#define COMMAND_TE (0x80)
-#define COMMAND_IPSW (0x40)
-#define COMMAND_IBH_LO (0x20)
-#define COMMAND_PU_LVL (0x10)
-#define COMMAND_WAM (0x08)
-#define COMMAND_TDM (0x04)
-#define COMMAND_WAF (0x02)
-#define COMMAND_TDF (0x01)
-
-#define HOURS_12_24 (0x40)
-#define HOURS_AM_PM (0x20)
DEFINE_DEVICE_TYPE(DS1286, ds1286_device, "ds1286", "DS1286 Watchdog Timekeeper")
DEFINE_DEVICE_TYPE(DS1386_8K, ds1386_8k_device, "ds1386_8k", "DS1386-8K RAMified Watchdog Timekeeper")
@@ -77,48 +63,26 @@ ds1386_32k_device::ds1386_32k_device(const machine_config &mconfig, const char *
{
}
-void ds1386_device::safe_inta_cb(int state)
-{
- if (!m_inta_cb.isnull())
- m_inta_cb(state);
-}
-
-void ds1386_device::safe_intb_cb(int state)
-{
- if (!m_intb_cb.isnull())
- m_intb_cb(state);
-}
-
-void ds1386_device::safe_sqw_cb(int state)
-{
- if (!m_sqw_cb.isnull())
- m_sqw_cb(state);
-}
-
void ds1386_device::device_start()
{
- m_inta_cb.resolve();
- m_intb_cb.resolve();
- m_sqw_cb.resolve();
-
m_tod_alarm = 0;
m_watchdog_alarm = 0;
m_square = 1;
- safe_inta_cb(0);
- safe_intb_cb(0);
- safe_sqw_cb(1);
+ m_inta_cb(0);
+ m_intb_cb(0);
+ m_sqw_cb(1);
// allocate timers
- m_clock_timer = timer_alloc(CLOCK_TIMER);
+ m_clock_timer = timer_alloc(FUNC(ds1386_device::advance_hundredths), this);
m_clock_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
- m_square_timer = timer_alloc(SQUAREWAVE_TIMER);
+ m_square_timer = timer_alloc(FUNC(ds1386_device::square_tick), this);
m_square_timer->adjust(attotime::never);
- m_watchdog_timer = timer_alloc(WATCHDOG_TIMER);
+ m_watchdog_timer = timer_alloc(FUNC(ds1386_device::watchdog_tick), this);
m_watchdog_timer->adjust(attotime::never);
- m_inta_timer= timer_alloc(INTA_TIMER);
+ m_inta_timer = timer_alloc(FUNC(ds1386_device::inta_timer_elapsed), this);
m_inta_timer->adjust(attotime::never);
- m_intb_timer= timer_alloc(INTB_TIMER);
+ m_intb_timer = timer_alloc(FUNC(ds1386_device::intb_timer_elapsed), this);
m_intb_timer->adjust(attotime::never);
// state saving
@@ -160,7 +124,7 @@ void ds1386_device::time_of_day_alarm()
if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW)
{
- safe_inta_cb(m_tod_alarm);
+ m_inta_cb(m_tod_alarm);
if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL)
{
m_inta_timer->adjust(attotime::from_msec(3));
@@ -168,7 +132,7 @@ void ds1386_device::time_of_day_alarm()
}
else
{
- safe_intb_cb(m_tod_alarm);
+ m_intb_cb(m_tod_alarm);
if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL)
{
m_intb_timer->adjust(attotime::from_msec(3));
@@ -183,7 +147,7 @@ void ds1386_device::watchdog_alarm()
if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW)
{
- safe_intb_cb(m_watchdog_alarm);
+ m_intb_cb(m_watchdog_alarm);
if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL)
{
m_intb_timer->adjust(attotime::from_msec(3));
@@ -191,7 +155,7 @@ void ds1386_device::watchdog_alarm()
}
else
{
- safe_inta_cb(m_watchdog_alarm);
+ m_inta_cb(m_watchdog_alarm);
if (m_ram[REGISTER_COMMAND] & COMMAND_PU_LVL)
{
m_inta_timer->adjust(attotime::from_msec(3));
@@ -199,51 +163,37 @@ void ds1386_device::watchdog_alarm()
}
}
-void ds1386_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ds1386_device::square_tick)
{
- switch (id)
- {
- case CLOCK_TIMER:
- advance_hundredths();
- break;
-
- case SQUAREWAVE_TIMER:
- m_square = ((m_square == 0) ? 1 : 0);
- safe_sqw_cb(m_square);
- break;
-
- case WATCHDOG_TIMER:
- if ((m_ram[REGISTER_COMMAND] & COMMAND_WAF) == 0)
- watchdog_alarm();
- break;
-
- case INTA_TIMER:
- if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW)
- {
- m_tod_alarm = 0;
- }
- else
- {
- m_watchdog_alarm = 0;
- }
- safe_inta_cb(0);
- break;
+ m_square = 1 - m_square;
+ m_sqw_cb(m_square);
+}
- case INTB_TIMER:
- if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW)
- {
- m_watchdog_alarm = 0;
- }
- else
- {
- m_tod_alarm = 0;
- }
- safe_intb_cb(0);
- break;
- }
+TIMER_CALLBACK_MEMBER(ds1386_device::watchdog_tick)
+{
+ if ((m_ram[REGISTER_COMMAND] & COMMAND_WAF) == 0)
+ watchdog_alarm();
+}
+
+TIMER_CALLBACK_MEMBER(ds1386_device::inta_timer_elapsed)
+{
+ if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW)
+ m_tod_alarm = 0;
+ else
+ m_watchdog_alarm = 0;
+ m_inta_cb(0);
+}
+
+TIMER_CALLBACK_MEMBER(ds1386_device::intb_timer_elapsed)
+{
+ if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW)
+ m_watchdog_alarm = 0;
+ else
+ m_tod_alarm = 0;
+ m_intb_cb(0);
}
-void ds1386_device::advance_hundredths()
+TIMER_CALLBACK_MEMBER(ds1386_device::advance_hundredths)
{
if ((m_ram[REGISTER_COMMAND] & COMMAND_TE) != 0)
{
@@ -378,9 +328,6 @@ void ds1386_device::check_tod_alarm()
bool zeroes = (m_hundredths == 0 && m_seconds == 0);
if (zeroes && (m_ram[REGISTER_COMMAND] & COMMAND_TDF) == 0)
{
- bool minutes_match = (m_minutes & 0x7f) == (m_minutes_alarm & 0x7f);
- bool hours_match = (m_hours & 0x7f) == (m_hours_alarm & 0x7f);
- bool days_match = (m_days & 0x7) == (m_days_alarm & 0x07);
bool alarm_match = false;
switch (mode)
{
@@ -388,13 +335,13 @@ void ds1386_device::check_tod_alarm()
alarm_match = true;
break;
case ALARM_MINUTES_MATCH:
- alarm_match = minutes_match;
+ alarm_match = (m_minutes & 0x7f) == (m_minutes_alarm & 0x7f);
break;
case ALARM_HOURS_MATCH:
- alarm_match = hours_match;
+ alarm_match = (m_hours & 0x7f) == (m_hours_alarm & 0x7f);
break;
case ALARM_DAYS_MATCH:
- alarm_match = days_match;
+ alarm_match = (m_days & 0x7) == (m_days_alarm & 0x07);
break;
default:
break;
@@ -412,14 +359,16 @@ void ds1386_device::nvram_default()
m_ram[REGISTER_COMMAND] = COMMAND_TE | COMMAND_WAM | COMMAND_TDM;
}
-void ds1386_device::nvram_read(emu_file &file)
+bool ds1386_device::nvram_read(util::read_stream &file)
{
- file.read(&m_ram[0], m_ram_size);
+ auto const [err, actual] = read(file, &m_ram[0], m_ram_size);
+ return !err && (actual == m_ram_size);
}
-void ds1386_device::nvram_write(emu_file &file)
+bool ds1386_device::nvram_write(util::write_stream &file)
{
- file.write(&m_ram[0], m_ram_size);
+ auto const [err, actual] = write(file, &m_ram[0], m_ram_size);
+ return !err;
}
void ds1386_device::data_w(offs_t offset, uint8_t data)
@@ -437,7 +386,7 @@ void ds1386_device::data_w(offs_t offset, uint8_t data)
{
case 0x00: // hundredths
case 0x03: // minutes alarm
- case 0x05: // horus alarm
+ case 0x05: // hours alarm
case 0x0a: // years
m_ram[offset] = data;
break;
@@ -468,24 +417,16 @@ void ds1386_device::data_w(offs_t offset, uint8_t data)
if (changed & DISABLE_SQW)
{
if (m_ram[offset] & DISABLE_SQW)
- {
m_square_timer->adjust(attotime::never);
- }
else
- {
m_square_timer->adjust(attotime::from_hz(2048));
- }
}
if (changed & DISABLE_OSC)
{
if (m_ram[offset] & DISABLE_OSC)
- {
m_clock_timer->adjust(attotime::never);
- }
else
- {
m_clock_timer->adjust(attotime::from_hz(100));
- }
}
break;
}
@@ -498,9 +439,9 @@ void ds1386_device::data_w(offs_t offset, uint8_t data)
m_ram[REGISTER_COMMAND] &= ~COMMAND_WAF;
m_watchdog_alarm = 0;
if (m_ram[REGISTER_COMMAND] & COMMAND_IPSW)
- safe_intb_cb(0);
+ m_intb_cb(0);
else
- safe_inta_cb(0);
+ m_inta_cb(0);
}
m_ram[offset] = data;
uint8_t wd_hundredths = m_ram[REGISTER_WATCHDOG_HUNDREDTHS];
@@ -530,16 +471,16 @@ void ds1386_device::data_w(offs_t offset, uint8_t data)
if (a_changed)
{
if (m_ram[offset] & COMMAND_IPSW)
- safe_inta_cb(m_tod_alarm);
+ m_inta_cb(m_tod_alarm);
else
- safe_inta_cb(m_watchdog_alarm);
+ m_inta_cb(m_watchdog_alarm);
}
if (b_changed)
{
if (m_ram[offset] & COMMAND_IPSW)
- safe_intb_cb(m_watchdog_alarm);
+ m_intb_cb(m_watchdog_alarm);
else
- safe_intb_cb(m_tod_alarm);
+ m_intb_cb(m_tod_alarm);
}
}
if (changed & COMMAND_WAM)
@@ -547,16 +488,16 @@ void ds1386_device::data_w(offs_t offset, uint8_t data)
if (m_ram[offset] & COMMAND_WAF)
{
if (m_ram[offset] & COMMAND_IPSW)
- safe_intb_cb(0);
+ m_intb_cb(0);
else
- safe_inta_cb(0);
+ m_inta_cb(0);
}
else if (m_watchdog_alarm)
{
if (m_ram[offset] & COMMAND_IPSW)
- safe_intb_cb(m_watchdog_alarm);
+ m_intb_cb(m_watchdog_alarm);
else
- safe_inta_cb(m_watchdog_alarm);
+ m_inta_cb(m_watchdog_alarm);
}
}
if (changed & COMMAND_TDM)
@@ -564,16 +505,16 @@ void ds1386_device::data_w(offs_t offset, uint8_t data)
if (m_ram[offset] & COMMAND_TDF)
{
if (m_ram[offset] & COMMAND_IPSW)
- safe_inta_cb(0);
+ m_inta_cb(0);
else
- safe_intb_cb(0);
+ m_intb_cb(0);
}
else if (m_tod_alarm)
{
if (m_ram[offset] & COMMAND_IPSW)
- safe_inta_cb(m_tod_alarm);
+ m_inta_cb(m_tod_alarm);
else
- safe_intb_cb(m_tod_alarm);
+ m_intb_cb(m_tod_alarm);
}
}
break;
diff --git a/src/devices/machine/ds1386.h b/src/devices/machine/ds1386.h
index 0e994e436c9..c7b15d16799 100644
--- a/src/devices/machine/ds1386.h
+++ b/src/devices/machine/ds1386.h
@@ -88,9 +88,9 @@ public:
void data_w(offs_t offset, uint8_t data);
uint8_t data_r(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER( ce_w );
- DECLARE_WRITE_LINE_MEMBER( oe_w );
- DECLARE_WRITE_LINE_MEMBER( we_w );
+ void ce_w(int state);
+ void oe_w(int state);
+ void we_w(int state);
protected:
enum
@@ -125,37 +125,51 @@ protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
// device_rtc_interface overrides
virtual bool rtc_feature_y2k() const override { return false; }
virtual bool rtc_feature_leap_year() const override { return true; }
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
- static constexpr device_timer_id CLOCK_TIMER = 0;
- static constexpr device_timer_id SQUAREWAVE_TIMER = 1;
- static constexpr device_timer_id WATCHDOG_TIMER = 2;
- static constexpr device_timer_id INTA_TIMER = 3;
- static constexpr device_timer_id INTB_TIMER = 4;
-
protected:
+ enum
+ {
+ DISABLE_OSC = 0x80,
+ DISABLE_SQW = 0x40,
+
+ COMMAND_TE = 0x80,
+ COMMAND_IPSW = 0x40,
+ COMMAND_IBH_LO = 0x20,
+ COMMAND_PU_LVL = 0x10,
+ COMMAND_WAM = 0x08,
+ COMMAND_TDM = 0x04,
+ COMMAND_WAF = 0x02,
+ COMMAND_TDF = 0x01,
+
+ HOURS_12_24 = 0x40,
+ HOURS_AM_PM = 0x20
+ };
+
+
+ TIMER_CALLBACK_MEMBER(advance_hundredths);
+ TIMER_CALLBACK_MEMBER(square_tick);
+ TIMER_CALLBACK_MEMBER(watchdog_tick);
+ TIMER_CALLBACK_MEMBER(inta_timer_elapsed);
+ TIMER_CALLBACK_MEMBER(intb_timer_elapsed);
+
void safe_inta_cb(int state);
void safe_intb_cb(int state);
void safe_sqw_cb(int state);
- void set_current_time();
-
void check_tod_alarm();
void time_of_day_alarm();
void watchdog_alarm();
- void advance_hundredths();
-
void copy_ram_to_registers();
void copy_registers_to_ram();
diff --git a/src/devices/machine/ds1994.cpp b/src/devices/machine/ds1994.cpp
index c63fdd0da15..544bc20d050 100644
--- a/src/devices/machine/ds1994.cpp
+++ b/src/devices/machine/ds1994.cpp
@@ -9,28 +9,26 @@
*
*/
-// FIXME: convert to device_rtc_interface and remove time.h
-// FIXME: convert logging to use logmacro.h
+// FIXME: convert to device_rtc_interface and remove <ctime>
#include "emu.h"
-#include "machine/ds1994.h"
+#include "ds1994.h"
#include <ctime>
+#include <tuple>
-#define VERBOSE_LEVEL 0
-inline void ds1994_device::verboselog(int n_level, const char *s_fmt, ...)
-{
- if (VERBOSE_LEVEL >= n_level)
- {
- va_list v;
- char buf[32768];
- va_start(v, s_fmt);
- vsprintf(buf, s_fmt, v);
- va_end(v);
- logerror("ds1994 %s: %s", machine().describe_context(), buf);
- }
-}
+#define LOG_ERRORS (1U << 1)
+#define LOG_1WIRE (1U << 2)
+#define LOG_ROM_COMMANDS (1U << 3)
+#define LOG_COMMANDS (1U << 4)
+#define LOG_STATES (1U << 5)
+#define LOG_RESETS (1U << 6)
+#define LOG_WRITES (1U << 7)
+#define LOG_READS (1U << 8)
+
+#define VERBOSE (0)
+#include "logmacro.h"
// device type definition
DEFINE_DEVICE_TYPE(DS1994, ds1994_device, "ds1994", "DS1994 iButton 4Kb Memory Plus Time")
@@ -115,9 +113,9 @@ void ds1994_device::device_start()
elem = STATE_IDLE;
// timers
- m_timer_main = timer_alloc(TIMER_MAIN);
- m_timer_reset = timer_alloc(TIMER_RESET);
- m_timer_clock = timer_alloc(TIMER_CLOCK);
+ m_timer_main = timer_alloc(FUNC(ds1994_device::main_tick), this);
+ m_timer_reset = timer_alloc(FUNC(ds1994_device::reset_tick), this);
+ m_timer_clock = timer_alloc(FUNC(ds1994_device::clock_tick), this);
m_timer_clock->adjust(attotime::from_hz(256), 0, attotime::from_hz(256));
}
@@ -144,11 +142,11 @@ void ds1994_device::device_reset()
memcpy(m_regs, region->base() + ROM_SIZE + SPD_SIZE + DATA_SIZE + RTC_SIZE, REGS_SIZE);
return;
}
- verboselog(0, "ds1994 %s: Wrong region length for data, expected 0x%x, got 0x%x\n", tag(), ROM_SIZE + SPD_SIZE + DATA_SIZE + RTC_SIZE + REGS_SIZE, region->bytes());
+ LOGMASKED(LOG_ERRORS, "ds1994 %s: Wrong region length for data, expected 0x%x, got 0x%x\n", tag(), ROM_SIZE + SPD_SIZE + DATA_SIZE + RTC_SIZE + REGS_SIZE, region->bytes());
}
else
{
- verboselog(0, "ds1994 %s: Warning, no id provided, answer will be all zeroes.\n", tag());
+ LOGMASKED(LOG_ERRORS, "ds1994 %s: Warning, no id provided, answer will be all zeroes.\n", tag());
memset(m_rom, 0, ROM_SIZE);
memset(m_ram, 0, SPD_SIZE);
memset(m_sram, 0, DATA_SIZE);
@@ -168,11 +166,11 @@ bool ds1994_device::one_wire_tx_bit(uint8_t value)
if (!m_bit)
{
m_shift = value;
- verboselog(1, "one_wire_tx_bit: Byte to send %02x\n", m_shift);
+ LOGMASKED(LOG_1WIRE, "one_wire_tx_bit: Byte to send %02x\n", m_shift);
}
m_tx = m_shift & 1;
m_shift >>= 1;
- verboselog(1, "one_wire_tx_bit: State %d\n", m_tx);
+ LOGMASKED(LOG_1WIRE, "one_wire_tx_bit: State %d\n", m_tx);
m_bit++;
if (m_bit == 8) return true;
else
@@ -186,11 +184,11 @@ bool ds1994_device::one_wire_rx_bit(void)
{
m_shift |= 0x80;
}
- verboselog(1, "one_wire_rx_bit: State %d\n", m_rx);
+ LOGMASKED(LOG_1WIRE, "one_wire_rx_bit: State %d\n", m_rx);
m_bit++;
if (m_bit == 8)
{
- verboselog(1, "one_wire_rx_bit: Byte Received %02x\n", m_shift);
+ LOGMASKED(LOG_1WIRE, "one_wire_rx_bit: Byte Received %02x\n", m_shift);
return true;
}
else
@@ -203,29 +201,29 @@ bool ds1994_device::one_wire_rx_bit(void)
/* */
/********************************************/
-void ds1994_device::ds1994_rom_cmd(void)
+void ds1994_device::handle_rom_cmd(void)
{
- verboselog(2, "timer_main state_rom_command\n");
+ LOGMASKED(LOG_ROM_COMMANDS, "rom_cmd\n");
if (one_wire_rx_bit())
{
switch (m_shift)
{
case ROMCMD_READROM:
- verboselog(1, "timer_main rom_cmd readrom\n");
+ LOGMASKED(LOG_ROM_COMMANDS, "rom_cmd readrom\n");
m_bit = 0;
m_byte = 0;
m_state[0] = STATE_READROM;
m_state_ptr = 0;
break;
case ROMCMD_SKIPROM:
- verboselog(1, "timer_main rom_cmd skiprom\n");
+ LOGMASKED(LOG_ROM_COMMANDS, "rom_cmd skiprom\n");
m_bit = 0;
m_byte = 0;
m_state[0] = STATE_COMMAND;
m_state_ptr = 0;
break;
case ROMCMD_MATCHROM:
- verboselog(1, "timer_main rom_cmd matchrom\n");
+ LOGMASKED(LOG_ROM_COMMANDS, "rom_cmd matchrom\n");
m_bit = 0;
m_byte = 0;
m_state[0] = STATE_MATCHROM;
@@ -233,11 +231,11 @@ void ds1994_device::ds1994_rom_cmd(void)
break;
case ROMCMD_SEARCHROM:
case ROMCMD_SEARCHINT:
- verboselog(0, "timer_main rom_command not implemented %02x\n", m_shift);
+ LOGMASKED(LOG_ERRORS, "rom_command not implemented %02x\n", m_shift);
m_state[m_state_ptr] = STATE_COMMAND;
break;
default:
- verboselog(0, "timer_main rom_command not found %02x\n", m_shift);
+ LOGMASKED(LOG_ERRORS, "rom_command not found %02x\n", m_shift);
m_state[m_state_ptr] = STATE_IDLE;
break;
}
@@ -250,15 +248,15 @@ void ds1994_device::ds1994_rom_cmd(void)
/* */
/********************************************/
-void ds1994_device::ds1994_cmd(void)
+void ds1994_device::handle_cmd(void)
{
- verboselog(2, "timer_main state_command\n");
+ LOGMASKED(LOG_COMMANDS, "state_command\n");
if (one_wire_rx_bit())
{
switch (m_shift)
{
case COMMAND_READ_MEMORY:
- verboselog(1, "timer_main cmd read_memory\n");
+ LOGMASKED(LOG_COMMANDS, "cmd read_memory\n");
m_bit = 0;
m_byte = 0;
m_state[0] = STATE_ADDRESS1;
@@ -268,7 +266,7 @@ void ds1994_device::ds1994_cmd(void)
m_state_ptr = 0;
break;
case COMMAND_WRITE_SCRATCHPAD:
- verboselog(1, "timer_main cmd write_scratchpad\n");
+ LOGMASKED(LOG_COMMANDS, "cmd write_scratchpad\n");
m_bit = 0;
m_byte = 0;
m_offs_ro = false;
@@ -279,7 +277,7 @@ void ds1994_device::ds1994_cmd(void)
m_state_ptr = 0;
break;
case COMMAND_READ_SCRATCHPAD:
- verboselog(1, "timer_main cmd read_scratchpad\n");
+ LOGMASKED(LOG_COMMANDS, "cmd read_scratchpad\n");
m_bit = 0;
m_byte = 0;
m_state[0] = STATE_TXADDRESS1;
@@ -290,7 +288,7 @@ void ds1994_device::ds1994_cmd(void)
m_state_ptr = 0;
break;
case COMMAND_COPY_SCRATCHPAD:
- verboselog(1, "timer_main cmd copy_scratchpad\n");
+ LOGMASKED(LOG_COMMANDS, "cmd copy_scratchpad\n");
m_bit = 0;
m_byte = 0;
m_offs_ro = true;
@@ -303,7 +301,7 @@ void ds1994_device::ds1994_cmd(void)
m_state_ptr = 0;
break;
default:
- verboselog(0, "timer_main command not handled %02x\n", m_shift);
+ LOGMASKED(LOG_COMMANDS, "command not handled %02x\n", m_shift);
m_state[m_state_ptr] = STATE_IDLE;
break;
}
@@ -316,7 +314,7 @@ void ds1994_device::ds1994_cmd(void)
/* */
/********************************************/
-uint8_t ds1994_device::ds1994_readmem()
+uint8_t ds1994_device::readmem()
{
if (m_address < 0x200)
{
@@ -332,7 +330,7 @@ uint8_t ds1994_device::ds1994_readmem()
return 0;
}
-void ds1994_device::ds1994_writemem(uint8_t value)
+void ds1994_device::writemem(uint8_t value)
{
if (m_address < 0x200)
{
@@ -353,231 +351,232 @@ void ds1994_device::ds1994_writemem(uint8_t value)
/* */
/*************************************************/
-void ds1994_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ds1994_device::main_tick)
{
- switch (id)
+ switch (m_state[m_state_ptr])
{
- case TIMER_CLOCK:
- for (auto & elem : m_rtc)
+ case STATE_RESET1:
+ LOGMASKED(LOG_STATES, "timer_main state_reset1 %d\n", m_rx);
+ m_tx = false;
+ m_state[m_state_ptr] = STATE_RESET2;
+ m_timer_main->adjust(t_pdl);
+ break;
+ case STATE_RESET2:
+ LOGMASKED(LOG_STATES, "timer_main state_reset2 %d\n", m_rx);
+ m_tx = true;
+ m_bit = 0;
+ m_shift = 0;
+ m_state[m_state_ptr] = STATE_ROMCMD;
+ break;
+ case STATE_ROMCMD:
+ handle_rom_cmd();
+ break;
+ case STATE_COMMAND:
+ handle_cmd();
+ break;
+ case STATE_MATCHROM:
+ LOGMASKED(LOG_STATES, "timer_main state_matchrom - Data to match: <- %d\n", m_rx);
+ if (one_wire_rx_bit())
{
- elem++;
- if (elem != 0)
+ if (m_rom[7- m_byte] == m_shift)
{
- break;
+ m_byte++;
+ m_bit = 0;
+ LOGMASKED(LOG_STATES, "timer_main state_matchrom: datamatch %x - byte=%d\n", m_shift, m_byte);
+ }
+ else
+ {
+ m_state[m_state_ptr] = STATE_IDLE;
+ LOGMASKED(LOG_STATES, "timer_main state_matchrom: no match rx=%x <> mem=%x - byte:%d\n", m_shift, m_rom[7 - m_byte], m_byte);
}
}
+ if (m_byte == ROM_SIZE)
+ {
+ LOGMASKED(LOG_STATES, "timer_main matchrom finished\n");
+ m_state[m_state_ptr] = STATE_COMMAND;
+ }
break;
- case TIMER_RESET:
- verboselog(1, "timer_reset\n");
- m_state[m_state_ptr] = STATE_RESET;
- m_timer_reset->adjust(attotime::never);
+ case STATE_ADDRESS1:
+ LOGMASKED(LOG_STATES, "timer_main state_address1\n");
+ if (one_wire_rx_bit())
+ {
+ m_bit = 0;
+ if (m_offs_ro)
+ {
+ if (m_a1 != m_shift) m_auth = false;
+ LOGMASKED(LOG_STATES, "timer_main state_address1 - TA1=%02x - Auth_Code 1=%02x\n", m_a1, m_shift);
+ }
+ else
+ {
+ m_a1 = m_shift & 0xff;
+ LOGMASKED(LOG_STATES, "timer_main state_address1 - Address1=%02x\n", m_a1);
+ }
+ m_state_ptr++;
+ }
break;
- case TIMER_MAIN:
- switch (m_state[m_state_ptr])
+ case STATE_ADDRESS2:
+ LOGMASKED(LOG_STATES, "timer_main state_address2\n");
+ if (one_wire_rx_bit())
{
- case STATE_RESET1:
- verboselog(2, "timer_main state_reset1 %d\n", m_rx);
- m_tx = false;
- m_state[m_state_ptr] = STATE_RESET2;
- m_timer_main->adjust(t_pdl);
- break;
- case STATE_RESET2:
- verboselog(2, "timer_main state_reset2 %d\n", m_rx);
- m_tx = true;
- m_bit = 0;
- m_shift = 0;
- m_state[m_state_ptr] = STATE_ROMCMD;
- break;
- case STATE_ROMCMD:
- ds1994_rom_cmd();
- break;
- case STATE_COMMAND:
- ds1994_cmd();
- break;
- case STATE_MATCHROM:
- verboselog(2, "timer_main state_matchrom - Data to match: <- %d\n", m_rx);
- if (one_wire_rx_bit())
- {
- if (m_rom[7- m_byte] == m_shift)
- {
- m_byte++;
- m_bit = 0;
- verboselog(2, "timer_main state_matchrom: datamatch %x - byte=%d\n", m_shift, m_byte);
- }
- else
- {
- m_state[m_state_ptr] = STATE_IDLE;
- verboselog(1, "timer_main state_matchrom: no match rx=%x <> mem=%x - byte:%d\n", m_shift, m_rom[7 - m_byte], m_byte);
- }
- }
- if (m_byte == ROM_SIZE)
- {
- verboselog(2, "timer_main matchrom finished\n");
- m_state[m_state_ptr] = STATE_COMMAND;
- }
- break;
- case STATE_ADDRESS1:
- verboselog(2, "timer_main state_address1\n");
- if (one_wire_rx_bit())
- {
- m_bit = 0;
- if (m_offs_ro)
- {
- if (m_a1 != m_shift) m_auth = false;
- verboselog(1, "timer_main state_address1 - TA1=%02x - Auth_Code 1=%02x\n", m_a1, m_shift);
- }
- else
- {
- m_a1 = m_shift & 0xff;
- verboselog(2, "timer_main state_address1 - Address1=%02x\n", m_a1);
- }
- m_state_ptr++;
- }
- break;
- case STATE_ADDRESS2:
- verboselog(2, "timer_main state_address2\n");
- if (one_wire_rx_bit())
- {
- m_bit = 0;
- if (m_offs_ro)
- {
- if ( m_a2 != m_shift )
- m_auth = false;
- verboselog(1, "timer_main state_address1 - TA2=%02x - Auth_Code 2=%02x\n", m_a1, m_shift);
- }
- else
- {
- m_a2 = m_shift & 0xff;
- verboselog(2, "timer_main state_address2 - Address2=%02x\n", m_a2);
- }
- m_state_ptr++;
- }
- break;
- case STATE_OFFSET:
- verboselog(2, "timer_main state_offset\n");
- if (one_wire_rx_bit())
- {
- m_bit = 0;
- if (m_offs_ro)
- {
- if (m_a2 != m_shift)
- m_auth = false;
- verboselog(1, "timer_main state_address1 - OFS_ES=%02x - Auth_Code 3=%02x\n", m_offset, m_shift);
- }
- else
- {
- m_offset = m_shift & 0x1f;
- verboselog(2, "timer_main state_address2 - Offset=%02x\n", m_offset);
- }
- m_state_ptr++;
- }
- break;
- case STATE_WRITE_SCRATCHPAD:
- verboselog(2, "timer_main state_write_scratchpad\n");
- if (one_wire_rx_bit())
- {
- m_bit = 0;
- m_ram[m_offset & 0x1f] = m_shift & 0xff;
- m_offset++;
- }
- verboselog(2, "timer_main state_write_scratchpad %d Offs=%02x\n", m_rx, m_offset);
- break;
- case STATE_READROM:
- m_tx = true;
- if (m_byte == ROM_SIZE)
- {
- verboselog(1, "timer_main readrom finished\n");
- m_state[m_state_ptr] = STATE_COMMAND;
- }
- else
- verboselog(2, "timer_main readrom window closed\n");
- break;
- case STATE_TXADDRESS1:
- m_tx = true;
- if (m_byte == 1)
- {
- verboselog(1, "timer_main txaddress1 finished m_byte=%d\n", m_byte);
- m_byte = 0;
- m_state_ptr++;
- }
- else
- verboselog(2, "timer_main txaddress1 window closed\n");
- break;
- case STATE_TXADDRESS2:
- m_tx = true;
- if (m_byte == 1)
- {
- verboselog(1, "timer_main txaddress2 finished m_byte=%d\n", m_byte);
- m_byte = 0;
- m_state_ptr++;
- }
- else
- verboselog(2, "timer_main txaddress2 window closed\n");
- break;
- case STATE_TXOFFSET:
- m_tx = true;
- if (m_byte == 1)
- {
- verboselog(1, "timer_main txoffset finished - m_byte=%d\n", m_byte);
- m_byte = 0;
- m_state_ptr++;
- }
- else
- verboselog(2, "timer_main txoffset window closed\n");
- break;
- case STATE_READ_MEMORY:
- verboselog(2, "timer_main state_readmemory\n");
- break;
- case STATE_COPY_SCRATCHPAD:
- verboselog(2, "timer_main state_copy_scratchpad\n");
- break;
- case STATE_READ_SCRATCHPAD:
- verboselog(2, "timer_main state_read_scratchpad\n");
- break;
- default:
- verboselog(0, "timer_main state not handled: %d\n", m_state[m_state_ptr]);
- break;
+ m_bit = 0;
+ if (m_offs_ro)
+ {
+ if ( m_a2 != m_shift )
+ m_auth = false;
+ LOGMASKED(LOG_STATES, "timer_main state_address1 - TA2=%02x - Auth_Code 2=%02x\n", m_a1, m_shift);
+ }
+ else
+ {
+ m_a2 = m_shift & 0xff;
+ LOGMASKED(LOG_STATES, "timer_main state_address2 - Address2=%02x\n", m_a2);
+ }
+ m_state_ptr++;
}
- if (m_state[m_state_ptr] == STATE_INIT_COMMAND)
+ break;
+ case STATE_OFFSET:
+ LOGMASKED(LOG_STATES, "timer_main state_offset\n");
+ if (one_wire_rx_bit())
{
- switch (m_state[m_state_ptr + 1])
+ m_bit = 0;
+ if (m_offs_ro)
{
- case STATE_IDLE:
- case STATE_COMMAND:
- case STATE_ADDRESS1:
- case STATE_ADDRESS2:
- case STATE_OFFSET:
- break;
- case STATE_READ_MEMORY:
- verboselog(2, "timer_main (init_cmd) -> state_read_memory - set address\n");
- m_address = (m_a2 << 8) | m_a1;
- break;
- case STATE_WRITE_SCRATCHPAD:
- verboselog(2, "timer_main (init_cmd) -> state_write_scratchpad - set address\n");
- m_offs_ro = false;
- m_offset = 0;
- break;
- case STATE_READ_SCRATCHPAD:
- verboselog(2, "timer_main (init_cmd) -> state_read_scratchpad - set address\n");
- m_address = 0;
- break;
- case STATE_COPY_SCRATCHPAD:
- verboselog(2, "timer_main (init_cmd) -> state_copy_scratchpad - do copy\n");
- if (m_auth)
- {
- m_address = (m_a2 << 8) | m_a1;
- for (int i = 0; i <= m_offset; i++)
- {
- ds1994_writemem(m_ram[i]);
- m_address++;
- }
- }
- else
- verboselog(1, "timer_main (init_cmd) -> state_copy_scratchpad - Auth-Rejected\n");
- break;
+ if (m_a2 != m_shift)
+ m_auth = false;
+ LOGMASKED(LOG_STATES, "timer_main state_address1 - OFS_ES=%02x - Auth_Code 3=%02x\n", m_offset, m_shift);
+ }
+ else
+ {
+ m_offset = m_shift & 0x1f;
+ LOGMASKED(LOG_STATES, "timer_main state_address2 - Offset=%02x\n", m_offset);
}
m_state_ptr++;
}
+ break;
+ case STATE_WRITE_SCRATCHPAD:
+ LOGMASKED(LOG_STATES, "timer_main state_write_scratchpad\n");
+ if (one_wire_rx_bit())
+ {
+ m_bit = 0;
+ m_ram[m_offset & 0x1f] = m_shift & 0xff;
+ m_offset++;
+ }
+ LOGMASKED(LOG_STATES, "timer_main state_write_scratchpad %d Offs=%02x\n", m_rx, m_offset);
+ break;
+ case STATE_READROM:
+ m_tx = true;
+ if (m_byte == ROM_SIZE)
+ {
+ LOGMASKED(LOG_STATES, "timer_main readrom finished\n");
+ m_state[m_state_ptr] = STATE_COMMAND;
+ }
+ else
+ LOGMASKED(LOG_STATES, "timer_main readrom window closed\n");
+ break;
+ case STATE_TXADDRESS1:
+ m_tx = true;
+ if (m_byte == 1)
+ {
+ LOGMASKED(LOG_STATES, "timer_main txaddress1 finished m_byte=%d\n", m_byte);
+ m_byte = 0;
+ m_state_ptr++;
+ }
+ else
+ LOGMASKED(LOG_STATES, "timer_main txaddress1 window closed\n");
+ break;
+ case STATE_TXADDRESS2:
+ m_tx = true;
+ if (m_byte == 1)
+ {
+ LOGMASKED(LOG_STATES, "timer_main txaddress2 finished m_byte=%d\n", m_byte);
+ m_byte = 0;
+ m_state_ptr++;
+ }
+ else
+ LOGMASKED(LOG_STATES, "timer_main txaddress2 window closed\n");
+ break;
+ case STATE_TXOFFSET:
+ m_tx = true;
+ if (m_byte == 1)
+ {
+ LOGMASKED(LOG_STATES, "timer_main txoffset finished - m_byte=%d\n", m_byte);
+ m_byte = 0;
+ m_state_ptr++;
+ }
+ else
+ LOGMASKED(LOG_STATES, "timer_main txoffset window closed\n");
+ break;
+ case STATE_READ_MEMORY:
+ LOGMASKED(LOG_STATES, "timer_main state_readmemory\n");
+ break;
+ case STATE_COPY_SCRATCHPAD:
+ LOGMASKED(LOG_STATES, "timer_main state_copy_scratchpad\n");
+ break;
+ case STATE_READ_SCRATCHPAD:
+ LOGMASKED(LOG_STATES, "timer_main state_read_scratchpad\n");
+ break;
+ default:
+ LOGMASKED(LOG_ERRORS, "timer_main state not handled: %d\n", m_state[m_state_ptr]);
+ break;
+ }
+
+ if (m_state[m_state_ptr] == STATE_INIT_COMMAND)
+ {
+ switch (m_state[m_state_ptr + 1])
+ {
+ case STATE_IDLE:
+ case STATE_COMMAND:
+ case STATE_ADDRESS1:
+ case STATE_ADDRESS2:
+ case STATE_OFFSET:
+ break;
+ case STATE_READ_MEMORY:
+ LOGMASKED(LOG_STATES, "timer_main (init_cmd) -> state_read_memory - set address\n");
+ m_address = (m_a2 << 8) | m_a1;
+ break;
+ case STATE_WRITE_SCRATCHPAD:
+ LOGMASKED(LOG_STATES, "timer_main (init_cmd) -> state_write_scratchpad - set address\n");
+ m_offs_ro = false;
+ m_offset = 0;
+ break;
+ case STATE_READ_SCRATCHPAD:
+ LOGMASKED(LOG_STATES, "timer_main (init_cmd) -> state_read_scratchpad - set address\n");
+ m_address = 0;
+ break;
+ case STATE_COPY_SCRATCHPAD:
+ LOGMASKED(LOG_STATES, "timer_main (init_cmd) -> state_copy_scratchpad - do copy\n");
+ if (m_auth)
+ {
+ m_address = (m_a2 << 8) | m_a1;
+ for (int i = 0; i <= m_offset; i++)
+ {
+ writemem(m_ram[i]);
+ m_address++;
+ }
+ }
+ else
+ LOGMASKED(LOG_STATES, "timer_main (init_cmd) -> state_copy_scratchpad - Auth-Rejected\n");
+ break;
+ }
+ m_state_ptr++;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(ds1994_device::reset_tick)
+{
+ LOGMASKED(LOG_RESETS, "timer_reset\n");
+ m_state[m_state_ptr] = STATE_RESET;
+ m_timer_reset->adjust(attotime::never);
+}
+
+TIMER_CALLBACK_MEMBER(ds1994_device::clock_tick)
+{
+ for (uint8_t &elem : m_rtc)
+ {
+ elem++;
+ if (elem != 0)
+ {
+ break;
+ }
}
}
@@ -587,9 +586,9 @@ void ds1994_device::device_timer(emu_timer &timer, device_timer_id id, int param
/* */
/*********************/
-WRITE_LINE_MEMBER(ds1994_device::write)
+void ds1994_device::write(int state)
{
- verboselog(1, "write(%d)\n", state);
+ LOGMASKED(LOG_WRITES, "write(%d)\n", state);
if (!state && m_rx)
{
switch (m_state[m_state_ptr])
@@ -598,27 +597,27 @@ WRITE_LINE_MEMBER(ds1994_device::write)
case STATE_INIT_COMMAND:
break;
case STATE_ROMCMD:
- verboselog(2, "state_romcommand\n");
+ LOGMASKED(LOG_WRITES, "state_romcommand\n");
m_timer_main->adjust(t_samp);
break;
case STATE_COMMAND:
- verboselog(2, "state_command\n");
+ LOGMASKED(LOG_WRITES, "state_command\n");
m_timer_main->adjust(t_samp);
break;
case STATE_ADDRESS1:
- verboselog(2, "state_address1\n");
+ LOGMASKED(LOG_WRITES, "state_address1\n");
m_timer_main->adjust(t_samp);
break;
case STATE_ADDRESS2:
- verboselog(2, "state_address2\n");
+ LOGMASKED(LOG_WRITES, "state_address2\n");
m_timer_main->adjust(t_samp);
break;
case STATE_OFFSET:
- verboselog(2, "state_offset\n");
+ LOGMASKED(LOG_WRITES, "state_offset\n");
m_timer_main->adjust(t_samp);
break;
case STATE_TXADDRESS1:
- verboselog(2, "state_txaddress1\n");
+ LOGMASKED(LOG_WRITES, "state_txaddress1\n");
if (one_wire_tx_bit(m_a1))
{
m_bit = 0;
@@ -627,7 +626,7 @@ WRITE_LINE_MEMBER(ds1994_device::write)
m_timer_main->adjust(t_rdv);
break;
case STATE_TXADDRESS2:
- verboselog(2, "state_txaddress2\n");
+ LOGMASKED(LOG_WRITES, "state_txaddress2\n");
if (one_wire_tx_bit(m_a2))
{
m_bit = 0;
@@ -636,7 +635,7 @@ WRITE_LINE_MEMBER(ds1994_device::write)
m_timer_main->adjust(t_rdv);
break;
case STATE_TXOFFSET:
- verboselog(2, "state_txoffset\n");
+ LOGMASKED(LOG_WRITES, "state_txoffset\n");
if (one_wire_tx_bit(m_offset))
{
m_bit = 0;
@@ -645,7 +644,7 @@ WRITE_LINE_MEMBER(ds1994_device::write)
m_timer_main->adjust(t_rdv);
break;
case STATE_READROM:
- verboselog(2, "state_readrom\n");
+ LOGMASKED(LOG_WRITES, "state_readrom\n");
if (one_wire_tx_bit(m_rom[7 - m_byte]))
{
m_bit = 0;
@@ -654,8 +653,8 @@ WRITE_LINE_MEMBER(ds1994_device::write)
m_timer_main->adjust(t_rdv);
break;
case STATE_READ_MEMORY:
- verboselog(2, "state_read_memory\n");
- if (one_wire_tx_bit(ds1994_readmem()))
+ LOGMASKED(LOG_WRITES, "state_read_memory\n");
+ if (one_wire_tx_bit(readmem()))
{
m_bit = 0;
if (m_address < DATA_SIZE + RTC_SIZE + REGS_SIZE)
@@ -666,29 +665,29 @@ WRITE_LINE_MEMBER(ds1994_device::write)
m_timer_main->adjust(t_rdv);
break;
case STATE_MATCHROM:
- verboselog(2, "state_matchrom\n");
+ LOGMASKED(LOG_WRITES, "state_matchrom\n");
m_timer_main->adjust(t_rdv);
break;
case STATE_COPY_SCRATCHPAD:
if (m_auth)
{
- verboselog(2, "state_copy_scratchpad Auth_Code Match: %d\n", m_tx);
+ LOGMASKED(LOG_WRITES, "state_copy_scratchpad Auth_Code Match: %d\n", m_tx);
m_tx = true;
m_auth = false;
}
else
{
m_tx = false;
- verboselog(1, "state_copy_scratchpad Auth_Code No Match: %d\n", m_tx);
+ LOGMASKED(LOG_WRITES, "state_copy_scratchpad Auth_Code No Match: %d\n", m_tx);
}
m_timer_main->adjust(t_rdv);
break;
case STATE_WRITE_SCRATCHPAD:
- verboselog(2, "state_write_scratchpad\n");
+ LOGMASKED(LOG_WRITES, "state_write_scratchpad\n");
m_timer_main->adjust(t_samp);
break;
case STATE_READ_SCRATCHPAD:
- verboselog(2, "state_read_scratchpad\n");
+ LOGMASKED(LOG_WRITES, "state_read_scratchpad\n");
if (one_wire_tx_bit(m_ram[m_address]))
{
m_bit = 0;
@@ -700,7 +699,7 @@ WRITE_LINE_MEMBER(ds1994_device::write)
m_timer_main->adjust(t_rdv);
break;
default:
- verboselog(0, "state not handled: %d\n", m_state[m_state_ptr]);
+ LOGMASKED(LOG_ERRORS | LOG_WRITES, "state not handled: %d\n", m_state[m_state_ptr]);
break;
}
m_timer_reset->adjust(t_rstl);
@@ -726,9 +725,9 @@ WRITE_LINE_MEMBER(ds1994_device::write)
/* */
/*********************/
-READ_LINE_MEMBER(ds1994_device::read)
+int ds1994_device::read()
{
- verboselog(2, "read %d\n", m_tx && m_rx);
+ LOGMASKED(LOG_READS, "read %d\n", m_tx && m_rx);
return m_tx && m_rx;
}
@@ -751,13 +750,28 @@ void ds1994_device::nvram_default()
// .nv file
//-------------------------------------------------
-void ds1994_device::nvram_read(emu_file &file)
+bool ds1994_device::nvram_read(util::read_stream &file)
{
- file.read(m_rom, ROM_SIZE);
- file.read(m_ram, SPD_SIZE);
- file.read(m_sram, DATA_SIZE);
- file.read(m_rtc, RTC_SIZE);
- file.read(m_regs, REGS_SIZE);
+ std::error_condition err;
+ size_t actual;
+
+ std::tie(err, actual) = util::read(file, m_rom, ROM_SIZE);
+ if (err || (ROM_SIZE != actual))
+ return false;
+ std::tie(err, actual) = util::read(file, m_ram, SPD_SIZE);
+ if (err || (SPD_SIZE != actual))
+ return false;
+ std::tie(err, actual) = util::read(file, m_sram, DATA_SIZE);
+ if (err || (DATA_SIZE != actual))
+ return false;
+ std::tie(err, actual) = util::read(file, m_rtc, RTC_SIZE);
+ if (err || (RTC_SIZE != actual))
+ return false;
+ std::tie(err, actual) = util::read(file, m_regs, REGS_SIZE);
+ if (err || (REGS_SIZE != actual))
+ return false;
+
+ return true;
}
//-------------------------------------------------
@@ -765,11 +779,26 @@ void ds1994_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void ds1994_device::nvram_write(emu_file &file)
+bool ds1994_device::nvram_write(util::write_stream &file)
{
- file.write(m_rom, ROM_SIZE);
- file.write(m_ram, SPD_SIZE);
- file.write(m_sram, DATA_SIZE);
- file.write(m_rtc, RTC_SIZE);
- file.write(m_regs, REGS_SIZE);
+ std::error_condition err;
+ size_t actual;
+
+ std::tie(err, actual) = util::write(file, m_rom, ROM_SIZE);
+ if (err)
+ return false;
+ std::tie(err, actual) = util::write(file, m_ram, SPD_SIZE);
+ if (err)
+ return false;
+ std::tie(err, actual) = util::write(file, m_sram, DATA_SIZE);
+ if (err)
+ return false;
+ std::tie(err, actual) = util::write(file, m_rtc, RTC_SIZE);
+ if (err)
+ return false;
+ std::tie(err, actual) = util::write(file, m_regs, REGS_SIZE);
+ if (err)
+ return false;
+
+ return true;
}
diff --git a/src/devices/machine/ds1994.h b/src/devices/machine/ds1994.h
index a65f1b7d688..248fc6e8e90 100644
--- a/src/devices/machine/ds1994.h
+++ b/src/devices/machine/ds1994.h
@@ -30,19 +30,18 @@ class ds1994_device : public device_t, public device_nvram_interface
void ref_month(uint8_t month) { m_ref_month = month; }
void ref_day(uint8_t day) { m_ref_day = day; }
- DECLARE_WRITE_LINE_MEMBER(write);
- DECLARE_READ_LINE_MEMBER(read);
+ void write(int state);
+ int read();
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
enum {
@@ -65,12 +64,6 @@ class ds1994_device : public device_t, public device_nvram_interface
};
enum {
- TIMER_MAIN,
- TIMER_RESET,
- TIMER_CLOCK
- };
-
- enum {
STATE_IDLE,
STATE_RESET,
STATE_RESET1,
@@ -93,14 +86,20 @@ class ds1994_device : public device_t, public device_nvram_interface
STATE_COPY_SCRATCHPAD
};
- void ds1994_rom_cmd(void);
- void ds1994_cmd(void);
+ void handle_rom_cmd(void);
+ void handle_cmd(void);
bool one_wire_tx_bit(uint8_t value);
bool one_wire_rx_bit(void);
- uint8_t ds1994_readmem();
- void ds1994_writemem(uint8_t value);
+ uint8_t readmem();
+ void writemem(uint8_t value);
- emu_timer *m_timer_main, *m_timer_reset, *m_timer_clock;
+ TIMER_CALLBACK_MEMBER(main_tick);
+ TIMER_CALLBACK_MEMBER(reset_tick);
+ TIMER_CALLBACK_MEMBER(clock_tick);
+
+ emu_timer *m_timer_main;
+ emu_timer *m_timer_reset;
+ emu_timer *m_timer_clock;
uint32_t m_ref_year;
uint8_t m_ref_month;
@@ -124,8 +123,6 @@ class ds1994_device : public device_t, public device_nvram_interface
bool m_offs_ro;
attotime t_samp, t_rdv, t_rstl, t_pdh, t_pdl;
-
- inline void verboselog(int n_level, const char *s_fmt, ...) ATTR_PRINTF(3, 4);
};
// device type definition
diff --git a/src/devices/machine/ds2401.cpp b/src/devices/machine/ds2401.cpp
index a5fea5b189b..758d4405013 100644
--- a/src/devices/machine/ds2401.cpp
+++ b/src/devices/machine/ds2401.cpp
@@ -9,7 +9,9 @@
*/
#include "emu.h"
-#include "machine/ds2401.h"
+#include "ds2401.h"
+
+#include <cstdarg>
#define VERBOSE_LEVEL 0
@@ -60,8 +62,8 @@ void ds2401_device::device_start()
save_item(NAME(m_rx));
save_item(NAME(m_tx));
- m_timer_main = timer_alloc(TIMER_MAIN);
- m_timer_reset = timer_alloc(TIMER_RESET);
+ m_timer_main = timer_alloc(FUNC(ds2401_device::main_tick), this);
+ m_timer_reset = timer_alloc(FUNC(ds2401_device::reset_tick), this);
}
void ds2401_device::device_reset()
@@ -92,85 +94,82 @@ void ds2401_device::device_reset()
memset(m_data, 0, SIZE_DATA);
}
-void ds2401_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ds2401_device::reset_tick)
{
- switch(id)
+ verboselog(1, "timer_reset\n");
+ m_state = STATE_RESET;
+ m_timer_reset->adjust(attotime::never);
+}
+
+TIMER_CALLBACK_MEMBER(ds2401_device::main_tick)
+{
+ switch(m_state)
{
- case TIMER_RESET:
- verboselog(1, "timer_reset\n");
- m_state = STATE_RESET;
- m_timer_reset->adjust(attotime::never);
+ case STATE_RESET1:
+ verboselog(2, "timer_main state_reset1 %d\n", m_rx);
+ m_tx = false;
+ m_state = STATE_RESET2;
+ m_timer_main->adjust(t_pdl);
break;
- case TIMER_MAIN:
- switch(m_state)
- {
- case STATE_RESET1:
- verboselog(2, "timer_main state_reset1 %d\n", m_rx);
- m_tx = false;
- m_state = STATE_RESET2;
- m_timer_main->adjust(t_pdl);
- break;
+ case STATE_RESET2:
+ verboselog(2, "timer_main state_reset2 %d\n", m_rx);
+ m_tx = true;
+ m_bit = 0;
+ m_shift = 0;
+ m_state = STATE_COMMAND;
+ break;
- case STATE_RESET2:
- verboselog(2, "timer_main state_reset2 %d\n", m_rx);
- m_tx = true;
- m_bit = 0;
- m_shift = 0;
- m_state = STATE_COMMAND;
- break;
+ case STATE_COMMAND:
+ verboselog(2, "timer_main state_command %d\n", m_rx);
- case STATE_COMMAND:
- verboselog(2, "timer_main state_command %d\n", m_rx);
+ m_shift >>= 1;
+ if(m_rx)
+ {
+ m_shift |= 0x80;
+ }
- m_shift >>= 1;
- if(m_rx)
+ m_bit++;
+ if(m_bit == 8)
+ {
+ switch(m_shift)
{
- m_shift |= 0x80;
- }
+ case COMMAND_READROM:
+ case COMMAND_READROM_COMPAT:
+ verboselog(1, "timer_main readrom\n");
+ m_bit = 0;
+ m_byte = 0;
+ m_state = STATE_READROM;
+ break;
- m_bit++;
- if(m_bit == 8)
- {
- switch(m_shift)
- {
- case COMMAND_READROM:
- case COMMAND_READROM_COMPAT:
- verboselog(1, "timer_main readrom\n");
- m_bit = 0;
- m_byte = 0;
- m_state = STATE_READROM;
- break;
-
- default:
- verboselog(0, "timer_main command not handled %02x\n", m_shift);
- m_state = STATE_IDLE;
- break;
- }
+ default:
+ verboselog(0, "timer_main command not handled %02x\n", m_shift);
+ m_state = STATE_IDLE;
+ break;
}
- break;
+ }
+ break;
- case STATE_READROM:
- m_tx = true;
+ case STATE_READROM:
+ m_tx = true;
- if( m_byte == SIZE_DATA )
- {
- verboselog(1, "timer_main readrom finished\n");
- m_state = STATE_IDLE;
- }
- else
- {
- verboselog(2, "timer_main readrom window closed\n");
- }
- break;
- default:
- verboselog(0, "timer_main state not handled: %d\n", m_state);
- break;
+ if( m_byte == SIZE_DATA )
+ {
+ verboselog(1, "timer_main readrom finished\n");
+ m_state = STATE_IDLE;
}
+ else
+ {
+ verboselog(2, "timer_main readrom window closed\n");
+ }
+ break;
+ default:
+ verboselog(0, "timer_main state not handled: %d\n", m_state);
+ break;
}
}
-WRITE_LINE_MEMBER( ds2401_device::write )
+void ds2401_device::write(int state)
{
verboselog(1, "write(%d)\n", state);
@@ -230,7 +229,7 @@ WRITE_LINE_MEMBER( ds2401_device::write )
m_rx = state;
}
-READ_LINE_MEMBER( ds2401_device::read )
+int ds2401_device::read()
{
verboselog(2, "read %d\n", m_tx && m_rx);
return m_tx && m_rx;
diff --git a/src/devices/machine/ds2401.h b/src/devices/machine/ds2401.h
index 8b74c603cf9..30d266be796 100644
--- a/src/devices/machine/ds2401.h
+++ b/src/devices/machine/ds2401.h
@@ -24,8 +24,8 @@ public:
ds2401_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER( write );
- DECLARE_READ_LINE_MEMBER( read );
+ void write(int state);
+ int read();
uint8_t direct_read(int index);
protected:
@@ -45,15 +45,12 @@ protected:
STATE_READROM
};
- enum {
- TIMER_MAIN,
- TIMER_RESET
- };
-
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(reset_tick);
+ TIMER_CALLBACK_MEMBER(main_tick);
// internal state
int m_state, m_bit, m_shift;
diff --git a/src/devices/machine/ds2404.cpp b/src/devices/machine/ds2404.cpp
index 0b62e2dbbcf..680b4043e20 100644
--- a/src/devices/machine/ds2404.cpp
+++ b/src/devices/machine/ds2404.cpp
@@ -73,7 +73,7 @@ void ds2404_device::device_start()
for (auto & elem : m_state)
elem = STATE_IDLE;
- m_tick_timer = timer_alloc(0);
+ m_tick_timer = timer_alloc(FUNC(ds2404_device::timer_tick), this);
m_tick_timer->adjust(attotime::from_hz(256), 0, attotime::from_hz(256));
}
@@ -317,22 +317,13 @@ void ds2404_device::clk_w(uint8_t data)
}
}
-void ds2404_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ds2404_device::timer_tick)
{
- switch(id)
+ for(uint8_t &elem : m_rtc)
{
- case 0:
- // tick
- for(auto &elem : m_rtc)
- {
- elem++;
- if(elem != 0)
- break;
- }
+ elem++;
+ if(elem != 0)
break;
-
- default:
- throw emu_fatalerror("Unknown id in ds2404_device::device_timer");
}
}
@@ -353,9 +344,10 @@ void ds2404_device::nvram_default()
// .nv file
//-------------------------------------------------
-void ds2404_device::nvram_read(emu_file &file)
+bool ds2404_device::nvram_read(util::read_stream &file)
{
- file.read(m_sram, sizeof(m_sram));
+ auto const [err, actual] = read(file, m_sram, sizeof(m_sram));
+ return !err && (actual == sizeof(m_sram));
}
@@ -364,7 +356,8 @@ void ds2404_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void ds2404_device::nvram_write(emu_file &file)
+bool ds2404_device::nvram_write(util::write_stream &file)
{
- file.write(m_sram, sizeof(m_sram));
+ auto const [err, actual] = write(file, m_sram, sizeof(m_sram));
+ return !err;
}
diff --git a/src/devices/machine/ds2404.h b/src/devices/machine/ds2404.h
index 3e31b5b14cc..1ed22887b87 100644
--- a/src/devices/machine/ds2404.h
+++ b/src/devices/machine/ds2404.h
@@ -43,10 +43,10 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ TIMER_CALLBACK_MEMBER(timer_tick);
private:
void rom_cmd(uint8_t cmd);
diff --git a/src/devices/machine/ds2430a.cpp b/src/devices/machine/ds2430a.cpp
new file mode 100644
index 00000000000..fca443e76a1
--- /dev/null
+++ b/src/devices/machine/ds2430a.cpp
@@ -0,0 +1,693 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Dallas Semiconductor DS2430A 256-Bit 1-Wire EEPROM
+
+ The EEPROM is organized as 32 bytes of storage, backed by a
+ volatile scratchpad of identical size. The EEPROM itself is not
+ addressible, but may be copied to the scratchpad quickly in its
+ entirety by the "read memory" command. Copying the scratchpad to
+ EEPROM is also a bulk operation but of course takes longer.
+
+ The other addressable memory type in the DS2430A is a 64-bit
+ (i.e. 8-byte) "application" register. This can only be programmed
+ once, at which time two bits in the status register are zeroed
+ permanently. It is likewise backed by a scratchpad area, which
+ ceases to be readable once the register has been locked. (This
+ register seems to be rarely used and is currently not fully
+ emulated.)
+
+ As with most Dallas 1-Wire devices (but not the original DS2430,
+ which otherwise had the same organization but used a completely
+ incompatible command set), each DS2430A also contains a factory-
+ lasered ROM whose contents are an 8-bit device code (14h for this
+ type), a unique 48-bit serial number and an 8-bit CRC of the
+ preceding 56 bits.
+
+ Unlike most other 1-Wire EEPROMs, the DS2430A memory commands use
+ an 8-bit rather than 16-bit address for the EEPROM scratchpad and
+ the application register. The addresses wrap continuously from
+ 1Fh or 07h to 00h for both read and write operations.
+
+ DS1971 contains the same chip as DS2430A, but comes in a small
+ round MicroCan package.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "ds2430a.h"
+
+#include <numeric> // std::accumulate
+#include <tuple> // std::tie
+
+#define LOG_PULSE (1U << 1)
+#define LOG_BITS (1U << 2)
+#define LOG_STATE (1U << 3)
+#define LOG_DATA (1U << 4)
+#define LOG_COMMAND (1U << 5)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definitions
+DEFINE_DEVICE_TYPE(DS2430A, ds2430a_device, "ds2430a", "Dallas DS2430A 1-Wire EEPROM")
+DEFINE_DEVICE_TYPE(DS1971, ds1971_device, "ds1971", "Dallas DS1971 EEPROM iButton")
+
+
+//**************************************************************************
+// 1-WIRE PROTOCOL IMPLEMENTATION
+//**************************************************************************
+
+// timing constants
+static constexpr attoseconds_t tRSTL = 480 * ATTOSECONDS_PER_MICROSECOND; // 480 μs ≤ t < ∞
+static constexpr attoseconds_t tRSTH = 480 * ATTOSECONDS_PER_MICROSECOND; // 480 μs ≤ t < ∞
+static constexpr attoseconds_t tPDL = 120 * ATTOSECONDS_PER_MICROSECOND; // 60 μs ≤ t < 240 μs
+static constexpr attoseconds_t tPDH = 16 * ATTOSECONDS_PER_MICROSECOND; // 15 μs ≤ t < 60 μs (but must exceed 15 μs for Konami Viper games)
+static constexpr attoseconds_t tSLOT = 60 * ATTOSECONDS_PER_MICROSECOND; // 60 μs ≤ t < 120 μs
+static constexpr attoseconds_t tREC = 1 * ATTOSECONDS_PER_MICROSECOND; // 1 μs ≤ t < ∞
+static constexpr attoseconds_t tLOW0 = 60 * ATTOSECONDS_PER_MICROSECOND; // 60 μs ≤ t < 120 μs
+static constexpr attoseconds_t tLOW1 = 15 * ATTOSECONDS_PER_MICROSECOND; // 1 μs ≤ t < 15 μs
+static constexpr attoseconds_t tRELEASE = 30 * ATTOSECONDS_PER_MICROSECOND; // 1 μs ≤ t < 45 μs
+static constexpr attoseconds_t tCOPY = 10 * ATTOSECONDS_PER_MILLISECOND;
+static constexpr attoseconds_t tRDV = 15 * ATTOSECONDS_PER_MICROSECOND;
+static constexpr attoseconds_t tSLOT_read = tRDV + tRELEASE + tREC; // timing loops may be tighter for reads than for writes?
+
+static const char *const c_state_desc[] =
+{
+ "presence",
+ "ROM command",
+ "ROM read",
+ "ROM match",
+ "ROM search bit",
+ "ROM search /bit",
+ "ROM search write",
+ "memory command",
+ "memory read",
+ "memory write",
+ "memory copy",
+ "done"
+};
+
+ALLOW_SAVE_TYPE(ds1wire_device::state)
+
+
+//-------------------------------------------------
+// ds1wire_device - constructor
+//-------------------------------------------------
+
+ds1wire_device::ds1wire_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_timing_scale(1.0)
+ , m_slot_timer(nullptr)
+ , m_data_in(true) // idle state is high
+ , m_data_out(true)
+ , m_shift_data(0)
+ , m_command(0)
+ , m_bit_count(0)
+ , m_pulse_start_time(attotime::zero)
+ , m_current_state(state::DONE)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ds1wire_device::device_start()
+{
+ m_slot_timer = timer_alloc(FUNC(ds1wire_device::update_state), this);
+
+ // save state
+ save_item(NAME(m_data_in));
+ save_item(NAME(m_data_out));
+ save_item(NAME(m_shift_data));
+ save_item(NAME(m_command));
+ save_item(NAME(m_bit_count));
+ save_item(NAME(m_pulse_start_time));
+ save_item(NAME(m_current_state));
+}
+
+
+//-------------------------------------------------
+// data_r - read signal on data line
+//-------------------------------------------------
+
+int ds1wire_device::data_r()
+{
+ // Open drain output produces wired-AND signal
+ return m_data_in && m_data_out;
+}
+
+
+//-------------------------------------------------
+// data_w - write bit to data line
+//-------------------------------------------------
+
+void ds1wire_device::data_w(int state)
+{
+ // Look for transitions
+ if (m_data_in && !state)
+ {
+ m_data_in = false;
+ pulse_start(machine().time());
+ }
+ else if (!m_data_in && state)
+ {
+ m_data_in = true;
+ pulse_end(machine().time());
+ }
+}
+
+
+//-------------------------------------------------
+// set_state - handle internal state changes
+//-------------------------------------------------
+
+bool ds1wire_device::set_state(ds1wire_device::state new_state)
+{
+ if (m_current_state != new_state)
+ {
+ LOGMASKED(LOG_STATE, "New state: %s\n", c_state_desc[int(new_state)]);
+ m_current_state = new_state;
+ m_bit_count = 0;
+ return true;
+ }
+
+ return false;
+}
+
+
+//-------------------------------------------------
+// pulse_start - handle falling edge on data line
+//-------------------------------------------------
+
+void ds1wire_device::pulse_start(attotime time)
+{
+ if (m_pulse_start_time <= time)
+ {
+ m_pulse_start_time = time;
+ LOGMASKED(LOG_PULSE, "Pulse started at %s\n", time.to_string());
+
+ switch (m_current_state)
+ {
+ case state::MEMORY_READ:
+ case state::ROM_READ:
+ case state::ROM_SEARCH:
+ if ((m_bit_count & 7) == 0)
+ {
+ if (m_current_state == state::MEMORY_READ)
+ {
+ m_shift_data = ds1wire_read_memory(m_command, m_bit_count >> 3);
+ LOGMASKED(LOG_DATA, "%s: Master Rx byte %d = %02Xh (memory command %02Xh)\n", machine().describe_context(), m_bit_count >> 3, m_shift_data, m_command);
+ }
+ else
+ {
+ m_shift_data = ds1wire_read_rom(m_bit_count >> 3);
+ LOGMASKED(LOG_DATA, "%s: Master Rx ROM byte %d = %02Xh\n", machine().describe_context(), m_bit_count >> 3, m_shift_data);
+ }
+ }
+ LOGMASKED(LOG_BITS, "%s: Master Rx bit %d = %d\n", machine().describe_context(), m_bit_count & 7, BIT(m_shift_data, 0));
+ if (!BIT(m_shift_data, 0))
+ {
+ m_data_out = false;
+ m_slot_timer->adjust(scaled_time(tRELEASE));
+ }
+ break;
+
+ case state::ROM_MATCH:
+ if ((m_bit_count & 7) == 0)
+ m_shift_data = ds1wire_read_rom(m_bit_count >> 3);
+ break;
+
+ case state::ROM_SEARCH_COMPLEMENT:
+ LOGMASKED(LOG_BITS, "%s: Master Rx /bit %d = %d\n", machine().describe_context(), m_bit_count & 7, !BIT(m_shift_data, 0));
+ if (BIT(m_shift_data, 0))
+ {
+ m_data_out = false;
+ m_slot_timer->adjust(scaled_time(tRELEASE));
+ }
+ break;
+
+ case state::MEMORY_COPY:
+ logerror("Copy interrupted at %s\n", time.to_string());
+ (void)set_state(state::DONE);
+ break;
+
+ case state::PRESENCE:
+ case state::ROM_COMMAND:
+ case state::MEMORY_COMMAND:
+ case state::MEMORY_WRITE:
+ case state::ROM_SEARCH_WRITE:
+ case state::DONE:
+ // Only compilers care about cases that do nothing
+ break;
+ }
+ }
+ else
+ LOGMASKED(LOG_PULSE, "Pulse started too early at %s\n", time.to_string());
+}
+
+
+//-------------------------------------------------
+// pulse_end - handle rising edge on data line
+//-------------------------------------------------
+
+void ds1wire_device::pulse_end(attotime time)
+{
+ if (m_pulse_start_time < time)
+ {
+ // Measure pulse width
+ attotime pulse_width = time - m_pulse_start_time;
+ LOGMASKED(LOG_PULSE, "Pulse ended at %s (%d us measured width)\n", time.to_string(), int(pulse_width.as_double() * 1.0E6));
+ pulse_width = attotime::from_double(pulse_width.as_double() / m_timing_scale);
+
+ if (pulse_width >= attotime(0, tRSTL))
+ {
+ LOGMASKED(LOG_BITS, "%s: Master reset\n", machine().describe_context());
+ (void)set_state(state::PRESENCE);
+ m_slot_timer->adjust(scaled_time(tPDH));
+ m_pulse_start_time = time + scaled_time(tRSTH);
+ }
+ else if (pulse_width < attotime(0, tREC))
+ LOGMASKED(LOG_PULSE, "Pulse ended too early at %s\n", time.to_string());
+ else switch (m_current_state)
+ {
+ case state::ROM_COMMAND:
+ case state::MEMORY_COMMAND:
+ case state::MEMORY_WRITE:
+ m_shift_data >>= 1;
+ if (pulse_width < attotime(0, tLOW0))
+ m_shift_data |= 0x80;
+ LOGMASKED(LOG_BITS, "%s: Master Tx bit %d = %d\n", machine().describe_context(), m_bit_count & 7, BIT(m_shift_data, 7));
+ if ((m_bit_count & 7) == 7)
+ {
+ if ((m_bit_count >> 3) == 0 && (m_current_state == state::ROM_COMMAND || m_current_state == state::MEMORY_COMMAND))
+ {
+ LOGMASKED(LOG_COMMAND, "%s: Master Tx %s command = %02Xh\n", machine().describe_context(), m_current_state == state::ROM_COMMAND ? "ROM" : "memory", m_shift_data);
+ m_command = m_shift_data;
+ }
+ else
+ LOGMASKED(LOG_DATA, "%s: Master Tx byte %d = %02Xh\n", machine().describe_context(), m_bit_count >> 3, m_shift_data);
+ state next_state = ds1wire_next_state(m_current_state, m_command, m_bit_count >> 3, m_shift_data);
+ if (set_state(next_state))
+ {
+ if (next_state == state::MEMORY_COPY)
+ {
+ m_slot_timer->adjust(scaled_time(tCOPY));
+ break;
+ }
+ }
+ else
+ ++m_bit_count;
+ }
+ else
+ ++m_bit_count;
+ m_pulse_start_time += scaled_time(tSLOT);
+ break;
+
+ case state::MEMORY_READ:
+ case state::ROM_READ:
+ m_shift_data >>= 1;
+ if ((m_bit_count & 7) != 7 || !set_state(ds1wire_next_state(m_current_state, m_command, m_bit_count >> 3, 0)))
+ ++m_bit_count;
+ m_pulse_start_time += scaled_time(tSLOT_read);
+ break;
+
+ case state::ROM_SEARCH:
+ m_current_state = state::ROM_SEARCH_COMPLEMENT;
+ m_pulse_start_time += scaled_time(tSLOT_read);
+ break;
+
+ case state::ROM_SEARCH_COMPLEMENT:
+ m_current_state = state::ROM_SEARCH_WRITE;
+ m_pulse_start_time += scaled_time(tSLOT_read);
+ break;
+
+ case state::ROM_MATCH:
+ case state::ROM_SEARCH_WRITE:
+ if ((pulse_width >= attotime(0, tLOW0)) == BIT(m_shift_data, 0))
+ {
+ LOGMASKED(LOG_BITS, "%s: Master Tx bit %d not matched; device deselected\n", machine().describe_context(), m_bit_count & 7);
+ (void)set_state(state::DONE);
+ }
+ else
+ {
+ LOGMASKED(LOG_BITS, "%s: Master Tx bit %d = %d (matched)\n", machine().describe_context(), m_bit_count & 7, BIT(m_shift_data, 0));
+ m_shift_data >>= 1;
+ if ((m_bit_count & 7) != 7 || !set_state(ds1wire_next_state(m_current_state, m_command, m_bit_count >> 3, 0)))
+ {
+ ++m_bit_count;
+ if (m_current_state == state::ROM_SEARCH_WRITE)
+ m_current_state = state::ROM_SEARCH;
+ }
+ }
+ m_pulse_start_time += scaled_time(tSLOT);
+ break;
+
+ case state::PRESENCE:
+ case state::MEMORY_COPY:
+ case state::DONE:
+ // Only compilers care about cases that do nothing
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_state - generate timed responses to bus
+// transactions
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(ds1wire_device::update_state)
+{
+ switch (m_current_state)
+ {
+ case state::PRESENCE:
+ m_data_out = !m_data_out;
+ LOGMASKED(LOG_PULSE, "Presence pulse %sactive\n", m_data_out ? "in" : "");
+ if (m_data_out)
+ (void)set_state(state::ROM_COMMAND);
+ else
+ m_slot_timer->adjust(scaled_time(tPDL));
+ break;
+
+ case state::MEMORY_READ:
+ case state::ROM_READ:
+ case state::ROM_SEARCH:
+ case state::ROM_SEARCH_COMPLEMENT:
+ case state::DONE: // pull up data line after reading last bit
+ m_data_out = true;
+ break;
+
+ case state::MEMORY_COPY:
+ ds1wire_memory_copy(m_command);
+ m_current_state = state::DONE;
+ break;
+
+ case state::ROM_COMMAND:
+ case state::ROM_MATCH:
+ case state::MEMORY_COMMAND:
+ case state::MEMORY_WRITE:
+ case state::ROM_SEARCH_WRITE:
+ // Only compilers care about cases that do nothing
+ break;
+ }
+}
+
+
+//**************************************************************************
+// DEVICE EMULATION
+//**************************************************************************
+
+//-------------------------------------------------
+// ds2430a_device - constructor
+//-------------------------------------------------
+
+ds2430a_device::ds2430a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : ds1wire_device(mconfig, type, tag, owner, clock)
+ , device_nvram_interface(mconfig, *this)
+ , m_default_data(*this, DEVICE_SELF)
+ , m_start_address(0)
+{
+ std::fill(std::begin(m_scratchpad), std::end(m_scratchpad), 0);
+ std::fill(std::begin(m_app_scratchpad), std::end(m_app_scratchpad), 0);
+}
+
+ds2430a_device::ds2430a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds2430a_device(mconfig, DS2430A, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// ds1971_device - constructor
+//-------------------------------------------------
+
+ds1971_device::ds1971_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ds2430a_device(mconfig, DS1971, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ds2430a_device::device_start()
+{
+ ds1wire_device::device_start();
+
+ save_item(NAME(m_eeprom));
+ save_item(NAME(m_scratchpad));
+ save_item(NAME(m_app_scratchpad));
+ save_item(NAME(m_start_address));
+}
+
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// specified file
+//-------------------------------------------------
+
+bool ds2430a_device::nvram_read(util::read_stream &file)
+{
+ std::error_condition err;
+ size_t actual;
+ std::tie(err, actual) = read(file, &m_eeprom[0], 0x20);
+ if (err || (0x20 != actual))
+ return false;
+ std::tie(err, actual) = read(file, &m_rom[0], 8);
+ if (err || (8 != actual))
+ return false;
+
+ if (m_rom[0] != 0x14)
+ osd_printf_error("Incorrect ROM family code (expected 14h, found %02Xh in saved data)\n", m_rom[0]);
+ u8 const crc = std::accumulate(std::begin(m_rom), std::end(m_rom) - 1, u8(0), &ds1wire_crc);
+ if (m_rom[7] != crc)
+ osd_printf_error("Incorrect ROM CRC (expected %02Xh, found %02Xh in saved data)\n", crc, m_rom[7]);
+
+ return true;
+}
+
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// specified file
+//-------------------------------------------------
+
+bool ds2430a_device::nvram_write(util::write_stream &file)
+{
+ std::error_condition err;
+ size_t actual;
+ std::tie(err, actual) = write(file, &m_eeprom[0], 0x20);
+ if (err)
+ return false;
+ std::tie(err, actual) = write(file, &m_rom[0], 8);
+ if (err)
+ return false;
+
+ return true;
+}
+
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void ds2430a_device::nvram_default()
+{
+ if (m_default_data.found())
+ {
+ std::copy_n(&m_default_data[0], 0x20, &m_eeprom[0]);
+ std::copy_n(&m_default_data[0x20], 8, &m_rom[0]);
+
+ if (m_rom[0] != 0x14)
+ osd_printf_error("Incorrect ROM family code (expected 14h, found %02Xh in default data)\n", m_rom[0]);
+ u8 crc = std::accumulate(std::begin(m_rom), std::end(m_rom) - 1, u8(0), &ds1wire_crc);
+ if (m_rom[7] != crc)
+ osd_printf_error("Incorrect ROM CRC (expected %02Xh, found %02Xh in default data)\n", crc, m_rom[7]);
+ }
+ else
+ {
+ // Erase EEPROM to ones
+ std::fill(std::begin(m_eeprom), std::end(m_eeprom), 0xff);
+
+ // Make up a fake ID (shh, nobody alert the authorities)
+ m_rom[0] = 0x14;
+ m_rom[1] = 0x11;
+ m_rom[2] = 0x22;
+ m_rom[3] = 0x33;
+ m_rom[4] = 0x44;
+ m_rom[5] = 0x55;
+ m_rom[6] = 0x66;
+ m_rom[7] = std::accumulate(std::begin(m_rom), std::end(m_rom) - 1, u8(0), &ds1wire_crc);
+ }
+}
+
+
+//-------------------------------------------------
+// ds1wire_next_state - handle memory byte writes
+// and state changes
+//-------------------------------------------------
+
+ds1wire_device::state ds2430a_device::ds1wire_next_state(ds1wire_device::state prev_state, u8 command, u16 index, u8 data)
+{
+ if (prev_state == state::ROM_COMMAND)
+ {
+ switch (command)
+ {
+ case 0x33: // Read ROM
+ return state::ROM_READ;
+
+ case 0x55: // Match ROM
+ return state::ROM_MATCH;
+
+ case 0xcc: // Skip ROM
+ return state::MEMORY_COMMAND;
+
+ case 0xf0: // Search ROM
+ return state::ROM_SEARCH;
+
+ default:
+ return state::DONE;
+ }
+ }
+ else if (prev_state == state::ROM_READ && index == 7)
+ return state::DONE;
+ else if ((prev_state == state::ROM_MATCH || prev_state == state::ROM_SEARCH_WRITE) && index == 7)
+ return state::MEMORY_COMMAND;
+ else if (prev_state == state::MEMORY_COMMAND)
+ {
+ switch (command)
+ {
+ case 0x0f: // Write Scratchpad
+ case 0x99: // Write Application Register
+ if (index == 1)
+ {
+ m_start_address = data;
+ return state::MEMORY_READ;
+ }
+ else
+ return state::MEMORY_COMMAND;
+
+ case 0x55: // Copy Scratchpad
+ case 0x5a: // Copy & Lock Application Register
+ if (index == 1)
+ {
+ // Validation key is A5h
+ if (data == 0xa5)
+ return state::MEMORY_COPY;
+ else
+ return state::DONE;
+ }
+ else
+ return state::MEMORY_COMMAND;
+
+ case 0x66: // Read Status Register
+ if (index == 1)
+ {
+ // Validation key is 00h
+ if (data == 0x00)
+ return state::MEMORY_READ;
+ else
+ return state::DONE;
+ }
+ else
+ return state::MEMORY_COMMAND;
+
+ case 0xf0: // Read Memory
+ if (index == 0)
+ std::copy(std::begin(m_eeprom), std::end(m_eeprom), std::begin(m_scratchpad));
+ [[fallthrough]];
+
+ case 0xaa: // Read Scratchpad
+ case 0xc3: // Read Application Register
+ if (index == 1)
+ {
+ m_start_address = data;
+ return state::MEMORY_READ;
+ }
+ else
+ return state::MEMORY_COMMAND;
+
+ default:
+ logerror("Unrecognized memory command %02Xh\n", command);
+ return state::DONE;
+ }
+ }
+ else if (prev_state == state::MEMORY_READ && command == 0x66)
+ {
+ // Status register does not wrap around
+ return state::DONE;
+ }
+ else
+ {
+ if (prev_state == state::MEMORY_WRITE)
+ {
+ if (command == 0x0f)
+ m_scratchpad[(m_start_address + index) & 0x1f] = data;
+ else if (command == 0x99)
+ m_app_scratchpad[(m_start_address + index) & 0x07] = data;
+ }
+ return prev_state;
+ }
+}
+
+
+//-------------------------------------------------
+// ds1wire_read_rom - fetch one byte from ROM
+//-------------------------------------------------
+
+u8 ds2430a_device::ds1wire_read_rom(u16 index) const
+{
+ assert(index <= 7);
+ return m_rom[index];
+}
+
+
+//-------------------------------------------------
+// ds1wire_read_memory - fetch one byte from the
+// selected memory area
+//-------------------------------------------------
+
+u8 ds2430a_device::ds1wire_read_memory(u8 command, u16 index) const
+{
+ switch (command)
+ {
+ case 0x66: // Read Status Register
+ return 0xff; // TODO (only low 2 bits may be zero)
+
+ case 0xaa: // Read Scratchpad
+ case 0xf0: // Read Memory
+ return m_scratchpad[(m_start_address + index) & 0x1f];
+
+ case 0xc3: // Read Application Register
+ return m_app_scratchpad[(m_start_address + index) & 0x07];
+
+ default:
+ return 0xff;
+ }
+}
+
+
+//-------------------------------------------------
+// ds1wire_memory_copy - execute copy command
+// after a delay
+//-------------------------------------------------
+
+void ds2430a_device::ds1wire_memory_copy(u8 command)
+{
+ if (command == 0x55)
+ std::copy(std::begin(m_scratchpad), std::end(m_scratchpad), std::begin(m_eeprom));
+ else if (command == 0x5a)
+ logerror("Copy scratchpad to application register (not supported)\n");
+}
diff --git a/src/devices/machine/ds2430a.h b/src/devices/machine/ds2430a.h
new file mode 100644
index 00000000000..2d00e9f31ff
--- /dev/null
+++ b/src/devices/machine/ds2430a.h
@@ -0,0 +1,145 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Dallas Semiconductor DS2430A 256-Bit 1-Wire EEPROM
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_DS2430A_H
+#define MAME_MACHINE_DS2430A_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> ds1wire_device
+
+class ds1wire_device : public device_t
+{
+protected:
+ enum class state : u8
+ {
+ PRESENCE = 0,
+ ROM_COMMAND,
+ ROM_READ,
+ ROM_MATCH,
+ ROM_SEARCH,
+ ROM_SEARCH_COMPLEMENT,
+ ROM_SEARCH_WRITE,
+ MEMORY_COMMAND,
+ MEMORY_READ,
+ MEMORY_WRITE,
+ MEMORY_COPY,
+ DONE
+ };
+
+ ds1wire_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ // Dallas 1-Wire CRC algorithm (use with std::accumulate)
+ static u8 ds1wire_crc(u8 crc, u8 data) noexcept
+ {
+ for (int i = 8; i > 0; --i)
+ {
+ crc = (crc >> 1) ^ (BIT(data ^ crc, 0) ? 0x8c : 0);
+ data >>= 1;
+ }
+ return crc;
+ }
+
+public:
+ void set_timing_scale(double scale) { m_timing_scale = scale; }
+
+ // serial data line handlers
+ int data_r();
+ void data_w(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+ virtual state ds1wire_next_state(state prev_state, u8 command, u16 index, u8 data) = 0;
+ virtual u8 ds1wire_read_rom(u16 index) const = 0;
+ virtual u8 ds1wire_read_memory(u8 command, u16 index) const = 0;
+ virtual void ds1wire_memory_copy(u8 command) = 0;
+
+private:
+ // internal helpers
+ attotime scaled_time(attoseconds_t tconst) const { return attotime(0, tconst * m_timing_scale); }
+ bool set_state(state new_state);
+ void pulse_start(attotime time);
+ void pulse_end(attotime time);
+ TIMER_CALLBACK_MEMBER(update_state);
+
+ // misc. configuration
+ double m_timing_scale;
+
+ // timer object
+ emu_timer *m_slot_timer;
+
+ // line state
+ bool m_data_in;
+ bool m_data_out;
+
+ // internal state
+ u8 m_shift_data;
+ u8 m_command;
+ u32 m_bit_count;
+ attotime m_pulse_start_time;
+ state m_current_state;
+};
+
+
+// ======================> ds2430a_device
+
+class ds2430a_device : public ds1wire_device, public device_nvram_interface
+{
+public:
+ // device type constructor
+ ds2430a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+protected:
+ ds2430a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+
+ // device_nvram_interface overrides
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+ virtual void nvram_default() override;
+
+ // ds1wire_device overrides
+ virtual state ds1wire_next_state(state prev_state, u8 command, u16 index, u8 data) override;
+ virtual u8 ds1wire_read_rom(u16 index) const override;
+ virtual u8 ds1wire_read_memory(u8 command, u16 index) const override;
+ virtual void ds1wire_memory_copy(u8 command) override;
+
+private:
+ optional_region_ptr<u8> m_default_data;
+
+ u8 m_rom[8];
+ u8 m_eeprom[0x20];
+ u8 m_scratchpad[0x20];
+ u8 m_app_scratchpad[8];
+
+ u8 m_start_address;
+};
+
+// ======================> ds1971_device
+
+class ds1971_device : public ds2430a_device
+{
+public:
+ // device type constructor
+ ds1971_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+};
+
+// device type declarations
+DECLARE_DEVICE_TYPE(DS2430A, ds2430a_device)
+DECLARE_DEVICE_TYPE(DS1971, ds1971_device)
+
+#endif // MAME_MACHINE_DS2430A_H
diff --git a/src/devices/machine/ds6417.cpp b/src/devices/machine/ds6417.cpp
new file mode 100644
index 00000000000..dcde73f2a43
--- /dev/null
+++ b/src/devices/machine/ds6417.cpp
@@ -0,0 +1,174 @@
+// license:BSD-3-Clause
+// copyright-holders:Carl
+
+
+#include "emu.h"
+#include "ds6417.h"
+
+
+DEFINE_DEVICE_TYPE(DS6417, ds6417_device, "ds6417", "Dallas DS6417 CyberCard")
+
+ds6417_device::ds6417_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, DS6417, tag, owner, clock)
+ , device_memcard_image_interface(mconfig, *this)
+{
+}
+
+void ds6417_device::device_start()
+{
+ save_item(NAME(m_read));
+ save_item(NAME(m_clk));
+ save_item(NAME(m_reset));
+ save_item(NAME(m_start));
+ save_item(NAME(m_data));
+ save_item(NAME(m_command));
+ save_item(NAME(m_addr));
+ save_item(NAME(m_crc));
+ save_item(NAME(m_select));
+ save_item(NAME(m_shiftreg));
+ save_item(NAME(m_count));
+}
+
+void ds6417_device::device_reset()
+{
+ m_read = false;
+ m_start = false;
+ m_count = 0;
+ m_command = 0;
+}
+
+std::pair<std::error_condition, std::string> ds6417_device::call_load()
+{
+ if(length() != 32768)
+ return std::make_pair(image_error::INVALIDLENGTH, "Incorrect image file size (must be 32K)");
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+std::pair<std::error_condition, std::string> ds6417_device::call_create(int format_type, util::option_resolution *format_options)
+{
+ u8 buffer[32768] = {0};
+ if(fwrite(buffer, 32768) != 32768)
+ return std::make_pair(std::errc::io_error, std::string());
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+uint8_t ds6417_device::calccrc(uint8_t bit, uint8_t crc) const
+{
+ bit = (crc ^ bit) & 1;
+ if(bit)
+ return ((crc >> 1) | (bit << 7)) ^ 0x66;
+ else
+ return crc >> 1;
+}
+
+void ds6417_device::clock_w(int state)
+{
+ if(!m_reset || !exists())
+ return;
+
+ if(m_clk == (state != 0))
+ return;
+
+ m_clk = state;
+
+ if(m_read && !m_clk && m_start)
+ {
+ if(!(m_count & 7))
+ {
+ switch(m_command)
+ {
+ case CMD_READ:
+ case CMD_READMASK:
+ fread(&m_shiftreg, 1);
+ break;
+ case CMD_READPROT:
+ m_shiftreg = m_selectval;
+ break;
+ case CMD_READCRC:
+ m_shiftreg = m_crc;
+ break;
+ }
+ }
+
+ m_data = m_shiftreg & 1;
+ m_shiftreg >>= 1;
+ m_count++;
+ m_crc = calccrc(m_data, m_crc);
+ }
+ else if(m_clk && !m_read)
+ {
+ m_shiftreg = (m_shiftreg >> 1) | (m_data ? 0x80 : 0);
+ m_count++;
+
+ if(m_start)
+ {
+ m_crc = calccrc(m_data, m_crc);
+ if(!(m_count & 7))
+ {
+ switch(m_command)
+ {
+ case CMD_WRITE:
+ fwrite(&m_shiftreg, 1);
+ break;
+ case CMD_WRITEPROT:
+ m_selectval = m_shiftreg;
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch(m_count)
+ {
+ case 8:
+ if((m_shiftreg != 0xe8) && (m_shiftreg != 0x17))
+ reset();
+ break;
+ case 16:
+ m_addr = m_shiftreg;
+ break;
+ case 24:
+ m_addr |= m_shiftreg << 8;
+ break;
+ case 32:
+ m_addr |= (m_shiftreg & 7) << 16;
+ m_command = m_shiftreg >> 3;
+ break;
+ case 40:
+ m_select = m_shiftreg;
+ break;
+ case 48:
+ m_select |= m_shiftreg << 8;
+ break;
+ case 56:
+ // command crc
+ if((m_command & CMD_READMASK) == CMD_READMASK)
+ {
+ m_selbits = m_command & 7;
+ m_command &= 0x18;
+ }
+ switch(m_command)
+ {
+ case CMD_READ:
+ case CMD_READMASK:
+ m_crc = 0; [[fallthrough]];
+ case CMD_READPROT:
+ case CMD_READCRC:
+ m_read = true;
+ break;
+ case CMD_WRITE:
+ m_crc = 0; [[fallthrough]];
+ case CMD_WRITEPROT:
+ break;
+ default:
+ reset();
+ return;
+
+ }
+ m_start = true;
+ fseek(m_addr & 0x7fff, SEEK_SET);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/devices/machine/ds6417.h b/src/devices/machine/ds6417.h
new file mode 100644
index 00000000000..c71f7186d14
--- /dev/null
+++ b/src/devices/machine/ds6417.h
@@ -0,0 +1,63 @@
+// license:BSD-3-Clause
+// copyright-holders:Carl
+
+// Only known to be used by the Tandy VIS
+
+#ifndef MAME_MACHINE_DS6417_H
+#define MAME_MACHINE_DS6417_H
+
+#pragma once
+
+#include "imagedev/memcard.h"
+
+
+class ds6417_device : public device_t,
+ public device_memcard_image_interface
+{
+public:
+ // construction/destruction
+ ds6417_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *file_extensions() const noexcept override { return "bin"; }
+
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
+
+ void data_w(int state) { if(!m_read) m_data = state; }
+ void clock_w(int state);
+ void reset_w(int state) { if(!state && m_reset) reset(); m_reset = state; }
+ int data_r() { return m_read ? m_data : 0; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ uint8_t calccrc(uint8_t bit, uint8_t crc) const;
+ enum {
+ CMD_READ = 0x06,
+ CMD_WRITE = 0x11,
+ CMD_READPROT = 0x05,
+ CMD_WRITEPROT = 0x0e,
+ CMD_READMASK = 0x18,
+ CMD_READCRC = 0x03
+ };
+ bool m_reset;
+ bool m_clk;
+ bool m_data;
+ bool m_read;
+ bool m_start;
+ u8 m_count;
+ u8 m_shiftreg;
+ u8 m_command;
+ u8 m_crc;
+ u8 m_selbits;
+ u32 m_addr;
+ u16 m_select;
+ u16 m_selectval;
+};
+
+DECLARE_DEVICE_TYPE(DS6417, ds6417_device)
+
+#endif // MAME_MACHINE_DS6417_H
diff --git a/src/devices/machine/ds75160a.cpp b/src/devices/machine/ds75160a.cpp
index d5ad8007a61..d4e7f0a4582 100644
--- a/src/devices/machine/ds75160a.cpp
+++ b/src/devices/machine/ds75160a.cpp
@@ -27,13 +27,13 @@ DEFINE_DEVICE_TYPE(DS75160A, ds75160a_device, "ds75160a", "DS75160A GPIB Transce
// ds75160a_device - constructor
//-------------------------------------------------
-ds75160a_device::ds75160a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DS75160A, tag, owner, clock),
- m_read(*this),
- m_write(*this),
- m_data(0xff),
- m_te(0),
- m_pe(0)
+ds75160a_device::ds75160a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, DS75160A, tag, owner, clock),
+ m_read(*this, 0),
+ m_write(*this),
+ m_data(0xff),
+ m_te(0),
+ m_pe(0)
{
}
@@ -44,10 +44,6 @@ ds75160a_device::ds75160a_device(const machine_config &mconfig, const char *tag,
void ds75160a_device::device_start()
{
- // resolve callbacks
- m_read.resolve_safe(0);
- m_write.resolve_safe();
-
// register for state saving
save_item(NAME(m_data));
save_item(NAME(m_te));
@@ -91,7 +87,7 @@ void ds75160a_device::write(uint8_t data)
// te_w - transmit enable
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75160a_device::te_w )
+void ds75160a_device::te_w(int state)
{
if (m_te != state)
{
@@ -106,7 +102,7 @@ WRITE_LINE_MEMBER( ds75160a_device::te_w )
// pe_w - parallel enable
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75160a_device::pe_w )
+void ds75160a_device::pe_w(int state)
{
m_pe = state;
}
diff --git a/src/devices/machine/ds75160a.h b/src/devices/machine/ds75160a.h
index 5e2498d28ad..d26f2cabd46 100644
--- a/src/devices/machine/ds75160a.h
+++ b/src/devices/machine/ds75160a.h
@@ -43,8 +43,8 @@ public:
uint8_t read();
void write(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( te_w );
- DECLARE_WRITE_LINE_MEMBER( pe_w );
+ void te_w(int state);
+ void pe_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/ds75161a.cpp b/src/devices/machine/ds75161a.cpp
index 9d75d6b65a0..e314b84b7ea 100644
--- a/src/devices/machine/ds75161a.cpp
+++ b/src/devices/machine/ds75161a.cpp
@@ -27,34 +27,34 @@ DEFINE_DEVICE_TYPE(DS75161A, ds75161a_device, "ds75161a", "DS75161A GPIB Transce
// ds75161a_device - constructor
//-------------------------------------------------
-ds75161a_device::ds75161a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, DS75161A, tag, owner, clock),
- m_in_ren_cb(*this),
- m_in_ifc_cb(*this),
- m_in_ndac_cb(*this),
- m_in_nrfd_cb(*this),
- m_in_dav_cb(*this),
- m_in_eoi_cb(*this),
- m_in_atn_cb(*this),
- m_in_srq_cb(*this),
- m_out_ren_cb(*this),
- m_out_ifc_cb(*this),
- m_out_ndac_cb(*this),
- m_out_nrfd_cb(*this),
- m_out_dav_cb(*this),
- m_out_eoi_cb(*this),
- m_out_atn_cb(*this),
- m_out_srq_cb(*this),
- m_ren(1),
- m_ifc(1),
- m_ndac(1),
- m_nrfd(1),
- m_dav(1),
- m_eoi(1),
- m_atn(1),
- m_srq(1),
- m_te(0),
- m_dc(0)
+ds75161a_device::ds75161a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, DS75161A, tag, owner, clock),
+ m_in_ren_cb(*this, 0),
+ m_in_ifc_cb(*this, 0),
+ m_in_ndac_cb(*this, 0),
+ m_in_nrfd_cb(*this, 0),
+ m_in_dav_cb(*this, 0),
+ m_in_eoi_cb(*this, 0),
+ m_in_atn_cb(*this, 0),
+ m_in_srq_cb(*this, 0),
+ m_out_ren_cb(*this),
+ m_out_ifc_cb(*this),
+ m_out_ndac_cb(*this),
+ m_out_nrfd_cb(*this),
+ m_out_dav_cb(*this),
+ m_out_eoi_cb(*this),
+ m_out_atn_cb(*this),
+ m_out_srq_cb(*this),
+ m_ren(1),
+ m_ifc(1),
+ m_ndac(1),
+ m_nrfd(1),
+ m_dav(1),
+ m_eoi(1),
+ m_atn(1),
+ m_srq(1),
+ m_te(0),
+ m_dc(0)
{
}
@@ -64,25 +64,6 @@ ds75161a_device::ds75161a_device(const machine_config &mconfig, const char *tag,
void ds75161a_device::device_start()
{
- // resolve callbacks
- m_in_ren_cb.resolve_safe(0);
- m_in_ifc_cb.resolve_safe(0);
- m_in_ndac_cb.resolve_safe(0);
- m_in_nrfd_cb.resolve_safe(0);
- m_in_dav_cb.resolve_safe(0);
- m_in_eoi_cb.resolve_safe(0);
- m_in_atn_cb.resolve_safe(0);
- m_in_srq_cb.resolve_safe(0);
-
- m_out_ren_cb.resolve_safe();
- m_out_ifc_cb.resolve_safe();
- m_out_ndac_cb.resolve_safe();
- m_out_nrfd_cb.resolve_safe();
- m_out_dav_cb.resolve_safe();
- m_out_eoi_cb.resolve_safe();
- m_out_atn_cb.resolve_safe();
- m_out_srq_cb.resolve_safe();
-
// register for state saving
save_item(NAME(m_ren));
save_item(NAME(m_ifc));
@@ -123,7 +104,7 @@ void ds75161a_device::update_signals()
// te_w - transmit enable
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::te_w )
+void ds75161a_device::te_w(int state)
{
if (m_te != state)
{
@@ -138,7 +119,7 @@ WRITE_LINE_MEMBER( ds75161a_device::te_w )
// dc_w - direction control
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::dc_w )
+void ds75161a_device::dc_w(int state)
{
if (m_dc != state)
{
@@ -153,7 +134,7 @@ WRITE_LINE_MEMBER( ds75161a_device::dc_w )
// ren_r - remote enable read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::ren_r )
+int ds75161a_device::ren_r()
{
return m_dc ? m_in_ren_cb() : 0;
}
@@ -163,7 +144,7 @@ READ_LINE_MEMBER( ds75161a_device::ren_r )
// ifc_r - interface clear read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::ifc_r )
+int ds75161a_device::ifc_r()
{
return m_dc ? m_in_ifc_cb() : 0;
}
@@ -173,7 +154,7 @@ READ_LINE_MEMBER( ds75161a_device::ifc_r )
// ndac_r - not data acknowledge read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::ndac_r )
+int ds75161a_device::ndac_r()
{
return m_te ? m_in_ndac_cb() : 0;
}
@@ -183,7 +164,7 @@ READ_LINE_MEMBER( ds75161a_device::ndac_r )
// nrfd_r - not ready for data read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::nrfd_r )
+int ds75161a_device::nrfd_r()
{
return m_te ? m_in_nrfd_cb() : 0;
}
@@ -193,7 +174,7 @@ READ_LINE_MEMBER( ds75161a_device::nrfd_r )
// dav_r - data valid read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::dav_r )
+int ds75161a_device::dav_r()
{
return m_te ? 0 : m_in_dav_cb();
}
@@ -203,7 +184,7 @@ READ_LINE_MEMBER( ds75161a_device::dav_r )
// eoi_r - end or identify read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::eoi_r )
+int ds75161a_device::eoi_r()
{
int atn = m_in_atn_cb();
int eoi = m_in_eoi_cb();
@@ -218,7 +199,7 @@ READ_LINE_MEMBER( ds75161a_device::eoi_r )
// atn_r - attention read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::atn_r )
+int ds75161a_device::atn_r()
{
return m_dc ? m_in_atn_cb() : 0;
}
@@ -228,7 +209,7 @@ READ_LINE_MEMBER( ds75161a_device::atn_r )
// srq_r - service request read
//-------------------------------------------------
-READ_LINE_MEMBER( ds75161a_device::srq_r )
+int ds75161a_device::srq_r()
{
return m_dc ? 0 : m_in_srq_cb();
}
@@ -238,7 +219,7 @@ READ_LINE_MEMBER( ds75161a_device::srq_r )
// ren_w - remote enable write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::ren_w )
+void ds75161a_device::ren_w(int state)
{
if (m_ren != state)
{
@@ -253,7 +234,7 @@ WRITE_LINE_MEMBER( ds75161a_device::ren_w )
// ifc_w - interface clear write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::ifc_w )
+void ds75161a_device::ifc_w(int state)
{
if (m_ifc != state)
{
@@ -268,7 +249,7 @@ WRITE_LINE_MEMBER( ds75161a_device::ifc_w )
// ndac_w - not data acknowledge write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::ndac_w )
+void ds75161a_device::ndac_w(int state)
{
if (m_ndac != state)
{
@@ -283,7 +264,7 @@ WRITE_LINE_MEMBER( ds75161a_device::ndac_w )
// nrfd_w - not ready for data write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::nrfd_w )
+void ds75161a_device::nrfd_w(int state)
{
if (m_nrfd != state)
{
@@ -298,7 +279,7 @@ WRITE_LINE_MEMBER( ds75161a_device::nrfd_w )
// dav_w - data valid write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::dav_w )
+void ds75161a_device::dav_w(int state)
{
if (m_dav != state)
{
@@ -313,7 +294,7 @@ WRITE_LINE_MEMBER( ds75161a_device::dav_w )
// eoi_w - end or identify write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::eoi_w )
+void ds75161a_device::eoi_w(int state)
{
if (m_eoi != state)
{
@@ -328,7 +309,7 @@ WRITE_LINE_MEMBER( ds75161a_device::eoi_w )
// atn_w - attention write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::atn_w )
+void ds75161a_device::atn_w(int state)
{
if (m_atn != state)
{
@@ -343,7 +324,7 @@ WRITE_LINE_MEMBER( ds75161a_device::atn_w )
// srq_w - service request write
//-------------------------------------------------
-WRITE_LINE_MEMBER( ds75161a_device::srq_w )
+void ds75161a_device::srq_w(int state)
{
if (m_srq != state)
{
diff --git a/src/devices/machine/ds75161a.h b/src/devices/machine/ds75161a.h
index 8ea0a0b9632..a304b2893b3 100644
--- a/src/devices/machine/ds75161a.h
+++ b/src/devices/machine/ds75161a.h
@@ -47,26 +47,26 @@ public:
auto out_atn() { return m_out_atn_cb.bind(); }
auto out_srq() { return m_out_srq_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER( te_w );
- DECLARE_WRITE_LINE_MEMBER( dc_w );
-
- DECLARE_READ_LINE_MEMBER( ren_r );
- DECLARE_READ_LINE_MEMBER( ifc_r );
- DECLARE_READ_LINE_MEMBER( ndac_r );
- DECLARE_READ_LINE_MEMBER( nrfd_r );
- DECLARE_READ_LINE_MEMBER( dav_r );
- DECLARE_READ_LINE_MEMBER( eoi_r );
- DECLARE_READ_LINE_MEMBER( atn_r );
- DECLARE_READ_LINE_MEMBER( srq_r );
-
- DECLARE_WRITE_LINE_MEMBER( ren_w );
- DECLARE_WRITE_LINE_MEMBER( ifc_w );
- DECLARE_WRITE_LINE_MEMBER( ndac_w );
- DECLARE_WRITE_LINE_MEMBER( nrfd_w );
- DECLARE_WRITE_LINE_MEMBER( dav_w );
- DECLARE_WRITE_LINE_MEMBER( eoi_w );
- DECLARE_WRITE_LINE_MEMBER( atn_w );
- DECLARE_WRITE_LINE_MEMBER( srq_w );
+ void te_w(int state);
+ void dc_w(int state);
+
+ int ren_r();
+ int ifc_r();
+ int ndac_r();
+ int nrfd_r();
+ int dav_r();
+ int eoi_r();
+ int atn_r();
+ int srq_r();
+
+ void ren_w(int state);
+ void ifc_w(int state);
+ void ndac_w(int state);
+ void nrfd_w(int state);
+ void dav_w(int state);
+ void eoi_w(int state);
+ void atn_w(int state);
+ void srq_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/e0516.cpp b/src/devices/machine/e0516.cpp
index a5d029afe27..abf3d181048 100644
--- a/src/devices/machine/e0516.cpp
+++ b/src/devices/machine/e0516.cpp
@@ -15,14 +15,17 @@
// MACROS / CONSTANTS
//**************************************************************************
-#define LOG 0
+//#define VERBOSE 1
+#include "logmacro.h"
// states
enum
{
STATE_ADDRESS = 0,
- STATE_DATA
+ STATE_HI_Z,
+ STATE_DATA_READ,
+ STATE_DATA_WRITE
};
@@ -38,11 +41,24 @@ DEFINE_DEVICE_TYPE(E0516, e0516_device, "e0516", "E05-16 RTC")
// e0516_device - constructor
//-------------------------------------------------
-e0516_device::e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, E0516, tag, owner, clock)
- , device_rtc_interface(mconfig, *this)
- , m_cs(0), m_clk(0), m_data_latch(0), m_reg_latch(0), m_read_write(0), m_state(0), m_bits(0), m_dio(0)
- , m_timer(nullptr)
+e0516_device::e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, E0516, tag, owner, clock),
+ device_rtc_interface(mconfig, *this),
+ m_read_outsel(*this, 1),
+ m_write_sec(*this),
+ m_write_min(*this),
+ m_write_hrs(*this),
+ m_write_day(*this),
+ m_cs(1),
+ m_clk(0),
+ m_cycle(0),
+ m_data_latch(0),
+ m_reg_latch(0),
+ m_state(STATE_ADDRESS),
+ m_bits_left(4),
+ m_dio(0),
+ m_reset(1),
+ m_timer(nullptr)
{
}
@@ -54,28 +70,33 @@ e0516_device::e0516_device(const machine_config &mconfig, const char *tag, devic
void e0516_device::device_start()
{
// allocate timers
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(e0516_device::timer_tick), this);
m_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
// state saving
save_item(NAME(m_cs));
save_item(NAME(m_clk));
+ save_item(NAME(m_cycle));
save_item(NAME(m_data_latch));
save_item(NAME(m_reg_latch));
- save_item(NAME(m_read_write));
save_item(NAME(m_state));
- save_item(NAME(m_bits));
+ save_item(NAME(m_bits_left));
save_item(NAME(m_dio));
+ save_item(NAME(m_reset));
}
//-------------------------------------------------
-// device_timer - handler timer events
+// timer_tick - call into dirtc at 1Hz to
+// increment the seconds counter
//-------------------------------------------------
-void e0516_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(e0516_device::timer_tick)
{
- advance_seconds();
+ if (m_reset)
+ {
+ advance_seconds();
+ }
}
@@ -83,19 +104,31 @@ void e0516_device::device_timer(emu_timer &timer, device_timer_id id, int param,
// cs_w - chip select input
//-------------------------------------------------
-WRITE_LINE_MEMBER( e0516_device::cs_w )
+void e0516_device::cs_w(int state)
{
- if (LOG) logerror("E05-16 '%s' CS %u\n", tag(), state);
-
- m_cs = state;
+ if (m_cs != state)
+ {
+ LOG("E05-16 '%s' CS %u\n", tag(), state);
+ }
- if (m_cs)
+ if (!m_cs && state)
{
+ if ((m_state == STATE_DATA_WRITE) && (m_bits_left == 0) && (get_address() != 7))
+ {
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), get_address(), m_data_latch);
+
+ // write latched data to register
+ set_clock_register(get_address(), bcd_to_integer(m_data_latch));
+ }
+
+ m_cycle = 0;
m_data_latch = 0;
m_reg_latch = 0;
- m_bits = 0;
+ m_bits_left = 4;
m_state = STATE_ADDRESS;
}
+
+ m_cs = state;
}
@@ -103,65 +136,155 @@ WRITE_LINE_MEMBER( e0516_device::cs_w )
// clk_w - serial clock input
//-------------------------------------------------
-WRITE_LINE_MEMBER( e0516_device::clk_w )
+void e0516_device::clk_w(int state)
{
- if (LOG) logerror("E05-16 '%s' CLK %u\n", tag(), state);
-
+ if (m_cs) return;
+ if (m_clk == state) return;
m_clk = state;
- if (m_cs || m_clk) return;
+ if (m_clk) {
+ m_cycle++;
+ LOG("E05-16 '%s' CLK %u\n", tag(), m_cycle);
+ }
+
+ if (!m_bits_left) return;
+
+ if (!m_clk && (m_state == STATE_HI_Z))
+ {
+ m_state = STATE_DATA_READ;
+ return;
+ }
+
+ if (!m_clk && (m_state != STATE_DATA_READ)) return;
+ if (m_clk && (m_state == STATE_DATA_READ)) return;
- m_bits++;
+ m_bits_left--;
+ if ((m_state == STATE_DATA_READ) && (m_bits_left == 56) && !m_read_outsel()) return;
if (m_state == STATE_ADDRESS)
{
- if (LOG) logerror("E05-16 '%s' Command Bit %u\n", tag(), m_dio);
+ LOG("E05-16 '%s' Command Bit %u\n", tag(), m_dio);
// command
- m_reg_latch |= m_dio << 3;
- m_reg_latch >>= 1;
+ m_reg_latch <<= 1;
+ m_reg_latch |= m_dio;
+ m_reg_latch &= 0x0f;
- if (m_bits == 4)
+ if (m_bits_left == 0)
{
- m_state = STATE_DATA;
- m_bits = 0;
-
if (BIT(m_reg_latch, 0))
{
- // load register value to data latch
- m_data_latch = convert_to_bcd(get_clock_register(m_reg_latch >> 1));
+ m_state = STATE_DATA_READ;
+
+ if (get_address() == 7)
+ {
+ LOG("E05-16 '%s' Continuous Read-Out Mode\n", tag());
+
+ // continuous read-out mode
+ m_bits_left = 56;
+
+ // load all register values to data latch
+ m_data_latch = convert_to_bcd(get_clock_register(RTC_SECOND));
+ m_data_latch <<= 8;
+ m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_DAY_OF_WEEK));
+ m_data_latch <<= 8;
+ m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_YEAR));
+ m_data_latch <<= 8;
+ m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_MONTH));
+ m_data_latch <<= 8;
+ m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_DAY));
+ m_data_latch <<= 8;
+ m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_MINUTE));
+ m_data_latch <<= 8;
+ m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_HOUR));
+ }
+ else
+ {
+ LOG("E05-16 '%s' Read Register %u\n", tag(), get_address());
+
+ m_bits_left = 8;
+
+ // load register value to data latch
+ m_data_latch = convert_to_bcd(get_clock_register(get_address()));
+ }
+
+ if (!m_read_outsel())
+ {
+ m_state = STATE_HI_Z;
+ }
+ }
+ else
+ {
+ m_state = STATE_DATA_WRITE;
+
+ if (get_address() == 7)
+ {
+ LOG("E05-16 '%s' Continuous Write-In Mode\n", tag());
+
+ // continuous write-in mode
+ m_bits_left = 56;
+ }
+ else
+ {
+ LOG("E05-16 '%s' Write Register %u\n", tag(), get_address());
+
+ m_bits_left = 8;
+ }
}
}
}
else
{
// data
- if (BIT(m_reg_latch, 0))
+ if (m_state == STATE_DATA_READ)
{
// read
- if (LOG) logerror("E05-16 '%s' Data Bit OUT %u\n", tag(), m_dio);
-
m_dio = BIT(m_data_latch, 0);
m_data_latch >>= 1;
+
+ LOG("E05-16 '%s' Data Bit OUT %u\n", tag(), m_dio);
}
else
{
// write
- if (LOG) logerror("E05-16 '%s' Data Bit IN %u\n", tag(), m_dio);
-
- m_data_latch |= m_dio << 7;
- m_data_latch >>= 1;
- }
+ LOG("E05-16 '%s' Data Bit IN %u\n", tag(), m_dio);
- if (m_bits == 8)
- {
- m_state = STATE_ADDRESS;
- m_bits = 0;
+ m_data_latch <<= 1;
+ m_data_latch |= m_dio;
- if (!BIT(m_reg_latch, 0))
+ if (get_address() == 7)
{
- // write latched data to register
- set_clock_register(m_reg_latch >> 1, bcd_to_integer(m_data_latch));
+ switch (m_bits_left)
+ {
+ case 48:
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_HOUR, m_data_latch & 0xff);
+ set_clock_register(RTC_HOUR, bcd_to_integer(m_data_latch & 0xff));
+ break;
+ case 40:
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_MINUTE, m_data_latch & 0xff);
+ set_clock_register(RTC_MINUTE, bcd_to_integer(m_data_latch & 0xff));
+ break;
+ case 32:
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_DAY, m_data_latch & 0xff);
+ set_clock_register(RTC_DAY, bcd_to_integer(m_data_latch & 0xff));
+ break;
+ case 24:
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_MONTH, m_data_latch & 0xff);
+ set_clock_register(RTC_MONTH, bcd_to_integer(m_data_latch & 0xff));
+ break;
+ case 16:
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_YEAR, m_data_latch & 0xff);
+ set_clock_register(RTC_YEAR, bcd_to_integer(m_data_latch & 0xff));
+ break;
+ case 8:
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_DAY_OF_WEEK, m_data_latch & 0xff);
+ set_clock_register(RTC_DAY_OF_WEEK, bcd_to_integer(m_data_latch & 0xff));
+ break;
+ case 0:
+ LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_SECOND, m_data_latch & 0xff);
+ set_clock_register(RTC_SECOND, bcd_to_integer(m_data_latch & 0xff));
+ break;
+ }
}
}
}
@@ -172,11 +295,14 @@ WRITE_LINE_MEMBER( e0516_device::clk_w )
// dio_w - serial data input
//-------------------------------------------------
-WRITE_LINE_MEMBER( e0516_device::dio_w )
+void e0516_device::dio_w(int state)
{
- if (LOG) logerror("E05-16 '%s' DIO %u\n", tag(), state);
+ LOG("E05-16 '%s' DIO %u\n", tag(), state);
- m_dio = state;
+ if ((m_state != STATE_DATA_READ) && (m_state != STATE_HI_Z))
+ {
+ m_dio = state;
+ }
}
@@ -184,13 +310,42 @@ WRITE_LINE_MEMBER( e0516_device::dio_w )
// do_r - serial data output
//-------------------------------------------------
-READ_LINE_MEMBER( e0516_device::dio_r )
+int e0516_device::dio_r()
{
+ if (m_cs || (m_state == STATE_HI_Z))
+ {
+ // high impedance
+ return 0;
+ }
+
return m_dio;
}
//-------------------------------------------------
+// reset_w - reset input
+//-------------------------------------------------
+
+void e0516_device::reset_w(int state)
+{
+ LOG("E05-16 '%s' RESET %u\n", tag(), state);
+
+ if (m_reset && !state)
+ {
+ set_clock_register(RTC_SECOND, 0);
+ set_clock_register(RTC_MINUTE, 0);
+ set_clock_register(RTC_HOUR, 0);
+ set_clock_register(RTC_DAY, 1);
+ set_clock_register(RTC_MONTH, 1);
+ set_clock_register(RTC_DAY_OF_WEEK, 1);
+ set_clock_register(RTC_YEAR, 0);
+ }
+
+ m_reset = state;
+}
+
+
+//-------------------------------------------------
// rtc_clock_updated -
//-------------------------------------------------
diff --git a/src/devices/machine/e0516.h b/src/devices/machine/e0516.h
index 6e5d1b55779..0e1bff9759d 100644
--- a/src/devices/machine/e0516.h
+++ b/src/devices/machine/e0516.h
@@ -30,28 +30,45 @@ public:
// construction/destruction
e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER( cs_w );
- DECLARE_WRITE_LINE_MEMBER( clk_w );
- DECLARE_WRITE_LINE_MEMBER( dio_w );
- DECLARE_READ_LINE_MEMBER( dio_r );
+ auto outsel_rd_cb() { return m_read_outsel.bind(); }
+ auto sec_wr_cb() { return m_write_sec.bind(); }
+ auto min_wr_cb() { return m_write_min.bind(); }
+ auto hrs_wr_cb() { return m_write_hrs.bind(); }
+ auto day_wr_cb() { return m_write_day.bind(); }
+
+ void cs_w(int state);
+ void clk_w(int state);
+ void dio_w(int state);
+ int dio_r();
+ void reset_w(int state);
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
+ TIMER_CALLBACK_MEMBER(timer_tick);
+
+ devcb_read_line m_read_outsel;
+ devcb_write_line m_write_sec;
+ devcb_write_line m_write_min;
+ devcb_write_line m_write_hrs;
+ devcb_write_line m_write_day;
+
private:
- int m_cs; // chip select
- int m_clk; // clock
- int m_data_latch; // data latch
- int m_reg_latch; // register latch
- int m_read_write; // read/write data
- int m_state; // state
- int m_bits; // number of bits transferred
- int m_dio; // data pin
+ bool m_cs;
+ bool m_clk;
+ int m_cycle;
+ u64 m_data_latch;
+ int m_reg_latch;
+ int m_state;
+ int m_bits_left;
+ bool m_dio;
+ bool m_reset;
+
+ offs_t get_address() { return (m_reg_latch >> 1) & 0x07; }
// timers
emu_timer *m_timer;
diff --git a/src/devices/machine/e05a03.cpp b/src/devices/machine/e05a03.cpp
index 66a2a6785cc..a3c70907549 100644
--- a/src/devices/machine/e05a03.cpp
+++ b/src/devices/machine/e05a03.cpp
@@ -16,22 +16,22 @@
DEFINE_DEVICE_TYPE(E05A03, e05a03_device, "e05a03", "Epson E05A03 Gate Array")
-e05a03_device::e05a03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, E05A03, tag, owner, clock),
+e05a03_device::e05a03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, E05A03, tag, owner, clock),
m_write_nlq_lp(*this),
m_write_pe_lp(*this),
m_write_reso(*this),
m_write_pe(*this),
- m_read_data(*this),
+ m_read_data(*this, 0),
m_shift(0),
m_busy_leading(0),
m_busy_software(0),
m_nlqlp(0),
m_cndlp(0),
- #if 0
+#if 0
m_pe(0),
m_pelp(0),
- #endif
+#endif
m_printhead(0),
m_pf_motor(0),
m_cr_motor(0)
@@ -44,23 +44,16 @@ e05a03_device::e05a03_device(const machine_config &mconfig, const char *tag, dev
void e05a03_device::device_start()
{
- /* resolve callbacks */
- m_write_nlq_lp.resolve_safe();
- m_write_pe_lp.resolve_safe();
- m_write_reso.resolve_safe();
- m_write_pe.resolve_safe();
- m_read_data.resolve_safe(0);
-
/* register for state saving */
save_item(NAME(m_shift));
save_item(NAME(m_busy_leading));
save_item(NAME(m_busy_software));
save_item(NAME(m_nlqlp));
save_item(NAME(m_cndlp));
- #if 0
+#if 0
save_item(NAME(m_pe));
save_item(NAME(m_pelp));
- #endif
+#endif
save_item(NAME(m_printhead));
save_item(NAME(m_pf_motor));
save_item(NAME(m_cr_motor));
@@ -155,25 +148,25 @@ uint8_t e05a03_device::read(offs_t offset)
}
/* home position signal */
-WRITE_LINE_MEMBER( e05a03_device::home_w )
+void e05a03_device::home_w(int state)
{
}
/* printhead solenoids trigger */
-WRITE_LINE_MEMBER( e05a03_device::fire_w )
+void e05a03_device::fire_w(int state)
{
}
-WRITE_LINE_MEMBER( e05a03_device::strobe_w )
+void e05a03_device::strobe_w(int state)
{
}
-READ_LINE_MEMBER( e05a03_device::busy_r )
+int e05a03_device::busy_r()
{
return 1;
}
-WRITE_LINE_MEMBER( e05a03_device::resi_w )
+void e05a03_device::resi_w(int state)
{
if (!state)
{
@@ -182,7 +175,7 @@ WRITE_LINE_MEMBER( e05a03_device::resi_w )
}
}
-WRITE_LINE_MEMBER( e05a03_device::init_w )
+void e05a03_device::init_w(int state)
{
resi_w(state);
}
diff --git a/src/devices/machine/e05a03.h b/src/devices/machine/e05a03.h
index 4748bb3a84b..4193e218a38 100644
--- a/src/devices/machine/e05a03.h
+++ b/src/devices/machine/e05a03.h
@@ -29,12 +29,12 @@ public:
void write(offs_t offset, uint8_t data);
uint8_t read(offs_t offset);
- WRITE_LINE_MEMBER( home_w ); /* home position signal */
- WRITE_LINE_MEMBER( fire_w ); /* printhead solenoids trigger */
- WRITE_LINE_MEMBER( strobe_w );
- READ_LINE_MEMBER( busy_r );
- WRITE_LINE_MEMBER( resi_w ); /* reset input */
- WRITE_LINE_MEMBER( init_w ); /* centronics init */
+ void home_w(int state); /* home position signal */
+ void fire_w(int state); /* printhead solenoids trigger */
+ void strobe_w(int state);
+ int busy_r();
+ void resi_w(int state); /* reset input */
+ void init_w(int state); /* centronics init */
protected:
// device-level overrides
diff --git a/src/devices/machine/e05a30.cpp b/src/devices/machine/e05a30.cpp
index 378fedc0539..272fd3d2716 100644
--- a/src/devices/machine/e05a30.cpp
+++ b/src/devices/machine/e05a30.cpp
@@ -18,8 +18,8 @@
DEFINE_DEVICE_TYPE(E05A30, e05a30_device, "e05a30", "Epson E05A30 Gate Array")
-e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, E05A30, tag, owner, clock),
+e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, E05A30, tag, owner, clock),
m_write_printhead(*this),
m_write_pf_stepper(*this),
m_write_cr_stepper(*this),
@@ -29,9 +29,11 @@ e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, dev
m_write_centronics_perror(*this),
m_write_centronics_fault(*this),
m_write_centronics_select(*this),
+ m_write_cpu_reset(*this),
+ m_write_ready_led(*this),
m_printhead(0),
m_pf_stepper(0),
- m_cr_stepper(0), m_centronics_data(0), m_centronics_busy(0), m_centronics_nack(0), m_centronics_strobe(0), m_centronics_data_latch(0), m_centronics_data_latched(0)
+ m_cr_stepper(0), m_centronics_data(0), m_centronics_busy(0), m_centronics_nack(0), m_centronics_init(1), m_centronics_strobe(0), m_centronics_data_latch(0), m_centronics_data_latched(0)
{
}
@@ -41,17 +43,6 @@ e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, dev
void e05a30_device::device_start()
{
- /* resolve callbacks */
- m_write_printhead.resolve_safe();
- m_write_pf_stepper.resolve_safe();
- m_write_cr_stepper.resolve_safe();
- m_write_ready.resolve_safe();
- m_write_centronics_ack.resolve_safe();
- m_write_centronics_busy.resolve_safe();
- m_write_centronics_perror.resolve_safe();
- m_write_centronics_fault.resolve_safe();
- m_write_centronics_select.resolve_safe();
-
/* register for state saving */
save_item(NAME(m_printhead));
save_item(NAME(m_pf_stepper));
@@ -72,6 +63,7 @@ void e05a30_device::device_reset()
/* centronics init */
m_centronics_nack = false;
m_centronics_busy = false;
+ m_write_ready_led(get_ready_led());
m_write_centronics_ack (!m_centronics_nack);
m_write_centronics_busy ( m_centronics_busy);
m_write_centronics_perror(false);
@@ -145,13 +137,14 @@ void e05a30_device::update_cr_stepper(uint8_t data)
Centronics
***************************************************************************/
-WRITE_LINE_MEMBER( e05a30_device::centronics_input_strobe )
+void e05a30_device::centronics_input_strobe(int state)
{
if (m_centronics_strobe == true && state == false && !m_centronics_busy) {
m_centronics_data_latch = m_centronics_data;
m_centronics_data_latched = true;
m_centronics_busy = true;
+ m_write_ready_led(get_ready_led());
m_write_centronics_busy(m_centronics_busy);
}
@@ -159,6 +152,18 @@ WRITE_LINE_MEMBER( e05a30_device::centronics_input_strobe )
}
+void e05a30_device::centronics_input_init(int state)
+{
+ if (m_centronics_init == 1 && state == 0) // when init goes low, do a reset cycle
+ {
+ m_write_cpu_reset(0);
+ m_write_cpu_reset(1);
+ device_reset(); // this will trigger an NMI after 0.9 seconds
+ }
+ m_centronics_init = state;
+}
+
+
/***************************************************************************
IMPLEMENTATION
***************************************************************************/
@@ -187,13 +192,17 @@ void e05a30_device::write(offs_t offset, uint8_t data)
case 0x04:
m_centronics_nack = BIT(data,5);
m_centronics_busy = BIT(data,0);
+ m_write_ready_led(get_ready_led());
/* The ActionPrinter 2000 firmware might overwrite the busy signal at
* address 20AB if the host depends only on the busy signal and
* doesn't wait for the ack pulse. To avoid skipping input data, we
* assume the busy signal cannot be reset while the data hasn't been
* read. */
if (m_centronics_data_latched)
+ {
m_centronics_busy = true;
+ m_write_ready_led(get_ready_led());
+ }
m_write_centronics_ack (!m_centronics_nack);
m_write_centronics_busy( m_centronics_busy);
break;
diff --git a/src/devices/machine/e05a30.h b/src/devices/machine/e05a30.h
index b6fd7af343b..943502a808f 100644
--- a/src/devices/machine/e05a30.h
+++ b/src/devices/machine/e05a30.h
@@ -24,22 +24,25 @@ public:
auto centronics_perror() { return m_write_centronics_perror.bind(); }
auto centronics_fault() { return m_write_centronics_fault.bind(); }
auto centronics_select() { return m_write_centronics_select.bind(); }
+ auto cpu_reset() { return m_write_cpu_reset.bind(); }
+ auto ready_led() { return m_write_ready_led.bind(); }
void write(offs_t offset, uint8_t data);
uint8_t read(offs_t offset);
/* Centronics stuff */
- DECLARE_WRITE_LINE_MEMBER( centronics_input_strobe );
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data0 ) { if (state) m_centronics_data |= 0x01; else m_centronics_data &= ~0x01; }
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data1 ) { if (state) m_centronics_data |= 0x02; else m_centronics_data &= ~0x02; }
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data2 ) { if (state) m_centronics_data |= 0x04; else m_centronics_data &= ~0x04; }
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data3 ) { if (state) m_centronics_data |= 0x08; else m_centronics_data &= ~0x08; }
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data4 ) { if (state) m_centronics_data |= 0x10; else m_centronics_data &= ~0x10; }
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data5 ) { if (state) m_centronics_data |= 0x20; else m_centronics_data &= ~0x20; }
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data6 ) { if (state) m_centronics_data |= 0x40; else m_centronics_data &= ~0x40; }
- DECLARE_WRITE_LINE_MEMBER( centronics_input_data7 ) { if (state) m_centronics_data |= 0x80; else m_centronics_data &= ~0x80; }
+ void centronics_input_init(int state);
+ void centronics_input_strobe(int state);
+ void centronics_input_data0(int state) { if (state) m_centronics_data |= 0x01; else m_centronics_data &= ~0x01; }
+ void centronics_input_data1(int state) { if (state) m_centronics_data |= 0x02; else m_centronics_data &= ~0x02; }
+ void centronics_input_data2(int state) { if (state) m_centronics_data |= 0x04; else m_centronics_data &= ~0x04; }
+ void centronics_input_data3(int state) { if (state) m_centronics_data |= 0x08; else m_centronics_data &= ~0x08; }
+ void centronics_input_data4(int state) { if (state) m_centronics_data |= 0x10; else m_centronics_data &= ~0x10; }
+ void centronics_input_data5(int state) { if (state) m_centronics_data |= 0x20; else m_centronics_data &= ~0x20; }
+ void centronics_input_data6(int state) { if (state) m_centronics_data |= 0x40; else m_centronics_data &= ~0x40; }
+ void centronics_input_data7(int state) { if (state) m_centronics_data |= 0x80; else m_centronics_data &= ~0x80; }
- int ready_led() { return !m_centronics_busy; }
+ int get_ready_led() { return !m_centronics_busy; }
protected:
// device-level overrides
@@ -57,6 +60,8 @@ private:
devcb_write_line m_write_centronics_perror;
devcb_write_line m_write_centronics_fault;
devcb_write_line m_write_centronics_select;
+ devcb_write_line m_write_cpu_reset;
+ devcb_write_line m_write_ready_led;
void update_printhead(int pos, uint8_t data);
void update_pf_stepper(uint8_t data);
@@ -73,10 +78,12 @@ private:
uint8_t m_centronics_data;
int m_centronics_busy;
int m_centronics_nack;
+ uint8_t m_centronics_init;
uint8_t m_centronics_strobe;
uint8_t m_centronics_data_latch;
uint8_t m_centronics_data_latched;
uint32_t m_c000_shift_register;
+
};
DECLARE_DEVICE_TYPE(E05A30, e05a30_device)
diff --git a/src/devices/machine/edlc.cpp b/src/devices/machine/edlc.cpp
index 9749191afe2..26bcad50e21 100644
--- a/src/devices/machine/edlc.cpp
+++ b/src/devices/machine/edlc.cpp
@@ -25,7 +25,6 @@
#include "edlc.h"
#include "hashing.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_FRAMES (1U << 1)
#define LOG_FILTER (1U << 2)
@@ -39,7 +38,7 @@ static const u8 ETH_BROADCAST[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
seeq8003_device::seeq8003_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
- , device_network_interface(mconfig, *this, 10.0f)
+ , device_network_interface(mconfig, *this, 10)
, m_out_int(*this)
, m_out_rxrdy(*this)
, m_out_txrdy(*this)
@@ -53,10 +52,6 @@ seeq8003_device::seeq8003_device(machine_config const &mconfig, char const *tag,
void seeq8003_device::device_start()
{
- m_out_int.resolve_safe();
- m_out_rxrdy.resolve_safe();
- m_out_txrdy.resolve_safe();
-
save_item(NAME(m_int_state));
save_item(NAME(m_reset_state));
save_item(NAME(m_station_address));
@@ -67,8 +62,8 @@ void seeq8003_device::device_start()
//save_item(NAME(m_rx_fifo));
//save_item(NAME(m_tx_fifo));
- m_tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(seeq8003_device::transmit), this));
- m_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(seeq8003_device::interrupt), this));
+ m_tx_timer = timer_alloc(FUNC(seeq8003_device::transmit), this);
+ m_int_timer = timer_alloc(FUNC(seeq8003_device::interrupt), this);
m_int_state = 0;
m_reset_state = 1;
@@ -87,7 +82,7 @@ void seeq8003_device::device_reset()
// TODO: deassert RxDC and TxRET
- if (m_dev)
+ if (has_net_device())
m_out_txrdy(1);
interrupt();
@@ -258,7 +253,7 @@ void seeq8003_device::tx_command_w(u8 data)
m_tx_command = data;
}
-void seeq8003_device::transmit(void *ptr, int param)
+void seeq8003_device::transmit(s32 param)
{
if (m_tx_fifo.queue_length())
{
@@ -288,7 +283,7 @@ void seeq8003_device::transmit(void *ptr, int param)
dump_bytes(buf, length);
// transmit the frame
- send(buf, length);
+ send(buf, length, 4);
// TODO: transmit errors/TxRET
@@ -333,7 +328,7 @@ int seeq8003_device::receive(u8 *buf, int length)
return length;
}
-void seeq8003_device::interrupt(void *ptr, int param)
+void seeq8003_device::interrupt(s32 param)
{
int const state =
(!(m_tx_status & TXS_O) && (m_tx_status & m_tx_command & TXS_M)) ||
@@ -432,7 +427,7 @@ void seeq80c03_device::send_complete_cb(int result)
else
{
// assume transmit failure and no device means loss of carrier
- if ((m_control & CTL_TNC) && !m_dev)
+ if ((m_control & CTL_TNC) && !has_net_device())
m_flags |= FLAGS_TNC;
}
}
diff --git a/src/devices/machine/edlc.h b/src/devices/machine/edlc.h
index 6b7d468f475..a450bcba9cd 100644
--- a/src/devices/machine/edlc.h
+++ b/src/devices/machine/edlc.h
@@ -7,6 +7,7 @@
#pragma once
#include "machine/bankdev.h"
+#include "dinetwork.h"
class seeq8003_device :
public device_t,
@@ -37,11 +38,11 @@ public:
protected:
seeq8003_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock = 0);
- // device_t overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- // device_network_interface overrides
+ // device_network_interface implementation
virtual int recv_start_cb(u8 *buf, int length) override;
// register read handlers
@@ -55,9 +56,9 @@ protected:
virtual void tx_command_w(u8 data);
// helpers
- void transmit(void *ptr, int param);
+ void transmit(s32 param);
int receive(u8 *buf, int length);
- void interrupt(void *ptr = nullptr, int param = 0);
+ void interrupt(s32 param = 0);
virtual bool address_filter(u8 *address);
void dump_bytes(u8 *buf, int length);
diff --git a/src/devices/machine/eeprom.cpp b/src/devices/machine/eeprom.cpp
index 0c81a6701e0..50be30e9131 100644
--- a/src/devices/machine/eeprom.cpp
+++ b/src/devices/machine/eeprom.cpp
@@ -2,14 +2,16 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- eeprom.c
+ eeprom.cpp
Base class for EEPROM devices.
***************************************************************************/
#include "emu.h"
-#include "machine/eeprom.h"
+#include "eeprom.h"
+
+#include "multibyte.h"
//#define VERBOSE 1
#include "logmacro.h"
@@ -23,18 +25,18 @@
// eeprom_base_device - constructor
//-------------------------------------------------
-eeprom_base_device::eeprom_base_device(const machine_config &mconfig, device_type devtype, const char *tag, device_t *owner)
- : device_t(mconfig, devtype, tag, owner, 0),
- device_nvram_interface(mconfig, *this),
- m_region(*this, DEVICE_SELF),
- m_cells(0),
- m_address_bits(0),
- m_data_bits(0),
- m_default_data(nullptr),
- m_default_data_size(0),
- m_default_value(0),
- m_default_value_set(false),
- m_completion_time(attotime::zero)
+eeprom_base_device::eeprom_base_device(const machine_config &mconfig, device_type devtype, const char *tag, device_t *owner) :
+ device_t(mconfig, devtype, tag, owner, 0),
+ device_nvram_interface(mconfig, *this),
+ m_region(*this, DEVICE_SELF),
+ m_cells(0),
+ m_address_bits(0),
+ m_data_bits(0),
+ m_default_data(nullptr),
+ m_default_data_size(0),
+ m_default_value(0),
+ m_default_value_set(false),
+ m_completion_time(attotime::zero)
{
// a 2ms write time is too long for rfjetsa
m_operation_time[WRITE_TIME] = attotime::from_usec(1750);
@@ -249,12 +251,13 @@ void eeprom_base_device::nvram_default()
// .nv file
//-------------------------------------------------
-void eeprom_base_device::nvram_read(emu_file &file)
+bool eeprom_base_device::nvram_read(util::read_stream &file)
{
- uint32_t eeprom_length = 1 << m_address_bits;
- uint32_t eeprom_bytes = eeprom_length * m_data_bits / 8;
+ uint32_t const eeprom_length = 1 << m_address_bits;
+ uint32_t const eeprom_bytes = eeprom_length * m_data_bits / 8;
- file.read(&m_data[0], eeprom_bytes);
+ auto const [err, actual_bytes] = util::read(file, &m_data[0], eeprom_bytes);
+ return !err && (actual_bytes == eeprom_bytes);
}
@@ -263,12 +266,13 @@ void eeprom_base_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void eeprom_base_device::nvram_write(emu_file &file)
+bool eeprom_base_device::nvram_write(util::write_stream &file)
{
- uint32_t eeprom_length = 1 << m_address_bits;
- uint32_t eeprom_bytes = eeprom_length * m_data_bits / 8;
+ uint32_t const eeprom_length = 1 << m_address_bits;
+ uint32_t const eeprom_bytes = eeprom_length * m_data_bits / 8;
- file.write(&m_data[0], eeprom_bytes);
+ auto const [err, actual_bytes] = util::write(file, &m_data[0], eeprom_bytes);
+ return !err;
}
@@ -279,7 +283,7 @@ void eeprom_base_device::nvram_write(emu_file &file)
uint32_t eeprom_base_device::internal_read(offs_t address)
{
if (m_data_bits == 16)
- return m_data[address * 2] | (m_data[address * 2 + 1] << 8);
+ return get_u16le(&m_data[address * 2]);
else
return m_data[address];
}
@@ -293,9 +297,7 @@ uint32_t eeprom_base_device::internal_read(offs_t address)
void eeprom_base_device::internal_write(offs_t address, uint32_t data)
{
if (m_data_bits == 16)
- {
- m_data[address * 2] = data;
- m_data[address * 2 + 1] = data >> 8;
- } else
+ put_u16le(&m_data[address * 2], data);
+ else
m_data[address] = data;
}
diff --git a/src/devices/machine/eeprom.h b/src/devices/machine/eeprom.h
index eb0a64b9234..e0693455e2f 100644
--- a/src/devices/machine/eeprom.h
+++ b/src/devices/machine/eeprom.h
@@ -63,20 +63,20 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
optional_memory_region m_region;
std::unique_ptr<uint8_t []> m_data;
// configuration state
- uint32_t m_cells;
- uint8_t m_address_bits;
- uint8_t m_data_bits;
+ uint32_t m_cells;
+ uint8_t m_address_bits;
+ uint8_t m_data_bits;
const void * m_default_data;
- uint32_t m_default_data_size;
- uint32_t m_default_value;
+ uint32_t m_default_data_size;
+ uint32_t m_default_value;
bool m_default_value_set;
attotime m_operation_time[TIMING_COUNT];
diff --git a/src/devices/machine/eeprompar.cpp b/src/devices/machine/eeprompar.cpp
index 3393ae91a2c..787093f9194 100644
--- a/src/devices/machine/eeprompar.cpp
+++ b/src/devices/machine/eeprompar.cpp
@@ -47,7 +47,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/eeprompar.h"
+#include "eeprompar.h"
//#define VERBOSE 1
#include "logmacro.h"
@@ -180,7 +180,7 @@ uint8_t eeprom_parallel_28xx_device::read(address_space &space, offs_t offset)
// oe_w - direct write to /OE (true line state)
//-------------------------------------------------
-WRITE_LINE_MEMBER(eeprom_parallel_28xx_device::oe_w)
+void eeprom_parallel_28xx_device::oe_w(int state)
{
LOG("%s: EEPROM %s for writing\n", machine().describe_context(), state ? "unlocked" : "locked");
m_oe = state ? 1 : 0;
diff --git a/src/devices/machine/eeprompar.h b/src/devices/machine/eeprompar.h
index 9399e32a349..07f3e37e059 100644
--- a/src/devices/machine/eeprompar.h
+++ b/src/devices/machine/eeprompar.h
@@ -37,7 +37,7 @@ public:
uint8_t read(address_space &space, offs_t offset);
// control lines
- DECLARE_WRITE_LINE_MEMBER(oe_w);
+ void oe_w(int state);
void unlock_write8(uint8_t data);
void unlock_write16(uint16_t data);
void unlock_write32(uint32_t data);
diff --git a/src/devices/machine/eepromser.cpp b/src/devices/machine/eepromser.cpp
index bd0447258f6..e060eaed79a 100644
--- a/src/devices/machine/eepromser.cpp
+++ b/src/devices/machine/eepromser.cpp
@@ -112,7 +112,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/eepromser.h"
+#include "eepromser.h"
@@ -190,9 +190,6 @@ void eeprom_serial_base_device::device_start()
// start the base class
eeprom_base_device::device_start();
- // resolve callback
- m_do_cb.resolve_safe();
-
// save the current state
save_item(NAME(m_state));
save_item(NAME(m_cs_state));
@@ -331,7 +328,7 @@ void eeprom_serial_base_device::set_state(eeprom_state newstate)
{ STATE_WAIT_FOR_COMPLETION, "WAIT_FOR_COMPLETION" },
};
const char *newstate_string = "UNKNOWN";
- for (int index = 0; index < ARRAY_LENGTH(s_state_names); index++)
+ for (int index = 0; index < std::size(s_state_names); index++)
if (s_state_names[index].state == newstate)
newstate_string = s_state_names[index].string;
LOG2("New state: %s\n", newstate_string);
@@ -340,8 +337,8 @@ void eeprom_serial_base_device::set_state(eeprom_state newstate)
// switch to the new state
m_state = newstate;
- // set DO high (actually high impedance; pullup assumed)
- m_do_cb(1);
+ // set DO high (actually high impedance; pullup assumed) except when entering STATE_READING_DATA
+ m_do_cb(m_state != STATE_READING_DATA);
}
@@ -484,7 +481,7 @@ void eeprom_serial_base_device::execute_command()
{ COMMAND_ERASEALL, "Execute command:ERASEALL\n" },
};
const char *command_string = s_command_names[0].string;
- for (int index = 0; index < ARRAY_LENGTH(s_command_names); index++)
+ for (int index = 0; index < std::size(s_command_names); index++)
if (s_command_names[index].command == m_command)
command_string = s_command_names[index].string;
LOG1(command_string, m_address);
@@ -565,7 +562,7 @@ void eeprom_serial_base_device::execute_write_command()
{ COMMAND_WRITEALL, "Execute write command: WRITEALL (%X) = 0x%X\n" },
};
const char *command_string = "UNKNOWN";
- for (int index = 0; index < ARRAY_LENGTH(s_command_names); index++)
+ for (int index = 0; index < std::size(s_command_names); index++)
if (s_command_names[index].command == m_command)
command_string = s_command_names[index].string;
LOG1(command_string, m_address, m_shift_register);
@@ -656,16 +653,16 @@ void eeprom_serial_93cxx_device::parse_command_and_address()
// do_read - read handlers
//-------------------------------------------------
-READ_LINE_MEMBER(eeprom_serial_93cxx_device::do_read) { return base_do_read() & ((m_state == STATE_WAIT_FOR_START_BIT) ? base_ready_read() : 1); }
+int eeprom_serial_93cxx_device::do_read() { return base_do_read() & ((m_state == STATE_WAIT_FOR_START_BIT) ? base_ready_read() : 1); }
//-------------------------------------------------
// cs_write/clk_write/di_write - write handlers
//-------------------------------------------------
-WRITE_LINE_MEMBER(eeprom_serial_93cxx_device::cs_write) { base_cs_write(state); }
-WRITE_LINE_MEMBER(eeprom_serial_93cxx_device::clk_write) { base_clk_write(state); }
-WRITE_LINE_MEMBER(eeprom_serial_93cxx_device::di_write) { base_di_write(state); }
+void eeprom_serial_93cxx_device::cs_write(int state) { base_cs_write(state); }
+void eeprom_serial_93cxx_device::clk_write(int state) { base_clk_write(state); }
+void eeprom_serial_93cxx_device::di_write(int state) { base_di_write(state); }
@@ -713,17 +710,17 @@ void eeprom_serial_er5911_device::parse_command_and_address()
// do_read/ready_read - read handlers
//-------------------------------------------------
-READ_LINE_MEMBER(eeprom_serial_er5911_device::do_read) { return base_do_read(); }
-READ_LINE_MEMBER(eeprom_serial_er5911_device::ready_read) { return base_ready_read(); }
+int eeprom_serial_er5911_device::do_read() { return base_do_read(); }
+int eeprom_serial_er5911_device::ready_read() { return base_ready_read(); }
//-------------------------------------------------
// cs_write/clk_write/di_write - write handlers
//-------------------------------------------------
-WRITE_LINE_MEMBER(eeprom_serial_er5911_device::cs_write) { base_cs_write(state); }
-WRITE_LINE_MEMBER(eeprom_serial_er5911_device::clk_write) { base_clk_write(state); }
-WRITE_LINE_MEMBER(eeprom_serial_er5911_device::di_write) { base_di_write(state); }
+void eeprom_serial_er5911_device::cs_write(int state) { base_cs_write(state); }
+void eeprom_serial_er5911_device::clk_write(int state) { base_clk_write(state); }
+void eeprom_serial_er5911_device::di_write(int state) { base_di_write(state); }
@@ -740,14 +737,13 @@ void eeprom_serial_x24c44_device::device_start()
// start the base class
eeprom_serial_base_device::device_start();
- int16_t i=0;
- m_ram_length=0xf;
+ m_ram_length = 0xf;
- for (i=0;i<16;i++){
- m_ram_data[i]=read(i); //autoreload at power up
- }
- m_reading=0;
- m_store_latch=0;
+ for (int i = 0; i < 16; i++)
+ m_ram_data[i] = read(i); // autoreload at power up
+
+ m_reading = 0;
+ m_store_latch = 0;
// save the current state
save_item(NAME(m_ram_data));
@@ -755,31 +751,28 @@ void eeprom_serial_x24c44_device::device_start()
save_item(NAME(m_store_latch));
}
-void eeprom_serial_x24c44_device::copy_eeprom_to_ram(){
- uint16_t i=0;
+void eeprom_serial_x24c44_device::copy_eeprom_to_ram()
+{
LOG1("EEPROM TO RAM COPY!!!\n");
- for (i=0;i<16;i++){
- m_ram_data[i]=read(i);
- }
- m_store_latch=1;
+ for (int i = 0; i < 16; i++)
+ m_ram_data[i] = read(i);
+ m_store_latch = 1;
}
-
-
-void eeprom_serial_x24c44_device::copy_ram_to_eeprom(){
- uint16_t i=0;
- if (m_store_latch){
+void eeprom_serial_x24c44_device::copy_ram_to_eeprom()
+{
+ if (m_store_latch)
+ {
LOG1("RAM TO EEPROM COPY\n");
- for (i=0;i<16;i++){
+ for (int i = 0; i < 16; i++)
write(i, m_ram_data[i]);
- }
- m_store_latch=0;
- }else{
- LOG0("Store command with store latch not set!\n");
+ m_store_latch = 0;
}
-
+ else
+ LOG0("Store command with store latch not set!\n");
}
+
//-------------------------------------------------
// execute_command - execute a command once we
// have enough bits for one
@@ -807,7 +800,7 @@ void eeprom_serial_x24c44_device::execute_command()
{ COMMAND_COPY_RAM_TO_EEPROM, "Execute command:COPY_RAM_TO_EEPROM\n" },
};
const char *command_string = s_command_names[0].string;
- for (int index = 0; index < ARRAY_LENGTH(s_command_names); index++)
+ for (int index = 0; index < std::size(s_command_names); index++)
if (s_command_names[index].command == m_command)
command_string = s_command_names[index].string;
LOG1(command_string, m_address);
@@ -829,14 +822,14 @@ void eeprom_serial_x24c44_device::execute_command()
// lock the chip; return to IN_RESET state
case COMMAND_LOCK:
m_locked = true;
- m_store_latch=0;
+ m_store_latch = 0;
set_state(STATE_IN_RESET);
break;
// unlock the chip; return to IN_RESET state
case COMMAND_UNLOCK:
m_locked = false;
- m_store_latch=1;
+ m_store_latch = 1;
set_state(STATE_IN_RESET);
break;
@@ -909,20 +902,18 @@ void eeprom_serial_x24c44_device::handle_event(eeprom_event event)
// if we have enough bits for a command + address, check it out
m_command_address_accum = (m_command_address_accum << 1) | m_di_state;
- m_bits_accum=m_bits_accum+1;
+ m_bits_accum = m_bits_accum + 1;
- if (m_bits_accum == 2 + m_command_address_bits){
+ if (m_bits_accum == 2 + m_command_address_bits)
+ {
//read command is only 2 bits all other are 3 bits!!!
-
- parse_command_and_address_2_bit();
-
+ parse_command_and_address_2_bit();
}
- if (!m_reading){
- if (m_bits_accum == 3 + m_command_address_bits){
+ if (!m_reading && m_bits_accum == 3 + m_command_address_bits)
+ {
execute_command();
}
- }
}
else if (event == EVENT_CS_FALLING_EDGE)
set_state(STATE_IN_RESET);
@@ -934,8 +925,9 @@ void eeprom_serial_x24c44_device::handle_event(eeprom_event event)
{
int bit_index = m_bits_accum++;
- if (bit_index % m_data_bits == 0 && (bit_index == 0 || m_streaming_enabled)){
- m_shift_register=m_ram_data[m_address];
+ if (bit_index % m_data_bits == 0 && (bit_index == 0 || m_streaming_enabled))
+ {
+ m_shift_register = m_ram_data[m_address];
//m_shift_register=bitswap<16>(m_shift_register,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
//m_shift_register=bitswap<16>(m_shift_register,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8);
@@ -979,7 +971,7 @@ void eeprom_serial_x24c44_device::handle_event(eeprom_event event)
//m_shift_register=bitswap<16>(m_shift_register, 0, 1, 2, 3, 4, 5,6,7, 8, 9,10,11,12,13,14,15);
//m_shift_register=bitswap<16>(m_shift_register, 7, 6, 5, 4, 3, 2,1,0,15,14,13,12,11,10, 9, 8);
m_shift_register=bitswap<16>(m_shift_register,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7);
- m_ram_data[m_address]=m_shift_register;
+ m_ram_data[m_address] = m_shift_register;
LOG1("write to RAM addr=%02X data=%04X\n",m_address,m_shift_register);
}
@@ -1015,7 +1007,7 @@ void eeprom_serial_x24c44_device::parse_command_and_address()
m_address = (m_command_address_accum >> 3) & 0x0f;
- LOG1("EEPROM: command= %04X, address %02X\n", m_command_address_accum& 0x07, m_address);
+ LOG1("EEPROM: command= %04X, address %02X\n", m_command_address_accum & 0x07, m_address);
switch (m_command_address_accum & 0x07)
{
@@ -1069,16 +1061,16 @@ void eeprom_serial_x24c44_device::parse_command_and_address_2_bit()
// do_read/ready_read - read handlers
//-------------------------------------------------
-READ_LINE_MEMBER(eeprom_serial_x24c44_device::do_read) { return base_do_read(); }
+int eeprom_serial_x24c44_device::do_read() { return base_do_read(); }
//-------------------------------------------------
// cs_write/clk_write/di_write - write handlers
//-------------------------------------------------
-WRITE_LINE_MEMBER(eeprom_serial_x24c44_device::cs_write) { base_cs_write(state); }
-WRITE_LINE_MEMBER(eeprom_serial_x24c44_device::clk_write) { base_clk_write(state); }
-WRITE_LINE_MEMBER(eeprom_serial_x24c44_device::di_write) { base_di_write(state); }
+void eeprom_serial_x24c44_device::cs_write(int state) { base_cs_write(state); }
+void eeprom_serial_x24c44_device::clk_write(int state) { base_clk_write(state); }
+void eeprom_serial_x24c44_device::di_write(int state) { base_di_write(state); }
//**************************************************************************
diff --git a/src/devices/machine/eepromser.h b/src/devices/machine/eepromser.h
index d3d33db19d6..4e5361e5e2f 100644
--- a/src/devices/machine/eepromser.h
+++ b/src/devices/machine/eepromser.h
@@ -122,12 +122,12 @@ class eeprom_serial_93cxx_device : public eeprom_serial_base_device
{
public:
// read handlers
- DECLARE_READ_LINE_MEMBER(do_read); // combined DO+READY/BUSY
+ int do_read(); // combined DO+READY/BUSY
// write handlers
- DECLARE_WRITE_LINE_MEMBER(cs_write); // CS signal (active high)
- DECLARE_WRITE_LINE_MEMBER(clk_write); // CLK signal (active high)
- DECLARE_WRITE_LINE_MEMBER(di_write); // DI
+ void cs_write(int state); // CS signal (active high)
+ void clk_write(int state); // CLK signal (active high)
+ void di_write(int state); // DI
protected:
// construction/destruction
@@ -154,13 +154,13 @@ class eeprom_serial_er5911_device : public eeprom_serial_base_device
{
public:
// read handlers
- DECLARE_READ_LINE_MEMBER(do_read); // DO
- DECLARE_READ_LINE_MEMBER(ready_read); // READY/BUSY only
+ int do_read(); // DO
+ int ready_read(); // READY/BUSY only
// write handlers
- DECLARE_WRITE_LINE_MEMBER(cs_write); // CS signal (active high)
- DECLARE_WRITE_LINE_MEMBER(clk_write); // CLK signal (active high)
- DECLARE_WRITE_LINE_MEMBER(di_write); // DI
+ void cs_write(int state); // CS signal (active high)
+ void clk_write(int state); // CLK signal (active high)
+ void di_write(int state); // DI
protected:
// construction/destruction
@@ -179,12 +179,12 @@ class eeprom_serial_x24c44_device : public eeprom_serial_base_device
//async store not implemented
public:
// read handlers
- DECLARE_READ_LINE_MEMBER(do_read); // DO
+ int do_read(); // DO
// write handlers
- DECLARE_WRITE_LINE_MEMBER(cs_write); // CS signal (active high)
- DECLARE_WRITE_LINE_MEMBER(clk_write); // CLK signal (active high)
- DECLARE_WRITE_LINE_MEMBER(di_write); // DI
+ void cs_write(int state); // CS signal (active high)
+ void clk_write(int state); // CLK signal (active high)
+ void di_write(int state); // DI
protected:
// construction/destruction
diff --git a/src/devices/machine/em_reel.cpp b/src/devices/machine/em_reel.cpp
new file mode 100644
index 00000000000..392c9331818
--- /dev/null
+++ b/src/devices/machine/em_reel.cpp
@@ -0,0 +1,125 @@
+// license:BSD-3-Clause
+// copyright-holders:SomeRandomGuyIdk
+/**********************************************************************
+
+ Electromechanical reels for slot machines
+
+**********************************************************************/
+
+#include "emu.h"
+#include "em_reel.h"
+
+#include <algorithm>
+
+
+ALLOW_SAVE_TYPE(em_reel_device::dir);
+ALLOW_SAVE_TYPE(em_reel_device::reel_state);
+
+DEFINE_DEVICE_TYPE(EM_REEL, em_reel_device, "em_reel", "Electromechanical Reel")
+
+em_reel_device::em_reel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, EM_REEL, tag, owner, clock),
+ m_reel_out(*this, tag),
+ m_state_cb(*this)
+{
+}
+
+void em_reel_device::set_state(uint8_t state)
+{
+ if(m_state == reel_state::STOPPED)
+ {
+ if(state)
+ {
+ m_state = reel_state::SPINNING;
+ m_move_timer->adjust(m_step_period);
+ m_state_cb(1);
+ }
+ }
+ else if(m_state == reel_state::SPINNING)
+ {
+ if(!state)
+ {
+ if(is_at_detent()) // If reel is already on a detent, then stop it immediately
+ {
+ m_move_timer->adjust(attotime::never);
+ m_state = reel_state::STOPPED;
+ m_state_cb(0);
+ }
+ else
+ {
+ m_state = reel_state::STOPPING;
+ }
+ }
+ }
+ else if(m_state == reel_state::STOPPING)
+ {
+ if(state)
+ m_state = reel_state::SPINNING;
+ }
+}
+
+inline bool em_reel_device::is_at_detent() const
+{
+ auto const found = std::lower_bound(m_detents.begin(), m_detents.end(), m_pos);
+ return (m_detents.end() != found) && (*found == m_pos);
+}
+
+TIMER_CALLBACK_MEMBER( em_reel_device::move )
+{
+ if(m_direction == dir::REVERSE)
+ {
+ if(m_pos == 0)
+ m_pos = m_max_pos;
+ else
+ m_pos--;
+ }
+ else
+ {
+ if(m_pos == m_max_pos)
+ m_pos = 0;
+ else
+ m_pos++;
+ }
+
+ if(m_state == reel_state::STOPPING && is_at_detent()) // Stop once a detent is reached
+ {
+ m_state = reel_state::STOPPED;
+ m_state_cb(0);
+ }
+ else
+ {
+ m_move_timer->adjust(m_step_period);
+ }
+
+ m_reel_out = m_pos;
+}
+
+void em_reel_device::device_start()
+{
+ m_reel_out.resolve();
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_pos));
+ save_item(NAME(m_direction));
+
+ m_move_timer = timer_alloc(FUNC(em_reel_device::move), this);
+
+ m_state = reel_state::STOPPED;
+ m_pos = 0;
+}
+
+void em_reel_device::device_validity_check(validity_checker &valid) const
+{
+ auto detent = m_detents.begin();
+ while(m_detents.end() != detent)
+ {
+ if(*detent > m_max_pos)
+ fatalerror("Detent on step %u is out of range, maximum is %u\n", *detent, m_max_pos);
+
+ auto const next = std::next(detent);
+ if((m_detents.end() != next) && (*next <= *detent))
+ fatalerror("Detents %u and %u are not in ascending order\n", *detent, *next);
+
+ detent = next;
+ }
+}
diff --git a/src/devices/machine/em_reel.h b/src/devices/machine/em_reel.h
new file mode 100644
index 00000000000..1a50fffcff1
--- /dev/null
+++ b/src/devices/machine/em_reel.h
@@ -0,0 +1,89 @@
+// license:BSD-3-Clause
+// copyright-holders:SomeRandomGuyIdk
+/**********************************************************************
+
+ Electromechanical reels for slot machines
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_EM_REEL_H
+#define MAME_MACHINE_EM_REEL_H
+
+#pragma once
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+
+class em_reel_device : public device_t
+{
+public:
+ enum class dir : uint8_t
+ {
+ FORWARD = 0, // Steps count up
+ REVERSE // Steps count down
+ };
+
+ em_reel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ template <typename T>
+ em_reel_device(
+ const machine_config &mconfig, const char *tag, device_t *owner,
+ uint16_t steps, T &&detents, attotime period, dir direction = dir::REVERSE) :
+ em_reel_device(mconfig, tag, owner, 0)
+ {
+ set_max_pos(steps);
+ set_detents(std::forward<T>(detents));
+ set_rotation_period(period);
+ set_direction(direction);
+ }
+
+ // Movement state callback, used for playing samples
+ auto state_changed_callback() { return m_state_cb.bind(); }
+
+ // Set period for one full rotation
+ void set_rotation_period(attotime period) { m_step_period = period / (m_max_pos + 1); }
+
+ // Get the reel's current step position
+ uint16_t get_pos() const { return m_pos; }
+ // Start and stop the reel
+ void set_state(uint8_t state);
+ // Set the direction the reel moves in
+ void set_direction(dir direction) { m_direction = direction; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_validity_check(validity_checker &valid) const override;
+
+private:
+ enum class reel_state : uint8_t
+ {
+ STOPPED = 0,
+ SPINNING,
+ STOPPING
+ };
+
+ TIMER_CALLBACK_MEMBER(move);
+
+ void set_max_pos(uint16_t steps) { m_max_pos = steps - 1; }
+ template <typename T> void set_detents(T &&detents) { m_detents.assign(std::begin(detents), std::end(detents)); }
+
+ bool is_at_detent() const;
+
+ std::vector<uint16_t> m_detents;
+ uint16_t m_max_pos;
+ attotime m_step_period;
+
+ output_finder<> m_reel_out;
+ devcb_write_line m_state_cb;
+
+ reel_state m_state;
+ uint16_t m_pos;
+ dir m_direction;
+ emu_timer *m_move_timer;
+};
+
+DECLARE_DEVICE_TYPE(EM_REEL, em_reel_device)
+
+#endif // MAME_MACHINE_EM_REEL_H
diff --git a/src/devices/machine/er1400.cpp b/src/devices/machine/er1400.cpp
index f42a9f58f9c..03b1df5036c 100644
--- a/src/devices/machine/er1400.cpp
+++ b/src/devices/machine/er1400.cpp
@@ -22,7 +22,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/er1400.h"
+#include "er1400.h"
#define VERBOSE 0
#include "logmacro.h"
@@ -75,7 +75,7 @@ void er1400_device::device_start()
m_data_array = std::make_unique<u16[]>(100);
save_pointer(NAME(m_data_array), 100);
- m_data_propagation_timer = timer_alloc(PROPAGATION_TIMER);
+ m_data_propagation_timer = timer_alloc(FUNC(er1400_device::propagate_data), this);
}
@@ -104,9 +104,12 @@ void er1400_device::nvram_default()
// .nv file
//-------------------------------------------------
-void er1400_device::nvram_read(emu_file &file)
+bool er1400_device::nvram_read(util::read_stream &file)
{
- file.read(&m_data_array[0], 100 * sizeof(m_data_array[0]));
+ size_t const size = 100 * sizeof(m_data_array[0]);
+
+ auto const [err, actual] = read(file, &m_data_array[0], size);
+ return !err && (actual == size);
}
@@ -115,9 +118,12 @@ void er1400_device::nvram_read(emu_file &file)
// specified file
//-------------------------------------------------
-void er1400_device::nvram_write(emu_file &file)
+bool er1400_device::nvram_write(util::write_stream &file)
{
- file.write(&m_data_array[0], 100 * sizeof(m_data_array[0]));
+ size_t const size = 100 * sizeof(m_data_array[0]);
+
+ auto const [err, actual] = write(file, &m_data_array[0], size);
+ return !err;
}
@@ -239,7 +245,7 @@ void er1400_device::erase_data()
// data_w - write data input line
//-------------------------------------------------
-WRITE_LINE_MEMBER(er1400_device::data_w)
+void er1400_device::data_w(int state)
{
m_data_input = bool(state);
}
@@ -249,7 +255,7 @@ WRITE_LINE_MEMBER(er1400_device::data_w)
// c1_w - write to first control line
//-------------------------------------------------
-WRITE_LINE_MEMBER(er1400_device::c1_w)
+void er1400_device::c1_w(int state)
{
if (bool(state) == BIT(m_code_input, 2))
return;
@@ -264,7 +270,7 @@ WRITE_LINE_MEMBER(er1400_device::c1_w)
// c2_w - write to second control line
//-------------------------------------------------
-WRITE_LINE_MEMBER(er1400_device::c2_w)
+void er1400_device::c2_w(int state)
{
if (bool(state) == BIT(m_code_input, 1))
return;
@@ -279,7 +285,7 @@ WRITE_LINE_MEMBER(er1400_device::c2_w)
// c3_w - write to third control line
//-------------------------------------------------
-WRITE_LINE_MEMBER(er1400_device::c3_w)
+void er1400_device::c3_w(int state)
{
if (bool(state) == BIT(m_code_input, 0))
return;
@@ -291,24 +297,18 @@ WRITE_LINE_MEMBER(er1400_device::c3_w)
//-------------------------------------------------
-// device_timer - called whenever a device timer
-// fires
+// propagate_data - clock data out from the chip
//-------------------------------------------------
-void er1400_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(er1400_device::propagate_data)
{
- switch (id)
+ if (m_code_input == 5)
{
- case PROPAGATION_TIMER:
- if (m_code_input == 5)
- {
- m_data_output = BIT(m_data_register, 13);
- LOG("Data output %d bit\n", m_data_output);
- }
- else
- m_data_output = false;
- break;
+ m_data_output = BIT(m_data_register, 13);
+ LOG("Data output %d bit\n", m_data_output);
}
+ else
+ m_data_output = false;
}
@@ -316,14 +316,14 @@ void er1400_device::device_timer(emu_timer &timer, device_timer_id id, int param
// clock_w - write to clock line
//-------------------------------------------------
-WRITE_LINE_MEMBER(er1400_device::clock_w)
+void er1400_device::clock_w(int state)
{
if (m_clock_input == bool(state))
return;
m_clock_input = bool(state);
// Commands are clocked by a logical 1 -> 0 transition (i.e. rising edge)
- if (!state)
+ if (state)
{
if (machine().time() >= m_write_time)
write_data();
@@ -396,7 +396,7 @@ WRITE_LINE_MEMBER(er1400_device::clock_w)
// data_r - read data line
//-------------------------------------------------
-READ_LINE_MEMBER(er1400_device::data_r)
+int er1400_device::data_r()
{
- return m_data_input | m_data_output;
+ return m_data_input & m_data_output;
}
diff --git a/src/devices/machine/er1400.h b/src/devices/machine/er1400.h
index 984a6c9eea0..045fd7a0ef8 100644
--- a/src/devices/machine/er1400.h
+++ b/src/devices/machine/er1400.h
@@ -35,22 +35,23 @@ public:
er1400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
// line handlers
- DECLARE_WRITE_LINE_MEMBER(data_w);
- DECLARE_WRITE_LINE_MEMBER(c1_w);
- DECLARE_WRITE_LINE_MEMBER(c2_w);
- DECLARE_WRITE_LINE_MEMBER(c3_w);
- DECLARE_WRITE_LINE_MEMBER(clock_w);
- DECLARE_READ_LINE_MEMBER(data_r);
+ void data_w(int state);
+ void c1_w(int state);
+ void c2_w(int state);
+ void c3_w(int state);
+ void clock_w(int state);
+ int data_r();
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ TIMER_CALLBACK_MEMBER(propagate_data);
private:
enum
diff --git a/src/devices/machine/er2055.cpp b/src/devices/machine/er2055.cpp
index 20fd3805e7d..f6c74bb3d6c 100644
--- a/src/devices/machine/er2055.cpp
+++ b/src/devices/machine/er2055.cpp
@@ -12,7 +12,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/er2055.h"
+#include "er2055.h"
#include "logmacro.h"
@@ -83,9 +83,10 @@ void er2055_device::nvram_default()
// .nv file
//-------------------------------------------------
-void er2055_device::nvram_read(emu_file &file)
+bool er2055_device::nvram_read(util::read_stream &file)
{
- file.read(&m_rom_data[0], SIZE_DATA);
+ auto const [err, actual] = read(file, &m_rom_data[0], SIZE_DATA);
+ return !err && (actual == SIZE_DATA);
}
@@ -94,9 +95,10 @@ void er2055_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void er2055_device::nvram_write(emu_file &file)
+bool er2055_device::nvram_write(util::write_stream &file)
{
- file.write(&m_rom_data[0], SIZE_DATA);
+ auto const [err, actual] = write(file, &m_rom_data[0], SIZE_DATA);
+ return !err;
}
@@ -161,7 +163,7 @@ void er2055_device::update_state()
// successive write or erase operations
//-------------------------------------------------
-WRITE_LINE_MEMBER(er2055_device::set_clk)
+void er2055_device::set_clk(int state)
{
uint8_t oldstate = m_control_state;
if (state)
diff --git a/src/devices/machine/er2055.h b/src/devices/machine/er2055.h
index 74cbfe6f68e..449ffde2bb2 100644
--- a/src/devices/machine/er2055.h
+++ b/src/devices/machine/er2055.h
@@ -50,7 +50,7 @@ public:
// control lines -- all lines are specified as active-high (even CS2)
void set_control(uint8_t cs1, uint8_t cs2, uint8_t c1, uint8_t c2);
- DECLARE_WRITE_LINE_MEMBER(set_clk);
+ void set_clk(int state);
protected:
// device-level overrides
@@ -58,8 +58,8 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
void update_state();
diff --git a/src/devices/machine/exorterm.cpp b/src/devices/machine/exorterm.cpp
index 9db3f0658e4..977b84ec937 100644
--- a/src/devices/machine/exorterm.cpp
+++ b/src/devices/machine/exorterm.cpp
@@ -17,7 +17,8 @@ TODO
****************************************************************************/
#include "emu.h"
-#include "machine/exorterm.h"
+#include "exorterm.h"
+
#include "speaker.h"
#include "exorterm155.lh"
@@ -304,7 +305,7 @@ void exorterm155_device::pia_kbd_pb_w(u8 data)
// if the firmware uses these?
}
-WRITE_LINE_MEMBER(exorterm155_device::pia_cfg_cb2_w)
+void exorterm155_device::pia_cfg_cb2_w(int state)
{
m_beeper->set_state(!state);
}
@@ -334,11 +335,6 @@ void exorterm155_device::pia_disp_pb_w(u8 data)
m_rs232_conn_dtr_handler(BIT(data, 7));
}
-READ_LINE_MEMBER(exorterm155_device::pia_disp_ca2_r)
-{
- return m_ring;
-}
-
//**************************************************************************
// VIDEO EMULATION
//**************************************************************************
@@ -458,7 +454,7 @@ GFXDECODE_END
// MACHINE EMULATION
//**************************************************************************
-WRITE_LINE_MEMBER(exorterm155_device::sys_timer_w)
+void exorterm155_device::sys_timer_w(int state)
{
// 3.4ms
m_pia_disp->cb1_w(state);
@@ -478,7 +474,7 @@ WRITE_LINE_MEMBER(exorterm155_device::sys_timer_w)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f1_clock)
+void exorterm155_device::write_f1_clock(int state)
{
if (BIT(m_rs232_baud->read(), 0))
{
@@ -487,7 +483,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f1_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f3_clock)
+void exorterm155_device::write_f3_clock(int state)
{
if (BIT(m_rs232_baud->read(), 1))
{
@@ -496,7 +492,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f3_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f5_clock)
+void exorterm155_device::write_f5_clock(int state)
{
if (BIT(m_rs232_baud->read(), 2))
{
@@ -505,7 +501,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f5_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f6_clock)
+void exorterm155_device::write_f6_clock(int state)
{
if (BIT(m_rs232_baud->read(), 3))
{
@@ -514,7 +510,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f6_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f7_clock)
+void exorterm155_device::write_f7_clock(int state)
{
if (BIT(m_rs232_baud->read(), 4))
{
@@ -523,7 +519,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f7_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f8_clock)
+void exorterm155_device::write_f8_clock(int state)
{
if (BIT(m_rs232_baud->read(), 5))
{
@@ -532,7 +528,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f8_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f9_clock)
+void exorterm155_device::write_f9_clock(int state)
{
if (BIT(m_rs232_baud->read(), 6))
{
@@ -541,7 +537,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f9_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f11_clock)
+void exorterm155_device::write_f11_clock(int state)
{
if (BIT(m_rs232_baud->read(), 7))
{
@@ -550,7 +546,7 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f11_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::write_f13_clock)
+void exorterm155_device::write_f13_clock(int state)
{
if (BIT(m_rs232_baud->read(), 8))
{
@@ -559,38 +555,38 @@ WRITE_LINE_MEMBER(exorterm155_device::write_f13_clock)
}
}
-WRITE_LINE_MEMBER(exorterm155_device::acia_txd_w)
+void exorterm155_device::acia_txd_w(int state)
{
m_rs232_conn_txd_handler(state);
}
-WRITE_LINE_MEMBER(exorterm155_device::acia_rts_w)
+void exorterm155_device::acia_rts_w(int state)
{
m_rs232_conn_rts_handler(state);
}
-WRITE_LINE_MEMBER(exorterm155_device::rs232_conn_dcd_w)
+void exorterm155_device::rs232_conn_dcd_w(int state)
{
m_acia->write_dcd(state);
}
-WRITE_LINE_MEMBER(exorterm155_device::rs232_conn_dsr_w)
+void exorterm155_device::rs232_conn_dsr_w(int state)
{
// Input of Display PIA PB5, pulled high.
m_dsr = state;
}
-WRITE_LINE_MEMBER(exorterm155_device::rs232_conn_ri_w)
+void exorterm155_device::rs232_conn_ri_w(int state)
{
- m_ring = state;
+ m_pia_disp->ca2_w(state);
}
-WRITE_LINE_MEMBER(exorterm155_device::rs232_conn_cts_w)
+void exorterm155_device::rs232_conn_cts_w(int state)
{
m_acia->write_cts(state);
}
-WRITE_LINE_MEMBER(exorterm155_device::rs232_conn_rxd_w)
+void exorterm155_device::rs232_conn_rxd_w(int state)
{
m_acia->write_rxd(state);
}
@@ -734,13 +730,6 @@ TIMER_CALLBACK_MEMBER(exorterm155_device::kbd_repeat)
-void exorterm155_device::device_resolve_objects()
-{
- m_rs232_conn_dtr_handler.resolve_safe();
- m_rs232_conn_rts_handler.resolve_safe();
- m_rs232_conn_txd_handler.resolve_safe();
-}
-
void exorterm155_device::device_start()
{
m_online_led.resolve();
@@ -757,12 +746,11 @@ void exorterm155_device::device_start()
save_item(NAME(m_sys_timer_count));
save_item(NAME(m_dsr));
- save_item(NAME(m_ring));
save_item(NAME(m_kbd_start_holdoff));
// Keyboard
- m_kbd_scan_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(exorterm155_device::kbd_scan_row), this));
- m_kbd_repeat_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(exorterm155_device::kbd_repeat), this));
+ m_kbd_scan_timer = timer_alloc(FUNC(exorterm155_device::kbd_scan_row), this);
+ m_kbd_repeat_timer = timer_alloc(FUNC(exorterm155_device::kbd_repeat), this);
kbd_reset_state();
kbd_repeat_stop();
@@ -774,7 +762,6 @@ void exorterm155_device::device_start()
save_item(NAME(m_kbd_last_modifiers));
m_dsr = 1;
- m_ring = 0;
}
void exorterm155_device::device_reset()
@@ -877,7 +864,7 @@ void exorterm155_device::device_add_mconfig(machine_config &config)
m_pia_disp->writepa_handler().set(FUNC(exorterm155_device::pia_disp_pa_w));
m_pia_disp->readpb_handler().set(FUNC(exorterm155_device::pia_disp_pb_r));
m_pia_disp->writepb_handler().set(FUNC(exorterm155_device::pia_disp_pb_w));
- m_pia_disp->readca2_handler().set(FUNC(exorterm155_device::pia_disp_ca2_r));
+ m_pia_disp->ca2_w(0);
m_pia_disp->irqa_handler().set(m_irqs, FUNC(input_merger_device::in_w<5>));
m_pia_disp->irqb_handler().set(m_irqs, FUNC(input_merger_device::in_w<6>));
diff --git a/src/devices/machine/exorterm.h b/src/devices/machine/exorterm.h
index ee41cab4422..45c141a7b95 100644
--- a/src/devices/machine/exorterm.h
+++ b/src/devices/machine/exorterm.h
@@ -36,16 +36,15 @@ public:
auto rs232_conn_txd_handler() { return m_rs232_conn_txd_handler.bind(); }
auto rs232_conn_dtr_handler() { return m_rs232_conn_dtr_handler.bind(); }
auto rs232_conn_rts_handler() { return m_rs232_conn_rts_handler.bind(); }
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_dcd_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_dsr_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_ri_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_cts_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_rxd_w);
+ void rs232_conn_dcd_w(int state);
+ void rs232_conn_dsr_w(int state);
+ void rs232_conn_ri_w(int state);
+ void rs232_conn_cts_w(int state);
+ void rs232_conn_rxd_w(int state);
protected:
exorterm155_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
- virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
@@ -77,22 +76,21 @@ private:
void mem_map(address_map &map);
- DECLARE_WRITE_LINE_MEMBER(acia_txd_w);
- DECLARE_WRITE_LINE_MEMBER(acia_rts_w);
+ void acia_txd_w(int state);
+ void acia_rts_w(int state);
// Clocks
- DECLARE_WRITE_LINE_MEMBER(write_f1_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f3_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f5_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f6_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f7_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f8_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f9_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f11_clock);
- DECLARE_WRITE_LINE_MEMBER(write_f13_clock);
+ void write_f1_clock(int state);
+ void write_f3_clock(int state);
+ void write_f5_clock(int state);
+ void write_f6_clock(int state);
+ void write_f7_clock(int state);
+ void write_f8_clock(int state);
+ void write_f9_clock(int state);
+ void write_f11_clock(int state);
+ void write_f13_clock(int state);
u8 m_dsr;
- u8 m_ring;
devcb_write_line m_rs232_conn_txd_handler;
devcb_write_line m_rs232_conn_dtr_handler;
@@ -104,10 +102,10 @@ private:
u8 m_inv_video;
u8 m_special_char_disp;
- DECLARE_WRITE_LINE_MEMBER(sys_timer_w);
+ void sys_timer_w(int state);
u8 m_sys_timer_count;
- DECLARE_WRITE_LINE_MEMBER(pia_cfg_cb2_w);
+ void pia_cfg_cb2_w(int state);
u8 pia_kbd_pa_r();
u8 pia_kbd_pb_r();
@@ -117,7 +115,6 @@ private:
u8 pia_disp_pb_r();
void pia_disp_pa_w(u8 data);
void pia_disp_pb_w(u8 data);
- DECLARE_READ_LINE_MEMBER(pia_disp_ca2_r);
u8 m_kbd_start_holdoff;
@@ -130,7 +127,6 @@ private:
void kbd_repeat_start(u8 row, u8 column);
void kbd_repeat_restart();
void kbd_repeat_stop();
- void kbd_repeat();
void kbd_send_translated(u8 code);
TIMER_CALLBACK_MEMBER(kbd_scan_row);
diff --git a/src/devices/machine/f3853.cpp b/src/devices/machine/f3853.cpp
index 4f7b6ff798b..87ee05ed19c 100644
--- a/src/devices/machine/f3853.cpp
+++ b/src/devices/machine/f3853.cpp
@@ -46,7 +46,7 @@ DEFINE_DEVICE_TYPE(F38T56, f38t56_device, "f38t56_psu", "Fairchild F38T56 PSU")
f3853_device::f3853_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, type, tag, owner, clock),
m_int_req_callback(*this),
- m_pri_out_callback(*this),
+ m_pri_out_callback(*this), // TODO: not implemented
m_int_daisy_chain_callback(*this),
m_int_vector(0),
m_prescaler(31),
@@ -60,7 +60,7 @@ f3853_device::f3853_device(const machine_config &mconfig, const char *tag, devic
f3851_device::f3851_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
f3853_device(mconfig, type, tag, owner, clock),
- m_read_port(*this),
+ m_read_port(*this, 0),
m_write_port(*this)
{ }
@@ -88,20 +88,9 @@ f38t56_device::f38t56_device(const machine_config &mconfig, const char *tag, dev
void f3853_device::device_resolve_objects()
{
- m_int_req_callback.resolve_safe();
- m_pri_out_callback.resolve_safe(); // TODO: not implemented
m_int_daisy_chain_callback.resolve();
}
-void f3851_device::device_resolve_objects()
-{
- f3853_device::device_resolve_objects();
-
- // 2 I/O ports
- m_read_port.resolve_all_safe(0);
- m_write_port.resolve_all_safe();
-}
-
void f3853_device::device_start()
{
// lookup table for 3851/3853 lfsr timer
@@ -113,7 +102,7 @@ void f3853_device::device_start()
reg = reg << 1 | (BIT(reg,7) ^ BIT(reg,5) ^ BIT(reg,4) ^ BIT(reg,3) ^ 1);
}
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(f3853_device::timer_callback),this));
+ m_timer = timer_alloc(FUNC(f3853_device::timer_callback), this);
// zerofill (what's not in constructor)
m_external_int_enable = false;
@@ -207,7 +196,7 @@ TIMER_CALLBACK_MEMBER(f3853_device::timer_callback)
}
-WRITE_LINE_MEMBER(f3853_device::ext_int_w)
+void f3853_device::ext_int_w(int state)
{
if (!m_external_interrupt_line && state && m_external_int_enable)
{
@@ -217,7 +206,7 @@ WRITE_LINE_MEMBER(f3853_device::ext_int_w)
set_interrupt_request_line();
}
-WRITE_LINE_MEMBER(f3853_device::pri_in_w)
+void f3853_device::pri_in_w(int state)
{
m_priority_line = bool(state);
set_interrupt_request_line();
diff --git a/src/devices/machine/f3853.h b/src/devices/machine/f3853.h
index f7d6adb3b5c..16bdde050e2 100644
--- a/src/devices/machine/f3853.h
+++ b/src/devices/machine/f3853.h
@@ -76,8 +76,8 @@ public:
virtual uint8_t read(offs_t offset);
virtual void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(ext_int_w);
- DECLARE_WRITE_LINE_MEMBER(pri_in_w);
+ void ext_int_w(int state);
+ void pri_in_w(int state);
virtual TIMER_CALLBACK_MEMBER(timer_callback);
@@ -86,7 +86,7 @@ public:
protected:
f3853_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
+ // device_t implementation
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
@@ -136,8 +136,6 @@ public:
protected:
f3851_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- virtual void device_resolve_objects() override;
-
devcb_read8::array<2> m_read_port;
devcb_write8::array<2> m_write_port;
};
diff --git a/src/devices/machine/f4702.cpp b/src/devices/machine/f4702.cpp
new file mode 100644
index 00000000000..499f1a6793a
--- /dev/null
+++ b/src/devices/machine/f4702.cpp
@@ -0,0 +1,260 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/****************************************************************************
+
+ Fairchild 4702B Programmable Bit Rate Generator
+
+ Originally numbered 34702 in Fairchild's isoplanar CMOS series (whose
+ lower-numbered products were logical equivalents of RCA CD4000 and
+ Motorola MC14500 series devices), this BRG incorporates some unusually
+ sophisticated features into its 16-pin package, which may be why
+ Fairchild classified it as a LSI IC.
+
+ The standard 2.4576 MHz master clock, either generated from a crystal
+ oscillator (Ix, Ox) or provided as a TTL input (CP), is first prescaled
+ by dividing by 8 and then divided further down through a network of
+ counters with differing periods. These counters are tapped at 13 points,
+ each frequency being 16 times a common baud rate. The rate output (Z),
+ whose changes are synchronized with the master clock, is multiplexed
+ from any one of these internal sources or an external rate input (Im) by
+ a 4-bit select code (S0, S1, S2, S3).
+
+ The buffered clock output (CO) and the three prescaler divisions (Q0,
+ Q1, Q2) are not only conveniently available externally for clocking
+ additional 4702s or other devices, but can also be exploited to
+ generate 8 baud rates simultaneously, with the aid of a Fairchild 93L34
+ (or compatible) addressable latch for demultiplexing the channels. In
+ this configuration, the CO, Q and Z outputs are respectively tied to the
+ latch's enable, address and data inputs, and the Q outputs are directly
+ or indirectly fed back into the S inputs. (Fairchild even suggested
+ scanning 9LS170 register files with the Q outputs so as to make each
+ rate individually programmable.)
+
+ The rate select codes are arranged so that connecting a simple five-
+ point switch to the S inputs can obtain 110, 150, 300, 1200 or 2400
+ baud, and only three binary switches are needed to select between all
+ five of those rates plus 1800, 4800 and 9600 baud. 19200 baud can also
+ be obtained by tapping the Q2 output, but no more than 4 internally
+ multiplexed rates can be used at once if Im is generated from Q2.
+
+ All inputs and outputs except Ix and Ox are TTL-compatible, with the
+ inputs also having internal pull-ups so switches can be connected
+ directly.
+
+ To enable the Ix/Ox oscillator circuit, Ecp must be high and CP must
+ remain low, since Ecp and CP both being high places the chip in a
+ continuous reset mode (except for the CO output). If Ecp is brought
+ low, the initialization circuit produces an internal master reset
+ pulse the first time CP goes high. Neither of these two reset methods
+ was used much in practice.
+
+ Intersil, one of not many companies to second-source the original 4702,
+ later produced IM4712, a minor variant which requires fewer external
+ discrete components to drive the crystal oscillator but is otherwise
+ logically identical.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "f4702.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(F4702, f4702_device, "f4702", "Fairchild 4702B Bit Rate Generator")
+
+
+//**************************************************************************
+// DEVICE CONSTRUCTION AND INITIALIZATION
+//**************************************************************************
+
+//-------------------------------------------------
+// f4702_device - constructor
+//-------------------------------------------------
+
+f4702_device::f4702_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, F4702, tag, owner, clock)
+ , device_execute_interface(mconfig, *this)
+ , m_s_callback(*this, 15)
+ , m_z_callback(*this)
+ , m_main_counter(0)
+ , m_div_200_50(0)
+ , m_div_134_5(0)
+ , m_div_110(0)
+ , m_div_1800(0)
+ , m_im(true)
+ , m_s(0)
+ , m_icount(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void f4702_device::device_start()
+{
+ set_icountptr(m_icount);
+
+ save_item(NAME(m_main_counter));
+ save_item(NAME(m_div_200_50));
+ save_item(NAME(m_div_134_5));
+ save_item(NAME(m_div_110));
+ save_item(NAME(m_div_1800));
+ save_item(NAME(m_im));
+ save_item(NAME(m_s));
+}
+
+
+//-------------------------------------------------
+// reset_counters - optional master reset
+//-------------------------------------------------
+
+void f4702_device::reset_counters()
+{
+ // Reset counter network
+ m_main_counter = 0;
+ m_div_200_50 = 0;
+ m_div_134_5 = 0;
+ m_div_1800 = 0;
+
+ // Reset Q and Z outputs
+ m_z_callback(0, 0);
+}
+
+
+//**************************************************************************
+// RATE GENERATION
+//**************************************************************************
+
+//-------------------------------------------------
+// im_w - set external rate input
+//-------------------------------------------------
+
+void f4702_device::im_w(int state)
+{
+ m_im = state;
+}
+
+
+//-------------------------------------------------
+// z_output - recalculate output state
+//-------------------------------------------------
+
+bool f4702_device::z_output() const
+{
+ // Select Z output from one of the 13 counter taps or the external input
+ switch (m_s)
+ {
+ // S3–S0 = LLLL or LLLH: multiplexed input
+ case 0:
+ case 1:
+ default:
+ return m_im;
+
+ // S3–S0 = LLHL: 50 baud
+ case 2:
+ return m_div_200_50 >= 12;
+
+ // S3–S0 = LLHH: 75 baud
+ case 3:
+ return BIT(m_main_counter, 10);
+
+ // S3–S0 = LHLL: 134.5 baud (-0.87% error)
+ case 4:
+ return m_div_134_5 >= 9;
+
+ // S3–S0 = LHLH: 200 baud
+ case 5:
+ return (m_div_200_50 % 6) >= 3;
+
+ // S3–S0 = LHHL: 600 baud
+ case 6:
+ return BIT(m_main_counter, 7);
+
+ // S3–S0 = LHHH or HHLL: 2400 baud
+ case 7:
+ case 12:
+ return BIT(m_main_counter, 5);
+
+ // S3–S0 = HLLL: 9600 baud
+ case 8:
+ return BIT(m_main_counter, 3);
+
+ // S3–S0 = HLLH: 4800 baud
+ case 9:
+ return BIT(m_main_counter, 4);
+
+ // S3–S0 = HLHL: 1800 baud
+ case 10:
+ return (m_div_1800 % 5) >= 2;
+
+ // S3–S0 = HLHH: 1200 baud
+ case 11:
+ return BIT(m_main_counter, 6);
+
+ // S3–S0 = HHLH: 300 baud
+ case 13:
+ return BIT(m_main_counter, 8);
+
+ // S3–S0 = HHHL: 150 baud
+ case 14:
+ return BIT(m_main_counter, 9);
+
+ // S3–S0 = HHHH: 110 baud (-0.83% error)
+ case 15:
+ return m_div_110 >= 11;
+ }
+}
+
+
+//-------------------------------------------------
+// execute_run - execute a timeslice's worth of
+// counting
+//-------------------------------------------------
+
+void f4702_device::execute_run()
+{
+ do {
+ // Drive the main scan and frequency counter
+ m_main_counter++;
+ if ((m_main_counter & 0x00f) == 0)
+ {
+ // Divide 9600 baud by 16/3 (16 = 5 + 5 + 6)
+ m_div_1800++;
+ if (m_div_1800 >= 16)
+ m_div_1800 = 0;
+
+ if ((m_main_counter & 0x03f) == 0)
+ {
+ // Divide 2400 baud by 18
+ m_div_134_5++;
+ if (m_div_134_5 >= 18)
+ m_div_134_5 = 0;
+
+ // Divide 2400 baud by 22 as well
+ m_div_110++;
+ if (m_div_110 >= 22)
+ m_div_110 = 0;
+
+ if ((m_main_counter & 0x07f) == 0)
+ {
+ // Divide 1200 baud by 6 and then again by 4
+ m_div_200_50++;
+ if (m_div_200_50 >= 24)
+ m_div_200_50 = 0;
+ }
+ }
+ }
+
+ // Update Q and Z outputs
+ m_z_callback(m_main_counter & 0x007, z_output());
+
+ // S3–S0 inputs are valid on the rising edge of CO
+ m_s = m_s_callback(m_main_counter & 0x007) & 15;
+ } while (--m_icount > 0);
+}
diff --git a/src/devices/machine/f4702.h b/src/devices/machine/f4702.h
new file mode 100644
index 00000000000..dcafebe5fd0
--- /dev/null
+++ b/src/devices/machine/f4702.h
@@ -0,0 +1,75 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/****************************************************************************
+
+ Fairchild 4702B Programmable Bit Rate Generator
+
+*****************************************************************************
+ ____ ____
+ Q0 1 |* \_/ | 16 Vdd
+ Q1 2 | | 15 Im
+ Q2 3 | | 14 S0
+ _Ecp 4 | | 13 S1
+ CP 5 | 4702BPC | 12 S2
+ Ox 6 | | 11 S3
+ Ix 7 | | 10 Z
+ Vss 8 |___________| 9 CO
+
+****************************************************************************/
+
+#ifndef MAME_MACHINE_F4702_H
+#define MAME_MACHINE_F4702_H
+
+#pragma once
+
+
+// ======================> f4702_device
+
+class f4702_device : public device_t, public device_execute_interface
+{
+public:
+ f4702_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // callback configuration
+ auto s_callback() { return m_s_callback.bind(); }
+ auto z_callback() { return m_z_callback.bind(); }
+
+ // external rate input
+ void im_w(int state);
+
+ // reset control (optional)
+ void reset_counters();
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+
+ // device_execute_interface implementation
+ virtual void execute_run() override;
+
+private:
+ // internal helpers
+ bool z_output() const;
+
+ // input & output callbacks
+ devcb_read8 m_s_callback;
+ devcb_write8 m_z_callback;
+
+ // internal counters
+ u16 m_main_counter;
+ u8 m_div_200_50;
+ u8 m_div_134_5;
+ u8 m_div_110;
+ u8 m_div_1800;
+
+ // miscellaneous state
+ bool m_im;
+ u8 m_s;
+ s32 m_icount;
+};
+
+// device type declaration
+DECLARE_DEVICE_TYPE(F4702, f4702_device)
+
+#endif // MAME_MACHINE_F4702_H
+
diff --git a/src/devices/machine/fdc37c665gt.cpp b/src/devices/machine/fdc37c665gt.cpp
index 90f78c77e54..feeec63a201 100644
--- a/src/devices/machine/fdc37c665gt.cpp
+++ b/src/devices/machine/fdc37c665gt.cpp
@@ -1,58 +1,451 @@
// license:BSD-3-Clause
-// copyright-holders:smf
+// copyright-holders: Samuele Zannoli, windyfairy
+/***************************************************************************
+
+FDC37C665GT.h
+
+SMSC FDC37C665GT High Performance Multi-Mode Parallel Port Super I/O Floppy Disk Controllers
+
+***************************************************************************/
+
#include "emu.h"
#include "fdc37c665gt.h"
-fdc37c665gt_device::fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, FDC37C665GT, tag, owner, clock),
- m_uart1(*this, "uart1"),
- m_uart2(*this, "uart2")
+#define LOG_CONFIG (1U << 1) // Show global configuration changes
+
+#define VERBOSE (LOG_GENERAL | LOG_CONFIG)
+// #define LOG_OUTPUT_STREAM std::cout
+
+#include "logmacro.h"
+
+#define LOGCONFIG(...) LOGMASKED(LOG_CONFIG, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(FDC37C665GT, fdc37c665gt_device, "fdc37c665gt", "FDC37C665GT")
+
+fdc37c665gt_device::fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, upd765_family_device::mode_t floppy_mode)
+ : device_t(mconfig, FDC37C665GT, tag, owner, clock)
+ , mode(OperatingMode::Run)
+ , config_key_step(0)
+ , config_index(0)
+ , m_floppy_mode(floppy_mode)
+ , m_fintr_callback(*this)
+ , m_fdrq_callback(*this)
+ , m_pintr1_callback(*this)
+ , m_irq3_callback(*this)
+ , m_irq4_callback(*this)
+ , m_txd1_callback(*this)
+ , m_ndtr1_callback(*this)
+ , m_nrts1_callback(*this)
+ , m_txd2_callback(*this)
+ , m_ndtr2_callback(*this)
+ , m_nrts2_callback(*this)
+ , m_fdc(*this, "fdc")
+ , m_serial(*this, "uart%u", 1)
+ , m_lpt(*this, "lpt")
+{
+}
+
+void fdc37c665gt_device::device_start()
{
+ // Configuration registers and related bits aren't affected by soft resets
+ // Default addresses
+ com_addresses[0] = 0x3f8;
+ com_addresses[1] = 0x2f8;
+ com_addresses[2] = 0x338;
+ com_addresses[3] = 0x238;
+
+ device_addresses[LogicalDevice::IDE] = 0x1f0;
+ device_addresses[LogicalDevice::FDC] = 0x3f0;
+ device_addresses[LogicalDevice::Parallel] = 0x278;
+ device_addresses[LogicalDevice::Serial1] = 0; // COM port
+ device_addresses[LogicalDevice::Serial2] = 1; // COM port
+
+ const uint8_t configuration_registers_defaults[] = {
+ 0x3b, 0x9f, 0xdc, 0x78, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x01, 0x00
+ };
+
+ // Set the value first and then use write_configuration_register because some flags
+ // rely on other flags being initialized properly first
+ std::copy(std::begin(configuration_registers_defaults), std::end(configuration_registers_defaults), std::begin(configuration_registers));
+ for (int i = 0; i < std::size(configuration_registers_defaults); i++) {
+ write_configuration_register(i, configuration_registers_defaults[i]);
+ }
+}
+
+void fdc37c665gt_device::device_add_mconfig(machine_config &config)
+{
+ // floppy disc controller
+ N82077AA(config, m_fdc, 24_MHz_XTAL, m_floppy_mode);
+ m_fdc->intrq_wr_callback().set(FUNC(fdc37c665gt_device::irq_floppy_w));
+
+ // parallel port
+ PC_LPT(config, m_lpt);
+ m_lpt->irq_handler().set(FUNC(fdc37c665gt_device::irq_parallel_w));
+
+ // serial ports
+ NS16550(config, m_serial[0], clock() / 13);
+ m_serial[0]->out_int_callback().set(FUNC(fdc37c665gt_device::irq_serial1_w));
+ m_serial[0]->out_tx_callback().set(FUNC(fdc37c665gt_device::txd_serial1_w));
+ m_serial[0]->out_dtr_callback().set(FUNC(fdc37c665gt_device::dtr_serial1_w));
+ m_serial[0]->out_rts_callback().set(FUNC(fdc37c665gt_device::rts_serial1_w));
+
+ NS16550(config, m_serial[1], clock() / 13);
+ m_serial[1]->out_int_callback().set(FUNC(fdc37c665gt_device::irq_serial2_w));
+ m_serial[1]->out_tx_callback().set(FUNC(fdc37c665gt_device::txd_serial2_w));
+ m_serial[1]->out_dtr_callback().set(FUNC(fdc37c665gt_device::dtr_serial2_w));
+ m_serial[1]->out_rts_callback().set(FUNC(fdc37c665gt_device::rts_serial2_w));
}
uint8_t fdc37c665gt_device::read(offs_t offset)
{
- uint8_t data = 0;
+ // TODO: IDE not implemented
- if ((offset & 0x3f8) == 0x3f8)
- {
- data = m_uart1->ins8250_r(offset & 7);
+ // Parallel port
+ if (offset >= device_addresses[LogicalDevice::Parallel] && offset <= device_addresses[LogicalDevice::Parallel] + 2) {
+ if (!enabled_logical[LogicalDevice::Parallel]) {
+ return 0;
+ }
+
+ return m_lpt->read(offset - device_addresses[LogicalDevice::Parallel]);
}
- else if ((offset & 0x3f8) == 0x2f8)
- {
- data = m_uart2->ins8250_r(offset & 7);
+
+ // Serial 1
+ if (offset >= com_addresses[device_addresses[LogicalDevice::Serial1]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial1]] + 7) {
+ if (!enabled_logical[LogicalDevice::Serial1]) {
+ return 0;
+ }
+
+ return m_serial[0]->ins8250_r(offset - com_addresses[device_addresses[LogicalDevice::Serial1]]);
+ }
+
+ // Serial 2
+ if (offset >= com_addresses[device_addresses[LogicalDevice::Serial2]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial2]] + 7) {
+ if (!enabled_logical[LogicalDevice::Serial2]) {
+ return 0;
+ }
+
+ return m_serial[1]->ins8250_r(offset - com_addresses[device_addresses[LogicalDevice::Serial2]]);
}
- else
- {
- printf("fdc37c665gt_device::read %04x %02x\n", offset, data);
+
+ // FDC, +6 is used by IDE
+ if ((offset >= device_addresses[LogicalDevice::FDC] && offset <= device_addresses[LogicalDevice::FDC] + 5)
+ || offset == device_addresses[LogicalDevice::FDC] + 7) {
+ if (!enabled_logical[LogicalDevice::FDC]) {
+ return 0;
+ }
+
+ switch (offset - device_addresses[LogicalDevice::FDC]) {
+ case 0: return m_fdc->sra_r();
+ case 1: return m_fdc->srb_r();
+ case 2: return m_fdc->dor_r();
+ case 3: return m_fdc->tdr_r();
+ case 4: return m_fdc->msr_r();
+ case 5: return m_fdc->fifo_r();
+ case 7: return m_fdc->dir_r();
+ }
}
- return data;
+
+ return 0;
}
void fdc37c665gt_device::write(offs_t offset, uint8_t data)
{
- if ((offset & 0x3f8) == 0x3f8)
- {
- m_uart1->ins8250_w(offset & 7, data);
+ // TODO: IDE not implemented
+
+ // Parallel port
+ if (offset >= device_addresses[LogicalDevice::Parallel] && offset <= device_addresses[LogicalDevice::Parallel] + 2) {
+ if (!enabled_logical[LogicalDevice::Parallel]) {
+ return;
+ }
+
+ m_lpt->write(offset - device_addresses[LogicalDevice::Parallel], data);
+ return;
}
- else if ((offset & 0x3f8) == 0x2f8)
- {
- m_uart2->ins8250_w(offset & 7, data);
+
+ // Serial 1
+ if (offset >= com_addresses[device_addresses[LogicalDevice::Serial1]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial1]] + 7) {
+ if (!enabled_logical[LogicalDevice::Serial1]) {
+ return;
+ }
+
+ m_serial[0]->ins8250_w(offset - com_addresses[device_addresses[LogicalDevice::Serial1]], data);
+ return;
}
- else
- {
- printf("fdc37c665gt_device::write %04x %02x\n", offset, data);
+
+ // Serial 2
+ if (offset >= com_addresses[device_addresses[LogicalDevice::Serial2]] && offset <= com_addresses[device_addresses[LogicalDevice::Serial2]] + 7) {
+ if (!enabled_logical[LogicalDevice::Serial2]) {
+ return;
+ }
+
+ m_serial[1]->ins8250_w(offset - com_addresses[device_addresses[LogicalDevice::Serial2]], data);
+ return;
+ }
+
+ // FDC, +6 is used by IDE
+ if ((offset >= device_addresses[LogicalDevice::FDC] && offset <= device_addresses[LogicalDevice::FDC] + 5)
+ || offset == device_addresses[LogicalDevice::FDC] + 7) {
+ auto fdc_offset = offset - device_addresses[LogicalDevice::FDC];
+
+ if ((!enabled_logical[LogicalDevice::FDC] && fdc_offset > 1)) {
+ return;
+ }
+
+ switch (fdc_offset) {
+ case 0: // FDC37C665GT Configuration
+ if (mode == OperatingMode::Run) {
+ if (data != 0x55) {
+ config_key_step = 0;
+ return;
+ }
+
+ config_key_step++;
+ if (config_key_step > 1) {
+ config_key_step = 0;
+ mode = OperatingMode::Configuration;
+ }
+ } else {
+ if (data == 0xaa) {
+ mode = OperatingMode::Run;
+ return;
+ }
+
+ config_index = data;
+ }
+ return;
+
+ case 1: // FDC37C665GT Configuration
+ if (mode == OperatingMode::Run) {
+ config_key_step = 0;
+ return;
+ }
+
+ write_configuration_register(config_index, data & 0xff);
+ return;
+
+ case 2: m_fdc->dor_w(data); return;
+ case 3: m_fdc->tdr_w(data); return;
+ case 4: m_fdc->dsr_w(data); return;
+ case 5: m_fdc->fifo_w(data); return;
+ case 7: m_fdc->ccr_w(data); return;
+ }
}
}
-void fdc37c665gt_device::device_start()
+void fdc37c665gt_device::write_configuration_register(int index, int data)
+{
+ if (BIT(configuration_registers[1], 7) == 0) {
+ // Bit 7 of CR1 is LOCK CRx
+ // When this is set to 0, it can only be set back to 1 by a hard reset or power-up reset
+ LOGCONFIG("IGNORED configuration register cr[%02x] = %02x\n", index, data);
+ return;
+ }
+
+ configuration_registers[index] = data;
+ LOGCONFIG("Modified configuration register cr[%02x] = %02x\n", index, data);
+
+ if (index == 0) {
+ enabled_logical[LogicalDevice::IDE] = BIT(configuration_registers[index], 1);
+ enabled_logical[LogicalDevice::FDC] = BIT(configuration_registers[index], 3) && BIT(configuration_registers[index], 4);
+ } else if (index == 1) {
+ enabled_logical[LogicalDevice::Parallel] = BIT(configuration_registers[index], 2) && BIT(configuration_registers[index], 3);
+
+ auto lpt_port = BIT(configuration_registers[index], 0, 2);
+ if (lpt_port == 0) {
+ enabled_logical[LogicalDevice::Parallel] = false; // Disabled
+ } else if (lpt_port == 1) {
+ device_addresses[LogicalDevice::Parallel] = 0x3bc;
+ } else if (lpt_port == 2) {
+ device_addresses[LogicalDevice::Parallel] = 0x378;
+ } else if (lpt_port == 3) {
+ device_addresses[LogicalDevice::Parallel] = 0x278; // Default
+ }
+
+ auto com34 = BIT(configuration_registers[index], 5, 2);
+ if (com34 == 0) {
+ com_addresses[2] = 0x338;
+ com_addresses[3] = 0x238;
+ } else if (com34 == 1) {
+ com_addresses[2] = 0x3e8;
+ com_addresses[3] = 0x2e8;
+ } else if (com34 == 2) {
+ com_addresses[2] = 0x2e8;
+ com_addresses[3] = 0x2e0;
+ } else if (com34 == 3) {
+ com_addresses[2] = 0x220;
+ com_addresses[3] = 0x228;
+ }
+ } else if (index == 2) {
+ enabled_logical[LogicalDevice::Serial1] = BIT(configuration_registers[index], 2) && BIT(configuration_registers[index], 3);
+ device_addresses[LogicalDevice::Serial1] = BIT(configuration_registers[index], 0, 2);
+
+ enabled_logical[LogicalDevice::Serial2] = BIT(configuration_registers[index], 6) && BIT(configuration_registers[index], 7);
+ device_addresses[LogicalDevice::Serial2] = BIT(configuration_registers[index], 4, 2);
+ } else if (index == 3) {
+ auto floppy_mode = BIT(configuration_registers[index], 5, 2);
+
+ // 2 is reserved/unused
+ if (floppy_mode == 3) {
+ m_floppy_mode = upd765_family_device::mode_t::AT;
+ } else if (floppy_mode == 1) {
+ m_floppy_mode = upd765_family_device::mode_t::PS2;
+ } else if (floppy_mode == 0) {
+ m_floppy_mode = upd765_family_device::mode_t::M30;
+ }
+
+ m_fdc->set_mode(m_floppy_mode);
+ } else if (index == 4) {
+ // Set clock speeds for MIDI modes (clock divisor becomes 12 instead of 13)
+ m_serial[0]->set_unscaled_clock(clock() / (13 - BIT(configuration_registers[4], 4)));
+ m_serial[1]->set_unscaled_clock(clock() / (13 - BIT(configuration_registers[5], 5)));
+ } else if (index == 5) {
+ auto fdc_port = BIT(configuration_registers[index], 0);
+ if (fdc_port == 0) {
+ device_addresses[LogicalDevice::FDC] = 0x3f0;
+ } else if (fdc_port == 1) {
+ device_addresses[LogicalDevice::FDC] = 0x370;
+ }
+ }
+}
+
+void fdc37c665gt_device::irq_floppy_w(int state)
{
+ if (!enabled_logical[LogicalDevice::FDC]) {
+ return;
+ }
+
+ m_fintr_callback(state);
}
-void fdc37c665gt_device::device_add_mconfig(machine_config &config)
+void fdc37c665gt_device::irq_parallel_w(int state)
{
- NS16550(config, m_uart1, XTAL(24'000'000)/13);
- NS16550(config, m_uart2, XTAL(24'000'000)/13);
+ if (!enabled_logical[LogicalDevice::Parallel]) {
+ return;
+ }
+
+ m_pintr1_callback(state);
}
-DEFINE_DEVICE_TYPE(FDC37C665GT, fdc37c665gt_device, "fdc37c665gt", "FDC37C665GT")
+void fdc37c665gt_device::irq_serial1_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial1]) {
+ return;
+ }
+
+ m_irq4_callback(state);
+}
+
+void fdc37c665gt_device::txd_serial1_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial1]) {
+ return;
+ }
+
+ m_txd1_callback(state);
+}
+
+void fdc37c665gt_device::dtr_serial1_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial1]) {
+ return;
+ }
+
+ m_ndtr1_callback(state);
+}
+
+void fdc37c665gt_device::rts_serial1_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial1]) {
+ return;
+ }
+
+ m_nrts1_callback(state);
+}
+
+void fdc37c665gt_device::irq_serial2_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial2]) {
+ return;
+ }
+
+ m_irq3_callback(state);
+}
+
+void fdc37c665gt_device::txd_serial2_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial2]) {
+ return;
+ }
+
+ m_txd2_callback(state);
+}
+
+void fdc37c665gt_device::dtr_serial2_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial2]) {
+ return;
+ }
+
+ m_ndtr2_callback(state);
+}
+
+void fdc37c665gt_device::rts_serial2_w(int state)
+{
+ if (!enabled_logical[LogicalDevice::Serial2]) {
+ return;
+ }
+
+ m_nrts2_callback(state);
+}
+
+void fdc37c665gt_device::rxd1_w(int state)
+{
+ m_serial[0]->rx_w(state);
+}
+
+void fdc37c665gt_device::ndcd1_w(int state)
+{
+ m_serial[0]->dcd_w(state);
+}
+
+void fdc37c665gt_device::ndsr1_w(int state)
+{
+ m_serial[0]->dsr_w(state);
+}
+
+void fdc37c665gt_device::nri1_w(int state)
+{
+ m_serial[0]->ri_w(state);
+}
+
+void fdc37c665gt_device::ncts1_w(int state)
+{
+ m_serial[0]->cts_w(state);
+}
+
+void fdc37c665gt_device::rxd2_w(int state)
+{
+ m_serial[1]->rx_w(state);
+}
+
+void fdc37c665gt_device::ndcd2_w(int state)
+{
+ m_serial[1]->dcd_w(state);
+}
+
+void fdc37c665gt_device::ndsr2_w(int state)
+{
+ m_serial[1]->dsr_w(state);
+}
+
+void fdc37c665gt_device::nri2_w(int state)
+{
+ m_serial[1]->ri_w(state);
+}
+
+void fdc37c665gt_device::ncts2_w(int state)
+{
+ m_serial[1]->cts_w(state);
+}
diff --git a/src/devices/machine/fdc37c665gt.h b/src/devices/machine/fdc37c665gt.h
index df733078aae..17e768438c0 100644
--- a/src/devices/machine/fdc37c665gt.h
+++ b/src/devices/machine/fdc37c665gt.h
@@ -1,37 +1,132 @@
// license:BSD-3-Clause
-// copyright-holders:smf
-/*
-* fdc37c665gt.h
-*
-*/
+// copyright-holders: Samuele Zannoli, windyfairy
+/***************************************************************************
+
+FDC37C665GT.h
+
+SMSC FDC37C665GT High Performance Multi-Mode Parallel Port Super I/O Floppy Disk Controllers
+
+***************************************************************************/
#ifndef MAME_MACHINE_FDC37C665GT_H
#define MAME_MACHINE_FDC37C665GT_H
#pragma once
-#include "ins8250.h"
+// floppy disk controller
+#include "machine/upd765.h"
+#include "imagedev/floppy.h"
+// parallel port
+#include "machine/pc_lpt.h"
+// serial port
+#include "machine/ins8250.h"
class fdc37c665gt_device : public device_t
{
public:
- // construction/destruction
- fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : fdc37c665gt_device(mconfig, tag, owner, clock, upd765_family_device::mode_t::AT)
+ { }
+
+ fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, upd765_family_device::mode_t floppy_mode);
+
+ // optional information overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+ // to access io ports
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
+ auto fintr() { return m_fintr_callback.bind(); }
+ auto fdrq() { return m_fdrq_callback.bind(); }
+ auto txd1() { return m_txd1_callback.bind(); }
+ auto ndtr1() { return m_ndtr1_callback.bind(); }
+ auto nrts1() { return m_nrts1_callback.bind(); }
+ auto txd2() { return m_txd2_callback.bind(); }
+ auto ndtr2() { return m_ndtr2_callback.bind(); }
+ auto nrts2() { return m_nrts2_callback.bind(); }
+
+ // chip pins for uarts
+ void rxd1_w(int state);
+ void ndcd1_w(int state);
+ void ndsr1_w(int state);
+ void nri1_w(int state);
+ void ncts1_w(int state);
+ void rxd2_w(int state);
+ void ndcd2_w(int state);
+ void ndsr2_w(int state);
+ void nri2_w(int state);
+ void ncts2_w(int state);
+
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_add_mconfig(machine_config &config) override;
+
+ // for the internal floppy controller
+ void irq_floppy_w(int state);
+
+ // for the internal parallel port
+ void irq_parallel_w(int state);
+
+ // for the internal uarts
+ void irq_serial1_w(int state);
+ void txd_serial1_w(int state);
+ void dtr_serial1_w(int state);
+ void rts_serial1_w(int state);
+ void irq_serial2_w(int state);
+ void txd_serial2_w(int state);
+ void dtr_serial2_w(int state);
+ void rts_serial2_w(int state);
private:
- required_device<ns16550_device> m_uart1;
- required_device<ns16550_device> m_uart2;
+ // put your private members here
+ enum OperatingMode
+ {
+ Run = 0,
+ Configuration = 1
+ } mode;
+
+ enum LogicalDevice
+ {
+ FDC = 0,
+ IDE,
+ Parallel,
+ Serial1,
+ Serial2,
+
+ LogicalDeviceEnd
+ };
+
+ int config_key_step;
+ int config_index;
+ bool enabled_logical[LogicalDevice::LogicalDeviceEnd];
+ int device_addresses[LogicalDevice::LogicalDeviceEnd];
+ int com_addresses[4];
+
+ upd765_family_device::mode_t m_floppy_mode;
+
+ uint8_t configuration_registers[16];
+
+ devcb_write_line m_fintr_callback;
+ devcb_write_line m_fdrq_callback;
+ devcb_write_line m_pintr1_callback; // Parallel
+ devcb_write_line m_irq3_callback; // Serial Port COM1/COM3
+ devcb_write_line m_irq4_callback; // Serial Port COM2/COM4
+
+ devcb_write_line m_txd1_callback;
+ devcb_write_line m_ndtr1_callback;
+ devcb_write_line m_nrts1_callback;
+ devcb_write_line m_txd2_callback;
+ devcb_write_line m_ndtr2_callback;
+ devcb_write_line m_nrts2_callback;
+
+ required_device<n82077aa_device> m_fdc;
+ required_device_array<ns16550_device, 2> m_serial;
+ required_device<pc_lpt_device> m_lpt;
+
+ void write_configuration_register(int index, int data);
};
-// device type definition
-DECLARE_DEVICE_TYPE(FDC37C665GT, fdc37c665gt_device)
+DECLARE_DEVICE_TYPE(FDC37C665GT, fdc37c665gt_device);
#endif // MAME_MACHINE_FDC37C665GT_H
diff --git a/src/devices/machine/fdc37c93x.cpp b/src/devices/machine/fdc37c93x.cpp
index 98811cc8c2d..e613cc59400 100644
--- a/src/devices/machine/fdc37c93x.cpp
+++ b/src/devices/machine/fdc37c93x.cpp
@@ -9,14 +9,16 @@ SMSC FDC37C93x Plug and Play Compatible Ultra I/O Controller
***************************************************************************/
#include "emu.h"
-#include "bus/isa/isa.h"
-#include "machine/ds128x.h"
-#include "machine/fdc37c93x.h"
+#include "fdc37c93x.h"
-DEFINE_DEVICE_TYPE(FDC37C93X, fdc37c93x_device, "fdc37c93x", "SMSC FDC37C93X")
+#include "machine/pckeybrd.h"
-fdc37c93x_device::fdc37c93x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, FDC37C93X, tag, owner, clock)
+#include "formats/naslite_dsk.h"
+
+DEFINE_DEVICE_TYPE(FDC37C93X, fdc37c93x_device, "fdc37c93x", "SMSC FDC37C93X Super I/O")
+
+fdc37c93x_device::fdc37c93x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
, device_isa16_card_interface(mconfig, *this)
, mode(OperatingMode::Run)
, config_key_step(0)
@@ -70,6 +72,13 @@ fdc37c93x_device::fdc37c93x_device(const machine_config &mconfig, const char *ta
dreq_mapping[n] = -1;
}
+fdc37c93x_device::fdc37c93x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : fdc37c93x_device(mconfig, FDC37C93X, tag, owner, clock)
+{
+ m_device_id = 0x02;
+ m_device_rev = 0x01;
+}
+
/*
0 FDC:
60,61 03f0 +(0-7)
@@ -235,10 +244,11 @@ static void pc_hd_floppies(device_slot_interface &device)
device.option_add("35dd", FLOPPY_35_DD);
}
-FLOPPY_FORMATS_MEMBER(fdc37c93x_device::floppy_formats)
- FLOPPY_PC_FORMAT,
- FLOPPY_NASLITE_FORMAT
-FLOPPY_FORMATS_END
+void fdc37c93x_device::floppy_formats(format_registration &fr)
+{
+ fr.add_pc_formats();
+ fr.add(FLOPPY_NASLITE_FORMAT);
+}
void fdc37c93x_device::device_add_mconfig(machine_config &config)
{
@@ -254,13 +264,13 @@ void fdc37c93x_device::device_add_mconfig(machine_config &config)
pc_lpt_lptdev->irq_handler().set(FUNC(fdc37c93x_device::irq_parallel_w));
// serial ports
- NS16450(config, pc_serial1_comdev, XTAL(1'843'200)); // or NS16550 ?
+ NS16550(config, pc_serial1_comdev, XTAL(1'843'200));
pc_serial1_comdev->out_int_callback().set(FUNC(fdc37c93x_device::irq_serial1_w));
pc_serial1_comdev->out_tx_callback().set(FUNC(fdc37c93x_device::txd_serial1_w));
pc_serial1_comdev->out_dtr_callback().set(FUNC(fdc37c93x_device::dtr_serial1_w));
pc_serial1_comdev->out_rts_callback().set(FUNC(fdc37c93x_device::rts_serial1_w));
- NS16450(config, pc_serial2_comdev, XTAL(1'843'200));
+ NS16550(config, pc_serial2_comdev, XTAL(1'843'200));
pc_serial2_comdev->out_int_callback().set(FUNC(fdc37c93x_device::irq_serial2_w));
pc_serial2_comdev->out_tx_callback().set(FUNC(fdc37c93x_device::txd_serial2_w));
pc_serial2_comdev->out_dtr_callback().set(FUNC(fdc37c93x_device::dtr_serial2_w));
@@ -274,160 +284,173 @@ void fdc37c93x_device::device_add_mconfig(machine_config &config)
// keyboard
KBDC8042(config, m_kbdc);
m_kbdc->set_keyboard_type(kbdc8042_device::KBDC8042_PS2);
+ m_kbdc->set_interrupt_type(kbdc8042_device::KBDC8042_DOUBLE);
m_kbdc->input_buffer_full_callback().set(FUNC(fdc37c93x_device::irq_keyboard_w));
+ m_kbdc->input_buffer_full_mouse_callback().set(FUNC(fdc37c93x_device::irq_mouse_w));
m_kbdc->system_reset_callback().set(FUNC(fdc37c93x_device::kbdp20_gp20_reset_w));
m_kbdc->gate_a20_callback().set(FUNC(fdc37c93x_device::kbdp21_gp25_gatea20_w));
+ m_kbdc->set_keyboard_tag("at_keyboard");
+
+ at_keyboard_device &at_keyb(AT_KEYB(config, "at_keyboard", pc_keyboard_device::KEYBOARD_TYPE::AT, 1));
+ at_keyb.keypress().set(m_kbdc, FUNC(kbdc8042_device::keyboard_w));
}
-WRITE_LINE_MEMBER(fdc37c93x_device::irq_floppy_w)
+void fdc37c93x_device::irq_floppy_w(int state)
{
if (enabled_logical[LogicalDevice::FDC] == false)
return;
request_irq(configuration_registers[LogicalDevice::FDC][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::drq_floppy_w)
+void fdc37c93x_device::drq_floppy_w(int state)
{
if (enabled_logical[LogicalDevice::FDC] == false)
return;
request_dma(configuration_registers[LogicalDevice::FDC][0x74], state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::irq_parallel_w)
+void fdc37c93x_device::irq_parallel_w(int state)
{
if (enabled_logical[LogicalDevice::Parallel] == false)
return;
request_irq(configuration_registers[LogicalDevice::Parallel][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::irq_serial1_w)
+void fdc37c93x_device::irq_serial1_w(int state)
{
if (enabled_logical[LogicalDevice::Serial1] == false)
return;
request_irq(configuration_registers[LogicalDevice::Serial1][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::txd_serial1_w)
+void fdc37c93x_device::txd_serial1_w(int state)
{
if (enabled_logical[LogicalDevice::Serial1] == false)
return;
m_txd1_callback(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::dtr_serial1_w)
+void fdc37c93x_device::dtr_serial1_w(int state)
{
if (enabled_logical[LogicalDevice::Serial1] == false)
return;
m_ndtr1_callback(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::rts_serial1_w)
+void fdc37c93x_device::rts_serial1_w(int state)
{
if (enabled_logical[LogicalDevice::Serial1] == false)
return;
m_nrts1_callback(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::irq_serial2_w)
+void fdc37c93x_device::irq_serial2_w(int state)
{
if (enabled_logical[LogicalDevice::Serial2] == false)
return;
request_irq(configuration_registers[LogicalDevice::Serial2][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::txd_serial2_w)
+void fdc37c93x_device::txd_serial2_w(int state)
{
if (enabled_logical[LogicalDevice::Serial2] == false)
return;
m_txd2_callback(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::dtr_serial2_w)
+void fdc37c93x_device::dtr_serial2_w(int state)
{
if (enabled_logical[LogicalDevice::Serial2] == false)
return;
m_ndtr2_callback(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::rts_serial2_w)
+void fdc37c93x_device::rts_serial2_w(int state)
{
if (enabled_logical[LogicalDevice::Serial2] == false)
return;
m_nrts2_callback(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::rxd1_w)
+void fdc37c93x_device::rxd1_w(int state)
{
pc_serial1_comdev->rx_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::ndcd1_w)
+void fdc37c93x_device::ndcd1_w(int state)
{
pc_serial1_comdev->dcd_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::ndsr1_w)
+void fdc37c93x_device::ndsr1_w(int state)
{
pc_serial1_comdev->dsr_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::nri1_w)
+void fdc37c93x_device::nri1_w(int state)
{
pc_serial1_comdev->ri_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::ncts1_w)
+void fdc37c93x_device::ncts1_w(int state)
{
pc_serial1_comdev->cts_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::rxd2_w)
+void fdc37c93x_device::rxd2_w(int state)
{
pc_serial2_comdev->rx_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::ndcd2_w)
+void fdc37c93x_device::ndcd2_w(int state)
{
pc_serial2_comdev->dcd_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::ndsr2_w)
+void fdc37c93x_device::ndsr2_w(int state)
{
pc_serial2_comdev->dsr_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::nri2_w)
+void fdc37c93x_device::nri2_w(int state)
{
pc_serial2_comdev->ri_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::ncts2_w)
+void fdc37c93x_device::ncts2_w(int state)
{
pc_serial2_comdev->cts_w(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::irq_rtc_w)
+void fdc37c93x_device::irq_rtc_w(int state)
{
if (enabled_logical[LogicalDevice::RTC] == false)
return;
request_irq(configuration_registers[LogicalDevice::RTC][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::irq_keyboard_w)
+void fdc37c93x_device::irq_keyboard_w(int state)
{
if (enabled_logical[LogicalDevice::Keyboard] == false)
return;
request_irq(configuration_registers[LogicalDevice::Keyboard][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::kbdp21_gp25_gatea20_w)
+void fdc37c93x_device::irq_mouse_w(int state)
+{
+ if (enabled_logical[LogicalDevice::Keyboard] == false)
+ return;
+ request_irq(configuration_registers[LogicalDevice::Keyboard][0x72], state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void fdc37c93x_device::kbdp21_gp25_gatea20_w(int state)
{
if (enabled_logical[LogicalDevice::Keyboard] == false)
return;
m_gp25_gatea20_callback(state);
}
-WRITE_LINE_MEMBER(fdc37c93x_device::kbdp20_gp20_reset_w)
+void fdc37c93x_device::kbdp20_gp20_reset_w(int state)
{
if (enabled_logical[LogicalDevice::Keyboard] == false)
return;
@@ -499,7 +522,6 @@ void fdc37c93x_device::write(offs_t offset, uint8_t data)
/* Map/unmap internal devices */
-#if 1
uint8_t fdc37c93x_device::disabled_read()
{
return 0xff;
@@ -511,26 +533,14 @@ void fdc37c93x_device::disabled_write(uint8_t data)
void fdc37c93x_device::unmap_fdc(address_map &map)
{
- map(0x0, 0x0).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
- map(0x1, 0x1).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
+ //map(0x0, 0x0).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
+ //map(0x1, 0x1).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
map(0x2, 0x2).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
map(0x3, 0x3).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
map(0x4, 0x4).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
map(0x5, 0x5).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
map(0x7, 0x7).rw(FUNC(fdc37c93x_device::disabled_read), FUNC(fdc37c93x_device::disabled_write));
}
-#else
-void fdc37c93x_device::unmap_fdc(address_map &map)
-{
- map(0x0, 0x0).noprw();
- map(0x1, 0x1).noprw();
- map(0x2, 0x2).noprw();
- map(0x3, 0x3).noprw();
- map(0x4, 0x4).noprw();
- map(0x5, 0x5).noprw();
- map(0x7, 0x7).noprw();
-}
-#endif
void fdc37c93x_device::map_fdc_addresses()
{
@@ -605,7 +615,8 @@ void fdc37c93x_device::unmap_serial2_addresses()
void fdc37c93x_device::map_rtc(address_map &map)
{
- map(0x0, 0xf).rw(ds12885_rtcdev, FUNC(ds12885_device::read), FUNC(ds12885_device::write));
+ map(0x0, 0xf).lr8(NAME([this]() { return ds12885_rtcdev->get_address(); })).w(ds12885_rtcdev, FUNC(ds12885_device::address_w)).umask32(0x00ff00ff); // datasheet implies address might be a R/W register
+ map(0x0, 0xf).rw(ds12885_rtcdev, FUNC(ds12885_device::data_r), FUNC(ds12885_device::data_w)).umask32(0xff00ff00);
}
void fdc37c93x_device::map_rtc_addresses()
@@ -772,6 +783,8 @@ void fdc37c93x_device::write_fdd_configuration_register(int index, int data)
}
if (index == 0x74)
update_dreq_mapping(configuration_registers[LogicalDevice::FDC][0x74], LogicalDevice::FDC);
+ if (index == 0xF0)
+ logerror("FDD Mode Register changed: Floppy Mode %d FDC DMA Mode %d Interface Mode %d Swap Drives %d\n", (data >> 0) & 1, (data >> 1) & 1, (data >> 2) & 3, (data >> 4) & 1);
}
void fdc37c93x_device::write_parallel_configuration_register(int index, int data)
@@ -902,10 +915,10 @@ uint16_t fdc37c93x_device::read_global_configuration_register(int index)
ret = logical_device;
break;
case 0x20:
- ret = 2;
+ ret = m_device_id;
break;
case 0x21:
- ret = 1;
+ ret = m_device_rev;
break;
}
logerror("Read global configuration register %02X = %02X\n", index, ret);
@@ -975,19 +988,19 @@ void fdc37c93x_device::device_start()
m_isa->set_dma_channel(2, this, true);
m_isa->set_dma_channel(3, this, true);
remap(AS_IO, 0, 0x400);
- m_gp20_reset_callback.resolve_safe();
- m_gp25_gatea20_callback.resolve_safe();
- m_irq1_callback.resolve_safe();
- m_irq8_callback.resolve_safe();
- m_irq9_callback.resolve_safe();
- m_txd1_callback.resolve_safe();
- m_ndtr1_callback.resolve_safe();
- m_nrts1_callback.resolve_safe();
- m_txd2_callback.resolve_safe();
- m_ndtr2_callback.resolve_safe();
- m_nrts2_callback.resolve_safe();
}
void fdc37c93x_device::device_reset()
{
}
+
+// 'M707 is mostly same except no IDE ports and extra power management regs
+DEFINE_DEVICE_TYPE(FDC37M707, fdc37m707_device, "fdc37m707", "SMSC FDC37M707 Super I/O")
+
+
+fdc37m707_device::fdc37m707_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : fdc37c93x_device(mconfig, FDC37M707, tag, owner, clock)
+{
+ m_device_id = 0x42;
+ m_device_rev = 0x01;
+}
diff --git a/src/devices/machine/fdc37c93x.h b/src/devices/machine/fdc37c93x.h
index ae5a9619b78..7ec1922498f 100644
--- a/src/devices/machine/fdc37c93x.h
+++ b/src/devices/machine/fdc37c93x.h
@@ -7,24 +7,19 @@ fdc37c93x.h
SMSC FDC37C93x Plug and Play Compatible Ultra I/O Controller
***************************************************************************/
-
#ifndef MAME_MACHINE_FDC37C93X_H
#define MAME_MACHINE_FDC37C93X_H
#pragma once
-#include "machine/8042kbdc.h"
-// floppy disk controller
-#include "machine/upd765.h"
+#include "bus/isa/isa.h"
#include "imagedev/floppy.h"
-#include "formats/pc_dsk.h"
-#include "formats/naslite_dsk.h"
-// parallel port
-#include "machine/pc_lpt.h"
-// serial port
+#include "machine/8042kbdc.h"
+#include "machine/ds128x.h"
#include "machine/ins8250.h"
+#include "machine/pc_lpt.h"
+#include "machine/upd765.h"
-// make sure that pckeybrd.cpp 8042kbdc.cpp are present in project
class fdc37c93x_device : public device_t, public device_isa16_card_interface
{
@@ -51,36 +46,37 @@ public:
void remap(int space_id, offs_t start, offs_t end) override;
// for the internal floppy controller
- DECLARE_WRITE_LINE_MEMBER(irq_floppy_w);
- DECLARE_WRITE_LINE_MEMBER(drq_floppy_w);
+ void irq_floppy_w(int state);
+ void drq_floppy_w(int state);
// for the internal parallel port
- DECLARE_WRITE_LINE_MEMBER(irq_parallel_w);
+ void irq_parallel_w(int state);
// for the internal uarts
- DECLARE_WRITE_LINE_MEMBER(irq_serial1_w);
- DECLARE_WRITE_LINE_MEMBER(txd_serial1_w);
- DECLARE_WRITE_LINE_MEMBER(dtr_serial1_w);
- DECLARE_WRITE_LINE_MEMBER(rts_serial1_w);
- DECLARE_WRITE_LINE_MEMBER(irq_serial2_w);
- DECLARE_WRITE_LINE_MEMBER(txd_serial2_w);
- DECLARE_WRITE_LINE_MEMBER(dtr_serial2_w);
- DECLARE_WRITE_LINE_MEMBER(rts_serial2_w);
+ void irq_serial1_w(int state);
+ void txd_serial1_w(int state);
+ void dtr_serial1_w(int state);
+ void rts_serial1_w(int state);
+ void irq_serial2_w(int state);
+ void txd_serial2_w(int state);
+ void dtr_serial2_w(int state);
+ void rts_serial2_w(int state);
// chip pins for uarts
- DECLARE_WRITE_LINE_MEMBER(rxd1_w);
- DECLARE_WRITE_LINE_MEMBER(ndcd1_w);
- DECLARE_WRITE_LINE_MEMBER(ndsr1_w);
- DECLARE_WRITE_LINE_MEMBER(nri1_w);
- DECLARE_WRITE_LINE_MEMBER(ncts1_w);
- DECLARE_WRITE_LINE_MEMBER(rxd2_w);
- DECLARE_WRITE_LINE_MEMBER(ndcd2_w);
- DECLARE_WRITE_LINE_MEMBER(ndsr2_w);
- DECLARE_WRITE_LINE_MEMBER(nri2_w);
- DECLARE_WRITE_LINE_MEMBER(ncts2_w);
+ void rxd1_w(int state);
+ void ndcd1_w(int state);
+ void ndsr1_w(int state);
+ void nri1_w(int state);
+ void ncts1_w(int state);
+ void rxd2_w(int state);
+ void ndcd2_w(int state);
+ void ndsr2_w(int state);
+ void nri2_w(int state);
+ void ncts2_w(int state);
// rtc
- DECLARE_WRITE_LINE_MEMBER(irq_rtc_w);
+ void irq_rtc_w(int state);
// keyboard
- DECLARE_WRITE_LINE_MEMBER(irq_keyboard_w);
- DECLARE_WRITE_LINE_MEMBER(kbdp21_gp25_gatea20_w);
- DECLARE_WRITE_LINE_MEMBER(kbdp20_gp20_reset_w);
+ void irq_keyboard_w(int state);
+ void irq_mouse_w(int state);
+ void kbdp21_gp25_gatea20_w(int state);
+ void kbdp20_gp20_reset_w(int state);
void unmap_fdc(address_map &map);
void map_lpt(address_map &map);
@@ -100,9 +96,11 @@ public:
uint8_t keybc_status_r();
void keybc_command_w(uint8_t data);
- DECLARE_FLOPPY_FORMATS(floppy_formats);
+ static void floppy_formats(format_registration &fr);
protected:
+ fdc37c93x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
@@ -111,6 +109,9 @@ protected:
virtual void dack_w(int line, uint8_t data) override;
virtual void eop_w(int state) override;
+ u8 m_device_id = 0;
+ u8 m_device_rev = 0;
+
private:
// put your private members here
enum OperatingMode
@@ -149,8 +150,8 @@ private:
devcb_write_line m_nrts2_callback;
required_device<smc37c78_device> floppy_controller_fdcdev;
required_device<pc_lpt_device> pc_lpt_lptdev;
- required_device<ns16450_device> pc_serial1_comdev;
- required_device<ns16450_device> pc_serial2_comdev;
+ required_device<ns16550_device> pc_serial1_comdev;
+ required_device<ns16550_device> pc_serial2_comdev;
required_device<ds12885_device> ds12885_rtcdev;
required_device<kbdc8042_device> m_kbdc;
int sysopt_pin;
@@ -185,17 +186,26 @@ private:
void write_auxio_configuration_register(int index, int data);
uint16_t read_global_configuration_register(int index);
uint16_t read_logical_configuration_register(int index);
- uint16_t read_fdd_configuration_register(int index) { return 0; }
- uint16_t read_ide1_configuration_register(int index) { return 0; }
- uint16_t read_ide2_configuration_register(int index) { return 0; }
- uint16_t read_parallel_configuration_register(int index) { return 0; }
- uint16_t read_serial1_configuration_register(int index) { return 0; }
- uint16_t read_serial2_configuration_register(int index) { return 0; }
+ uint16_t read_fdd_configuration_register(int index) { return configuration_registers[logical_device][index]; }
+ uint16_t read_ide1_configuration_register(int index) { return configuration_registers[logical_device][index]; }
+ uint16_t read_ide2_configuration_register(int index) { return configuration_registers[logical_device][index]; }
+ uint16_t read_parallel_configuration_register(int index) { return configuration_registers[logical_device][index]; }
+ uint16_t read_serial1_configuration_register(int index) { return configuration_registers[logical_device][index]; }
+ uint16_t read_serial2_configuration_register(int index) { return configuration_registers[logical_device][index]; }
uint16_t read_rtc_configuration_register(int index);
uint16_t read_keyboard_configuration_register(int index);
uint16_t read_auxio_configuration_register(int index);
};
+class fdc37m707_device : public fdc37c93x_device
+{
+public:
+ fdc37m707_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~fdc37m707_device() {}
+};
+
DECLARE_DEVICE_TYPE(FDC37C93X, fdc37c93x_device);
+DECLARE_DEVICE_TYPE(FDC37M707, fdc37m707_device);
+
#endif // MAME_MACHINE_FDC37C93X_H
diff --git a/src/devices/machine/fdc_pll.cpp b/src/devices/machine/fdc_pll.cpp
index 2e8694d2f01..b753a49fc0d 100644
--- a/src/devices/machine/fdc_pll.cpp
+++ b/src/devices/machine/fdc_pll.cpp
@@ -4,17 +4,6 @@
#include "fdc_pll.h"
#include "imagedev/floppy.h"
-std::string fdc_pll_t::tts(attotime t)
-{
- char buf[256];
- bool neg = t.seconds() < 0;
- if(neg)
- t = attotime::zero - t;
- int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- sprintf(buf, "%c%3d.%03d,%03d,%03d", neg ? '-' : ' ', int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
- return buf;
-}
-
void fdc_pll_t::set_clock(const attotime &_period)
{
period = _period;
@@ -74,7 +63,7 @@ int fdc_pll_t::feed_read_data(attotime &tm, const attotime& edge, const attotime
#if 0
if(!edge.is_never())
- fprintf(stderr, "ctime=%s, transition_time=%s, next=%s, pha=%s\n", tts(ctime).c_str(), tts(edge).c_str(), tts(next).c_str(), tts(phase_adjust).c_str());
+ fprintf(stderr, "%s\n", util::string_format("fdc pll ctime=%s, transition_time=%s, next=%s, pha=%s\n", ctime.to_string(), edge.to_string(), next.to_string(), phase_adjust.to_string()).c_str());
#endif
if(next > limit)
@@ -138,7 +127,7 @@ bool fdc_pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *flop
if(etime > limit)
return true;
- if(bit && write_position < ARRAY_LENGTH(write_buffer))
+ if(bit && write_position < std::size(write_buffer))
write_buffer[write_position++] = ctime + period/2;
tm = etime;
diff --git a/src/devices/machine/fdc_pll.h b/src/devices/machine/fdc_pll.h
index fb2bb35fe60..c048f5d2618 100644
--- a/src/devices/machine/fdc_pll.h
+++ b/src/devices/machine/fdc_pll.h
@@ -17,8 +17,8 @@ public:
attotime write_start_time;
attotime write_buffer[32];
- int write_position;
- int freq_hist;
+ int write_position = 0;
+ int freq_hist = 0;
void set_clock(const attotime &period);
void reset(const attotime &when);
@@ -29,8 +29,6 @@ public:
void start_writing(const attotime &tm);
void commit(floppy_image_device *floppy, const attotime &tm);
void stop_writing(floppy_image_device *floppy, const attotime &tm);
-
- std::string tts(attotime tm);
};
#endif // MAME_MACHINE_FDC_PLL_H
diff --git a/src/devices/machine/fga002.cpp b/src/devices/machine/fga002.cpp
index 59a40777aa9..f9683b4f152 100644
--- a/src/devices/machine/fga002.cpp
+++ b/src/devices/machine/fga002.cpp
@@ -34,13 +34,12 @@
#include "emu.h"
#include "fga002.h"
-//#define LOG_GENERAL (1U << 0)
-#define LOG_SETUP (1U << 1)
-#define LOG_READ (1U << 2)
-#define LOG_INT (1U << 3)
-#define LOG_VEC (1U << 4)
-#define LOG_LVL (1U << 5)
-#define LOG_IACK (1U << 6)
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_INT (1U << 3)
+#define LOG_VEC (1U << 4)
+#define LOG_LVL (1U << 5)
+#define LOG_IACK (1U << 6)
//#define VERBOSE (LOG_GENERAL | LOG_SETUP)
//#define LOG_OUTPUT_FUNC printf
@@ -77,10 +76,10 @@ DEFINE_DEVICE_TYPE(FGA002, fga002_device, "fga002", "Force FGA-002")
fga002_device::fga002_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, m_out_int_cb(*this)
- , m_liack4_cb(*this)
- , m_liack5_cb(*this)
- , m_liack6_cb(*this)
- , m_liack7_cb(*this)
+ , m_liack4_cb(*this, 0)
+ , m_liack5_cb(*this, 0)
+ , m_liack6_cb(*this, 0)
+ , m_liack7_cb(*this, 0)
, m_irq_level(uint8_t(0))
{
for (auto & elem : m_int_state)
@@ -96,15 +95,8 @@ void fga002_device::device_start()
{
LOG("%s\n", FUNCNAME);
- // resolve callbacks
- m_out_int_cb.resolve_safe();
- m_liack4_cb.resolve_safe(0);
- m_liack5_cb.resolve_safe(0);
- m_liack6_cb.resolve_safe(0);
- m_liack7_cb.resolve_safe(0);
-
// Timers
- fga_timer = timer_alloc(TIMER_ID_FGA);
+ fga_timer = timer_alloc(FUNC(fga002_device::timer_tick), this);
save_pointer (NAME (m_fga002), sizeof(m_fga002));
@@ -143,31 +135,24 @@ void fga002_device::device_reset()
}
//-------------------------------------------------
-// device_timer - handler timer events
+// timer_tick - decrement timer 0
//-------------------------------------------------
-void fga002_device::device_timer (emu_timer &timer, device_timer_id id, int32_t param, void *ptr)
+
+TIMER_CALLBACK_MEMBER(fga002_device::timer_tick)
{
- switch(id)
+ if (m_tim0count-- == 0) // Zero detect
{
- case TIMER_ID_FGA:
- if (m_tim0count-- == 0) // Zero detect
+ if ((m_fga002[FGA_TIM0CTL] & REG_TIM0CTL_ZERO_STOP) == 0)
{
- if ((m_fga002[FGA_TIM0CTL] & REG_TIM0CTL_ZERO_STOP) == 0)
- {
- fga_timer->adjust(attotime::never, TIMER_ID_FGA, attotime::never);
- }
+ fga_timer->adjust(attotime::never);
+ }
+ else
+ {
+ if ((m_fga002[FGA_TIM0CTL] & REG_TIM0CTL_AUTOPRELOAD) == 0)
+ m_tim0count &= 0xff;
else
- {
- if ((m_fga002[FGA_TIM0CTL] & REG_TIM0CTL_AUTOPRELOAD) == 0)
- m_tim0count &= 0xff;
- else
- m_tim0count = m_fga002[FGA_TIM0PRELOAD];
- }
+ m_tim0count = m_fga002[FGA_TIM0PRELOAD];
}
- break;
- default:
- LOG("Unhandled Timer ID %d\n", id);
- break;
}
}
@@ -408,27 +393,27 @@ void fga002_device::do_fga002reg_tim0ctl_w(uint8_t data)
if ((data & REG_TIM0CTL_START_STOP) != (m_fga002[FGA_TIM0CTL] & REG_TIM0CTL_START_STOP))
{
if ((data & REG_TIM0CTL_START_STOP) == 0)
- fga_timer->adjust(attotime::never, TIMER_ID_FGA, attotime::never);
+ fga_timer->adjust(attotime::never);
else
{
switch (data & REG_TIM0CTL_CLK_MSK)
{
- case REG_TIM0CTL_CLK_1_MIC: fga_timer->adjust(attotime::from_usec(1), TIMER_ID_FGA, attotime::from_usec(1)); break;
- case REG_TIM0CTL_CLK_2_MIC: fga_timer->adjust(attotime::from_usec(2), TIMER_ID_FGA, attotime::from_usec(2)); break;
- case REG_TIM0CTL_CLK_4_MIC: fga_timer->adjust(attotime::from_usec(4), TIMER_ID_FGA, attotime::from_usec(4)); break;
- case REG_TIM0CTL_CLK_8_MIC: fga_timer->adjust(attotime::from_usec(8), TIMER_ID_FGA, attotime::from_usec(8)); break;
- case REG_TIM0CTL_CLK_16_MIC: fga_timer->adjust(attotime::from_usec(16), TIMER_ID_FGA, attotime::from_usec(16)); break;
- case REG_TIM0CTL_CLK_32_MIC: fga_timer->adjust(attotime::from_usec(32), TIMER_ID_FGA, attotime::from_usec(32)); break;
- case REG_TIM0CTL_CLK_64_MIC: fga_timer->adjust(attotime::from_usec(64), TIMER_ID_FGA, attotime::from_usec(64)); break;
- case REG_TIM0CTL_CLK_128_MIC: fga_timer->adjust(attotime::from_usec(128), TIMER_ID_FGA, attotime::from_usec(128)); break;
- case REG_TIM0CTL_CLK_256_MIC: fga_timer->adjust(attotime::from_usec(256), TIMER_ID_FGA, attotime::from_usec(256)); break;
- case REG_TIM0CTL_CLK_512_MIC: fga_timer->adjust(attotime::from_usec(512), TIMER_ID_FGA, attotime::from_usec(512)); break;
- case REG_TIM0CTL_CLK_2_MIL: fga_timer->adjust(attotime::from_msec(2), TIMER_ID_FGA, attotime::from_msec(2)); break;
- case REG_TIM0CTL_CLK_8_MIL: fga_timer->adjust(attotime::from_msec(8), TIMER_ID_FGA, attotime::from_msec(8)); break;
- case REG_TIM0CTL_CLK_32_MIL: fga_timer->adjust(attotime::from_msec(32), TIMER_ID_FGA, attotime::from_msec(32)); break;
- case REG_TIM0CTL_CLK_125_MIL: fga_timer->adjust(attotime::from_msec(125), TIMER_ID_FGA, attotime::from_msec(125)); break;
- case REG_TIM0CTL_CLK_500_MIL: fga_timer->adjust(attotime::from_msec(500), TIMER_ID_FGA, attotime::from_msec(500)); break;
- case REG_TIM0CTL_CLK_2_SEC: fga_timer->adjust(attotime::from_seconds(2), TIMER_ID_FGA, attotime::from_seconds(2)); break;
+ case REG_TIM0CTL_CLK_1_MIC: fga_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); break;
+ case REG_TIM0CTL_CLK_2_MIC: fga_timer->adjust(attotime::from_usec(2), 0, attotime::from_usec(2)); break;
+ case REG_TIM0CTL_CLK_4_MIC: fga_timer->adjust(attotime::from_usec(4), 0, attotime::from_usec(4)); break;
+ case REG_TIM0CTL_CLK_8_MIC: fga_timer->adjust(attotime::from_usec(8), 0, attotime::from_usec(8)); break;
+ case REG_TIM0CTL_CLK_16_MIC: fga_timer->adjust(attotime::from_usec(16), 0, attotime::from_usec(16)); break;
+ case REG_TIM0CTL_CLK_32_MIC: fga_timer->adjust(attotime::from_usec(32), 0, attotime::from_usec(32)); break;
+ case REG_TIM0CTL_CLK_64_MIC: fga_timer->adjust(attotime::from_usec(64), 0, attotime::from_usec(64)); break;
+ case REG_TIM0CTL_CLK_128_MIC: fga_timer->adjust(attotime::from_usec(128), 0, attotime::from_usec(128)); break;
+ case REG_TIM0CTL_CLK_256_MIC: fga_timer->adjust(attotime::from_usec(256), 0, attotime::from_usec(256)); break;
+ case REG_TIM0CTL_CLK_512_MIC: fga_timer->adjust(attotime::from_usec(512), 0, attotime::from_usec(512)); break;
+ case REG_TIM0CTL_CLK_2_MIL: fga_timer->adjust(attotime::from_msec(2), 0, attotime::from_msec(2)); break;
+ case REG_TIM0CTL_CLK_8_MIL: fga_timer->adjust(attotime::from_msec(8), 0, attotime::from_msec(8)); break;
+ case REG_TIM0CTL_CLK_32_MIL: fga_timer->adjust(attotime::from_msec(32), 0, attotime::from_msec(32)); break;
+ case REG_TIM0CTL_CLK_125_MIL: fga_timer->adjust(attotime::from_msec(125), 0, attotime::from_msec(125)); break;
+ case REG_TIM0CTL_CLK_500_MIL: fga_timer->adjust(attotime::from_msec(500), 0, attotime::from_msec(500)); break;
+ case REG_TIM0CTL_CLK_2_SEC: fga_timer->adjust(attotime::from_seconds(2), 0, attotime::from_seconds(2)); break;
default: logerror("REG_TIM0CTL programmer error, please report\n"); break; // Should never happen
}
}
@@ -599,14 +584,14 @@ void fga002_device::lirq_w(int status, int vector, int control, int state)
}
}
-WRITE_LINE_MEMBER (fga002_device::lirq0_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL0, INT_LOCAL0, FGA_ICRLOCAL0, state ); }
-WRITE_LINE_MEMBER (fga002_device::lirq1_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL1, INT_LOCAL1, FGA_ICRLOCAL1, state ); }
-WRITE_LINE_MEMBER (fga002_device::lirq2_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL2, INT_LOCAL2, FGA_ICRLOCAL2, state ); }
-WRITE_LINE_MEMBER (fga002_device::lirq3_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL3, INT_LOCAL3, FGA_ICRLOCAL3, state ); }
-WRITE_LINE_MEMBER (fga002_device::lirq4_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL4, INT_LOCAL4, FGA_ICRLOCAL4, state ); }
-WRITE_LINE_MEMBER (fga002_device::lirq5_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL5, INT_LOCAL5, FGA_ICRLOCAL5, state ); }
-WRITE_LINE_MEMBER (fga002_device::lirq6_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL6, INT_LOCAL6, FGA_ICRLOCAL6, state ); }
-WRITE_LINE_MEMBER (fga002_device::lirq7_w) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL7, INT_LOCAL7, FGA_ICRLOCAL7, state ); }
+void fga002_device::lirq0_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL0, INT_LOCAL0, FGA_ICRLOCAL0, state ); }
+void fga002_device::lirq1_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL1, INT_LOCAL1, FGA_ICRLOCAL1, state ); }
+void fga002_device::lirq2_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL2, INT_LOCAL2, FGA_ICRLOCAL2, state ); }
+void fga002_device::lirq3_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL3, INT_LOCAL3, FGA_ICRLOCAL3, state ); }
+void fga002_device::lirq4_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL4, INT_LOCAL4, FGA_ICRLOCAL4, state ); }
+void fga002_device::lirq5_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL5, INT_LOCAL5, FGA_ICRLOCAL5, state ); }
+void fga002_device::lirq6_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL6, INT_LOCAL6, FGA_ICRLOCAL6, state ); }
+void fga002_device::lirq7_w(int state) { LOGINT("%s\n", FUNCNAME); lirq_w( FGA_ISLOCAL7, INT_LOCAL7, FGA_ICRLOCAL7, state ); }
void fga002_device::write(offs_t offset, uint8_t data){
LOG("%s[%04x] <- %02x - ", FUNCNAME, offset, data);
diff --git a/src/devices/machine/fga002.h b/src/devices/machine/fga002.h
index be72206eb76..f28a82f16e5 100644
--- a/src/devices/machine/fga002.h
+++ b/src/devices/machine/fga002.h
@@ -16,14 +16,14 @@ class fga002_device : public device_t
uint8_t read(offs_t offset);
void lirq_w(int status, int vector, int control, int state);
- DECLARE_WRITE_LINE_MEMBER( lirq0_w );
- DECLARE_WRITE_LINE_MEMBER( lirq1_w );
- DECLARE_WRITE_LINE_MEMBER( lirq2_w );
- DECLARE_WRITE_LINE_MEMBER( lirq3_w );
- DECLARE_WRITE_LINE_MEMBER( lirq4_w );
- DECLARE_WRITE_LINE_MEMBER( lirq5_w );
- DECLARE_WRITE_LINE_MEMBER( lirq6_w );
- DECLARE_WRITE_LINE_MEMBER( lirq7_w );
+ void lirq0_w(int state);
+ void lirq1_w(int state);
+ void lirq2_w(int state);
+ void lirq3_w(int state);
+ void lirq4_w(int state);
+ void lirq5_w(int state);
+ void lirq6_w(int state);
+ void lirq7_w(int state);
u16 iack();
int acknowledge();
@@ -57,7 +57,8 @@ class fga002_device : public device_t
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
#endif
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(timer_tick);
devcb_write_line m_out_int_cb;
devcb_read8 m_liack4_cb;
@@ -86,10 +87,7 @@ class fga002_device : public device_t
uint8_t do_fga002reg_istim0_r();
void do_fga002reg_istim0_w(uint8_t data);
emu_timer *fga_timer;
- enum
- {
- TIMER_ID_FGA
- };
+
enum {
REG_TIM0CTL_ZERO_STOP = 0x80,
REG_TIM0CTL_AUTOPRELOAD = 0x40,
diff --git a/src/devices/machine/fm_scsi.cpp b/src/devices/machine/fm_scsi.cpp
new file mode 100644
index 00000000000..4747f8ab856
--- /dev/null
+++ b/src/devices/machine/fm_scsi.cpp
@@ -0,0 +1,436 @@
+// license:BSD-3-Clause
+// copyright-holders:Barry Rodewald
+/*
+ *
+ * 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 "debugger.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
+
+/*
+ * Device config
+ */
+
+DEFINE_DEVICE_TYPE(FMSCSI, fmscsi_device, "fmscsi", "FM-SCSI")
+
+/*
+ * Device
+ */
+
+fmscsi_device::fmscsi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : legacy_scsi_host_adapter(mconfig, FMSCSI, tag, owner, clock),
+ m_irq_handler(*this),
+ m_drq_handler(*this)
+{
+}
+
+void fmscsi_device::device_start()
+{
+ 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;
+
+ // allocate read timer
+ m_transfer_timer = timer_alloc(FUNC(fmscsi_device::update_transfer), this);
+ m_phase_timer = timer_alloc(FUNC(fmscsi_device::set_phase), this);
+}
+
+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;
+ stop_transfer();
+ set_input_line(FMSCSI_LINE_INT,0);
+ m_irq_handler(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_t 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\n", group);
+
+ // never executed
+ //return 6;
+}
+
+TIMER_CALLBACK_MEMBER(fmscsi_device::update_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_handler(1);
+ }
+}
+
+void fmscsi_device::stop_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_handler(0);
+ }
+ logerror("FMSCSI: Stopping transfer : (%i/%i)\n",m_result_index,m_result_length);
+}
+
+uint8_t 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)
+ read_data(m_buffer,512); // read next sector
+
+ if(m_result_index >= m_result_length)
+ {
+ // end of data transfer
+ stop_transfer();
+ }
+ 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 = get_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_t 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)
+ write_data(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_handler(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
+ send_command(m_command,m_command_index);
+ m_result_length = get_length();
+ phase = legacy_scsi_host_adapter::get_phase();
+ 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);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(fmscsi_device::set_phase)
+{
+ m_phase = param;
+ logerror("FMSCSI: phase set to %i\n",m_phase);
+ // set input lines accordingly
+ switch(param)
+ {
+ 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
+ read_data(m_buffer,512);
+ m_result_index = 0;
+ logerror("FMSCSI: Starting transfer in (%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 out (%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_t line, uint8_t 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_handler(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_handler(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_t fmscsi_device::get_input_line(uint8_t line)
+{
+ return m_input_lines & line;
+}
+
+void fmscsi_device::set_output_line(uint8_t line, uint8_t 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
+ {
+ if (select(m_target))
+ {
+ 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_t fmscsi_device::get_output_line(uint8_t line)
+{
+ return m_output_lines & line;
+}
+
+uint8_t fmscsi_device::fmscsi_status_r(void)
+{
+ // status inputs
+ return m_input_lines;
+}
+
+void fmscsi_device::fmscsi_control_w(uint8_t 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);
+}
+
+uint8_t fmscsi_device::fmscsi_r(offs_t offset)
+{
+ 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;
+}
+
+void fmscsi_device::fmscsi_w(offs_t offset, uint8_t data)
+{
+ 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/devices/machine/fm_scsi.h b/src/devices/machine/fm_scsi.h
new file mode 100644
index 00000000000..9a3df8c0ba6
--- /dev/null
+++ b/src/devices/machine/fm_scsi.h
@@ -0,0 +1,73 @@
+// license:BSD-3-Clause
+// copyright-holders:Barry Rodewald
+/*
+ * fm_scsi.h
+ *
+ * SCSI controller used in Fujitsu FMR-50, FMR-60, and FM-Towns
+ *
+ */
+
+#ifndef MAME_MACHINE_FM_SCSI_H
+#define MAME_MACHINE_FM_SCSI_H
+
+#include "machine/legscsi.h"
+
+
+class fmscsi_device : public legacy_scsi_host_adapter
+{
+public:
+ // construction/destruction
+ fmscsi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // configuration helpers
+ auto irq_handler() { return m_irq_handler.bind(); }
+ auto drq_handler() { return m_drq_handler.bind(); }
+
+ // any publically accessible interfaces needed for runtime
+ uint8_t fmscsi_data_r(void);
+ void fmscsi_data_w(uint8_t data);
+ uint8_t fmscsi_status_r(void);
+ void fmscsi_control_w(uint8_t data);
+ uint8_t fmscsi_r(offs_t offset);
+ void fmscsi_w(offs_t offset, uint8_t data);
+
+ TIMER_CALLBACK_MEMBER(set_phase);
+ int get_phase(void);
+ void set_input_line(uint8_t line, uint8_t state);
+ uint8_t get_input_line(uint8_t line);
+ void set_output_line(uint8_t line, uint8_t state);
+ uint8_t get_output_line(uint8_t line);
+
+protected:
+ // device-level overrides (none are required, but these are common)
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ TIMER_CALLBACK_MEMBER(update_transfer);
+
+private:
+ int get_scsi_cmd_len(uint8_t cbyte);
+ void stop_transfer();
+
+ devcb_write_line m_irq_handler;
+ devcb_write_line m_drq_handler;
+
+ uint8_t m_command[32];
+ //uint8_t m_result[32];
+ uint8_t m_command_index;
+ int m_result_length;
+ uint32_t m_result_index;
+ uint8_t m_input_lines;
+ uint8_t m_output_lines;
+ uint8_t m_data;
+ uint8_t m_last_id;
+ uint8_t m_phase;
+ uint8_t m_target;
+ uint8_t m_buffer[512];
+ emu_timer* m_transfer_timer;
+ emu_timer* m_phase_timer;
+};
+
+DECLARE_DEVICE_TYPE(FMSCSI, fmscsi_device)
+
+#endif // MAME_MACHINE_FM_SCSI_H
diff --git a/src/devices/machine/gayle.cpp b/src/devices/machine/gayle.cpp
index 0e55fcd2bb6..bb43e8d5188 100644
--- a/src/devices/machine/gayle.cpp
+++ b/src/devices/machine/gayle.cpp
@@ -1,22 +1,37 @@
-// license:GPL-2.0+
-// copyright-holders:Dirk Best
+// license: GPL-2.0+
+// copyright-holders: Dirk Best
/***************************************************************************
GAYLE
- Gate array used in the Amiga 600 and Amiga 1200 computers.
+ Gate array used in the Amiga 600 and Amiga 1200 computers for the
+ following functions:
+ - Address decoding and timing for ROM, RAM, CIA, RTC
+ (and unused: Flash ROM, ArcNet)
+ - Data buffers for chip RAM
+ - IDE interface
+ - Credit card (PCMCIA) interface
+ - System reset
+ - Floppy helper
+ - E clock generation
+
+ TODO:
+ - Generate bus errors (REG_CHANGE, bit 0)
+ - Disabling the PCMCIA interface should remove access to PCMCIA memory
+ - Move more functionality here
***************************************************************************/
#include "emu.h"
#include "gayle.h"
+#define LOG_REG (1U << 1)
+#define LOG_IDE (1U << 2)
+#define LOG_CC (1U << 3)
+#define LOG_ID (1U << 4)
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-#define VERBOSE 0
+//#define VERBOSE (LOG_GENERAL | LOG_REG | LOG_CC)
+#include "logmacro.h"
//**************************************************************************
@@ -37,10 +52,10 @@ DEFINE_DEVICE_TYPE(GAYLE, gayle_device, "gayle", "Amiga GAYLE")
gayle_device::gayle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, GAYLE, tag, owner, clock),
m_int2_w(*this),
- m_cs0_read(*this),
- m_cs0_write(*this),
- m_cs1_read(*this),
- m_cs1_write(*this),
+ m_int6_w(*this),
+ m_rst_w(*this),
+ m_ide_cs_r_cb(*this, 0xffff),
+ m_ide_cs_w_cb(*this),
m_gayle_id(0xff),
m_gayle_id_count(0)
{
@@ -52,15 +67,9 @@ gayle_device::gayle_device(const machine_config &mconfig, const char *tag, devic
void gayle_device::device_start()
{
- // resolve callbacks
- m_int2_w.resolve_safe();
- m_cs0_read.resolve_safe(0xffff);
- m_cs0_write.resolve_safe();
- m_cs1_read.resolve_safe(0xffff);
- m_cs1_write.resolve_safe();
-
save_item(NAME(m_gayle_id_count));
save_item(NAME(m_gayle_reg));
+ save_item(NAME(m_line_state));
}
//-------------------------------------------------
@@ -69,117 +78,321 @@ void gayle_device::device_start()
void gayle_device::device_reset()
{
+ // internal registers are cleared to 0 on reset
m_gayle_reg[0] = 0;
m_gayle_reg[1] = 0;
m_gayle_reg[2] = 0;
m_gayle_reg[3] = 0;
+
+ // lower interrupts
+ m_int2_w(0);
+ m_int6_w(0);
+}
+
+
+//**************************************************************************
+// ADDRESS MAP
+//**************************************************************************
+
+void gayle_device::register_map(address_map &map)
+{
+ // base address 0xdaXXXX
+ map(0x0000, 0x001f).mirror(0x0fe0).rw(FUNC(gayle_device::ide_cs_r<1>), FUNC(gayle_device::ide_cs_w<1>));
+ map(0x2000, 0x201f).mirror(0x0fe0).rw(FUNC(gayle_device::ide_cs_r<0>), FUNC(gayle_device::ide_cs_w<0>));
+ map(0x8000, 0x8001).rw(FUNC(gayle_device::status_r), FUNC(gayle_device::status_w));
+ map(0x9000, 0x9001).rw(FUNC(gayle_device::change_r), FUNC(gayle_device::change_w));
+ map(0xa000, 0xa001).rw(FUNC(gayle_device::int_r), FUNC(gayle_device::int_w));
+ map(0xb000, 0xb001).rw(FUNC(gayle_device::control_r), FUNC(gayle_device::control_w));
}
//**************************************************************************
-// IMPLEMENTATION
+// INTERNAL
//**************************************************************************
-uint16_t gayle_device::gayle_r(offs_t offset, uint16_t mem_mask)
+void gayle_device::dump_register()
{
- uint16_t data = 0xffff;
- offset <<= 1;
+ LOGMASKED(LOG_REG, "status = %02x, change = %02x, int = %02x, control = %02x\n",
+ m_gayle_reg[REG_STATUS], m_gayle_reg[REG_CHANGE], m_gayle_reg[REG_INT], m_gayle_reg[REG_CONTROL]);
+}
- // swap
- mem_mask = swapendian_int16(mem_mask);
+void gayle_device::line_change(int line, int state, int level)
+{
+ LOGMASKED(line == LINE_IDE ? LOG_IDE : LOG_CC, "line_change: %d %d %d\n", line, state, level);
- if (BIT(offset, 15))
+ m_line_state &= ~(1 << line);
+ m_line_state |= (state << line);
+
+ // ignore pcmcia line changes if the interface is disabled
+ if (line != LINE_IDE && BIT(m_gayle_reg[REG_STATUS], 0))
+ return;
+
+ // did we change state?
+ if (BIT(m_gayle_reg[REG_STATUS], line) != state)
{
- switch (offset & 0x7fff)
+ // indicate a change to the line
+ m_gayle_reg[REG_CHANGE] |= 1 << line;
+
+ // special handling for line 6 (credit card detect)
+ if (line == LINE_CC_DET && BIT(m_gayle_reg[REG_CHANGE], 1))
{
- case 0x0000: data = m_gayle_reg[0]; break;
- case 0x1000: data = m_gayle_reg[1]; break;
- case 0x2000: data = m_gayle_reg[2]; break;
- case 0x3000: data = m_gayle_reg[3]; break;
+ LOG("resetting due to credit card detection change\n");
+
+ m_rst_w(0);
+ m_rst_w(1);
+ reset();
+
+ return;
}
- }
- else
- {
- if (!BIT(offset, 14))
+
+ if (state)
+ m_gayle_reg[REG_STATUS] |= 1 << line;
+ else
+ m_gayle_reg[REG_STATUS] &= ~(1 << line);
+
+ // generate interrupt (if enabled)
+ if (BIT(m_gayle_reg[REG_INT], line))
{
- if (BIT(offset, 13))
- data = m_cs0_read((offset >> 2) & 0x07, mem_mask);
+ LOGMASKED(line == LINE_IDE ? LOG_IDE : LOG_CC, "line %d int assert\n", line);
+
+ if (level == 2)
+ m_int2_w(1);
else
- data = m_cs1_read((offset >> 2) & 0x07, mem_mask);
+ m_int6_w(1);
}
}
+}
- if (VERBOSE)
- logerror("gayle_r(%06x): %04x & %04x\n", offset, data, mem_mask);
- // swap data
- data = swapendian_int16(data);
+//**************************************************************************
+// REGISTER
+//**************************************************************************
- return data;
+uint16_t gayle_device::status_r()
+{
+ // 7------- ide interrupt status
+ // -6------ credit card detect
+ // --5----- battery voltage 1/status change
+ // ---4---- battery voltage 2/digital audio
+ // ----3--- credit card write enable
+ // -----2-- credit card busy/interrupt request
+ // ------1- enable pcmcia digital audio
+ // -------0 disable pcmcia
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG, "status_r: %02x\n", m_gayle_reg[REG_STATUS]);
+
+ return (m_gayle_reg[REG_STATUS] << 8) | m_gayle_reg[REG_STATUS];
}
-void gayle_device::gayle_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+void gayle_device::status_w(uint16_t data)
{
- offset <<= 1;
+ uint8_t previous = m_gayle_reg[REG_STATUS];
+ data >>= 8;
+ LOGMASKED(LOG_REG, "status_w: %02x\n", data);
- // swap
- mem_mask = swapendian_int16(mem_mask);
- data = swapendian_int16(data) & mem_mask;
+ // pcmcia interface disable?
+ if (BIT(data, 0) == 1)
+ m_gayle_reg[REG_STATUS] &= 0x03;
- if (VERBOSE)
- logerror("gayle_w(%06x): %04x & %04x\n", offset, data, mem_mask);
+ // lowest two bits can be set freely
+ m_gayle_reg[REG_STATUS] &= ~0x03;
+ m_gayle_reg[REG_STATUS] |= data & 0x03;
- if (BIT(offset, 15))
+ // status bits can only be set
+ m_gayle_reg[REG_STATUS] |= data & 0xfc;
+
+ // pcmcia interface re-enabled?
+ if (BIT(previous, 0) == 1 && BIT(data, 0) == 0)
{
- switch (offset & 0x7fff)
- {
- case 0x0000:
- m_gayle_reg[0] = data;
- break;
- case 0x1000:
- m_gayle_reg[1] &= data;
- m_gayle_reg[1] |= data & 0x03;
- break;
- case 0x2000:
- m_gayle_reg[2] = data;
- break;
- case 0x3000:
- m_gayle_reg[3] = data;
- break;
- }
+ cc_cd_w(BIT(m_line_state, 6));
+ cc_bvd1_w(BIT(m_line_state, 5));
+ cc_bvd2_w(BIT(m_line_state, 4));
+ cc_wp_w(BIT(m_line_state, 3));
}
- else
+}
+
+uint16_t gayle_device::change_r()
+{
+ // 7------- ide interrupt changed
+ // -6------ credit card detect changed
+ // --5----- battery voltage 1/status change changed
+ // ---4---- battery voltage 2/digital audio changed
+ // ----3--- credit card write enable changed
+ // -----2-- credit card busy/interrupt request changed
+ // ------1- generate reset after cc detect change
+ // -------0 generate bus error after cc detect change
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG, "change_r: %02x\n", m_gayle_reg[REG_CHANGE]);
+
+ return (m_gayle_reg[REG_CHANGE] << 8) | m_gayle_reg[REG_CHANGE];
+}
+
+void gayle_device::change_w(uint16_t data)
+{
+ data >>= 8;
+ LOGMASKED(LOG_REG, "change_w: %02x\n", data);
+
+ // clear ide interrupt?
+ if (BIT(data, 7) == 0)
{
- if (!BIT(offset, 14))
- {
- if (BIT(offset, 13))
- m_cs0_write((offset >> 2) & 0x07, data, mem_mask);
- else
- m_cs1_write((offset >> 2) & 0x07, data, mem_mask);
- }
+ LOGMASKED(LOG_REG, "ide int cleared\n", data);
+ m_int2_w(0);
+ }
+
+ // clear cc detect interrupt?
+ if (BIT(data, 6) == 0)
+ {
+ LOGMASKED(LOG_REG, "cc detect int cleared\n", data);
+ m_int6_w(0);
+ }
+
+ // clear bvd1/sc interrupt?
+ if (BIT(data, 5) == 0)
+ {
+ LOGMASKED(LOG_REG, "bvd1/sc int cleared\n", data);
+ if (BIT(m_gayle_reg[REG_INT], 1))
+ m_int6_w(0);
+ else
+ m_int2_w(0);
+ }
+
+ // clear bvd2/da interrupt?
+ if (BIT(data, 4) == 0)
+ {
+ LOGMASKED(LOG_REG, "bvd2/da int cleared\n", data);
+ if (BIT(m_gayle_reg[REG_INT], 1))
+ m_int6_w(0);
+ else
+ m_int2_w(0);
}
+
+ // clear write protect interrupt?
+ if (BIT(data, 3) == 0)
+ {
+ LOGMASKED(LOG_REG, "write protect int cleared\n", data);
+ m_int2_w(0);
+ }
+
+ // enabling reset on cc detect change can immediately generate a reset
+ if (BIT(data, 1) && BIT(m_gayle_reg[REG_CHANGE], 6))
+ {
+ LOGMASKED(LOG_REG, "resetting\n", data);
+
+ m_rst_w(0);
+ m_rst_w(1);
+ reset();
+
+ return;
+ }
+
+ m_gayle_reg[REG_CHANGE] = (m_gayle_reg[REG_CHANGE] & data) | (data & 0x03);
}
-WRITE_LINE_MEMBER( gayle_device::ide_interrupt_w )
+uint16_t gayle_device::int_r()
{
- if (VERBOSE)
- logerror("ide_interrupt_w: %d\n", state);
+ // 7------- ide interrupt enable
+ // -6------ credit card detect interrupt enable
+ // --5----- battery voltage 1/status change interrupt enable
+ // ---4---- battery voltage 2/digital audio interrupt enable
+ // ----3--- write enable interrupt enable
+ // -----2-- busy/interrupt request interrupt enable
+ // ------1- set interrupt level for battery voltage 1/2
+ // -------0 set interrupt level for busy/interrupt request
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG, "int_r: %02x\n", m_gayle_reg[REG_INT]);
+
+ return (m_gayle_reg[REG_INT] << 8) | m_gayle_reg[REG_INT];
+}
- // did we change state?
- if (BIT(m_gayle_reg[GAYLE_CS], 7) != state)
- m_gayle_reg[GAYLE_IRQ] |= 1 << 7;
+void gayle_device::int_w(uint16_t data)
+{
+ data >>= 8;
+ LOGMASKED(LOG_REG, "int_w: %02x\n", data);
- // set line state
- if (state)
- m_gayle_reg[GAYLE_CS] |= 1 << 7;
- else
- m_gayle_reg[GAYLE_CS] &= ~(1 << 7);
+ m_gayle_reg[REG_INT] = data;
+}
+
+uint16_t gayle_device::control_r()
+{
+ // 7654---- not implemented in hardware
+ // ----32--- slow mem (250 ns, 150 ns, 100 ns, 720 ns)
+ // ------1- program 12v
+ // -------0 program 5v
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG, "control_r: %02x\n", m_gayle_reg[REG_CONTROL]);
+
+ return (m_gayle_reg[REG_CONTROL] << 8) | m_gayle_reg[REG_CONTROL];
+}
+
+void gayle_device::control_w(uint16_t data)
+{
+ data >>= 8;
+ LOGMASKED(LOG_REG, "control_w: %02x\n", data);
+
+ m_gayle_reg[REG_CONTROL] = data;
+}
+
+
+//**************************************************************************
+// IDE
+//**************************************************************************
- // update interrupts
- if (BIT(m_gayle_reg[GAYLE_INTEN], 7))
- m_int2_w(BIT(m_gayle_reg[GAYLE_CS], 7));
+template<int N>
+uint16_t gayle_device::ide_cs_r(offs_t offset, uint16_t mem_mask)
+{
+ return m_ide_cs_r_cb[N]((offset >> 1) & 0x07, mem_mask);
+}
+
+template<int N>
+void gayle_device::ide_cs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ m_ide_cs_w_cb[N]((offset >> 1) & 0x07, data, mem_mask);
+}
+
+void gayle_device::ide_interrupt_w(int state)
+{
+ LOGMASKED(LOG_IDE, "ide_interrupt_w: %d\n", state);
+ line_change(7, state, 2);
+}
+
+
+//**************************************************************************
+// CREDIT CARD
+//**************************************************************************
+
+void gayle_device::cc_cd_w(int state)
+{
+ LOGMASKED(LOG_CC, "cc_cd_w: %d\n", state);
+ line_change(LINE_CC_DET, state, 6);
}
+void gayle_device::cc_bvd1_w(int state)
+{
+ LOGMASKED(LOG_CC, "cc_bvd1_w: %d\n", state);
+ line_change(LINE_CC_BVD1_SC, state, BIT(m_gayle_reg[REG_INT], 1) ? 6 : 2);
+}
+
+void gayle_device::cc_bvd2_w(int state)
+{
+ LOGMASKED(LOG_CC, "cc_bvd2_w: %d\n", state);
+ line_change(LINE_CC_BVD2_DA, state, BIT(m_gayle_reg[REG_INT], 1) ? 6 : 2);
+}
+
+void gayle_device::cc_wp_w(int state)
+{
+ LOGMASKED(LOG_CC, "cc_wp_w: %d\n", state);
+ line_change(LINE_CC_WP, state, 2);
+}
+
+
+//**************************************************************************
+// ID
+//**************************************************************************
+
uint16_t gayle_device::gayle_id_r(offs_t offset, uint16_t mem_mask)
{
uint16_t data;
@@ -189,16 +402,14 @@ uint16_t gayle_device::gayle_id_r(offs_t offset, uint16_t mem_mask)
else
data = 0xffff;
- if (VERBOSE)
- logerror("gayle_id_r(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id);
+ LOGMASKED(LOG_ID, "gayle_id_r(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id);
return data;
}
void gayle_device::gayle_id_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
- if (VERBOSE)
- logerror("gayle_id_w(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id);
+ LOGMASKED(LOG_ID, "gayle_id_w(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id);
m_gayle_id_count = 0;
}
diff --git a/src/devices/machine/gayle.h b/src/devices/machine/gayle.h
index c756e6117b7..b4c6bbf2b41 100644
--- a/src/devices/machine/gayle.h
+++ b/src/devices/machine/gayle.h
@@ -1,11 +1,56 @@
-// license:GPL-2.0+
-// copyright-holders:Dirk Best
+// license: GPL-2.0+
+// copyright-holders: Dirk Best
/***************************************************************************
GAYLE
Gate array used in the Amiga 600 and Amiga 1200 computers.
+ 84-pin
+
+ 1 PE12 43 A14
+ 2 PE5 44 A15
+ 3 GND 45 GND
+ 4 NOISE 46 A16
+ 5 CC-RESET 47 A17
+ 6 _CC_ENA 48 A18
+ 7 _CC_REG 49 A19
+ 8 _CC_CEL 50 A20
+ 9 _CC_CEU 51 A21
+ 10 E 52 A22
+ 11 _FLASH 53 A23
+ 12 _IDE_IRQ 54 D7
+ 13 _IDE_CS1 55 D6
+ 14 _IDE_CS2 56 D5
+ 15 _SPARE_CS 57 D4
+ 16 _NET_CS 58 D3
+ 17 _RTC_CS 59 D2
+ 18 _IOWR 60 D1
+ 19 _IORD 61 D0
+ 20 VCC 62 VCC
+ 21 _ROMEN 63 _KBRESET
+ 22 C14M 64 DKWEB
+ 23 CCK 65 DKWDB
+ 24 GND 66 GND
+ 25 XRDY 67 MTRON
+ 26 _OVR 68 MTRX
+ 27 _OEL 69 DKWE
+ 28 _OEB 70 _DKWD
+ 29 _DBR 71 _MTR
+ 30 _BLS 72 _SEL
+ 31 _REGEN 73 _ODD_CIA
+ 32 _RAMEN 74 _EVEN_CIA
+ 33 _AS 75 _CC_CD1
+ 34 _UDS 76 _CC_CD2
+ 35 _LDS 77 _CC_BVD1
+ 36 R_W 78 _CC_BVD2
+ 37 _DTACK 79 CC_WP
+ 38 _BGACK 80 _CC_BUSY_IREQ
+ 39 _HLT 81 _WAIT
+ 40 _RST 82 _BERR
+ 41 A12 83 _INT6
+ 42 A13 84 _INT2
+
***************************************************************************/
#ifndef MAME_MACHINE_GAYLE_H
@@ -28,16 +73,21 @@ public:
// callbacks
auto int2_handler() { return m_int2_w.bind(); }
- auto cs0_read_handler() { return m_cs0_read.bind(); }
- auto cs0_write_handler() { return m_cs0_write.bind(); }
- auto cs1_read_handler() { return m_cs1_read.bind(); }
- auto cs1_write_handler() { return m_cs1_write.bind(); }
+ auto int6_handler() { return m_int6_w.bind(); }
+ auto rst_handler() { return m_rst_w.bind(); }
+ template<int N> auto ide_cs_r_cb() { return m_ide_cs_r_cb[N].bind(); }
+ template<int N> auto ide_cs_w_cb() { return m_ide_cs_w_cb[N].bind(); }
// interface
- DECLARE_WRITE_LINE_MEMBER( ide_interrupt_w );
+ void ide_interrupt_w(int state);
+
+ // credit card signals
+ void cc_cd_w(int state);
+ void cc_bvd1_w(int state);
+ void cc_bvd2_w(int state);
+ void cc_wp_w(int state);
- uint16_t gayle_r(offs_t offset, uint16_t mem_mask = ~0);
- void gayle_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void register_map(address_map &map);
uint16_t gayle_id_r(offs_t offset, uint16_t mem_mask = ~0);
void gayle_id_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
@@ -49,24 +99,55 @@ protected:
virtual void device_reset() override;
private:
+ void dump_register();
+ void line_change(int line, int state, int level);
+
+ template<int N> uint16_t ide_cs_r(offs_t offset, uint16_t mem_mask);
+ template<int N> void ide_cs_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ uint16_t status_r();
+ void status_w(uint16_t data);
+ uint16_t change_r();
+ void change_w(uint16_t data);
+ uint16_t int_r();
+ void int_w(uint16_t data);
+ uint16_t control_r();
+ void control_w(uint16_t data);
+
enum
{
- GAYLE_CS = 0, // interrupt status
- GAYLE_IRQ, // interrupt change
- GAYLE_INTEN, // interrupt enable register
- GAYLE_CFG // config register
+ REG_STATUS = 0,
+ REG_CHANGE,
+ REG_INT,
+ REG_CONTROL
+ };
+
+ enum
+ {
+ LINE_IDE = 7,
+ LINE_CC_DET = 6,
+ LINE_CC_BVD1_SC = 5,
+ LINE_CC_BVD2_DA = 4,
+ LINE_CC_WP = 3,
+ LINE_CC_BUSY_IREQ = 2
};
devcb_write_line m_int2_w;
+ devcb_write_line m_int6_w;
+ devcb_write_line m_rst_w;
- devcb_read16 m_cs0_read;
- devcb_write16 m_cs0_write;
- devcb_read16 m_cs1_read;
- devcb_write16 m_cs1_write;
+ devcb_read16::array<2> m_ide_cs_r_cb;
+ devcb_write16::array<2> m_ide_cs_w_cb;
+ // gayle id, bitwise readable by the cpu
uint8_t m_gayle_id;
- int m_gayle_id_count;
+ uint8_t m_gayle_id_count;
+
+ // gayle register, readable/writeable by the cpu
uint8_t m_gayle_reg[4];
+
+ // internal latched line state
+ uint8_t m_line_state;
};
// device type definition
diff --git a/src/devices/machine/gen_fifo.cpp b/src/devices/machine/gen_fifo.cpp
index 10fcf37429c..188c5df4eda 100644
--- a/src/devices/machine/gen_fifo.cpp
+++ b/src/devices/machine/gen_fifo.cpp
@@ -49,59 +49,51 @@ template<typename T> void generic_fifo_device_base<T>::clear()
template<typename T> void generic_fifo_device_base<T>::device_start()
{
- m_empty_cb.resolve_safe();
- m_full_cb.resolve_safe();
-
- m_sync_empty = timer_alloc(0);
- m_sync_full = timer_alloc(1);
+ m_sync_empty = timer_alloc(FUNC(generic_fifo_device_base<T>::sync_empty), this);
+ m_sync_full = timer_alloc(FUNC(generic_fifo_device_base<T>::sync_full), this);
// This is not saving the fifo, let's hope it's empty...
save_item(NAME(m_empty_triggered));
save_item(NAME(m_full_triggered));
}
-template<typename T> void generic_fifo_device_base<T>::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+template<typename T> TIMER_CALLBACK_MEMBER(generic_fifo_device_base<T>::sync_empty)
{
- switch(id) {
- case T_FULL: {
- // Add the extra values in if there's space
- bool was_empty = is_empty();
- bool was_full = is_full();
-
- while(!m_extra_values.empty() && !is_full()) {
- T t(std::move(m_extra_values.front()));
- m_extra_values.erase(m_extra_values.begin());
- m_values.emplace_back(std::move(t));
+ // Sync was called for a fifo empty, is it still empty?
+ if(is_empty()) {
+ // If yes, stop the destination if not done yet
+ if(!m_empty_triggered) {
+ m_empty_triggered = true;
+ m_on_fifo_empty_post_sync();
}
+ }
+}
- // Adjust devcb lines as needed
- if(was_empty && !is_empty())
- m_empty_cb(false);
- if(!was_full && is_full())
- m_full_cb(true);
+template<typename T> TIMER_CALLBACK_MEMBER(generic_fifo_device_base<T>::sync_full)
+{
+ // Add the extra values in if there's space
+ bool was_empty = is_empty();
+ bool was_full = is_full();
- // Are there still values that don't fit?
- if(!m_extra_values.empty()) {
- // If yes, stop the source if not done yet
- if(!m_full_triggered) {
- m_full_triggered = true;
- m_on_fifo_full_post_sync();
- }
- }
- break;
+ while(!m_extra_values.empty() && !is_full()) {
+ T t(std::move(m_extra_values.front()));
+ m_extra_values.erase(m_extra_values.begin());
+ m_values.emplace_back(std::move(t));
}
- case T_EMPTY: {
- // Sync was called for a fifo empty, is it still empty?
- if(is_empty()) {
- // If yes, stop the destination if not done yet
- if(!m_empty_triggered) {
- m_empty_triggered = true;
- m_on_fifo_empty_post_sync();
- }
+ // Adjust devcb lines as needed
+ if(was_empty && !is_empty())
+ m_empty_cb(false);
+ if(!was_full && is_full())
+ m_full_cb(true);
+
+ // Are there still values that don't fit?
+ if(!m_extra_values.empty()) {
+ // If yes, stop the source if not done yet
+ if(!m_full_triggered) {
+ m_full_triggered = true;
+ m_on_fifo_full_post_sync();
}
- break;
- }
}
}
diff --git a/src/devices/machine/gen_fifo.h b/src/devices/machine/gen_fifo.h
index a33f4d4880f..8e27ef73b6a 100644
--- a/src/devices/machine/gen_fifo.h
+++ b/src/devices/machine/gen_fifo.h
@@ -197,7 +197,9 @@ private:
bool m_empty_triggered, m_full_triggered;
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(sync_empty);
+ TIMER_CALLBACK_MEMBER(sync_full);
};
class generic_fifo_u32_device : public generic_fifo_device_base<u32>
diff --git a/src/devices/machine/gen_latch.cpp b/src/devices/machine/gen_latch.cpp
index 2e3929b108a..e75d2fe8979 100644
--- a/src/devices/machine/gen_latch.cpp
+++ b/src/devices/machine/gen_latch.cpp
@@ -9,7 +9,7 @@
#include "emu.h"
#include "gen_latch.h"
-#define LOG_WARN (1U << 0)
+#define LOG_WARN (1U << 1)
#define VERBOSE (LOG_WARN)
#include "logmacro.h"
@@ -45,7 +45,6 @@ generic_latch_base_device::generic_latch_base_device(const machine_config &mconf
void generic_latch_base_device::device_start()
{
- m_data_pending_cb.resolve_safe();
save_item(NAME(m_latch_written));
// synchronization is needed since other devices may not be initialized yet
@@ -56,7 +55,7 @@ void generic_latch_base_device::device_start()
// init_callback - set initial state
//-------------------------------------------------
-void generic_latch_base_device::init_callback(void *ptr, s32 param)
+void generic_latch_base_device::init_callback(s32 param)
{
m_data_pending_cb(m_latch_written ? 1 : 0);
}
@@ -67,7 +66,7 @@ void generic_latch_base_device::init_callback(void *ptr, s32 param)
void generic_latch_base_device::device_reset()
{
- m_latch_written = false;
+ set_latch_written(false);
}
//-------------------------------------------------
@@ -75,7 +74,7 @@ void generic_latch_base_device::device_reset()
// to be read
//-------------------------------------------------
-READ_LINE_MEMBER(generic_latch_base_device::pending_r)
+int generic_latch_base_device::pending_r()
{
return m_latch_written ? 1 : 0;
}
@@ -138,12 +137,12 @@ void generic_latch_8_device::clear_w(u8 data)
m_latched_value = 0x00;
}
-WRITE_LINE_MEMBER( generic_latch_8_device::preset )
+void generic_latch_8_device::preset(int state)
{
m_latched_value = 0xff;
}
-WRITE_LINE_MEMBER( generic_latch_8_device::clear )
+void generic_latch_8_device::clear(int state)
{
m_latched_value = 0x00;
}
@@ -153,7 +152,7 @@ WRITE_LINE_MEMBER( generic_latch_8_device::clear )
// callback to set a latch value
//-------------------------------------------------
-void generic_latch_8_device::sync_callback(void *ptr, s32 param)
+void generic_latch_8_device::sync_callback(s32 param)
{
u8 value = param;
@@ -209,12 +208,12 @@ void generic_latch_16_device::clear_w(u16 data)
m_latched_value = 0x0000;
}
-WRITE_LINE_MEMBER( generic_latch_16_device::preset )
+void generic_latch_16_device::preset(int state)
{
m_latched_value = 0xffff;
}
-WRITE_LINE_MEMBER( generic_latch_16_device::clear )
+void generic_latch_16_device::clear(int state)
{
m_latched_value = 0x0000;
}
@@ -224,7 +223,7 @@ WRITE_LINE_MEMBER( generic_latch_16_device::clear )
// callback to set a latch value
//-------------------------------------------------
-void generic_latch_16_device::sync_callback(void *ptr, s32 param)
+void generic_latch_16_device::sync_callback(s32 param)
{
u16 value = param;
diff --git a/src/devices/machine/gen_latch.h b/src/devices/machine/gen_latch.h
index 4080cbebe8d..946ac5c380c 100644
--- a/src/devices/machine/gen_latch.h
+++ b/src/devices/machine/gen_latch.h
@@ -34,7 +34,7 @@ public:
auto data_pending_callback() { return m_data_pending_cb.bind(); }
void set_separate_acknowledge(bool ack) { m_separate_acknowledge = ack; }
- DECLARE_READ_LINE_MEMBER(pending_r);
+ int pending_r();
u8 acknowledge_r(address_space &space);
void acknowledge_w(u8 data = 0);
@@ -51,7 +51,7 @@ protected:
void set_latch_written(bool latch_written);
private:
- void init_callback(void *ptr, s32 param);
+ void init_callback(s32 param);
bool m_separate_acknowledge;
bool m_latch_written;
@@ -72,13 +72,13 @@ public:
void preset_w(u8 data = 0xff);
void clear_w(u8 data = 0);
- DECLARE_WRITE_LINE_MEMBER( preset );
- DECLARE_WRITE_LINE_MEMBER( clear );
+ void preset(int state);
+ void clear(int state);
protected:
virtual void device_start() override;
- void sync_callback(void *ptr, s32 param);
+ void sync_callback(s32 param);
private:
u8 m_latched_value;
@@ -98,13 +98,13 @@ public:
void preset_w(u16 data = 0xffff);
void clear_w(u16 data = 0);
- DECLARE_WRITE_LINE_MEMBER( preset );
- DECLARE_WRITE_LINE_MEMBER( clear );
+ void preset(int state);
+ void clear(int state);
protected:
virtual void device_start() override;
- void sync_callback(void *ptr, s32 param);
+ void sync_callback(s32 param);
private:
u16 m_latched_value;
diff --git a/src/devices/machine/generalplus_gpl16250soc.cpp b/src/devices/machine/generalplus_gpl16250soc.cpp
index b8f7ef690cc..dc4505ce9ff 100644
--- a/src/devices/machine/generalplus_gpl16250soc.cpp
+++ b/src/devices/machine/generalplus_gpl16250soc.cpp
@@ -25,6 +25,33 @@
DEFINE_DEVICE_TYPE(GCM394, sunplus_gcm394_device, "gcm394", "GeneralPlus GPL16250 System-on-a-Chip")
+sunplus_gcm394_base_device::sunplus_gcm394_base_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock, address_map_constructor internal) :
+ unsp_20_device(mconfig, type, tag, owner, clock, internal),
+ device_mixer_interface(mconfig, *this, 2),
+ m_screen(*this, finder_base::DUMMY_TAG),
+ m_spg_video(*this, "spgvideo"),
+ m_spg_audio(*this, "spgaudio"),
+ m_internalrom(*this, "internal"),
+ m_mainram(*this, "mainram"),
+ m_porta_in(*this, 0),
+ m_portb_in(*this, 0),
+ m_portc_in(*this, 0),
+ m_portd_in(*this, 0),
+ m_porta_out(*this),
+ m_portb_out(*this),
+ m_portc_out(*this),
+ m_portd_out(*this),
+ m_nand_read_cb(*this, 0),
+ m_csbase(0x20000),
+ m_cs_space(nullptr),
+ m_romtype(0),
+ m_space_read_cb(*this, 0),
+ m_space_write_cb(*this),
+ m_boot_mode(0),
+ m_cs_callback(*this, DEVICE_SELF, FUNC(sunplus_gcm394_base_device::default_cs_callback))
+{
+}
+
sunplus_gcm394_device::sunplus_gcm394_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sunplus_gcm394_base_device(mconfig, GCM394, tag, owner, clock)
{
@@ -46,6 +73,122 @@ generalplus_gpspispi_device::generalplus_gpspispi_device(const machine_config &m
}
+void generalplus_gpspi_direct_device::ramwrite_w(offs_t offset, uint16_t data)
+{
+ // TODO: Gross hack, it puts some self-check code in RAM at startup, this replaces those calls with retf.
+ if (offset == 0x100 && data == 0xf14c) data = 0x9a90;
+ if (offset == 0x00 && data == 0x9311) data = 0x9a90;
+
+ m_mainram[offset] = data;
+}
+
+uint16_t generalplus_gpspi_direct_device::ramread_r(offs_t offset)
+{
+ return m_mainram[offset];
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_7b40_r()
+{
+ return 0xffff; // doesn't care for now
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_79f5_r()
+{
+ return 0xffff; // hangs if returning 0
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_7b46_r()
+{
+ int i = machine().rand();
+
+ if (i & 1) return 0x01;
+ else return 0x02;
+}
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_79f4_r()
+{
+ // status bits?
+ return machine().rand();
+}
+
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_7af0_r()
+{
+ return m_7af0;
+}
+
+void generalplus_gpspi_direct_device::spi_direct_7af0_w(uint16_t data)
+{
+ // words read from ROM are written here during the checksum routine in RAM, and must
+ // be shifted for the checksum to pass.
+ m_7af0 = data >> 8;
+}
+
+
+uint16_t generalplus_gpspi_direct_device::spi_direct_78e8_r()
+{
+ return machine().rand();
+}
+
+void generalplus_gpspi_direct_device::device_start()
+{
+ sunplus_gcm394_base_device::device_start();
+ save_item(NAME(m_7af0));
+}
+
+void generalplus_gpspi_direct_device::device_reset()
+{
+ sunplus_gcm394_base_device::device_reset();
+ m_7af0 = 0;
+}
+
+void generalplus_gpspi_direct_device::spi_direct_78e8_w(uint16_t data)
+{
+ logerror("%s: spi_direct_78e8_w %04x\n", machine().describe_context(), data);
+}
+
+void generalplus_gpspi_direct_device::gpspi_direct_internal_map(address_map& map)
+{
+ sunplus_gcm394_base_device::base_internal_map(map);
+
+ map(0x000000, 0x0027ff).rw(FUNC(generalplus_gpspi_direct_device::ramread_r), FUNC(generalplus_gpspi_direct_device::ramwrite_w));
+ // TODO: RAM is only 0x2800 on this, like earlier SPG2xx models? unmap the extra from the base_internal_map?
+
+ map(0x00780b, 0x00780b).nopw();
+
+ map(0x0078e8, 0x0078e8).rw(FUNC(generalplus_gpspi_direct_device::spi_direct_78e8_r), FUNC(generalplus_gpspi_direct_device::spi_direct_78e8_w));
+
+ map(0x0079f4, 0x0079f4).r(FUNC(generalplus_gpspi_direct_device::spi_direct_79f4_r));
+ map(0x0079f5, 0x0079f5).r(FUNC(generalplus_gpspi_direct_device::spi_direct_79f5_r));
+
+ map(0x007af0, 0x007af0).rw(FUNC(generalplus_gpspi_direct_device::spi_direct_7af0_r), FUNC(generalplus_gpspi_direct_device::spi_direct_7af0_w));
+
+ map(0x007b40, 0x007b40).r(FUNC(generalplus_gpspi_direct_device::spi_direct_7b40_r));
+// map(0x007b46, 0x007b46).r(FUNC(generalplus_gpspi_direct_device::spi_direct_7b46_r));
+ map(0x007b40, 0x007b40).nopw();
+ map(0x007b41, 0x007b41).nopw();
+ map(0x007b42, 0x007b42).nopw();
+
+ map(0x007b46, 0x007b46).ram(); // values must be written and read from here, but is there any transformation?
+ map(0x007b47, 0x007b47).nopw();
+ map(0x007b48, 0x007b48).nopw();
+
+ map(0x007b49, 0x007b49).ram();
+
+ map(0x009000, 0x3fffff).rom().region("spidirect", 0);
+}
+
+
+DEFINE_DEVICE_TYPE(GP_SPI_DIRECT, generalplus_gpspi_direct_device, "gpac800spi_direct", "GeneralPlus GPL16250 (with direct SPI handling)")
+
+generalplus_gpspi_direct_device::generalplus_gpspi_direct_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ sunplus_gcm394_base_device(mconfig, GP_SPI_DIRECT, tag, owner, clock, address_map_constructor(FUNC(generalplus_gpspi_direct_device::gpspi_direct_internal_map), this))
+{
+}
+
+
+
+
void sunplus_gcm394_base_device::default_cs_callback(uint16_t cs0, uint16_t cs1, uint16_t cs2, uint16_t cs3, uint16_t cs4)
{
logerror("callback not hooked\n");
@@ -163,7 +306,7 @@ void sunplus_gcm394_base_device::trigger_systemm_dma(int channel)
else if ((mode & 0x50) == 0x10)
destdelta = -1;
- LOGMASKED(LOG_GCM394_SYSDMA, "%s:possible DMA operation with params mode:%04x source:%08x (word offset) dest:%08x (word offset) length:%08x (words) while csbank is %02x\n", machine().describe_context().c_str(), mode, source, dest, length, m_membankswitch_7810 );
+ LOGMASKED(LOG_GCM394_SYSDMA, "%s:possible DMA operation with params mode:%04x source:%08x (word offset) dest:%08x (word offset) length:%08x (words) while csbank is %02x\n", machine().describe_context(), mode, source, dest, length, m_membankswitch_7810 );
// wrlshunt transfers ROM to RAM, all RAM write addresses have 0x800000 in the destination set
@@ -224,6 +367,10 @@ void sunplus_gcm394_base_device::trigger_systemm_dma(int channel)
if (mem.read_word(0x4abe7) == 0x4840)
mem.write_word(0x4abe7, 0x4841); // camp rock IRQ? wait hack
+ //if (mem.read_word(0x37244) == 0x4845)
+ // mem.write_word(0x37244, 0x4840); // hannah montana guitar force service mode
+
+
// clear params after operation
@@ -406,7 +553,6 @@ void sunplus_gcm394_base_device::chipselect_csx_memory_device_control_w(offs_t o
logerror("CS%d set to size: %02x (%08x words) md: %01x %s warat: %01x wait: %01x\n", offset, cs_size, (cs_size+1)*0x10000, cs_md, md[cs_md], cs_warat, cs_wait);
-
m_cs_callback(m_782x[0], m_782x[1], m_782x[2], m_782x[3], m_782x[4]);
}
@@ -431,8 +577,7 @@ uint16_t sunplus_gcm394_base_device::ioarea_7860_porta_r()
void sunplus_gcm394_base_device::ioarea_7860_porta_w(uint16_t data)
{
LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7860_porta_w %04x\n", machine().describe_context(), data);
- if (m_porta_out)
- m_porta_out(data);
+ m_porta_out(data);
}
uint16_t sunplus_gcm394_base_device::ioarea_7861_porta_buffer_r()
@@ -487,16 +632,13 @@ uint16_t sunplus_gcm394_base_device::ioarea_7869_portb_buffer_r()
void sunplus_gcm394_base_device::ioarea_7869_portb_buffer_w(uint16_t data)
{
LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7869_portb_buffer_w %04x\n", machine().describe_context(), data);
-
- if (m_portb_out) // buffer writes must update output state too, beijuehh requires it for banking
- m_portb_out(data);
+ m_portb_out(data); // buffer writes must update output state too, beijuehh requires it for banking
}
void sunplus_gcm394_base_device::ioarea_7868_portb_w(uint16_t data)
{
LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7868_portb_w %04x\n", machine().describe_context(), data);
- if (m_portb_out)
- m_portb_out(data);
+ m_portb_out(data);
}
uint16_t sunplus_gcm394_base_device::ioarea_786a_portb_direction_r()
@@ -535,8 +677,7 @@ void sunplus_gcm394_base_device::ioarea_7870_portc_w(uint16_t data)
{
LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7870_portc_w %04x\n", machine().describe_context(), data);
m_7870 = data;
- if (m_portc_out)
- m_portc_out(data);
+ m_portc_out(data);
}
uint16_t sunplus_gcm394_base_device::ioarea_7871_portc_buffer_r()
@@ -587,9 +728,7 @@ void sunplus_gcm394_base_device::ioarea_7878_portd_w(uint16_t data)
{
LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7878_portd_w %04x\n", machine().describe_context(), data);
//m_7878 = data;
-
- if (m_portd_out)
- m_portd_out(data);
+ m_portd_out(data);
}
uint16_t sunplus_gcm394_base_device::ioarea_7879_portd_buffer_r()
@@ -601,9 +740,7 @@ uint16_t sunplus_gcm394_base_device::ioarea_7879_portd_buffer_r()
void sunplus_gcm394_base_device::ioarea_7879_portd_buffer_w(uint16_t data)
{
LOGMASKED(LOG_GCM394_IO, "%s:sunplus_gcm394_base_device::ioarea_7879_portd_buffer_w %04x\n", machine().describe_context(), data);
-
- if (m_portd_out) // buffer writes must update output state too, beijuehh requires it for banking
- m_portd_out(data);
+ m_portd_out(data); // buffer writes must update output state too, beijuehh requires it for banking
}
@@ -1450,23 +1587,7 @@ void sunplus_gcm394_base_device::device_start()
m_cs_callback.resolve();
- m_porta_in.resolve_safe(0);
- m_portb_in.resolve_safe(0);
- m_portc_in.resolve_safe(0);
- m_portd_in.resolve_safe(0);
-
- m_porta_out.resolve();
- m_portb_out.resolve();
- m_portc_out.resolve();
- m_portd_out.resolve();
-
-
- m_space_read_cb.resolve_safe(0);
- m_space_write_cb.resolve();
-
- m_nand_read_cb.resolve_safe(0);
-
- m_unk_timer = timer_alloc(0);
+ m_unk_timer = timer_alloc(FUNC(sunplus_gcm394_base_device::unknown_tick), this);
m_unk_timer->adjust(attotime::never);
save_item(NAME(m_dma_params));
@@ -1665,29 +1786,22 @@ void sunplus_gcm394_base_device::checkirq6()
*/
-void sunplus_gcm394_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(sunplus_gcm394_base_device::unknown_tick)
{
- switch (id)
- {
- case 0:
- {
- m_7935 |= 0x0100;
- set_state_unsynced(UNSP_IRQ6_LINE, ASSERT_LINE);
- //set_state_unsynced(UNSP_IRQ4_LINE, ASSERT_LINE);
+ m_7935 |= 0x0100;
+ set_state_unsynced(UNSP_IRQ6_LINE, ASSERT_LINE);
+ //set_state_unsynced(UNSP_IRQ4_LINE, ASSERT_LINE);
// checkirq6();
- break;
- }
- }
}
-WRITE_LINE_MEMBER(sunplus_gcm394_base_device::audioirq_w)
+void sunplus_gcm394_base_device::audioirq_w(int state)
{
//set_state_unsynced(UNSP_IRQ5_LINE, state);
}
-WRITE_LINE_MEMBER(sunplus_gcm394_base_device::videoirq_w)
+void sunplus_gcm394_base_device::videoirq_w(int state)
{
set_state_unsynced(UNSP_IRQ5_LINE, state);
}
diff --git a/src/devices/machine/generalplus_gpl16250soc.h b/src/devices/machine/generalplus_gpl16250soc.h
index 095b0692352..f50f2eeef60 100644
--- a/src/devices/machine/generalplus_gpl16250soc.h
+++ b/src/devices/machine/generalplus_gpl16250soc.h
@@ -27,33 +27,6 @@ public:
{
}
- sunplus_gcm394_base_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock, address_map_constructor internal) :
- unsp_20_device(mconfig, type, tag, owner, clock, internal),
- device_mixer_interface(mconfig, *this, 2),
- m_screen(*this, finder_base::DUMMY_TAG),
- m_spg_video(*this, "spgvideo"),
- m_spg_audio(*this, "spgaudio"),
- m_internalrom(*this, "internal"),
- m_mainram(*this, "mainram"),
- m_porta_in(*this),
- m_portb_in(*this),
- m_portc_in(*this),
- m_portd_in(*this),
- m_porta_out(*this),
- m_portb_out(*this),
- m_portc_out(*this),
- m_portd_out(*this),
- m_nand_read_cb(*this),
- m_csbase(0x20000),
- m_cs_space(nullptr),
- m_romtype(0),
- m_space_read_cb(*this),
- m_space_write_cb(*this),
- m_boot_mode(0),
- m_cs_callback(*this, DEVICE_SELF, FUNC(sunplus_gcm394_base_device::default_cs_callback))
- {
- }
-
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_spg_video->screen_update(screen, bitmap, cliprect); }
auto porta_in() { return m_porta_in.bind(); }
@@ -71,7 +44,7 @@ public:
auto nand_read_callback() { return m_nand_read_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER(vblank) { m_spg_video->vblank(state); }
+ void vblank(int state) { m_spg_video->vblank(state); }
virtual void device_add_mconfig(machine_config& config) override;
@@ -95,6 +68,7 @@ public:
inline uint16_t get_ram_addr(uint32_t addr) { return m_mainram[addr]; }
protected:
+ sunplus_gcm394_base_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock, address_map_constructor internal);
virtual void device_start() override;
virtual void device_reset() override;
@@ -194,7 +168,7 @@ protected:
uint16_t m_system_dma_memtype;
devcb_read16 m_nand_read_cb;
- int m_csbase;
+ uint32_t m_csbase;
uint16_t internalrom_lower32_r(offs_t offset);
@@ -347,8 +321,8 @@ private:
void unkarea_7961_w(uint16_t data);
- DECLARE_WRITE_LINE_MEMBER(videoirq_w);
- DECLARE_WRITE_LINE_MEMBER(audioirq_w);
+ void videoirq_w(int state);
+ void audioirq_w(int state);
uint16_t system_7a35_r();
uint16_t system_7a37_r();
@@ -360,7 +334,8 @@ private:
void checkirq6();
emu_timer *m_unk_timer;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(unknown_tick);
inline uint16_t read_space(uint32_t offset);
inline void write_space(uint32_t offset, uint16_t data);
@@ -464,10 +439,47 @@ private:
uint16_t spi_unk_7943_r();
};
+class generalplus_gpspi_direct_device : public sunplus_gcm394_base_device
+{
+public:
+ template <typename T>
+ generalplus_gpspi_direct_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&screen_tag) :
+ generalplus_gpspi_direct_device(mconfig, tag, owner, clock)
+ {
+ m_screen.set_tag(std::forward<T>(screen_tag));
+ //m_csbase = 0x30000;
+ // TODO: is cs_space even used by this type?
+ m_csbase = 0xffffffff;
+ }
+
+ generalplus_gpspi_direct_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ void gpspi_direct_internal_map(address_map &map);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ uint16_t ramread_r(offs_t offset);
+ void ramwrite_w(offs_t offset, uint16_t data);
+ uint16_t spi_direct_7b40_r();
+ uint16_t spi_direct_7b46_r();
+ uint16_t spi_direct_7af0_r();
+ void spi_direct_7af0_w(uint16_t data);
+ uint16_t spi_direct_79f5_r();
+ uint16_t spi_direct_78e8_r();
+ void spi_direct_78e8_w(uint16_t data);
+ uint16_t spi_direct_79f4_r();
+
+ uint16_t m_7af0;
+};
+
DECLARE_DEVICE_TYPE(GCM394, sunplus_gcm394_device)
DECLARE_DEVICE_TYPE(GPAC800, generalplus_gpac800_device)
DECLARE_DEVICE_TYPE(GP_SPISPI, generalplus_gpspispi_device)
+DECLARE_DEVICE_TYPE(GP_SPI_DIRECT, generalplus_gpspi_direct_device)
#endif // MAME_MACHINE_GENERALPLUS_GPL16250SOC_H
diff --git a/src/devices/machine/generalplus_gpl16250soc_video.cpp b/src/devices/machine/generalplus_gpl16250soc_video.cpp
index 4f3a754e43c..b9bdc02351a 100644
--- a/src/devices/machine/generalplus_gpl16250soc_video.cpp
+++ b/src/devices/machine/generalplus_gpl16250soc_video.cpp
@@ -33,7 +33,7 @@ gcm394_base_video_device::gcm394_base_video_device(const machine_config &mconfig
m_video_irq_cb(*this),
m_palette(*this, "palette"),
m_gfxdecode(*this, "gfxdecode"),
- m_space_read_cb(*this),
+ m_space_read_cb(*this, 0),
m_rowscroll(*this, "^rowscroll"),
m_rowzoom(*this, "^rowzoom"),
m_alt_extrasprite_hack(0),
@@ -200,17 +200,13 @@ void gcm394_base_video_device::decodegfx(const char* tag)
void gcm394_base_video_device::device_start()
{
- m_video_irq_cb.resolve();
-
m_maxgfxelement = 0;
// debug helper only
if (memregion(":maincpu"))
decodegfx(":maincpu");
- m_space_read_cb.resolve_safe(0);
-
- m_screenpos_timer = timer_alloc(TIMER_SCREENPOS);
+ m_screenpos_timer = timer_alloc(FUNC(gcm394_base_video_device::screen_pos_reached), this);
m_screenpos_timer->adjust(attotime::never);
save_item(NAME(m_page0_addr_lsb));
@@ -1112,7 +1108,7 @@ void gcm394_base_video_device::check_video_irq()
m_video_irq_cb((m_video_irq_status & m_video_irq_enable) ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE_LINE_MEMBER(gcm394_base_video_device::vblank)
+void gcm394_base_video_device::vblank(int state)
{
if (!state)
{
@@ -1132,27 +1128,20 @@ WRITE_LINE_MEMBER(gcm394_base_video_device::vblank)
}
}
-void gcm394_base_video_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(gcm394_base_video_device::screen_pos_reached)
{
- switch (id)
+ if (m_video_irq_enable & 2)
{
- case TIMER_SCREENPOS:
- {
- if (m_video_irq_enable & 2)
- {
- m_video_irq_status |= 2;
- check_video_irq();
- }
+ m_video_irq_status |= 2;
+ check_video_irq();
+ }
- //printf("firing irq timer\n");
+ //printf("firing irq timer\n");
- m_screen->update_partial(m_screen->vpos());
+ m_screen->update_partial(m_screen->vpos());
- // fire again, jak_dbz pinball needs this
- m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos-19, m_xirqpos));
- break;
- }
- }
+ // fire again, jak_dbz pinball needs this
+ m_screenpos_timer->adjust(m_screen->time_until_pos(m_yirqpos-19, m_xirqpos));
}
diff --git a/src/devices/machine/generalplus_gpl16250soc_video.h b/src/devices/machine/generalplus_gpl16250soc_video.h
index 429e3246e04..e68169898ed 100644
--- a/src/devices/machine/generalplus_gpl16250soc_video.h
+++ b/src/devices/machine/generalplus_gpl16250soc_video.h
@@ -22,7 +22,7 @@ public:
gcm394_base_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
- DECLARE_WRITE_LINE_MEMBER(vblank);
+ void vblank(int state);
auto space_read_callback() { return m_space_read_cb.bind(); }
@@ -134,14 +134,13 @@ public:
uint16_t video_7051_r();
uint16_t video_70e0_prng_r();
- auto write_video_irq_callback() { return m_video_irq_cb.bind(); };
+ auto write_video_irq_callback() { return m_video_irq_cb.bind(); }
virtual void device_add_mconfig(machine_config& config) override;
protected:
- static const device_timer_id TIMER_SCREENPOS = 2;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ TIMER_CALLBACK_MEMBER(screen_pos_reached);
inline void check_video_irq();
diff --git a/src/devices/machine/generic_spi_flash.cpp b/src/devices/machine/generic_spi_flash.cpp
new file mode 100644
index 00000000000..7421004bf2e
--- /dev/null
+++ b/src/devices/machine/generic_spi_flash.cpp
@@ -0,0 +1,199 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+#include "emu.h"
+#include "generic_spi_flash.h"
+
+#define LOG_SPI (1U << 1)
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(GENERIC_SPI_FLASH, generic_spi_flash_device, "generic_spi_flash", "Generic SPI Flash handling")
+
+generic_spi_flash_device::generic_spi_flash_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, GENERIC_SPI_FLASH, tag, owner, clock)
+ , device_nvram_interface(mconfig, *this)
+{
+}
+
+void generic_spi_flash_device::device_start()
+{
+ save_item(NAME(m_spiaddr));
+ save_item(NAME(m_spi_state));
+ save_item(NAME(m_spilatch));
+ save_item(NAME(m_spidir));
+}
+
+void generic_spi_flash_device::device_reset()
+{
+ m_spiaddr = 0;
+ m_spi_state = 0;
+ m_spilatch = 0;
+ m_spidir = false;
+}
+
+void generic_spi_flash_device::write(uint8_t data)
+{
+ if (!m_spidir) // Send to SPI
+ {
+ switch (m_spi_state)
+ {
+ case READY_FOR_COMMAND:
+ if (data == 0x03)
+ {
+ m_spi_state = READY_FOR_ADDRESS2;
+ }
+ else if (data == 0x05)
+ {
+ m_spi_state = READY_FOR_STATUS_READ;
+ }
+ else if (data == 0x0b)
+ {
+ m_spi_state = READY_FOR_HSADDRESS2;
+ }
+ else if (data == 0x06)
+ {
+ // write enable
+ m_spi_state = READY_FOR_COMMAND;
+ }
+ else if (data == 0x04)
+ {
+ // write disable
+ m_spi_state = READY_FOR_COMMAND;
+ }
+ else if (data == 0x02)
+ {
+ // page program
+ m_spi_state = READY_FOR_WRITEADDRESS2;
+ }
+ else if (data == 0x20)
+ {
+ // erase 4k sector
+ m_spi_state = READY_FOR_COMMAND;
+ }
+ else
+ {
+ fatalerror("SPI set to unknown mode %02x\n", data);
+ }
+ break;
+
+ case READY_FOR_WRITEADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_WRITEADDRESS1;
+ break;
+
+ case READY_FOR_WRITEADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_WRITEADDRESS0;
+ break;
+
+ case READY_FOR_WRITEADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ m_spi_state = READY_FOR_WRITE;
+ LOGMASKED(LOG_SPI, "SPI set to page WRITE mode with address %08x\n", m_spiaddr);
+ break;
+
+ case READY_FOR_WRITE:
+ LOGMASKED(LOG_SPI, "Write SPI data %02x\n", data);
+
+ m_spiptr[(m_spiaddr++) & (m_length-1)] = data;
+
+ break;
+
+
+ case READY_FOR_ADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_ADDRESS1;
+ break;
+
+ case READY_FOR_ADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_ADDRESS0;
+ break;
+
+ case READY_FOR_ADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ m_spi_state = READY_FOR_READ;
+ m_spidir = 1;
+ LOGMASKED(LOG_SPI, "SPI set to READ mode with address %08x\n", m_spiaddr);
+ break;
+
+ case READY_FOR_HSADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_HSADDRESS1;
+ break;
+
+ case READY_FOR_HSADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_HSADDRESS0;
+ break;
+
+ case READY_FOR_HSADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ m_spi_state = READY_FOR_HSDUMMY;
+ break;
+
+ case READY_FOR_HSDUMMY:
+ m_spi_state = READY_FOR_READ;
+ m_spidir = 1;
+ LOGMASKED(LOG_SPI, "SPI set to High Speed READ mode with address %08x\n", m_spiaddr);
+ break;
+
+ case READY_FOR_SECTORERASEADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_SECTORERASEADDRESS1;
+ break;
+
+ case READY_FOR_SECTORERASEADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_SECTORERASEADDRESS0;
+ break;
+
+ case READY_FOR_SECTORERASEADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ LOGMASKED(LOG_SPI, "SPI set to Erase Sector with address %08x\n", m_spiaddr);
+ break;
+
+ }
+ }
+ else
+ {
+ if (m_spi_state == READY_FOR_READ)
+ {
+ m_spilatch = m_spiptr[(m_spiaddr++) & (m_length-1)];
+ }
+ else if (m_spi_state == READY_FOR_STATUS_READ)
+ {
+ m_spilatch = 0x00;
+ }
+ else
+ {
+ m_spilatch = 0x00;
+ }
+ }
+}
+
+
+
+void generic_spi_flash_device::nvram_default()
+{
+}
+
+bool generic_spi_flash_device::nvram_read(util::read_stream &file)
+{
+ if (m_spiptr == nullptr)
+ {
+ return false;
+ }
+
+ auto const [err, actual] = util::read(file, m_spiptr, m_length);
+ return !err && (actual == m_length);
+}
+
+bool generic_spi_flash_device::nvram_write(util::write_stream &file)
+{
+ auto const [err, actual] = util::write(file, m_spiptr, m_length);
+ return !err;
+}
+
diff --git a/src/devices/machine/generic_spi_flash.h b/src/devices/machine/generic_spi_flash.h
new file mode 100644
index 00000000000..4c6559fb479
--- /dev/null
+++ b/src/devices/machine/generic_spi_flash.h
@@ -0,0 +1,83 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+#ifndef MAME_MACHINE_GENERIC_SPI_FLASH_H
+#define MAME_MACHINE_GENERIC_SPI_FLASH_H
+
+#pragma once
+
+class generic_spi_flash_device : public device_t,
+ public device_nvram_interface
+{
+public:
+ generic_spi_flash_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock);
+
+ void set_rom_ptr(uint8_t* rom) { m_spiptr = rom; }
+ void set_rom_size(size_t size) { m_length = size; }
+
+ uint8_t read()
+ {
+ return m_spilatch;
+ }
+
+ void set_ready()
+ {
+ m_spi_state = READY_FOR_COMMAND;
+ }
+
+ void dir_w(int state)
+ {
+ m_spidir = state;
+ }
+
+ void write(uint8_t data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_nvram_interface overrides
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+private:
+ enum
+ {
+ READY_FOR_COMMAND = 0x00,
+
+ READY_FOR_ADDRESS2 = 0x01,
+ READY_FOR_ADDRESS1 = 0x02,
+ READY_FOR_ADDRESS0 = 0x03,
+
+ READY_FOR_HSADDRESS2 = 0x04,
+ READY_FOR_HSADDRESS1 = 0x05,
+ READY_FOR_HSADDRESS0 = 0x06,
+ READY_FOR_HSDUMMY = 0x07,
+
+ READY_FOR_WRITEADDRESS2 = 0x08,
+ READY_FOR_WRITEADDRESS1 = 0x09,
+ READY_FOR_WRITEADDRESS0 = 0x0a,
+
+ READY_FOR_SECTORERASEADDRESS2 = 0x0b,
+ READY_FOR_SECTORERASEADDRESS1 = 0x0c,
+ READY_FOR_SECTORERASEADDRESS0 = 0x0d,
+
+ READY_FOR_WRITE = 0x0e,
+
+ READY_FOR_READ = 0x0f,
+ READY_FOR_STATUS_READ = 0x10,
+ };
+
+ uint32_t m_spiaddr;
+ uint8_t m_spi_state;
+ uint8_t m_spilatch;
+ bool m_spidir;
+
+ uint8_t* m_spiptr;
+ size_t m_length;
+};
+
+DECLARE_DEVICE_TYPE(GENERIC_SPI_FLASH, generic_spi_flash_device)
+
+#endif // MAME_MACHINE_GENERIC_SPI_FLASH_H
diff --git a/src/devices/machine/genpc.cpp b/src/devices/machine/genpc.cpp
index d9706309225..b0e57789932 100644
--- a/src/devices/machine/genpc.cpp
+++ b/src/devices/machine/genpc.cpp
@@ -4,11 +4,10 @@
machine/genpc.cpp
-
***************************************************************************/
#include "emu.h"
-#include "machine/genpc.h"
+#include "genpc.h"
#include "imagedev/cassette.h"
#include "machine/i8255.h"
@@ -16,6 +15,7 @@
#include "machine/pit8253.h"
#include "machine/ram.h"
#include "sound/spkrdev.h"
+
#include "speaker.h"
@@ -55,7 +55,7 @@ void ibm5160_mb_device::pc_page_w(offs_t offset, uint8_t data)
}
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dma_hrq_changed )
+void ibm5160_mb_device::pc_dma_hrq_changed(int state)
{
m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
@@ -126,7 +126,7 @@ void ibm5160_mb_device::pc_dma8237_0_dack_w(uint8_t data)
}
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dma8237_out_eop )
+void ibm5160_mb_device::pc_dma8237_out_eop(int state)
{
m_cur_eop = state == ASSERT_LINE;
if(m_dma_channel != -1)
@@ -149,10 +149,10 @@ void ibm5160_mb_device::pc_select_dma_channel(int channel, bool state)
}
}
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack0_w ) { pc_select_dma_channel(0, state); }
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack1_w ) { pc_select_dma_channel(1, state); }
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack2_w ) { pc_select_dma_channel(2, state); }
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack3_w ) { pc_select_dma_channel(3, state); }
+void ibm5160_mb_device::pc_dack0_w(int state) { pc_select_dma_channel(0, state); }
+void ibm5160_mb_device::pc_dack1_w(int state) { pc_select_dma_channel(1, state); }
+void ibm5160_mb_device::pc_dack2_w(int state) { pc_select_dma_channel(2, state); }
+void ibm5160_mb_device::pc_dack3_w(int state) { pc_select_dma_channel(3, state); }
/*************************************************************
*
@@ -160,13 +160,13 @@ WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack3_w ) { pc_select_dma_channel(3, st
*
*************************************************************/
-WRITE_LINE_MEMBER(ibm5160_mb_device::pc_speaker_set_spkrdata)
+void ibm5160_mb_device::pc_speaker_set_spkrdata(int state)
{
m_pc_spkrdata = state ? 1 : 0;
m_speaker->level_w(m_pc_spkrdata & m_pit_out2);
}
-WRITE_LINE_MEMBER(ibm5160_mb_device::pic_int_w)
+void ibm5160_mb_device::pic_int_w(int state)
{
m_int_callback(state);
}
@@ -178,7 +178,7 @@ WRITE_LINE_MEMBER(ibm5160_mb_device::pic_int_w)
*
*************************************************************/
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_pit8253_out1_changed )
+void ibm5160_mb_device::pc_pit8253_out1_changed(int state)
{
/* Trigger DMA channel #0 */
if ( m_out1 == 0 && state == 1 && m_u73_q2 == 0 )
@@ -190,13 +190,13 @@ WRITE_LINE_MEMBER( ibm5160_mb_device::pc_pit8253_out1_changed )
}
-WRITE_LINE_MEMBER( ibm5160_mb_device::pc_pit8253_out2_changed )
+void ibm5160_mb_device::pc_pit8253_out2_changed(int state)
{
m_pit_out2 = state ? 1 : 0;
m_speaker->level_w(m_pc_spkrdata & m_pit_out2);
}
-WRITE_LINE_MEMBER( ibm5150_mb_device::pc_pit8253_out2_changed )
+void ibm5150_mb_device::pc_pit8253_out2_changed(int state)
{
ibm5160_mb_device::pc_pit8253_out2_changed(state);
m_cassette->output(m_pit_out2 ? 1.0 : -1.0);
@@ -258,7 +258,7 @@ WRITE_LINE_MEMBER( ibm5150_mb_device::pc_pit8253_out2_changed )
* ON ON - one disk drive
*
**********************************************************/
-WRITE_LINE_MEMBER( ibm5150_mb_device::keyboard_clock_w )
+void ibm5150_mb_device::keyboard_clock_w(int state)
{
if (!m_ppi_keyboard_clear && !state && !m_ppi_shift_enable)
{
@@ -268,11 +268,11 @@ WRITE_LINE_MEMBER( ibm5150_mb_device::keyboard_clock_w )
m_ppi_shift_register |= m_ppi_data_signal << 7;
m_pic8259->ir1_w(m_ppi_shift_enable);
- m_pc_kbdc->data_write_from_mb(!m_ppi_shift_enable);
+ m_kbddata_callback(!m_ppi_shift_enable);
}
}
-WRITE_LINE_MEMBER( ec1841_mb_device::keyboard_clock_w )
+void ec1841_mb_device::keyboard_clock_w(int state)
{
if (!m_ppi_keyboard_clear && !state && !m_ppi_shift_enable)
{
@@ -282,11 +282,11 @@ WRITE_LINE_MEMBER( ec1841_mb_device::keyboard_clock_w )
m_ppi_shift_register |= m_ppi_data_signal << 7;
m_pic8259->ir1_w(m_ppi_shift_enable);
- m_pc_kbdc->data_write_from_mb(!m_ppi_shift_enable);
+ m_kbddata_callback(!m_ppi_shift_enable);
}
}
-WRITE_LINE_MEMBER( ibm5160_mb_device::keyboard_clock_w )
+void ibm5160_mb_device::keyboard_clock_w(int state)
{
if (!m_ppi_keyboard_clear && !state && !m_ppi_shift_enable)
{
@@ -296,12 +296,12 @@ WRITE_LINE_MEMBER( ibm5160_mb_device::keyboard_clock_w )
m_ppi_shift_register |= m_ppi_data_signal << 7;
m_pic8259->ir1_w(m_ppi_shift_enable);
- m_pc_kbdc->data_write_from_mb(!m_ppi_shift_enable);
+ m_kbddata_callback(!m_ppi_shift_enable);
}
}
-WRITE_LINE_MEMBER( ibm5160_mb_device::keyboard_data_w )
+void ibm5160_mb_device::keyboard_data_w(int state)
{
m_ppi_data_signal = state;
}
@@ -380,9 +380,9 @@ void ibm5160_mb_device::pc_ppi_portb_w(uint8_t data)
m_pic8259->ir1_w(m_ppi_shift_enable);
}
- m_pc_kbdc->data_write_from_mb(!m_ppi_shift_enable);
+ m_kbddata_callback(!m_ppi_shift_enable);
m_ppi_clock_signal = ( m_ppi_keyb_clock ) ? 1 : 0;
- m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal);
+ m_kbdclk_callback(m_ppi_clock_signal);
}
@@ -399,7 +399,7 @@ void ibm5160_mb_device::nmi_enable_w(uint8_t data)
m_nmi_callback(CLEAR_LINE);
}
-WRITE_LINE_MEMBER( ibm5160_mb_device::iochck_w )
+void ibm5160_mb_device::iochck_w(int state)
{
if (m_nmi_enabled && !state)
m_nmi_callback(ASSERT_LINE);
@@ -450,7 +450,7 @@ void ibm5160_mb_device::device_add_mconfig(machine_config &config)
PIC8259(config, m_pic8259);
m_pic8259->out_int_callback().set(FUNC(ibm5160_mb_device::pic_int_w));
- I8255A(config, m_ppi8255, 0);
+ I8255A(config, m_ppi8255);
m_ppi8255->in_pa_callback().set(FUNC(ibm5160_mb_device::pc_ppi_porta_r));
m_ppi8255->out_pb_callback().set(FUNC(ibm5160_mb_device::pc_ppi_portb_w));
m_ppi8255->in_pc_callback().set(FUNC(ibm5160_mb_device::pc_ppi_portc_r));
@@ -469,10 +469,6 @@ void ibm5160_mb_device::device_add_mconfig(machine_config &config)
m_isabus->drq3_callback().set(m_dma8237, FUNC(am9517a_device::dreq3_w));
m_isabus->iochck_callback().set(FUNC(ibm5160_mb_device::iochck_w));
- PC_KBDC(config, m_pc_kbdc, 0);
- m_pc_kbdc->out_clock_cb().set(FUNC(ibm5160_mb_device::keyboard_clock_w));
- m_pc_kbdc->out_data_cb().set(FUNC(ibm5160_mb_device::keyboard_data_w));
-
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00);
@@ -481,25 +477,25 @@ void ibm5160_mb_device::device_add_mconfig(machine_config &config)
static INPUT_PORTS_START( ibm5160_mb )
PORT_START("DSW0") /* IN1 */
- PORT_DIPNAME( 0xc0, 0x40, "Number of floppy drives")
+ PORT_DIPNAME( 0xc0, 0x40, "Number of floppy drives") PORT_DIPLOCATION("SW1:7,8")
PORT_DIPSETTING( 0x00, "1" )
PORT_DIPSETTING( 0x40, "2" )
PORT_DIPSETTING( 0x80, "3" )
PORT_DIPSETTING( 0xc0, "4" )
- PORT_DIPNAME( 0x30, 0x30, "Graphics adapter")
+ PORT_DIPNAME( 0x30, 0x30, "Graphics adapter") PORT_DIPLOCATION("SW1:5,6")
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_DIPNAME( 0x0c, 0x0c, "RAM banks") PORT_DIPLOCATION("SW1:3,4")
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_DIPNAME( 0x02, 0x00, "8087 installed") PORT_DIPLOCATION("SW1:2")
PORT_DIPSETTING( 0x00, DEF_STR(No) )
PORT_DIPSETTING( 0x02, DEF_STR(Yes) )
- PORT_DIPNAME( 0x01, 0x01, "Boot from floppy")
+ PORT_DIPNAME( 0x01, 0x01, "Boot from floppy") PORT_DIPLOCATION("SW1:1")
PORT_DIPSETTING( 0x01, DEF_STR(Yes) )
PORT_DIPSETTING( 0x00, DEF_STR(No) )
INPUT_PORTS_END
@@ -540,10 +536,11 @@ ibm5160_mb_device::ibm5160_mb_device(
, m_ppi8255(*this, "ppi8255")
, m_speaker(*this, "speaker")
, m_isabus(*this, "isa")
- , m_pc_kbdc(*this, "pc_kbdc")
, m_ram(*this, ":" RAM_TAG)
, m_int_callback(*this)
, m_nmi_callback(*this)
+ , m_kbdclk_callback(*this)
+ , m_kbddata_callback(*this)
{
}
@@ -559,19 +556,6 @@ void ibm5160_mb_device::map(address_map &map)
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void ibm5160_mb_device::device_resolve_objects()
-{
- m_int_callback.resolve_safe();
- m_nmi_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -628,8 +612,6 @@ void ibm5150_mb_device::device_add_mconfig(machine_config &config)
{
ibm5160_mb_device::device_add_mconfig(config);
- subdevice<pc_kbdc_device>("pc_kbdc")->out_clock_cb().set(FUNC(ibm5150_mb_device::keyboard_clock_w));
-
m_ppi8255->out_pb_callback().set(FUNC(ibm5150_mb_device::pc_ppi_portb_w));
m_ppi8255->in_pc_callback().set(FUNC(ibm5150_mb_device::pc_ppi_portc_r));
@@ -639,6 +621,59 @@ void ibm5150_mb_device::device_add_mconfig(machine_config &config)
m_cassette->set_interface("ibm5150_cass");
}
+static INPUT_PORTS_START( ibm5150_mb )
+ PORT_START("DSW0")
+ PORT_DIPNAME( 0xc0, 0x40, "Number of floppy drives") PORT_DIPLOCATION("SW1:7,8")
+ PORT_DIPSETTING( 0x00, "1" )
+ PORT_DIPSETTING( 0x40, "2" )
+ PORT_DIPSETTING( 0x80, "3" )
+ PORT_DIPSETTING( 0xc0, "4" )
+ PORT_DIPNAME( 0x30, 0x30, "Graphics adapter") PORT_DIPLOCATION("SW1:5,6")
+ PORT_DIPSETTING( 0x00, "EGA/VGA" )
+ PORT_DIPSETTING( 0x10, "Color 40x25" )
+ PORT_DIPSETTING( 0x20, "Color 80x25" )
+ PORT_DIPSETTING( 0x30, "Monochrome" )
+ PORT_DIPNAME( 0x0c, 0x0c, "Base RAM size") PORT_DIPLOCATION("SW1:3,4")
+ PORT_DIPSETTING( 0x00, "16K" )
+ PORT_DIPSETTING( 0x04, "32K" )
+ PORT_DIPSETTING( 0x08, "48K" )
+ PORT_DIPSETTING( 0x0c, "64K" )
+ PORT_DIPNAME( 0x02, 0x00, "8087 installed") PORT_DIPLOCATION("SW1:2")
+ PORT_DIPSETTING( 0x00, DEF_STR(No) )
+ PORT_DIPSETTING( 0x02, DEF_STR(Yes) )
+ PORT_DIPNAME( 0x01, 0x01, "Boot from floppy") PORT_DIPLOCATION("SW1:1")
+ PORT_DIPSETTING( 0x01, DEF_STR(Yes) )
+ PORT_DIPSETTING( 0x00, DEF_STR(No) )
+
+ PORT_START("DSW1")
+ PORT_DIPNAME( 0x1f, 0x12, "Extra RAM size") PORT_DIPLOCATION("SW2:1,2,3,4,5")
+ PORT_DIPSETTING( 0x00, "None" )
+ PORT_DIPSETTING( 0x01, "32K" )
+ PORT_DIPSETTING( 0x02, "64K" )
+ PORT_DIPSETTING( 0x03, "96K" )
+ PORT_DIPSETTING( 0x04, "128K" )
+ PORT_DIPSETTING( 0x05, "160K" )
+ PORT_DIPSETTING( 0x06, "192K" )
+ PORT_DIPSETTING( 0x07, "224K" )
+ PORT_DIPSETTING( 0x08, "256K" )
+ PORT_DIPSETTING( 0x09, "288K" )
+ PORT_DIPSETTING( 0x0a, "320K" )
+ PORT_DIPSETTING( 0x0b, "352K" )
+ PORT_DIPSETTING( 0x0c, "384K" )
+ PORT_DIPSETTING( 0x0d, "416K" )
+ PORT_DIPSETTING( 0x0e, "448K" )
+ PORT_DIPSETTING( 0x0f, "480K" )
+ PORT_DIPSETTING( 0x10, "512K" )
+ PORT_DIPSETTING( 0x11, "544K" )
+ PORT_DIPSETTING( 0x12, "576K" )
+ PORT_DIPUNUSED_DIPLOC( 0xe0, 0x00, "SW2:6,7,8" )
+INPUT_PORTS_END
+
+ioport_constructor ibm5150_mb_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ibm5150_mb );
+}
+
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
@@ -664,31 +699,7 @@ uint8_t ibm5150_mb_device::pc_ppi_porta_r()
/* 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 ( m_ram->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;
- }
+ data = ioport("DSW0")->read();
}
else
{
@@ -708,37 +719,11 @@ uint8_t ibm5150_mb_device::pc_ppi_portc_r()
/* KB port C: equipment flags */
if (m_ppi_portc_switch_high)
{
- /* read hi nibble of SW2 */
- data = data & 0xf0;
-
- switch ( m_ram->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 ( m_ram->size() > 960 * 1024 )
- data |= 0x0D;
-
- PIO_LOG(1,"PIO_C_r (hi)",("$%02x\n", data));
+ data = (data & 0xf0) | ioport("DSW1")->read();
}
else
{
- /* read lo nibble of S2 */
- data = (data & 0xf0) | (ioport("DSW0")->read() & 0x0f);
- PIO_LOG(1,"PIO_C_r (lo)",("$%02x\n", data));
+ data = (data & 0xf0) | (ioport("DSW1")->read() >> 4);
}
if ( ! ( m_ppi_portb & 0x08 ) )
@@ -771,7 +756,7 @@ void ibm5150_mb_device::pc_ppi_portb_w(uint8_t data)
{
/* KB controller port B */
m_ppi_portb = data;
- m_ppi_portc_switch_high = data & 0x08;
+ m_ppi_portc_switch_high = data & 0x04;
m_ppi_keyboard_clear = data & 0x80;
m_ppi_keyb_clock = data & 0x40;
m_pit8253->write_gate2(BIT(data, 0));
@@ -787,9 +772,9 @@ void ibm5150_mb_device::pc_ppi_portb_w(uint8_t data)
m_pic8259->ir1_w(m_ppi_shift_enable);
}
- m_pc_kbdc->data_write_from_mb(!m_ppi_shift_enable);
+ m_kbddata_callback(!m_ppi_shift_enable);
m_ppi_clock_signal = ( m_ppi_keyb_clock ) ? 1 : 0;
- m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal);
+ m_kbdclk_callback(m_ppi_clock_signal);
}
//**************************************************************************
@@ -920,8 +905,6 @@ void ec1841_mb_device::device_add_mconfig(machine_config &config)
m_ppi8255->out_pb_callback().set(FUNC(ec1841_mb_device::pc_ppi_portb_w));
m_ppi8255->in_pc_callback().set(FUNC(ec1841_mb_device::pc_ppi_portc_r));
-
- subdevice<pc_kbdc_device>("pc_kbdc")->out_clock_cb().set(FUNC(ec1841_mb_device::keyboard_clock_w));
}
static INPUT_PORTS_START( ec1841_mb )
@@ -1005,9 +988,9 @@ void ec1841_mb_device::pc_ppi_portb_w(uint8_t data)
m_pic8259->ir1_w(m_ppi_shift_enable);
}
- m_pc_kbdc->data_write_from_mb(!m_ppi_shift_enable);
+ m_kbddata_callback(!m_ppi_shift_enable);
m_ppi_clock_signal = ( m_ppi_keyb_clock ) ? 1 : 0;
- m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal);
+ m_kbdclk_callback(m_ppi_clock_signal);
}
uint8_t ec1841_mb_device::pc_ppi_portc_r()
@@ -1050,7 +1033,6 @@ void pc_noppi_mb_device::device_add_mconfig(machine_config &config)
{
ibm5160_mb_device::device_add_mconfig(config);
- config.device_remove("pc_kbdc");
config.device_remove("ppi8255");
}
@@ -1062,11 +1044,23 @@ ioport_constructor pc_noppi_mb_device::device_input_ports() const
return INPUT_PORTS_NAME( pc_noppi_mb );
}
+uint8_t pc_noppi_mb_device::pc_ppi_porta_r()
+{
+ return m_ppi_shift_register;
+}
+
+uint8_t pc_noppi_mb_device::pc_ppi_portb_r()
+{
+ return m_ppi_portb;
+}
+
void pc_noppi_mb_device::map(address_map &map)
{
map(0x0000, 0x000f).rw("dma8237", FUNC(am9517a_device::read), FUNC(am9517a_device::write));
map(0x0020, 0x002f).rw("pic8259", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
map(0x0040, 0x004f).rw("pit8253", FUNC(pit8253_device::read), FUNC(pit8253_device::write));
+ map(0x0060, 0x0060).r(FUNC(pc_noppi_mb_device::pc_ppi_porta_r));
+ map(0x0061, 0x0061).rw(FUNC(pc_noppi_mb_device::pc_ppi_portb_r), FUNC(pc_noppi_mb_device::pc_ppi_portb_w));
map(0x0080, 0x008f).w(FUNC(pc_noppi_mb_device::pc_page_w));
map(0x00a0, 0x00a1).w(FUNC(pc_noppi_mb_device::nmi_enable_w));
}
diff --git a/src/devices/machine/genpc.h b/src/devices/machine/genpc.h
index c1bce1c3072..1fa96086c1f 100644
--- a/src/devices/machine/genpc.h
+++ b/src/devices/machine/genpc.h
@@ -20,7 +20,6 @@
#include "bus/isa/isa.h"
#include "bus/isa/isa_cards.h"
-#include "bus/pc_kbd/pc_kbdc.h"
// ======================> ibm5160_mb_device
@@ -28,18 +27,20 @@ class ibm5160_mb_device : public device_t
{
public:
// construction/destruction
- ibm5160_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ibm5160_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
// inline configuration
template <typename T> void set_cputag(T &&tag)
{
m_maincpu.set_tag(std::forward<T>(tag));
- subdevice<isa8_device>("isa")->set_memspace(std::forward<T>(tag), AS_PROGRAM);
- subdevice<isa8_device>("isa")->set_iospace(std::forward<T>(tag), AS_IO);
+ m_isabus.lookup()->set_memspace(std::forward<T>(tag), AS_PROGRAM);
+ m_isabus.lookup()->set_iospace(std::forward<T>(tag), AS_IO);
}
auto int_callback() { return m_int_callback.bind(); }
auto nmi_callback() { return m_nmi_callback.bind(); }
+ auto kbdclk_callback() { return m_kbdclk_callback.bind(); }
+ auto kbddata_callback() { return m_kbddata_callback.bind(); }
void map(address_map &map);
@@ -48,21 +49,23 @@ public:
void pc_page_w(offs_t offset, uint8_t data);
void nmi_enable_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( pc_speaker_set_spkrdata );
+ void pc_speaker_set_spkrdata(int state);
- DECLARE_WRITE_LINE_MEMBER( pc_pit8253_out1_changed );
- virtual DECLARE_WRITE_LINE_MEMBER( pc_pit8253_out2_changed );
+ void pc_pit8253_out1_changed(int state);
+ virtual void pc_pit8253_out2_changed(int state);
- DECLARE_WRITE_LINE_MEMBER( pic_int_w );
+ void pic_int_w(int state);
+
+ // interface to the keyboard
+ void keyboard_clock_w(int state);
+ void keyboard_data_w(int state);
protected:
ibm5160_mb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- // optional information overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
@@ -76,11 +79,12 @@ protected:
optional_device<i8255_device> m_ppi8255;
required_device<speaker_sound_device> m_speaker;
required_device<isa8_device> m_isabus;
- optional_device<pc_kbdc_device> m_pc_kbdc;
required_device<ram_device> m_ram;
devcb_write_line m_int_callback;
devcb_write_line m_nmi_callback;
+ devcb_write_line m_kbdclk_callback;
+ devcb_write_line m_kbddata_callback;
/* U73 is an LS74 - dual flip flop */
/* Q2 is set by OUT1 from the 8253 and goes to DRQ1 on the 8237 */
@@ -96,23 +100,19 @@ protected:
int m_ppi_portc_switch_high;
int m_ppi_speaker;
int m_ppi_keyboard_clear;
- uint8_t m_ppi_keyb_clock;
- uint8_t m_ppi_portb;
- uint8_t m_ppi_clock_signal;
- uint8_t m_ppi_data_signal;
- uint8_t m_ppi_shift_register;
- uint8_t m_ppi_shift_enable;
-
- // interface to the keyboard
- DECLARE_WRITE_LINE_MEMBER( keyboard_clock_w );
- DECLARE_WRITE_LINE_MEMBER( keyboard_data_w );
+ uint8_t m_ppi_keyb_clock;
+ uint8_t m_ppi_portb;
+ uint8_t m_ppi_clock_signal;
+ uint8_t m_ppi_data_signal;
+ uint8_t m_ppi_shift_register;
+ uint8_t m_ppi_shift_enable;
uint8_t pc_ppi_porta_r();
uint8_t pc_ppi_portc_r();
void pc_ppi_portb_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( pc_dma_hrq_changed );
- DECLARE_WRITE_LINE_MEMBER( pc_dma8237_out_eop );
+ void pc_dma_hrq_changed(int state);
+ void pc_dma8237_out_eop(int state);
uint8_t pc_dma_read_byte(offs_t offset);
void pc_dma_write_byte(offs_t offset, uint8_t data);
uint8_t pc_dma8237_1_dack_r();
@@ -122,11 +122,11 @@ protected:
void pc_dma8237_2_dack_w(uint8_t data);
void pc_dma8237_3_dack_w(uint8_t data);
void pc_dma8237_0_dack_w(uint8_t data);
- 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( iochck_w );
+ void pc_dack0_w(int state);
+ void pc_dack1_w(int state);
+ void pc_dack2_w(int state);
+ void pc_dack3_w(int state);
+ void iochck_w(int state);
void pc_select_dma_channel(int channel, bool state);
};
@@ -141,17 +141,18 @@ class ibm5150_mb_device : public ibm5160_mb_device
{
public:
// construction/destruction
- ibm5150_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ibm5150_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- DECLARE_WRITE_LINE_MEMBER( keyboard_clock_w );
+ void keyboard_clock_w(int state);
- virtual DECLARE_WRITE_LINE_MEMBER( pc_pit8253_out2_changed ) override;
+ virtual void pc_pit8253_out2_changed(int state) override;
protected:
ibm5150_mb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // optional information overrides
+ // device_t implementation
virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
private:
required_device<cassette_image_device> m_cassette;
@@ -170,7 +171,9 @@ class ec1841_mb_device : public ibm5160_mb_device
{
public:
// construction/destruction
- ec1841_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ec1841_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ void keyboard_clock_w(int state);
protected:
ec1841_mb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -183,8 +186,6 @@ protected:
private:
uint8_t pc_ppi_portc_r();
void pc_ppi_portb_w(uint8_t data);
-
- DECLARE_WRITE_LINE_MEMBER( keyboard_clock_w );
};
DECLARE_DEVICE_TYPE(EC1841_MOTHERBOARD, ec1841_mb_device)
@@ -194,7 +195,7 @@ class ec1840_mb_device : public ec1841_mb_device
{
public:
// construction/destruction
- ec1840_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ec1840_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
protected:
// optional information overrides
@@ -214,17 +215,22 @@ class pc_noppi_mb_device : public ibm5160_mb_device
{
public:
// construction/destruction
- pc_noppi_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ pc_noppi_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
uint8_t pit_out2() { return m_pit_out2; } // helper for near-clones with multifunction ics instead of 8255s
void map(address_map &map);
+ uint8_t pc_ppi_portb_r();
+
protected:
pc_noppi_mb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
+
+private:
+ uint8_t pc_ppi_porta_r();
};
DECLARE_DEVICE_TYPE(PCNOPPI_MOTHERBOARD, pc_noppi_mb_device)
diff --git a/src/devices/machine/gt64xxx.cpp b/src/devices/machine/gt64xxx.cpp
index 4b2aab527e5..3f3ea408022 100644
--- a/src/devices/machine/gt64xxx.cpp
+++ b/src/devices/machine/gt64xxx.cpp
@@ -3,11 +3,11 @@
#include "emu.h"
#include "gt64xxx.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_GALILEO (1U << 1)
#define LOG_TIMERS (1U << 2)
#define LOG_DMA (1U << 3)
#define LOG_PCI (1U << 4)
+#define LOG_IRQ (1U << 5)
//#define VERBOSE (LOG_GENERAL | LOG_GALILEO | LOG_TIMERS | LOG_DMA | LOG_PCI)
#include "logmacro.h"
@@ -16,26 +16,28 @@
#define LOGTIMERS(...) LOGMASKED(LOG_TIMERS, __VA_ARGS__)
#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__)
#define LOGPCI(...) LOGMASKED(LOG_PCI, __VA_ARGS__)
+#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__)
-/*************************************
- *
- * Galileo constants
- *
- *************************************/
+//************************************
+//
+// Galileo constants
+//
+//************************************
#define TIMER_PERIOD attotime::from_hz(clock())
#define PCI_BUS_CLOCK 33000000
-// Number of dma words to transfer at a time, real hardware configurable between 8-32
+// Number of dma words (32 bits) to transfer at a time, real hardware configurable between 8-32
#define DMA_BURST_SIZE 32
-#define DMA_TIMER_PERIOD attotime::from_hz(PCI_BUS_CLOCK / 48)
+// DMA will transfer up to DMA_BURST_SIZE*4 bytes every DMA_TIMER_PERIOD seconds
+#define DMA_TIMER_PERIOD attotime::from_hz(PCI_BUS_CLOCK / 64)
-/* Galileo registers - 0x000-0x3ff */
+// Galileo registers - 0x000-0x3ff
#define GREG_CPU_CONFIG (0x000/4)
-#define GREG_R1_0_LO (0x008/4)
-#define GREG_R1_0_HI (0x010/4)
-#define GREG_R3_2_LO (0x018/4)
-#define GREG_R3_2_HI (0x020/4)
+#define GREG_R1_0_LO (0x008/4)
+#define GREG_R1_0_HI (0x010/4)
+#define GREG_R3_2_LO (0x018/4)
+#define GREG_R3_2_HI (0x020/4)
#define GREG_CS_2_0_LO (0x028/4)
#define GREG_CS_2_0_HI (0x030/4)
#define GREG_CS_3_BOOT_LO (0x038/4)
@@ -51,7 +53,7 @@
#define GREG_PCI_MEM1_LO (0x080/4)
#define GREG_PCI_MEM1_HI (0x088/4)
-/* Galileo registers - 0x400-0x7ff */
+// Galileo registers - 0x400-0x7ff
#define GREG_RAS0_LO (0x400/4)
#define GREG_RAS0_HI (0x404/4)
#define GREG_RAS1_LO (0x408/4)
@@ -82,7 +84,7 @@
#define GREG_DEVICE_BOOT (0x46c/4)
#define GREG_ADDRESS_ERROR (0x470/4)
-/* Galileo registers - 0x800-0xbff */
+// Galileo registers - 0x800-0xbff
#define GREG_DMA0_COUNT (0x800/4)
#define GREG_DMA1_COUNT (0x804/4)
#define GREG_DMA2_COUNT (0x808/4)
@@ -110,20 +112,20 @@
#define GREG_DMA_ARBITER (0x860/4)
#define GREG_TIMER_CONTROL (0x864/4)
-/* Galileo registers - 0xc00-0xfff */
+// Galileo registers - 0xc00-0xfff
#define GREG_PCI_COMMAND (0xc00/4)
#define GREG_PCI_TIMEOUT (0xc04/4)
-#define GREG_PCI_R1_0 (0xc08/4)
-#define GREG_PCI_R3_2 (0xc0c/4)
+#define GREG_PCI_R1_0 (0xc08/4)
+#define GREG_PCI_R3_2 (0xc0c/4)
#define GREG_PCI_CS_2_0 (0xc10/4)
#define GREG_PCI_CS_3_BOOT (0xc14/4)
-#define GREG_INT_STATE (0xc18/4)
-#define GREG_INT_MASK (0xc1c/4)
-#define GREG_PCI_INT_MASK (0xc24/4)
+#define GREG_INTR_CAUSE (0xc18/4)
+#define GREG_CPU_MASK (0xc1c/4)
+#define GREG_PCI_MASK (0xc24/4)
#define GREG_CONFIG_ADDRESS (0xcf8/4)
#define GREG_CONFIG_DATA (0xcfc/4)
-/* Galileo interrupts */
+// Galileo interrupts
#define GINT_SUMMARY_SHIFT (0)
#define GINT_MEMOUT_SHIFT (1)
#define GINT_DMAOUT_SHIFT (2)
@@ -193,8 +195,7 @@ void gt64xxx_device::device_start()
{
pci_host_device::device_start();
m_cpu_space = &m_cpu->space(AS_PCI_CONFIG);
- memory_space = &space(AS_PCI_MEM);
- io_space = &space(AS_PCI_IO);
+ set_spaces(&space(AS_PCI_MEM), &space(AS_PCI_IO));
memory_window_start = 0;
memory_window_end = 0xffffffff;
@@ -205,7 +206,7 @@ void gt64xxx_device::device_start()
status = 0x0;
// DMA timer
- m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gt64xxx_device::perform_dma), this));
+ m_dma_timer = timer_alloc(FUNC(gt64xxx_device::perform_dma), this);
// Leave the timer disabled.
m_dma_timer->adjust(attotime::never, 0, DMA_TIMER_PERIOD);
@@ -227,13 +228,15 @@ void gt64xxx_device::device_start()
LOGGALILEO("gt64xxx_device::device_start UPDATE Mapped size: 0x%08X start: 0x1fd00000 end: %08X\n", romSize, 0x1fd00000 + romSize - 1);
}
- /* allocate timers for the galileo */
- m_timer[0].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gt64xxx_device::timer_callback), this));
- m_timer[1].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gt64xxx_device::timer_callback), this));
- m_timer[2].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gt64xxx_device::timer_callback), this));
- m_timer[3].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gt64xxx_device::timer_callback), this));
+ // allocate timers for the galileo
+ m_timer[0].timer = timer_alloc(FUNC(gt64xxx_device::timer_callback), this);
+ m_timer[1].timer = timer_alloc(FUNC(gt64xxx_device::timer_callback), this);
+ m_timer[2].timer = timer_alloc(FUNC(gt64xxx_device::timer_callback), this);
+ m_timer[3].timer = timer_alloc(FUNC(gt64xxx_device::timer_callback), this);
// Save states
+ save_item(NAME(m_irq_pending));
+ save_item(NAME(m_irq_state));
save_item(NAME(m_pci_stall_state));
save_item(NAME(m_retry_count));
save_item(NAME(m_pci_cpu_stalled));
@@ -243,10 +246,8 @@ void gt64xxx_device::device_start()
save_item(NAME(m_cpu_stalled_mem_mask));
save_item(NAME(m_prev_addr));
save_item(NAME(m_reg));
- for (int i = 0; i < ARRAY_LENGTH(m_timer); i++) {
- save_item(NAME(m_timer[i].active), i);
- save_item(NAME(m_timer[i].count), i);
- }
+ save_item(STRUCT_MEMBER(m_timer, active));
+ save_item(STRUCT_MEMBER(m_timer, count));
save_item(NAME(m_dma_active));
// m_ram[4]
save_pointer(NAME(m_ram[0].data()), m_simm_size[0] / 4);
@@ -308,6 +309,8 @@ void gt64xxx_device::device_reset()
map_cpu_space();
regenerate_config_mapping();
+ m_irq_pending = 0;
+ m_irq_state = CLEAR_LINE;
m_pci_stall_state = 0;
m_retry_count = 0;
m_pci_cpu_stalled = 0;
@@ -462,7 +465,7 @@ void gt64xxx_device::reset_all_mappings()
}
// PCI Stalling
-WRITE_LINE_MEMBER(gt64xxx_device::pci_stall)
+void gt64xxx_device::pci_stall(int state)
{
// Reset the retry count once unstalled
if (state==0 && m_pci_stall_state==1) {
@@ -481,13 +484,13 @@ WRITE_LINE_MEMBER(gt64xxx_device::pci_stall)
m_stall_windex--;
index++;
}
- /* resume CPU execution */
+ // resume CPU execution
machine().scheduler().trigger(45678);
- LOGGALILEO("Resuming CPU on PCI Stall\n");
+ LOGMASKED(LOG_GALILEO | LOG_PCI | LOG_DMA, "Resuming CPU on PCI Stall\n");
}
}
- /* set the new state */
+ // set the new state
m_pci_stall_state = state;
}
@@ -522,7 +525,7 @@ void gt64xxx_device::master_mem0_w(offs_t offset, uint32_t data, uint32_t mem_ma
m_stall_windex++;
// Stall cpu until trigger
m_cpu_space->device().execute().spin_until_trigger(45678);
- LOGMASKED(LOG_GALILEO | LOG_PCI, "%s Stalling CPU on PCI Stall\n", machine().describe_context());
+ LOGMASKED(LOG_GALILEO | LOG_PCI | LOG_DMA, "%s Stalling CPU on PCI Stall\n", machine().describe_context());
}
else {
fatalerror("master_mem0_w: m_stall_windex full\n");
@@ -623,7 +626,7 @@ uint32_t gt64xxx_device::cpu_if_r(offs_t offset)
{
uint32_t result = m_reg[offset];
- /* switch off the offset for special cases */
+ // switch off the offset for special cases
switch (offset)
{
case GREG_TIMER0_COUNT:
@@ -662,10 +665,16 @@ uint32_t gt64xxx_device::cpu_if_r(offs_t offset)
result = config_address_r();
break;
- case GREG_INT_STATE:
- case GREG_INT_MASK:
+ case GREG_INTR_CAUSE:
+ LOGIRQ("%s Galileo GREG_INTR_CAUSE read from offset %03X = %08X\n", machine().describe_context(), offset * 4, result);
+ break;
+
+ case GREG_CPU_MASK:
+ LOGGALILEO("%s Galileo GREG_CPU_MASK read from offset %03X = %08X\n", machine().describe_context(), offset*4, result);
+ break;
+
case GREG_TIMER_CONTROL:
-// LOGGALILEO("%s Galileo read from offset %03X = %08X\n", machine().describe_context(), offset*4, result);
+ LOGTIMERS("%s Galileo read from offset %03X = %08X\n", machine().describe_context(), offset*4, result);
break;
default:
@@ -688,7 +697,7 @@ void gt64xxx_device::cpu_if_w(address_space &space, offs_t offset, uint32_t data
uint32_t oldata = m_reg[offset];
COMBINE_DATA(&m_reg[offset]);
- /* switch off the offset for special cases */
+ // switch off the offset for special cases
switch (offset)
{
case GREG_R1_0_LO:
@@ -719,25 +728,33 @@ void gt64xxx_device::cpu_if_w(address_space &space, offs_t offset, uint32_t data
{
int which = offset % 4;
- /* keep the read only activity bit */
+ // keep the read only activity bit
m_reg[offset] &= ~0x4000;
m_reg[offset] |= (oldata & 0x4000);
- /* fetch next record */
+ // fetch next record
if (data & 0x2000)
dma_fetch_next(space, which);
m_reg[offset] &= ~0x2000;
- /* if enabling, start the DMA */
+ // if enabling, start the DMA
if (!(oldata & 0x1000) && (data & 0x1000) && !(m_dma_active & (1<<which)))
{
// Trigger the timer if there are no dma's active
if (m_dma_active==0)
- m_dma_timer->adjust(attotime::zero, 0, DMA_TIMER_PERIOD);
+ m_dma_timer->adjust(DMA_TIMER_PERIOD, 0, DMA_TIMER_PERIOD);
m_dma_active |= (1<< which);
//perform_dma(space, which);
LOGDMA("%s Galileo starting DMA Chan %i\n", machine().describe_context(), which);
}
+ if ((oldata & 0x1000) && !(data & 0x1000) && (m_dma_active & (1 << which)))
+ {
+ m_dma_active &= ~(1 << which);
+ // Turn off the timer
+ m_dma_timer->adjust(attotime::never);
+ LOGDMA("%s Galileo stopping DMA Chan %i\n", machine().describe_context(), which);
+ }
+
LOGGALILEO("%s Galileo write to offset %03X = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
break;
}
@@ -776,7 +793,7 @@ void gt64xxx_device::cpu_if_w(address_space &space, offs_t offset, uint32_t data
timer->count &= 0xffffff;
}
timer->timer->adjust(TIMER_PERIOD * timer->count, which);
- LOGTIMERS("Adjusted timer to fire in %f secs\n", (TIMER_PERIOD * timer->count).as_double());
+ LOGTIMERS("Adjusted timer%d to fire in %f secs\n", which, (TIMER_PERIOD * timer->count).as_double());
}
else if (timer->active && !(data & mask))
{
@@ -784,18 +801,25 @@ void gt64xxx_device::cpu_if_w(address_space &space, offs_t offset, uint32_t data
timer->active = 0;
timer->count = (timer->count > elapsed) ? (timer->count - elapsed) : 0;
timer->timer->adjust(attotime::never, which);
- LOGTIMERS("Disabled timer\n");
+ LOGTIMERS("Disabled timer%d\n", which);
}
}
break;
}
- case GREG_INT_STATE:
- LOGGALILEO("%s Galileo write to IRQ clear = %08X & %08X\n", offset*4, data, mem_mask);
+ case GREG_INTR_CAUSE:
+ LOGIRQ("%s Galileo GREG_INTR_CAUSE write to offset %03X = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
m_reg[offset] = oldata & data;
update_irqs();
break;
+ case GREG_CPU_MASK:
+ LOGGALILEO("%s Galileo GREG_CPU_MASK write to offset %03X = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ // Bits 0, 25:21, 31:30 are read only '0'
+ m_reg[offset] &= 0x3c1ffffe;
+ update_irqs();
+ break;
+
case GREG_CONFIG_DATA:
pci_host_device::config_data_w(offset, data);
LOGGALILEO("%s Galileo PCI config data write to offset %03X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask);
@@ -831,7 +855,6 @@ void gt64xxx_device::cpu_if_w(address_space &space, offs_t offset, uint32_t data
case GREG_DMA0_SOURCE: case GREG_DMA1_SOURCE: case GREG_DMA2_SOURCE: case GREG_DMA3_SOURCE:
case GREG_DMA0_DEST: case GREG_DMA1_DEST: case GREG_DMA2_DEST: case GREG_DMA3_DEST:
case GREG_DMA0_NEXT: case GREG_DMA1_NEXT: case GREG_DMA2_NEXT: case GREG_DMA3_NEXT:
- case GREG_INT_MASK:
LOGGALILEO("%s Galileo write to offset %03X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask);
break;
@@ -841,46 +864,79 @@ void gt64xxx_device::cpu_if_w(address_space &space, offs_t offset, uint32_t data
}
}
-/*************************************
- *
- * Galileo timers & interrupts
- *
- *************************************/
+//************************************
+//
+// Galileo timers & interrupts
+//
+//************************************
void gt64xxx_device::update_irqs()
{
+ // Set cause from pending only if current irq state is clear
+ // seattle hyprdriv freezes (MT07568) if a DMA0 interrupt is sent while the processor is already in the exception handler
+ if (!m_irq_state)
+ {
+ m_reg[GREG_INTR_CAUSE] = m_irq_pending;
+ m_irq_pending = 0;
+ // Set interrupt summary bit
+ if (m_reg[GREG_INTR_CAUSE] & 0xfffffffe)
+ m_reg[GREG_INTR_CAUSE] |= (1 << 0);
+ else
+ m_reg[GREG_INTR_CAUSE] &= ~(1 << 0);
+
+ // set CPU interrupt summary of bits 29:26, 20:1
+ if (m_reg[GREG_INTR_CAUSE] & m_reg[GREG_CPU_MASK] & 0x3c1ffffe)
+ m_reg[GREG_INTR_CAUSE] |= (1 << 30);
+ else
+ m_reg[GREG_INTR_CAUSE] &= ~(1 << 30);
+ }
+ // if any unmasked interrupts are active, we generate
int state = CLEAR_LINE;
-
- /* if any unmasked interrupts are live, we generate */
- if (m_reg[GREG_INT_STATE] & m_reg[GREG_INT_MASK])
+ if (m_reg[GREG_INTR_CAUSE] & m_reg[GREG_CPU_MASK])
state = ASSERT_LINE;
- if (m_irq_num != -1)
+
+ if (m_irq_num != -1 && state != m_irq_state)
+ {
m_cpu->set_input_line(m_irq_num, state);
+ m_irq_state = state;
+ LOGIRQ("gt64xxx_device IRQ %s irqNum: %i cause = %08X mask = %08X time: %s\n", (state == ASSERT_LINE) ? "asserted" : "cleared", m_irq_num, m_reg[GREG_INTR_CAUSE], m_reg[GREG_CPU_MASK], machine().time().as_string());
+ }
- LOGGALILEO("Galileo IRQ %s irqNum: %i state = %08X mask = %08X\n", (state == ASSERT_LINE) ? "asserted" : "cleared", m_irq_num, m_reg[GREG_INT_STATE], m_reg[GREG_INT_MASK]);
+ // Run again if we cleared and there are new interrupts pending
+ if (!state && m_irq_pending)
+ {
+ LOGIRQ("gt64xxx_device new irq pending %08x time: %s\n", m_irq_pending, machine().time().as_string());
+ update_irqs();
+ }
}
-
TIMER_CALLBACK_MEMBER(gt64xxx_device::timer_callback)
{
int which = param;
galileo_timer *timer = &m_timer[which];
- LOGTIMERS("timer %d fired\n", which);
+ LOGTIMERS("timer%d fired at time %s\n", which, machine().time().as_string());
- /* copy the start value from the registers */
+ // copy the start value from the registers
timer->count = m_reg[GREG_TIMER0_COUNT + which];
if (which != 0)
timer->count &= 0xffffff;
- /* if we're a timer, adjust the timer to fire again */
+ // if we're a timer, adjust the timer to fire again
if (m_reg[GREG_TIMER_CONTROL] & (2 << (2 * which)))
- timer->timer->adjust(TIMER_PERIOD * timer->count, which);
+ {
+ // unsure what a 0-length timer should do, but it produces an infinite loop so guard against it
+ u32 effcount = timer->count;
+ if (effcount == 0)
+ effcount = (which != 0) ? 0xffffff : 0xffffffff;
+ timer->timer->adjust(TIMER_PERIOD * effcount, which);
+ }
else
timer->active = timer->count = 0;
- /* trigger the interrupt */
- m_reg[GREG_INT_STATE] |= 1 << (GINT_T0EXP_SHIFT + which);
+ // trigger the interrupt
+ //m_reg[GREG_INTR_CAUSE] |= 1 << (GINT_T0EXP_SHIFT + which);
+ m_irq_pending |= 1 << (GINT_T0EXP_SHIFT + which);
update_irqs();
}
@@ -904,35 +960,30 @@ int gt64xxx_device::dma_fetch_next(address_space &space, int which)
offs_t address = 0;
uint32_t data;
- /* no-op for unchained mode */
+ // no-op for unchained mode
if (!(m_reg[GREG_DMA0_CONTROL + which] & 0x200))
address = m_reg[GREG_DMA0_NEXT + which];
- /* if we hit the end address, signal an interrupt */
+ // exit if we hit the end address
if (address == 0)
{
- if (m_reg[GREG_DMA0_CONTROL + which] & 0x400)
- {
- m_reg[GREG_INT_STATE] |= 1 << (GINT_DMA0COMP_SHIFT + which);
- update_irqs();
- }
m_reg[GREG_DMA0_CONTROL + which] &= ~0x5000;
return 0;
}
- /* fetch the byte count */
+ // fetch the byte count
data = space.read_dword(address); address += 4;
m_reg[GREG_DMA0_COUNT + which] = data;
- /* fetch the source address */
+ // fetch the source address
data = space.read_dword(address); address += 4;
m_reg[GREG_DMA0_SOURCE + which] = data;
- /* fetch the dest address */
+ // fetch the dest address
data = space.read_dword(address); address += 4;
m_reg[GREG_DMA0_DEST + which] = data;
- /* fetch the next record address */
+ // fetch the next record address
data = space.read_dword(address); address += 4;
m_reg[GREG_DMA0_NEXT + which] = data;
return 1;
@@ -956,7 +1007,8 @@ TIMER_CALLBACK_MEMBER (gt64xxx_device::perform_dma)
if (which==-1)
{
logerror("gt64xxx_device::perform_dma Warning! DMA Timer called with no pending DMA. m_dma_active = %08X\n", m_dma_active);
- } else
+ }
+ else
{
offs_t srcaddr = m_reg[GREG_DMA0_SOURCE + which];
offs_t dstaddr = m_reg[GREG_DMA0_DEST + which];
@@ -968,7 +1020,7 @@ TIMER_CALLBACK_MEMBER (gt64xxx_device::perform_dma)
m_reg[GREG_DMA0_CONTROL + which] |= 0x5000;
- /* determine src/dst inc */
+ // determine src/dst inc
switch ((m_reg[GREG_DMA0_CONTROL + which] >> 2) & 3)
{
default:
@@ -984,36 +1036,39 @@ TIMER_CALLBACK_MEMBER (gt64xxx_device::perform_dma)
case 2: dstinc = 0; break;
}
- LOGDMA("Performing DMA%d: src=%08X dst=%08X bytes=%04X sinc=%d dinc=%d\n", which, srcaddr, dstaddr, bytesleft, srcinc, dstinc);
-
- int burstCount = 0;
- /* standard transfer */
- while (bytesleft > 0 && burstCount < DMA_BURST_SIZE)
+ // check for pci stall
+ if (m_pci_stall_state)
{
- if (m_pci_stall_state)
+ uint32_t configRetryCount = (m_reg[GREG_PCI_TIMEOUT] >> 16) & 0xff;
+ m_retry_count++;
+ if (m_retry_count < 4)
+ LOGDMA("%s Stalling DMA on voodoo retry_count: %i max: %i time: %s\n", machine().describe_context(), m_retry_count, configRetryCount, machine().time().as_string());
+ if (configRetryCount == 0)
{
- if (m_retry_count<4) LOGDMA("%s Stalling DMA on voodoo retry_count: %i\n", machine().describe_context(), m_retry_count);
- // Save info
- m_reg[GREG_DMA0_SOURCE + which] = srcaddr;
- m_reg[GREG_DMA0_DEST + which] = dstaddr;
- m_reg[GREG_DMA0_COUNT + which] = (m_reg[GREG_DMA0_COUNT + which] & ~0xffff) | bytesleft;
-
- m_retry_count++;
- uint32_t configRetryCount = (m_reg[GREG_PCI_TIMEOUT] >> 16) & 0xff;
- if (m_retry_count >= configRetryCount && configRetryCount > 0)
- {
- logerror("gt64xxx_device::perform_dma Error! Too many PCI retries. DMA%d: src=%08X dst=%08X bytes=%04X sinc=%d dinc=%d\n", which, srcaddr, dstaddr, bytesleft, srcinc, dstinc);
- // Signal error and abort DMA
- m_dma_active &= ~(1 << which);
- m_retry_count = 0;
- return;
- }
- else
- {
- // Come back later
- return;
- }
+ // Almost infinite retries, but avoid hanging the machine
+ if (configRetryCount == ~0x0)
+ fatalerror("gt64xxx_device::perform_dma Error! PCI is hung. DMA%d: src=%08X dst=%08X bytes=%04X sinc=%d dinc=%d\n", which, srcaddr, dstaddr, bytesleft, srcinc, dstinc);
+ }
+ else if (m_retry_count >= configRetryCount)
+ {
+ logerror("gt64xxx_device::perform_dma Error! Too many PCI retries. DMA%d: src=%08X dst=%08X bytes=%04X sinc=%d dinc=%d\n", which, srcaddr, dstaddr, bytesleft, srcinc, dstinc);
+ // Signal error and abort DMA
+ m_dma_active &= ~(1 << which);
+ m_retry_count = 0;
+ // Turn off the timer
+ m_dma_timer->adjust(attotime::never);
+ // Set the RetryCtr interrupt
+ m_irq_pending |= 1 << (GINT_DMA0COMP_SHIFT + which);
+ update_irqs();
}
+ return;
+ }
+
+ // do the transfer
+ LOGDMA("gt64xxx_device: Starting DMA%d: src=%08X dst=%08X bytes=%04X sinc=%d dinc=%d time=%s\n", which, srcaddr, dstaddr, bytesleft, srcinc, dstinc, machine().time().as_string());
+ int burstCount = 0;
+ while (bytesleft > 0 && burstCount < DMA_BURST_SIZE && !m_pci_stall_state)
+ {
if (bytesleft < 4)
{
dstSpace->write_byte(dstaddr, srcSpace->read_byte(srcaddr));
@@ -1021,7 +1076,8 @@ TIMER_CALLBACK_MEMBER (gt64xxx_device::perform_dma)
dstaddr += dstinc;
bytesleft--;
}
- else {
+ else
+ {
dstSpace->write_dword(dstaddr, srcSpace->read_dword(srcaddr));
srcaddr += srcinc * 4;
dstaddr += dstinc * 4;
@@ -1029,29 +1085,37 @@ TIMER_CALLBACK_MEMBER (gt64xxx_device::perform_dma)
}
burstCount++;
}
- /* not verified, but seems logical these should be updated byte the end */
+ // not verified, but seems logical these should be updated at the end
m_reg[GREG_DMA0_SOURCE + which] = srcaddr;
m_reg[GREG_DMA0_DEST + which] = dstaddr;
m_reg[GREG_DMA0_COUNT + which] = (m_reg[GREG_DMA0_COUNT + which] & ~0xffff) | bytesleft;
- /* if we did not hit zero, punt and return later */
- if (bytesleft != 0)
- {
- return;
- }
- /* interrupt? */
- if (!(m_reg[GREG_DMA0_CONTROL + which] & 0x400))
+ // Check if we are done this descriptor
+ if (bytesleft == 0)
{
- m_reg[GREG_INT_STATE] |= 1 << (GINT_DMA0COMP_SHIFT + which);
- update_irqs();
- }
+ // byte count zero interrupt
+ if (!(m_reg[GREG_DMA0_CONTROL + which] & (1 << 10)))
+ {
+ m_irq_pending |= 1 << (GINT_DMA0COMP_SHIFT + which);
+ update_irqs();
+ }
- // Fetch the next dma for this channel (to be performed next scheduled burst)
- if (dma_fetch_next(*m_cpu_space, which) == 0)
- {
- m_dma_active &= ~(1 << which);
- // Turn off the timer
- m_dma_timer->adjust(attotime::never);
+ // Fetch the next dma for this channel (to be performed next scheduled burst)
+ if ((m_reg[GREG_DMA0_CONTROL + which] & (1 << 9)) || dma_fetch_next(*m_cpu_space, which) == 0)
+ {
+ LOGDMA("gt64xxx_device: Done DMA descriptors time: %s\n", machine().time().as_string());
+ m_dma_active &= ~(1 << which);
+
+ // Turn off the timer
+ m_dma_timer->adjust(attotime::never);
+
+ // no more descriptors interrupt (bit 10) in chained mode (not bit 9)
+ if ((m_reg[GREG_DMA0_CONTROL + which] & (1 << 10)) && !(m_reg[GREG_DMA0_CONTROL + which] & (1 << 9)))
+ {
+ m_irq_pending |= 1 << (GINT_DMA0COMP_SHIFT + which);
+ update_irqs();
+ }
+ }
}
}
}
diff --git a/src/devices/machine/gt64xxx.h b/src/devices/machine/gt64xxx.h
index 8f5bd7db079..9efa29e9dd2 100644
--- a/src/devices/machine/gt64xxx.h
+++ b/src/devices/machine/gt64xxx.h
@@ -29,11 +29,11 @@ public:
void set_autoconfig(int autoconfig) { m_autoconfig = autoconfig; }
void set_irq_num(int irq_num) { m_irq_num = irq_num; }
virtual void config_map(address_map &map) override;
- void set_simm_size(int index, int size) { m_simm_size[index] = size; };
- void set_simm0_size(int size) { m_simm_size[0] = size; };
- void set_simm1_size(int size) { m_simm_size[1] = size; };
+ void set_simm_size(int index, int size) { m_simm_size[index] = size; }
+ void set_simm0_size(int size) { m_simm_size[0] = size; }
+ void set_simm1_size(int size) { m_simm_size[1] = size; }
- DECLARE_WRITE_LINE_MEMBER(pci_stall);
+ void pci_stall(int state);
// pci bus
uint32_t pci_config_r(offs_t offset, uint32_t mem_mask = ~0);
@@ -104,6 +104,8 @@ private:
int m_irq_num;
int m_simm_size[4];
+ int m_irq_state;
+ uint32_t m_irq_pending;
int m_pci_stall_state;
int m_retry_count;
int m_pci_cpu_stalled;
diff --git a/src/devices/machine/gt913_io.cpp b/src/devices/machine/gt913_io.cpp
new file mode 100644
index 00000000000..cc229932174
--- /dev/null
+++ b/src/devices/machine/gt913_io.cpp
@@ -0,0 +1,155 @@
+// license:BSD-3-Clause
+// copyright-holders:Devin Acker
+/***************************************************************************
+ Casio GT913 I/O (HLE)
+
+ TODO:
+ - timer behavior is unverified (see comment in timer_control_w and timer_adjust)
+ - various other unemulated registers
+
+***************************************************************************/
+
+#include "emu.h"
+#include "gt913_io.h"
+#include "cpu/h8/h8.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(GT913_IO_HLE, gt913_io_hle_device, "gt913_io_hle", "Casio GT913F I/O (HLE)")
+
+gt913_io_hle_device::gt913_io_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, GT913_IO_HLE, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_intc(*this, finder_base::DUMMY_TAG)
+{
+ m_timer_irq[0] = m_timer_irq[1] = 0;
+}
+
+void gt913_io_hle_device::device_start()
+{
+ m_timer[0] = timer_alloc(FUNC(gt913_io_hle_device::irq_timer_tick), this);
+ m_timer[1] = timer_alloc(FUNC(gt913_io_hle_device::irq_timer_tick), this);
+
+ save_item(NAME(m_timer_control));
+ save_item(NAME(m_timer_rate));
+ save_item(NAME(m_timer_irq_pending));
+ save_item(NAME(m_adc_enable));
+ save_item(NAME(m_adc_channel));
+ save_item(NAME(m_adc_data));
+}
+
+void gt913_io_hle_device::device_reset()
+{
+ m_timer_control[0] = m_timer_control[1] = 0x00;
+ m_timer_rate[0] = m_timer_rate[1] = 0;
+ m_timer_irq_pending[0] = m_timer_irq_pending[1] = false;
+
+ m_adc_enable = false;
+ m_adc_channel = false;
+ m_adc_data[0] = m_adc_data[1] = 0;
+}
+
+TIMER_CALLBACK_MEMBER(gt913_io_hle_device::irq_timer_tick)
+{
+ m_timer_irq_pending[param] = true;
+ timer_check_irq((offs_t)param);
+}
+
+void gt913_io_hle_device::timer_control_w(offs_t offset, uint8_t data)
+{
+ assert(offset < 2);
+ // TODO: ctk551 clears and sets bit 4 during the respective timer's IRQ, what should this do? pause/restart the timer?
+ m_timer_control[offset] = data;
+ timer_check_irq((int)offset);
+}
+
+uint8_t gt913_io_hle_device::timer_control_r(offs_t offset)
+{
+ assert(offset < 2);
+ return m_timer_control[offset];
+}
+
+void gt913_io_hle_device::timer_rate0_w(uint16_t data)
+{
+ m_timer_rate[0] = data;
+ timer_adjust(0);
+}
+
+void gt913_io_hle_device::timer_rate1_w(uint8_t data)
+{
+ m_timer_rate[1] = data;
+ timer_adjust(1);
+}
+
+void gt913_io_hle_device::timer_adjust(offs_t num)
+{
+ assert(num < 2);
+
+ /*
+ On the CTK-551, this behavior provides the expected rate for timer 0, which is the MIDI PPQN timer.
+ For timer 1, this is less certain, but it seems to provide an auto power off delay only a little
+ longer than the "about six minutes" mentioned in the user manual.
+ */
+ u64 clocks = m_timer_rate[num];
+ if (!clocks)
+ {
+ m_timer[num]->adjust(attotime::never);
+ }
+ else
+ {
+ switch (m_timer_control[num] & 0x7)
+ {
+ default:
+ logerror("unknown timer %u prescaler %u (pc = %04x)\n", num, m_timer_control[num] & 0x7, m_cpu->pc());
+ break;
+ case 0:
+ break;
+ case 2:
+ clocks <<= 9;
+ break;
+ }
+
+ attotime period = m_cpu->clocks_to_attotime(clocks);
+ m_timer[num]->adjust(period, (int)num, period);
+ }
+}
+
+void gt913_io_hle_device::timer_check_irq(offs_t num)
+{
+ assert(num < 2);
+
+ if (BIT(m_timer_control[num], 3) && m_timer_irq_pending[num])
+ {
+ m_intc->internal_interrupt(m_timer_irq[num]);
+ m_timer_irq_pending[num] = false;
+ }
+}
+
+void gt913_io_hle_device::adc_control_w(uint8_t data)
+{
+ m_adc_enable = BIT(data, 2);
+ m_adc_channel = BIT(data, 3);
+ if (m_adc_enable && BIT(data, 0))
+ {
+ if (!m_adc_channel)
+ m_adc_data[0] = m_cpu->do_read_adc(0);
+ else
+ m_adc_data[1] = m_cpu->do_read_adc(1);
+ }
+}
+
+uint8_t gt913_io_hle_device::adc_control_r()
+{
+ return (m_adc_enable << 2) | (m_adc_channel << 3);
+}
+
+uint8_t gt913_io_hle_device::adc_data_r()
+{
+ if (!m_adc_channel)
+ return m_adc_data[0];
+ else
+ return m_adc_data[1];
+}
diff --git a/src/devices/machine/gt913_io.h b/src/devices/machine/gt913_io.h
new file mode 100644
index 00000000000..0346d701230
--- /dev/null
+++ b/src/devices/machine/gt913_io.h
@@ -0,0 +1,73 @@
+// license:BSD-3-Clause
+// copyright-holders: Devin Acker
+/***************************************************************************
+ Casio GT913 I/O (HLE)
+***************************************************************************/
+
+#ifndef MAME_MACHINE_GT913_IO_H
+#define MAME_MACHINE_GT913_IO_H
+
+#pragma once
+
+#include "cpu/h8/h8_intc.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> gt913_kbd_hle_device
+
+class gt913_io_hle_device : public device_t
+{
+public:
+ // construction/destruction
+ gt913_io_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ template<typename T, typename U> gt913_io_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, U &&intc, int t0irq, int t1irq)
+ : gt913_io_hle_device(mconfig, tag, owner)
+ {
+ m_cpu.set_tag(std::forward<T>(cpu));
+ m_intc.set_tag(std::forward<U>(intc));
+ m_timer_irq[0] = t0irq;
+ m_timer_irq[1] = t1irq;
+ }
+
+ void timer_control_w(offs_t offset, uint8_t data);
+ uint8_t timer_control_r(offs_t offset);
+ void timer_rate0_w(uint16_t data);
+ void timer_rate1_w(uint8_t data);
+
+ void adc_control_w(uint8_t data);
+ uint8_t adc_control_r();
+ uint8_t adc_data_r();
+
+protected:
+ void timer_adjust(offs_t num);
+ void timer_check_irq(offs_t num);
+
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ TIMER_CALLBACK_MEMBER(irq_timer_tick);
+
+private:
+ required_device<h8_device> m_cpu;
+ required_device<h8_intc_device> m_intc;
+
+ /* timers */
+ uint8_t m_timer_control[2];
+ uint16_t m_timer_rate[2];
+ int m_timer_irq[2];
+ bool m_timer_irq_pending[2];
+ emu_timer *m_timer[2];
+
+ /* 2x ADC */
+ bool m_adc_enable, m_adc_channel;
+ uint8_t m_adc_data[2];
+
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(GT913_IO_HLE, gt913_io_hle_device)
+
+#endif // MAME_MACHINE_GT913_IO_H
diff --git a/src/devices/machine/gt913_kbd.cpp b/src/devices/machine/gt913_kbd.cpp
new file mode 100644
index 00000000000..8b086b00626
--- /dev/null
+++ b/src/devices/machine/gt913_kbd.cpp
@@ -0,0 +1,104 @@
+// license:BSD-3-Clause
+// copyright-holders:Devin Acker
+/***************************************************************************
+ Casio GT913 keyboard controller (HLE)
+
+ This is the keyboard controller portion of the GT913.
+ The actual keyboard keys (as opposed to console buttons) have two
+ contacts per key, which allows the controller to detect the velocity
+ of the keypress. The detected velocity is read as a 7-bit value
+ from the data port, along with the actual key scan code.
+
+ Right now, velocity is just simulated using an (optional) analog
+ control. The keyboard FIFO size is also basically a guess based on
+ the CTK-551's 16-key polyphony.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "gt913_kbd.h"
+#include "keyboard.ipp"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(GT913_KBD_HLE, gt913_kbd_hle_device, "gt913_kbd_hle", "Casio GT913F keyboard controller (HLE)")
+
+gt913_kbd_hle_device::gt913_kbd_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, GT913_KBD_HLE, tag, owner, clock),
+ device_matrix_keyboard_interface(mconfig, *this, "FI0", "FI1", "FI2", "FI3", "FI4", "FI5", "FI6", "FI7", "FI8", "FI9", "FI10", "KI0", "KI1", "KI2"),
+ m_velocity(*this, "VELOCITY"),
+ m_irq_cb(*this)
+{
+}
+
+void gt913_kbd_hle_device::device_start()
+{
+ save_item(NAME(m_status));
+ save_item(NAME(m_fifo));
+ save_item(NAME(m_fifo_read));
+ save_item(NAME(m_fifo_write));
+}
+
+void gt913_kbd_hle_device::device_reset()
+{
+ m_status = 0x0000;
+ std::memset(m_fifo, 0xff, sizeof(m_fifo));
+ m_fifo_read = m_fifo_write = 0;
+
+ reset_key_state();
+ start_processing(attotime::from_hz(9600));
+}
+
+void gt913_kbd_hle_device::key_add(uint8_t row, uint8_t column, int state)
+{
+ m_fifo[m_fifo_write] = (row << 3) | (column & 7);
+ if (state)
+ m_fifo[m_fifo_write] |= 0x80;
+
+ if (((m_fifo_write + 1) & 15) != m_fifo_read)
+ {
+ (++m_fifo_write) &= 15;
+ update_status();
+ }
+}
+
+void gt913_kbd_hle_device::update_status()
+{
+ if (m_fifo_read == m_fifo_write)
+ m_status &= 0x7fff;
+ else
+ m_status |= 0x8000;
+
+ if (BIT(m_status, 15) && BIT(m_status, 14))
+ m_irq_cb(1);
+ else
+ m_irq_cb(0);
+}
+
+uint16_t gt913_kbd_hle_device::read()
+{
+ if (m_fifo_read == m_fifo_write)
+ return 0xff00;
+
+ uint16_t data = (m_fifo[m_fifo_read] << 8) | m_velocity.read_safe(0x7f);
+
+ if (!machine().side_effects_disabled())
+ {
+ if (m_fifo_read != m_fifo_write)
+ {
+ (++m_fifo_read) &= 15;
+ update_status();
+ }
+ }
+
+ return data;
+}
+
+void gt913_kbd_hle_device::status_w(uint16_t data)
+{
+ m_status = data;
+ update_status();
+}
diff --git a/src/devices/machine/gt913_kbd.h b/src/devices/machine/gt913_kbd.h
new file mode 100644
index 00000000000..3bf2ced327e
--- /dev/null
+++ b/src/devices/machine/gt913_kbd.h
@@ -0,0 +1,56 @@
+// license:BSD-3-Clause
+// copyright-holders: Devin Acker
+/***************************************************************************
+ Casio GT913 keyboard controller (HLE)
+***************************************************************************/
+
+#ifndef MAME_MACHINE_GT913_KBD_H
+#define MAME_MACHINE_GT913_KBD_H
+
+#pragma once
+
+#include "keyboard.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> gt913_kbd_hle_device
+
+class gt913_kbd_hle_device : public device_t, protected device_matrix_keyboard_interface<14>
+{
+public:
+ // construction/destruction
+ gt913_kbd_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ auto irq_cb() { return m_irq_cb.bind(); }
+
+ uint16_t read();
+ void status_w(uint16_t data);
+ uint16_t status_r() { return m_status; }
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_matrix_keyboard_interface overrides
+ virtual void key_make(uint8_t row, uint8_t column) override { key_add(row, column, 0); }
+ virtual void key_break(uint8_t row, uint8_t column) override { key_add(row, column, 1); }
+
+ void key_add(uint8_t row, uint8_t column, int state);
+ void update_status();
+private:
+ optional_ioport m_velocity;
+
+ devcb_write_line m_irq_cb;
+
+ uint16_t m_status;
+ uint8_t m_fifo[16];
+ uint8_t m_fifo_read, m_fifo_write;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(GT913_KBD_HLE, gt913_kbd_hle_device)
+
+#endif // MAME_MACHINE_GT913_KBD_H
diff --git a/src/devices/machine/gt913_snd.cpp b/src/devices/machine/gt913_snd.cpp
new file mode 100644
index 00000000000..803e6443278
--- /dev/null
+++ b/src/devices/machine/gt913_snd.cpp
@@ -0,0 +1,384 @@
+// license:BSD-3-Clause
+// copyright-holders:Devin Acker
+/***************************************************************************
+ Casio GT913 sound (HLE)
+
+ This is the sound portion of the GT913.
+ Up to 24 voices can be mixed into a 16-bit stereo serial bitstream,
+ which is then input to either a serial DAC or a HG51B-based DSP,
+ depending on the model of keyboard.
+
+ The sample format, as well as other details such as the linear interpolation,
+ are covered in these two Japanese patents:
+ https://patents.google.com/patent/JP3603343B2/en
+ https://patents.google.com/patent/JPH07199996A/en
+
+ TODO: Volume envelope rates still need adjusting.
+ (See comment in gt913_sound_device::command_w regarding command 6007)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "gt913_snd.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(GT913_SOUND, gt913_sound_device, "gt913_sound_hle", "Casio GT913F sound")
+
+// expand 2-bit exponent deltas
+const u8 gt913_sound_device::exp_2_to_3[4] = { 0, 1, 2, 7 };
+
+// sign-extend 7-bit sample deltas
+const s8 gt913_sound_device::sample_7_to_8[128] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49,
+ -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33,
+ -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17,
+ -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
+};
+
+// based on SW-10 softsynth
+const u16 gt913_sound_device::volume_ramp[17] =
+{
+ 0x0000, 0x00fa, 0x0231, 0x03b5, 0x0596, 0x07ee, 0x0ad8, 0x0e78,
+ 0x12fa, 0x1897, 0x1f93, 0x2843, 0x3313, 0x4087, 0x5143, 0x6617,
+ 0x8000
+};
+
+gt913_sound_device::gt913_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, GT913_SOUND, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , device_rom_interface(mconfig, *this)
+{
+}
+
+void gt913_sound_device::device_start()
+{
+ /*
+ generate sound at 104 cycles per sample (~= 144.231 kHz sample clock to the DAC)
+ on keyboard models that include a DSP, this also results in a multiple
+ of the 36.058 kHz CPU->DSP sync signal shown in some schematics (WK-1200 and others)
+ */
+ m_stream = stream_alloc(0, 2, clock() / 104);
+
+ save_item(NAME(m_gain));
+ save_item(NAME(m_data));
+
+ save_item(STRUCT_MEMBER(m_voices, m_enable));
+
+ save_item(STRUCT_MEMBER(m_voices, m_addr_start));
+ save_item(STRUCT_MEMBER(m_voices, m_addr_end));
+ save_item(STRUCT_MEMBER(m_voices, m_addr_loop));
+
+ save_item(STRUCT_MEMBER(m_voices, m_addr_current));
+ save_item(STRUCT_MEMBER(m_voices, m_addr_frac));
+ save_item(STRUCT_MEMBER(m_voices, m_pitch));
+
+ save_item(STRUCT_MEMBER(m_voices, m_sample));
+ save_item(STRUCT_MEMBER(m_voices, m_sample_next));
+ save_item(STRUCT_MEMBER(m_voices, m_exp));
+
+ save_item(STRUCT_MEMBER(m_voices, m_volume_data));
+ save_item(STRUCT_MEMBER(m_voices, m_volume_current));
+ save_item(STRUCT_MEMBER(m_voices, m_volume_target));
+ save_item(STRUCT_MEMBER(m_voices, m_volume_rate));
+
+ save_item(STRUCT_MEMBER(m_voices, m_balance));
+ save_item(STRUCT_MEMBER(m_voices, m_gain));
+}
+
+void gt913_sound_device::device_reset()
+{
+ m_gain = 0;
+ std::memset(m_data, 0, sizeof(m_data));
+
+ std::memset(m_voices, 0, sizeof(m_voices));
+}
+
+void gt913_sound_device::sound_stream_update(sound_stream& stream, std::vector<read_stream_view> const& inputs, std::vector<write_stream_view>& outputs)
+{
+ for (int i = 0; i < outputs[0].samples(); i++)
+ {
+ s64 left = 0, right = 0;
+
+ for (auto& voice : m_voices)
+ {
+ update_envelope(voice);
+ if (voice.m_enable)
+ mix_sample(voice, left, right);
+ }
+
+ outputs[0].put_int_clamp(i, (left * m_gain) >> 27, 32678);
+ outputs[1].put_int_clamp(i, (right * m_gain) >> 27, 32768);
+ }
+}
+
+void gt913_sound_device::rom_bank_pre_change()
+{
+ m_stream->update();
+}
+
+void gt913_sound_device::mix_sample(voice_t& voice, s64& left, s64& right)
+{
+ // update sample position
+ voice.m_addr_frac += voice.m_pitch;
+ while (voice.m_enable && voice.m_addr_frac >= (1 << 25))
+ {
+ voice.m_addr_frac -= (1 << 25);
+ update_sample(voice);
+ }
+
+ // interpolate, apply envelope + channel gain, and mix into output
+ const u8 step = (voice.m_addr_frac >> 22) & 7;
+
+ const u8 env = (voice.m_volume_current >> 27);
+ const u16 env_step = (voice.m_volume_current >> 16) & 0x7ff;
+ const u32 env_level = (u32)volume_ramp[env] + (((volume_ramp[env + 1] - volume_ramp[env]) * env_step) >> 11);
+
+ const s64 sample = ((s64)voice.m_sample + (voice.m_sample_next * step / 8)) * voice.m_gain * env_level;
+
+ left += sample * voice.m_balance[0];
+ right += sample * voice.m_balance[1];
+}
+
+void gt913_sound_device::update_envelope(voice_t& voice)
+{
+ if (voice.m_volume_target > voice.m_volume_current
+ && (voice.m_volume_target - voice.m_volume_current) > voice.m_volume_rate)
+ {
+ voice.m_volume_current += voice.m_volume_rate;
+ }
+ else if (voice.m_volume_target < voice.m_volume_current
+ && (voice.m_volume_current - voice.m_volume_target) > voice.m_volume_rate)
+ {
+ voice.m_volume_current -= voice.m_volume_rate;
+ }
+ else
+ {
+ voice.m_volume_current = voice.m_volume_target;
+ }
+}
+
+void gt913_sound_device::update_sample(voice_t& voice)
+{
+ voice.m_sample += voice.m_sample_next;
+
+ if (voice.m_addr_current >= voice.m_addr_end)
+ {
+ if (voice.m_addr_loop == voice.m_addr_end)
+ {
+ voice.m_enable = false;
+ return;
+ }
+
+ voice.m_addr_current = voice.m_addr_loop;
+ /*
+ The last 12 bytes of each sample are a table containing five sample and exponent value pairs
+ for the data words immediately after the loop point. The first pair corresponds to what the
+ sample and exponent value will be _after_ processing the first 16-bit word after the loop,
+ so once we've reached that point, use those values to reload the current sample and exponent
+ */
+ const u32 addr_loop_data = (voice.m_addr_end + 1) & ~1;
+
+ voice.m_sample_next = read_word(addr_loop_data) - voice.m_sample;
+ voice.m_exp = read_word(addr_loop_data + 10) & 7;
+
+ if (!BIT(voice.m_addr_current, 0))
+ {
+ /*
+ the loop data represents the state after applying both samples in a 16-bit word,
+ so if we're looping to the first of the two samples, compensate for the second one
+ */
+ const u16 word = read_word(voice.m_addr_current);
+ const s16 delta = sample_7_to_8[word >> 9];
+ voice.m_sample_next -= delta * (1 << voice.m_exp);
+ }
+ }
+ else
+ {
+ /*
+ For all other samples, just get the next sample delta value.
+ For even-numbered samples, also update the exponent/shift value.
+ */
+ const u16 word = read_word(voice.m_addr_current & ~1);
+ s16 delta = 0;
+
+ if (!BIT(voice.m_addr_current, 0))
+ {
+ voice.m_exp += exp_2_to_3[word & 3];
+ voice.m_exp &= 7;
+ delta = sample_7_to_8[(word >> 2) & 0x7f];
+ }
+ else
+ {
+ delta = sample_7_to_8[word >> 9];
+ }
+ voice.m_sample_next = delta * (1 << voice.m_exp);
+ }
+
+ voice.m_addr_current++;
+}
+
+void gt913_sound_device::data_w(offs_t offset, u16 data)
+{
+ assert(offset < 3);
+ m_data[offset] = data;
+}
+
+u16 gt913_sound_device::data_r(offs_t offset)
+{
+ assert(offset < 3);
+ return m_data[offset];
+}
+
+void gt913_sound_device::command_w(u16 data)
+{
+ m_stream->update();
+
+ const uint8_t voicenum = (data & 0x1f00) >> 8;
+ const uint16_t voicecmd = data & 0x60ff;
+
+ if (data == 0x0012)
+ {
+ m_gain = m_data[0] & 0x3f;
+ return;
+ }
+ else if (voicenum >= 24)
+ {
+ return;
+ }
+
+ auto& voice = m_voices[voicenum];
+ if (voicecmd == 0x0008) // voice data write commands
+ {
+ /*
+ sample start addresses seem to need to be word-aligned to decode properly
+ (see: ctk551 "Trumpet" patch, which will have a bad exponent value otherwise)
+ this apparently doesn't apply to end/loop addresses, though, or else samples
+ may loop badly or even become noticeably detuned
+ TODO: is the LSB of start addresses supposed to indicate something else, then?
+ */
+ voice.m_addr_start = (m_data[1] | (m_data[2] << 16)) & 0x3ffffe;
+ }
+ else if (voicecmd == 0x0000)
+ {
+ voice.m_addr_end = (m_data[0] | (m_data[1] << 16)) & 0x3fffff;
+ }
+ else if (voicecmd == 0x2000)
+ {
+ voice.m_addr_loop = (m_data[0] | (m_data[1] << 16)) & 0x3fffff;
+ }
+ else if (voicecmd == 0x200a)
+ {
+ /* TODO: what does bit 3 of data[2] do? ctk551 sets it unconditionally */
+ voice.m_exp = m_data[2] & 7;
+ }
+ else if (voicecmd == 0x200b)
+ {
+ bool enable = BIT(m_data[2], 7);
+ if (enable && !m_voices[voicenum].m_enable)
+ {
+ voice.m_addr_current = voice.m_addr_start;
+ voice.m_addr_frac = 0;
+ voice.m_volume_current = 0;
+ voice.m_sample = voice.m_sample_next = 0;
+ }
+
+ voice.m_enable = enable;
+ }
+ else if (voicecmd == 0x4004)
+ {
+ voice.m_balance[0] = (m_data[1] & 0xe0) >> 5;
+ voice.m_balance[1] = (m_data[1] & 0x1c) >> 2;
+ }
+ else if (voicecmd == 0x4005)
+ {
+ /*
+ for pitch, data[1] apparently contains both the most and least significant of 4 bytes,
+ with data0 in the middle. strange, but apparently correct (see higher octaves of ctk551 E.Piano2)
+ */
+ voice.m_pitch = (m_data[1] << 24) | (m_data[0] << 8) | (m_data[1] >> 8);
+ }
+ else if (voicecmd == 0x6006)
+ {
+ /*
+ per-voice gain used for normalizing samples
+ currently treated such that the lower 3 bits are fractional
+ */
+ voice.m_gain = m_data[1] & 0xff;
+ }
+ else if (voicecmd == 0x6007)
+ {
+ // logerror("voice %u volume %u rate %u\n", voicenum, (m_data[0] >> 8), m_data[0] & 0xff);
+
+ voice.m_volume_data = m_data[0];
+ voice.m_volume_target = (m_data[0] & 0x7f00) << 16;
+
+ // referenced from the SW-10 softsynth
+ u8 base = m_data[0] & 0xff;
+ u8 shift = base >> 5;
+ switch (shift)
+ {
+ case 0:
+ shift = base >> 2;
+ base &= 3;
+ break;
+
+ case 1:
+ shift = 8;
+ base &= 0x1f;
+ break;
+
+ default:
+ shift += 6;
+ base = (base & 0x1f) | 0x20;
+ break;
+ }
+ /*
+ this part is less certain - the overall rate needs adjusting based on
+ the sample rate difference between this and the softsynth.
+ it's probably not exact, but it sounds okay
+ */
+ voice.m_volume_rate = (base * 3) << (shift + 5);
+ }
+ else if (voicecmd == 0x2028) // voice data read commands
+ {
+ /*
+ data0 is used to determine if it's time to start the next part of the volume envelope or not
+ */
+ m_data[0] = voice.m_volume_current >> 16;
+ /*
+ data1 is used to read consecutive output samples and detect zero crossings when
+ applying volume or expression changes to a MIDI channel
+ */
+ m_data[1] = voice.m_sample;
+ }
+ else if (voicecmd == 0x6020)
+ {
+ /*
+ AP-10 sometimes issues this command, then clears the low byte of data0,
+ and then issues command 0x6007 with the result (to pause an envelope?)
+ */
+ m_data[0] = voice.m_volume_data;
+ }
+ else
+ {
+ logerror("unknown sound write %04x (data: %04x %04x %04x)\n", data, m_data[0], m_data[1], m_data[2]);
+ }
+}
+
+u16 gt913_sound_device::status_r()
+{
+ /*
+ ctk551 reads the current gain level out of the lower 6 bits and ignores the rest
+ it's unknown what, if anything, the other bits are supposed to contain
+ */
+ return m_gain & 0x3f;
+}
diff --git a/src/devices/machine/gt913_snd.h b/src/devices/machine/gt913_snd.h
new file mode 100644
index 00000000000..4c5bfd4a153
--- /dev/null
+++ b/src/devices/machine/gt913_snd.h
@@ -0,0 +1,88 @@
+// license:BSD-3-Clause
+// copyright-holders: Devin Acker
+/***************************************************************************
+ Casio GT913 sound (HLE)
+***************************************************************************/
+
+#ifndef MAME_AUDIO_GT913_H
+#define MAME_AUDIO_GT913_H
+
+#pragma once
+
+#include "dirom.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> gt913_sound_device
+
+class gt913_sound_device : public device_t,
+ public device_sound_interface,
+ public device_rom_interface<21, 1, 0, ENDIANNESS_BIG>
+{
+public:
+ static constexpr feature_type imperfect_features() { return feature::SOUND; }
+
+ // construction/destruction
+ gt913_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ void data_w(offs_t offset, u16 data);
+ u16 data_r(offs_t offset);
+ void command_w(u16 data);
+ u16 status_r();
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_sound_interface overrides
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+ // device_rom_interface overrides
+ virtual void rom_bank_pre_change() override;
+
+private:
+ sound_stream *m_stream;
+
+ u8 m_gain;
+ u16 m_data[3];
+
+ static const u8 exp_2_to_3[4];
+ static const s8 sample_7_to_8[128];
+ static const u16 volume_ramp[17];
+
+ struct voice_t
+ {
+ bool m_enable;
+
+ u32 m_addr_start;
+ u32 m_addr_end;
+ u32 m_addr_loop;
+
+ u32 m_addr_current;
+ u32 m_addr_frac, m_pitch;
+
+ s16 m_sample, m_sample_next;
+ u8 m_exp;
+
+ u16 m_volume_data;
+ u32 m_volume_current, m_volume_target;
+ u32 m_volume_rate;
+
+ u8 m_balance[2];
+ u8 m_gain;
+ };
+
+ void mix_sample(voice_t& voice, s64& left, s64& right);
+ void update_envelope(voice_t& voice);
+ void update_sample(voice_t& voice);
+
+ voice_t m_voices[24];
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(GT913_SOUND, gt913_sound_device)
+
+#endif // MAME_AUDIO_GT913_H
diff --git a/src/devices/machine/hd63450.cpp b/src/devices/machine/hd63450.cpp
index 86d8a9e101c..e0b5e3cdd2f 100644
--- a/src/devices/machine/hd63450.cpp
+++ b/src/devices/machine/hd63450.cpp
@@ -18,7 +18,7 @@ hd63450_device::hd63450_device(const machine_config &mconfig, const char *tag, d
: device_t(mconfig, HD63450, tag, owner, clock)
, m_irq_callback(*this)
, m_dma_end(*this)
- , m_dma_read(*this)
+ , m_dma_read(*this, 0)
, m_dma_write(*this)
, m_cpu(*this, finder_base::DUMMY_TAG)
{
@@ -42,15 +42,9 @@ hd63450_device::hd63450_device(const machine_config &mconfig, const char *tag, d
void hd63450_device::device_start()
{
- // resolve callbacks
- m_irq_callback.resolve_safe();
- m_dma_end.resolve_safe();
- m_dma_read.resolve_all();
- m_dma_write.resolve_all();
-
// Initialise timers and registers
for (int x = 0; x < 4; x++)
- m_timer[x] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hd63450_device::dma_transfer_timer), this));
+ m_timer[x] = timer_alloc(FUNC(hd63450_device::dma_transfer_timer), this);
save_item(STRUCT_MEMBER(m_reg, csr));
save_item(STRUCT_MEMBER(m_reg, cer));
@@ -62,6 +56,7 @@ void hd63450_device::device_start()
save_item(STRUCT_MEMBER(m_reg, mar));
save_item(STRUCT_MEMBER(m_reg, dar));
save_item(STRUCT_MEMBER(m_reg, btc));
+ save_item(STRUCT_MEMBER(m_reg, bar));
save_item(STRUCT_MEMBER(m_reg, niv));
save_item(STRUCT_MEMBER(m_reg, eiv));
save_item(STRUCT_MEMBER(m_reg, mfc));
@@ -200,7 +195,7 @@ void hd63450_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
dma_transfer_abort(channel);
if (data & 0x0020) // halt operation
dma_transfer_halt(channel);
- if (data & 0x0040) // continure operation
+ if (data & 0x0040) // continue operation
dma_transfer_continue(channel);
if ((data & 0x0008) == 0)
clear_irq(channel);
@@ -278,7 +273,7 @@ void hd63450_device::dma_transfer_start(int channel)
m_reg[channel].csr &= ~0xe0;
m_reg[channel].csr |= 0x08; // Channel active
m_reg[channel].csr &= ~0x30; // Reset Error and Normal termination bits
- if ((m_reg[channel].ocr & 0x0c) != 0x00) // Array chain or Link array chain
+ if ((m_reg[channel].ocr & 0x0c) == 0x08) // Array chain
{
m_reg[channel].mar = space.read_word(m_reg[channel].bar) << 16;
m_reg[channel].mar |= space.read_word(m_reg[channel].bar+2);
@@ -286,11 +281,22 @@ void hd63450_device::dma_transfer_start(int channel)
if (m_reg[channel].btc > 0)
m_reg[channel].btc--;
}
+ else if ((m_reg[channel].ocr & 0x0c) == 0x0c) // Link array chain
+ {
+ u32 bar = m_reg[channel].bar;
+ m_reg[channel].mar = space.read_word(bar) << 16;
+ m_reg[channel].mar |= space.read_word(bar+2);
+ m_reg[channel].mtc = space.read_word(bar+4);
+ m_reg[channel].bar = space.read_word(bar+6) << 16;
+ m_reg[channel].bar |= space.read_word(bar+8);
+ }
// Burst transfers will halt the CPU until the transfer is complete
- if ((m_reg[channel].dcr & 0xc0) == 0x00) // Burst transfer
+ // max rate transfer hold the bus
+ if (((m_reg[channel].dcr & 0xc0) == 0x00)) // Burst transfer
{
- m_cpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+ if((m_reg[channel].ocr & 3) == 1) // TODO: proper cycle stealing
+ m_cpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
m_timer[channel]->adjust(attotime::zero, channel, m_burst_clock[channel]);
}
else if (!(m_reg[channel].ocr & 2))
@@ -353,9 +359,11 @@ void hd63450_device::single_transfer(int x)
if (!dma_in_progress(x)) // DMA in progress in channel x
return;
+ m_bec = 0;
+
if (m_reg[x].ocr & 0x80) // direction: 1 = device -> memory
{
- if (!m_dma_read[x].isnull())
+ if (!m_dma_read[x].isunset())
{
data = m_dma_read[x](m_reg[x].mar);
if (data == -1)
@@ -395,7 +403,7 @@ void hd63450_device::single_transfer(int x)
}
else // memory -> device
{
- if (!m_dma_write[x].isnull())
+ if (!m_dma_write[x].isunset())
{
data = space.read_byte(m_reg[x].mar);
m_dma_write[x]((offs_t)m_reg[x].mar,data);
@@ -432,6 +440,11 @@ void hd63450_device::single_transfer(int x)
// LOG("DMA#%i: byte transfer %08lx -> %08lx\n",x,m_reg[x].mar,m_reg[x].dar);
}
+ if (m_bec == ERR_BUS)
+ {
+ set_error(x, 9); //assume error in mar, TODO: other errors
+ return;
+ }
// decrease memory transfer counter
if (m_reg[x].mtc > 0)
@@ -452,7 +465,7 @@ void hd63450_device::single_transfer(int x)
{
// End of transfer
LOG("DMA#%i: End of transfer\n",x);
- if ((m_reg[x].ocr & 0x0c) != 0 && m_reg[x].btc > 0)
+ if ((m_reg[x].ocr & 0x0c) == 0x08 && m_reg[x].btc > 0)
{
m_reg[x].btc--;
m_reg[x].bar+=6;
@@ -461,13 +474,31 @@ void hd63450_device::single_transfer(int x)
m_reg[x].mtc = space.read_word(m_reg[x].bar+4);
return;
}
+ else if ((m_reg[x].ocr & 0x0c) == 0x0c && m_reg[x].bar)
+ {
+ u32 bar = m_reg[x].bar;
+ m_reg[x].mar = space.read_word(bar) << 16;
+ m_reg[x].mar |= space.read_word(bar+2);
+ m_reg[x].mtc = space.read_word(bar+4);
+ m_reg[x].bar = space.read_word(bar+6) << 16;
+ m_reg[x].bar |= space.read_word(bar+8);
+ return;
+ }
+ else if (m_reg[x].ccr & 0x40)
+ {
+ m_reg[x].mar = m_reg[x].bar;
+ m_reg[x].mtc = m_reg[x].btc;
+ m_reg[x].csr |= 0x40;
+ set_irq(x);
+ return;
+ }
m_timer[x]->adjust(attotime::never);
m_reg[x].csr |= 0xe0; // channel operation complete, block transfer complete
m_reg[x].csr &= ~0x08; // channel no longer active
m_reg[x].ccr &= ~0xc0;
- // Burst transfer
- if ((m_reg[x].dcr & 0xc0) == 0x00)
+ // Burst transfer or max rate transfer
+ if (((m_reg[x].dcr & 0xc0) == 0x00) || ((m_reg[x].ocr & 3) == 1))
{
m_cpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
}
@@ -484,64 +515,56 @@ void hd63450_device::set_error(int channel, uint8_t code)
m_reg[channel].cer = code;
m_reg[channel].ccr &= ~0xc0;
+ if (((m_reg[channel].dcr & 0xc0) == 0x00) || ((m_reg[channel].ocr & 3) == 1))
+ m_cpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); // if the cpu is halted resume it
set_irq(channel);
}
-WRITE_LINE_MEMBER(hd63450_device::drq0_w)
+void hd63450_device::drq_w(int channel, int state)
{
- bool ostate = m_drq_state[0];
- m_drq_state[0] = state;
+ bool ostate = m_drq_state[channel];
+ m_drq_state[channel] = state;
- if ((m_reg[0].ocr & 2) && (state && !ostate))
+ if ((m_reg[channel].ocr & 2) && (state && !ostate))
{
- // in cycle steal mode drq is supposed to be edge triggered
- single_transfer(0);
- m_timer[0]->adjust(m_our_clock[0], 0, m_our_clock[0]);
+ // in cycle steal mode DRQ is supposed to be edge triggered
+ single_transfer(channel);
+ m_timer[channel]->adjust(m_our_clock[channel], channel, m_our_clock[channel]);
}
else if (!state)
- m_timer[0]->adjust(attotime::never);
+ m_timer[channel]->adjust(attotime::never);
}
-WRITE_LINE_MEMBER(hd63450_device::drq1_w)
+void hd63450_device::pcl_w(int channel, int state)
{
- bool ostate = m_drq_state[1];
- m_drq_state[1] = state;
+ bool ostate = (m_reg[channel].csr & 1);
- if ((m_reg[1].ocr & 2) && (state && !ostate))
- {
- single_transfer(1);
- m_timer[1]->adjust(m_our_clock[1], 1, m_our_clock[1]);
- }
- else if (!state)
- m_timer[1]->adjust(attotime::never);
-}
+ // status can be determined by PCS in CSR regardless of PCL in DCR
+ if (state)
+ m_reg[channel].csr |= 0x01; // PCS
+ else
+ m_reg[channel].csr &= ~0x01;
-WRITE_LINE_MEMBER(hd63450_device::drq2_w)
-{
- bool ostate = m_drq_state[2];
- m_drq_state[2] = state;
-
- if ((m_reg[2].ocr & 2) && (state && !ostate))
- {
- single_transfer(2);
- m_timer[2]->adjust(m_our_clock[2], 2, m_our_clock[2]);
- }
- else if (!state)
- m_timer[2]->adjust(attotime::never);
-}
-
-WRITE_LINE_MEMBER(hd63450_device::drq3_w)
-{
- bool ostate = m_drq_state[3];
- m_drq_state[3] = state;
-
- if ((m_reg[3].ocr & 2) && (state && !ostate))
+ switch (m_reg[channel].dcr & 7)
{
- single_transfer(3);
- m_timer[3]->adjust(m_our_clock[3], 3, m_our_clock[3]);
+ case 0: // status
+ if (!state && ostate)
+ m_reg[channel].csr |= 0x02; // PCT
+ break;
+ case 1: // status with interrupt
+ if (!state && ostate)
+ {
+ m_reg[channel].csr |= 0x02; // PCT
+ set_irq(channel);
+ }
+ break;
+ case 2: // 1/8 start pulse
+ LOG("DMA#%i: PCL write : %d 1/8 starting pulse not implemented\n", channel, state);
+ break;
+ case 3: // abort
+ LOG("DMA#%i: PCL write : %d abort not implemented\n", channel, state);
+ break;
}
- else if (!state)
- m_timer[3]->adjust(attotime::never);
}
void hd63450_device::set_irq(int channel)
diff --git a/src/devices/machine/hd63450.h b/src/devices/machine/hd63450.h
index 5aa17321090..8034ef784d7 100644
--- a/src/devices/machine/hd63450.h
+++ b/src/devices/machine/hd63450.h
@@ -43,12 +43,26 @@ public:
uint16_t read(offs_t offset);
void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- DECLARE_WRITE_LINE_MEMBER(drq0_w);
- DECLARE_WRITE_LINE_MEMBER(drq1_w);
- DECLARE_WRITE_LINE_MEMBER(drq2_w);
- DECLARE_WRITE_LINE_MEMBER(drq3_w);
+ void drq0_w(int state) { drq_w(0, state); }
+ void drq1_w(int state) { drq_w(1, state); }
+ void drq2_w(int state) { drq_w(2, state); }
+ void drq3_w(int state) { drq_w(3, state); }
+ void pcl0_w(int state) { pcl_w(0, state); }
+ void pcl1_w(int state) { pcl_w(1, state); }
+ void pcl2_w(int state) { pcl_w(2, state); }
+ void pcl3_w(int state) { pcl_w(3, state); }
uint8_t iack();
+ enum {
+ ERR_RESET = 0,
+ ERR_FREE_BUS_RETRY = 3,
+ ERR_RETRY = 4,
+ ERR_BUS = 5,
+ ERR_HALT = 6,
+ ERR_NONE= 7
+ };
+ void bec_w(offs_t offset, uint8_t data) { m_bec = data; }
+
void single_transfer(int x);
void set_timer(int channel, const attotime &tm);
@@ -97,6 +111,7 @@ private:
bool m_drq_state[4];
int8_t m_irq_channel;
+ uint8_t m_bec;
// tell if a channel is in use
bool dma_in_progress(int channel) const { return (m_reg[channel].csr & 0x08) != 0; }
@@ -111,6 +126,9 @@ private:
// interrupt helpers
void set_irq(int channel);
void clear_irq(int channel);
+
+ void drq_w(int channel, int state);
+ void pcl_w(int channel, int state);
};
DECLARE_DEVICE_TYPE(HD63450, hd63450_device)
diff --git a/src/devices/machine/hd64610.cpp b/src/devices/machine/hd64610.cpp
index 3b8393b9a11..41482acacfe 100644
--- a/src/devices/machine/hd64610.cpp
+++ b/src/devices/machine/hd64610.cpp
@@ -16,9 +16,10 @@
#include "emu.h"
#include "hd64610.h"
+
#include "coreutil.h"
-#define VERBOSE 1
+#define VERBOSE 0
#include "logmacro.h"
@@ -169,12 +170,8 @@ hd64610_device::hd64610_device(const machine_config &mconfig, const char *tag, d
void hd64610_device::device_start()
{
- // resolve callbacks
- m_out_irq_cb.resolve_safe();
- m_out_1hz_cb.resolve_safe();
-
// allocate timers
- m_counter_timer = timer_alloc(TIMER_UPDATE_COUNTER);
+ m_counter_timer = timer_alloc(FUNC(hd64610_device::update_counter), this);
m_counter_timer->adjust(attotime::from_hz(clock() / 256), 0, attotime::from_hz(clock() / 256));
// state saving
@@ -185,37 +182,32 @@ void hd64610_device::device_start()
//-------------------------------------------------
-// device_timer - handler timer events
+// update_counter - update our count registers
//-------------------------------------------------
-void hd64610_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(hd64610_device::update_counter)
{
- switch (id)
+ if(m_hline_state || (m_regs[REG_CRB] & CRB_S))
{
- case TIMER_UPDATE_COUNTER:
- if(m_hline_state || (m_regs[REG_CRB] & CRB_S))
- {
- m_regs[REG_64HZ]++;
+ m_regs[REG_64HZ]++;
- if (m_regs[REG_64HZ] & 0x80)
- {
- // update seconds
- advance_seconds();
+ if (m_regs[REG_64HZ] & 0x80)
+ {
+ // update seconds
+ advance_seconds();
- // set carry flag
- m_regs[REG_CRA] |= CRA_CF;
+ // set carry flag
+ m_regs[REG_CRA] |= CRA_CF;
- m_regs[REG_64HZ] &= 0x7f;
- }
+ m_regs[REG_64HZ] &= 0x7f;
+ }
- // update 1Hz out
- m_out_1hz_cb(BIT(m_regs[REG_64HZ], 6));
+ // update 1Hz out
+ m_out_1hz_cb(BIT(m_regs[REG_64HZ], 6));
- // update IRQ
- check_alarm();
- set_irq_line();
- }
- break;
+ // update IRQ
+ check_alarm();
+ set_irq_line();
}
}
@@ -232,7 +224,7 @@ void hd64610_device::rtc_clock_updated(int year, int month, int day, int day_of_
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;
+ m_regs[REG_DAY_OF_THE_WEEK] = day_of_week - 1;
check_alarm();
set_irq_line();
@@ -255,9 +247,10 @@ void hd64610_device::nvram_default()
// .nv file
//-------------------------------------------------
-void hd64610_device::nvram_read(emu_file &file)
+bool hd64610_device::nvram_read(util::read_stream &file)
{
- file.read(m_regs, 0x10);
+ auto const [err, actual] = util::read(file, m_regs, 0x10);
+ return !err && (actual == 0x10);
}
@@ -266,9 +259,10 @@ void hd64610_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void hd64610_device::nvram_write(emu_file &file)
+bool hd64610_device::nvram_write(util::write_stream &file)
{
- file.write(m_regs, 0x10);
+ auto const [err, actual] = util::write(file, m_regs, 0x10);
+ return !err;
}
diff --git a/src/devices/machine/hd64610.h b/src/devices/machine/hd64610.h
index 517ff11284f..9dda6ed03e5 100644
--- a/src/devices/machine/hd64610.h
+++ b/src/devices/machine/hd64610.h
@@ -48,15 +48,16 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ TIMER_CALLBACK_MEMBER(update_counter);
private:
void set_irq_line();
@@ -64,8 +65,6 @@ private:
void write_counter(int counter, uint8_t value);
void check_alarm();
- static const device_timer_id TIMER_UPDATE_COUNTER = 0;
-
devcb_write_line m_out_irq_cb;
devcb_write_line m_out_1hz_cb;
diff --git a/src/devices/machine/hdc92x4.cpp b/src/devices/machine/hdc92x4.cpp
index 4354711738f..1ffe1428a27 100644
--- a/src/devices/machine/hdc92x4.cpp
+++ b/src/devices/machine/hdc92x4.cpp
@@ -73,46 +73,46 @@
#include "formats/imageutl.h"
-#define LOG_DETAIL (1U<<1) // More detail
-#define LOG_WARN (1U<<2) // Warning
+#define LOG_DETAIL (1U << 1) // More detail
+#define LOG_WARN (1U << 2) // Warning
// Per-command debugging
-#define LOG_COMMAND (1U<<3)
-#define LOG_SELECT (1U<<4)
-#define LOG_STEP (1U<<5)
-#define LOG_RESTORE (1U<<6)
-#define LOG_SUBSTATES (1U<<7)
-#define LOG_READ (1U<<8)
-#define LOG_WRITE (1U<<9)
-#define LOG_READREG (1U<<10)
-#define LOG_SETREG (1U<<11)
-#define LOG_SETPTR (1U<<12)
-#define LOG_FORMAT (1U<<13)
-#define LOG_READTRACK (1U<<14)
+#define LOG_COMMAND (1U << 3)
+#define LOG_SELECT (1U << 4)
+#define LOG_STEP (1U << 5)
+#define LOG_RESTORE (1U << 6)
+#define LOG_SUBSTATES (1U << 7)
+#define LOG_READ (1U << 8)
+#define LOG_WRITE (1U << 9)
+#define LOG_READREG (1U << 10)
+#define LOG_SETREG (1U << 11)
+#define LOG_SETPTR (1U << 12)
+#define LOG_FORMAT (1U << 13)
+#define LOG_READTRACK (1U << 14)
// Common states
-#define LOG_READID (1U<<15)
-#define LOG_VERIFY (1U<<16)
-#define LOG_TRANSFER (1U<<17)
+#define LOG_READID (1U << 15)
+#define LOG_VERIFY (1U << 16)
+#define LOG_TRANSFER (1U << 17)
// Live states debugging
-#define LOG_LIVE (1U<<18)
-#define LOG_SHIFT (1U<<19)
-#define LOG_SYNC (1U<<20)
+#define LOG_LIVE (1U << 18)
+#define LOG_SHIFT (1U << 19)
+#define LOG_SYNC (1U << 20)
// Misc debugging
-#define LOG_DELAY (1U<<21)
-#define LOG_INT (1U<<22)
-#define LOG_LINES (1U<<23)
-#define LOG_INDEX (1U<<24)
-#define LOG_DMA (1U<<25)
-#define LOG_DONE (1U<<26)
-#define LOG_FAIL (1U<<27)
-#define LOG_AUXBUS (1U<<28)
-#define LOG_HEADER (1U<<29)
-#define LOG_GAPS (1U<<30)
-
-#define VERBOSE ( LOG_GENERAL | LOG_WARN )
+#define LOG_DELAY (1U << 21)
+#define LOG_INT (1U << 22)
+#define LOG_LINES (1U << 23)
+#define LOG_INDEX (1U << 24)
+#define LOG_DMA (1U << 25)
+#define LOG_DONE (1U << 26)
+#define LOG_FAIL (1U << 27)
+#define LOG_AUXBUS (1U << 28)
+#define LOG_HEADER (1U << 29)
+#define LOG_GAPS (1U << 30)
+
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
#include "logmacro.h"
@@ -294,15 +294,6 @@ enum
};
/*
- Timers
-*/
-enum
-{
- GEN_TIMER = 1,
- COM_TIMER
-};
-
-/*
Definition of bits in the Mode register
*/
enum {
@@ -482,7 +473,7 @@ hdc92x4_device::hdc92x4_device(const machine_config &mconfig, device_type type,
m_out_dmarq(*this),
m_out_dip(*this),
m_out_auxbus(*this),
- m_in_dma(*this),
+ m_in_dma(*this, 0),
m_out_dma(*this),
m_initialized(false)
{
@@ -517,6 +508,14 @@ bool hdc92x4_device::fm_mode()
}
/*
+ Tell whether we have timed steps or buffered steps.
+*/
+bool hdc92x4_device::timed_steps()
+{
+ return ((m_register_w[MODE]&MO_STEPRATE)!=0);
+}
+
+/*
Are we back on track 0?
*/
bool hdc92x4_device::on_track00()
@@ -793,7 +792,7 @@ void hdc92x4_device::wait_time(emu_timer *tm, int microsec, int next_substate)
void hdc92x4_device::wait_time(emu_timer *tm, const attotime &delay, int param)
{
- LOGMASKED(LOG_DELAY, "[%s] Delaying by %4.2f microsecs\n", ttsn().c_str(), delay.as_double()*1000000);
+ LOGMASKED(LOG_DELAY, "[%s] Delaying by %4.2f microsecs\n", ttsn(), delay.as_double()*1000000);
tm->adjust(delay);
m_substate = param;
m_state_after_line = UNDEF;
@@ -810,7 +809,7 @@ void hdc92x4_device::wait_line(int line, line_state level, int substate, bool st
if (line == SEEKCOMP_LINE && (seek_complete() == (level==ASSERT_LINE)))
{
- LOGMASKED(LOG_LINES, "SEEK_COMPLETE line is already %d\n", level);
+ LOGMASKED(LOG_STEP, "SEEK_COMPLETE line is already %d\n", level);
}
else
{
@@ -913,7 +912,14 @@ void hdc92x4_device::read_id(int& cont, bool implied_seek, bool wait_seek_comple
// zero -> we're already there
if (m_substate == VERIFY) cont = NEXT;
- else m_track_delta = desired_cylinder() - current_cylinder();
+ else
+ {
+ m_track_delta = desired_cylinder() - current_cylinder();
+ if (m_track_delta > 0)
+ LOGMASKED(LOG_STEP, "Implied seek %d tracks inwards\n", m_track_delta);
+ if (m_track_delta < 0)
+ LOGMASKED(LOG_STEP, "Implied seek %d tracks outwards\n", -m_track_delta);
+ }
break;
@@ -924,7 +930,7 @@ void hdc92x4_device::read_id(int& cont, bool implied_seek, bool wait_seek_comple
if (wait_seek_complete)
{
// We have to wait for SEEK COMPLETE
- LOGMASKED(LOG_SUBSTATES, "Waiting for SEEK COMPLETE\n");
+ LOGMASKED(LOG_STEP, "Waiting for SEEK COMPLETE\n");
wait_line(SEEKCOMP_LINE, ASSERT_LINE, READ_ID_SEEK_COMPLETE, false);
cont = WAIT;
}
@@ -937,7 +943,7 @@ void hdc92x4_device::read_id(int& cont, bool implied_seek, bool wait_seek_comple
break;
}
- LOGMASKED(LOG_SUBSTATES, "substate STEP_ON\n");
+ LOGMASKED(LOG_STEP, "substate STEP_ON\n");
// STEPDIR = 0 -> towards TRK00
set_bits(m_output2, OUT2_STEPDIR, (m_track_delta>0));
set_bits(m_output2, OUT2_STEPPULSE, true);
@@ -946,7 +952,7 @@ void hdc92x4_device::read_id(int& cont, bool implied_seek, bool wait_seek_comple
break;
case READ_ID_STEPOFF:
- LOGMASKED(LOG_SUBSTATES, "substate STEP_OFF\n");
+ LOGMASKED(LOG_STEP, "substate STEP_OFF\n");
set_bits(m_output2, OUT2_STEPPULSE, false);
m_track_delta += (m_track_delta<0)? 1 : -1;
// Return to STEP_ON, check whether there are more steps
@@ -1162,6 +1168,7 @@ void hdc92x4_device::data_transfer(int& cont)
case DATA_TRANSFER_READ:
// OK, sector has been read.
// Check CRC
+ LOGMASKED(LOG_SUBSTATES, "substate DATA_TRANSFER_READ\n");
if (m_live_state.crc != 0)
{
// Set Retry Required flag
@@ -1368,7 +1375,7 @@ void hdc92x4_device::reset_controller()
*/
void hdc92x4_device::drive_deselect()
{
- LOGMASKED(LOG_SELECT, "DESELECT command\n");
+ LOGMASKED(LOG_COMMAND, "DESELECT command\n");
m_selected_drive_number = NODRIVE;
m_output1 = 0x00;
set_command_done(TC_SUCCESS);
@@ -1440,7 +1447,7 @@ void hdc92x4_device::restore_drive()
break;
case STEP_ON:
- LOGMASKED(LOG_SUBSTATES, "[%s] substate STEP_ON\n", ttsn().c_str());
+ LOGMASKED(LOG_RESTORE, "[%s] substate STEP_ON\n", ttsn());
// Increase step count
m_seek_count++;
@@ -1455,7 +1462,7 @@ void hdc92x4_device::restore_drive()
break;
case STEP_OFF:
- LOGMASKED(LOG_SUBSTATES, "[%s] substate STEP_OFF\n", ttsn().c_str());
+ LOGMASKED(LOG_RESTORE, "[%s] substate STEP_OFF\n", ttsn());
set_bits(m_output2, OUT2_STEPPULSE, false);
wait_time(m_timer, step_time(), RESTORE_CHECK);
cont = WAIT;
@@ -1496,7 +1503,7 @@ void hdc92x4_device::step_drive()
if (m_substate == UNDEF)
{
- LOGMASKED(LOG_STEP, "STEP IN/OUT command %02x\n", current_command());
+ LOGMASKED(LOG_COMMAND, "STEP IN/OUT command %02x\n", current_command());
m_substate = STEP_ON;
}
@@ -1671,7 +1678,7 @@ void hdc92x4_device::drive_select()
// Calculate the head load delays
head_load_delay = head_load_delay_enable? m_register_w[DATA] * head_load_timer_increment[m_selected_drive_type] : 0;
- LOGMASKED(LOG_SELECT, "DRIVE SELECT command (%02x): head load delay=%d, type=%d, drive=%d, pout=%02x, step_rate=%d\n", current_command(), head_load_delay, m_selected_drive_type, driveparm&3, m_register_w[RETRY_COUNT]&0x0f, pulse_width() + step_time());
+ LOGMASKED(LOG_COMMAND, "DRIVE SELECT command (%02x): head load delay=%d, type=%d, drive=%d, pout=%02x, step_rate=%d\n", current_command(), head_load_delay, m_selected_drive_type, driveparm&3, m_register_w[RETRY_COUNT]&0x0f, pulse_width() + step_time());
// Copy the DMA registers to registers CURRENT_HEAD, CURRENT_CYLINDER,
// and CURRENT_IDENT. This is required during formatting [1,2]
@@ -1722,7 +1729,7 @@ void hdc92x4_device::drive_select()
void hdc92x4_device::set_register_pointer()
{
m_register_pointer = current_command() & 0xf;
- LOGMASKED(LOG_SETPTR, "SET REGISTER POINTER command; start reg=%d\n", m_register_pointer);
+ LOGMASKED(LOG_COMMAND, "SET REGISTER POINTER command; start reg=%d\n", m_register_pointer);
// The specification does not say anything about the effect of setting an
// invalid value (only "care should be taken")
if (m_register_pointer > 10)
@@ -1753,7 +1760,7 @@ void hdc92x4_device::seek_read_id()
if (m_substate == UNDEF)
{
// Command init
- LOGMASKED(LOG_READ, "SEEK / READ ID command %02x, CHS=(%d,%d,%d)\n", current_command(), desired_cylinder(), desired_head(), desired_sector());
+ LOGMASKED(LOG_COMMAND, "SEEK / READ ID command %02x, CHS=(%d,%d,%d)\n", current_command(), desired_cylinder(), desired_head(), desired_sector());
m_substate = READ_ID;
}
@@ -1827,7 +1834,7 @@ void hdc92x4_device::read_sectors()
{
// Command init
m_logical = (current_command() & 0x04)!=0; // used in VERIFY and DATA TRANSFER substate
- LOGMASKED(LOG_READ, "READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", m_logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector());
+ LOGMASKED(LOG_READ, "[%s] READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", ttsn(), m_logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector());
m_bypass = !m_is_hdc9234 && (current_command() & 0x02)!=0;
m_transfer_enabled = (current_command() & 0x01)!=0;
@@ -1843,7 +1850,7 @@ void hdc92x4_device::read_sectors()
switch (m_substate & 0xf0)
{
case READ_ID:
- read_id(cont, implied_seek, true); // Always check SEEK COMPLETE
+ read_id(cont, implied_seek, !timed_steps()); // Check SEEK COMPLETE when time bits are 000
break;
case VERIFY:
verify(cont); // for physical, only verify the first sector
@@ -1879,7 +1886,7 @@ void hdc92x4_device::read_track()
{
if (m_substate == UNDEF)
{
- LOGMASKED(LOG_READTRACK, "READ TRACK command %02x, head = %d\n", current_command(), desired_head());
+ LOGMASKED(LOG_COMMAND, "READ TRACK command %02x, head = %d\n", current_command(), desired_head());
dma_address_out(m_register_w[DMA23_16], m_register_w[DMA15_8], m_register_w[DMA7_0]);
m_transfer_enabled = (current_command() & 1)!=0;
}
@@ -2003,7 +2010,7 @@ void hdc92x4_device::format_track()
{
if (m_substate == UNDEF)
{
- LOGMASKED(LOG_FORMAT, "FORMAT TRACK command %02x, head = %d\n", current_command(), desired_head());
+ LOGMASKED(LOG_COMMAND, "FORMAT TRACK command %02x, head = %d\n", current_command(), desired_head());
m_substate = WAITINDEX0;
m_deleted = (current_command() & 0x10)!=0;
m_reduced_write_current = (current_command() & 0x08)!=0;
@@ -2118,7 +2125,7 @@ void hdc92x4_device::write_sectors()
{
// Command init
m_logical = (current_command() & 0x20)!=0;
- LOGMASKED(LOG_WRITE, "WRITE SECTORS %s command %02x, CHS=(%d,%d,%d)\n", m_logical? "LOGICAL" : "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector());
+ LOGMASKED(LOG_COMMAND, "WRITE SECTORS %s command %02x, CHS=(%d,%d,%d)\n", m_logical? "LOGICAL" : "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector());
m_multi_sector = (m_register_w[SECTOR_COUNT] != 1);
m_substate = READ_ID;
@@ -2156,7 +2163,7 @@ void hdc92x4_device::write_sectors()
switch (m_substate & 0xf0)
{
case READ_ID:
- read_id(cont, implied_seek, true); // Always check SEEK COMPLETE
+ read_id(cont, implied_seek, !timed_steps()); // Check SEEK COMPLETE when time bits are 000
break;
case VERIFY:
verify(cont);
@@ -2190,17 +2197,9 @@ void hdc92x4_device::write_sectors()
===========================================================================
*/
-std::string hdc92x4_device::tts(const attotime &t)
-{
- char buf[256];
- int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
- return buf;
-}
-
-std::string hdc92x4_device::ttsn()
+std::string hdc92x4_device::ttsn() const
{
- return tts(machine().time());
+ return machine().time().to_string();
}
bool hdc92x4_device::found_mark(int state)
@@ -2245,7 +2244,7 @@ bool hdc92x4_device::found_mark(int state)
*/
void hdc92x4_device::live_start(int state)
{
- LOGMASKED(LOG_LIVE, "[%s] Live start substate=%02x\n", ttsn().c_str(), state);
+ LOGMASKED(LOG_LIVE, "[%s] Live start substate=%02x\n", ttsn(), state);
m_live_state.time = machine().time();
m_live_state.state = state;
m_live_state.next_state = -1;
@@ -2266,7 +2265,7 @@ void hdc92x4_device::live_start(int state)
live_run();
m_last_live_state = UNDEF;
- LOGMASKED(LOG_LIVE, "[%s] Live start end\n", ttsn().c_str()); // delete
+ LOGMASKED(LOG_LIVE, "[%s] Live start end\n", ttsn()); // delete
}
void hdc92x4_device::live_run()
@@ -2292,11 +2291,11 @@ void hdc92x4_device::live_run_until(attotime limit)
if (limit == attotime::never)
{
- LOGMASKED(LOG_LIVE, "[%s live] live_run, live_state=%02x, mode=%s\n", tts(m_live_state.time).c_str(), m_live_state.state, fm_mode()? "FM":"MFM");
+ LOGMASKED(LOG_LIVE, "[%s live] live_run, live_state=%02x, mode=%s\n", m_live_state.time.to_string(), m_live_state.state, fm_mode()? "FM":"MFM");
}
else
{
- LOGMASKED(LOG_LIVE, "[%s live] live_run until %s, live_state=%02x, mode=%s\n", tts(m_live_state.time).c_str(), tts(limit).c_str(), m_live_state.state, fm_mode()? "FM":"MFM");
+ LOGMASKED(LOG_LIVE, "[%s live] live_run until %s, live_state=%02x, mode=%s\n", m_live_state.time.to_string(), limit.to_string(), m_live_state.state, fm_mode()? "FM":"MFM");
}
if (limit == attotime::never)
@@ -2328,7 +2327,7 @@ void hdc92x4_device::live_run_until(attotime limit)
if (m_last_live_state != SEARCH_IDAM)
{
- LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM [limit %s]\n",tts(m_live_state.time).c_str(), tts(limit).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM [limit %s]\n", m_live_state.time.to_string(), limit.to_string());
m_last_live_state = m_live_state.state;
}
@@ -2337,17 +2336,17 @@ void hdc92x4_device::live_run_until(attotime limit)
if (read_one_bit(limit))
{
- LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM limit reached\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM limit reached\n", m_live_state.time.to_string());
return;
}
- // logerror("SEARCH_IDAM\n", tts(m_live_state.time).c_str());
- LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", tts(m_live_state.time).c_str(), m_live_state.shift_reg,
+ // logerror("SEARCH_IDAM\n", m_live_state.time.to_string());
+ LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", m_live_state.time.to_string(), m_live_state.shift_reg,
get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter);
// [1,2]: The ID field sync mark must be found within 33,792 byte times
if (m_live_state.bit_count_total > 33792*16)
{
- LOGMASKED(LOG_LIVE, "[%s live] Sector not found within 33,792 byte times\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Sector not found within 33,792 byte times\n", m_live_state.time.to_string());
// Desired sector not found within time
if (m_substate == VERIFY3)
wait_for_realtime(VERIFY_FAILED);
@@ -2361,7 +2360,7 @@ void hdc92x4_device::live_run_until(attotime limit)
// MFM case
if (m_live_state.shift_reg == 0x4489)
{
- LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n", m_live_state.time.to_string());
preset_crc(m_live_state, 0xa1);
m_live_state.data_separator_phase = false;
m_live_state.bit_counter = 0;
@@ -2374,7 +2373,7 @@ void hdc92x4_device::live_run_until(attotime limit)
// FM case
if (m_live_state.shift_reg == 0xf57e)
{
- LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM: IDAM found [byte count %d]\n", tts(m_live_state.time).c_str(), m_live_state.bit_count_total/16);
+ LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM: IDAM found [byte count %d]\n", m_live_state.time.to_string(), m_live_state.bit_count_total/16);
preset_crc(m_live_state, 0xfe);
m_live_state.data_separator_phase = false;
m_live_state.bit_counter = 0;
@@ -2397,14 +2396,14 @@ void hdc92x4_device::live_run_until(attotime limit)
if (m_last_live_state != READ_TWO_MORE_A1_IDAM)
{
- LOGMASKED(LOG_LIVE, "[%s live] READ_TWO_MORE_A1\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] READ_TWO_MORE_A1\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
// Beyond time limit?
if (read_one_bit(limit)) return;
- LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", tts(m_live_state.time).c_str(), m_live_state.shift_reg,
+ LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", m_live_state.time.to_string(), m_live_state.shift_reg,
get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter);
if (m_live_state.bit_count_total > 33792*16)
@@ -2426,12 +2425,12 @@ void hdc92x4_device::live_run_until(attotime limit)
m_live_state.state = SEARCH_IDAM;
}
else
- LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n", m_live_state.time.to_string());
// Continue
break;
}
- LOGMASKED(LOG_LIVE, "[%s live] Found data value %02X\n",tts(m_live_state.time).c_str(), m_live_state.data_reg);
+ LOGMASKED(LOG_LIVE, "[%s live] Found data value %02X\n", m_live_state.time.to_string(), m_live_state.data_reg);
// Check for ident field (fe, ff, fd, fc)
if ((m_live_state.data_reg & 0xfc) != 0xfc)
@@ -2439,11 +2438,11 @@ void hdc92x4_device::live_run_until(attotime limit)
// This may happen when we accidentally locked onto the DAM. Look for the next IDAM.
if (m_live_state.data_reg == 0xf8 || m_live_state.data_reg == 0xfb)
{
- LOGMASKED(LOG_LIVE, "[%s live] Looks like a DAM; continue to next mark\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Looks like a DAM; continue to next mark\n", m_live_state.time.to_string());
}
else
{
- LOGMASKED(LOG_LIVE, "[%s live] Missing ident data after A1A1A1, and it was not DAM; format corrupt?\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Missing ident data after A1A1A1, and it was not DAM; format corrupt?\n", m_live_state.time.to_string());
}
m_live_state.state = SEARCH_IDAM;
break;
@@ -2459,7 +2458,7 @@ void hdc92x4_device::live_run_until(attotime limit)
case READ_ID_FIELDS_INTO_REGS:
if (m_last_live_state != READ_ID_FIELDS_INTO_REGS)
{
- LOGMASKED(LOG_LIVE, "[%s live] READ_ID_FIELDS_INTO_REGS\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] READ_ID_FIELDS_INTO_REGS\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
@@ -2496,7 +2495,7 @@ void hdc92x4_device::live_run_until(attotime limit)
case SEARCH_DAM:
if (m_last_live_state != SEARCH_DAM)
{
- LOGMASKED(LOG_LIVE, "[%s live] SEARCH_DAM\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] SEARCH_DAM\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
@@ -2505,7 +2504,7 @@ void hdc92x4_device::live_run_until(attotime limit)
if(read_one_bit(limit))
return;
- LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", tts(m_live_state.time).c_str(), m_live_state.shift_reg,
+ LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", m_live_state.time.to_string(), m_live_state.shift_reg,
get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter);
if (!fm_mode())
@@ -2519,7 +2518,7 @@ void hdc92x4_device::live_run_until(attotime limit)
if (m_live_state.bit_counter >= 28*16 && m_live_state.shift_reg == 0x4489)
{
- LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n", m_live_state.time.to_string());
preset_crc(m_live_state, 0xa1);
m_live_state.data_separator_phase = false;
m_live_state.bit_counter = 0;
@@ -2561,14 +2560,14 @@ void hdc92x4_device::live_run_until(attotime limit)
case READ_TWO_MORE_A1_DAM: {
if (m_last_live_state != READ_TWO_MORE_A1_DAM)
{
- LOGMASKED(LOG_LIVE, "[%s live] READ_TWO_MORE_A1_DAM\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] READ_TWO_MORE_A1_DAM\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
if(read_one_bit(limit))
return;
- LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", tts(m_live_state.time).c_str(), m_live_state.shift_reg,
+ LOGMASKED(LOG_SHIFT, "[%s live] shift = %04x data=%02x c=%d\n", m_live_state.time.to_string(), m_live_state.shift_reg,
get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter);
// Repeat until we have collected 16 bits
@@ -2585,12 +2584,12 @@ void hdc92x4_device::live_run_until(attotime limit)
return;
}
else
- LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n", m_live_state.time.to_string());
// Continue
break;
}
- LOGMASKED(LOG_LIVE, "[%s live] Found data value %02X\n",tts(m_live_state.time).c_str(), m_live_state.data_reg);
+ LOGMASKED(LOG_LIVE, "[%s live] Found data value %02X\n", m_live_state.time.to_string(), m_live_state.data_reg);
if ((m_live_state.data_reg & 0xff) == 0xf8)
{
@@ -2620,7 +2619,7 @@ void hdc92x4_device::live_run_until(attotime limit)
{
if (m_last_live_state != READ_SECTOR_DATA)
{
- LOGMASKED(LOG_LIVE, "[%s live] READ_SECTOR_DATA\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] READ_SECTOR_DATA\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
@@ -2645,7 +2644,7 @@ void hdc92x4_device::live_run_until(attotime limit)
// Repeat until we have collected 16 bits
if (m_live_state.bit_counter & 15) break;
- LOGMASKED(LOG_LIVE, "[%s live] Found data value %02X, CRC=%04x\n",tts(m_live_state.time).c_str(), m_live_state.data_reg, m_live_state.crc);
+ LOGMASKED(LOG_LIVE, "[%s live] Found data value %02X, CRC=%04x\n", m_live_state.time.to_string(), m_live_state.data_reg, m_live_state.crc);
int slot = (m_live_state.bit_counter >> 4)-1;
if (slot < sector_size())
@@ -2666,7 +2665,7 @@ void hdc92x4_device::live_run_until(attotime limit)
}
else
{
- LOGMASKED(LOG_LIVE, "[%s live] Sector read completed\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Sector read completed\n", m_live_state.time.to_string());
wait_for_realtime(IDLE);
}
return;
@@ -2678,7 +2677,7 @@ void hdc92x4_device::live_run_until(attotime limit)
case READ_SECTOR_DATA_CONT:
if (m_last_live_state != READ_SECTOR_DATA_CONT)
{
- LOGMASKED(LOG_LIVE, "[%s live] READ_SECTOR_DATA_CONT\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] READ_SECTOR_DATA_CONT\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
@@ -2723,7 +2722,7 @@ void hdc92x4_device::live_run_until(attotime limit)
// 4. Write the sector content and calculate the CRC on the fly
// 5. Write the CRC bytes
- LOGMASKED(LOG_LIVE, "[%s live] WRITE_DAM_AND_SECTOR\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] WRITE_DAM_AND_SECTOR\n", m_live_state.time.to_string());
skip_on_track(m_gap2_size, WRITE_DAM_SYNC);
break;
@@ -2825,10 +2824,14 @@ void hdc92x4_device::live_run_until(attotime limit)
write_on_track(encode((m_live_state.crc >> 8) & 0xff), 1, WRITE_DATA_CRC);
}
else
+ {
// Write a filler byte so that the last CRC bit is saved correctly
// Without, the last bit of the CRC value may be flipped
- write_on_track(encode(0xff), 1, WRITE_DONE);
-
+ // This is an effect of the PLL, not of MFM
+ // Compare with the header CRC, where during formatting, the
+ // CRC bytes are followed by the gap bytes.
+ write_on_track(encode(fm_mode()? 0xff : 0x4e), 1, WRITE_DONE);
+ }
break;
case WRITE_DONE:
@@ -3064,14 +3067,14 @@ void hdc92x4_device::live_run_until(attotime limit)
// The pause is implemented by doing dummy reads on the floppy
if (read_one_bit(limit))
{
- LOGMASKED(LOG_LIVE, "[%s live] return; limit=%s\n", tts(m_live_state.time).c_str(), tts(limit).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] return; limit=%s\n", m_live_state.time.to_string(), limit.to_string());
return;
}
// Repeat until we have collected 16 bits
if ((m_live_state.bit_counter & 15)==0)
{
- LOGMASKED(LOG_DETAIL, "[%s live] Read byte %02x, repeat = %d\n", tts(m_live_state.time).c_str(), m_live_state.data_reg, m_live_state.repeat);
+ LOGMASKED(LOG_DETAIL, "[%s live] Read byte %02x, repeat = %d\n", m_live_state.time.to_string(), m_live_state.data_reg, m_live_state.repeat);
wait_for_realtime(READ_TRACK_NEXT_BYTE);
return;
}
@@ -3154,18 +3157,18 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
if (limit == attotime::never)
{
- LOGMASKED(LOG_LIVE, "[%s live] live_run_hd, live_state=%02x, mode=%s\n", tts(m_live_state.time).c_str(), m_live_state.state, fm_mode()? "FM":"MFM");
+ LOGMASKED(LOG_LIVE, "[%s live] live_run_hd, live_state=%02x, mode=%s\n", m_live_state.time.to_string(), m_live_state.state, fm_mode()? "FM":"MFM");
}
else
{
- LOGMASKED(LOG_LIVE, "[%s live] live_run_hd until %s, live_state=%02x, mode=%s\n", tts(m_live_state.time).c_str(), tts(limit).c_str(), m_live_state.state, fm_mode()? "FM":"MFM");
+ LOGMASKED(LOG_LIVE, "[%s live] live_run_hd until %s, live_state=%02x, mode=%s\n", m_live_state.time.to_string(), limit.to_string(), m_live_state.state, fm_mode()? "FM":"MFM");
}
// We did not specify an upper time bound, so we take the next index pulse
if (limit == attotime::never && m_harddisk != nullptr)
{
limit = m_harddisk->track_end_time();
- LOGMASKED(LOG_LIVE, "[%s live] live_run_hd new limit %s\n", tts(m_live_state.time).c_str(), tts(limit).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] live_run_hd new limit %s\n", m_live_state.time.to_string(), limit.to_string());
}
while (true)
@@ -3175,7 +3178,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
case SEARCH_IDAM:
if (m_last_live_state != SEARCH_IDAM)
{
- LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM [limit %s]\n",tts(m_live_state.time).c_str(), tts(limit).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM [limit %s]\n", m_live_state.time.to_string(), limit.to_string());
m_last_live_state = m_live_state.state;
}
@@ -3184,12 +3187,12 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
if (read_from_mfmhd(limit))
{
- LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM limit reached\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] SEARCH_IDAM limit reached\n", m_live_state.time.to_string());
return;
}
if ((m_live_state.bit_counter & 0x000f)==0)
- LOGMASKED(LOG_LIVE, "[%s live] Read %04x\n", tts(m_live_state.time).c_str(), m_live_state.shift_reg);
+ LOGMASKED(LOG_LIVE, "[%s live] Read %04x\n", m_live_state.time.to_string(), m_live_state.shift_reg);
// [1,2]: The ID field sync mark must be found within 33,792 byte times
if (m_live_state.bit_count_total > 33792*16)
@@ -3199,12 +3202,13 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
wait_for_realtime(VERIFY_FAILED);
else
wait_for_realtime(SEARCH_IDAM_FAILED);
+
return;
}
if (found_mark(SEARCH_IDAM))
{
- LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n", m_live_state.time.to_string());
preset_crc(m_live_state, 0xa1);
m_live_state.data_separator_phase = false;
m_live_state.bit_counter = 0;
@@ -3233,9 +3237,9 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
if ((m_live_state.data_reg & 0xfc) != 0xfc)
{
if (m_live_state.data_reg == 0xf8 || m_live_state.data_reg == 0xfb)
- LOGMASKED(LOG_LIVE, "[%s live] Looks like a DAM; continue to next mark\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Looks like a DAM; continue to next mark\n", m_live_state.time.to_string());
else
- LOGMASKED(LOG_LIVE, "[%s live] Missing ident data after A1, and it was not DAM; format corrupt?\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Missing ident data after A1, and it was not DAM; format corrupt?\n", m_live_state.time.to_string());
m_live_state.state = SEARCH_IDAM;
}
@@ -3250,7 +3254,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
case READ_ID_FIELDS_INTO_REGS:
if (m_last_live_state != READ_ID_FIELDS_INTO_REGS)
{
- LOGMASKED(LOG_LIVE, "[%s live] READ_ID_FIELDS_INTO_REGS\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] READ_ID_FIELDS_INTO_REGS\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
@@ -3278,7 +3282,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
case SEARCH_DAM:
if (m_last_live_state != SEARCH_DAM)
{
- LOGMASKED(LOG_LIVE, "[%s live] SEARCH_DAM\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] SEARCH_DAM\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
set_bits(m_register_r[CHIP_STATUS], CS_DELDATA, false);
@@ -3286,7 +3290,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
if (read_from_mfmhd(limit)) return;
if ((m_live_state.bit_counter & 15)==0)
- LOGMASKED(LOG_LIVE, "[%s live] Read %04x\n", tts(m_live_state.time).c_str(), m_live_state.shift_reg);
+ LOGMASKED(LOG_LIVE, "[%s live] Read %04x\n", m_live_state.time.to_string(), m_live_state.shift_reg);
if (m_live_state.bit_counter > 30*16)
{
@@ -3297,7 +3301,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
if (found_mark(SEARCH_DAM))
{
- LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Found an A1 mark\n", m_live_state.time.to_string());
preset_crc(m_live_state, 0xa1);
m_live_state.data_separator_phase = false;
m_live_state.bit_counter = 0;
@@ -3312,14 +3316,14 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
if ((m_live_state.data_reg & 0xff) == 0xf8)
{
- LOGMASKED(LOG_LIVE, "[%s live] Found deleted data mark F8 after DAM sync\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Found deleted data mark F8 after DAM sync\n", m_live_state.time.to_string());
set_bits(m_register_r[CHIP_STATUS], CS_DELDATA, true);
}
else
{
if ((m_live_state.data_reg & 0xff) != 0xfb)
{
- LOGMASKED(LOG_FAIL, "[%s live] Missing FB/F8 data mark after DAM sync; found %04x\n", tts(m_live_state.time).c_str(), m_live_state.shift_reg);
+ LOGMASKED(LOG_FAIL, "[%s live] Missing FB/F8 data mark after DAM sync; found %04x\n", m_live_state.time.to_string(), m_live_state.shift_reg);
wait_for_realtime(SEARCH_DAM_FAILED);
return;
}
@@ -3336,7 +3340,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
case READ_SECTOR_DATA:
if (m_last_live_state != READ_SECTOR_DATA)
{
- LOGMASKED(LOG_LIVE, "[%s live] READ_SECTOR_DATA\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] READ_SECTOR_DATA\n", m_live_state.time.to_string());
m_last_live_state = m_live_state.state;
}
@@ -3356,7 +3360,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
if (m_live_state.bit_counter & 15) break;
slot = (m_live_state.bit_counter >> 4)-1;
- LOGMASKED(LOG_LIVE, "[%s live] Found data value [%d/%d] = %02X, CRC=%04x\n",tts(m_live_state.time).c_str(), slot, sector_size(), m_live_state.data_reg, m_live_state.crc);
+ LOGMASKED(LOG_LIVE, "[%s live] Found data value [%d/%d] = %02X, CRC=%04x\n", m_live_state.time.to_string(), slot, sector_size(), m_live_state.data_reg, m_live_state.crc);
if (slot < sector_size())
{
@@ -3384,7 +3388,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
}
else
{
- LOGMASKED(LOG_LIVE, "[%s live] Sector read completed\n",tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Sector read completed\n", m_live_state.time.to_string());
wait_for_realtime(IDLE);
}
return;
@@ -3411,7 +3415,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
m_out_dip(ASSERT_LINE);
m_out_dma(0, m_register_r[DATA], 0xff);
- LOGMASKED(LOG_LIVE, "[%s live] Byte %02x sent via DMA\n",tts(m_live_state.time).c_str(), m_register_r[DATA] & 0xff);
+ LOGMASKED(LOG_LIVE, "[%s live] Byte %02x sent via DMA\n", m_live_state.time.to_string(), m_register_r[DATA] & 0xff);
}
m_live_state.state = READ_SECTOR_DATA;
break;
@@ -3422,14 +3426,14 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
// The pause is implemented by doing dummy reads on the hard disk
if (read_from_mfmhd(limit))
{
- LOGMASKED(LOG_LIVE, "[%s live] return; limit=%s\n", tts(m_live_state.time).c_str(), tts(limit).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] return; limit=%s\n", m_live_state.time.to_string(), limit.to_string());
return;
}
// Repeat until we have collected 16 bits
if ((m_live_state.bit_counter & 15)==0)
{
- LOGMASKED(LOG_DETAIL, "[%s live] Read byte %02x, repeat = %d\n", tts(m_live_state.time).c_str(), m_live_state.data_reg, m_live_state.repeat);
+ LOGMASKED(LOG_DETAIL, "[%s live] Read byte %02x, repeat = %d\n", m_live_state.time.to_string(), m_live_state.data_reg, m_live_state.repeat);
wait_for_realtime(READ_TRACK_NEXT_BYTE);
return;
}
@@ -3449,7 +3453,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
case WRITE_TRACK_BYTE:
if (write_to_mfmhd(limit))
{
- LOGMASKED(LOG_LIVE, "[%s live] write limit reached\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] write limit reached\n", m_live_state.time.to_string());
return;
}
@@ -3480,7 +3484,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
// ======= HD sector write =====================================
case WRITE_DAM_AND_SECTOR:
- LOGMASKED(LOG_LIVE, "[%s live] Skipping GAP2\n", tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s live] Skipping GAP2\n", m_live_state.time.to_string());
skip_on_track(m_gap2_size, WRITE_DAM_SYNC);
break;
@@ -3572,9 +3576,11 @@ void hdc92x4_device::live_run_hd_until(attotime limit)
write_on_track(encode_hd((m_live_state.crc >> 8) & 0xff), 1, WRITE_DATA_CRC);
}
else
+ {
// Write a filler byte so that the last CRC bit is saved correctly
- write_on_track(encode_hd(0xff), 1, WRITE_DONE);
-
+ // See above for an explanation
+ write_on_track(encode_hd(0x4e), 1, WRITE_DONE);
+ }
break;
case WRITE_DONE:
@@ -3776,7 +3782,7 @@ void hdc92x4_device::live_sync()
if(m_live_state.time > machine().time())
{
// If so, we must roll back to the last checkpoint
- LOGMASKED(LOG_SYNC, "[%s] Rolling back and replaying [%s live]\n", ttsn().c_str(), tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_SYNC, "[%s] Rolling back and replaying [%s live]\n", ttsn(), m_live_state.time.to_string());
rollback();
// and replay until we reach the machine time
@@ -3796,7 +3802,7 @@ void hdc92x4_device::live_sync()
{
// We are behind machine time, so we will never get back to that
// time, thus we can commit that position
- LOGMASKED(LOG_SYNC, "[%s] Committing [%s live]\n", ttsn().c_str(), tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_SYNC, "[%s] Committing [%s live]\n", ttsn(), m_live_state.time.to_string());
// Commit bits from pll buffer to disk until live time (if there is something to write)
if (using_floppy())
@@ -3823,7 +3829,7 @@ void hdc92x4_device::live_abort()
{
if (!m_live_state.time.is_never() && m_live_state.time > machine().time())
{
- LOGMASKED(LOG_LIVE, "[%s] Abort; rolling back and replaying [%s live]\n", ttsn().c_str(), tts(m_live_state.time).c_str());
+ LOGMASKED(LOG_LIVE, "[%s] Abort; rolling back and replaying [%s live]\n", ttsn(), m_live_state.time.to_string());
rollback();
live_run_until(machine().time());
}
@@ -3876,6 +3882,11 @@ uint8_t hdc92x4_device::get_data_from_encoding(uint16_t raw)
return (value >> 14) & 0xff;
}
+/*
+ TODO: Check whether the whole rollback concept makes sense in this
+ controller. Unlike the wd17xx, this controller contains a lot more state,
+ including the external RAM connected via DMA.
+*/
void hdc92x4_device::rollback()
{
m_live_state = m_checkpoint_state;
@@ -3890,7 +3901,7 @@ void hdc92x4_device::wait_for_realtime(int state)
{
m_live_state.next_state = state;
m_timer->adjust(m_live_state.time - machine().time());
- LOGMASKED(LOG_LIVE, "[%s live] Waiting for real time [%s] to catch up; next state = %02x\n", tts(m_live_state.time).c_str(), ttsn().c_str(), state);
+ LOGMASKED(LOG_LIVE, "[%s live] Waiting for real time [%s] to catch up; next state = %02x\n", m_live_state.time.to_string(), ttsn(), state);
}
/*
@@ -4015,7 +4026,7 @@ void hdc92x4_device::encode_raw(uint16_t raw)
m_live_state.bit_counter = 16;
m_live_state.shift_reg = m_live_state.shift_reg_save = raw;
m_live_state.last_data_bit = raw & 1;
- LOGMASKED(LOG_DETAIL, "[%s live] Write %02x (%04x)\n", tts(m_live_state.time).c_str(), get_data_from_encoding(raw), raw);
+ LOGMASKED(LOG_DETAIL, "[%s live] Write %02x (%04x)\n", m_live_state.time.to_string(), get_data_from_encoding(raw), raw);
checkpoint();
}
@@ -4304,7 +4315,7 @@ void hdc92x4_device::write(offs_t offset, uint8_t data)
{
if ((offset & 1) == 0)
{
- LOGMASKED(LOG_COMMAND, "New register write access %02x\n", data & 0xff);
+ LOGMASKED(LOG_DETAIL, "New register write access %02x\n", data & 0xff);
if (m_executing) LOGMASKED(LOG_WARN, "Error - previous command %02x not completed; register access ignored\n", current_command());
else
{
@@ -4314,7 +4325,7 @@ void hdc92x4_device::write(offs_t offset, uint8_t data)
}
else
{
- LOGMASKED(LOG_COMMAND, "New incoming command %02x\n", data);
+ LOGMASKED(LOG_DETAIL, "New incoming command %02x\n", data);
if (m_executing) LOGMASKED(LOG_WARN, "Error - previous command %02x not completed; new command %02x ignored\n", current_command(), data);
else
{
@@ -4537,7 +4548,7 @@ bool hdc92x4_device::waiting_for_other_line(int line)
void hdc92x4_device::index_handler()
{
int level = index_hole()? ASSERT_LINE : CLEAR_LINE;
- LOGMASKED(LOG_LINES, "[%s] Index handler; level=%d\n", ttsn().c_str(), level);
+ LOGMASKED(LOG_LINES, "[%s] Index handler; level=%d\n", ttsn(), level);
// Synchronize our position on the track
live_sync();
@@ -4550,7 +4561,7 @@ void hdc92x4_device::index_handler()
if (waiting_for_line(INDEX_LINE, level))
{
- LOGMASKED(LOG_LINES, "[%s] Index pulse level=%d triggers event\n", ttsn().c_str(), level);
+ LOGMASKED(LOG_LINES, "[%s] Index pulse level=%d triggers event\n", ttsn(), level);
m_substate = m_state_after_line;
m_state_after_line = UNDEF;
if (m_stopwrite)
@@ -4572,7 +4583,7 @@ void hdc92x4_device::index_handler()
void hdc92x4_device::ready_handler()
{
int level = drive_ready()? ASSERT_LINE : CLEAR_LINE;
- LOGMASKED(LOG_LINES, "[%s] Ready handler; level=%d\n", ttsn().c_str(), level);
+ LOGMASKED(LOG_LINES, "[%s] Ready handler; level=%d\n", ttsn(), level);
// Set the interrupt status flag
set_bits(m_register_r[INT_STATUS], ST_RDYCHNG, true);
@@ -4599,17 +4610,22 @@ void hdc92x4_device::ready_handler()
void hdc92x4_device::seek_complete_handler()
{
int level = seek_complete()? ASSERT_LINE : CLEAR_LINE;
- LOGMASKED(LOG_LINES, "[%s] Seek complete handler; level=%d\n", ttsn().c_str(), level);
-
- // Synchronize our position on the track
- live_sync();
+ LOGMASKED(LOG_STEP, "[%s] Seek complete handler; level=%d\n", ttsn(), level);
+ // Some commands may wait for SEEK_COMPLETE regardless of the step rate
if (waiting_for_line(SEEKCOMP_LINE, level))
{
+ // Synchronize our position on the track
+ live_sync();
+
m_substate = m_state_after_line;
m_state_after_line = UNDEF;
reenter_command_processing();
}
+ else
+ {
+ if (level==ASSERT_LINE) LOGMASKED(LOG_LINES, "[%s] Ignoring seek complete signal\n", ttsn());
+ }
}
/*
@@ -4646,7 +4662,7 @@ void hdc92x4_device::auxbus_out()
m_output2 = (m_output2 & 0xb0) | desired_head();
if (m_reduced_write_current) m_output2 |= OUT2_REDWRT;
- LOGMASKED(LOG_AUXBUS, "[%s] Setting OUTPUT1=%02x, OUTPUT2=%02x\n", ttsn().c_str(), m_output1, m_output2);
+ LOGMASKED(LOG_AUXBUS, "[%s] Setting OUTPUT1=%02x, OUTPUT2=%02x\n", ttsn(), m_output1, m_output2);
if (m_output1 != m_output1_old || m_output2 != m_output2_old)
{
@@ -4696,11 +4712,11 @@ void hdc92x4_device::set_interrupt(line_state intr)
/*
DMA acknowledge line.
*/
-WRITE_LINE_MEMBER( hdc92x4_device::dmaack )
+void hdc92x4_device::dmaack(int state)
{
if (state==ASSERT_LINE)
{
- LOGMASKED(LOG_DMA, "[%s] DMA acknowledged\n", ttsn().c_str());
+ LOGMASKED(LOG_DMA, "[%s] DMA acknowledged\n", ttsn());
set_bits(m_register_r[INT_STATUS], ST_OVRUN, false);
}
}
@@ -4720,8 +4736,11 @@ void hdc92x4_device::connect_floppy_drive(floppy_image_device* floppy)
void hdc92x4_device::connect_hard_drive(mfm_harddisk_device* harddisk)
{
m_harddisk = harddisk;
- m_hd_encoding = m_harddisk->get_encoding();
- LOGMASKED(LOG_DETAIL, "HD encoding = %d\n", m_hd_encoding);
+ if (harddisk != nullptr)
+ {
+ m_hd_encoding = m_harddisk->get_encoding();
+ LOGMASKED(LOG_DETAIL, "HD encoding = %d\n", m_hd_encoding);
+ }
}
/*
@@ -4736,28 +4755,28 @@ void hdc92x4_device::set_clock_divider(int line, int value)
}
/*
- This is reached when a timer has expired
+ These are reached when the relevant timer has expired
*/
-void hdc92x4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(hdc92x4_device::gen_timer_expired)
{
live_sync();
m_timed_wait = false;
- switch (id)
- {
- case GEN_TIMER:
- reenter_command_processing();
- break;
- case COM_TIMER:
- process_command();
- break;
- }
+ reenter_command_processing();
+}
+
+TIMER_CALLBACK_MEMBER(hdc92x4_device::com_timer_expired)
+{
+ live_sync();
+ m_timed_wait = false;
+
+ process_command();
}
/*
Reset the controller. Negative logic, but we use ASSERT_LINE.
*/
-WRITE_LINE_MEMBER( hdc92x4_device::reset )
+void hdc92x4_device::reset(int state)
{
if (state == ASSERT_LINE)
{
@@ -4768,17 +4787,10 @@ WRITE_LINE_MEMBER( hdc92x4_device::reset )
void hdc92x4_device::device_start()
{
- m_out_intrq.resolve_safe();
- m_out_dip.resolve_safe();
- m_out_auxbus.resolve_safe();
- m_out_dmarq.resolve_safe();
- m_out_dma.resolve_safe();
- m_in_dma.resolve_safe(0);
-
// allocate timers
- m_timer = timer_alloc(GEN_TIMER);
- m_cmd_timer = timer_alloc(COM_TIMER);
- // m_live_timer = timer_alloc(LIVE_TIMER);
+ m_timer = timer_alloc(FUNC(hdc92x4_device::gen_timer_expired), this);
+ m_cmd_timer = timer_alloc(FUNC(hdc92x4_device::com_timer_expired), this);
+ // m_live_timer = timer_alloc(FUNC(hdc92x4_device::live_timer_expired), this);
m_live_state.state = IDLE;
}
diff --git a/src/devices/machine/hdc92x4.h b/src/devices/machine/hdc92x4.h
index c4850ffa103..0a2ef365d7e 100644
--- a/src/devices/machine/hdc92x4.h
+++ b/src/devices/machine/hdc92x4.h
@@ -47,8 +47,8 @@ public:
// Accessors from the CPU side
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( reset );
- DECLARE_WRITE_LINE_MEMBER( dmaack );
+ void reset(int state);
+ void dmaack(int state);
// Callbacks
auto intrq_cb() { return m_out_intrq.bind(); }
@@ -80,9 +80,13 @@ public:
protected:
hdc92x4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool is_hdc9234);
- void device_start() override;
- void device_reset() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ TIMER_CALLBACK_MEMBER(gen_timer_expired);
+ TIMER_CALLBACK_MEMBER(com_timer_expired);
+
+private:
const bool m_is_hdc9234;
devcb_write_line m_out_intrq; // INT line
@@ -95,10 +99,12 @@ protected:
// Internal register pointer used for sequential register loading
int m_register_pointer;
+protected:
// Read and write registers
uint8_t m_register_w[12];
uint8_t m_register_r[15];
+private:
// Interrupt management (outgoing INT pin)
void set_interrupt(line_state intr);
@@ -123,9 +129,11 @@ protected:
// Intermediate storage for register
uint8_t m_regvalue;
+protected:
// Drive type that has been selected in drive_select
int m_selected_drive_type;
+private:
// Drive numbere that has been selected in drive_select
int m_selected_drive_number;
@@ -137,9 +145,6 @@ protected:
emu_timer *m_cmd_timer;
// emu_timer *m_live_timer;
- // Timer callback
- void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
// Handlers for incoming signals
void ready_handler();
void index_handler();
@@ -156,11 +161,8 @@ protected:
void wait_time(emu_timer *tm, const attotime &delay, int param);
void wait_line(int line, line_state level, int substate, bool stopwrite);
- // Converts attotime to a string
- std::string tts(const attotime &t);
-
// Current time
- std::string ttsn();
+ std::string ttsn() const;
// Utility routine to set or reset bits
void set_bits(uint8_t& byte, int mask, bool set);
@@ -364,9 +366,13 @@ protected:
int m_gap3_size;
int m_sync_size;
+protected:
// Are we in FM mode?
bool fm_mode();
+ // Do we have timed steps?
+ bool timed_steps();
+
// Seek completed?
bool seek_complete();
@@ -424,6 +430,7 @@ protected:
// Was the Bad Sector flag set for the recently read sector header?
bool bad_sector();
+private:
// Common subprograms READ ID, VERIFY, and DATA TRANSFER
void read_id(int& cont, bool implied_seek, bool wait_seek_complete);
void verify(int& cont);
@@ -458,8 +465,8 @@ public:
hdc9224_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
- int step_time() override;
- int header_length() override;
+ virtual int step_time() override;
+ virtual int header_length() override;
};
class hdc9234_device : public hdc92x4_device
@@ -468,8 +475,8 @@ public:
hdc9234_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
- int step_time() override;
- int header_length() override;
+ virtual int step_time() override;
+ virtual int header_length() override;
};
#endif // MAME_MACHINE_HDC92X4_H
diff --git a/src/devices/machine/hp_dc100_tape.cpp b/src/devices/machine/hp_dc100_tape.cpp
index a9cbb925163..75e4778f2c5 100644
--- a/src/devices/machine/hp_dc100_tape.cpp
+++ b/src/devices/machine/hp_dc100_tape.cpp
@@ -30,17 +30,21 @@
#include "emu.h"
#include "hp_dc100_tape.h"
+#include "util/ioprocsfilter.h"
+
// Debugging
-#include "logmacro.h"
+
#define LOG_TMR_MASK (LOG_GENERAL << 1)
-#define LOG_TMR(...) LOGMASKED(LOG_TMR_MASK, __VA_ARGS__)
#define LOG_DBG_MASK (LOG_TMR_MASK << 1)
-#define LOG_DBG(...) LOGMASKED(LOG_DBG_MASK, __VA_ARGS__)
#define LOG_RW_MASK (LOG_DBG_MASK << 1)
+
+#define LOG_TMR(...) LOGMASKED(LOG_TMR_MASK, __VA_ARGS__)
+#define LOG_DBG(...) LOGMASKED(LOG_DBG_MASK, __VA_ARGS__)
#define LOG_RW(...) LOGMASKED(LOG_RW_MASK, __VA_ARGS__)
-#undef VERBOSE
+
//#define VERBOSE (LOG_GENERAL | LOG_TMR_MASK | LOG_DBG_MASK | LOG_RW_MASK)
#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
// Bit manipulation
namespace {
@@ -49,12 +53,12 @@ namespace {
return (T)1U << n;
}
- template<typename T> void BIT_CLR(T& w , unsigned n)
+ template<typename T> void BIT_CLR(T& w, unsigned n)
{
w &= ~BIT_MASK<T>(n);
}
- template<typename T> void BIT_SET(T& w , unsigned n)
+ template<typename T> void BIT_SET(T& w, unsigned n)
{
w |= BIT_MASK<T>(n);
}
@@ -63,55 +67,47 @@ namespace {
// Device type definition
DEFINE_DEVICE_TYPE(HP_DC100_TAPE, hp_dc100_tape_device, "hp_dc100_tape", "HP DC100 tape drive")
-// Timers
-enum {
- BIT_TMR_ID,
- TACHO_TMR_ID,
- HOLE_TMR_ID,
- MOTION_TMR_ID
-};
-
// Constants
constexpr double MOTION_MARGIN = 1e-5; // Margin to ensure motion events have passed when timer expires (10 µs)
constexpr hti_format_t::tape_pos_t TAPE_INIT_POS = 80 * hti_format_t::ONE_INCH_POS; // Initial tape position: 80" from beginning (just past the punched part)
hp_dc100_tape_device::hp_dc100_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig , HP_DC100_TAPE , tag , owner , clock)
- , device_image_interface(mconfig , *this)
+ : microtape_image_device(mconfig, HP_DC100_TAPE, tag, owner, clock)
, m_cart_out_handler(*this)
, m_hole_handler(*this)
, m_tacho_tick_handler(*this)
, m_motion_handler(*this)
, m_rd_bit_handler(*this)
- , m_wr_bit_handler(*this)
+ , m_wr_bit_handler(*this, 0)
+ , m_unit_name()
, m_image()
, m_image_dirty(false)
{
}
-image_init_result hp_dc100_tape_device::call_load()
+std::pair<std::error_condition, std::string> hp_dc100_tape_device::call_load()
{
return internal_load(false);
}
-image_init_result hp_dc100_tape_device::call_create(int format_type, util::option_resolution *format_options)
+std::pair<std::error_condition, std::string> hp_dc100_tape_device::call_create(int format_type, util::option_resolution *format_options)
{
return internal_load(true);
}
void hp_dc100_tape_device::call_unload()
{
- LOG("call_unload dirty=%d\n" , m_image_dirty);
+ LOG("call_unload dirty=%d\n", m_image_dirty);
device_reset();
if (m_image_dirty) {
- io_generic io;
- io.file = (device_image_interface *)this;
- io.procs = &image_ioprocs;
- io.filler = 0;
- m_image.save_tape(&io);
- m_image_dirty = false;
+ check_for_file();
+ auto io = util::random_read_write_fill(image_core_file(), 0);
+ if (io) {
+ m_image.save_tape(*io);
+ m_image_dirty = false;
+ }
}
m_image.clear_tape();
@@ -128,7 +124,14 @@ std::string hp_dc100_tape_device::call_display()
return buffer;
}
- char track = m_track ? 'B' : 'A';
+ if (!m_unit_name.empty()) {
+ buffer += m_unit_name;
+ buffer += " ";
+ }
+
+ if (m_image.no_of_tracks() > 1) {
+ buffer += m_track ? "B " : "A ";
+ }
char r_w = m_current_op == OP_WRITE || m_current_op == OP_ERASE ? 'W' : 'R';
char m1;
char m2;
@@ -143,7 +146,7 @@ std::string hp_dc100_tape_device::call_display()
int pos_in = get_approx_pos() / hti_format_t::ONE_INCH_POS;
- buffer = string_format("%c %c %c%c [%04d/1824]" , track , r_w , m1 , m2 , pos_in);
+ buffer += string_format("%c %c%c [%04d/1824]", r_w, m1, m2, pos_in);
return buffer;
}
@@ -158,7 +161,7 @@ void hp_dc100_tape_device::set_acceleration(double accel)
m_acceleration = accel;
}
-void hp_dc100_tape_device::set_set_points(double slow_sp , double fast_sp)
+void hp_dc100_tape_device::set_set_points(double slow_sp, double fast_sp)
{
m_slow_set_point = slow_sp;
m_fast_set_point = fast_sp;
@@ -169,9 +172,9 @@ void hp_dc100_tape_device::set_tick_size(hti_format_t::tape_pos_t size)
m_tick_size = size;
}
-void hp_dc100_tape_device::set_bits_per_word(unsigned bits)
+void hp_dc100_tape_device::set_image_format(hti_format_t::image_format_t fmt)
{
- m_image.set_bits_per_word(bits);
+ m_image.set_image_format(fmt);
}
void hp_dc100_tape_device::set_go_threshold(double threshold)
@@ -179,10 +182,15 @@ void hp_dc100_tape_device::set_go_threshold(double threshold)
m_go_threshold = threshold;
}
+void hp_dc100_tape_device::set_name(const std::string& name)
+{
+ m_unit_name = name;
+}
+
void hp_dc100_tape_device::set_track_no(unsigned track)
{
- if (m_track != track) {
- LOG_DBG("Setting track %u (op=%d)\n" , track , static_cast<int>(m_current_op));
+ if (m_track != track && track < m_image.no_of_tracks()) {
+ LOG_DBG("Setting track %u (op=%d)\n", track, static_cast<int>(m_current_op));
auto saved_op = m_current_op;
if (m_current_op != OP_IDLE) {
// Close current op on old track
@@ -196,7 +204,7 @@ void hp_dc100_tape_device::set_track_no(unsigned track)
}
}
-bool hp_dc100_tape_device::set_speed_setpoint(tape_speed_t speed , bool fwd)
+bool hp_dc100_tape_device::set_speed_setpoint(tape_speed_t speed, bool fwd)
{
if (!m_present) {
return false;
@@ -206,7 +214,7 @@ bool hp_dc100_tape_device::set_speed_setpoint(tape_speed_t speed , bool fwd)
if (m_set_point != new_setpoint) {
update_speed_pos();
- LOG_DBG("Speed SP changed %f->%f %.6f p=%d\n" , m_set_point , new_setpoint , machine().time().as_double() , m_tape_pos);
+ LOG_DBG("Speed SP changed %f->%f %.6f p=%d\n", m_set_point, new_setpoint, machine().time().as_double(), m_tape_pos);
m_tape_speed = speed;
m_set_point = new_setpoint;
// Speed set point changed, accelerate/decelerate
@@ -226,13 +234,13 @@ bool hp_dc100_tape_device::set_speed_setpoint(tape_speed_t speed , bool fwd)
}
}
-void hp_dc100_tape_device::set_op(tape_op_t op , bool force)
+void hp_dc100_tape_device::set_op(tape_op_t op, bool force)
{
if (!m_present || m_start_time.is_never()) {
return;
}
if (!m_in_set_op && (op != m_current_op || force)) {
- LOG_DBG("Op %d->%d (f=%d)\n" , m_current_op , op , force);
+ LOG_DBG("Op %d->%d (f=%d)\n", m_current_op, op, force);
m_in_set_op = true;
update_speed_pos();
auto prev_op = m_current_op;
@@ -251,21 +259,21 @@ void hp_dc100_tape_device::set_op(tape_op_t op , bool force)
LOG("Starting RD after WR?\n");
}
if (fabs(m_speed) < m_slow_set_point) {
- LOG("Starting RD at %f speed?\n" , m_speed);
+ LOG("Starting RD at %f speed?\n", m_speed);
}
- m_rd_it_valid = m_image.next_data(get_track_no() , m_tape_pos , is_moving_fwd() , false , m_rd_it);
+ m_rd_it_valid = m_image.next_data(get_track_no(), m_tape_pos, is_moving_fwd(), false, m_rd_it);
load_rd_word();
m_gap_detect_start = m_tape_pos;
break;
case OP_WRITE:
if (m_accelerating || fabs(m_speed) != m_slow_set_point) {
- LOG("Starting WR at %f speed (acc=%d)?\n" , m_speed , m_accelerating);
+ LOG("Starting WR at %f speed (acc=%d)?\n", m_speed, m_accelerating);
}
if (prev_op == OP_READ) {
// Switching from RD to WR
// Clear out the part of m_rw_word that is going to be written
- LOG_RW("Switch RD->WR @%d, idx=%d, w=%04x\n" , m_rw_pos , m_bit_idx , m_rw_word);
+ LOG_RW("Switch RD->WR @%d, idx=%d, w=%04x\n", m_rw_pos, m_bit_idx, m_rw_word);
if (is_moving_fwd()) {
if (--m_bit_idx >= 0) {
m_rw_word &= 0xffffU << (m_bit_idx + 1);
@@ -297,7 +305,7 @@ void hp_dc100_tape_device::set_op(tape_op_t op , bool force)
break;
case OP_ERASE:
- LOG_DBG("Start GAP @%d\n" , m_tape_pos);
+ LOG_DBG("Start GAP @%d\n", m_tape_pos);
m_rw_pos = m_tape_pos;
break;
@@ -337,11 +345,11 @@ void hp_dc100_tape_device::update_speed_pos()
double acceleration = m_set_point > m_speed ? m_acceleration : -m_acceleration;
bool retrigger_motion = false;
if (delta_time_double < time_to_const_v) {
- space_const_a = const_a_space(acceleration , delta_time_double);
+ space_const_a = const_a_space(acceleration, delta_time_double);
m_speed += delta_time_double * acceleration;
time_const_v = 0.0;
} else {
- space_const_a = const_a_space(acceleration , time_to_const_v);
+ space_const_a = const_a_space(acceleration, time_to_const_v);
time_const_v = delta_time_double - time_to_const_v;
LOG_DBG("Acceleration ends\n");
m_accelerating = false;
@@ -357,13 +365,13 @@ void hp_dc100_tape_device::update_speed_pos()
(fabs(prev_speed) - m_go_threshold) * (fabs(m_speed) - m_go_threshold) < 0.0) {
// Slow speed threshold crossed
// In-motion threshold crossed
- LOG_DBG("Thr crossed %f->%f\n" , prev_speed , m_speed);
+ LOG_DBG("Thr crossed %f->%f\n", prev_speed, m_speed);
motion_event = true;
retrigger_motion = true;
}
if (prev_speed * m_speed < 0.0) {
// Direction inverted (speed sign flipped)
- LOG_DBG("Dir inverted s=%f\n" , m_speed);
+ LOG_DBG("Dir inverted s=%f\n", m_speed);
inverted = true;
retrigger_motion = true;
}
@@ -376,8 +384,8 @@ void hp_dc100_tape_device::update_speed_pos()
}
hti_format_t::tape_pos_t delta_pos = (hti_format_t::tape_pos_t)((space_const_a + m_speed * time_const_v) * hti_format_t::ONE_INCH_POS);
- LOG_DBG("dp=%d\n" , delta_pos);
- if (!hti_format_t::pos_offset(m_tape_pos , true , delta_pos)) {
+ LOG_DBG("dp=%d\n", delta_pos);
+ if (!hti_format_t::pos_offset(m_tape_pos, true, delta_pos)) {
LOG("Tape unspooled!\n");
}
@@ -404,7 +412,7 @@ hti_format_t::tape_pos_t hp_dc100_tape_device::get_approx_pos() const
attotime delta_time{ machine().time() - m_start_time };
hti_format_t::tape_pos_t delta_pos = (hti_format_t::tape_pos_t)(delta_time.as_double() * m_speed * hti_format_t::ONE_INCH_POS);
auto tape_pos = m_tape_pos;
- hti_format_t::pos_offset(tape_pos , true , delta_pos);
+ hti_format_t::pos_offset(tape_pos, true, delta_pos);
return tape_pos;
}
@@ -415,15 +423,15 @@ bool hp_dc100_tape_device::gap_reached(hti_format_t::tape_pos_t min_gap_size)
if (m_gap_detect_start != hti_format_t::NULL_TAPE_POS &&
abs(m_gap_detect_start - m_tape_pos) >= min_gap_size) {
auto tmp = m_tape_pos;
- hti_format_t::pos_offset(tmp , is_moving_fwd() , -min_gap_size);
- if (m_image.just_gap(get_track_no() , tmp , m_tape_pos)) {
+ hti_format_t::pos_offset(tmp, is_moving_fwd(), -min_gap_size);
+ if (m_image.just_gap(get_track_no(), tmp, m_tape_pos)) {
return true;
}
}
return false;
}
-void hp_dc100_tape_device::time_to_next_gap(hti_format_t::tape_pos_t min_gap_size , bool new_gap , emu_timer *target_timer)
+void hp_dc100_tape_device::time_to_next_gap(hti_format_t::tape_pos_t min_gap_size, bool new_gap, emu_timer *target_timer)
{
update_speed_pos();
@@ -432,30 +440,23 @@ void hp_dc100_tape_device::time_to_next_gap(hti_format_t::tape_pos_t min_gap_siz
bool found = true;
if (new_gap) {
hti_format_t::track_iterator_t it;
- found = m_image.next_data(get_track_no() , tmp , fwd , true , it);
+ found = m_image.next_data(get_track_no(), tmp, fwd, true, it);
if (found) {
- tmp = hti_format_t::farthest_end(it , !fwd);
+ tmp = m_image.farthest_end(it, !fwd);
}
}
- if (found && m_image.next_gap(get_track_no() , tmp , fwd , min_gap_size)) {
+ if (found && m_image.next_gap(get_track_no(), tmp, fwd, min_gap_size)) {
hti_format_t::tape_pos_t dummy;
- LOG_DBG("TTNG T%u S%d N%d %d->%d\n" , get_track_no() , min_gap_size , new_gap , m_tape_pos , tmp);
+ LOG_DBG("TTNG T%u S%d N%d %d->%d\n", get_track_no(), min_gap_size, new_gap, m_tape_pos, tmp);
time_to_distance(tmp - m_tape_pos, dummy, target_timer);
} else {
- LOG_DBG("TTNG T%u S%d N%d %d->X\n" , get_track_no() , min_gap_size , new_gap , m_tape_pos);
+ LOG_DBG("TTNG T%u S%d N%d %d->X\n", get_track_no(), min_gap_size, new_gap, m_tape_pos);
target_timer->reset();
}
}
void hp_dc100_tape_device::device_start()
{
- m_cart_out_handler.resolve_safe();
- m_hole_handler.resolve_safe();
- m_tacho_tick_handler.resolve_safe();
- m_motion_handler.resolve_safe();
- m_rd_bit_handler.resolve_safe();
- m_wr_bit_handler.resolve_safe(0);
-
save_item(NAME(m_acceleration));
save_item(NAME(m_slow_set_point));
save_item(NAME(m_fast_set_point));
@@ -479,10 +480,10 @@ void hp_dc100_tape_device::device_start()
save_item(NAME(m_next_hole_pos));
save_item(NAME(m_image_dirty));
- m_bit_timer = timer_alloc(BIT_TMR_ID);
- m_tacho_timer = timer_alloc(TACHO_TMR_ID);
- m_hole_timer = timer_alloc(HOLE_TMR_ID);
- m_motion_timer = timer_alloc(MOTION_TMR_ID);
+ m_bit_timer = timer_alloc(FUNC(hp_dc100_tape_device::bit_timer_tick), this);
+ m_tacho_timer = timer_alloc(FUNC(hp_dc100_tape_device::tacho_timer_tick), this);
+ m_hole_timer = timer_alloc(FUNC(hp_dc100_tape_device::hole_timer_tick), this);
+ m_motion_timer = timer_alloc(FUNC(hp_dc100_tape_device::motion_timer_tick), this);
}
void hp_dc100_tape_device::device_reset()
@@ -490,71 +491,76 @@ void hp_dc100_tape_device::device_reset()
clear_state();
}
-void hp_dc100_tape_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(hp_dc100_tape_device::bit_timer_tick)
{
- LOG_TMR("%.6f TMR %d p=%d s=%.3f(%.3f) a=%d\n" , machine().time().as_double() , id , m_tape_pos , m_speed , m_set_point , m_accelerating);
+ LOG_TMR("%.6f TMR 0 p=%d s=%.3f(%.3f) a=%d\n", machine().time().as_double(), m_tape_pos, m_speed, m_set_point, m_accelerating);
update_speed_pos();
- switch (id) {
- case BIT_TMR_ID:
- m_tape_pos = m_next_bit_pos;
- if (m_current_op == OP_READ) {
- bool bit = BIT(m_rd_it->second , m_bit_idx);
- m_rd_bit_handler(bit);
- if (is_moving_fwd()) {
- if (--m_bit_idx >= 0) {
- time_to_distance(m_image.bit_length(BIT(m_rd_it->second , m_bit_idx)), m_next_bit_pos, m_bit_timer);
- } else {
- m_rd_it_valid = m_image.adv_it(get_track_no() , true , m_rd_it) != hti_format_t::ADV_NO_MORE_DATA;
- load_rd_word();
- }
+ m_tape_pos = m_next_bit_pos;
+ if (m_current_op == OP_READ) {
+ bool bit = BIT(m_rd_it->second, m_bit_idx);
+ m_rd_bit_handler(bit);
+ if (is_moving_fwd()) {
+ if (--m_bit_idx >= 0) {
+ time_to_distance(m_image.bit_length(BIT(m_rd_it->second, m_bit_idx)), m_next_bit_pos, m_bit_timer);
} else {
- if (++m_bit_idx < 16) {
- time_to_distance(-m_image.bit_length(BIT(m_rd_it->second , m_bit_idx)), m_next_bit_pos, m_bit_timer);
- } else {
- m_rd_it_valid = m_image.adv_it(get_track_no() , false , m_rd_it) != hti_format_t::ADV_NO_MORE_DATA;
- load_rd_word();
- }
+ m_rd_it_valid = m_image.adv_it(get_track_no(), true, m_rd_it) != hti_format_t::ADV_NO_MORE_DATA;
+ load_rd_word();
}
- } else if (m_current_op == OP_WRITE) {
- bool bit = m_wr_bit_handler();
- hti_format_t::tape_pos_t bit_len = m_image.bit_length(bit);
- if (bit) {
- BIT_SET(m_rw_word , m_bit_idx);
- }
- if (is_moving_fwd()) {
- if (--m_bit_idx < 0) {
- store_wr_word();
- }
+ } else {
+ if (++m_bit_idx < 16) {
+ time_to_distance(-m_image.bit_length(BIT(m_rd_it->second, m_bit_idx)), m_next_bit_pos, m_bit_timer);
} else {
- if (++m_bit_idx >= 16) {
- store_wr_word();
- }
- bit_len = -bit_len;
+ m_rd_it_valid = m_image.adv_it(get_track_no(), false, m_rd_it) != hti_format_t::ADV_NO_MORE_DATA;
+ load_rd_word();
+ }
+ }
+ } else if (m_current_op == OP_WRITE) {
+ bool bit = m_wr_bit_handler();
+ hti_format_t::tape_pos_t bit_len = m_image.bit_length(bit);
+ if (bit) {
+ BIT_SET(m_rw_word, m_bit_idx);
+ }
+ if (is_moving_fwd()) {
+ if (--m_bit_idx < 0) {
+ store_wr_word();
}
- time_to_distance(bit_len, m_next_bit_pos, m_bit_timer);
+ } else {
+ if (++m_bit_idx >= 16) {
+ store_wr_word();
+ }
+ bit_len = -bit_len;
}
- break;
+ time_to_distance(bit_len, m_next_bit_pos, m_bit_timer);
+ }
+}
- case TACHO_TMR_ID:
- m_tape_pos = m_next_tacho_pos;
- m_tacho_tick_handler(1);
- adjust_tacho_timer();
- break;
+TIMER_CALLBACK_MEMBER(hp_dc100_tape_device::tacho_timer_tick)
+{
+ LOG_TMR("%.6f TMR 1 p=%d s=%.3f(%.3f) a=%d\n", machine().time().as_double(), m_tape_pos, m_speed, m_set_point, m_accelerating);
+ update_speed_pos();
- case HOLE_TMR_ID:
- m_tape_pos = m_next_hole_pos;
- m_hole_handler(1);
- adjust_hole_timer();
- break;
+ m_tape_pos = m_next_tacho_pos;
+ m_tacho_tick_handler(1);
+ adjust_tacho_timer();
+}
- case MOTION_TMR_ID:
- // In itself it does nothing (all work is in update_speed_pos)
- break;
+TIMER_CALLBACK_MEMBER(hp_dc100_tape_device::hole_timer_tick)
+{
+ LOG_TMR("%.6f TMR 2 p=%d s=%.3f(%.3f) a=%d\n", machine().time().as_double(), m_tape_pos, m_speed, m_set_point, m_accelerating);
+ update_speed_pos();
- default:
- break;
- }
+ m_tape_pos = m_next_hole_pos;
+ m_hole_handler(1);
+ adjust_hole_timer();
+}
+
+TIMER_CALLBACK_MEMBER(hp_dc100_tape_device::motion_timer_tick)
+{
+ LOG_TMR("%.6f TMR 2 p=%d s=%.3f(%.3f) a=%d\n", machine().time().as_double(), m_tape_pos, m_speed, m_set_point, m_accelerating);
+ update_speed_pos();
+
+ // All work is in update_speed_pos
}
void hp_dc100_tape_device::clear_state()
@@ -583,31 +589,42 @@ void hp_dc100_tape_device::clear_state()
set_tape_present(is_loaded());
}
-image_init_result hp_dc100_tape_device::internal_load(bool is_create)
+std::pair<std::error_condition, std::string> hp_dc100_tape_device::internal_load(bool is_create)
{
- LOG("load %d\n" , is_create);
+ LOG("load %d\n", is_create);
device_reset();
- io_generic io;
- io.file = (device_image_interface *)this;
- io.procs = &image_ioprocs;
- io.filler = 0;
+ check_for_file();
if (is_create) {
+ auto io = util::random_read_write_fill(image_core_file(), 0);
+ if (!io) {
+ LOG("out of memory\n");
+ set_tape_present(false);
+ return std::make_pair(std::errc::not_enough_memory, std::string());
+ }
m_image.clear_tape();
- m_image.save_tape(&io);
- } else if (!m_image.load_tape(&io)) {
- LOG("load failed\n");
- seterror(IMAGE_ERROR_INVALIDIMAGE , "Wrong format");
- set_tape_present(false);
- return image_init_result::FAIL;
+ m_image.save_tape(*io);
+ } else {
+ auto io = util::random_read_fill(image_core_file(), 0);
+ if (!io) {
+ LOG("out of memory\n");
+ set_tape_present(false);
+ return std::make_pair(std::errc::not_enough_memory, std::string());
+ }
+ if (!m_image.load_tape(*io)) {
+ LOG("load failed\n");
+ //seterror(image_error::INVALIDIMAGE, "Wrong format");
+ set_tape_present(false);
+ return std::make_pair(image_error::INVALIDIMAGE, std::string());
+ }
}
LOG("load OK\n");
m_image_dirty = false;
set_tape_present(true);
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
void hp_dc100_tape_device::set_tape_present(bool present)
@@ -618,7 +635,7 @@ void hp_dc100_tape_device::set_tape_present(bool present)
}
}
-double hp_dc100_tape_device::compute_set_point(tape_speed_t speed , bool fwd) const
+double hp_dc100_tape_device::compute_set_point(tape_speed_t speed, bool fwd) const
{
double sp;
@@ -639,7 +656,7 @@ double hp_dc100_tape_device::compute_set_point(tape_speed_t speed , bool fwd) co
void hp_dc100_tape_device::start_tape()
{
- LOG_DBG("Tape started %.6f p=%d\n" , machine().time().as_double() , m_tape_pos);
+ LOG_DBG("Tape started %.6f p=%d\n", machine().time().as_double(), m_tape_pos);
m_start_time = machine().time();
m_accelerating = true;
m_speed = 0;
@@ -647,7 +664,7 @@ void hp_dc100_tape_device::start_tape()
void hp_dc100_tape_device::stop_tape()
{
- LOG_DBG("Tape stops %.6f p=%d\n" , machine().time().as_double() , m_tape_pos);
+ LOG_DBG("Tape stops %.6f p=%d\n", machine().time().as_double(), m_tape_pos);
m_start_time = attotime::never;
m_accelerating = false;
m_speed = 0;
@@ -657,34 +674,34 @@ void hp_dc100_tape_device::stop_tape()
stop_op();
}
-double hp_dc100_tape_device::const_a_space(double a , double t) const
+double hp_dc100_tape_device::const_a_space(double a, double t) const
{
// Space traveled in time 't' at constant acceleration 'a' starting with 'm_speed' speed
return t * (m_speed + a / 2 * t);
}
-attotime hp_dc100_tape_device::time_to_threshold(double threshold , bool zero_allowed) const
+attotime hp_dc100_tape_device::time_to_threshold(double threshold, bool zero_allowed) const
{
attotime time{ attotime::never };
auto delta_sp = m_set_point - m_speed;
auto delta_t = threshold - m_speed;
- LOG_DBG("Dsp=%.6f D+th=%.6f\n" , delta_sp , delta_t);
+ LOG_DBG("Dsp=%.6f D+th=%.6f\n", delta_sp, delta_t);
if ((delta_sp * delta_t > 0.0 && fabs(delta_t) <= fabs(delta_sp)) ||
(zero_allowed && delta_t == 0.0)) {
time = attotime::from_double(fabs(delta_t) / m_acceleration);
- LOG_DBG("Time to +th: %.6f\n" , time.as_double());
+ LOG_DBG("Time to +th: %.6f\n", time.as_double());
}
delta_t = -threshold - m_speed;
- LOG_DBG("Dsp=%.6f D-th=%.6f\n" , delta_sp , delta_t);
+ LOG_DBG("Dsp=%.6f D-th=%.6f\n", delta_sp, delta_t);
if ((delta_sp * delta_t > 0.0 && fabs(delta_t) <= fabs(delta_sp)) ||
(zero_allowed && delta_t == 0.0)) {
double tm = fabs(delta_t) / m_acceleration;
if (tm < time.as_double()) {
time = attotime::from_double(tm);
- LOG_DBG("Time to -th: %.6f\n" , time.as_double());
+ LOG_DBG("Time to -th: %.6f\n", time.as_double());
}
}
return time;
@@ -701,16 +718,16 @@ void hp_dc100_tape_device::set_motion_timer()
// 3. Tape direction reverses
// 4. Set point is reached
// Motion timer is set to expire at the event that occurs first
- attotime time{ time_to_threshold(m_slow_set_point , true) };
+ attotime time{ time_to_threshold(m_slow_set_point, true) };
- attotime tmp{ time_to_threshold(m_go_threshold , false) };
+ attotime tmp{ time_to_threshold(m_go_threshold, false) };
if (tmp < time) {
time = tmp;
}
// Time to the moment when tape inverts its motion
// (i.e. when m_speed crosses 0)
- tmp = time_to_threshold(0.0 , false);
+ tmp = time_to_threshold(0.0, false);
if (tmp < time) {
time = tmp;
}
@@ -733,7 +750,7 @@ void hp_dc100_tape_device::set_motion_timer()
}
}
-void hp_dc100_tape_device::time_to_distance(hti_format_t::tape_pos_t distance , hti_format_t::tape_pos_t& target_pos , emu_timer *target_timer) const
+void hp_dc100_tape_device::time_to_distance(hti_format_t::tape_pos_t distance, hti_format_t::tape_pos_t& target_pos, emu_timer *target_timer) const
{
if (m_start_time.is_never()) {
// If tape is stopped we'll never get there..
@@ -742,7 +759,7 @@ void hp_dc100_tape_device::time_to_distance(hti_format_t::tape_pos_t distance ,
}
target_pos = m_tape_pos;
- if (!hti_format_t::pos_offset(target_pos , true , distance)) {
+ if (!hti_format_t::pos_offset(target_pos, true, distance)) {
// Beyond end of tape
target_timer->reset();
return;
@@ -765,11 +782,11 @@ void hp_dc100_tape_device::time_to_distance(hti_format_t::tape_pos_t distance ,
if (has_root) {
double time_in_const_a_pos = (sqrt(delta) - m_speed) / acceleration;
double time_in_const_a_neg = -(sqrt(delta) + m_speed) / acceleration;
- LOG_DBG("TTD %.6f %.6f\n" , time_in_const_a_pos , time_in_const_a_neg);
+ LOG_DBG("TTD %.6f %.6f\n", time_in_const_a_pos, time_in_const_a_neg);
if (time_in_const_a_pos >= 0.0) {
if (time_in_const_a_neg >= 0.0) {
// pos + neg +
- time_in_const_a = std::min(time_in_const_a_pos , time_in_const_a_neg);
+ time_in_const_a = std::min(time_in_const_a_pos, time_in_const_a_neg);
} else {
// pos + neg -
time_in_const_a = time_in_const_a_pos;
@@ -784,14 +801,14 @@ void hp_dc100_tape_device::time_to_distance(hti_format_t::tape_pos_t distance ,
}
}
}
- LOG_DBG("TTD %d %d %.6f %.6f %.6f\n" , distance , has_root , m_speed , time_to_const_v , time_in_const_a);
+ LOG_DBG("TTD %d %d %.6f %.6f %.6f\n", distance, has_root, m_speed, time_to_const_v, time_in_const_a);
if (has_root && time_in_const_a <= time_to_const_v) {
// Entirely in the constant A phase
time_const_a = time_in_const_a;
space = 0.0;
} else {
// Partly in const A & partly in const V
- double space_in_const_a = const_a_space(acceleration , time_to_const_v);
+ double space_in_const_a = const_a_space(acceleration, time_to_const_v);
space -= space_in_const_a;
time_const_a = time_to_const_v;
}
@@ -816,7 +833,7 @@ void hp_dc100_tape_device::time_to_distance(hti_format_t::tape_pos_t distance ,
} else {
time_const_v = 0.0;
}
- LOG_DBG("TTD %.6f %.6f\n" , time_const_a , time_const_v);
+ LOG_DBG("TTD %.6f %.6f\n", time_const_a, time_const_v);
target_timer->adjust(attotime::from_double(time_const_a + time_const_v));
}
@@ -837,13 +854,13 @@ void hp_dc100_tape_device::adjust_tacho_timer()
// on a tick (tick_fract == 0)
dist_to_next = -m_tick_size;
}
- LOG_DBG("Next tick @%d (pos=%d)\n" , dist_to_next , m_tape_pos);
+ LOG_DBG("Next tick @%d (pos=%d)\n", dist_to_next, m_tape_pos);
time_to_distance(dist_to_next, m_next_tacho_pos, m_tacho_timer);
}
void hp_dc100_tape_device::adjust_hole_timer()
{
- auto hole_pos = m_image.next_hole(m_tape_pos , is_moving_fwd());
+ auto hole_pos = m_image.next_hole(m_tape_pos, is_moving_fwd());
if (hole_pos == hti_format_t::NULL_TAPE_POS) {
m_hole_timer->reset();
} else {
@@ -856,8 +873,8 @@ void hp_dc100_tape_device::stop_op()
if (m_current_op == OP_WRITE) {
store_wr_word();
} else if (m_current_op == OP_ERASE) {
- LOG_DBG("Wr gap from %d to %d\n" , m_rw_pos , m_tape_pos);
- m_image.write_gap(get_track_no() , m_rw_pos , m_tape_pos);
+ LOG_DBG("Wr gap from %d to %d\n", m_rw_pos, m_tape_pos);
+ m_image.write_gap(get_track_no(), m_rw_pos, m_tape_pos);
m_image_dirty = true;
}
m_bit_timer->reset();
@@ -875,16 +892,16 @@ void hp_dc100_tape_device::load_rd_word()
m_bit_idx = 0;
}
// This is actually the nearest end (dir is inverted)
- m_rw_pos = m_next_bit_pos = hti_format_t::farthest_end(m_rd_it , !fwd);
+ m_rw_pos = m_next_bit_pos = m_image.farthest_end(m_rd_it, !fwd);
// Compute end of bit cell
- hti_format_t::tape_pos_t bit_len = m_image.bit_length(BIT(m_rd_it->second , m_bit_idx));
+ hti_format_t::tape_pos_t bit_len = m_image.bit_length(BIT(m_rd_it->second, m_bit_idx));
if (!fwd) {
bit_len = -bit_len;
}
- time_to_distance(m_next_bit_pos + bit_len - m_tape_pos , m_next_bit_pos , m_bit_timer);
- LOG_RW("RD %04x @%d\n" , m_rd_it->second , m_next_bit_pos);
+ time_to_distance(m_next_bit_pos + bit_len - m_tape_pos, m_next_bit_pos, m_bit_timer);
+ LOG_RW("RD %04x @%d\n", m_rd_it->second, m_next_bit_pos);
} else {
- LOG_RW("End of RD data @%d\n" , m_tape_pos);
+ LOG_RW("End of RD data @%d\n", m_tape_pos);
stop_op();
m_gap_detect_start = m_tape_pos;
}
@@ -901,8 +918,8 @@ void hp_dc100_tape_device::store_wr_word()
if (!fwd) {
m_rw_pos -= word_length;
}
- LOG_RW("WR %04x @%d\n" , m_rw_word , m_rw_pos);
- m_image.write_word(get_track_no() , m_rw_pos , m_rw_word , word_length , fwd);
+ LOG_RW("WR %04x @%d\n", m_rw_word, m_rw_pos);
+ m_image.write_word(get_track_no(), m_rw_pos, m_rw_word, word_length, fwd);
m_image_dirty = true;
m_rw_word = 0;
if (fwd) {
diff --git a/src/devices/machine/hp_dc100_tape.h b/src/devices/machine/hp_dc100_tape.h
index 167bb953b10..3792be1acb8 100644
--- a/src/devices/machine/hp_dc100_tape.h
+++ b/src/devices/machine/hp_dc100_tape.h
@@ -13,26 +13,21 @@
#pragma once
+#include "imagedev/magtape.h"
+
#include "formats/hti_tape.h"
-class hp_dc100_tape_device : public device_t,
- public device_image_interface
+class hp_dc100_tape_device : public microtape_image_device
{
public:
// Construction
hp_dc100_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- // device_image_interface overrides
- virtual image_init_result call_load() override;
- virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
virtual void call_unload() override;
virtual std::string call_display() override;
- virtual iodevice_t image_type() const noexcept override { return IO_MAGTAPE; }
- virtual bool is_readable() const noexcept override { return true; }
- virtual bool is_writeable() const noexcept override { return true; }
- virtual bool is_creatable() const noexcept override { return true; }
- virtual bool must_be_loaded() const noexcept override { return false; }
- virtual bool is_reset_on_load() const noexcept override { return false; }
virtual const char *file_extensions() const noexcept override;
// **** Units ****
@@ -44,8 +39,9 @@ public:
void set_acceleration(double accel);
void set_set_points(double slow_sp , double fast_sp);
void set_tick_size(hti_format_t::tape_pos_t size);
- void set_bits_per_word(unsigned bits);
+ void set_image_format(hti_format_t::image_format_t fmt);
void set_go_threshold(double threshold);
+ void set_name(const std::string& name);
// Commands
void set_track_no(unsigned track);
@@ -104,10 +100,14 @@ public:
auto wr_bit() { return m_wr_bit_handler.bind(); }
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(bit_timer_tick);
+ TIMER_CALLBACK_MEMBER(tacho_timer_tick);
+ TIMER_CALLBACK_MEMBER(hole_timer_tick);
+ TIMER_CALLBACK_MEMBER(motion_timer_tick);
private:
devcb_write_line m_cart_out_handler;
@@ -123,6 +123,7 @@ private:
double m_fast_set_point;
hti_format_t::tape_pos_t m_tick_size;
double m_go_threshold;
+ std::string m_unit_name;
// State
hti_format_t::tape_pos_t m_tape_pos;
@@ -156,7 +157,7 @@ private:
bool m_image_dirty;
void clear_state();
- image_init_result internal_load(bool is_create);
+ std::pair<std::error_condition, std::string> internal_load(bool is_create);
void set_tape_present(bool present);
double compute_set_point(tape_speed_t speed , bool fwd) const;
void start_tape();
diff --git a/src/devices/machine/hp_taco.cpp b/src/devices/machine/hp_taco.cpp
index 6760a7eda01..d32076311bd 100644
--- a/src/devices/machine/hp_taco.cpp
+++ b/src/devices/machine/hp_taco.cpp
@@ -28,8 +28,8 @@
// according to flow charts in [1]
// - Handling of error conditions, R/W bits, tachometer ticks and gaps according to [1]
// What's not in:
-// - Commands that are not used at all by the software I analyzed, especially those that
-// R/W tapes in HP9825 format. They could be added easily, though.
+// - Commands that are not used at all by the software I analyzed. They could be added easily,
+// though.
// - Accurate execution times of commands
// - Handling of FLG signal: the emulated chip always reports itself as ready for writing.
// - Read threshold is ignored. Real tapes could be read with either a low or high threshold.
@@ -141,16 +141,18 @@
#include "hp_taco.h"
// Debugging
-#include "logmacro.h"
+
#define LOG_DBG_MASK (LOG_GENERAL << 1)
-#define LOG_DBG(...) LOGMASKED(LOG_DBG_MASK, __VA_ARGS__)
#define LOG_RW_MASK (LOG_DBG_MASK << 1)
-#define LOG_RW(...) LOGMASKED(LOG_RW_MASK, __VA_ARGS__)
#define LOG_REG_MASK (LOG_RW_MASK << 1)
+
+#define LOG_DBG(...) LOGMASKED(LOG_DBG_MASK, __VA_ARGS__)
+#define LOG_RW(...) LOGMASKED(LOG_RW_MASK, __VA_ARGS__)
#define LOG_REG(...) LOGMASKED(LOG_REG_MASK, __VA_ARGS__)
-#undef VERBOSE
+
//#define VERBOSE (LOG_GENERAL | LOG_DBG_MASK | LOG_RW_MASK | LOG_REG_MASK)
#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
// Bit manipulation
namespace {
@@ -159,24 +161,17 @@ namespace {
return (T)1U << n;
}
- template<typename T> void BIT_CLR(T& w , unsigned n)
+ template<typename T> void BIT_CLR(T& w, unsigned n)
{
w &= ~BIT_MASK<T>(n);
}
- template<typename T> void BIT_SET(T& w , unsigned n)
+ template<typename T> void BIT_SET(T& w, unsigned n)
{
w |= BIT_MASK<T>(n);
}
}
-// Timers
-enum {
- GAP_TMR_ID,
- EVD_TMR_ID,
- ERROR_TMR_ID
-};
-
// **** Constants ****
constexpr unsigned TACH_FREQ_FAST = 87196; // Tachometer pulse frequency for fast speed (90.08 ips)
constexpr unsigned TACH_FREQ_SLOW = 21276; // Tachometer pulse frequency for slow speed (21.98 ips)
@@ -243,7 +238,7 @@ enum cmd_t : uint8_t {
CMD_ERASE = 0b000100, // Erase tape
CMD_WR_REVERSAL = 0b000101, // Write flux reversal (*)
CMD_WR = 0b000110, // Write
- CMD_WR_9825 = 0b000111, // Write 9825 (*)
+ CMD_WR_9825 = 0b000111, // Write 9825
CMD_STOP = 0b001000, // Stop
CMD_STOP_INT = 0b001001, // Stop & interrupt
CMD_SET_TRACK = 0b001100, // Set track
@@ -262,17 +257,17 @@ enum cmd_t : uint8_t {
CMD_WR_GAP_N_TACH = 0b101100, // Write gap of N tach
CMD_INT_N_GAP = 0b110000, // Interrupt on N gap
CMD_WR_SYNC = 0b110010, // Write synchronous
- CMD_WR_SYNC_9825 = 0b110011, // Write synchronous 9825 (*)
+ CMD_WR_SYNC_9825 = 0b110011, // Write synchronous 9825
CMD_INT_N_TACH_22 = 0b110100, // Interrupt on N tach after 22 ips
CMD_WR_CSUM = 0b110110, // Write checksum
- CMD_WR_CSUM_9825 = 0b110111, // Write checksum 9825 (*)
+ CMD_WR_CSUM_9825 = 0b110111, // Write checksum 9825
CMD_INT_STOP_N_TACH = 0b111000, // Interrupt and stop on N tach
CMD_INT_STOP_N_TACH1= 0b111001, // Interrupt and stop on N tach (int when stopped)
CMD_RD_6UPD = 0b111010, // Read 6% update
- CMD_RD_9825_6UPD = 0b111011, // Read 9825 6% update (*)
+ CMD_RD_9825_6UPD = 0b111011, // Read 9825 6% update
CMD_INT_N_TACH = 0b111100, // Interrupt on N tach
CMD_RD_CSUM_6UPD = 0b111110, // Read checksum 6% update
- CMD_RD_9825_CSUM6 = 0b111111 // Read checksum 9825 6% update (*)
+ CMD_RD_9825_CSUM6 = 0b111111 // Read checksum 9825 6% update
};
// Device type definition
@@ -281,7 +276,7 @@ DEFINE_DEVICE_TYPE(HP_TACO, hp_taco_device, "hp_taco", "HP TACO")
// Constructors
hp_taco_device::hp_taco_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
- , m_tape(*this , "drive")
+ , m_tape(*this, "drive")
, m_irq_handler(*this)
, m_flg_handler(*this)
, m_sts_handler(*this)
@@ -293,9 +288,14 @@ hp_taco_device::hp_taco_device(const machine_config &mconfig, const char *tag, d
{
}
+void hp_taco_device::set_name(const std::string& name)
+{
+ m_tape->set_name(name);
+}
+
void hp_taco_device::reg_w(offs_t offset, uint16_t data)
{
- LOG_REG("wr R%u = %04x\n", 4 + offset , data);
+ LOG_REG("wr R%u = %04x\n", 4 + offset, data);
// Any I/O activity clears IRQ
irq_w(false);
@@ -339,9 +339,9 @@ uint16_t hp_taco_device::reg_r(offs_t offset)
case 1:
// Command & status register
if (m_tape->gap_reached(SHORT_GAP_LENGTH)) {
- BIT_SET(m_status_reg , CMD_ST_GAP);
+ BIT_SET(m_status_reg, CMD_ST_GAP);
} else {
- BIT_CLR(m_status_reg , CMD_ST_GAP);
+ BIT_CLR(m_status_reg, CMD_ST_GAP);
}
res = (m_cmd_reg & CMD_REG_MASK) | (m_status_reg & STATUS_REG_MASK);
break;
@@ -358,44 +358,44 @@ uint16_t hp_taco_device::reg_r(offs_t offset)
break;
}
- LOG_REG("rd R%u = %04x\n", 4 + offset , res);
+ LOG_REG("rd R%u = %04x\n", 4 + offset, res);
return res;
}
-READ_LINE_MEMBER(hp_taco_device::flg_r)
+int hp_taco_device::flg_r()
{
return m_flg;
}
-READ_LINE_MEMBER(hp_taco_device::sts_r)
+int hp_taco_device::sts_r()
{
return m_sts;
}
-WRITE_LINE_MEMBER(hp_taco_device::cart_out_w)
+void hp_taco_device::cart_out_w(int state)
{
- LOG_DBG("cart_out_w %d\n" , state);
+ LOG_DBG("cart_out_w %d\n", state);
set_tape_present(!state);
if (state && m_cmd_state != CMD_IDLE) {
- set_error(true , false);
+ set_error(true, false);
m_cmd_state = CMD_IDLE;
}
}
-WRITE_LINE_MEMBER(hp_taco_device::hole_w)
+void hp_taco_device::hole_w(int state)
{
if (state) {
LOG_DBG("hole_w\n");
if (m_cmd_state != CMD_IDLE && m_cmd_state != CMD_STOPPING &&
- (!is_double_hole_cmd(m_cmd_reg) || BIT(m_status_reg , CMD_ST_HOLE))) {
- set_error(true , false);
+ (!is_double_hole_cmd(m_cmd_reg) || BIT(m_status_reg, CMD_ST_HOLE))) {
+ set_error(true, false);
}
- BIT_SET(m_status_reg , CMD_ST_HOLE);
+ BIT_SET(m_status_reg, CMD_ST_HOLE);
}
}
-WRITE_LINE_MEMBER(hp_taco_device::tacho_tick_w)
+void hp_taco_device::tacho_tick_w(int state)
{
if (state) {
LOG_DBG("tacho_tick_w\n");
@@ -422,7 +422,7 @@ WRITE_LINE_MEMBER(hp_taco_device::tacho_tick_w)
if (m_cmd_state == CMD_PH2) {
m_tach_reg++;
if (m_tach_reg == 0) {
- if (!BIT(m_cmd_reg , CMD_ST_G0)) {
+ if (!BIT(m_cmd_reg, CMD_ST_G0)) {
irq_w(true);
}
send_stop();
@@ -451,20 +451,22 @@ WRITE_LINE_MEMBER(hp_taco_device::tacho_tick_w)
}
}
-WRITE_LINE_MEMBER(hp_taco_device::motion_w)
+void hp_taco_device::motion_w(int state)
{
if (state) {
cmd_fsm();
}
}
-WRITE_LINE_MEMBER(hp_taco_device::rd_bit_w)
+void hp_taco_device::rd_bit_w(int state)
{
- LOG_RW("RD bit %d (st=%d,w=%04x,i=%u)\n" , state , m_cmd_state , m_working_reg , m_bit_idx);
+ LOG_RW("RD bit %d (st=%d,w=%04x,i=%u)\n", state, m_cmd_state, m_working_reg, m_bit_idx);
if (m_cmd_state != CMD_IDLE) {
switch (get_cmd(m_cmd_reg)) {
case CMD_RD_6UPD:
+ case CMD_RD_9825_6UPD:
case CMD_RD_CSUM_6UPD:
+ case CMD_RD_9825_CSUM6:
if (m_cmd_state == CMD_PH1) {
if (m_bit_idx < 8) {
m_bit_idx++;
@@ -472,30 +474,34 @@ WRITE_LINE_MEMBER(hp_taco_device::rd_bit_w)
// Synchronized
LOG_RW("RD synced!\n");
m_cmd_state = CMD_PH2;
- m_bit_idx = 15;
+ m_bit_idx = BIT(m_cmd_reg, CMD_ST_G0) ? 17 : 15;
m_working_reg = 0;
}
} else if (m_cmd_state == CMD_PH2) {
- if (state) {
- BIT_SET(m_working_reg , m_bit_idx);
+ if (m_bit_idx == 17) {
+ // 9825 format: skip first 17th bit after preamble
+ m_bit_idx = 15;
+ break;
+ } else if (m_bit_idx != 16 && state) {
+ // Skip 17th bit when reading in 9825 format
+ BIT_SET(m_working_reg, m_bit_idx);
}
- if (m_bit_idx) {
- m_bit_idx--;
- } else {
+ if (adv_bit_idx()) {
m_data_reg = m_working_reg;
- m_bit_idx = 15;
m_working_reg = 0;
- if (!BIT(m_cmd_reg , CMD_ST_G2)) {
+ if (!BIT(m_cmd_reg, CMD_ST_G2)) {
update_checksum(m_data_reg);
}
- LOG_RW("RD word %04x csum=%04x\n" , m_data_reg , m_checksum_reg);
+ LOG_RW("RD word %04x csum=%04x\n", m_data_reg, m_checksum_reg);
irq_w(true);
}
}
break;
case CMD_WR_SYNC:
+ case CMD_WR_SYNC_9825:
case CMD_WR_CSUM:
+ case CMD_WR_CSUM_9825:
if (m_cmd_state == CMD_PH1) {
LOG_RW("WR synced\n");
m_cmd_state = CMD_PH2;
@@ -510,35 +516,38 @@ WRITE_LINE_MEMBER(hp_taco_device::rd_bit_w)
}
}
-READ_LINE_MEMBER(hp_taco_device::wr_bit_r)
+int hp_taco_device::wr_bit_r()
{
bool bit = false;
if (is_cmd_wr(m_cmd_reg) && m_cmd_state == CMD_PH2) {
- bit = BIT(m_working_reg , m_bit_idx);
- if (m_bit_idx) {
- m_bit_idx--;
+ if (m_bit_idx == 16) {
+ // HP9825 format: 17th bit
+ bit = true;
} else {
- m_bit_idx = 15;
+ bit = BIT(m_working_reg, m_bit_idx);
+ }
+ if (adv_bit_idx()) {
m_working_reg = m_data_reg;
- if (get_cmd(m_cmd_reg) != CMD_WR_CSUM) {
+ // Bit 0 selects HP9825 mode: it is to be ignored here
+ if ((get_cmd(m_cmd_reg) & ~BIT_MASK<uint8_t>(0)) != CMD_WR_CSUM) {
update_checksum(m_data_reg);
}
- LOG_RW("WR word %04x csum=%04x\n" , m_working_reg , m_checksum_reg);
+ LOG_RW("WR word %04x csum=%04x\n", m_working_reg, m_checksum_reg);
m_data_reg = m_checksum_reg;
irq_w(true);
}
}
- LOG_RW("WR bit %d (w=%04x,i=%u)\n" , bit , m_working_reg , m_bit_idx);
+ LOG_RW("WR bit %d (w=%04x,i=%u)\n", bit, m_working_reg, m_bit_idx);
return bit;
}
void hp_taco_device::device_add_mconfig(machine_config &config)
{
- HP_DC100_TAPE(config , m_tape , 0);
+ HP_DC100_TAPE(config, m_tape, 0);
m_tape->set_acceleration(ACCELERATION);
- m_tape->set_set_points(SLOW_SPEED , FAST_SPEED);
+ m_tape->set_set_points(SLOW_SPEED, FAST_SPEED);
m_tape->set_tick_size(TACH_TICK_LEN);
- m_tape->set_bits_per_word(16);
+ m_tape->set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS);
m_tape->set_go_threshold(MOVING_THRESHOLD);
m_tape->cart_out().set(FUNC(hp_taco_device::cart_out_w));
m_tape->hole().set(FUNC(hp_taco_device::hole_w));
@@ -551,10 +560,6 @@ void hp_taco_device::device_add_mconfig(machine_config &config)
void hp_taco_device::device_start()
{
LOG("device_start\n");
- m_irq_handler.resolve_safe();
- m_flg_handler.resolve_safe();
- m_sts_handler.resolve_safe();
-
save_item(NAME(m_data_reg));
save_item(NAME(m_cmd_reg));
save_item(NAME(m_status_reg));
@@ -569,9 +574,9 @@ void hp_taco_device::device_start()
save_item(NAME(m_working_reg));
save_item(NAME(m_bit_idx));
- m_gap_timer = timer_alloc(GAP_TMR_ID);
- m_evd_timer = timer_alloc(EVD_TMR_ID);
- m_error_timer = timer_alloc(ERROR_TMR_ID);
+ m_gap_timer = timer_alloc(FUNC(hp_taco_device::gap_timer_tick), this);
+ m_evd_timer = timer_alloc(FUNC(hp_taco_device::evd_timer_tick), this);
+ m_error_timer = timer_alloc(FUNC(hp_taco_device::error_timer_tick), this);
}
void hp_taco_device::device_reset()
@@ -586,67 +591,51 @@ void hp_taco_device::device_reset()
m_irq_handler(false);
m_flg_handler(true);
m_sts_handler(true);
- set_error(false , false);
+ set_error(false, false);
m_gap_timer->reset();
m_evd_timer->reset();
m_error_timer->reset();
}
-void hp_taco_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(hp_taco_device::gap_timer_tick)
{
- switch (id) {
- case GAP_TMR_ID:
- m_tape->update_speed_pos();
- LOG_DBG("Gap tmr @%g pos=%d cmd %02x st %d\n" , machine().time().as_double() , m_tape->get_pos() , get_cmd(m_cmd_reg) , m_cmd_state);
-
- switch (get_cmd(m_cmd_reg)) {
- case CMD_INT_ON_GAP:
- if (m_cmd_state == CMD_PH1) {
- irq_and_end();
- }
- break;
-
- case CMD_STOP_IN_GAP:
- case CMD_STOP_IN_GAP1:
- if (m_cmd_state == CMD_PH1) {
- // Count 256 ticks
- m_tach_reg = 0xff00;
- m_cmd_state = CMD_PH2;
- }
- break;
-
- case CMD_INT_N_GAP:
- if (m_cmd_state == CMD_PH1) {
- m_tach_reg++;
- if (m_tach_reg == 0) {
- irq_and_end();
- } else {
- set_gap_timer();
- }
- }
- break;
+ m_tape->update_speed_pos();
+ LOG_DBG("Gap tmr @%g pos=%d cmd %02x st %d\n", machine().time().as_double(), m_tape->get_pos(), get_cmd(m_cmd_reg), m_cmd_state);
- case CMD_RD_6UPD:
- case CMD_RD_CSUM_6UPD:
- // Gap in read error
- set_error(false , true);
- break;
+ switch (get_cmd(m_cmd_reg)) {
+ case CMD_INT_ON_GAP:
+ if (m_cmd_state == CMD_PH1) {
+ irq_and_end();
+ }
+ break;
- default:
- break;
+ case CMD_STOP_IN_GAP:
+ case CMD_STOP_IN_GAP1:
+ if (m_cmd_state == CMD_PH1) {
+ // Count 256 ticks
+ m_tach_reg = 0xff00;
+ m_cmd_state = CMD_PH2;
}
break;
- case EVD_TMR_ID:
- m_tape->update_speed_pos();
- LOG_DBG("EVD tmr @%g pos=%d cmd %02x st %d\n" , machine().time().as_double() , m_tape->get_pos() , get_cmd(m_cmd_reg) , m_cmd_state);
- set_error(true , false);
+ case CMD_INT_N_GAP:
+ if (m_cmd_state == CMD_PH1) {
+ m_tach_reg++;
+ if (m_tach_reg == 0) {
+ irq_and_end();
+ } else {
+ set_gap_timer();
+ }
+ }
break;
- case ERROR_TMR_ID:
- LOG_DBG("Error tmr\n");
- irq_w(true);
+ case CMD_RD_6UPD:
+ case CMD_RD_9825_6UPD:
+ case CMD_RD_CSUM_6UPD:
+ case CMD_RD_9825_CSUM6:
+ // Gap in read error
+ set_error(false, true);
break;
default:
@@ -654,6 +643,19 @@ void hp_taco_device::device_timer(emu_timer &timer, device_timer_id id, int para
}
}
+TIMER_CALLBACK_MEMBER(hp_taco_device::evd_timer_tick)
+{
+ m_tape->update_speed_pos();
+ LOG_DBG("EVD tmr @%g pos=%d cmd %02x st %d\n", machine().time().as_double(), m_tape->get_pos(), get_cmd(m_cmd_reg), m_cmd_state);
+ set_error(true, false);
+}
+
+TIMER_CALLBACK_MEMBER(hp_taco_device::error_timer_tick)
+{
+ LOG_DBG("Error tmr\n");
+ irq_w(true);
+}
+
void hp_taco_device::clear_state()
{
m_data_reg = 0;
@@ -675,7 +677,7 @@ void hp_taco_device::irq_w(bool state)
if (state != m_irq) {
m_irq = state;
m_irq_handler(state);
- LOG_DBG("IRQ = %d\n" , state);
+ LOG_DBG("IRQ = %d\n", state);
}
}
@@ -684,13 +686,13 @@ void hp_taco_device::sts_w(bool state)
if (state != m_sts) {
m_sts = state;
m_sts_handler(state);
- LOG_DBG("STS = %d\n" , state);
+ LOG_DBG("STS = %d\n", state);
}
}
-void hp_taco_device::set_error(bool error , bool gap_in_read)
+void hp_taco_device::set_error(bool error, bool gap_in_read)
{
- LOG_DBG("Error %d %d\n" , error , gap_in_read);
+ LOG_DBG("Error %d %d\n", error, gap_in_read);
m_error = error;
m_gap_in_read = gap_in_read;
@@ -702,7 +704,7 @@ void hp_taco_device::set_error(bool error , bool gap_in_read)
m_cmd_state = CMD_IDLE;
}
sts_w(false);
- m_error_timer->adjust(attotime::zero , 0 , clocks_to_attotime(ERROR_IRQ_PERIOD));
+ m_error_timer->adjust(attotime::zero, 0, clocks_to_attotime(ERROR_IRQ_PERIOD));
if (m_error) {
send_stop();
}
@@ -713,17 +715,17 @@ void hp_taco_device::set_error(bool error , bool gap_in_read)
hti_format_t::tape_pos_t hp_taco_device::min_gap_size() const
{
- return BIT(m_cmd_reg , CMD_ST_FGAP) ? LONG_GAP_LENGTH : SHORT_GAP_LENGTH;
+ return BIT(m_cmd_reg, CMD_ST_FGAP) ? LONG_GAP_LENGTH : SHORT_GAP_LENGTH;
}
void hp_taco_device::set_gap_timer()
{
- m_tape->time_to_next_gap(min_gap_size() , true , m_gap_timer);
+ m_tape->time_to_next_gap(min_gap_size(), true, m_gap_timer);
}
void hp_taco_device::set_evd_timer()
{
- m_tape->time_to_next_gap(EVD_GAP_LENGTH , false , m_evd_timer);
+ m_tape->time_to_next_gap(EVD_GAP_LENGTH, false, m_evd_timer);
}
void hp_taco_device::set_tape_present(bool present)
@@ -745,18 +747,18 @@ void hp_taco_device::send_go()
{
hp_dc100_tape_device::tape_speed_t speed;
- if (BIT(m_cmd_reg , CMD_ST_FST)) {
+ if (BIT(m_cmd_reg, CMD_ST_FST)) {
speed = hp_dc100_tape_device::SP_FAST;
} else {
speed = hp_dc100_tape_device::SP_SLOW;
}
- m_tape->set_speed_setpoint(speed , BIT(m_cmd_reg , CMD_ST_FWD));
+ m_tape->set_speed_setpoint(speed, BIT(m_cmd_reg, CMD_ST_FWD));
}
void hp_taco_device::send_stop()
{
m_tape->set_op(hp_dc100_tape_device::OP_IDLE);
- if (m_tape->set_speed_setpoint(hp_dc100_tape_device::SP_STOP , false)) {
+ if (m_tape->set_speed_setpoint(hp_dc100_tape_device::SP_STOP, false)) {
m_cmd_state = CMD_STOPPING;
}
}
@@ -784,7 +786,7 @@ void hp_taco_device::start_rd()
if (m_tape->get_op() != hp_dc100_tape_device::OP_READ) {
m_tape->set_op(hp_dc100_tape_device::OP_READ);
// TODO: check
- m_tape->time_to_next_gap(GIR_GAP_LENGTH , true , m_gap_timer);
+ m_tape->time_to_next_gap(GIR_GAP_LENGTH, true, m_gap_timer);
set_evd_timer();
}
}
@@ -796,6 +798,16 @@ void hp_taco_device::start_wr()
m_evd_timer->reset();
}
+bool hp_taco_device::adv_bit_idx()
+{
+ if (m_bit_idx) {
+ m_bit_idx--;
+ } else {
+ m_bit_idx = BIT(m_cmd_reg, CMD_ST_G0) ? 16 : 15;
+ }
+ return m_bit_idx == 15;
+}
+
void hp_taco_device::update_checksum(uint16_t data)
{
// Update checksum with data
@@ -832,6 +844,7 @@ void hp_taco_device::cmd_fsm()
break;
case CMD_WR:
+ case CMD_WR_9825:
if (m_cmd_state == CMD_PH0 && is_at_slow_speed()) {
m_cmd_state = CMD_PH2;
m_bit_idx = 15;
@@ -873,7 +886,9 @@ void hp_taco_device::cmd_fsm()
break;
case CMD_WR_SYNC:
+ case CMD_WR_SYNC_9825:
case CMD_WR_CSUM:
+ case CMD_WR_CSUM_9825:
if (m_cmd_state == CMD_PH0 && is_at_slow_speed()) {
m_cmd_state = CMD_PH1;
start_rd();
@@ -895,7 +910,9 @@ void hp_taco_device::cmd_fsm()
break;
case CMD_RD_6UPD:
+ case CMD_RD_9825_6UPD:
case CMD_RD_CSUM_6UPD:
+ case CMD_RD_9825_CSUM6:
if (m_cmd_state == CMD_PH0 && is_at_slow_speed()) {
m_cmd_state = CMD_PH1;
start_rd();
@@ -911,7 +928,7 @@ void hp_taco_device::cmd_fsm()
}
}
if (prev_state != m_cmd_state) {
- LOG_DBG("FSM st %d->%d\n" , prev_state , m_cmd_state);
+ LOG_DBG("FSM st %d->%d\n", prev_state, m_cmd_state);
}
}
@@ -924,17 +941,17 @@ uint8_t hp_taco_device::get_cmd(uint16_t cmd_reg)
bool hp_taco_device::is_cmd_rd_wr(uint16_t cmd_reg)
{
- return BIT(cmd_reg , CMD_ST_G1);
+ return BIT(cmd_reg, CMD_ST_G1);
}
bool hp_taco_device::is_cmd_rd(uint16_t cmd_reg)
{
- return is_cmd_rd_wr(cmd_reg) && BIT(cmd_reg , CMD_ST_G3);
+ return is_cmd_rd_wr(cmd_reg) && BIT(cmd_reg, CMD_ST_G3);
}
bool hp_taco_device::is_cmd_wr(uint16_t cmd_reg)
{
- return is_cmd_rd_wr(cmd_reg) && !BIT(cmd_reg , CMD_ST_G3);
+ return is_cmd_rd_wr(cmd_reg) && !BIT(cmd_reg, CMD_ST_G3);
}
bool hp_taco_device::is_double_hole_cmd(uint16_t cmd_reg)
@@ -944,7 +961,7 @@ bool hp_taco_device::is_double_hole_cmd(uint16_t cmd_reg)
void hp_taco_device::start_cmd_exec(uint16_t new_cmd_reg)
{
- LOG_DBG("New cmd %02x D=%d S=%d @ %g cmd %02x st %d\n" , get_cmd(new_cmd_reg) , BIT(new_cmd_reg , CMD_ST_FWD) , BIT(new_cmd_reg , CMD_ST_FST) , machine().time().as_double() , get_cmd(m_cmd_reg) , m_cmd_state);
+ LOG_DBG("New cmd %02x D=%d S=%d @ %g cmd %02x st %d\n", get_cmd(new_cmd_reg), BIT(new_cmd_reg, CMD_ST_FWD), BIT(new_cmd_reg, CMD_ST_FST), machine().time().as_double(), get_cmd(m_cmd_reg), m_cmd_state);
m_tape->update_speed_pos();
@@ -952,7 +969,7 @@ void hp_taco_device::start_cmd_exec(uint16_t new_cmd_reg)
if (new_cmd_code == CMD_CLEAR_ST) {
// Clear status
- set_error(false , false);
+ set_error(false, false);
sts_w(true);
if (!m_tape->cart_out_r()) {
BIT_CLR(m_status_reg, CMD_ST_CART_OUT);
@@ -967,7 +984,7 @@ void hp_taco_device::start_cmd_exec(uint16_t new_cmd_reg)
hp_dc100_tape_device::tape_op_t op = hp_dc100_tape_device::OP_IDLE;
if (m_gap_in_read) {
- set_error(false , false);
+ set_error(false, false);
}
m_cmd_state = CMD_PH0;
@@ -987,8 +1004,11 @@ void hp_taco_device::start_cmd_exec(uint16_t new_cmd_reg)
break;
case CMD_WR:
+ case CMD_WR_9825:
case CMD_WR_SYNC:
+ case CMD_WR_SYNC_9825:
case CMD_WR_CSUM:
+ case CMD_WR_CSUM_9825:
// 1. Wait for tape to reach 22 ips
// 2. Wait for data to begin (not for CMD_WR)
// 3. Write words on tape
@@ -1014,11 +1034,11 @@ void hp_taco_device::start_cmd_exec(uint16_t new_cmd_reg)
case CMD_SET_TRACK:
// 1. Set A/B track
- if (BIT(new_cmd_reg , CMD_ST_MOD)) {
- BIT_SET(m_status_reg , CMD_ST_TRB);
+ if (BIT(new_cmd_reg, CMD_ST_MOD)) {
+ BIT_SET(m_status_reg, CMD_ST_TRB);
m_tape->set_track_no(1);
} else {
- BIT_CLR(m_status_reg , CMD_ST_TRB);
+ BIT_CLR(m_status_reg, CMD_ST_TRB);
m_tape->set_track_no(0);
}
start_tape = false;
@@ -1073,7 +1093,9 @@ void hp_taco_device::start_cmd_exec(uint16_t new_cmd_reg)
break;
case CMD_RD_6UPD:
+ case CMD_RD_9825_6UPD:
case CMD_RD_CSUM_6UPD:
+ case CMD_RD_9825_CSUM6:
// 1. Wait for tape to reach 22 ips
// 2. Wait for preamble
// 3. Read words
@@ -1092,16 +1114,16 @@ void hp_taco_device::start_cmd_exec(uint16_t new_cmd_reg)
break;
default:
- LOG("Unrecognized command %x\n" , new_cmd_code);
+ LOG("Unrecognized command %x\n", new_cmd_code);
start_tape = false;
break;
}
if (start_tape) {
if (m_error ||
- (BIT(m_status_reg , CMD_ST_HOLE) && !is_double_hole_cmd(new_cmd_reg)) ||
- BIT(m_status_reg , CMD_ST_CART_OUT)) {
- set_error(true , false);
+ (BIT(m_status_reg, CMD_ST_HOLE) && !is_double_hole_cmd(new_cmd_reg)) ||
+ BIT(m_status_reg, CMD_ST_CART_OUT)) {
+ set_error(true, false);
return;
} else {
send_go();
diff --git a/src/devices/machine/hp_taco.h b/src/devices/machine/hp_taco.h
index 0ea70122b7f..7c92a33618c 100644
--- a/src/devices/machine/hp_taco.h
+++ b/src/devices/machine/hp_taco.h
@@ -27,20 +27,23 @@ public:
auto flg() { return m_flg_handler.bind(); }
auto sts() { return m_sts_handler.bind(); }
+ // Set unit name
+ void set_name(const std::string& name);
+
// Register read/write
void reg_w(offs_t offset, uint16_t data);
uint16_t reg_r(offs_t offset);
// Flag & status read
- DECLARE_READ_LINE_MEMBER(flg_r);
- DECLARE_READ_LINE_MEMBER(sts_r);
+ int flg_r();
+ int sts_r();
- DECLARE_WRITE_LINE_MEMBER(cart_out_w);
- DECLARE_WRITE_LINE_MEMBER(hole_w);
- DECLARE_WRITE_LINE_MEMBER(tacho_tick_w);
- DECLARE_WRITE_LINE_MEMBER(motion_w);
- DECLARE_WRITE_LINE_MEMBER(rd_bit_w);
- DECLARE_READ_LINE_MEMBER(wr_bit_r);
+ void cart_out_w(int state);
+ void hole_w(int state);
+ void tacho_tick_w(int state);
+ void motion_w(int state);
+ void rd_bit_w(int state);
+ int wr_bit_r();
protected:
hp_taco_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -49,7 +52,10 @@ protected:
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(gap_timer_tick);
+ TIMER_CALLBACK_MEMBER(evd_timer_tick);
+ TIMER_CALLBACK_MEMBER(error_timer_tick);
private:
required_device<hp_dc100_tape_device> m_tape;
@@ -107,6 +113,7 @@ private:
bool is_at_slow_speed() const;
void start_rd();
void start_wr();
+ bool adv_bit_idx();
void update_checksum(uint16_t data);
void cmd_fsm();
static uint8_t get_cmd(uint16_t cmd_reg);
diff --git a/src/devices/machine/i2cmem.cpp b/src/devices/machine/i2cmem.cpp
index 94c08716f97..625ecb1cabe 100644
--- a/src/devices/machine/i2cmem.cpp
+++ b/src/devices/machine/i2cmem.cpp
@@ -23,15 +23,18 @@ there are two standard values.
***************************************************************************/
#include "emu.h"
-#include "machine/i2cmem.h"
+#include "i2cmem.h"
+
+#include <cstdarg>
constexpr int STATE_IDLE(0);
constexpr int STATE_DEVSEL(1);
constexpr int STATE_ADDRESSHIGH(2);
constexpr int STATE_ADDRESSLOW(3);
constexpr int STATE_DATAIN(4);
-constexpr int STATE_DATAOUT(5);
-constexpr int STATE_RESET(6);
+constexpr int STATE_READSELACK(5);
+constexpr int STATE_DATAOUT(6);
+constexpr int STATE_RESET(7);
constexpr int DEVSEL_RW(1);
constexpr int DEVSEL_ADDRESS(0xfe);
@@ -49,7 +52,7 @@ static inline void ATTR_PRINTF( 3, 4 ) verboselog( device_t *device, int n_level
va_list v;
char buf[ 32768 ];
va_start( v, s_fmt );
- vsprintf( buf, s_fmt, v );
+ vsnprintf( buf, 32768, s_fmt, v );
va_end( v );
device->logerror( "%s: I2CMEM %s", device->machine().describe_context(), buf );
}
@@ -60,16 +63,19 @@ static inline void ATTR_PRINTF( 3, 4 ) verboselog( device_t *device, int n_level
//**************************************************************************
// device type definition
-DEFINE_DEVICE_TYPE(I2C_24C01, i2c_24c01_device, "24c01", "24C01 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_PCD8572, i2c_pcd8572_device, "pcd8572", "PCD8572 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_24C02, i2c_24c02_device, "24c02", "24C02 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_M24C02, i2c_m24c02_device, "m24c02", "M24C02 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_24C04, i2c_24c04_device, "24c04", "24C04 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_X2404P, i2c_x2404p_device, "x2404p", "X2404P I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_24C08, i2c_24c08_device, "24c08", "24C08 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_24C16, i2c_24c16_device, "24c16", "24C16 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_24C64, i2c_24c64_device, "24c64", "24C64 I2C Memory")
-DEFINE_DEVICE_TYPE(I2C_24C512, i2c_24c512_device, "24c512", "24C512 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_X24C01, i2c_x24c01_device, "x24c01", "X24C01 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_24C01, i2c_24c01_device, "24c01", "24C01 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_PCF8570, i2c_pcf8570_device, "pcf8570", "PCF8570 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_PCD8572, i2c_pcd8572_device, "pcd8572", "PCD8572 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_PCF8582, i2c_pcf8582_device, "pcf8582", "PCF8582 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_24C02, i2c_24c02_device, "24c02", "24C02 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_M24C02, i2c_m24c02_device, "m24c02", "M24C02 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_24C04, i2c_24c04_device, "24c04", "24C04 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_X2404P, i2c_x2404p_device, "x2404p", "X2404P I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_24C08, i2c_24c08_device, "24c08", "24C08 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_24C16, i2c_24c16_device, "24c16", "24C16 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_24C64, i2c_24c64_device, "24c64", "24C64 I2C Memory")
+DEFINE_DEVICE_TYPE(I2C_24C512, i2c_24c512_device, "24c512", "24C512 I2C Memory")
//**************************************************************************
// LIVE DEVICE
@@ -103,27 +109,45 @@ i2cmem_device::i2cmem_device(
m_wc(0),
m_sdar(1),
m_state(STATE_IDLE),
+ m_bits(0),
m_shift(0),
m_devsel(0),
m_addresshigh(0),
m_byteaddr(0),
m_page_offset(0),
- m_page_written_size(0)
+ m_page_written_size(0),
+ m_devsel_address_low(false)
{
// these memories work off the I2C clock only
assert(!clock);
}
+i2c_x24c01_device::i2c_x24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i2cmem_device(mconfig, I2C_X24C01, tag, owner, clock, 0, 8, 0x80)
+{
+ set_devsel_address_low(true);
+}
+
i2c_24c01_device::i2c_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
i2cmem_device(mconfig, I2C_24C01, tag, owner, clock, 0, 8, 0x80)
{
}
+i2c_pcf8570_device::i2c_pcf8570_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ i2cmem_device(mconfig, I2C_PCF8570, tag, owner, clock, 0, 0, 0x100)
+{
+}
+
i2c_pcd8572_device::i2c_pcd8572_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
i2cmem_device(mconfig, I2C_PCD8572, tag, owner, clock, 0, 0, 0x80)
{
}
+i2c_pcf8582_device::i2c_pcf8582_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
+ i2cmem_device(mconfig, I2C_PCF8582, tag, owner, clock, 0, 0, 0x100)
+{
+}
+
i2c_24c02_device::i2c_24c02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
i2cmem_device(mconfig, I2C_24C02, tag, owner, clock, 0, 8, 0x100)
{
@@ -229,9 +253,10 @@ void i2cmem_device::nvram_default()
// .nv file
//-------------------------------------------------
-void i2cmem_device::nvram_read( emu_file &file )
+bool i2cmem_device::nvram_read( util::read_stream &file )
{
- file.read( &m_data[0], m_data_size );
+ auto const [err, actual] = read( file, &m_data[0], m_data_size );
+ return !err && ( actual == m_data_size );
}
//-------------------------------------------------
@@ -239,9 +264,10 @@ void i2cmem_device::nvram_read( emu_file &file )
// .nv file
//-------------------------------------------------
-void i2cmem_device::nvram_write( emu_file &file )
+bool i2cmem_device::nvram_write( util::write_stream &file )
{
- file.write( &m_data[0], m_data_size );
+ auto const [err, actual] = write( file, &m_data[0], m_data_size );
+ return !err;
}
@@ -250,7 +276,7 @@ void i2cmem_device::nvram_write( emu_file &file )
// READ/WRITE HANDLERS
//**************************************************************************
-WRITE_LINE_MEMBER( i2cmem_device::write_e0 )
+void i2cmem_device::write_e0(int state)
{
state &= 1;
if( m_e0 != state )
@@ -261,7 +287,7 @@ WRITE_LINE_MEMBER( i2cmem_device::write_e0 )
}
-WRITE_LINE_MEMBER( i2cmem_device::write_e1 )
+void i2cmem_device::write_e1(int state)
{
state &= 1;
if( m_e1 != state )
@@ -272,7 +298,7 @@ WRITE_LINE_MEMBER( i2cmem_device::write_e1 )
}
-WRITE_LINE_MEMBER( i2cmem_device::write_e2 )
+void i2cmem_device::write_e2(int state)
{
state &= 1;
if( m_e2 != state )
@@ -283,7 +309,7 @@ WRITE_LINE_MEMBER( i2cmem_device::write_e2 )
}
-WRITE_LINE_MEMBER( i2cmem_device::write_sda )
+void i2cmem_device::write_sda(int state)
{
state &= 1;
if( m_sdaw != state )
@@ -310,7 +336,7 @@ WRITE_LINE_MEMBER( i2cmem_device::write_sda )
}
else
{
- verboselog( this, 2, "start\n" );
+ verboselog( this, 1, "start\n" );
m_state = STATE_DEVSEL;
m_bits = 0;
}
@@ -320,7 +346,7 @@ WRITE_LINE_MEMBER( i2cmem_device::write_sda )
}
}
-WRITE_LINE_MEMBER( i2cmem_device::write_scl )
+void i2cmem_device::write_scl(int state)
{
if( m_scl != state )
{
@@ -345,91 +371,112 @@ WRITE_LINE_MEMBER( i2cmem_device::write_scl )
{
if( m_scl )
{
- switch( m_state )
- {
- case STATE_DEVSEL:
- m_devsel = m_shift;
-
- if( m_devsel == 0 )
- {
- // TODO: Atmel datasheets document 2-wire software reset, but doesn't mention it will lower sda only that it will release it.
- // ltv_naru however requires it to be lowered, but we don't currently know the manufacturer of the chip used.
- verboselog( this, 1, "software reset\n" );
- m_state = STATE_RESET;
- m_sdar = 0;
- }
- else if( !select_device() )
- {
- verboselog( this, 1, "devsel %02x: not this device\n", m_devsel );
- m_state = STATE_IDLE;
- }
- else if( ( m_devsel & DEVSEL_RW ) == 0 )
- {
- verboselog( this, 1, "devsel %02x: write\n", m_devsel );
- m_state = skip_addresshigh() ? STATE_ADDRESSLOW : STATE_ADDRESSHIGH;
- }
- else
- {
- verboselog( this, 1, "devsel %02x: read\n", m_devsel );
- m_state = STATE_DATAOUT;
- }
- break;
-
- case STATE_ADDRESSHIGH:
- m_addresshigh = m_shift;
-
- verboselog(this, 1, "addresshigh %02x\n", m_addresshigh);
-
- m_state = STATE_ADDRESSLOW;
- break;
-
- case STATE_ADDRESSLOW:
- m_byteaddr = m_shift | (skip_addresshigh() ? ((m_devsel & DEVSEL_ADDRESS) << 7) & address_mask() : m_addresshigh << 8);
- m_page_offset = 0;
- m_page_written_size = 0;
-
- verboselog( this, 1, "addresslow %02x (byteaddr %04x)\n", m_shift, m_byteaddr );
-
- m_state = STATE_DATAIN;
- break;
-
- case STATE_DATAIN:
- if( m_wc )
- {
- verboselog( this, 0, "write not enabled\n" );
- m_state = STATE_IDLE;
- }
- else if( m_write_page_size > 0 )
- {
- m_page[ m_page_offset ] = m_shift;
- verboselog( this, 1, "page[ %04x ] <- %02x\n", m_page_offset, m_page[ m_page_offset ] );
-
- m_page_offset++;
- if( m_page_offset == m_write_page_size )
- m_page_offset = 0;
- m_page_written_size++;
- if( m_page_written_size > m_write_page_size)
- m_page_written_size = m_write_page_size;
- }
- else
- {
- int offset = data_offset();
-
- verboselog( this, 1, "data[ %04x ] <- %02x\n", offset, m_shift );
- m_data[ offset ] = m_shift;
-
- m_byteaddr++;
- }
- break;
- }
-
m_bits++;
}
else
{
if( m_bits == 8 )
{
- m_sdar = 0;
+ switch( m_state )
+ {
+ case STATE_DEVSEL:
+ m_devsel = m_shift;
+
+ if( m_devsel == 0 && !m_devsel_address_low )
+ {
+ // TODO: Atmel datasheets document 2-wire software reset, but doesn't mention it will lower sda only that it will release it.
+ // ltv_naru however requires it to be lowered, but we don't currently know the manufacturer of the chip used.
+ verboselog( this, 1, "software reset\n" );
+ m_state = STATE_RESET;
+ }
+ else if( !select_device() )
+ {
+ verboselog( this, 1, "devsel %02x: not this device\n", m_devsel );
+ m_state = STATE_IDLE;
+ }
+ else if( ( m_devsel & DEVSEL_RW ) == 0 )
+ {
+ if (m_devsel_address_low)
+ {
+ verboselog( this, 1, "devsel %02x: write (Xicor special, address %02x)\n", m_devsel, m_devsel >> 1);
+ m_byteaddr = (m_devsel & DEVSEL_ADDRESS) >> 1;
+ m_page_offset = 0;
+ m_page_written_size = 0;
+ m_state = STATE_DATAIN;
+ }
+ else
+ {
+ verboselog( this, 1, "devsel %02x: write\n", m_devsel );
+ m_state = skip_addresshigh() ? STATE_ADDRESSLOW : STATE_ADDRESSHIGH;
+ }
+ }
+ else
+ {
+ if (m_devsel_address_low)
+ {
+ verboselog( this, 1, "devsel %02x: read (Xicor special, address %02x)\n", m_devsel, m_devsel >> 1);
+ m_byteaddr = (m_devsel & DEVSEL_ADDRESS) >> 1;
+ }
+ else
+ {
+ verboselog( this, 1, "devsel %02x: read\n", m_devsel );
+ }
+ m_state = STATE_READSELACK;
+ }
+ break;
+
+ case STATE_ADDRESSHIGH:
+ m_addresshigh = m_shift;
+
+ verboselog(this, 1, "addresshigh %02x\n", m_addresshigh);
+
+ m_state = STATE_ADDRESSLOW;
+ break;
+
+ case STATE_ADDRESSLOW:
+ m_byteaddr = m_shift | (skip_addresshigh() ? ((m_devsel & DEVSEL_ADDRESS) << 7) & address_mask() : m_addresshigh << 8);
+ m_page_offset = 0;
+ m_page_written_size = 0;
+
+ verboselog( this, 1, "addresslow %02x (byteaddr %04x)\n", m_shift, m_byteaddr );
+
+ m_state = STATE_DATAIN;
+ break;
+
+ case STATE_DATAIN:
+ if( m_wc )
+ {
+ verboselog( this, 0, "write not enabled\n" );
+ m_state = STATE_IDLE;
+ }
+ else if( m_write_page_size > 0 )
+ {
+ m_page[ m_page_offset ] = m_shift;
+ verboselog( this, 1, "page[ %04x ] <- %02x\n", m_page_offset, m_page[ m_page_offset ] );
+
+ m_page_offset++;
+ if( m_page_offset == m_write_page_size )
+ m_page_offset = 0;
+ m_page_written_size++;
+ if( m_page_written_size > m_write_page_size)
+ m_page_written_size = m_write_page_size;
+ }
+ else
+ {
+ int offset = data_offset();
+
+ verboselog( this, 1, "data[ %04x ] <- %02x\n", offset, m_shift );
+ m_data[ offset ] = m_shift;
+
+ m_byteaddr++;
+ }
+ break;
+ }
+
+ if( m_state != STATE_IDLE )
+ {
+ m_sdar = 0 ;
+ }
}
else
{
@@ -440,11 +487,20 @@ WRITE_LINE_MEMBER( i2cmem_device::write_scl )
}
break;
+ case STATE_READSELACK:
+ m_bits = 0;
+ m_state = STATE_DATAOUT;
+ break;
+
case STATE_DATAOUT:
if( m_bits < 8 )
{
if( m_scl )
{
+ m_bits++;
+ }
+ else
+ {
if( m_bits == 0 )
{
int offset = data_offset();
@@ -457,7 +513,6 @@ WRITE_LINE_MEMBER( i2cmem_device::write_scl )
m_sdar = ( m_shift >> 7 ) & 1;
m_shift = ( m_shift << 1 ) & 0xff;
- m_bits++;
}
}
else
@@ -470,18 +525,11 @@ WRITE_LINE_MEMBER( i2cmem_device::write_scl )
m_state = STATE_IDLE;
}
- m_bits++;
+ m_bits = 0;
}
else
{
- if( m_bits == 8 )
- {
- m_sdar = 1;
- }
- else
- {
- m_bits = 0;
- }
+ m_sdar = 1;
}
}
break;
@@ -489,9 +537,13 @@ WRITE_LINE_MEMBER( i2cmem_device::write_scl )
case STATE_RESET:
if( m_scl )
{
- verboselog(this, 1, "software reset ack\n");
- m_state = STATE_IDLE;
- m_sdar = 1;
+ if( m_bits > 8 )
+ {
+ verboselog(this, 1, "software reset ack\n");
+ m_state = STATE_IDLE;
+ m_sdar = 1;
+ }
+ m_bits++;
}
break;
}
@@ -499,7 +551,7 @@ WRITE_LINE_MEMBER( i2cmem_device::write_scl )
}
-WRITE_LINE_MEMBER( i2cmem_device::write_wc )
+void i2cmem_device::write_wc(int state)
{
state &= 1;
if( m_wc != state )
@@ -510,10 +562,9 @@ WRITE_LINE_MEMBER( i2cmem_device::write_wc )
}
-READ_LINE_MEMBER( i2cmem_device::read_sda )
+int i2cmem_device::read_sda()
{
int res = m_sdar & 1;
-
verboselog( this, 2, "read sda %d\n", res );
return res;
@@ -531,6 +582,12 @@ int i2cmem_device::address_mask()
int i2cmem_device::select_device()
{
+ if ( m_devsel_address_low )
+ {
+ // Due to a full address and read/write flag fitting in one 8-bit packet, the Xicor X24C01 replies on all addresses.
+ return 1;
+ }
+
int device = ( m_slave_address & 0xf0 ) | ( m_e2 << 3 ) | ( m_e1 << 2 ) | ( m_e0 << 1 );
int mask = DEVSEL_ADDRESS & ~( skip_addresshigh() ? address_mask() >> 7 : 0 );
diff --git a/src/devices/machine/i2cmem.h b/src/devices/machine/i2cmem.h
index 3a7916a838a..07aebfa78ab 100644
--- a/src/devices/machine/i2cmem.h
+++ b/src/devices/machine/i2cmem.h
@@ -40,13 +40,13 @@ public:
i2cmem_device & set_wc(int wc) { m_wc = wc; return *this; }
// I/O operations
- DECLARE_WRITE_LINE_MEMBER( write_e0 );
- DECLARE_WRITE_LINE_MEMBER( write_e1 );
- DECLARE_WRITE_LINE_MEMBER( write_e2 );
- DECLARE_WRITE_LINE_MEMBER( write_sda );
- DECLARE_WRITE_LINE_MEMBER( write_scl );
- DECLARE_WRITE_LINE_MEMBER( write_wc );
- DECLARE_READ_LINE_MEMBER( read_sda );
+ void write_e0(int state);
+ void write_e1(int state);
+ void write_e2(int state);
+ void write_sda(int state);
+ void write_scl(int state);
+ void write_wc(int state);
+ int read_sda();
protected:
// construction/destruction
@@ -57,8 +57,11 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read( emu_file &file ) override;
- virtual void nvram_write( emu_file &file ) override;
+ virtual bool nvram_read( util::read_stream &file ) override;
+ virtual bool nvram_write( util::write_stream &file ) override;
+
+ // configuration helpers
+ void set_devsel_address_low(bool devsel_address_low) { m_devsel_address_low = devsel_address_low; }
// internal helpers
int address_mask();
@@ -90,6 +93,7 @@ protected:
std::vector<uint8_t> m_page;
int m_page_offset;
int m_page_written_size;
+ bool m_devsel_address_low;
};
#define DECLARE_I2C_DEVICE(name) \
@@ -99,8 +103,11 @@ protected:
i2c_##name##_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); \
};
+DECLARE_I2C_DEVICE(x24c01);
DECLARE_I2C_DEVICE(24c01);
+DECLARE_I2C_DEVICE(pcf8570);
DECLARE_I2C_DEVICE(pcd8572);
+DECLARE_I2C_DEVICE(pcf8582);
DECLARE_I2C_DEVICE(24c02);
DECLARE_I2C_DEVICE(m24c02);
DECLARE_I2C_DEVICE(24c04);
@@ -111,15 +118,18 @@ DECLARE_I2C_DEVICE(24c64);
DECLARE_I2C_DEVICE(24c512);
// device type definition
-DECLARE_DEVICE_TYPE(I2C_24C01, i2c_24c01_device)
+DECLARE_DEVICE_TYPE(I2C_X24C01, i2c_x24c01_device)
+DECLARE_DEVICE_TYPE(I2C_24C01, i2c_24c01_device)
+DECLARE_DEVICE_TYPE(I2C_PCF8570, i2c_pcf8570_device)
DECLARE_DEVICE_TYPE(I2C_PCD8572, i2c_pcd8572_device)
-DECLARE_DEVICE_TYPE(I2C_24C02, i2c_24c02_device)
+DECLARE_DEVICE_TYPE(I2C_PCF8582, i2c_pcf8582_device)
+DECLARE_DEVICE_TYPE(I2C_24C02, i2c_24c02_device)
DECLARE_DEVICE_TYPE(I2C_M24C02, i2c_m24c02_device)
-DECLARE_DEVICE_TYPE(I2C_24C04, i2c_24c04_device)
-DECLARE_DEVICE_TYPE(I2C_X2404P, i2c_x2404p_device)
-DECLARE_DEVICE_TYPE(I2C_24C08, i2c_24c08_device)
-DECLARE_DEVICE_TYPE(I2C_24C16, i2c_24c16_device)
-DECLARE_DEVICE_TYPE(I2C_24C64, i2c_24c64_device)
-DECLARE_DEVICE_TYPE(I2C_24C512, i2c_24c512_device)
+DECLARE_DEVICE_TYPE(I2C_24C04, i2c_24c04_device)
+DECLARE_DEVICE_TYPE(I2C_X2404P, i2c_x2404p_device)
+DECLARE_DEVICE_TYPE(I2C_24C08, i2c_24c08_device)
+DECLARE_DEVICE_TYPE(I2C_24C16, i2c_24c16_device)
+DECLARE_DEVICE_TYPE(I2C_24C64, i2c_24c64_device)
+DECLARE_DEVICE_TYPE(I2C_24C512, i2c_24c512_device)
#endif // MAME_MACHINE_I2CMEM_H
diff --git a/src/devices/machine/i3001.cpp b/src/devices/machine/i3001.cpp
index decca559d56..2f607c4ff0c 100644
--- a/src/devices/machine/i3001.cpp
+++ b/src/devices/machine/i3001.cpp
@@ -50,7 +50,7 @@ void i3001_device::fc_w(uint8_t fc)
m_fo_handler(m_fo);
}
-WRITE_LINE_MEMBER(i3001_device::clk_w)
+void i3001_device::clk_w(int state)
{
update();
}
diff --git a/src/devices/machine/i3001.h b/src/devices/machine/i3001.h
index 11231456f5b..fa3368c05ce 100644
--- a/src/devices/machine/i3001.h
+++ b/src/devices/machine/i3001.h
@@ -41,6 +41,13 @@ class i3001_device : public device_t
public:
i3001_device(const machine_config &mconfig , const char *tag , device_t *owner , uint32_t clock = 0);
+ // Output callbacks
+ template <typename... T> void set_fo_w_cb(T &&... args) { m_fo_handler.set(std::forward<T>(args)...); }
+
+ // Input callbacks
+ template <typename... T> void set_px_r_cb(T &&... args) { m_px_handler.set(std::forward<T>(args)...); }
+ template <typename... T> void set_sx_r_cb(T &&... args) { m_sx_handler.set(std::forward<T>(args)...); }
+
// Mask of valid bits in address
static constexpr uint16_t ADDR_MASK = ((1U << 9) - 1);
@@ -54,35 +61,28 @@ public:
void fc_w(uint8_t fc);
// Write Flag Input
- DECLARE_WRITE_LINE_MEMBER(fi_w) { m_fi = state; }
+ void fi_w(int state) { m_fi = state; }
// Read Flag Output
- DECLARE_READ_LINE_MEMBER(fo_r) { return m_fo; }
+ int fo_r() { return m_fo; }
// Read carry/zero flags
- DECLARE_READ_LINE_MEMBER(carry_r) { return m_carry; }
- DECLARE_READ_LINE_MEMBER(zero_r) { return m_zero; }
-
- // Output callbacks
- auto fo_w() { return m_fo_handler.bind(); }
-
- // Input callbacks
- auto px_r() { return m_px_handler.bind(); }
- auto sx_r() { return m_sx_handler.bind(); }
+ int carry_r() { return m_carry; }
+ int zero_r() { return m_zero; }
// Load address (in real hw address is loaded through PX/SX buses)
void addr_w(uint16_t addr) { m_addr = addr & ADDR_MASK; }
// Clock pulse
- DECLARE_WRITE_LINE_MEMBER(clk_w);
+ void clk_w(int state);
protected:
virtual void device_start() override;
private:
- devcb_write_line m_fo_handler;
- devcb_read8 m_px_handler;
- devcb_read8 m_sx_handler;
+ device_delegate<void (int)> m_fo_handler;
+ device_delegate<uint8_t ()> m_px_handler;
+ device_delegate<uint8_t ()> m_sx_handler;
uint16_t m_addr;
uint8_t m_pr;
diff --git a/src/devices/machine/i3002.cpp b/src/devices/machine/i3002.cpp
index 0abfff3eb45..932646f1114 100644
--- a/src/devices/machine/i3002.cpp
+++ b/src/devices/machine/i3002.cpp
@@ -108,7 +108,7 @@ void i3002_device::fc_kbus_w(uint8_t fc , uint8_t k)
m_kbus = k & WORD_MASK;
}
-WRITE_LINE_MEMBER(i3002_device::clk_w)
+void i3002_device::clk_w(int state)
{
if (state) {
update();
@@ -125,7 +125,7 @@ bool i3002_device::update_ro()
decode_fc(m_fc , fg , rg , reg);
if (fg == 0 && rg == 2) {
- uint8_t ik = m_ibus_handler() & m_kbus;
+ uint8_t ik = !m_ibus_handler.isnull() ? m_ibus_handler() & m_kbus : 0;
uint8_t at = m_reg[ reg ];
set_ro(BIT(at , 0) && !BIT(ik , 0));
return true;
diff --git a/src/devices/machine/i3002.h b/src/devices/machine/i3002.h
index 70932afe7a2..338908e3a7b 100644
--- a/src/devices/machine/i3002.h
+++ b/src/devices/machine/i3002.h
@@ -35,6 +35,14 @@ class i3002_device : public device_t
public:
i3002_device(const machine_config &mconfig , const char *tag , device_t *owner , uint32_t clock = 0);
+ // Output callbacks
+ template <typename... T> void set_co_w_cb(T &&... args) { m_co_handler.set(std::forward<T>(args)...); }
+ template <typename... T> void set_ro_w_cb(T &&... args) { m_ro_handler.set(std::forward<T>(args)...); }
+
+ // Input bus callbacks
+ template <typename... T> void set_ibus_r_cb(T &&... args) { m_ibus_handler.set(std::forward<T>(args)...); }
+ template <typename... T> void set_mbus_r_cb(T &&... args) { m_mbus_handler.set(std::forward<T>(args)...); }
+
// Width of bit-slice
static constexpr unsigned SLICE_SIZE = 2;
@@ -68,31 +76,23 @@ public:
void fc_kbus_w(uint8_t fc , uint8_t k);
// Write Carry Input
- DECLARE_WRITE_LINE_MEMBER(ci_w) { m_ci = state != 0; }
+ void ci_w(int state) { m_ci = state; }
// Write Left Input
- DECLARE_WRITE_LINE_MEMBER(li_w) { m_li = state != 0; }
+ void li_w(int state) { m_li = state; }
// Read Carry Output
- DECLARE_READ_LINE_MEMBER(co_r) const { return m_co; }
+ int co_r() const { return m_co; }
// Read Right Output
- DECLARE_READ_LINE_MEMBER(ro_r) const { return m_ro; }
-
- // Output callbacks
- auto co_w() { return m_co_handler.bind(); }
- auto ro_w() { return m_ro_handler.bind(); }
-
- // Input bus callbacks
- auto ibus_r() { return m_ibus_handler.bind(); }
- auto mbus_r() { return m_mbus_handler.bind(); }
+ int ro_r() const { return m_ro; }
// Read output buses
uint8_t abus_r() const { return m_reg[ REG_MAR ]; }
uint8_t dbus_r() const { return m_reg[ REG_AC ]; }
// Clock pulse
- DECLARE_WRITE_LINE_MEMBER(clk_w);
+ void clk_w(int state);
// Compute RO if FC is the code of right-shift op (and return true)
// Return false in all other cases
@@ -106,10 +106,10 @@ protected:
virtual void device_start() override;
private:
- devcb_write_line m_co_handler;
- devcb_write_line m_ro_handler;
- devcb_read8 m_ibus_handler;
- devcb_read8 m_mbus_handler;
+ device_delegate<void (int)> m_co_handler;
+ device_delegate<void (int)> m_ro_handler;
+ device_delegate<uint8_t ()> m_ibus_handler;
+ device_delegate<uint8_t ()> m_mbus_handler;
uint8_t m_reg[ REG_COUNT ];
uint8_t m_fc;
diff --git a/src/devices/machine/i7220.cpp b/src/devices/machine/i7220.cpp
index 4050cd5aff8..aecb95bb16d 100644
--- a/src/devices/machine/i7220.cpp
+++ b/src/devices/machine/i7220.cpp
@@ -29,9 +29,8 @@
#include "i7220.h"
-//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already
-#define LOG_REGISTER (1U << 1)
-#define LOG_DEBUG (1U << 2)
+#define LOG_REGISTER (1U << 1)
+#define LOG_DEBUG (1U << 2)
//#define VERBOSE (LOG_DEBUG)
//#define LOG_OUTPUT_FUNC printf
@@ -75,11 +74,7 @@ i7220_device::i7220_device(const machine_config &mconfig, const char *tag, devic
void i7220_device::device_start()
{
- // resolve callbacks
- intrq_cb.resolve_safe();
- drq_cb.resolve_safe();
-
- bi.tm = timer_alloc(0);
+ m_bi.tm = timer_alloc(FUNC(i7220_device::general_continue), this);
// register for state saving
save_item(NAME(m_regs));
@@ -96,9 +91,9 @@ void i7220_device::device_start()
void i7220_device::device_reset()
{
- main_phase = PHASE_IDLE;
- bi.main_state = IDLE;
- bi.sub_state = IDLE;
+ m_main_phase = PHASE_IDLE;
+ m_bi.main_state = IDLE;
+ m_bi.sub_state = IDLE;
set_drq(false);
set_irq(false);
@@ -108,42 +103,37 @@ void i7220_device::device_reset()
memset(&m_regs, 0, sizeof(m_regs));
}
-void i7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- general_continue(bi);
-}
-
-image_init_result i7220_device::call_load()
+std::pair<std::error_condition, std::string> i7220_device::call_load()
{
if (length() != (m_data_size * I7110_MBM_SIZE))
{
- return image_init_result::FAIL;
+ return std::make_pair(image_error::INVALIDLENGTH, std::string());
}
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
void i7220_device::set_drq(bool state)
{
- if (state != drq)
+ if (state != m_drq)
{
- drq = state;
- drq_cb(drq);
+ m_drq = state;
+ drq_cb(m_drq);
}
}
void i7220_device::set_irq(bool state)
{
- if (state != irq)
+ if (state != m_irq)
{
- irq = state;
- intrq_cb(irq);
+ m_irq = state;
+ intrq_cb(m_irq);
}
}
void i7220_device::update_drq()
{
- switch (bi.main_state)
+ switch (m_bi.main_state)
{
case READ_DATA:
set_drq(m_fifo_size < 22 ? false : true);
@@ -175,7 +165,7 @@ uint8_t i7220_device::fifo_pop()
{
val = m_fifo.dequeue();
m_fifo_size--;
- if (main_phase == PHASE_EXEC)
+ if (m_main_phase == PHASE_EXEC)
{
update_drq();
}
@@ -193,7 +183,7 @@ void i7220_device::fifo_push(uint8_t val)
{
m_fifo.enqueue(val);
m_fifo_size++;
- if (main_phase == PHASE_EXEC)
+ if (m_main_phase == PHASE_EXEC)
{
update_drq();
}
@@ -204,16 +194,16 @@ void i7220_device::update_regs()
{
m_blr = (m_regs[R_BLR_M] << 8) + m_regs[R_BLR_L];
m_ar = (m_regs[R_AR_M] << 8) + m_regs[R_AR_L];
- blr_count = m_blr & 0x7ff;
- blr_nfc = (m_blr >> 12) ? ((m_blr >> 12) << 1) : 1;
- ar_addr = m_ar & 0x7ff;
- ar_mbm = (m_ar >> 11) & 15;
+ m_blr_count = m_blr & 0x7ff;
+ m_blr_nfc = (m_blr >> 12) ? ((m_blr >> 12) << 1) : 1;
+ m_ar_addr = m_ar & 0x7ff;
+ m_ar_mbm = (m_ar >> 11) & 15;
}
void i7220_device::start_command(int cmd)
{
- main_phase = PHASE_EXEC;
+ m_main_phase = PHASE_EXEC;
m_str &= ~SR_CLEAR;
switch (cmd)
@@ -224,45 +214,45 @@ void i7220_device::start_command(int cmd)
// MBM GROUP SELECT bits in the AR must select the last MBM in the system.
case C_INIT:
LOG("BMC INIT: BLR %04x (NFC %d pages %d) AR %04x (MBM %d addr %03x) ER %02d\n",
- m_blr, blr_nfc, blr_count, m_ar, ar_mbm, ar_addr, m_regs[R_ER]);
- if (blr_nfc != 2)
+ m_blr, m_blr_nfc, m_blr_count, m_ar, m_ar_mbm, m_ar_addr, m_regs[R_ER]);
+ if (m_blr_nfc != 2)
{
- command_fail_start(bi);
+ command_fail_start();
}
else
{
- init_start(bi);
+ init_start();
}
break;
case C_READ_FSA_STATUS:
- read_fsa_start(bi);
+ read_fsa_start();
break;
// all parametric registers must be properly set up before issuing Read Bubble Data command
case C_READ:
LOG("BMC RBD: BLR %04x (NFC %d pages %d) AR %04x (MBM %d addr %03x) ER %02d\n",
- m_blr, blr_nfc, blr_count, m_ar, ar_mbm, ar_addr, m_regs[R_ER]);
- if (ar_mbm >= m_data_size || blr_nfc != 2)
+ m_blr, m_blr_nfc, m_blr_count, m_ar, m_ar_mbm, m_ar_addr, m_regs[R_ER]);
+ if (m_ar_mbm >= m_data_size || m_blr_nfc != 2)
{
- command_fail_start(bi);
+ command_fail_start();
}
else
{
- read_data_start(bi);
+ read_data_start();
}
break;
case C_WRITE:
LOG("BMC WBD: BLR %04x (NFC %d pages %d) AR %04x (MBM %d addr %03x) ER %02d\n",
- m_blr, blr_nfc, blr_count, m_ar, ar_mbm, ar_addr, m_regs[R_ER]);
- if (ar_mbm >= m_data_size || blr_nfc != 2)
+ m_blr, m_blr_nfc, m_blr_count, m_ar, m_ar_mbm, m_ar_addr, m_regs[R_ER]);
+ if (m_ar_mbm >= m_data_size || m_blr_nfc != 2)
{
- command_fail_start(bi);
+ command_fail_start();
}
else
{
- write_data_start(bi);
+ write_data_start();
}
break;
@@ -271,28 +261,28 @@ void i7220_device::start_command(int cmd)
m_regs[R_AR_L] = 0;
m_regs[R_AR_M] &= ~7;
update_regs();
- main_phase = PHASE_RESULT;
+ m_main_phase = PHASE_RESULT;
m_str |= SR_DONE;
break;
// controlled termination of currently executing command. command accepted in BUSY state.
// if not BUSY, clears FIFO.
case C_ABORT:
- if (main_phase == PHASE_IDLE)
+ if (m_main_phase == PHASE_IDLE)
{
fifo_clear();
}
else
{
- main_phase = PHASE_RESULT;
- bi.main_state = bi.sub_state = IDLE;
+ m_main_phase = PHASE_RESULT;
+ m_bi.main_state = m_bi.sub_state = IDLE;
}
m_str |= SR_DONE;
break;
case C_RESET_FIFO:
fifo_clear();
- main_phase = PHASE_RESULT;
+ m_main_phase = PHASE_RESULT;
m_str |= SR_DONE;
break;
@@ -300,45 +290,45 @@ void i7220_device::start_command(int cmd)
case C_RESET:
m_regs[R_UR] = 0;
fifo_clear();
- main_phase = PHASE_RESULT;
+ m_main_phase = PHASE_RESULT;
m_str |= SR_DONE;
break;
default:
- command_fail_start(bi);
+ command_fail_start();
break;
}
}
-void i7220_device::general_continue(bubble_info &bi)
+TIMER_CALLBACK_MEMBER(i7220_device::general_continue)
{
- switch (bi.main_state)
+ switch (m_bi.main_state)
{
case IDLE:
break;
case INIT:
- init_continue(bi);
+ init_continue();
break;
case FAIL:
- command_fail_continue(bi);
+ command_fail_continue();
break;
case READ_FSA:
- read_fsa_continue(bi);
+ read_fsa_continue();
break;
case READ_DATA:
- read_data_continue(bi);
+ read_data_continue();
break;
case WRITE_DATA:
- write_data_continue(bi);
+ write_data_continue();
break;
default:
- LOG("BMC general_continue on unknown main-state %d\n", bi.main_state);
+ LOG("BMC general_continue on unknown main-state %d\n", m_bi.main_state);
break;
}
}
@@ -348,11 +338,11 @@ void i7220_device::delay_cycles(emu_timer *tm, int cycles)
tm->adjust(attotime::from_double(double(cycles) / clock()));
}
-void i7220_device::command_end(bubble_info &bi, bool success)
+void i7220_device::command_end(bool success)
{
- logerror("command done (%s) - %02x\n", success ? "success" : "fail", m_str);
- main_phase = PHASE_RESULT;
- bi.main_state = bi.sub_state = IDLE;
+ LOG("command done (%s) - %02x\n", success ? "success" : "fail", m_str);
+ m_main_phase = PHASE_RESULT;
+ m_bi.main_state = m_bi.sub_state = IDLE;
if (success)
{
m_str |= SR_DONE;
@@ -364,91 +354,88 @@ void i7220_device::command_end(bubble_info &bi, bool success)
}
-void i7220_device::command_fail_start(bubble_info &bi)
+void i7220_device::command_fail_start()
{
- bi.main_state = FAIL;
- bi.sub_state = INITIALIZE;
+ m_bi.main_state = FAIL;
+ m_bi.sub_state = INITIALIZE;
- command_fail_continue(bi);
+ command_fail_continue();
}
-void i7220_device::command_fail_continue(bubble_info &bi)
+void i7220_device::command_fail_continue()
{
- for (;;)
+ switch (m_bi.sub_state)
{
- switch (bi.sub_state)
- {
- case INITIALIZE:
- bi.sub_state = COMMAND_DONE;
- delay_cycles(bi.tm, 1200); // XXX
- return;
+ case INITIALIZE:
+ m_bi.sub_state = COMMAND_DONE;
+ delay_cycles(m_bi.tm, 1200); // XXX
+ return;
- case COMMAND_DONE:
- command_end(bi, false);
- return;
+ case COMMAND_DONE:
+ command_end(false);
+ return;
- default:
- LOG("BMC fail unknown sub-state %d\n", bi.sub_state);
- return;
- }
+ default:
+ LOG("BMC fail unknown sub-state %d\n", m_bi.sub_state);
+ return;
}
}
-void i7220_device::init_start(bubble_info &bi)
+void i7220_device::init_start()
{
- bi.main_state = INIT;
- bi.sub_state = INITIALIZE;
+ m_bi.main_state = INIT;
+ m_bi.sub_state = INITIALIZE;
- init_continue(bi);
+ init_continue();
}
-void i7220_device::init_continue(bubble_info &bi)
+void i7220_device::init_continue()
{
for (;;)
{
- switch (bi.sub_state)
+ switch (m_bi.sub_state)
{
case INITIALIZE:
- bi.sub_state = WAIT_FSA_REPLY;
- delay_cycles(bi.tm, m_data_size * 60); // p. 4-16 of BPK72UM
+ m_bi.sub_state = WAIT_FSA_REPLY;
+ delay_cycles(m_bi.tm, m_data_size * 60); // p. 4-16 of BPK72UM
return;
case WAIT_FSA_REPLY:
- bi.sub_state = COMMAND_DONE;
+ m_bi.sub_state = COMMAND_DONE;
break;
case COMMAND_DONE:
- command_end(bi, true);
+ command_end(true);
return;
default:
- LOG("BMC init unknown sub-state %d\n", bi.sub_state);
+ LOG("BMC init unknown sub-state %d\n", m_bi.sub_state);
return;
}
}
}
-void i7220_device::read_fsa_start(bubble_info &bi)
+void i7220_device::read_fsa_start()
{
- bi.main_state = READ_FSA;
- bi.sub_state = INITIALIZE;
+ m_bi.main_state = READ_FSA;
+ m_bi.sub_state = INITIALIZE;
- read_fsa_continue(bi);
+ read_fsa_continue();
}
-void i7220_device::read_fsa_continue(bubble_info &bi)
+void i7220_device::read_fsa_continue()
{
for (;;)
{
- switch (bi.sub_state)
+ switch (m_bi.sub_state)
{
case INITIALIZE:
- bi.sub_state = WAIT_FSA_REPLY;
- delay_cycles(bi.tm, m_data_size * 60); // p. 4-16 of BPK72UM
+ m_bi.sub_state = WAIT_FSA_REPLY;
+ delay_cycles(m_bi.tm, m_data_size * 60); // p. 4-16 of BPK72UM
return;
case WAIT_FSA_REPLY:
- bi.sub_state = COMMAND_DONE;
+ m_bi.sub_state = COMMAND_DONE;
break;
case COMMAND_DONE:
@@ -458,113 +445,113 @@ void i7220_device::read_fsa_continue(bubble_info &bi)
fifo_push(0x28); // FIFOMT | ECF/F
fifo_push(0x28);
}
- command_end(bi, true);
+ command_end(true);
return;
default:
- LOG("BMC read fsa unknown sub-state %d\n", bi.sub_state);
+ LOG("BMC read fsa unknown sub-state %d\n", m_bi.sub_state);
return;
}
}
}
-void i7220_device::read_data_start(bubble_info &bi)
+void i7220_device::read_data_start()
{
- bi.main_state = READ_DATA;
- bi.sub_state = INITIALIZE;
+ m_bi.main_state = READ_DATA;
+ m_bi.sub_state = INITIALIZE;
- read_data_continue(bi);
+ read_data_continue();
}
-void i7220_device::read_data_continue(bubble_info &bi)
+void i7220_device::read_data_continue()
{
for (;;)
{
- switch (bi.sub_state)
+ switch (m_bi.sub_state)
{
case INITIALIZE:
- bi.sub_state = SECTOR_READ;
- bi.counter = 0; // 256-bit pages
- bi.limit = blr_count * blr_nfc;
- fseek((ar_addr * 32 * blr_nfc) + (ar_mbm * I7110_MBM_SIZE) + (bi.counter * 32), SEEK_SET);
+ m_bi.sub_state = SECTOR_READ;
+ m_bi.counter = 0; // 256-bit pages
+ m_bi.limit = m_blr_count * m_blr_nfc;
+ fseek((m_ar_addr * 32 * m_blr_nfc) + (m_ar_mbm * I7110_MBM_SIZE) + (m_bi.counter * 32), SEEK_SET);
break;
case SECTOR_READ:
- fread(buf, 32);
- bi.sub_state = WAIT_FSA_REPLY;
- delay_cycles(bi.tm, 270 * 20); // p. 4-14 of BPK72UM
+ fread(m_buf, 32);
+ m_bi.sub_state = WAIT_FSA_REPLY;
+ delay_cycles(m_bi.tm, 270 * 20); // p. 4-14 of BPK72UM
break;
case WAIT_FSA_REPLY:
- LOGDBG("BMC read data: ct %02d limit %02d\n", bi.counter, bi.limit);
- if (bi.counter < bi.limit)
+ LOGDBG("BMC read data: ct %02d limit %02d\n", m_bi.counter, m_bi.limit);
+ if (m_bi.counter < m_bi.limit)
{
for (int a = 0; a < 32; a++)
- fifo_push(buf[a]);
- bi.sub_state = SECTOR_READ;
- bi.counter++;
- delay_cycles(bi.tm, 270 * 20); // p. 4-14 of BPK72UM
+ fifo_push(m_buf[a]);
+ m_bi.sub_state = SECTOR_READ;
+ m_bi.counter++;
+ delay_cycles(m_bi.tm, 270 * 20); // p. 4-14 of BPK72UM
return;
}
- bi.sub_state = COMMAND_DONE;
+ m_bi.sub_state = COMMAND_DONE;
break;
case COMMAND_DONE:
- command_end(bi, true);
+ command_end(true);
return;
default:
- LOG("BMC read data unknown sub-state %d\n", bi.sub_state);
+ LOG("BMC read data unknown sub-state %d\n", m_bi.sub_state);
return;
}
}
}
-void i7220_device::write_data_start(bubble_info &bi)
+void i7220_device::write_data_start()
{
- bi.main_state = WRITE_DATA;
- bi.sub_state = INITIALIZE;
+ m_bi.main_state = WRITE_DATA;
+ m_bi.sub_state = INITIALIZE;
- write_data_continue(bi);
+ write_data_continue();
}
-void i7220_device::write_data_continue(bubble_info &bi)
+void i7220_device::write_data_continue()
{
for (;;)
{
- switch (bi.sub_state)
+ switch (m_bi.sub_state)
{
case INITIALIZE:
- bi.sub_state = WAIT_FIFO;
- bi.counter = 0;
- bi.limit = blr_count * blr_nfc * 32;
- delay_cycles(bi.tm, 270 * 20); // p. 4-14 of BPK72UM
+ m_bi.sub_state = WAIT_FIFO;
+ m_bi.counter = 0;
+ m_bi.limit = m_blr_count * m_blr_nfc * 32;
+ delay_cycles(m_bi.tm, 270 * 20); // p. 4-14 of BPK72UM
return;
case WAIT_FIFO:
- LOGDBG("BMC write data: fifo %02d ct %02d limit %02d\n", m_fifo_size, bi.counter, bi.limit);
+ LOGDBG("BMC write data: fifo %02d ct %02d limit %02d\n", m_fifo_size, m_bi.counter, m_bi.limit);
if (m_fifo_size >= 32)
{
for (int a = 0; a < 32; a++)
- buf[a] = fifo_pop();
- fseek((ar_addr * 32 * blr_nfc) + (ar_mbm * I7110_MBM_SIZE) + bi.counter, SEEK_SET);
- fwrite(buf, 32);
- bi.counter += 32;
+ m_buf[a] = fifo_pop();
+ fseek((m_ar_addr * 32 * m_blr_nfc) + (m_ar_mbm * I7110_MBM_SIZE) + m_bi.counter, SEEK_SET);
+ fwrite(m_buf, 32);
+ m_bi.counter += 32;
}
- if (bi.counter < bi.limit)
+ if (m_bi.counter < m_bi.limit)
{
- delay_cycles(bi.tm, 270 * 20); // p. 4-14 of BPK72UM
+ delay_cycles(m_bi.tm, 270 * 20); // p. 4-14 of BPK72UM
return;
}
- bi.sub_state = COMMAND_DONE;
+ m_bi.sub_state = COMMAND_DONE;
break;
case COMMAND_DONE:
- command_end(bi, true);
+ command_end(true);
return;
default:
- LOG("BMC write data unknown sub-state %d\n", bi.sub_state);
+ LOG("BMC write data unknown sub-state %d\n", m_bi.sub_state);
return;
}
}
@@ -598,10 +585,10 @@ uint8_t i7220_device::read(offs_t offset)
case 1:
data = m_str;
- if (main_phase == PHASE_EXEC)
+ if (m_main_phase == PHASE_EXEC)
{
data |= SR_BUSY;
- switch (bi.main_state)
+ switch (m_bi.main_state)
{
case READ_DATA:
if (!m_fifo.empty()) // XXX
@@ -626,10 +613,10 @@ uint8_t i7220_device::read(offs_t offset)
}
}
LOGREG("BMC R status == %02x (phase %d state %d:%d fifo %d drq %d)\n",
- data, main_phase, bi.main_state, bi.sub_state, m_fifo_size, drq);
- if (main_phase == PHASE_RESULT)
+ data, m_main_phase, m_bi.main_state, m_bi.sub_state, m_fifo_size, m_drq);
+ if (m_main_phase == PHASE_RESULT)
{
- main_phase = PHASE_IDLE;
+ m_main_phase = PHASE_IDLE;
}
break;
}
@@ -692,10 +679,10 @@ void i7220_device::write(offs_t offset, uint8_t data)
else if (BIT(data, 4))
{
m_cmdr = data & 15;
- if (main_phase == PHASE_IDLE)
+ if (m_main_phase == PHASE_IDLE)
{
LOG("BMC command %02x '%s'\n", data, commands[m_cmdr]);
- main_phase = PHASE_CMD;
+ m_main_phase = PHASE_CMD;
start_command(m_cmdr);
}
}
diff --git a/src/devices/machine/i7220.h b/src/devices/machine/i7220.h
index a65eecbf119..a7c6a585e0e 100644
--- a/src/devices/machine/i7220.h
+++ b/src/devices/machine/i7220.h
@@ -49,26 +49,26 @@ public:
void set_data_size(int data_size) { m_data_size = data_size; }
- // image-level overrides
- virtual image_init_result call_load() override;
-
- virtual iodevice_t image_type() const noexcept override { return IO_MEMCARD; }
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual bool is_readable() const noexcept override { return true; }
virtual bool is_writeable() const noexcept override { return true; }
virtual bool is_creatable() const noexcept override { return false; }
- virtual bool must_be_loaded() const noexcept override { return true; }
virtual bool is_reset_on_load() const noexcept override { return false; }
virtual const char *file_extensions() const noexcept override { return "bubble"; }
+ virtual const char *image_type_name() const noexcept override { return "bubble"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "mbm"; }
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(general_continue);
int m_data_size;
@@ -169,34 +169,37 @@ private:
void update_drq();
void start_command(int cmd);
- void general_continue(bubble_info &bi);
- void command_end(bubble_info &bi, bool success);
+ void command_end(bool success);
- void command_fail_start(bubble_info &bi);
- void command_fail_continue(bubble_info &bi);
+ void command_fail_start();
+ void command_fail_continue();
- void init_start(bubble_info &bi);
- void init_continue(bubble_info &bi);
+ void init_start();
+ void init_continue();
- void read_fsa_start(bubble_info &bi);
- void read_fsa_continue(bubble_info &bi);
+ void read_fsa_start();
+ void read_fsa_continue();
- void read_data_start(bubble_info &bi);
- void read_data_continue(bubble_info &bi);
+ void read_data_start();
+ void read_data_continue();
- void write_data_start(bubble_info &bi);
- void write_data_continue(bubble_info &bi);
+ void write_data_start();
+ void write_data_continue();
void fifo_clear();
void fifo_push(uint8_t val);
uint8_t fifo_pop();
- int main_phase;
- bool drq, irq;
- bubble_info bi;
+ int m_main_phase;
+ bool m_drq;
+ bool m_irq;
+ bubble_info m_bi;
- uint8_t buf[32];
- int blr_count, blr_nfc, ar_addr, ar_mbm;
+ uint8_t m_buf[32];
+ int m_blr_count;
+ int m_blr_nfc;
+ int m_ar_addr;
+ int m_ar_mbm;
devcb_write_line intrq_cb;
devcb_write_line drq_cb;
diff --git a/src/devices/machine/i80130.cpp b/src/devices/machine/i80130.cpp
index b9b632b93e1..09a5edceacf 100644
--- a/src/devices/machine/i80130.cpp
+++ b/src/devices/machine/i80130.cpp
@@ -124,16 +124,16 @@ void i80130_device::device_add_mconfig(machine_config &config)
// i80130_device - constructor
//-------------------------------------------------
-i80130_device::i80130_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, I80130, tag, owner, clock),
- m_pic(*this, "pic"),
- m_pit(*this, "pit"),
- m_write_irq(*this),
- m_write_ack(*this),
- m_write_lir(*this),
- m_write_systick(*this),
- m_write_delay(*this),
- m_write_baud(*this)
+i80130_device::i80130_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, I80130, tag, owner, clock),
+ m_pic(*this, "pic"),
+ m_pit(*this, "pit"),
+ m_write_irq(*this),
+ m_write_ack(*this),
+ m_write_lir(*this),
+ m_write_systick(*this),
+ m_write_delay(*this),
+ m_write_baud(*this)
{
}
@@ -144,13 +144,6 @@ i80130_device::i80130_device(const machine_config &mconfig, const char *tag, dev
void i80130_device::device_start()
{
- // resolve callbacks
- m_write_irq.resolve_safe();
- m_write_ack.resolve_safe();
- m_write_lir.resolve_safe();
- m_write_systick.resolve_safe();
- m_write_delay.resolve_safe();
- m_write_baud.resolve_safe();
}
diff --git a/src/devices/machine/i80130.h b/src/devices/machine/i80130.h
index 0b5958ad875..e2e0d34fe90 100644
--- a/src/devices/machine/i80130.h
+++ b/src/devices/machine/i80130.h
@@ -32,14 +32,14 @@ public:
uint8_t inta_r() { return m_pic->acknowledge(); }
- DECLARE_WRITE_LINE_MEMBER( ir0_w ) { m_pic->ir0_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ir1_w ) { m_pic->ir1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ir2_w ) { m_pic->ir2_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ir3_w ) { m_pic->ir3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ir4_w ) { m_pic->ir4_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ir5_w ) { m_pic->ir5_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ir6_w ) { m_pic->ir6_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ir7_w ) { m_pic->ir7_w(state); }
+ void ir0_w(int state) { m_pic->ir0_w(state); }
+ void ir1_w(int state) { m_pic->ir1_w(state); }
+ void ir2_w(int state) { m_pic->ir2_w(state); }
+ void ir3_w(int state) { m_pic->ir3_w(state); }
+ void ir4_w(int state) { m_pic->ir4_w(state); }
+ void ir5_w(int state) { m_pic->ir5_w(state); }
+ void ir6_w(int state) { m_pic->ir6_w(state); }
+ void ir7_w(int state) { m_pic->ir7_w(state); }
protected:
// device-level overrides
@@ -60,10 +60,10 @@ private:
devcb_write_line m_write_delay;
devcb_write_line m_write_baud;
- DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); }
- DECLARE_WRITE_LINE_MEMBER( systick_w ) { m_write_systick(state); }
- DECLARE_WRITE_LINE_MEMBER( delay_w ) { m_write_delay(state); }
- DECLARE_WRITE_LINE_MEMBER( baud_w ) { m_write_baud(state); }
+ void irq_w(int state) { m_write_irq(state); }
+ void systick_w(int state) { m_write_systick(state); }
+ void delay_w(int state) { m_write_delay(state); }
+ void baud_w(int state) { m_write_baud(state); }
uint16_t io_r(offs_t offset, uint16_t mem_mask = ~0);
void io_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
diff --git a/src/devices/machine/i8087.cpp b/src/devices/machine/i8087.cpp
index 9d2327bd3af..17613b1edbe 100644
--- a/src/devices/machine/i8087.cpp
+++ b/src/devices/machine/i8087.cpp
@@ -154,17 +154,6 @@ static inline floatx80 floatx80_abs(floatx80 fx)
return fx;
}
-static inline double fx80_to_double(floatx80 fx)
-{
- uint64_t d = floatx80_to_float64(fx);
- return *(double*)&d;
-}
-
-static inline floatx80 double_to_fx80(double in)
-{
- return float64_to_floatx80(*(uint64_t*)&in);
-}
-
DEFINE_DEVICE_TYPE(I8087, i8087_device, "i8087", "Intel 8087")
i8087_device::i8087_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
@@ -207,15 +196,11 @@ void i8087_device::device_start()
save_item(NAME(m_sw));
save_item(NAME(m_tw));
- m_int_handler.resolve_safe();
- m_busy_handler.resolve_safe();
- m_int_handler(0);
- m_busy_handler(1);
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(i8087_device::release_busy), this);
build_opcode_table();
}
-void i8087_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(i8087_device::release_busy)
{
m_busy_handler(1);
}
@@ -2267,10 +2252,8 @@ void i8087_device::f2xm1(u8 modrm)
}
else
{
- // TODO: Inaccurate
- double x = fx80_to_double(ST(0));
- double res = pow(2.0, x) - 1;
- result = double_to_fx80(res);
+ extern floatx80 f2xm1(floatx80 a);
+ result = f2xm1(ST(0));
}
if (check_exceptions())
@@ -2293,7 +2276,6 @@ void i8087_device::fyl2x(u8 modrm)
else
{
floatx80 x = ST(0);
- floatx80 y = ST(1);
if (x.high & 0x8000)
{
@@ -2302,10 +2284,8 @@ void i8087_device::fyl2x(u8 modrm)
}
else
{
- // TODO: Inaccurate
- double d64 = fx80_to_double(x);
- double l2x = log(d64)/log(2.0);
- result = floatx80_mul(double_to_fx80(l2x), y);
+ extern floatx80 fyl2x(floatx80 a, floatx80 b);
+ result = fyl2x(ST(0), ST(1));
}
}
@@ -2329,13 +2309,8 @@ void i8087_device::fyl2xp1(u8 modrm)
}
else
{
- floatx80 x = ST(0);
- floatx80 y = ST(1);
-
- // TODO: Inaccurate
- double d64 = fx80_to_double(x);
- double l2x1 = log(d64 + 1.0)/log(2.0);
- result = floatx80_mul(double_to_fx80(l2x1), y);
+ extern floatx80 fyl2xp1(floatx80 a, floatx80 b);
+ result = fyl2xp1(ST(0), ST(1));
}
if (check_exceptions())
@@ -2396,16 +2371,14 @@ void i8087_device::fpatan(u8 modrm)
{
floatx80 result;
- if (X87_IS_ST_EMPTY(0))
+ if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1))
{
set_stack_underflow();
result = fx80_inan;
}
else
{
- // TODO: Inaccurate
- double val = atan2(fx80_to_double(ST(1)) , fx80_to_double(ST(0)));
- result = double_to_fx80(val);
+ result = floatx80_fpatan(ST(0), ST(1));
}
if (check_exceptions())
@@ -2463,7 +2436,7 @@ void i8087_device::fcos(u8 modrm)
{
result = ST(0);
-#if 0 // TODO: Function produces bad values
+#if 1 // TODO: Function produces bad values
if (floatx80_fcos(result) != -1)
m_sw &= ~X87_SW_C2;
else
@@ -2503,7 +2476,7 @@ void i8087_device::fsincos(u8 modrm)
s_result = c_result = ST(0);
-#if 0 // TODO: Function produces bad values
+#if 1 // TODO: Function produces bad values
if (sf_fsincos(s_result, &s_result, &c_result) != -1)
m_sw &= ~X87_SW_C2;
else
@@ -4236,6 +4209,7 @@ void i8087_device::fsave(u8 modrm)
for (int i = 0; i < 8; ++i)
WRITE80(ea + i*10, ST(i));
+ reset();
CYCLES(67);
}
diff --git a/src/devices/machine/i8087.h b/src/devices/machine/i8087.h
index 4ee28a095bf..be926b88a37 100644
--- a/src/devices/machine/i8087.h
+++ b/src/devices/machine/i8087.h
@@ -2,8 +2,8 @@
// copyright-holders:Philip Bennett, Carl
// SoftFloat 2 lacks an include guard
-#ifndef softfloat_h
-#define softfloat_h 1
+#ifndef softfloat2_h
+#define softfloat2_h 1
#include "softfloat/milieu.h"
#include "softfloat/softfloat.h"
#endif
@@ -26,7 +26,8 @@ protected:
i8087_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(release_busy);
private:
address_space &space() { return *m_space; }
diff --git a/src/devices/machine/i8155.cpp b/src/devices/machine/i8155.cpp
index 996faed2f42..7fad5016760 100644
--- a/src/devices/machine/i8155.cpp
+++ b/src/devices/machine/i8155.cpp
@@ -38,8 +38,8 @@ DEFINE_DEVICE_TYPE(I8156, i8156_device, "i8156", "Intel 8156 RAM, I/O & Timer")
// MACROS / CONSTANTS
//**************************************************************************
-#define LOG_PORT (1U << 0)
-#define LOG_TIMER (1U << 1)
+#define LOG_PORT (1U << 1)
+#define LOG_TIMER (1U << 2)
#define VERBOSE (0)
#include "logmacro.h"
@@ -268,26 +268,26 @@ inline void i8155_device::write_port(int port, uint8_t data)
// i8155_device - constructor
//-------------------------------------------------
-i8155_device::i8155_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : i8155_device(mconfig, I8155, tag, owner, clock)
+i8155_device::i8155_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8155_device(mconfig, I8155, tag, owner, clock)
{
}
-i8155_device::i8155_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- m_in_pa_cb(*this),
- m_in_pb_cb(*this),
- m_in_pc_cb(*this),
- m_out_pa_cb(*this),
- m_out_pb_cb(*this),
- m_out_pc_cb(*this),
- m_out_to_cb(*this),
- m_command(0),
- m_status(0),
- m_count_length(0),
- m_count_loaded(0),
- m_to(0),
- m_count_even_phase(false)
+i8155_device::i8155_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_in_pa_cb(*this, 0),
+ m_in_pb_cb(*this, 0),
+ m_in_pc_cb(*this, 0),
+ m_out_pa_cb(*this),
+ m_out_pb_cb(*this),
+ m_out_pc_cb(*this),
+ m_out_to_cb(*this),
+ m_command(0),
+ m_status(0),
+ m_count_length(0),
+ m_count_loaded(0),
+ m_to(0),
+ m_count_even_phase(false)
{
}
@@ -296,8 +296,8 @@ i8155_device::i8155_device(const machine_config &mconfig, device_type type, cons
// i8156_device - constructor
//-------------------------------------------------
-i8156_device::i8156_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : i8155_device(mconfig, I8156, tag, owner, clock)
+i8156_device::i8156_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8155_device(mconfig, I8156, tag, owner, clock)
{
}
@@ -308,21 +308,12 @@ i8156_device::i8156_device(const machine_config &mconfig, const char *tag, devic
void i8155_device::device_start()
{
- // resolve callbacks
- m_in_pa_cb.resolve_safe(0);
- m_in_pb_cb.resolve_safe(0);
- m_in_pc_cb.resolve_safe(0);
- m_out_pa_cb.resolve_safe();
- m_out_pb_cb.resolve_safe();
- m_out_pc_cb.resolve_safe();
- m_out_to_cb.resolve_safe();
-
// allocate RAM
m_ram = make_unique_clear<uint8_t[]>(256);
// allocate timers
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i8155_device::timer_half_counted), this));
- m_timer_tc = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i8155_device::timer_tc), this));
+ m_timer = timer_alloc(FUNC(i8155_device::timer_half_counted), this);
+ m_timer_tc = timer_alloc(FUNC(i8155_device::timer_tc), this);
// register for state saving
save_item(NAME(m_io_m));
diff --git a/src/devices/machine/i8212.cpp b/src/devices/machine/i8212.cpp
index c6cf46eafe5..af3cb72c722 100644
--- a/src/devices/machine/i8212.cpp
+++ b/src/devices/machine/i8212.cpp
@@ -60,9 +60,9 @@ DEFINE_DEVICE_TYPE(I8212, i8212_device, "i8212", "Intel 8212 I/O Port")
i8212_device::i8212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, I8212, tag, owner, clock),
m_write_int(*this),
- m_read_di(*this),
+ m_read_di(*this, 0),
m_write_do(*this),
- m_read_md(*this),
+ m_read_md(*this, 0),
m_stb(1), m_data(0)
{
}
@@ -74,12 +74,6 @@ i8212_device::i8212_device(const machine_config &mconfig, const char *tag, devic
void i8212_device::device_start()
{
- // resolve callbacks
- m_write_int.resolve_safe();
- m_read_di.resolve_safe(0);
- m_write_do.resolve_safe();
- m_read_md.resolve_safe(0);
-
// register for state saving
save_item(NAME(m_stb));
save_item(NAME(m_data));
@@ -188,7 +182,7 @@ void i8212_device::strobe(uint8_t data)
// stb_w - data strobe write
//-------------------------------------------------
-WRITE_LINE_MEMBER(i8212_device::stb_w)
+void i8212_device::stb_w(int state)
{
// active on falling edge
if (m_stb && !state)
diff --git a/src/devices/machine/i8212.h b/src/devices/machine/i8212.h
index efd84d11813..b8992e5842e 100644
--- a/src/devices/machine/i8212.h
+++ b/src/devices/machine/i8212.h
@@ -52,7 +52,7 @@ public:
void strobe(uint8_t data);
// line write handlers
- DECLARE_WRITE_LINE_MEMBER(stb_w);
+ void stb_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/i8214.cpp b/src/devices/machine/i8214.cpp
index 4eb767d9396..fa511e32963 100644
--- a/src/devices/machine/i8214.cpp
+++ b/src/devices/machine/i8214.cpp
@@ -40,7 +40,8 @@ void i8214_device::trigger_interrupt(int level)
// set interrupt line
m_write_int(ASSERT_LINE);
- m_write_int(CLEAR_LINE);
+ if (!m_int_dis_hack)
+ m_write_int(CLEAR_LINE); // TODO: wait one clock cycle to clear
}
@@ -52,7 +53,12 @@ void i8214_device::check_interrupt()
{
if (m_int_dis)
{
- LOG("not checking interrupts because m_int_dis\n");
+ LOG("not checking interrupts because m_int_dis (%02x)\n", m_r);
+ if (m_int_dis_hack && m_r == 0xff)
+ {
+ m_int_dis = 0;
+ m_write_int(CLEAR_LINE);
+ }
return;
}
if (!m_etlg)
@@ -89,6 +95,12 @@ void i8214_device::check_interrupt()
}
}
}
+
+ if (m_int_dis_hack)
+ {
+ m_int_dis = 0;
+ m_write_int(CLEAR_LINE);
+ }
}
@@ -105,6 +117,7 @@ i8214_device::i8214_device(const machine_config &mconfig, const char *tag, devic
: device_t(mconfig, I8214, tag, owner, clock)
, m_write_int(*this)
, m_write_enlg(*this)
+ , m_int_dis_hack(false)
, m_inte(0)
, m_int_dis(0)
, m_a(0)
@@ -122,10 +135,6 @@ i8214_device::i8214_device(const machine_config &mconfig, const char *tag, devic
void i8214_device::device_start()
{
- // resolve callbacks
- m_write_int.resolve_safe();
- m_write_enlg.resolve_safe();
-
m_int_dis = 0;
m_etlg = 1;
diff --git a/src/devices/machine/i8214.h b/src/devices/machine/i8214.h
index 9b567660990..d8514e400ef 100644
--- a/src/devices/machine/i8214.h
+++ b/src/devices/machine/i8214.h
@@ -32,6 +32,8 @@ public:
// construction/destruction
i8214_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ void set_int_dis_hack(bool hack) { m_int_dis_hack = hack; }
+
auto int_wr_callback() { return m_write_int.bind(); }
auto enlg_wr_callback() { return m_write_enlg.bind(); }
@@ -58,6 +60,8 @@ private:
devcb_write_line m_write_int;
devcb_write_line m_write_enlg;
+ bool m_int_dis_hack;
+
int m_inte; // interrupt enable
int m_int_dis; // interrupt (latch) disable flip-flop
int m_a; // request level
diff --git a/src/devices/machine/i82355.cpp b/src/devices/machine/i82355.cpp
index 88726f7f04e..b2c5d35abaf 100644
--- a/src/devices/machine/i82355.cpp
+++ b/src/devices/machine/i82355.cpp
@@ -66,19 +66,6 @@ i82355_device::i82355_device(const machine_config &mconfig, const char *tag, dev
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void i82355_device::device_resolve_objects()
-{
- m_eint_callback.resolve_safe();
- m_lint_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
diff --git a/src/devices/machine/i82355.h b/src/devices/machine/i82355.h
index 25cb776d9f7..8d219b36334 100644
--- a/src/devices/machine/i82355.h
+++ b/src/devices/machine/i82355.h
@@ -32,8 +32,7 @@ public:
void local_w(offs_t offset, u8 data);
protected:
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/i82357.cpp b/src/devices/machine/i82357.cpp
index 80319a8a52a..0d8c14c4bbe 100644
--- a/src/devices/machine/i82357.cpp
+++ b/src/devices/machine/i82357.cpp
@@ -22,8 +22,6 @@
#include "emu.h"
#include "i82357.h"
-#define LOG_GENERAL (1U << 0)
-
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
@@ -35,7 +33,7 @@ i82357_device::i82357_device(const machine_config &mconfig, const char *tag, dev
, m_pic(*this, "pic%u", 0)
, m_pit(*this, "pit%u", 0)
, m_dma(*this, "dma%u", 0)
- , m_out_rtc(*this)
+ , m_out_rtc_address(*this)
, m_out_nmi(*this)
, m_out_spkr(*this)
{
@@ -130,7 +128,7 @@ void i82357_device::map(address_map &map)
{
m_nmi_enabled = !BIT(data, 7);
- m_out_rtc(0, data & 0x7f);
+ m_out_rtc_address(data & 0x7f);
m_nmi_check->adjust(attotime::zero);
}, "nmi_rtc").umask64(0xff);
@@ -206,11 +204,7 @@ void i82357_device::map(address_map &map)
void i82357_device::device_start()
{
- m_out_rtc.resolve_safe();
- m_out_nmi.resolve_safe();
- m_out_spkr.resolve_safe();
-
- m_nmi_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i82357_device::nmi_check), this));
+ m_nmi_check = timer_alloc(FUNC(i82357_device::nmi_check), this);
}
void i82357_device::device_reset()
@@ -267,7 +261,7 @@ void i82357_device::nmi_ext_w(u8 data)
m_nmi_check->adjust(attotime::zero);
}
-WRITE_LINE_MEMBER(i82357_device::in_iochk)
+void i82357_device::in_iochk(int state)
{
if (!state && !(m_nmi_reg & NMI_PARITY_DISABLE))
{
@@ -279,7 +273,7 @@ WRITE_LINE_MEMBER(i82357_device::in_iochk)
m_nmi_reg &= ~NMI_IOCHK;
}
-WRITE_LINE_MEMBER(i82357_device::in_parity)
+void i82357_device::in_parity(int state)
{
if (!state && !(m_nmi_reg & NMI_IOCHK_DISABLE))
{
diff --git a/src/devices/machine/i82357.h b/src/devices/machine/i82357.h
index 3c5a7756061..7b15cb5c6bb 100644
--- a/src/devices/machine/i82357.h
+++ b/src/devices/machine/i82357.h
@@ -15,15 +15,15 @@ class i82357_device : public device_t
public:
i82357_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
- auto out_rtc_cb() { return m_out_rtc.bind(); }
- auto out_int_cb() { return subdevice<pic8259_device>("pic0")->out_int_callback(); }
+ auto out_rtc_address_cb() { return m_out_rtc_address.bind(); }
+ auto out_int_cb() { return m_pic[0].lookup()->out_int_callback(); }
auto out_nmi_cb() { return m_out_nmi.bind(); }
auto out_spkr_cb() { return m_out_spkr.bind(); }
u32 eisa_irq_ack() { return m_pic[0]->acknowledge(); }
- DECLARE_WRITE_LINE_MEMBER(in_iochk);
- DECLARE_WRITE_LINE_MEMBER(in_parity);
+ void in_iochk(int state);
+ void in_parity(int state);
void map(address_map &map);
@@ -45,7 +45,7 @@ private:
required_device_array<pit8254_device, 2> m_pit;
required_device_array<eisa_dma_device, 2> m_dma;
- devcb_write8 m_out_rtc;
+ devcb_write8 m_out_rtc_address;
devcb_write_line m_out_nmi;
devcb_write_line m_out_spkr;
diff --git a/src/devices/machine/i82371eb_acpi.cpp b/src/devices/machine/i82371eb_acpi.cpp
new file mode 100644
index 00000000000..5a6fe84af00
--- /dev/null
+++ b/src/devices/machine/i82371eb_acpi.cpp
@@ -0,0 +1,194 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ PIIX4E ACPI interface
+
+ TODO:
+ - PIIX4 / PIIX4M dispatches
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "i82371eb_acpi.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps (verbose)
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(I82371EB_ACPI, i82371eb_acpi_device, "i82371eb_acpi", "Intel 82371EB PIIX4E Power Management and ACPI")
+
+i82371eb_acpi_device::i82371eb_acpi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, I82371EB_ACPI, tag, owner, clock)
+ , m_acpi(*this, "acpi")
+ , m_smbus(*this, "smbus")
+
+{
+ // 0x068000 - Bridge devices, other bridge device
+ // rev 0x02 for PIIX4E A-0, rev 0x03 for PIIX4M
+ set_ids(0x80867113, 0x02, 0x068000, 0x00);
+}
+
+void i82371eb_acpi_device::device_add_mconfig(machine_config &config)
+{
+
+}
+
+void i82371eb_acpi_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+ // TODO: has interrupt pin
+ map(0x10, 0xd7).unmaprw();
+ map(0x10, 0xd7).rw(FUNC(i82371eb_acpi_device::unmap_log_r), FUNC(i82371eb_acpi_device::unmap_log_w));
+ // I/O space
+ map(0x40, 0x43).rw(FUNC(i82371eb_acpi_device::pmba_r), FUNC(i82371eb_acpi_device::pmba_w));
+ map(0x5c, 0x5f).rw(FUNC(i82371eb_acpi_device::devresa_r), FUNC(i82371eb_acpi_device::devresa_w));
+ map(0x80, 0x80).rw(FUNC(i82371eb_acpi_device::pmregmisc_r), FUNC(i82371eb_acpi_device::pmregmisc_w));
+ // SMBus space
+ map(0x90, 0x93).rw(FUNC(i82371eb_acpi_device::smbba_r), FUNC(i82371eb_acpi_device::smbba_w));
+ map(0xd2, 0xd2).rw(FUNC(i82371eb_acpi_device::smbhstcfg_r), FUNC(i82371eb_acpi_device::smbhstcfg_w));
+}
+
+void i82371eb_acpi_device::io_map(address_map &map)
+{
+}
+
+
+void i82371eb_acpi_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+// printf("%08llx %08llx %08llx %04llx %04llx %04llx\n", memory_window_start, memory_window_end, memory_offset ,io_window_start, io_window_end, io_offset);
+ if (io_offset != 0)
+ throw emu_fatalerror("I82371EB_ACPI io_offset != 0 (%04llx)", io_offset);
+
+ //LOGMAP("PMIOSE %s\n", m_pmiose ? "Enable" : "Disable");
+
+ if (m_pmiose)
+ {
+ LOGMAP("- PMBA %04x-%04x\n", m_pmba, m_pmba + 0x3f);
+ // TODO: subset, should map up to 0x3f only (and current lpc-acpi don't)
+ m_acpi->map_device(memory_window_start, memory_window_end, 0, memory_space, io_window_start, m_pmba + 0x3f, m_pmba, io_space);
+ }
+
+ const bool iose = bool(BIT(command, 0));
+
+ LOGMAP("IOSE (SMBus) %s\n", m_pmiose ? "Enable" : "Disable");
+
+ // presume if SMB_HST_EN is zero will also remove SMBUS mapping
+ if (iose && BIT(m_smbus_host_config, 0))
+ {
+ LOGMAP("- SMBBA %04x-%04x (%08x %08x)\n", m_smbba, m_smbba + 0xf, io_window_start, io_window_end);
+ io_space->install_device(m_smbba, m_smbba | 0xf, *m_smbus, &smbus_device::map);
+ }
+}
+
+void i82371eb_acpi_device::device_start()
+{
+ pci_device::device_start();
+
+#if 0
+ memory_window_start = 0;
+ memory_window_end = 0xffffffff;
+ memory_offset = 0;
+ io_window_start = 0;
+ io_window_end = 0xffff;
+ io_offset = 0;
+#endif
+}
+
+
+void i82371eb_acpi_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ status = 0x0280;
+ m_pmiose = false;
+ m_pmba = 0;
+ m_smbba = 0;
+ m_devresa = 0;
+}
+
+u8 i82371eb_acpi_device::pmregmisc_r()
+{
+ return m_pmiose;
+}
+
+void i82371eb_acpi_device::pmregmisc_w(u8 data)
+{
+ m_pmiose = bool(BIT(data, 0));
+ remap_cb();
+}
+
+u32 i82371eb_acpi_device::pmba_r()
+{
+ // RTE bit 0 high (I/O space)
+ return m_pmba | 1;
+}
+
+void i82371eb_acpi_device::pmba_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_pmba);
+ m_pmba &= 0xffc0;
+ remap_cb();
+}
+
+u32 i82371eb_acpi_device::devresa_r()
+{
+ return m_devresa;
+}
+
+void i82371eb_acpi_device::devresa_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_devresa);
+ LOGIO("devresa w %08x\n", m_devresa);
+// remap_cb();
+}
+
+u32 i82371eb_acpi_device::smbba_r()
+{
+ // RTE bit 0 high (I/O space)
+ return m_smbba | 1;
+}
+
+void i82371eb_acpi_device::smbba_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_smbba);
+ m_smbba &= 0xfff0;
+ remap_cb();
+}
+
+u8 i82371eb_acpi_device::smbhstcfg_r()
+{
+ return m_smbus_host_config;
+}
+
+void i82371eb_acpi_device::smbhstcfg_w(u8 data)
+{
+ m_smbus_host_config = data;
+ remap_cb();
+}
+
+/*
+ * Debugging
+ */
+
+u8 i82371eb_acpi_device::unmap_log_r(offs_t offset)
+{
+ LOGTODO("I82371EB_ACPI Unemulated [%02x] R\n", offset + 0x10);
+ return 0;
+}
+
+void i82371eb_acpi_device::unmap_log_w(offs_t offset, u8 data)
+{
+ LOGTODO("I82371EB_ACPI Unemulated [%02x] %02x W\n", offset + 0x10, data);
+}
diff --git a/src/devices/machine/i82371eb_acpi.h b/src/devices/machine/i82371eb_acpi.h
new file mode 100644
index 00000000000..0cb3f7fb315
--- /dev/null
+++ b/src/devices/machine/i82371eb_acpi.h
@@ -0,0 +1,63 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_I82371EB_ACPI_H
+#define MAME_MACHINE_I82371EB_ACPI_H
+
+#pragma once
+
+#include "pci.h"
+#include "lpc-acpi.h"
+#include "pci-smbus.h"
+
+class i82371eb_acpi_device : public pci_device
+{
+public:
+ i82371eb_acpi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void io_map(address_map &map);
+
+private:
+ required_device<lpc_acpi_device> m_acpi;
+ required_device<smbus_device> m_smbus;
+
+ u8 pmregmisc_r();
+ void pmregmisc_w(u8 data);
+
+ u8 smbhstcfg_r();
+ void smbhstcfg_w(u8 data);
+
+ u32 pmba_r();
+ void pmba_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+
+ u32 devresa_r();
+ void devresa_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+
+ u32 smbba_r();
+ void smbba_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+
+ bool m_pmiose = false;
+ u32 m_pmba = 0;
+ u32 m_smbba = 0;
+ u8 m_smbus_host_config = 0;
+ u32 m_devresa = 0;
+
+ u8 unmap_log_r(offs_t offset);
+ void unmap_log_w(offs_t offset, u8 data);
+};
+
+DECLARE_DEVICE_TYPE(I82371EB_ACPI, i82371eb_acpi_device)
+
+#endif
diff --git a/src/devices/machine/i82371eb_ide.cpp b/src/devices/machine/i82371eb_ide.cpp
new file mode 100644
index 00000000000..f938a94e884
--- /dev/null
+++ b/src/devices/machine/i82371eb_ide.cpp
@@ -0,0 +1,37 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ PIIX4E IDE interface
+
+ TODO:
+ - i82371ab PIIX4 / i82371mb PIIX4M dispatches
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "i82371eb_ide.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(I82371EB_IDE, i82371eb_ide_device, "i82371eb_ide", "Intel 82371EB PIIX4E PCI to ISA southbridge")
+
+i82371eb_ide_device::i82371eb_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82371sb_ide_device(mconfig, I82371EB_IDE, tag, owner, clock)
+{
+ // 0x010180 - Mass storage device, IDE controller, bus master capable
+ // rev 0x00 PIIX4 A-0 / A-1
+ // rev 0x01 PIIX4 B-0 / PIIX4E A-0 / PIIX4M A-0
+ set_ids(0x80867111, 0x01, 0x010180, 0x00);
+}
diff --git a/src/devices/machine/i82371eb_ide.h b/src/devices/machine/i82371eb_ide.h
new file mode 100644
index 00000000000..66f08e3330e
--- /dev/null
+++ b/src/devices/machine/i82371eb_ide.h
@@ -0,0 +1,26 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_I82371EB_IDE_H
+#define MAME_MACHINE_I82371EB_IDE_H
+
+#pragma once
+
+#include "machine/i82371sb.h"
+
+class i82371eb_ide_device : public i82371sb_ide_device
+{
+public:
+ template <typename T>
+ i82371eb_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ : i82371eb_ide_device(mconfig, tag, owner, clock)
+ {
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ }
+
+ i82371eb_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+DECLARE_DEVICE_TYPE(I82371EB_IDE, i82371eb_ide_device)
+
+#endif // MAME_MACHINE_I82371EB_IDE_H
diff --git a/src/devices/machine/i82371eb_isa.cpp b/src/devices/machine/i82371eb_isa.cpp
new file mode 100644
index 00000000000..bb7473a0af4
--- /dev/null
+++ b/src/devices/machine/i82371eb_isa.cpp
@@ -0,0 +1,49 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ PIIX4E ISA interface
+
+ TODO:
+ - i82371ab PIIX4 / i82371mb PIIX4M dispatches
+ - pinpoint actual differences wrt i82371sb (definitely EISA, then ...?)
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "i82371eb_isa.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(I82371EB_ISA, i82371eb_isa_device, "i82371eb_isa", "Intel 82371EB PIIX4E PCI to ISA/EIO southbridge")
+
+i82371eb_isa_device::i82371eb_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82371sb_isa_device(mconfig, I82371EB_ISA, tag, owner, clock)
+
+{
+ // 0x060100 - Bridge device, PCI-to-ISA bridge
+ // TODO: above can change to 0x068000 if positive decode is used.
+ // rev 0x00 PIIX4 A-0 / A-1
+ // rev 0x01 PIIX4 B-0
+ // rev 0x02 for PIIX4E A-0 / PIIX4M A-0
+ set_ids(0x80867110, 0x02, 0x060100, 0x00);
+}
+
+void i82371eb_isa_device::config_map(address_map &map)
+{
+ i82371sb_isa_device::config_map(map);
+// map(0x90, 0x91) PDMACFG
+// map(0xb0, 0xb0) GENCFG
+
+}
diff --git a/src/devices/machine/i82371eb_isa.h b/src/devices/machine/i82371eb_isa.h
new file mode 100644
index 00000000000..56b9412051b
--- /dev/null
+++ b/src/devices/machine/i82371eb_isa.h
@@ -0,0 +1,29 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_I82371EB_ISA_H
+#define MAME_MACHINE_I82371EB_ISA_H
+
+#pragma once
+
+#include "machine/i82371sb.h"
+
+class i82371eb_isa_device : public i82371sb_isa_device
+{
+public:
+ template <typename T>
+ i82371eb_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ : i82371eb_isa_device(mconfig, tag, owner, clock)
+ {
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ }
+
+ i82371eb_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+private:
+ virtual void config_map(address_map &map) override;
+};
+
+DECLARE_DEVICE_TYPE(I82371EB_ISA, i82371eb_isa_device)
+
+#endif // MAME_MACHINE_I82371EB_ISA_H
diff --git a/src/devices/machine/i82371eb_usb.cpp b/src/devices/machine/i82371eb_usb.cpp
new file mode 100644
index 00000000000..4a3a74caadd
--- /dev/null
+++ b/src/devices/machine/i82371eb_usb.cpp
@@ -0,0 +1,96 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ PIIX4E USB interface
+
+ TODO:
+ - Actual USB ports;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "i82371eb_usb.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(I82371EB_USB, i82371eb_usb_device, "i82371eb_usb", "Intel 82371EB PIIX4E USB Host Controller")
+
+i82371eb_usb_device::i82371eb_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, I82371EB_USB, tag, owner, clock)
+
+{
+ // 0x0c0300 - Serial Bus Controller, USB, UHCI Host
+ // rev PIIX4E A-0 / PIIX4M A-0 = 0x01
+ set_ids(0x80867112, 0x01, 0x0c0300, 0x00);
+}
+
+void i82371eb_usb_device::device_add_mconfig(machine_config &config)
+{
+
+}
+
+void i82371eb_usb_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+ // 0x60 sbrnum - serial bus release number
+ // 0xc0-0xc1 legsup - Legacy Support Register
+ map(0x60, 0xff).rw(FUNC(i82371eb_usb_device::unmap_log_r), FUNC(i82371eb_usb_device::unmap_log_w));
+}
+
+void i82371eb_usb_device::io_map(address_map &map)
+{
+
+}
+
+void i82371eb_usb_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+// io_space->install_device(0, 0x03ff, *this, &i82371eb_usb_device::io_map);
+}
+
+void i82371eb_usb_device::device_start()
+{
+ pci_device::device_start();
+
+ skip_map_regs(4);
+ add_map(32, M_IO, FUNC(i82371eb_usb_device::io_map));
+
+ // INTD#
+ intr_pin = 4;
+}
+
+
+void i82371eb_usb_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ status = 0x0280;
+}
+
+/*
+ * Debugging
+ */
+
+u8 i82371eb_usb_device::unmap_log_r(offs_t offset)
+{
+ LOGTODO("I82371EB_USB Unemulated [%02x] R\n", offset + 0x60);
+ return 0;
+}
+
+void i82371eb_usb_device::unmap_log_w(offs_t offset, u8 data)
+{
+ LOGTODO("I82371EB_USB Unemulated [%02x] %02x W\n", offset + 0x60, data);
+}
diff --git a/src/devices/machine/i82371eb_usb.h b/src/devices/machine/i82371eb_usb.h
new file mode 100644
index 00000000000..ea27406d93b
--- /dev/null
+++ b/src/devices/machine/i82371eb_usb.h
@@ -0,0 +1,37 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_I82371EB_USB_H
+#define MAME_MACHINE_I82371EB_USB_H
+
+#pragma once
+
+#include "pci.h"
+
+class i82371eb_usb_device : public pci_device
+{
+public:
+ i82371eb_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void io_map(address_map &map);
+
+private:
+ u8 unmap_log_r(offs_t offset);
+ void unmap_log_w(offs_t offset, u8 data);
+};
+
+DECLARE_DEVICE_TYPE(I82371EB_USB, i82371eb_usb_device)
+
+#endif
diff --git a/src/devices/machine/i82371sb.cpp b/src/devices/machine/i82371sb.cpp
index 9140b0d4216..d93c3361cba 100644
--- a/src/devices/machine/i82371sb.cpp
+++ b/src/devices/machine/i82371sb.cpp
@@ -6,19 +6,22 @@
#include "speaker.h"
-
DEFINE_DEVICE_TYPE(I82371SB_ISA, i82371sb_isa_device, "i82371sb_isa", "Intel 82371 southbridge ISA bridge")
void i82371sb_isa_device::config_map(address_map &map)
{
pci_device::config_map(map);
+ map(0x06, 0x07).rw(FUNC(i82371sb_isa_device::status_r), FUNC(i82371sb_isa_device::status_w));
+ map(0x10, 0x4b).noprw();
map(0x4c, 0x4c).rw(FUNC(i82371sb_isa_device::iort_r), FUNC(i82371sb_isa_device::iort_w));
map(0x4e, 0x4f).rw(FUNC(i82371sb_isa_device::xbcs_r), FUNC(i82371sb_isa_device::xbcs_w));
map(0x60, 0x63).rw(FUNC(i82371sb_isa_device::pirqrc_r), FUNC(i82371sb_isa_device::pirqrc_w));
- map(0x68, 0x68).rw(FUNC(i82371sb_isa_device::tom_r), FUNC(i82371sb_isa_device::tom_w));
+ map(0x69, 0x69).rw(FUNC(i82371sb_isa_device::tom_r), FUNC(i82371sb_isa_device::tom_w));
map(0x6a, 0x6b).rw(FUNC(i82371sb_isa_device::mstat_r), FUNC(i82371sb_isa_device::mstat_w));
map(0x70, 0x71).rw(FUNC(i82371sb_isa_device::mbirq01_r), FUNC(i82371sb_isa_device::mbirq01_w));
map(0x76, 0x77).rw(FUNC(i82371sb_isa_device::mbdma_r), FUNC(i82371sb_isa_device::mbdma_w));
+ map(0x78, 0x79).rw(FUNC(i82371sb_isa_device::pcsc_r), FUNC(i82371sb_isa_device::pcsc_w));
+ map(0x80, 0x80).rw(FUNC(i82371sb_isa_device::apicbase_r), FUNC(i82371sb_isa_device::apicbase_w));
map(0x82, 0x82).rw(FUNC(i82371sb_isa_device::dlc_r), FUNC(i82371sb_isa_device::dlc_w));
map(0xa0, 0xa0).rw(FUNC(i82371sb_isa_device::smicntl_r), FUNC(i82371sb_isa_device::smicntl_w));
map(0xa2, 0xa3).rw(FUNC(i82371sb_isa_device::smien_r), FUNC(i82371sb_isa_device::smien_w));
@@ -32,15 +35,23 @@ void i82371sb_isa_device::config_map(address_map &map)
void i82371sb_isa_device::internal_io_map(address_map &map)
{
map(0x0000, 0x001f).rw("dma8237_1", FUNC(am9517a_device::read), FUNC(am9517a_device::write));
- map(0x0020, 0x003f).rw("pic8259_master", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ map(0x0020, 0x0021).rw("pic8259_master", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+// map(0x002e, 0x002f) Super I/O config
map(0x0040, 0x005f).rw("pit8254", FUNC(pit8254_device::read), FUNC(pit8254_device::write));
map(0x0061, 0x0061).rw(FUNC(i82371sb_isa_device::at_portb_r), FUNC(i82371sb_isa_device::at_portb_w));
+// map(0x0070, 0x0070) RTC address, bit 7 NMI enable
+// map(0x0071, 0x0071) RTC data
+// map(0x0078, 0x0079) Board Configuration
map(0x0080, 0x009f).rw(FUNC(i82371sb_isa_device::at_page8_r), FUNC(i82371sb_isa_device::at_page8_w));
- map(0x00a0, 0x00bf).rw("pic8259_slave", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ map(0x00a0, 0x00a1).rw("pic8259_slave", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
map(0x00b2, 0x00b3).rw(FUNC(i82371sb_isa_device::read_apmcapms), FUNC(i82371sb_isa_device::write_apmcapms));
+ // Up to $de according to TC430HX spec?
map(0x00c0, 0x00df).rw(FUNC(i82371sb_isa_device::at_dma8237_2_r), FUNC(i82371sb_isa_device::at_dma8237_2_w));
- map(0x04d0, 0x04d1).rw(FUNC(i82371sb_isa_device::eisa_irq_read), FUNC(i82371sb_isa_device::eisa_irq_write));
map(0x00e0, 0x00ef).noprw();
+// map(0x00f0, 0x00f0) Reset Numeric Error
+// map(0x0270, 0x0273) I/O read port for PnP
+ map(0x04d0, 0x04d1).rw(FUNC(i82371sb_isa_device::eisa_irq_read), FUNC(i82371sb_isa_device::eisa_irq_write));
+ map(0x0cf9, 0x0cf9).rw(FUNC(i82371sb_isa_device::reset_control_r), FUNC(i82371sb_isa_device::reset_control_w));
}
//-------------------------------------------------
@@ -50,14 +61,14 @@ void i82371sb_isa_device::internal_io_map(address_map &map)
void i82371sb_isa_device::device_add_mconfig(machine_config &config)
{
PIT8254(config, m_pit8254);
- m_pit8254->set_clk<0>(4772720/4); // heartbeat IRQ
+ m_pit8254->set_clk<0>(4772720 / 4); // heartbeat IRQ
m_pit8254->out_handler<0>().set(FUNC(i82371sb_isa_device::at_pit8254_out0_changed));
- m_pit8254->set_clk<1>(4772720/4); // DRAM refresh
+ m_pit8254->set_clk<1>(4772720 / 4); // DRAM refresh
m_pit8254->out_handler<1>().set(FUNC(i82371sb_isa_device::at_pit8254_out1_changed));
- m_pit8254->set_clk<2>(4772720/4); // PIO port C pin 4, and speaker polling enough
+ m_pit8254->set_clk<2>(4772720 / 4); // PIO port C pin 4, and speaker polling enough
m_pit8254->out_handler<2>().set(FUNC(i82371sb_isa_device::at_pit8254_out2_changed));
- AM9517A(config, m_dma8237_1, XTAL(14'318'181)/3);
+ AM9517A(config, m_dma8237_1, XTAL(14'318'181) / 3);
m_dma8237_1->out_hreq_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq0_w));
m_dma8237_1->out_eop_callback().set(FUNC(i82371sb_isa_device::at_dma8237_out_eop));
m_dma8237_1->in_memr_callback().set(FUNC(i82371sb_isa_device::pc_dma_read_byte));
@@ -75,7 +86,7 @@ void i82371sb_isa_device::device_add_mconfig(machine_config &config)
m_dma8237_1->out_dack_callback<2>().set(FUNC(i82371sb_isa_device::pc_dack2_w));
m_dma8237_1->out_dack_callback<3>().set(FUNC(i82371sb_isa_device::pc_dack3_w));
- AM9517A(config, m_dma8237_2, XTAL(14'318'181)/3);
+ AM9517A(config, m_dma8237_2, XTAL(14'318'181) / 3);
m_dma8237_2->out_hreq_callback().set(FUNC(i82371sb_isa_device::pc_dma_hrq_changed));
m_dma8237_2->in_memr_callback().set(FUNC(i82371sb_isa_device::pc_dma_read_word));
m_dma8237_2->out_memw_callback().set(FUNC(i82371sb_isa_device::pc_dma_write_word));
@@ -104,8 +115,6 @@ void i82371sb_isa_device::device_add_mconfig(machine_config &config)
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
ISA16(config, m_isabus, 0);
- m_isabus->set_memspace(":maincpu", AS_PROGRAM);
- m_isabus->set_iospace(":maincpu", AS_IO);
m_isabus->irq3_callback().set(FUNC(i82371sb_isa_device::pc_irq3_w));
m_isabus->irq4_callback().set(FUNC(i82371sb_isa_device::pc_irq4_w));
m_isabus->irq5_callback().set(FUNC(i82371sb_isa_device::pc_irq5_w));
@@ -127,34 +136,60 @@ void i82371sb_isa_device::device_add_mconfig(machine_config &config)
m_isabus->iochck_callback().set(FUNC(i82371sb_isa_device::iochck_w));
}
-i82371sb_isa_device::i82371sb_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- pci_device(mconfig, I82371SB_ISA, tag, owner, clock),
- m_smi_callback(*this),
- m_boot_state_hook(*this),
- 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_isabus(*this, "isabus"),
- m_speaker(*this, "speaker"),
- m_at_spkrdata(0), m_pit_out2(0), m_dma_channel(0), m_cur_eop(false), m_dma_high_byte(0), m_eisa_irq_mode(0), m_at_speaker(0), m_refresh(false), m_channel_check(0), m_nmi_enabled(0)
+i82371sb_isa_device::i82371sb_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82371sb_isa_device(mconfig, I82371SB_ISA, tag, owner, clock)
{
set_ids(0x80867000, 0x03, 0x060100, 0x00000000);
}
+void i82371sb_isa_device::device_config_complete()
+{
+ auto isabus = m_isabus.finder_target();
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_memspace(m_maincpu, AS_PROGRAM);
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_iospace(m_maincpu, AS_IO);
+
+ pci_device::device_config_complete();
+}
+
+i82371sb_isa_device::i82371sb_isa_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, type, tag, owner, clock)
+ , m_smi_callback(*this)
+ , m_nmi_callback(*this)
+ , m_stpclk_callback(*this)
+ , m_boot_state_hook(*this)
+ , m_maincpu(*this, finder_base::DUMMY_TAG)
+ , 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_isabus(*this, "isabus")
+ , m_speaker(*this, "speaker")
+ , m_at_spkrdata(0)
+ , m_pit_out2(0)
+ , m_dma_channel(0)
+ , m_cur_eop(false)
+ , m_dma_high_byte(0)
+ , m_eisa_irq_mode(0)
+ , m_at_speaker(0)
+ , m_refresh(false)
+ , m_channel_check(0)
+ , m_nmi_enabled(0)
+{
+}
+
void i82371sb_isa_device::device_start()
{
pci_device::device_start();
- m_smi_callback.resolve();
- m_boot_state_hook.resolve();
+ m_pci_root->set_pin_mapper(pci_pin_mapper(*this, FUNC(i82371sb_isa_device::pin_mapper)));
+ m_pci_root->set_irq_handler(pci_irq_handler(*this, FUNC(i82371sb_isa_device::irq_handler)));
}
void i82371sb_isa_device::device_reset()
{
pci_device::device_reset();
+ status = 0x0280;
iort = 0x4d;
xbcs = 0x0003;
memset(pirqrc, 0x80, sizeof(pirqrc));
@@ -175,6 +210,7 @@ void i82371sb_isa_device::device_reset()
smireq = 0x0000;
ctlmtr = 0x00;
cthmtr = 0x00;
+ reset_control = 0;
m_at_spkrdata = 0;
m_pit_out2 = 1;
@@ -198,6 +234,12 @@ void i82371sb_isa_device::nop_w(uint8_t data)
{
}
+void i82371sb_isa_device::status_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ // bits 11-13 are clear on write
+ status = status & ~(data & (0x3800 & mem_mask));
+}
+
uint8_t i82371sb_isa_device::iort_r()
{
return iort;
@@ -286,6 +328,17 @@ void i82371sb_isa_device::mbdma_w(offs_t offset, uint8_t data)
logerror("mbdma[%d] = %02x\n", offset, mbdma);
}
+uint16_t i82371sb_isa_device::pcsc_r()
+{
+ return pcsc;
+}
+
+void i82371sb_isa_device::pcsc_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&pcsc);
+ logerror("pcsc = %04x\n", pcsc);
+}
+
uint8_t i82371sb_isa_device::apicbase_r()
{
return apicbase;
@@ -394,12 +447,19 @@ void i82371sb_isa_device::map_bios(address_space *memory_space, uint32_t start,
memory_space->install_rom(start, end, m_region->base() + (start & mask));
}
-void i82371sb_isa_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
- uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+void i82371sb_isa_device::map_extra(
+ uint64_t memory_window_start,
+ uint64_t memory_window_end,
+ uint64_t memory_offset,
+ address_space *memory_space,
+ uint64_t io_window_start,
+ uint64_t io_window_end,
+ uint64_t io_offset,
+ address_space *io_space)
{
// assume that map_extra of the southbridge is called before the one of the northbridge
m_isabus->remap(AS_PROGRAM, 0, 1 << 24);
- map_bios(memory_space, 0xfffc0000, 0xffffffff);
+ map_bios(memory_space, 0xffffffff - m_region->bytes() + 1, 0xffffffff);
map_bios(memory_space, 0x000e0000, 0x000fffff);
m_isabus->remap(AS_IO, 0, 0xffff);
io_space->install_device(0, 0xffff, *this, &i82371sb_isa_device::internal_io_map);
@@ -490,11 +550,10 @@ void i82371sb_isa_device::map_extra(uint64_t memory_window_start, uint64_t memor
#endif
}
-
// Southbridge
uint8_t i82371sb_isa_device::get_slave_ack(offs_t offset)
{
- if (offset==2) // IRQ = 2
+ if (offset == 2) // IRQ = 2
return m_pic8259_slave->acknowledge();
return 0x00;
@@ -506,21 +565,19 @@ void i82371sb_isa_device::at_speaker_set_spkrdata(uint8_t data)
m_speaker->level_w(m_at_spkrdata & m_pit_out2);
}
-
-
-WRITE_LINE_MEMBER( i82371sb_isa_device::at_pit8254_out0_changed )
+void i82371sb_isa_device::at_pit8254_out0_changed(int state)
{
if (m_pic8259_master)
m_pic8259_master->ir0_w(state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::at_pit8254_out1_changed )
+void i82371sb_isa_device::at_pit8254_out1_changed(int state)
{
- if(state)
+ if (state)
m_refresh = !m_refresh;
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::at_pit8254_out2_changed )
+void i82371sb_isa_device::at_pit8254_out2_changed(int state)
{
m_pit_out2 = state ? 1 : 0;
m_speaker->level_w(m_at_spkrdata & m_pit_out2);
@@ -530,7 +587,7 @@ uint8_t i82371sb_isa_device::at_page8_r(offs_t offset)
{
uint8_t data = m_at_pages[offset % 0x10];
- switch(offset % 8)
+ switch (offset % 8)
{
case 1:
data = m_dma_offset[BIT(offset, 3)][2];
@@ -548,12 +605,11 @@ uint8_t i82371sb_isa_device::at_page8_r(offs_t offset)
return data;
}
-
void i82371sb_isa_device::at_page8_w(offs_t offset, uint8_t data)
{
m_at_pages[offset % 0x10] = data;
- switch(offset % 8)
+ switch (offset % 8)
{
case 0:
m_boot_state_hook((offs_t)0, data);
@@ -573,46 +629,43 @@ void i82371sb_isa_device::at_page8_w(offs_t offset, uint8_t data)
}
}
-
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dma_hrq_changed )
+void i82371sb_isa_device::pc_dma_hrq_changed(int state)
{
m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
/* Assert HLDA */
- m_dma8237_2->hack_w( state );
+ m_dma8237_2->hack_w(state);
}
uint8_t i82371sb_isa_device::pc_dma_read_byte(offs_t offset)
{
- address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
- if(m_dma_channel == -1)
+ address_space &prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
return 0xff;
uint8_t result;
- offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;
+ offs_t page_offset = ((offs_t)m_dma_offset[0][m_dma_channel]) << 16;
result = prog_space.read_byte(page_offset + offset);
return result;
}
-
void i82371sb_isa_device::pc_dma_write_byte(offs_t offset, uint8_t data)
{
- address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
- if(m_dma_channel == -1)
+ address_space &prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
return;
- offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;
+ offs_t page_offset = ((offs_t)m_dma_offset[0][m_dma_channel]) << 16;
prog_space.write_byte(page_offset + offset, data);
}
-
uint8_t i82371sb_isa_device::pc_dma_read_word(offs_t offset)
{
- address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
- if(m_dma_channel == -1)
+ address_space &prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
return 0xff;
uint16_t result;
- offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;
+ offs_t page_offset = ((offs_t)m_dma_offset[1][m_dma_channel & 3]) << 16;
result = prog_space.read_word((page_offset & 0xfe0000) | (offset << 1));
m_dma_high_byte = result & 0xFF00;
@@ -620,18 +673,16 @@ uint8_t i82371sb_isa_device::pc_dma_read_word(offs_t offset)
return result & 0xFF;
}
-
void i82371sb_isa_device::pc_dma_write_word(offs_t offset, uint8_t data)
{
- address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
- if(m_dma_channel == -1)
+ address_space &prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
return;
- offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;
+ offs_t page_offset = ((offs_t)m_dma_offset[1][m_dma_channel & 3]) << 16;
prog_space.write_word((page_offset & 0xfe0000) | (offset << 1), m_dma_high_byte | data);
}
-
uint8_t i82371sb_isa_device::pc_dma8237_0_dack_r() { return m_isabus->dack_r(0); }
uint8_t i82371sb_isa_device::pc_dma8237_1_dack_r() { return m_isabus->dack_r(1); }
uint8_t i82371sb_isa_device::pc_dma8237_2_dack_r() { return m_isabus->dack_r(2); }
@@ -640,7 +691,6 @@ uint8_t i82371sb_isa_device::pc_dma8237_5_dack_r() { return m_isabus->dack_r(5);
uint8_t i82371sb_isa_device::pc_dma8237_6_dack_r() { return m_isabus->dack_r(6); }
uint8_t i82371sb_isa_device::pc_dma8237_7_dack_r() { return m_isabus->dack_r(7); }
-
void i82371sb_isa_device::pc_dma8237_0_dack_w(uint8_t data) { m_isabus->dack_w(0, data); }
void i82371sb_isa_device::pc_dma8237_1_dack_w(uint8_t data) { m_isabus->dack_w(1, data); }
void i82371sb_isa_device::pc_dma8237_2_dack_w(uint8_t data) { m_isabus->dack_w(2, data); }
@@ -649,37 +699,39 @@ void i82371sb_isa_device::pc_dma8237_5_dack_w(uint8_t data) { m_isabus->dack_w(5
void i82371sb_isa_device::pc_dma8237_6_dack_w(uint8_t data) { m_isabus->dack_w(6, data); }
void i82371sb_isa_device::pc_dma8237_7_dack_w(uint8_t data) { m_isabus->dack_w(7, data); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::at_dma8237_out_eop )
+void i82371sb_isa_device::at_dma8237_out_eop(int state)
{
m_cur_eop = state == ASSERT_LINE;
- if(m_dma_channel != -1)
- m_isabus->eop_w(m_dma_channel, m_cur_eop ? ASSERT_LINE : CLEAR_LINE );
+ if (m_dma_channel != -1)
+ m_isabus->eop_w(m_dma_channel, m_cur_eop ? ASSERT_LINE : CLEAR_LINE);
}
void i82371sb_isa_device::pc_select_dma_channel(int channel, bool state)
{
m_isabus->dack_line_w(channel, state);
- if(!state) {
+ if (!state)
+ {
m_dma_channel = channel;
- if(m_cur_eop)
- m_isabus->eop_w(channel, ASSERT_LINE );
- } else if(m_dma_channel == channel) {
+ if (m_cur_eop)
+ m_isabus->eop_w(channel, ASSERT_LINE);
+ }
+ else if (m_dma_channel == channel)
+ {
m_dma_channel = -1;
- if(m_cur_eop)
- m_isabus->eop_w(channel, CLEAR_LINE );
+ if (m_cur_eop)
+ m_isabus->eop_w(channel, CLEAR_LINE);
}
}
-
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack0_w ) { pc_select_dma_channel(0, state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack1_w ) { pc_select_dma_channel(1, state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack2_w ) { pc_select_dma_channel(2, state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack3_w ) { pc_select_dma_channel(3, state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack4_w ) { m_dma8237_1->hack_w( state ? 0 : 1); } // it's inverted
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack5_w ) { pc_select_dma_channel(5, state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack6_w ) { pc_select_dma_channel(6, state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_dack7_w ) { pc_select_dma_channel(7, state); }
+void i82371sb_isa_device::pc_dack0_w(int state) { pc_select_dma_channel(0, state); }
+void i82371sb_isa_device::pc_dack1_w(int state) { pc_select_dma_channel(1, state); }
+void i82371sb_isa_device::pc_dack2_w(int state) { pc_select_dma_channel(2, state); }
+void i82371sb_isa_device::pc_dack3_w(int state) { pc_select_dma_channel(3, state); }
+void i82371sb_isa_device::pc_dack4_w(int state) { m_dma8237_1->hack_w( state ? 0 : 1); } // it's inverted
+void i82371sb_isa_device::pc_dack5_w(int state) { pc_select_dma_channel(5, state); }
+void i82371sb_isa_device::pc_dack6_w(int state) { pc_select_dma_channel(6, state); }
+void i82371sb_isa_device::pc_dack7_w(int state) { pc_select_dma_channel(7, state); }
void i82371sb_isa_device::redirect_irq(int irq, int state)
{
@@ -727,7 +779,7 @@ void i82371sb_isa_device::redirect_irq(int irq, int state)
}
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqa_w)
+void i82371sb_isa_device::pc_pirqa_w(int state)
{
int irq = pirqrc[0] & 15;
@@ -736,7 +788,7 @@ WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqa_w)
redirect_irq(irq, state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqb_w )
+void i82371sb_isa_device::pc_pirqb_w(int state)
{
int irq = pirqrc[1] & 15;
@@ -745,7 +797,7 @@ WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqb_w )
redirect_irq(irq, state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqc_w )
+void i82371sb_isa_device::pc_pirqc_w(int state)
{
int irq = pirqrc[2] & 15;
@@ -754,7 +806,7 @@ WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqc_w )
redirect_irq(irq, state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqd_w )
+void i82371sb_isa_device::pc_pirqd_w(int state)
{
int irq = pirqrc[3] & 15;
@@ -763,7 +815,7 @@ WRITE_LINE_MEMBER( i82371sb_isa_device::pc_pirqd_w )
redirect_irq(irq, state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_mirq0_w )
+void i82371sb_isa_device::pc_mirq0_w(int state)
{
int irq = mbirq0 & 15;
@@ -772,7 +824,8 @@ WRITE_LINE_MEMBER( i82371sb_isa_device::pc_mirq0_w )
redirect_irq(irq, state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_mirq1_w )
+// FIXME: this is PIIX specific, doesn't exist on PIIX3
+void i82371sb_isa_device::pc_mirq1_w(int state)
{
int irq = mbirq1 & 15;
@@ -781,25 +834,30 @@ WRITE_LINE_MEMBER( i82371sb_isa_device::pc_mirq1_w )
redirect_irq(irq, state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_ferr_w )
+void i82371sb_isa_device::pc_ferr_w(int state)
{
+ if (!(xbcs & 32))
+ return;
m_pic8259_slave->ir5_w(state);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq1_w ) { m_pic8259_master->ir1_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq3_w ) { m_pic8259_master->ir3_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq4_w ) { m_pic8259_master->ir4_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq5_w ) { m_pic8259_master->ir5_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq6_w ) { m_pic8259_master->ir6_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq7_w ) { m_pic8259_master->ir7_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq8n_w ) { m_pic8259_slave->ir0_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq9_w ) { m_pic8259_slave->ir1_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq10_w ) { m_pic8259_slave->ir2_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq11_w ) { m_pic8259_slave->ir3_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq12m_w ) { m_pic8259_slave->ir4_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq14_w ) { m_pic8259_slave->ir6_w(state); }
-WRITE_LINE_MEMBER( i82371sb_isa_device::pc_irq15_w ) { m_pic8259_slave->ir7_w(state); }
+void i82371sb_isa_device::pc_extsmi_w(int state)
+{
+}
+void i82371sb_isa_device::pc_irq1_w(int state) { m_pic8259_master->ir1_w(state); }
+void i82371sb_isa_device::pc_irq3_w(int state) { m_pic8259_master->ir3_w(state); }
+void i82371sb_isa_device::pc_irq4_w(int state) { m_pic8259_master->ir4_w(state); }
+void i82371sb_isa_device::pc_irq5_w(int state) { m_pic8259_master->ir5_w(state); }
+void i82371sb_isa_device::pc_irq6_w(int state) { m_pic8259_master->ir6_w(state); }
+void i82371sb_isa_device::pc_irq7_w(int state) { m_pic8259_master->ir7_w(state); }
+void i82371sb_isa_device::pc_irq8n_w(int state) { m_pic8259_slave->ir0_w(state); }
+void i82371sb_isa_device::pc_irq9_w(int state) { m_pic8259_slave->ir1_w(state); }
+void i82371sb_isa_device::pc_irq10_w(int state) { m_pic8259_slave->ir2_w(state); }
+void i82371sb_isa_device::pc_irq11_w(int state) { m_pic8259_slave->ir3_w(state); }
+void i82371sb_isa_device::pc_irq12m_w(int state) { m_pic8259_slave->ir4_w(state); }
+void i82371sb_isa_device::pc_irq14_w(int state) { m_pic8259_slave->ir6_w(state); }
+void i82371sb_isa_device::pc_irq15_w(int state) { m_pic8259_slave->ir7_w(state); }
uint8_t i82371sb_isa_device::at_portb_r()
{
@@ -808,7 +866,7 @@ uint8_t i82371sb_isa_device::at_portb_r()
data &= ~0xd0; /* AT BIOS don't likes this being set */
/* 0x10 is the dram refresh line bit on the 5170, just a timer here, 15.085us. */
data |= m_refresh ? 0x10 : 0;
- if (m_pit_out2)
+ if (m_pit_out2)
data |= 0x20;
else
data &= ~0x20; /* ps2m30 wants this */
@@ -820,13 +878,13 @@ void i82371sb_isa_device::at_portb_w(uint8_t data)
{
m_at_speaker = data;
m_pit8254->write_gate2(BIT(data, 0));
- at_speaker_set_spkrdata( BIT(data, 1));
+ at_speaker_set_spkrdata(BIT(data, 1));
m_channel_check = BIT(data, 3);
if (m_channel_check)
m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
}
-WRITE_LINE_MEMBER( i82371sb_isa_device::iochck_w )
+void i82371sb_isa_device::iochck_w(int state)
{
if (!state && !m_channel_check && m_nmi_enabled)
m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
@@ -878,6 +936,18 @@ void i82371sb_isa_device::write_apmcapms(offs_t offset, uint8_t data)
}
else
apms = data;
+ logerror("write apmcapms %d %02x\n", offset, data);
+}
+
+uint8_t i82371sb_isa_device::reset_control_r(offs_t offset)
+{
+ return reset_control;
+}
+
+void i82371sb_isa_device::reset_control_w(offs_t offset, uint8_t data)
+{
+ reset_control = data;
+ logerror("reset_control = %02x\n", reset_control);
}
void i82371sb_isa_device::update_smireq_line()
@@ -893,13 +963,33 @@ void i82371sb_isa_device::update_smireq_line()
m_smi_callback(0);
}
+int i82371sb_isa_device::pin_mapper(int pin)
+{
+ if(pin < 0 || pin >= 4 || (pirqrc[pin] & 0x80))
+ return -1;
+ return pirqrc[pin];
+}
+
+void i82371sb_isa_device::irq_handler(int line, int state)
+{
+ if(line < 0 && line >= 16)
+ return;
+
+ logerror("irq_handler %d %d\n", line, state);
+ redirect_irq(line, state);
+}
+
+
DEFINE_DEVICE_TYPE(I82371SB_IDE, i82371sb_ide_device, "i82371sb_ide", "Intel 82371 southbridge IDE interface")
void i82371sb_ide_device::config_map(address_map &map)
{
pci_device::config_map(map);
- map(0x04, 0x05).rw(FUNC(i82371sb_ide_device::command_r), FUNC(i82371sb_ide_device::command_w));
+ map(0x06, 0x07).rw(FUNC(i82371sb_ide_device::status_r), FUNC(i82371sb_ide_device::status_w));
+ map(0x0d, 0x0d).rw(FUNC(i82371sb_ide_device::latency_timer_r), FUNC(i82371sb_ide_device::latency_timer_w));
+ map(0x10, 0x1f).noprw();
map(0x20, 0x23).rw(FUNC(i82371sb_ide_device::bmiba_r), FUNC(i82371sb_ide_device::bmiba_w));
+ map(0x24, 0x3b).noprw();
map(0x40, 0x41).rw(FUNC(i82371sb_ide_device::idetim_primary_r), FUNC(i82371sb_ide_device::idetim_primary_w));
map(0x42, 0x43).rw(FUNC(i82371sb_ide_device::idetim_secondary_r), FUNC(i82371sb_ide_device::idetim_secondary_w));
map(0x44, 0x44).rw(FUNC(i82371sb_ide_device::sidetim_r), FUNC(i82371sb_ide_device::sidetim_w));
@@ -917,32 +1007,48 @@ void i82371sb_ide_device::device_add_mconfig(machine_config &config)
{
BUS_MASTER_IDE_CONTROLLER(config, m_ide1).options(ata_devices, "hdd", nullptr, false);
m_ide1->irq_handler().set(FUNC(i82371sb_ide_device::primary_int));
- m_ide1->set_bus_master_space(":maincpu", AS_PROGRAM);
BUS_MASTER_IDE_CONTROLLER(config, m_ide2).options(ata_devices, "cdrom", nullptr, false);
m_ide2->irq_handler().set(FUNC(i82371sb_ide_device::secondary_int));
- m_ide2->set_bus_master_space(":maincpu", AS_PROGRAM);
}
-i82371sb_ide_device::i82371sb_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : pci_device(mconfig, I82371SB_IDE, tag, owner, clock)
- , command(2)
+void i82371sb_ide_device::device_config_complete()
+{
+ auto ide1 = m_ide1.finder_target();
+ auto ide2 = m_ide2.finder_target();
+ ide1.first.subdevice<bus_master_ide_controller_device>(ide1.second)->set_bus_master_space(m_maincpu, AS_PROGRAM);
+ ide2.first.subdevice<bus_master_ide_controller_device>(ide2.second)->set_bus_master_space(m_maincpu, AS_PROGRAM);
+
+ pci_device::device_config_complete();
+}
+
+i82371sb_ide_device::i82371sb_ide_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, type, tag, owner, clock)
+ , latency_timer(0)
, bmiba(1)
, idetim_primary(0)
, idetim_secondary(0)
, sidetim(0)
, m_irq_pri_callback(*this)
, m_irq_sec_callback(*this)
+ , m_maincpu(*this, finder_base::DUMMY_TAG)
, m_ide1(*this, "ide1")
, m_ide2(*this, "ide2")
{
+}
+
+i82371sb_ide_device::i82371sb_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82371sb_ide_device(mconfig, I82371SB_IDE, tag, owner, clock)
+{
set_ids(0x80867010, 0, 0x010180, 0x00000000);
}
void i82371sb_ide_device::device_start()
{
- m_irq_pri_callback.resolve();
- m_irq_sec_callback.resolve();
+ pci_device::device_start();
+ status = 0x0280;
+ command = 2;
+ command_mask = 5;
}
void i82371sb_ide_device::device_reset()
@@ -953,8 +1059,15 @@ void i82371sb_ide_device::reset_all_mappings()
{
}
-void i82371sb_ide_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
- uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+void i82371sb_ide_device::map_extra(
+ uint64_t memory_window_start,
+ uint64_t memory_window_end,
+ uint64_t memory_offset,
+ address_space *memory_space,
+ uint64_t io_window_start,
+ uint64_t io_window_end,
+ uint64_t io_offset,
+ address_space *io_space)
{
io_space->install_device(0, 0x3ff, *this, &i82371sb_ide_device::internal_io_map);
if (command & 1)
@@ -966,27 +1079,32 @@ void i82371sb_ide_device::map_extra(uint64_t memory_window_start, uint64_t memor
}
}
-WRITE_LINE_MEMBER(i82371sb_ide_device::primary_int)
+void i82371sb_ide_device::primary_int(int state)
{
m_irq_pri_callback(state);
}
-WRITE_LINE_MEMBER(i82371sb_ide_device::secondary_int)
+void i82371sb_ide_device::secondary_int(int state)
{
m_irq_sec_callback(state);
}
-uint16_t i82371sb_ide_device::command_r()
+void i82371sb_ide_device::status_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
- return command;
+ // bits 11-13 are clear on write
+ status = status & ~(data & (0x3800 & mem_mask));
+ logerror("status = %04x\n", status);
}
-void i82371sb_ide_device::command_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+uint8_t i82371sb_ide_device::latency_timer_r()
{
- mem_mask &= 5;
- COMBINE_DATA(&command);
- if (mem_mask & 1)
- remap_cb();
+ return latency_timer;
+}
+
+void i82371sb_ide_device::latency_timer_w(uint8_t data)
+{
+ latency_timer = data;
+ logerror("latency_timer = %02x\n", latency_timer);
}
uint32_t i82371sb_ide_device::bmiba_r()
@@ -998,6 +1116,7 @@ void i82371sb_ide_device::bmiba_w(offs_t offset, uint32_t data, uint32_t mem_mas
{
mem_mask &= 0xfff0;
COMBINE_DATA(&bmiba);
+ logerror("bmiba = %04x\n", bmiba);
if (command & 1)
remap_cb();
}
@@ -1007,8 +1126,10 @@ uint16_t i82371sb_ide_device::idetim_primary_r()
return idetim_primary;
}
-void i82371sb_ide_device::idetim_primary_w(uint16_t data)
+void i82371sb_ide_device::idetim_primary_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
+ COMBINE_DATA(&idetim_primary);
+ logerror("idetim_primary = %04x\n", idetim_primary);
}
uint16_t i82371sb_ide_device::idetim_secondary_r()
@@ -1016,8 +1137,10 @@ uint16_t i82371sb_ide_device::idetim_secondary_r()
return idetim_secondary;
}
-void i82371sb_ide_device::idetim_secondary_w(uint16_t data)
+void i82371sb_ide_device::idetim_secondary_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
+ COMBINE_DATA(&idetim_secondary);
+ logerror("idetim_secondary = %04x\n", idetim_secondary);
}
uint8_t i82371sb_ide_device::sidetim_r()
@@ -1027,6 +1150,8 @@ uint8_t i82371sb_ide_device::sidetim_r()
void i82371sb_ide_device::sidetim_w(uint8_t data)
{
+ sidetim = data;
+ logerror("sidetim = %02x\n", sidetim);
}
uint32_t i82371sb_ide_device::ide1_read32_cs0_r(offs_t offset, uint32_t mem_mask)
diff --git a/src/devices/machine/i82371sb.h b/src/devices/machine/i82371sb.h
index e6cddab4a3f..0166a9354e2 100644
--- a/src/devices/machine/i82371sb.h
+++ b/src/devices/machine/i82371sb.h
@@ -9,55 +9,69 @@
#include "pci.h"
#include "machine/pci-ide.h"
+#include "bus/ata/ataintf.h"
+#include "bus/isa/isa.h"
+
#include "machine/ins8250.h"
#include "machine/ds128x.h"
#include "machine/pic8259.h"
#include "machine/pit8253.h"
-#include "bus/ata/ataintf.h"
-
#include "sound/spkrdev.h"
#include "machine/ram.h"
-#include "bus/isa/isa.h"
#include "machine/nvram.h"
#include "machine/am9517a.h"
-
-class i82371sb_isa_device : public pci_device {
+class i82371sb_isa_device : public pci_device
+{
public:
+ template <typename T>
+ i82371sb_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ : i82371sb_isa_device(mconfig, tag, owner, clock)
+ {
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ }
+
i82371sb_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto smi() { return m_smi_callback.bind(); }
+ auto nmi() { return m_nmi_callback.bind(); }
+ auto stpclk() { return m_stpclk_callback.bind(); }
auto boot_state_hook() { return m_boot_state_hook.bind(); }
- DECLARE_WRITE_LINE_MEMBER(pc_pirqa_w);
- DECLARE_WRITE_LINE_MEMBER(pc_pirqb_w);
- DECLARE_WRITE_LINE_MEMBER(pc_pirqc_w);
- DECLARE_WRITE_LINE_MEMBER(pc_pirqd_w);
- DECLARE_WRITE_LINE_MEMBER(pc_mirq0_w);
- DECLARE_WRITE_LINE_MEMBER(pc_mirq1_w);
- DECLARE_WRITE_LINE_MEMBER(pc_ferr_w);
-
- DECLARE_WRITE_LINE_MEMBER(pc_irq1_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq3_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq4_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq5_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq6_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq7_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq8n_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq9_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq10_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq11_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq12m_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq14_w);
- DECLARE_WRITE_LINE_MEMBER(pc_irq15_w);
+ template <typename T> void set_cpu_tag(T &&tag) { m_maincpu.set_tag(std::forward<T>(tag)); }
+
+ void pc_pirqa_w(int state);
+ void pc_pirqb_w(int state);
+ void pc_pirqc_w(int state);
+ void pc_pirqd_w(int state);
+ void pc_mirq0_w(int state);
+ void pc_mirq1_w(int state);
+ void pc_ferr_w(int state);
+ void pc_extsmi_w(int state);
+
+ void pc_irq1_w(int state);
+ void pc_irq3_w(int state);
+ void pc_irq4_w(int state);
+ void pc_irq5_w(int state);
+ void pc_irq6_w(int state);
+ void pc_irq7_w(int state);
+ void pc_irq8n_w(int state);
+ void pc_irq9_w(int state);
+ void pc_irq10_w(int state);
+ void pc_irq11_w(int state);
+ void pc_irq12m_w(int state);
+ void pc_irq14_w(int state);
+ void pc_irq15_w(int state);
protected:
+ i82371sb_isa_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_add_mconfig(machine_config & config) override;
+ virtual void device_config_complete() override;
virtual void device_start() override;
virtual void device_reset() override;
- // optional information overrides
- virtual void device_add_mconfig(machine_config &config) override;
virtual void reset_all_mappings() override;
virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
@@ -68,9 +82,9 @@ protected:
virtual void config_map(address_map &map) override;
private:
- DECLARE_WRITE_LINE_MEMBER(at_pit8254_out0_changed);
- DECLARE_WRITE_LINE_MEMBER(at_pit8254_out1_changed);
- DECLARE_WRITE_LINE_MEMBER(at_pit8254_out2_changed);
+ void at_pit8254_out0_changed(int state);
+ void at_pit8254_out1_changed(int state);
+ void at_pit8254_out2_changed(int state);
uint8_t pc_dma8237_0_dack_r();
uint8_t pc_dma8237_1_dack_r();
uint8_t pc_dma8237_2_dack_r();
@@ -85,20 +99,20 @@ private:
void pc_dma8237_5_dack_w(uint8_t data);
void pc_dma8237_6_dack_w(uint8_t data);
void pc_dma8237_7_dack_w(uint8_t data);
- 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_WRITE_LINE_MEMBER(at_dma8237_out_eop);
- DECLARE_WRITE_LINE_MEMBER(pc_dma_hrq_changed);
+ void pc_dack0_w(int state);
+ void pc_dack1_w(int state);
+ void pc_dack2_w(int state);
+ void pc_dack3_w(int state);
+ void pc_dack4_w(int state);
+ void pc_dack5_w(int state);
+ void pc_dack6_w(int state);
+ void pc_dack7_w(int state);
+ void at_dma8237_out_eop(int state);
+ void pc_dma_hrq_changed(int state);
uint8_t pc_dma_read_byte(offs_t offset);
void pc_dma_write_byte(offs_t offset, uint8_t data);
uint8_t pc_dma_read_word(offs_t offset);
- void pc_dma_write_word(offs_t offset,uint8_t data);
+ void pc_dma_write_word(offs_t offset, uint8_t data);
uint8_t get_slave_ack(offs_t offset);
void internal_io_map(address_map &map);
@@ -106,6 +120,7 @@ private:
void boot_state_w(uint8_t data);
void nop_w(uint8_t data);
+ void status_w(offs_t offset, uint16_t data, uint16_t mem_mask);
uint8_t iort_r();
void iort_w(uint8_t data);
uint16_t xbcs_r();
@@ -120,6 +135,8 @@ private:
void mbirq01_w(offs_t offset, uint8_t data);
uint8_t mbdma_r(offs_t offset);
void mbdma_w(offs_t offset, uint8_t data);
+ uint16_t pcsc_r();
+ void pcsc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint8_t apicbase_r();
void apicbase_w(uint8_t data);
uint8_t dlc_r();
@@ -144,17 +161,21 @@ private:
void at_page8_w(offs_t offset, uint8_t data);
uint8_t at_portb_r();
void at_portb_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(iochck_w);
+ void iochck_w(int state);
uint8_t at_dma8237_2_r(offs_t offset);
void at_dma8237_2_w(offs_t offset, uint8_t data);
uint8_t eisa_irq_read(offs_t offset);
void eisa_irq_write(offs_t offset, uint8_t data);
uint8_t read_apmcapms(offs_t offset);
void write_apmcapms(offs_t offset, uint8_t data);
+ uint8_t reset_control_r(offs_t offset);
+ void reset_control_w(offs_t offset, uint8_t data);
void update_smireq_line();
devcb_write_line m_smi_callback;
+ devcb_write_line m_nmi_callback;
+ devcb_write_line m_stpclk_callback;
devcb_write8 m_boot_state_hook;
uint32_t see;
@@ -162,10 +183,11 @@ private:
uint8_t apmc, apms;
uint8_t iort, pirqrc[4], tom, mbirq0, mbirq1, mbdma[2], apicbase;
uint8_t dlc, smicntl, ftmr, ctlmtr, cthmtr;
+ uint8_t reset_control;
void map_bios(address_space *memory_space, uint32_t start, uint32_t end);
- //southbridge
+ // southbridge
required_device<cpu_device> m_maincpu;
required_device<pic8259_device> m_pic8259_master;
required_device<pic8259_device> m_pic8259_slave;
@@ -192,42 +214,58 @@ private:
void pc_select_dma_channel(int channel, bool state);
void redirect_irq(int irq, int state);
+
+ int pin_mapper(int pin);
+ void irq_handler(int line, int state);
};
DECLARE_DEVICE_TYPE(I82371SB_ISA, i82371sb_isa_device)
-
-class i82371sb_ide_device : public pci_device {
+class i82371sb_ide_device : public pci_device
+{
public:
+ template <typename T>
+ i82371sb_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ : i82371sb_ide_device(mconfig, tag, owner, clock)
+ {
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ }
+
i82371sb_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto irq_pri() { return m_irq_pri_callback.bind(); }
auto irq_sec() { return m_irq_sec_callback.bind(); }
+ template <typename T>
+ void set_cpu_tag(T &&tag) { m_maincpu.set_tag(std::forward<T>(tag)); }
+
protected:
+ i82371sb_ide_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_config_complete() override;
virtual void device_start() override;
virtual void device_reset() override;
- // optional information overrides
- virtual void device_add_mconfig(machine_config &config) override;
virtual void reset_all_mappings() override;
virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
- uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
virtual void config_map(address_map &map) override;
- DECLARE_WRITE_LINE_MEMBER(primary_int);
- DECLARE_WRITE_LINE_MEMBER(secondary_int);
+ void primary_int(int state);
+ void secondary_int(int state);
private:
- uint16_t command_r();
- void command_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void status_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ virtual uint8_t latency_timer_r() override;
+ void latency_timer_w(uint8_t data);
uint32_t bmiba_r();
void bmiba_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint16_t idetim_primary_r();
- void idetim_primary_w(uint16_t data);
+ void idetim_primary_w(offs_t offset, uint16_t data, uint16_t mem_mask);
uint16_t idetim_secondary_r();
- void idetim_secondary_w(uint16_t data);
+ void idetim_secondary_w(offs_t offset, uint16_t data, uint16_t mem_mask);
uint8_t sidetim_r();
void sidetim_w(uint8_t data);
@@ -242,7 +280,7 @@ private:
void internal_io_map(address_map &map);
- uint16_t command;
+ uint8_t latency_timer;
uint32_t bmiba;
int idetim_primary, idetim_secondary;
int sidetim;
@@ -250,6 +288,7 @@ private:
devcb_write_line m_irq_pri_callback;
devcb_write_line m_irq_sec_callback;
+ required_device<cpu_device> m_maincpu;
required_device<bus_master_ide_controller_device> m_ide1;
required_device<bus_master_ide_controller_device> m_ide2;
};
diff --git a/src/devices/machine/i8243.cpp b/src/devices/machine/i8243.cpp
index 5c6c0bfe385..ad6ed6d1820 100644
--- a/src/devices/machine/i8243.cpp
+++ b/src/devices/machine/i8243.cpp
@@ -27,7 +27,7 @@ i8243_device::i8243_device(const machine_config &mconfig, const char *tag, devic
: device_t(mconfig, I8243, tag, owner, clock)
, m_p{0, 0, 0, 0}
, m_p2out(0x0f), m_p2(0x0f), m_opcode(0), m_prog(1), m_cs(0)
- , m_readhandler(*this)
+ , m_readhandler(*this, 0)
, m_writehandler(*this)
{
}
@@ -38,9 +38,6 @@ i8243_device::i8243_device(const machine_config &mconfig, const char *tag, devic
void i8243_device::device_start()
{
- m_readhandler.resolve_all();
- m_writehandler.resolve_all();
-
save_item(NAME(m_p));
save_item(NAME(m_p2out));
save_item(NAME(m_p2));
@@ -76,7 +73,7 @@ void i8243_device::p2_w(uint8_t data)
void i8243_device::output_update(int which)
{
- if (m_writehandler[which].isnull())
+ if (m_writehandler[which].isunset())
logerror("%s: Unconfigured write to P%d (%01X)\n", machine().describe_context(), which + 4, m_p[which]);
else
m_writehandler[which](m_p[which]);
@@ -88,7 +85,7 @@ void i8243_device::output_update(int which)
// state
//-------------------------------------------------
-WRITE_LINE_MEMBER(i8243_device::prog_w)
+void i8243_device::prog_w(int state)
{
/* on high->low transition state, latch opcode/port */
if (m_prog && !state && !m_cs)
@@ -99,7 +96,7 @@ WRITE_LINE_MEMBER(i8243_device::prog_w)
if ((m_opcode >> 2) == mcs48_cpu_device::EXPANDER_OP_READ)
{
int which = m_opcode & 3;
- if (m_readhandler[which].isnull())
+ if (m_readhandler[which].isunset())
logerror("%s: Unconfigured read from P%d\n", machine().describe_context(), which + 4);
else
m_p[which] = m_readhandler[which]();
@@ -144,7 +141,7 @@ WRITE_LINE_MEMBER(i8243_device::prog_w)
// cs_w - handle chip select line (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(i8243_device::cs_w)
+void i8243_device::cs_w(int state)
{
m_cs = state;
if (m_cs)
diff --git a/src/devices/machine/i8243.h b/src/devices/machine/i8243.h
index 53c46358567..9547abb14cb 100644
--- a/src/devices/machine/i8243.h
+++ b/src/devices/machine/i8243.h
@@ -47,8 +47,8 @@ public:
uint8_t p2_r();
void p2_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(prog_w);
- DECLARE_WRITE_LINE_MEMBER(cs_w);
+ void prog_w(int state);
+ void cs_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/i82439hx.cpp b/src/devices/machine/i82439hx.cpp
index bffed0db0d8..7dc130dbfa6 100644
--- a/src/devices/machine/i82439hx.cpp
+++ b/src/devices/machine/i82439hx.cpp
@@ -8,7 +8,11 @@ DEFINE_DEVICE_TYPE(I82439HX, i82439hx_host_device, "i82439hx", "Intel 82439HX no
void i82439hx_host_device::config_map(address_map &map)
{
pci_host_device::config_map(map);
+ map(0x06, 0x07).rw(FUNC(i82439hx_host_device::status_r), FUNC(i82439hx_host_device::status_w));
+ map(0x0d, 0x0d).rw(FUNC(i82439hx_host_device::latency_timer_r), FUNC(i82439hx_host_device::latency_timer_w));
+ map(0x0f, 0x0f).rw(FUNC(i82439hx_host_device::bist_r), FUNC(i82439hx_host_device::bist_w));
map(0x10, 0x4f).noprw();
+ map(0x4f, 0x4f).rw(FUNC(i82439hx_host_device::acon_r), FUNC(i82439hx_host_device::acon_w));
map(0x50, 0x50).rw(FUNC(i82439hx_host_device::pcon_r), FUNC(i82439hx_host_device::pcon_w));
map(0x52, 0x52).rw(FUNC(i82439hx_host_device::cc_r), FUNC(i82439hx_host_device::cc_w));
map(0x56, 0x56).rw(FUNC(i82439hx_host_device::dramec_r), FUNC(i82439hx_host_device::dramec_w));
@@ -24,12 +28,18 @@ void i82439hx_host_device::config_map(address_map &map)
map(0x92, 0x92).r(FUNC(i82439hx_host_device::errsyn_r));
}
-i82439hx_host_device::i82439hx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : pci_host_device(mconfig, I82439HX, tag, owner, clock)
+i82439hx_host_device::i82439hx_host_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : pci_host_device(mconfig, type, tag, owner, clock)
, cpu(*this, finder_base::DUMMY_TAG)
{
}
+i82439hx_host_device::i82439hx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82439hx_host_device(mconfig, I82439HX, tag, owner, clock)
+{
+ set_ids_host(0x80861250, 0x03, 0x00000000);
+}
+
void i82439hx_host_device::set_ram_size(int _ram_size)
{
ram_size = _ram_size;
@@ -38,8 +48,7 @@ void i82439hx_host_device::set_ram_size(int _ram_size)
void i82439hx_host_device::device_start()
{
pci_host_device::device_start();
- memory_space = &cpu->space(AS_PROGRAM);
- io_space = &cpu->space(AS_IO);
+ set_spaces(&cpu->space(AS_PROGRAM), &cpu->space(AS_IO));
memory_window_start = 0;
memory_window_end = 0xffffffff;
@@ -48,7 +57,7 @@ void i82439hx_host_device::device_start()
io_window_end = 0xffff;
io_offset = 0;
command = 0x0006;
- command_mask = 0x0106;
+ command_mask = 0x0102;
status = 0x0200;
ram.resize(ram_size/4);
@@ -63,6 +72,9 @@ void i82439hx_host_device::device_reset()
{
pci_host_device::device_reset();
+ latency_timer = 0x00;
+ bist = 0x00;
+ acon = 0x00;
pcon = 0x00;
cc = 0xa2;
dramec = 0x00;
@@ -79,18 +91,27 @@ void i82439hx_host_device::device_reset()
smiact_n = 1;
}
+std::tuple<bool, bool> i82439hx_host_device::read_memory_holes()
+{
+ const bool lower_hole = (dramc & 0xc0) == 0x40;
+ const bool upper_hole = (dramc & 0xc0) != 0x80;
+ return std::make_tuple(lower_hole, upper_hole);
+}
+
void i82439hx_host_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
{
io_space->install_device(0, 0xffff, *static_cast<pci_host_device *>(this), &pci_host_device::io_configuration_access_map);
+ auto [memory_hole_lower, memory_hole_upper] = read_memory_holes();
+
// memory hole at 512-640 kbytes
- if((dramc & 0xc0) == 0x40)
+ if(memory_hole_lower)
memory_space->install_ram (0x00000000, 0x0007ffff, &ram[0x00000000/4]);
else
memory_space->install_ram (0x00000000, 0x0009ffff, &ram[0x00000000/4]);
- // assume that map_extra of the northbridge is called after the video card has mepped its memory here
+ // assume that map_extra of the northbridge is called after the video card has mapped its memory here
if (smram & 0x08)
{
if (smiact_n == 0)
@@ -156,7 +177,7 @@ void i82439hx_host_device::map_extra(uint64_t memory_window_start, uint64_t memo
memory_space->install_ram (0x00100000, 0x00efffff, &ram[0x00100000/4]);
// memory hole at 15-16 mbytes
- if((dramc & 0xc0) != 0x80)
+ if(memory_hole_upper)
memory_space->install_ram (0x00f00000, 0x00ffffff, &ram[0x00f00000/4]);
memory_space->install_ram (0x01000000, ram_size-1, &ram[0x01000000/4]);
@@ -168,6 +189,45 @@ uint8_t i82439hx_host_device::header_type_r()
return 0x00; // from datasheet
}
+void i82439hx_host_device::status_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ // bits 12-14 are clear on write
+ status = status & ~(data & (0x7000 & mem_mask));
+}
+
+uint8_t i82439hx_host_device::latency_timer_r()
+{
+ return latency_timer;
+}
+
+void i82439hx_host_device::latency_timer_w(uint8_t data)
+{
+ latency_timer = data;
+ logerror("latency_timer = %02x\n", latency_timer);
+}
+
+uint8_t i82439hx_host_device::bist_r()
+{
+ return bist;
+}
+
+void i82439hx_host_device::bist_w(uint8_t data)
+{
+ bist = data;
+ logerror("bist = %02x\n", bist);
+}
+
+uint8_t i82439hx_host_device::acon_r()
+{
+ return acon;
+}
+
+void i82439hx_host_device::acon_w(uint8_t data)
+{
+ acon = data;
+ logerror("acon = %02x\n", acon);
+}
+
uint8_t i82439hx_host_device::pcon_r()
{
return pcon;
@@ -233,6 +293,36 @@ void i82439hx_host_device::pam_w(offs_t offset, uint8_t data)
{
pam[offset - 1] = data;
logerror("pam[%d] = %02x\n", offset - 1, pam[offset - 1]);
+ switch (offset - 1)
+ {
+ case 0:
+ logerror(" F0000-FFFFF BIOS Area RE:%d WE:%d CE:%d R:%d\n", (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1);
+ break;
+ case 1:
+ logerror(" C0000-C3FFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 0) & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1);
+ logerror(" C4000-C7FFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1);
+ break;
+ case 2:
+ logerror(" C8000-CBFFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 0) & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1);
+ logerror(" CC000-CFFFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1);
+ break;
+ case 3:
+ logerror(" D0000-D3FFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 0) & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1);
+ logerror(" D4000-D7FFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1);
+ break;
+ case 4:
+ logerror(" D8000-DBFFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 0) & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1);
+ logerror(" DC000-DFFFF Add-On BIOS RE:%d WE:%d CE:%d R:%d\n", (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1);
+ break;
+ case 5:
+ logerror(" E0000-E3FFF BIOS Extension RE:%d WE:%d CE:%d R:%d\n", (data >> 0) & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1);
+ logerror(" E4000-E7FFF BIOS Extension RE:%d WE:%d CE:%d R:%d\n", (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1);
+ break;
+ case 6:
+ logerror(" E8000-EBFFF BIOS Extension RE:%d WE:%d CE:%d R:%d\n", (data >> 0) & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1);
+ logerror(" EC000-EFFFF BIOS Extension RE:%d WE:%d CE:%d R:%d\n", (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1);
+ break;
+ }
remap_cb();
}
@@ -308,7 +398,7 @@ uint8_t i82439hx_host_device::errsyn_r()
return errsyn;
}
-WRITE_LINE_MEMBER(i82439hx_host_device::smi_act_w)
+void i82439hx_host_device::smi_act_w(int state)
{
// state is 0 when smm is not active
// but smiact_n reflects the state of the SMIACT# pin
diff --git a/src/devices/machine/i82439hx.h b/src/devices/machine/i82439hx.h
index 73650cbac5d..3356b44b12f 100644
--- a/src/devices/machine/i82439hx.h
+++ b/src/devices/machine/i82439hx.h
@@ -15,7 +15,6 @@ public:
i82439hx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, int ram_size)
: i82439hx_host_device(mconfig, tag, owner, clock)
{
- set_ids_host(0x80861250, 0x03, 0x00000000);
set_cpu_tag(std::forward<T>(cpu_tag));
set_ram_size(ram_size);
}
@@ -24,9 +23,11 @@ public:
template <typename T> void set_cpu_tag(T &&tag) { cpu.set_tag(std::forward<T>(tag)); }
void set_ram_size(int ram_size);
- DECLARE_WRITE_LINE_MEMBER(smi_act_w);
+ void smi_act_w(int state);
protected:
+ i82439hx_host_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
virtual void device_start() override;
virtual void device_reset() override;
@@ -37,17 +38,27 @@ protected:
virtual void config_map(address_map &map) override;
+ virtual std::tuple<bool, bool> read_memory_holes();
+
private:
int ram_size;
required_device<device_memory_interface> cpu;
std::vector<uint32_t> ram;
- uint8_t pcon, cc, dramec, dramc, dramt;
+ uint8_t latency_timer, bist;
+ uint8_t acon, pcon, cc, dramec, dramc, dramt;
uint8_t pam[7], drb[8];
uint8_t drt, drat, smram, errcmd, errsts, errsyn;
int smiact_n;
virtual uint8_t header_type_r() override;
+ void status_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ virtual uint8_t latency_timer_r() override;
+ void latency_timer_w(uint8_t data);
+ virtual uint8_t bist_r() override;
+ void bist_w(uint8_t data);
+ uint8_t acon_r();
+ void acon_w(uint8_t data);
uint8_t pcon_r();
void pcon_w(uint8_t data);
uint8_t cc_r();
diff --git a/src/devices/machine/i82439tx.cpp b/src/devices/machine/i82439tx.cpp
index f8c1c9a8bb3..9196f8f7f4d 100644
--- a/src/devices/machine/i82439tx.cpp
+++ b/src/devices/machine/i82439tx.cpp
@@ -37,8 +37,7 @@ void i82439tx_host_device::set_ram_size(int _ram_size)
void i82439tx_host_device::device_start()
{
pci_host_device::device_start();
- memory_space = &cpu->space(AS_PROGRAM);
- io_space = &cpu->space(AS_IO);
+ set_spaces(&cpu->space(AS_PROGRAM), &cpu->space(AS_IO));
memory_window_start = 0;
memory_window_end = 0xffffffff;
diff --git a/src/devices/machine/i82443bx_host.cpp b/src/devices/machine/i82443bx_host.cpp
new file mode 100644
index 00000000000..aa06e993496
--- /dev/null
+++ b/src/devices/machine/i82443bx_host.cpp
@@ -0,0 +1,193 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ Intel 440BX 82443BX Host section
+
+ TODO:
+ - better subclassing leap, we currently use i82339hx base for convenience
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "i82443bx_host.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(I82443BX_HOST, i82443bx_host_device, "i82443bx_host", "Intel 82443BX PAC Host to PCI northbridge")
+DEFINE_DEVICE_TYPE(I82443LX_HOST, i82443lx_host_device, "i82443lx_host", "Intel 82443LX PAC Host to PCI northbridge")
+
+i82443bx_host_device::i82443bx_host_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : i82439hx_host_device(mconfig, type, tag, owner, clock)
+{
+}
+
+i82443bx_host_device::i82443bx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82443bx_host_device(mconfig, I82443BX_HOST, tag, owner, clock)
+{
+ // TODO: Device ID (DID) is 0x7192 when AGP_DIS is '1'
+ // rev 0x02 82443BX B-1
+ set_ids_host(0x80867190, 0x02, 0x00000000);
+}
+
+
+i82443lx_host_device::i82443lx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82443bx_host_device(mconfig, I82443LX_HOST, tag, owner, clock)
+{
+ set_ids_host(0x80867180, 0x00, 0x00000000);
+}
+
+void i82443bx_host_device::config_map(address_map &map)
+{
+ i82439hx_host_device::config_map(map);
+
+ // override first BAR slot for gfx window base address
+ map(0x10, 0x13).rw(FUNC(pci_device::address_base_r), FUNC(pci_device::address_base_w));
+
+ map(0x34, 0x34).r(FUNC(i82443bx_host_device::capptr_r));
+
+// map(0x50, 0x53).lr32(NAME([this] () { return machine().rand(); }));
+ // TODO: no DRT, moved as DRTC / DWTC in dword format to $e0/$e8
+ map(0x68, 0x68).rw(FUNC(i82443bx_host_device::fdhc_r), FUNC(i82443bx_host_device::fdhc_w));
+
+ // TODO: midqslvr.cpp r/ws the AGPCTRL register but don't seem to match what's in datasheet
+ // I also haven't yet enabled CAPPTR lolwut?
+ //map(0xb0, 0xb3)
+ map(0xd0, 0xd7).rw(FUNC(i82443bx_host_device::bspad_r), FUNC(i82443bx_host_device::bspad_w));
+}
+
+void i82443bx_host_device::apbase_map(address_map &map)
+{
+ // ...
+}
+
+void i82443bx_host_device::device_start()
+{
+ i82439hx_host_device::device_start();
+
+ // TODO: size
+ add_map(8*1024*1024, M_MEM, FUNC(i82443bx_host_device::apbase_map));
+
+ save_item(NAME(m_fdhc));
+ save_pointer(NAME(m_bspad), 8);
+}
+
+void i82443bx_host_device::device_reset()
+{
+ i82439hx_host_device::device_reset();
+
+ m_fdhc = 0;
+ for (int i = 0; i < 8; i++)
+ m_bspad[i] = 0;
+}
+
+u8 i82443bx_host_device::capptr_r()
+{
+ return 0xa0;
+}
+
+// Register is different wrt i82439hx
+std::tuple<bool, bool> i82443bx_host_device::read_memory_holes()
+{
+ const bool lower_hole = (m_fdhc & 0xc0) == 0x40;
+ // TODO: 11 is "reserved"
+ const bool upper_hole = (m_fdhc & 0xc0) != 0x80;
+ return std::make_tuple(lower_hole, upper_hole);
+}
+
+u8 i82443bx_host_device::fdhc_r()
+{
+ return m_fdhc;
+}
+
+void i82443bx_host_device::fdhc_w(u8 data)
+{
+ m_fdhc = data;
+ LOGIO("FDHC = %02x\n", data);
+ remap_cb();
+}
+
+/*
+ * BSPAD - BIOS Scratch Pad Register
+ * 8 bytes of pseudo-RAM
+ */
+u8 i82443bx_host_device::bspad_r(offs_t offset)
+{
+ LOGIO("BSPAD[%d] R\n", offset);
+ return m_bspad[offset];
+}
+
+void i82443bx_host_device::bspad_w(offs_t offset, u8 data)
+{
+ LOGIO("BSPAD[%d] = %02x\n", offset, data);
+ m_bspad[offset] = data;
+}
+
+/*****************************
+ *
+ * Virtual PCI-to-PCI bridge implementation
+ *
+ ****************************/
+
+DEFINE_DEVICE_TYPE(I82443BX_BRIDGE, i82443bx_bridge_device, "i82443bx_bridge", "Intel 82443BX Virtual PCI-to-PCI bridge")
+DEFINE_DEVICE_TYPE(I82443LX_BRIDGE, i82443lx_bridge_device, "i82443lx_bridge", "Intel 82443LX Virtual PCI-to-PCI bridge")
+
+i82443bx_bridge_device::i82443bx_bridge_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : pci_bridge_device(mconfig, type, tag, owner, clock)
+// , m_vga(*this, finder_base::DUMMY_TAG)
+{
+}
+
+i82443bx_bridge_device::i82443bx_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82443bx_bridge_device(mconfig, I82443BX_BRIDGE, tag, owner, clock)
+// , m_vga(*this, finder_base::DUMMY_TAG)
+{
+ set_ids_bridge(0x80867191, 0x00);
+}
+
+i82443lx_bridge_device::i82443lx_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : i82443bx_bridge_device(mconfig, I82443LX_BRIDGE, tag, owner, clock)
+{
+ set_ids_bridge(0x80867181, 0x00);
+}
+
+void i82443bx_bridge_device::map_extra(
+ uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space
+)
+{
+ if (BIT(bridge_control, 3))
+ {
+ //memory_space->install_device(0, 0xfffff, *m_vga, &sis630_gui_device::legacy_memory_map);
+ //io_space->install_device(0, 0x0fff, *m_vga, &sis630_gui_device::legacy_io_map);
+ }
+}
+
+void i82443bx_bridge_device::bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ pci_bridge_device::bridge_control_w(offset, data, mem_mask);
+ LOGMAP("- %s VGA control\n", bridge_control & 8 ? "Enable" : "Disable");
+ remap_cb();
+}
+
+void i82443bx_bridge_device::device_start()
+{
+ pci_bridge_device::device_start();
+}
+
+void i82443bx_bridge_device::device_reset()
+{
+ pci_bridge_device::device_reset();
+}
+
diff --git a/src/devices/machine/i82443bx_host.h b/src/devices/machine/i82443bx_host.h
new file mode 100644
index 00000000000..d4848985d88
--- /dev/null
+++ b/src/devices/machine/i82443bx_host.h
@@ -0,0 +1,105 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_I82443BX_HOST_H
+#define MAME_MACHINE_I82443BX_HOST_H
+
+#pragma once
+
+#include "pci.h"
+#include "machine/i82439hx.h"
+
+class i82443bx_host_device : public i82439hx_host_device
+{
+public:
+ template <typename T>
+ i82443bx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, int ram_size)
+ : i82443bx_host_device(mconfig, tag, owner, clock)
+ {
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ set_ram_size(ram_size);
+ }
+ i82443bx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ i82443bx_host_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void config_map(address_map &map) override;
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void apbase_map(address_map &map);
+
+ virtual u8 capptr_r() override;
+
+private:
+ virtual std::tuple<bool, bool> read_memory_holes() override;
+
+ u8 m_fdhc = 0;
+ u8 m_bspad[8]{};
+
+ u8 fdhc_r();
+ void fdhc_w(u8 data);
+ u8 bspad_r(offs_t offset);
+ void bspad_w(offs_t offset, u8 data);
+};
+
+class i82443lx_host_device : public i82443bx_host_device
+{
+public:
+ template <typename T>
+ i82443lx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, int ram_size)
+ : i82443lx_host_device(mconfig, tag, owner, clock)
+ {
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ set_ram_size(ram_size);
+ }
+ i82443lx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+class i82443bx_bridge_device : public pci_bridge_device
+{
+public:
+ /*template <typename T> sis630_bridge_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&gui_tag
+ ) : sis630_bridge_device(mconfig, tag, owner, clock)
+ {
+ // either 0001 or 6001 as device ID
+ set_ids_bridge(0x10396001, 0x00);
+ //set_multifunction_device(true);
+ //m_vga.set_tag(std::forward<T>(gui_tag));
+ }*/
+
+ i82443bx_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ i82443bx_bridge_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+private:
+ //required_device<sis630_gui_device> m_vga;
+
+ virtual void bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) override;
+};
+
+class i82443lx_bridge_device : public i82443bx_bridge_device
+{
+public:
+ i82443lx_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+DECLARE_DEVICE_TYPE(I82443BX_HOST, i82443bx_host_device)
+DECLARE_DEVICE_TYPE(I82443LX_HOST, i82443lx_host_device)
+
+DECLARE_DEVICE_TYPE(I82443BX_BRIDGE, i82443bx_bridge_device)
+DECLARE_DEVICE_TYPE(I82443LX_BRIDGE, i82443lx_bridge_device)
+
+
+#endif // MAME_MACHINE_I82443BX_HOST_H
diff --git a/src/devices/machine/i8251.cpp b/src/devices/machine/i8251.cpp
index 03cba758bbf..76e5a25dab7 100644
--- a/src/devices/machine/i8251.cpp
+++ b/src/devices/machine/i8251.cpp
@@ -85,24 +85,6 @@ v5x_scu_device::v5x_scu_device(const machine_config &mconfig, const char *tag, d
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void i8251_device::device_resolve_objects()
-{
- // resolve callbacks
- m_txd_handler.resolve_safe();
- m_rts_handler.resolve_safe();
- m_dtr_handler.resolve_safe();
- m_rxrdy_handler.resolve_safe();
- m_txrdy_handler.resolve_safe();
- m_txempty_handler.resolve_safe();
- m_syndet_handler.resolve_safe();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -826,28 +808,31 @@ void i8251_device::write(offs_t offset, uint8_t data)
}
-WRITE_LINE_MEMBER(i8251_device::write_rxd)
+void i8251_device::write_rxd(int state)
{
m_rxd = state;
LOGBITS("8251: Presented a %d\n", m_rxd);
// device_serial_interface::rx_w(state);
}
-WRITE_LINE_MEMBER(i8251_device::write_cts)
+void i8251_device::write_cts(int state)
{
m_cts = state;
- check_for_tx_start();
- update_tx_ready();
- update_tx_empty();
+ if (started())
+ {
+ check_for_tx_start();
+ update_tx_ready();
+ update_tx_empty();
+ }
}
-WRITE_LINE_MEMBER(i8251_device::write_dsr)
+void i8251_device::write_dsr(int state)
{
m_dsr = !state;
}
-WRITE_LINE_MEMBER(i8251_device::write_rxc)
+void i8251_device::write_rxc(int state)
{
if (!m_rxc && state)
{
@@ -863,7 +848,7 @@ WRITE_LINE_MEMBER(i8251_device::write_rxc)
m_rxc = state;
}
-WRITE_LINE_MEMBER(i8251_device::write_txc)
+void i8251_device::write_txc(int state)
{
if (m_txc != state)
{
@@ -875,7 +860,7 @@ WRITE_LINE_MEMBER(i8251_device::write_txc)
}
// forcibly kill hunt mode
-WRITE_LINE_MEMBER(i8251_device::write_syn)
+void i8251_device::write_syn(int state)
{
if (m_syndet_pin && state) // must be set as input
{
@@ -885,7 +870,7 @@ WRITE_LINE_MEMBER(i8251_device::write_syn)
}
}
-READ_LINE_MEMBER(i8251_device::txrdy_r)
+int i8251_device::txrdy_r()
{
return is_tx_enabled() && (m_status & I8251_STATUS_TX_READY) != 0;
}
diff --git a/src/devices/machine/i8251.h b/src/devices/machine/i8251.h
index 2bda850958e..127b5ad2629 100644
--- a/src/devices/machine/i8251.h
+++ b/src/devices/machine/i8251.h
@@ -15,8 +15,7 @@
#include "diserial.h"
-class i8251_device : public device_t,
- public device_serial_interface
+class i8251_device : public device_t, public device_serial_interface
{
public:
// construction/destruction
@@ -39,14 +38,14 @@ public:
virtual uint8_t read(offs_t offset);
virtual void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( write_rxd );
- DECLARE_WRITE_LINE_MEMBER( write_cts );
- DECLARE_WRITE_LINE_MEMBER( write_dsr );
- DECLARE_WRITE_LINE_MEMBER( write_txc );
- DECLARE_WRITE_LINE_MEMBER( write_rxc );
- DECLARE_WRITE_LINE_MEMBER( write_syn );
+ void write_rxd(int state);
+ void write_cts(int state);
+ void write_dsr(int state);
+ void write_txc(int state);
+ void write_rxc(int state);
+ void write_syn(int state);
- DECLARE_READ_LINE_MEMBER(txrdy_r);
+ int txrdy_r();
protected:
enum
@@ -66,8 +65,7 @@ protected:
device_t *owner,
uint32_t clock);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
@@ -133,7 +131,7 @@ private:
/* data being received */
uint8_t m_rx_data;
- /* tx buffer */
+ /* tx buffer */
uint8_t m_tx_data;
void sync1_w(uint8_t data);
void sync2_w(uint8_t data);
@@ -149,7 +147,7 @@ private:
u8 m_data_bits_count;
};
-class v5x_scu_device : public i8251_device
+class v5x_scu_device : public i8251_device
{
public:
// construction/destruction
@@ -159,6 +157,7 @@ public:
virtual void write(offs_t offset, uint8_t data) override;
protected:
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/i8255.cpp b/src/devices/machine/i8255.cpp
index e0e5d8297a6..3d0424da61b 100644
--- a/src/devices/machine/i8255.cpp
+++ b/src/devices/machine/i8255.cpp
@@ -64,7 +64,6 @@ enum
//**************************************************************************
DEFINE_DEVICE_TYPE(I8255, i8255_device, "i8255", "Intel 8255 PPI")
-decltype(I8255) I8255A = I8255;
DEFINE_DEVICE_TYPE(AMS40489_PPI, ams40489_ppi_device, "ams40489_ppi", "Amstrad AMS40489 PPI")
@@ -221,15 +220,15 @@ i8255_device::i8255_device(const machine_config &mconfig, device_type type, cons
, m_force_portb_in(is_ams40489)
, m_force_portc_out(is_ams40489)
, m_dont_clear_output_latches(is_ams40489)
- , m_in_pa_cb(*this)
- , m_in_pb_cb(*this)
- , m_in_pc_cb(*this)
+ , m_in_pa_cb(*this, 0)
+ , m_in_pb_cb(*this, 0)
+ , m_in_pc_cb(*this, 0)
, m_out_pa_cb(*this)
, m_out_pb_cb(*this)
, m_out_pc_cb(*this)
- , m_tri_pa_cb(*this)
- , m_tri_pb_cb(*this)
- , m_tri_pc_cb(*this)
+ , m_tri_pa_cb(*this, 0xff)
+ , m_tri_pb_cb(*this, 0xff)
+ , m_tri_pc_cb(*this, 0xff)
, m_control(0)
, m_intr{ 0, 0 }
{
@@ -240,20 +239,6 @@ i8255_device::i8255_device(const machine_config &mconfig, const char *tag, devic
{
}
-void i8255_device::device_resolve_objects()
-{
- // resolve callbacks
- m_in_pa_cb.resolve_safe(0);
- m_in_pb_cb.resolve_safe(0);
- m_in_pc_cb.resolve_safe(0);
- m_out_pa_cb.resolve_safe();
- m_out_pb_cb.resolve_safe();
- m_out_pc_cb.resolve_safe();
- m_tri_pa_cb.resolve_safe(0xff);
- m_tri_pb_cb.resolve_safe(0xff);
- m_tri_pc_cb.resolve_safe(0xff);
-}
-
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -878,7 +863,7 @@ uint8_t i8255_device::ackb_r()
}
-WRITE_LINE_MEMBER( i8255_device::pc2_w )
+void i8255_device::pc2_w(int state)
{
if (group_mode(GROUP_B) == 1)
{
@@ -896,7 +881,7 @@ WRITE_LINE_MEMBER( i8255_device::pc2_w )
else
{
// port B strobe
- if (!m_ibf[PORT_B] && !state)
+ if (!state)
{
LOG("I8255 Port B Strobe\n");
@@ -911,12 +896,12 @@ WRITE_LINE_MEMBER( i8255_device::pc2_w )
}
-WRITE_LINE_MEMBER( i8255_device::pc4_w )
+void i8255_device::pc4_w(int state)
{
if ((group_mode(GROUP_A) == 2) || ((group_mode(GROUP_A) == 1) && (port_mode(PORT_A) == MODE_INPUT)))
{
// port A strobe
- if (!m_ibf[PORT_A] && !state)
+ if (!state)
{
LOG("I8255 Port A Strobe\n");
@@ -930,7 +915,7 @@ WRITE_LINE_MEMBER( i8255_device::pc4_w )
}
-WRITE_LINE_MEMBER( i8255_device::pc6_w )
+void i8255_device::pc6_w(int state)
{
if ((group_mode(GROUP_A) == 2) || ((group_mode(GROUP_A) == 1) && (port_mode(PORT_A) == MODE_OUTPUT)))
{
diff --git a/src/devices/machine/i8255.h b/src/devices/machine/i8255.h
index 44a4dc72e5f..49951af0af9 100644
--- a/src/devices/machine/i8255.h
+++ b/src/devices/machine/i8255.h
@@ -68,15 +68,14 @@ public:
uint8_t pb_r();
uint8_t ackb_r();
- DECLARE_WRITE_LINE_MEMBER( pc2_w );
- DECLARE_WRITE_LINE_MEMBER( pc4_w );
- DECLARE_WRITE_LINE_MEMBER( pc6_w );
+ void pc2_w(int state);
+ void pc4_w(int state);
+ void pc6_w(int state);
protected:
i8255_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool is_ams40489);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
@@ -142,7 +141,7 @@ public:
// device type definition
DECLARE_DEVICE_TYPE(I8255, i8255_device)
-DECLARE_DEVICE_TYPE(I8255A, i8255_device)
+static auto &I8255A = I8255;
DECLARE_DEVICE_TYPE(AMS40489_PPI, ams40489_ppi_device)
#endif // MAME_MACHINE_I8255_H
diff --git a/src/devices/machine/i8257.cpp b/src/devices/machine/i8257.cpp
index 663c5851abf..d64453fcb19 100644
--- a/src/devices/machine/i8257.cpp
+++ b/src/devices/machine/i8257.cpp
@@ -9,7 +9,6 @@
#include "emu.h"
#include "i8257.h"
-//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already
#define LOG_SETUP (1U << 1)
#define LOG_TFR (1U << 2)
@@ -270,9 +269,9 @@ i8257_device::i8257_device(const machine_config &mconfig, const char *tag, devic
, m_temp(0)
, m_out_hrq_cb(*this)
, m_out_tc_cb(*this)
- , m_in_memr_cb(*this)
+ , m_in_memr_cb(*this, 0)
, m_out_memw_cb(*this)
- , m_in_ior_cb(*this)
+ , m_in_ior_cb(*this, 0)
, m_out_iow_cb(*this)
, m_out_dack_cb(*this)
{
@@ -289,15 +288,6 @@ void i8257_device::device_start()
// set our instruction counter
set_icountptr(m_icount);
- // resolve callbacks
- m_out_hrq_cb.resolve_safe();
- m_out_tc_cb.resolve_safe();
- m_in_memr_cb.resolve_safe(0);
- m_out_memw_cb.resolve_safe();
- m_in_ior_cb.resolve_all_safe(0);
- m_out_iow_cb.resolve_all_safe();
- m_out_dack_cb.resolve_all_safe();
-
// state saving
save_item(NAME(m_msb));
save_item(NAME(m_hreq));
@@ -428,7 +418,7 @@ void i8257_device::execute_run()
if (m_ready)
{
m_state = STATE_S4;
- if (m_channel[m_current_channel].m_count == 0)
+ if ((m_channel[m_current_channel].m_count == 0) && (MODE_TRANSFER_MASK != MODE_TRANSFER_READ))
set_tc(1);
}
else
@@ -439,7 +429,7 @@ void i8257_device::execute_run()
if (m_ready)
{
m_state = STATE_S4;
- if (m_channel[m_current_channel].m_count == 0)
+ if ((m_channel[m_current_channel].m_count == 0) && (MODE_TRANSFER_MASK != MODE_TRANSFER_READ))
set_tc(1);
}
break;
@@ -449,6 +439,8 @@ void i8257_device::execute_run()
{
dma_write();
}
+ if ((m_channel[m_current_channel].m_count == 0) && (MODE_TRANSFER_MASK == MODE_TRANSFER_READ))
+ set_tc(1);
advance();
if(m_hack && next_channel())
@@ -539,7 +531,7 @@ void i8257_device::write(offs_t offset, uint8_t data)
switch (offset & 0x01)
{
case REGISTER_ADDRESS:
- LOGSETUP(" * Register Address <- %02x\n", data);
+ LOGSETUP(" * Channel %d Register Address <- %02x\n", channel, data);
if (m_msb)
{
m_channel[channel].m_address = (data << 8) | (m_channel[channel].m_address & 0xff);
@@ -555,7 +547,7 @@ void i8257_device::write(offs_t offset, uint8_t data)
break;
case REGISTER_WORD_COUNT:
- LOGSETUP(" * Register Word Count <- %02x\n", data);
+ LOGSETUP(" * Channel %d Register Word Count <- %02x\n", channel, data);
if (m_msb)
{
m_channel[channel].m_count = ((data & 0x3f) << 8) | (m_channel[channel].m_count & 0xff);
diff --git a/src/devices/machine/i82586.cpp b/src/devices/machine/i82586.cpp
index 83cc21ac53c..578d1a32979 100644
--- a/src/devices/machine/i82586.cpp
+++ b/src/devices/machine/i82586.cpp
@@ -31,9 +31,10 @@
#include "emu.h"
#include "i82586.h"
+
#include "hashing.h"
+#include "multibyte.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_FRAMES (1U << 1)
#define LOG_FILTER (1U << 2)
#define LOG_CONFIG (1U << 3)
@@ -96,7 +97,7 @@ CFG_PARAMS[] =
{ "number of retries", "maximum number of retries", 15, 7, 0xf0, 4, true },
{ "no crc insertion", "crc appended to frame", 0, 8, 0x10, 4, false },
{ "prefetch bit in rbd", "disabled (valid only in new modes)", 0, 0, 0x80, 7, false },
- { "preamble length", "bytes", 7, 3, 0x30, 4, true },
+ { "preamble length", "2^(n+1) bytes", 2, 3, 0x30, 4, true },
{ "preamble until crs", "disabled", 1, 11, 0x01, 0, false },
{ "promiscuous mode", "address filter on", 0, 8, 0x01, 0, false },
{ "padding", "no padding", 0, 8, 0x80, 7, false },
@@ -111,7 +112,7 @@ CFG_PARAMS[] =
i82586_base_device::i82586_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endian, u8 datawidth, u8 addrwidth)
: device_t(mconfig, type, tag, owner, clock)
, device_memory_interface(mconfig, *this)
- , device_network_interface(mconfig, *this, 10.0f)
+ , device_network_interface(mconfig, *this, 10)
, m_space_config("shared", endian, datawidth, addrwidth)
, m_out_irq(*this)
, m_cx(false)
@@ -120,6 +121,7 @@ i82586_base_device::i82586_base_device(const machine_config &mconfig, device_typ
, m_rnr(false)
, m_initialised(false)
, m_reset(false)
+ , m_irq(false)
, m_irq_assert(1)
, m_cu_state(CU_IDLE)
, m_ru_state(RU_IDLE)
@@ -162,10 +164,7 @@ void i82586_base_device::device_start()
{
m_space = &space(0);
- m_out_irq.resolve();
-
- m_cu_timer = timer_alloc(CU_TIMER);
- m_cu_timer->enable(false);
+ m_cu_timer = timer_alloc(FUNC(i82586_base_device::cu_execute), this);
save_item(NAME(m_cx));
save_item(NAME(m_fr));
@@ -173,6 +172,7 @@ void i82586_base_device::device_start()
save_item(NAME(m_rnr));
save_item(NAME(m_initialised));
save_item(NAME(m_reset));
+ save_item(NAME(m_irq));
save_item(NAME(m_cu_state));
save_item(NAME(m_ru_state));
@@ -189,7 +189,7 @@ void i82586_base_device::device_start()
void i82586_base_device::device_reset()
{
- m_cu_timer->enable(false);
+ m_cu_timer->reset();
m_cx = false;
m_fr = false;
@@ -201,16 +201,9 @@ void i82586_base_device::device_reset()
m_ru_state = RU_IDLE;
m_scp_address = SCP_ADDRESS;
-}
+ m_mac_multi = 0;
-void i82586_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch (id)
- {
- case CU_TIMER:
- cu_execute();
- break;
- }
+ set_irq(false);
}
device_memory_interface::space_config_vector i82586_base_device::memory_space_config() const
@@ -220,7 +213,7 @@ device_memory_interface::space_config_vector i82586_base_device::memory_space_co
};
}
-WRITE_LINE_MEMBER(i82586_base_device::ca)
+void i82586_base_device::ca(int state)
{
LOG("channel attention %s (%s)\n", state ? "asserted" : "cleared", machine().describe_context());
@@ -234,7 +227,7 @@ WRITE_LINE_MEMBER(i82586_base_device::ca)
}
}
-WRITE_LINE_MEMBER(i82586_base_device::reset_w)
+void i82586_base_device::reset_w(int state)
{
LOG("reset %s (%s)\n", state ? "asserted" : "cleared", machine().describe_context());
@@ -336,12 +329,12 @@ void i82586_base_device::process_scb()
case CUC_RESUME:
m_cu_state = CU_ACTIVE;
- m_cu_timer->enable(true);
+ m_cu_timer->adjust(attotime::zero);
break;
case CUC_SUSPEND:
m_cu_state = CU_SUSPENDED;
- m_cu_timer->enable(false);
+ m_cu_timer->reset();
m_cna = true;
break;
@@ -406,7 +399,7 @@ void i82586_base_device::update_scb()
set_irq(m_cx || m_fr || m_cna || m_rnr);
}
-void i82586_base_device::cu_execute()
+TIMER_CALLBACK_MEMBER(i82586_base_device::cu_execute)
{
// fetch the command block command/status
const u32 cb_cs = m_space->read_dword(m_cba);
@@ -500,7 +493,7 @@ void i82586_base_device::cu_complete(const u16 status)
if (cb_cs & CB_S)
{
m_cu_state = CU_SUSPENDED;
- m_cu_timer->enable(false);
+ m_cu_timer->reset();
m_cna = true;
}
@@ -540,7 +533,7 @@ bool i82586_base_device::address_filter(u8 *mac)
}
// individual address
- if (!memcmp(mac, get_mac(), cfg_address_length()))
+ if (!memcmp(mac, &get_mac()[0], cfg_address_length()))
{
LOGMASKED(LOG_FILTER, "address_filter accepted: individual address match\n");
@@ -566,9 +559,16 @@ void i82586_base_device::set_irq(bool irq)
{
LOG("irq asserted\n");
+ // ensure an edge is generated if interrupt already asserted
+ if (m_irq)
+ m_out_irq(!m_irq_assert);
+
m_out_irq(m_irq_assert);
- m_out_irq(!m_irq_assert);
}
+ else if (m_irq)
+ m_out_irq(!m_irq_assert);
+
+ m_irq = irq;
}
u32 i82586_base_device::compute_crc(u8 *buf, int length, bool crc16)
@@ -582,7 +582,7 @@ u64 i82586_base_device::address_hash(u8 *buf, int length)
// address hash is computed using bits 2-7 from crc of address
u32 crc = compute_crc(buf, length, false);
- return 1U << ((crc >> 2) & 0x3f);
+ return u64(1) << ((crc >> 2) & 0x3f);
}
int i82586_base_device::fetch_bytes(u8 *buf, u32 src, int length)
@@ -821,7 +821,7 @@ void i82586_device::initialise()
bool i82586_device::cu_iasetup()
{
int len = cfg_address_length();
- char mac[6];
+ u8 mac[6];
u32 data;
if (len != 6)
@@ -832,14 +832,10 @@ bool i82586_device::cu_iasetup()
}
data = m_space->read_dword(m_cba + 4);
- mac[0] = (data >> 16) & 0xff;
- mac[1] = (data >> 24) & 0xff;
+ put_u16le(&mac[0], data >> 16);
data = m_space->read_dword(m_cba + 8);
- mac[2] = (data >> 0) & 0xff;
- mac[3] = (data >> 8) & 0xff;
- mac[4] = (data >> 16) & 0xff;
- mac[5] = (data >> 24) & 0xff;
+ put_u32le(&mac[2], data);
LOG("cu_iasetup individual address %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
set_mac(mac);
@@ -893,35 +889,49 @@ bool i82586_device::cu_configure()
bool i82586_device::cu_mcsetup()
{
- int addr_len = cfg_address_length();
- u16 mc_count;
- u8 data[6];
+ // read the address list length
+ int mc_count = m_space->read_word(m_cba + 6, TB_COUNT);
+
+ // reset current list
+ m_mac_multi = 0;
- if (addr_len != 6)
+ if (mc_count < cfg_address_length())
{
- LOG("cu_mcsetup unexpected address length %d != 6\n", addr_len);
- return false;
- }
+ LOG("cu_mcsetup multicast filter disabled\n");
- // read the address count
- mc_count = m_space->read_word(m_cba + 6, TB_COUNT);
+ return true;
+ }
+ else
+ LOG("cu_mcsetup configuring %d addresses\n", mc_count / cfg_address_length());
- // reset current list
- LOG("mc_setup configuring %d addresses\n", mc_count);
- m_mac_multi = 0;
+ std::vector<u8> buf;
+ offs_t offset = m_cba + 8;
// read and process the addresses
- for (int i = 0; i < mc_count; i++)
+ while (mc_count >= cfg_address_length())
{
- *(u16 *)&data[0] = m_space->read_word(m_cba + 8 + i * 6 + 0);
- *(u16 *)&data[1] = m_space->read_word(m_cba + 8 + i * 6 + 2);
- *(u16 *)&data[2] = m_space->read_word(m_cba + 8 + i * 6 + 4);
+ // read an address
+ while (buf.size() < cfg_address_length())
+ {
+ u16 const data = m_space->read_word(offset);
+
+ buf.push_back(data >> 0);
+ buf.push_back(data >> 8);
+
+ offset += 2;
+ }
// add a hash of this address to the table
- m_mac_multi |= address_hash(data, cfg_address_length());
+ m_mac_multi |= address_hash(buf.data(), cfg_address_length());
- LOG("mc_setup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n",
- data[0], data[1], data[2], data[3], data[4], data[5]);
+ if (cfg_address_length() == 6)
+ LOG("cu_mcsetup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+ // remove used address bytes from the buffer
+ buf.erase(buf.begin(), buf.begin() + cfg_address_length());
+
+ mc_count -= cfg_address_length();
}
return true;
@@ -940,19 +950,17 @@ bool i82586_device::cu_transmit(u32 command)
// optionally insert source, destination address and length (14 bytes)
if (!cfg_no_src_add_ins())
{
- const char *mac = get_mac();
+ const std::array<u8, 6> &mac = get_mac();
u32 data;
// insert destination address (6 bytes)
data = m_space->read_dword(m_cba + 8);
- buf[length++] = (data >> 0) & 0xff;
- buf[length++] = (data >> 8) & 0xff;
- buf[length++] = (data >> 16) & 0xff;
- buf[length++] = (data >> 24) & 0xff;
+ put_u32le(&buf[length], data);
+ length += 4;
data = m_space->read_dword(m_cba + 12);
- buf[length++] = (data >> 0) & 0xff;
- buf[length++] = (data >> 8) & 0xff;
+ put_u16le(&buf[length], data & 0xffff);
+ length += 2;
// insert source address (6 bytes)
LOG("cu_transmit inserting source address %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
@@ -961,8 +969,8 @@ bool i82586_device::cu_transmit(u32 command)
// insert length (2 bytes)
LOG("cu_transmit frame length 0x%04x\n", ((data >> 24) & 0xff) | ((data >> 16) & 0xff00));
- buf[length++] = (data >> 16) & 0xff;
- buf[length++] = (data >> 24) & 0xff;
+ put_u16le(&buf[length], data >> 16);
+ length += 2;
}
// check if there is no tbd
@@ -986,17 +994,15 @@ bool i82586_device::cu_transmit(u32 command)
}
// optionally compute/insert ethernet frame check sequence (4 bytes)
- if (!cfg_no_crc_insertion() && !cfg_loopback_mode())
+ if (!cfg_no_crc_insertion())
{
LOG("cu_transmit inserting frame check sequence\n");
u32 crc = compute_crc(buf, length, cfg_crc16());
// insert the fcs
- buf[length++] = (crc >> 0) & 0xff;
- buf[length++] = (crc >> 8) & 0xff;
- buf[length++] = (crc >> 16) & 0xff;
- buf[length++] = (crc >> 24) & 0xff;
+ put_u32le(&buf[length], crc);
+ length += 4;
}
if (cfg_loopback_mode())
@@ -1016,7 +1022,7 @@ bool i82586_device::cu_transmit(u32 command)
LOG("cu_transmit sending frame length %d\n", length);
dump_bytes(buf, length);
- return send(buf, length) == length;
+ return send(buf, length, 4) == length;
}
}
@@ -1048,7 +1054,7 @@ bool i82586_device::cu_dump()
memcpy(&buf[0x00], &m_cfg_bytes[0], CFG_SIZE);
// individual address
- memcpy(&buf[0x0c], get_mac(), 6);
+ memcpy(&buf[0x0c], &get_mac()[0], 6);
// hash register
*(u64 *)&buf[0x24] = m_mac_multi;
@@ -1078,8 +1084,8 @@ u16 i82586_device::ru_execute(u8 *buf, int length)
u32 rfd_cs = m_space->read_dword(m_rfd);
u16 status = 0;
- // current buffer position and bytes remaining
- int position = 0, remaining = length;
+ // current buffer position and bytes remaining (excluding fcs)
+ int position = 0, remaining = length - 4;
// set busy status
m_space->write_dword(m_rfd, rfd_cs | RFD_B);
@@ -1091,7 +1097,7 @@ u16 i82586_device::ru_execute(u8 *buf, int length)
status |= RFD_S_SHORT;
// set crc status
- if (!cfg_loopback_mode() && ~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE)
+ if (~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE)
{
LOGMASKED(LOG_FRAMES, "ru_execute crc error computed 0x%08x stored 0x%08x\n",
compute_crc(buf, length - 4, cfg_crc16()), *(u32 *)&buf[length - 4]);
@@ -1173,18 +1179,18 @@ u16 i82586_device::ru_execute(u8 *buf, int length)
void i82586_device::ru_complete(const u16 status)
{
- if (status & RFD_OK)
- LOG("ru_complete frame received without error\n");
- else
- LOG("ru_complete frame received with errors status 0x%04x\n", status);
-
- // update receive frame descriptor status
- u32 rfd_cs = m_space->read_dword(m_rfd);
- m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status);
-
// if we received without error, or we're saving bad frames, advance to the next rfd
if ((status & RFD_OK) || cfg_save_bad_frames())
{
+ if (status & RFD_OK)
+ LOG("ru_complete frame received without error\n");
+ else
+ LOG("ru_complete frame received with errors status 0x%04x\n", status);
+
+ // update receive frame descriptor status
+ u32 rfd_cs = m_space->read_dword(m_rfd);
+ m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status);
+
if (!(rfd_cs & RFD_EL))
{
// advance to next rfd
@@ -1202,17 +1208,19 @@ void i82586_device::ru_complete(const u16 status)
// set frame received status
m_fr = true;
- }
- // suspend on completion
- if (rfd_cs & RFD_S)
- {
- m_ru_state = RU_SUSPENDED;
- m_rnr = true;
- }
+ // suspend on completion
+ if (rfd_cs & RFD_S)
+ {
+ m_ru_state = RU_SUSPENDED;
+ m_rnr = true;
+ }
- static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY" };
- LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]);
+ static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY" };
+ LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]);
+ }
+ else
+ LOG("ru_complete discarded frame with errors status 0x%04x\n", status);
}
u32 i82586_device::address(u32 base, int offset, int address, u16 empty)
@@ -1329,7 +1337,7 @@ bool i82596_device::cu_iasetup()
{
int len = cfg_address_length();
u32 data;
- char mac[6];
+ u8 mac[6];
if (len != 6)
{
@@ -1343,26 +1351,18 @@ bool i82596_device::cu_iasetup()
case MODE_82586:
case MODE_32SEGMENTED:
data = m_space->read_dword(m_cba + 4);
- mac[0] = (data >> 16) & 0xff;
- mac[1] = (data >> 24) & 0xff;
+ put_u16le(&mac[0], data >> 16);
data = m_space->read_dword(m_cba + 8);
- mac[2] = (data >> 0) & 0xff;
- mac[3] = (data >> 8) & 0xff;
- mac[4] = (data >> 16) & 0xff;
- mac[5] = (data >> 24) & 0xff;
+ put_u32le(&mac[2], data);
break;
case MODE_LINEAR:
data = m_space->read_dword(m_cba + 8);
- mac[0] = (data >> 0) & 0xff;
- mac[1] = (data >> 8) & 0xff;
- mac[2] = (data >> 16) & 0xff;
- mac[3] = (data >> 24) & 0xff;
+ put_u32le(&mac[0], data);
data = m_space->read_dword(m_cba + 12);
- mac[4] = (data >> 0) & 0xff;
- mac[5] = (data >> 8) & 0xff;
+ put_u16le(&mac[4], data & 0xffff);
break;
}
@@ -1483,68 +1483,65 @@ bool i82596_device::cu_configure()
bool i82596_device::cu_mcsetup()
{
- int addr_len = cfg_address_length();
- u16 mc_count = 0;
-
- int offset = 0;
- u8 data[20];
- bool multi_ia;
-
- if (addr_len != 6)
- {
- LOG("cu_mcsetup unexpected address length %d != 6\n", addr_len);
- return false;
- }
+ u32 data = (mode() == MODE_LINEAR) ? m_space->read_dword(m_cba + 8) : m_space->read_word(m_cba + 6);
+ int mc_count = data & TB_COUNT;
- switch (mode())
+ // if length less than one address, clear multicast filter and finish
+ if (mc_count < cfg_address_length())
{
- case MODE_82586:
- case MODE_32SEGMENTED:
- mc_count = m_space->read_word(m_cba + 6, TB_COUNT);
- break;
+ LOG("cu_mcsetup multicast filter disabled\n");
+ m_mac_multi = 0;
- case MODE_LINEAR:
- mc_count = m_space->read_word(m_cba + 8, TB_COUNT);
- offset = 2;
- break;
+ return true;
}
- // if count is zero, release multicast list and finish
- if (mc_count == 0)
+ std::vector<u8> buf;
+ offs_t offset = m_cba + 8;
+
+ // already have the first two address bytes in linear mode
+ if (mode() != MODE_LINEAR)
{
- LOG("mc_setup multicast filter disabled\n");
- m_mac_multi = 0;
+ data = m_space->read_dword(offset);
- return true;
+ buf.push_back(data >> 0);
+ buf.push_back(data >> 8);
}
-
- // fetch the first word
- *(u32 *)&data[0] = m_space->read_dword(m_cba + 8);
+ buf.push_back(data >> 16);
+ buf.push_back(data >> 24);
+ offset += 4;
// multi ia when configured and lsb of first address is clear
- multi_ia = cfg_multi_ia() && !BIT(data[offset], 0);
+ bool const multi_ia = cfg_multi_ia() && !BIT(buf[0], 0);
- // clear existing list
- LOG("mc_setup configuring %d %s addresses\n", mc_count, multi_ia ? "multi-ia" : "multicast");
+ LOG("cu_mcsetup configuring %d %s addresses\n", mc_count / cfg_address_length(), multi_ia ? "multi-ia" : "multicast");
(multi_ia ? m_mac_multi_ia : m_mac_multi) = 0;
- for (int i = 0; i < mc_count; i++)
+ while (mc_count >= cfg_address_length())
{
- // compute offset of address in 18 byte buffer
- int n = (i % 3) * 6;
+ // read an address
+ while (buf.size() < cfg_address_length())
+ {
+ data = m_space->read_dword(offset);
- // read the next dword
- *(u32 *)&data[n + 6] = m_space->read_dword(m_cba + 8 + i * 4 + 4);
+ buf.push_back(data >> 0);
+ buf.push_back(data >> 8);
+ buf.push_back(data >> 16);
+ buf.push_back(data >> 24);
- // unaligned case needs special handling
- if (n == 12 && offset == 2)
- *(u16 *)&data[18] = *(u16 *)&data[0];
+ offset += 4;
+ }
// add a hash of this address to the table
- (multi_ia ? m_mac_multi_ia : m_mac_multi) |= address_hash(&data[n + offset], cfg_address_length());
+ (multi_ia ? m_mac_multi_ia : m_mac_multi) |= address_hash(buf.data(), cfg_address_length());
- LOG("mc_setup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n",
- data[n + offset + 0], data[n + offset + 1], data[n + offset + 2], data[n + offset + 3], data[n + offset + 4], data[n + offset + 5]);
+ if (cfg_address_length() == 6)
+ LOG("cu_mcsetup inserting address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+ // remove used address bytes from the buffer
+ buf.erase(buf.begin(), buf.begin() + cfg_address_length());
+
+ mc_count -= cfg_address_length();
}
return true;
@@ -1587,19 +1584,17 @@ bool i82596_device::cu_transmit(u32 command)
// optionally insert destination, source and length (14 bytes)
if (!cfg_no_src_add_ins())
{
- const char *mac = get_mac();
+ const std::array<u8, 6> &mac = get_mac();
u32 data;
// insert destination address (6 bytes)
data = m_space->read_dword(m_cba + 12 + offset);
- buf[length++] = (data >> 0) & 0xff;
- buf[length++] = (data >> 8) & 0xff;
- buf[length++] = (data >> 16) & 0xff;
- buf[length++] = (data >> 24) & 0xff;
+ put_u32le(&buf[length], data);
+ length += 4;
data = m_space->read_dword(m_cba + 16 + offset);
- buf[length++] = (data >> 0) & 0xff;
- buf[length++] = (data >> 8) & 0xff;
+ put_u16le(&buf[length], data & 0xffff);
+ length += 2;
// insert source address (6 bytes)
LOG("cu_transmit inserting source address %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
@@ -1608,8 +1603,8 @@ bool i82596_device::cu_transmit(u32 command)
// insert length from tcb (2 bytes)
LOG("cu_transmit frame length 0x%04x\n", ((data >> 24) & 0xff) | ((data >> 16) & 0xff00));
- buf[length++] = (data >> 16) & 0xff;
- buf[length++] = (data >> 24) & 0xff;
+ put_u16le(&buf[length], data >> 16);
+ length += 2;
// insert payload from tcb
LOG("cu_transmit inserting %d bytes from transmit command block\n", (tcb_count & TB_COUNT) - 8);
@@ -1666,10 +1661,8 @@ bool i82596_device::cu_transmit(u32 command)
u32 crc = compute_crc(buf, length, cfg_crc16());
// append the fcs
- buf[length++] = (crc >> 0) & 0xff;
- buf[length++] = (crc >> 8) & 0xff;
- buf[length++] = (crc >> 16) & 0xff;
- buf[length++] = (crc >> 24) & 0xff;
+ put_u32le(&buf[length], crc);
+ length += 4;
}
if (cfg_loopback_mode())
@@ -1726,7 +1719,7 @@ bool i82596_device::cu_dump()
memcpy(&buf[0x02], &m_cfg_bytes[2], 9);
// individual address
- memcpy(&buf[0x0c], get_mac(), 6);
+ memcpy(&buf[0x0c], &get_mac()[0], 6);
// hash register
*(u64 *)&buf[0x24] = m_mac_multi;
@@ -1737,7 +1730,7 @@ bool i82596_device::cu_dump()
memcpy(&buf[0x00], &m_cfg_bytes[2], 12);
// individual address
- memcpy(&buf[0x0e], get_mac(), 6);
+ memcpy(&buf[0x0e], &get_mac()[0], 6);
// hash register
*(u64 *)&buf[0x26] = m_mac_multi;
@@ -1816,7 +1809,7 @@ u16 i82596_device::ru_execute(u8 *buf, int length)
}
// set crc status
- if (!cfg_loopback_mode() && ~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE)
+ if (~compute_crc(buf, length, cfg_crc16()) != FCS_RESIDUE)
{
LOGMASKED(LOG_FRAMES, "ru_execute crc error computed 0x%08x stored 0x%08x\n",
compute_crc(buf, length - 4, cfg_crc16()), *(u32 *)&buf[length - 4]);
@@ -1834,7 +1827,7 @@ u16 i82596_device::ru_execute(u8 *buf, int length)
// TODO: increment alignment error counter
// set multicast status
- if (mode() != MODE_82586 && memcmp(buf, get_mac(), cfg_address_length()))
+ if (mode() != MODE_82586 && memcmp(buf, &get_mac()[0], cfg_address_length()))
status |= RFD_S_MULTICAST;
// fetch initial rbd address from rfd
@@ -1959,18 +1952,18 @@ u16 i82596_device::ru_execute(u8 *buf, int length)
void i82596_device::ru_complete(const u16 status)
{
- if (status & RFD_OK)
- LOG("ru_complete frame received without error\n");
- else
- LOG("ru_complete frame received with errors status 0x%04x\n", status);
-
- // store status
- const u32 rfd_cs = m_space->read_dword(m_rfd);
- m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status);
-
// if we received without error, or we're saving bad frames, advance to the next rfd
- if ((rfd_cs & RFD_OK) || cfg_save_bad_frames())
+ if ((status & RFD_OK) || cfg_save_bad_frames())
{
+ if (status & RFD_OK)
+ LOG("ru_complete frame received without error\n");
+ else
+ LOG("ru_complete frame received with errors status 0x%04x\n", status);
+
+ // update receive frame descriptor status
+ const u32 rfd_cs = m_space->read_dword(m_rfd);
+ m_space->write_dword(m_rfd, (rfd_cs & ~0xffffU) | status);
+
if (!(rfd_cs & RFD_EL))
{
// advance to next rfd
@@ -1993,17 +1986,19 @@ void i82596_device::ru_complete(const u16 status)
// set frame received status
m_fr = true;
- }
- // suspend on completion
- if (rfd_cs & RFD_S)
- {
- m_ru_state = RU_SUSPENDED;
- m_rnr = true;
- }
+ // suspend on completion
+ if (rfd_cs & RFD_S)
+ {
+ m_ru_state = RU_SUSPENDED;
+ m_rnr = true;
+ }
- static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY", nullptr, nullptr, nullptr, nullptr, nullptr, "NO RESOURCES (RFD)", nullptr, "NO RESOURCES (RBD)" };
- LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]);
+ static const char *const RU_STATE_NAME[] = { "IDLE", "SUSPENDED", "NO RESOURCES", nullptr, "READY", nullptr, nullptr, nullptr, nullptr, nullptr, "NO RESOURCES (RFD)", nullptr, "NO RESOURCES (RBD)" };
+ LOG("ru_complete complete state %s\n", RU_STATE_NAME[m_ru_state]);
+ }
+ else
+ LOG("ru_complete discarded frame with errors status 0x%04x\n", status);
}
u32 i82596_device::address(u32 base, int offset, int address, u16 empty)
diff --git a/src/devices/machine/i82586.h b/src/devices/machine/i82586.h
index ad02c0bfece..9fce2c70b6d 100644
--- a/src/devices/machine/i82586.h
+++ b/src/devices/machine/i82586.h
@@ -6,6 +6,8 @@
#pragma once
+#include "dinetwork.h"
+
class i82586_base_device :
public device_t,
public device_memory_interface,
@@ -157,8 +159,8 @@ public:
// callback configuration
auto out_irq_cb() { return m_out_irq.bind(); }
- DECLARE_WRITE_LINE_MEMBER(ca);
- DECLARE_WRITE_LINE_MEMBER(reset_w);
+ void ca(int state);
+ void reset_w(int state);
protected:
i82586_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endian, u8 datawidth, u8 addrwidth);
@@ -167,7 +169,6 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual space_config_vector memory_space_config() const override;
// device_network_interface overrides
@@ -181,7 +182,7 @@ protected:
virtual void update_scb();
// command unit
- virtual void cu_execute();
+ virtual TIMER_CALLBACK_MEMBER(cu_execute);
virtual void cu_complete(const u16 status);
virtual bool cu_iasetup() = 0;
virtual bool cu_configure() = 0;
@@ -211,7 +212,6 @@ protected:
address_space *m_space;
devcb_write_line m_out_irq;
- static const device_timer_id CU_TIMER = 0;
emu_timer *m_cu_timer;
// interrupt state
@@ -221,6 +221,7 @@ protected:
bool m_rnr; // receive unit became not ready
bool m_initialised;
bool m_reset;
+ bool m_irq;
int m_irq_assert; // configurable interrupt polarity
// receive/command unit state
diff --git a/src/devices/machine/i8271.cpp b/src/devices/machine/i8271.cpp
index 529a21b9b5d..420a0dcea9f 100644
--- a/src/devices/machine/i8271.cpp
+++ b/src/devices/machine/i8271.cpp
@@ -4,6 +4,9 @@
#include "emu.h"
#include "i8271.h"
+#define VERBOSE 0
+#include "logmacro.h"
+
DEFINE_DEVICE_TYPE(I8271, i8271_device, "i8271", "Intel 8271 FDC")
i8271_device::i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
@@ -37,14 +40,9 @@ void i8271_device::set_select_lines_connected(bool _select)
void i8271_device::device_start()
{
- intrq_cb.resolve_safe();
- drq_cb.resolve_safe();
- hdl_cb.resolve_safe();
- opt_cb.resolve_safe();
-
for(int i=0; i != 2; i++) {
char name[2];
- flopi[i].tm = timer_alloc(i);
+ flopi[i].tm = timer_alloc(FUNC(i8271_device::floppy_tick), this);
flopi[i].id = i;
if(select_connected) {
name[0] = '0'+i;
@@ -131,7 +129,7 @@ void i8271_device::set_floppies(floppy_connector *f0, floppy_connector *f1)
flopi[0].dev = nullptr;
if (f1) {
- flopi[1].dev = f0->get_device();
+ flopi[1].dev = f1->get_device();
if (flopi[1].dev != nullptr)
flopi[1].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&i8271_device::index_callback, this));
}
@@ -313,7 +311,7 @@ void i8271_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());
+ cur_live.fi->tm->adjust(cur_live.tm - machine().time(), cur_live.fi->id);
else
live_sync();
}
@@ -377,7 +375,7 @@ void i8271_device::live_run(attotime limit)
// infinity looking for data too.
limit = machine().time() + attotime::from_msec(1);
- cur_live.fi->tm->adjust(attotime::from_msec(1));
+ cur_live.fi->tm->adjust(attotime::from_msec(1), cur_live.fi->id);
}
}
@@ -386,18 +384,16 @@ void i8271_device::live_run(attotime limit)
case SEARCH_ADDRESS_MARK_HEADER:
if(read_one_bit(limit))
return;
-#if 0
- fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
- (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
- (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
- (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
- (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
- (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
- (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
- (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
- (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
- cur_live.bit_counter);
-#endif
+ LOG("%s: shift = %04x data=%02x c=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
+ (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
+ (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
+ (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
+ (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
+ (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
+ (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
+ (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ cur_live.bit_counter);
if(cur_live.shift_reg == 0xf57e) {
cur_live.crc = 0xef21;
@@ -414,8 +410,7 @@ void i8271_device::live_run(attotime limit)
break;
int slot = (cur_live.bit_counter >> 4)-1;
- if(0)
- fprintf(stderr, "%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm).c_str(), slot, cur_live.data_reg, cur_live.crc);
+ LOG("%s: slot=%d data=%02x crc=%04x\n", cur_live.tm.to_string(), slot, cur_live.data_reg, cur_live.crc);
cur_live.idbuf[slot] = cur_live.data_reg;
if(cur_live.fi->main_state == READ_ID) {
if(!set_output(cur_live.data_reg)) {
@@ -433,18 +428,16 @@ void i8271_device::live_run(attotime limit)
case SEARCH_ADDRESS_MARK_DATA:
if(read_one_bit(limit))
return;
-#if 0
- fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
- (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
- (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
- (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
- (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
- (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
- (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
- (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
- (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
- cur_live.bit_counter >> 4, cur_live.bit_counter & 15);
-#endif
+ LOG("%s: shift = %04x data=%02x c=%d.%x\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
+ (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
+ (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
+ (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
+ (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
+ (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
+ (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
+ (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ cur_live.bit_counter >> 4, cur_live.bit_counter & 15);
if(cur_live.bit_counter > 23*16) {
live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED);
@@ -686,7 +679,7 @@ void i8271_device::live_run(attotime limit)
break;
default:
- logerror("%s: Unknown live state %d\n", tts(cur_live.tm).c_str(), cur_live.state);
+ logerror("%s: Unknown live state %d\n", cur_live.tm.to_string(), cur_live.state);
return;
}
}
@@ -914,8 +907,8 @@ void i8271_device::start_command(int cmd)
break;
default:
- fprintf(stderr, "start command %d\n", cmd);
- exit(1);
+ logerror("start command %d\n", cmd);
+ break;
}
}
@@ -947,9 +940,9 @@ void i8271_device::seek_start(floppy_info &fi)
seek_continue(fi);
}
-void i8271_device::delay_cycles(emu_timer *tm, int cycles)
+void i8271_device::delay_cycles(floppy_info &fi, int cycles)
{
- tm->adjust(attotime::from_double(double(cycles)/cur_rate));
+ fi.tm->adjust(attotime::from_double(double(cycles)/cur_rate), fi.id);
}
void i8271_device::seek_continue(floppy_info &fi)
@@ -962,7 +955,7 @@ void i8271_device::seek_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -979,7 +972,7 @@ void i8271_device::seek_continue(floppy_info &fi)
fi.pcn++;
} while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*srate);
+ delay_cycles(fi, 500*srate);
return;
case SEEK_WAIT_STEP_TIME:
@@ -1117,7 +1110,7 @@ void i8271_device::read_data_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -1128,7 +1121,7 @@ void i8271_device::read_data_continue(floppy_info &fi)
fi.dev->stp_w(1);
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*srate);
+ delay_cycles(fi, 500*srate);
return;
case SEEK_WAIT_STEP_TIME:
@@ -1209,7 +1202,7 @@ void i8271_device::read_data_continue(floppy_info &fi)
return;
default:
- logerror("%s: read sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ logerror("%s: read sector unknown sub-state %d\n", ttsn(), fi.sub_state);
return;
}
}
@@ -1258,7 +1251,7 @@ void i8271_device::write_data_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -1269,7 +1262,7 @@ void i8271_device::write_data_continue(floppy_info &fi)
fi.dev->stp_w(1);
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*srate);
+ delay_cycles(fi, 500*srate);
return;
case SEEK_WAIT_STEP_TIME:
@@ -1336,7 +1329,7 @@ void i8271_device::write_data_continue(floppy_info &fi)
return;
default:
- logerror("%s: write sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ logerror("%s: write sector unknown sub-state %d\n", ttsn(), fi.sub_state);
return;
}
}
@@ -1385,7 +1378,7 @@ void i8271_device::format_track_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -1396,7 +1389,7 @@ void i8271_device::format_track_continue(floppy_info &fi)
fi.dev->stp_w(1);
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*srate);
+ delay_cycles(fi, 500*srate);
return;
case SEEK_WAIT_STEP_TIME:
@@ -1433,7 +1426,7 @@ void i8271_device::format_track_continue(floppy_info &fi)
return;
default:
- logerror("%s: format track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ logerror("%s: format track unknown sub-state %d\n", ttsn(), fi.sub_state);
return;
}
}
@@ -1478,7 +1471,7 @@ void i8271_device::read_id_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -1489,7 +1482,7 @@ void i8271_device::read_id_continue(floppy_info &fi)
fi.dev->stp_w(1);
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*srate);
+ delay_cycles(fi, 500*srate);
return;
case SEEK_WAIT_STEP_TIME:
@@ -1537,35 +1530,22 @@ void i8271_device::read_id_continue(floppy_info &fi)
return;
default:
- logerror("%s: read id unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ logerror("%s: read id unknown sub-state %d\n", ttsn(), fi.sub_state);
return;
}
}
}
-std::string i8271_device::tts(attotime t)
-{
- char buf[256];
- const char *sign = "";
- if(t.seconds() < 0) {
- t = attotime::zero-t;
- sign = "-";
- }
- int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- sprintf(buf, "%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
- return buf;
-}
-
-std::string i8271_device::ttsn()
+std::string i8271_device::ttsn() const
{
- return tts(machine().time());
+ return machine().time().to_string();
}
-void i8271_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(i8271_device::floppy_tick)
{
live_sync();
- floppy_info &fi = flopi[id];
+ floppy_info &fi = flopi[param];
switch(fi.sub_state) {
case SEEK_WAIT_STEP_SIGNAL_TIME:
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE;
@@ -1629,7 +1609,7 @@ void i8271_device::index_callback(floppy_image_device *floppy, int state)
break;
default:
- logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ logerror("%s: Index pulse on unknown sub-state %d\n", ttsn(), fi.sub_state);
break;
}
@@ -1674,7 +1654,7 @@ void i8271_device::general_continue(floppy_info &fi)
break;
default:
- logerror("%s: general_continue on unknown main-state %d\n", ttsn().c_str(), fi.main_state);
+ logerror("%s: general_continue on unknown main-state %d\n", ttsn(), fi.main_state);
break;
}
}
diff --git a/src/devices/machine/i8271.h b/src/devices/machine/i8271.h
index 9d02f2497d3..92880af57d4 100644
--- a/src/devices/machine/i8271.h
+++ b/src/devices/machine/i8271.h
@@ -44,7 +44,8 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(floppy_tick);
private:
enum {
@@ -206,8 +207,7 @@ private:
int cur_rate;
int idle_icnt;
- static std::string tts(attotime t);
- std::string ttsn();
+ std::string ttsn() const;
enum {
C_FORMAT_TRACK,
@@ -235,7 +235,7 @@ private:
void cmd_w(uint8_t data);
void param_w(uint8_t data);
- void delay_cycles(emu_timer *tm, int cycles);
+ void delay_cycles(floppy_info &fi, int cycles);
void set_drq(bool state);
void set_irq(bool state);
bool get_ready(int fid);
diff --git a/src/devices/machine/i8279.cpp b/src/devices/machine/i8279.cpp
index 5c186997cd0..16e7c5e64bc 100644
--- a/src/devices/machine/i8279.cpp
+++ b/src/devices/machine/i8279.cpp
@@ -99,9 +99,9 @@ i8279_device::i8279_device(const machine_config &mconfig, const char *tag, devic
m_out_sl_cb(*this),
m_out_disp_cb(*this),
m_out_bd_cb(*this),
- m_in_rl_cb(*this),
- m_in_shift_cb(*this),
- m_in_ctrl_cb(*this)
+ m_in_rl_cb(*this, 0xff),
+ m_in_shift_cb(*this, 1),
+ m_in_ctrl_cb(*this, 1)
{
}
@@ -111,16 +111,8 @@ i8279_device::i8279_device(const machine_config &mconfig, const char *tag, devic
void i8279_device::device_start()
{
- /* resolve callbacks */
- m_out_irq_cb.resolve();
- m_out_sl_cb.resolve();
- m_out_disp_cb.resolve();
- m_out_bd_cb.resolve();
- m_in_rl_cb.resolve();
- m_in_shift_cb.resolve();
- m_in_ctrl_cb.resolve();
m_scanclock = clock();
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i8279_device::timerproc_callback), this));
+ m_timer = timer_alloc(FUNC(i8279_device::timerproc_callback), this);
// save state
save_item(NAME(m_d_ram));
@@ -208,18 +200,11 @@ void i8279_device::clear_display()
m_status &= 0x80; // blow away fifo
m_s_ram_ptr = 0; // reset sensor pointer
m_debounce = 0; // reset debounce logic
- set_irq(0); // reset irq
+ m_out_irq_cb(0); // reset irq
}
}
-void i8279_device::set_irq(bool state)
-{
- if ( !m_out_irq_cb.isnull() )
- m_out_irq_cb( state );
-}
-
-
void i8279_device::new_fifo(u8 data)
{
// see if already overrun
@@ -249,7 +234,7 @@ void i8279_device::new_fifo(u8 data)
m_status = (m_status & 0xe8) + fifo_size + 1;
if (!fifo_size)
- set_irq(1); // something just went into fifo, so int
+ m_out_irq_cb(1); // something just went into fifo, so int
}
@@ -270,8 +255,6 @@ void i8279_device::timer_mainloop()
u8 scanner_mask = BIT(m_cmd[0], 0) ? 3 : BIT(m_cmd[0], 3) ? 15 : 7;
bool decoded = BIT(m_cmd[0], 0);
u8 kbd_type = (m_cmd[0] & 6) >> 1;
- bool shift_key = 1;
- bool ctrl_key = 1;
bool strobe_pulse = 0;
// keyboard
@@ -281,12 +264,8 @@ void i8279_device::timer_mainloop()
// type 3 = strobed
// Get shift keys
- if ( !m_in_shift_cb.isnull() )
- shift_key = m_in_shift_cb();
-
- if ( !m_in_ctrl_cb.isnull() )
- ctrl_key = m_in_ctrl_cb();
-
+ bool shift_key = m_in_shift_cb();
+ bool ctrl_key = m_in_ctrl_cb();
if (ctrl_key && !m_ctrl_key)
strobe_pulse = 1; // low-to-high is a strobe
@@ -294,11 +273,11 @@ void i8279_device::timer_mainloop()
// Read a row of keys
- if ( !m_in_rl_cb.isnull() )
+ if ( !m_in_rl_cb.isunset() )
{
u8 rl = m_in_rl_cb(0) ^ 0xff; // inverted
u8 addr = m_scanner & 7;
- assert(addr < ARRAY_LENGTH(m_s_ram));
+ assert(addr < std::size(m_s_ram));
// see if key still down from last time
u8 keys_down = rl & ~m_s_ram[addr];
@@ -354,7 +333,7 @@ void i8279_device::timer_mainloop()
if (m_se_mode && !BIT(m_status, 6))
{
m_status |= 0x40;
- set_irq(1);
+ m_out_irq_cb(1);
}
#endif // EMULATE_KEY_LOCKOUT
}
@@ -381,7 +360,7 @@ void i8279_device::timer_mainloop()
m_s_ram[addr] = rl;
// IRQ line goes high if a row changes value
- set_irq(1);
+ m_out_irq_cb(1);
}
break;
@@ -397,19 +376,15 @@ void i8279_device::timer_mainloop()
m_scanner = (m_scanner + 1) & (decoded ? 3 : 15);
- if ( !m_out_sl_cb.isnull() )
- {
- // Active low strobed output in decoded mode
- if (decoded)
- m_out_sl_cb((offs_t)0, (1 << m_scanner) ^ 15);
- else
- m_out_sl_cb((offs_t)0, m_scanner);
- }
+ // Active low strobed output in decoded mode
+ if (decoded)
+ m_out_sl_cb(offs_t(0), (1 << m_scanner) ^ 15);
+ else
+ m_out_sl_cb(offs_t(0), m_scanner);
// output a digit
- if ( !m_out_disp_cb.isnull() )
- m_out_disp_cb((offs_t)0, m_d_ram[m_scanner & scanner_mask] );
+ m_out_disp_cb(offs_t(0), m_d_ram[m_scanner & scanner_mask]);
}
@@ -444,7 +419,7 @@ u8 i8279_device::data_r()
if (sensor_mode)
{
// read sensor ram
- assert(m_s_ram_ptr < ARRAY_LENGTH(m_s_ram));
+ assert(m_s_ram_ptr < std::size(m_s_ram));
data = m_s_ram[m_s_ram_ptr];
if (!machine().side_effects_disabled())
{
@@ -454,7 +429,7 @@ u8 i8279_device::data_r()
}
else
{
- set_irq(0);
+ m_out_irq_cb(0);
}
}
}
@@ -476,7 +451,7 @@ u8 i8279_device::data_r()
m_fifo[i-1] = m_fifo[i];
fifo_size--;
if (!fifo_size)
- set_irq(0);
+ m_out_irq_cb(0);
}
break;
case 0x28: // overrun
@@ -551,7 +526,7 @@ void i8279_device::cmd_w(u8 data)
clear_display();
break;
case 7:
- set_irq(0);
+ m_out_irq_cb(0);
m_se_mode = BIT(data, 4);
m_status &= 0xbf;
break;
diff --git a/src/devices/machine/i8279.h b/src/devices/machine/i8279.h
index 56c111a2797..8be33fbb4d0 100644
--- a/src/devices/machine/i8279.h
+++ b/src/devices/machine/i8279.h
@@ -59,11 +59,9 @@ public:
void timer_mainloop();
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_post_load() override { }
- virtual void device_clock_changed() override { }
TIMER_CALLBACK_MEMBER( timerproc_callback );
@@ -71,7 +69,6 @@ private:
void timer_adjust();
void clear_display();
void new_fifo(u8 data);
- void set_irq(bool state);
devcb_write_line m_out_irq_cb; // IRQ
devcb_write8 m_out_sl_cb; // Scanlines SL0-3
diff --git a/src/devices/machine/i82875p.cpp b/src/devices/machine/i82875p.cpp
index 37d95112359..b187bacfa72 100644
--- a/src/devices/machine/i82875p.cpp
+++ b/src/devices/machine/i82875p.cpp
@@ -62,8 +62,7 @@ uint8_t i82875p_host_device::capptr_r()
void i82875p_host_device::device_start()
{
pci_host_device::device_start();
- memory_space = &cpu->space(AS_PROGRAM);
- io_space = &cpu->space(AS_IO);
+ set_spaces(&cpu->space(AS_PROGRAM), &cpu->space(AS_IO));
memory_window_start = 0;
memory_window_end = 0xffffffff;
diff --git a/src/devices/machine/i8291a.cpp b/src/devices/machine/i8291a.cpp
index 3692ba95a28..c2b396fe43b 100644
--- a/src/devices/machine/i8291a.cpp
+++ b/src/devices/machine/i8291a.cpp
@@ -38,73 +38,73 @@ ALLOW_SAVE_TYPE(i8291a_device::acceptor_handshake_state);
i8291a_device::i8291a_device(const machine_config &mconfig, const char *tag,
device_t *owner, uint32_t clock) :
- device_t{mconfig, I8291A, tag, owner, clock},
- m_int_write_func{*this},
- m_dreq_write_func{*this},
- m_trig_write_func{*this},
- m_eoi_write_func{*this},
- m_dav_write_func{*this},
- m_nrfd_write_func{*this},
- m_ndac_write_func{*this},
- m_srq_write_func{*this},
- m_dio_write_func{*this},
- m_dio_read_func{*this},
- m_din{0},
- m_dout{0},
- m_ints1{0},
- m_ints2{0},
- m_ie1{0},
- m_ie2{0},
- m_address0{0},
- m_address1{0},
- m_eos{0},
- m_spoll_mode{0},
- m_address_mode{0},
- m_address_status{0},
- m_cpt{0},
- m_auxa{0},
- m_auxb{0},
- m_atn{false},
- m_ren{false},
- m_nrfd{false},
- m_ndac{false},
- m_dav{false},
- m_srq{false},
- m_ifc{false},
- m_eoi{false},
- m_dio{0},
- m_nrfd_out{false},
- m_ndac_out{false},
- m_dav_out{false},
- m_srq_out{false},
- m_eoi_out{false},
- m_pon{false},
- m_rdy{false},
- m_lpe{false},
- m_ist{false},
- m_rtl{false},
- m_apt_flag{false},
- m_cpt_flag{false},
- m_din_flag{false},
- m_nba{false},
- m_pp_sense{false},
- m_pp_line{0},
- m_send_eoi{false},
- m_sh_state{source_handshake_state::SIDS},
- m_ah_state{acceptor_handshake_state::AIDS},
- m_t_state{talker_state::TIDS},
- m_tp_state{talker_primary_state::TPIS},
- m_tsp_state{talker_serial_poll_state::SPIS},
- m_l_state{listener_state::LIDS},
- m_lp_state{listener_primary_state::LPIS},
- m_rl_state{remote_local_state::LOCS},
- m_pp_state{parallel_poll_state::PPIS},
- m_dc_state{device_clear_state::DCIS},
- m_dt_state{device_trigger_state::DTIS},
- m_state_changed(false),
- m_ignore_ext_signals(false),
- m_intr_out(false),
- m_dreq_out(false)
+ device_t{mconfig, I8291A, tag, owner, clock},
+ m_int_write_func{*this},
+ m_dreq_write_func{*this},
+ m_trig_write_func{*this},
+ m_eoi_write_func{*this},
+ m_dav_write_func{*this},
+ m_nrfd_write_func{*this},
+ m_ndac_write_func{*this},
+ m_srq_write_func{*this},
+ m_dio_write_func{*this},
+ m_dio_read_func{*this, 0xff},
+ m_din{0},
+ m_dout{0},
+ m_ints1{0},
+ m_ints2{0},
+ m_ie1{0},
+ m_ie2{0},
+ m_address0{0},
+ m_address1{0},
+ m_eos{0},
+ m_spoll_mode{0},
+ m_address_mode{0},
+ m_address_status{0},
+ m_cpt{0},
+ m_auxa{0},
+ m_auxb{0},
+ m_atn{false},
+ m_ren{false},
+ m_nrfd{false},
+ m_ndac{false},
+ m_dav{false},
+ m_srq{false},
+ m_ifc{false},
+ m_eoi{false},
+ m_dio{0},
+ m_nrfd_out{false},
+ m_ndac_out{false},
+ m_dav_out{false},
+ m_srq_out{false},
+ m_eoi_out{false},
+ m_pon{false},
+ m_rdy{false},
+ m_lpe{false},
+ m_ist{false},
+ m_rtl{false},
+ m_apt_flag{false},
+ m_cpt_flag{false},
+ m_din_flag{false},
+ m_nba{false},
+ m_pp_sense{false},
+ m_pp_line{0},
+ m_send_eoi{false},
+ m_sh_state{source_handshake_state::SIDS},
+ m_ah_state{acceptor_handshake_state::AIDS},
+ m_t_state{talker_state::TIDS},
+ m_tp_state{talker_primary_state::TPIS},
+ m_tsp_state{talker_serial_poll_state::SPIS},
+ m_l_state{listener_state::LIDS},
+ m_lp_state{listener_primary_state::LPIS},
+ m_rl_state{remote_local_state::LOCS},
+ m_pp_state{parallel_poll_state::PPIS},
+ m_dc_state{device_clear_state::DCIS},
+ m_dt_state{device_trigger_state::DTIS},
+ m_state_changed(false),
+ m_ignore_ext_signals(false),
+ m_intr_out(false),
+ m_dreq_out(false)
{
}
@@ -144,16 +144,6 @@ void i8291a_device::device_reset()
void i8291a_device::device_start()
{
- m_int_write_func.resolve_safe();
- m_dreq_write_func.resolve_safe();
- m_dav_write_func.resolve_safe();
- m_nrfd_write_func.resolve_safe();
- m_ndac_write_func.resolve_safe();
- m_eoi_write_func.resolve_safe();
- m_srq_write_func.resolve_safe();
- m_dio_read_func.resolve_safe(0xff);
- m_dio_write_func.resolve_safe();
-
save_item(NAME(m_din));
save_item(NAME(m_dout));
save_item(NAME(m_ints1));
@@ -252,7 +242,7 @@ void i8291a_device::update_int()
if (m_intr_out != intr) {
LOGMASKED(LOG_INT, "%s: intr %s\n", __FUNCTION__, intr ? "true" : "false");
- m_int_write_func(intr);
+ m_int_write_func(intr != bool(m_auxb & REG_AUXB_INT_ACTIVE_LOW));
m_intr_out = intr;
}
}
@@ -443,6 +433,9 @@ void i8291a_device::aux_mode_w(uint8_t data)
break;
case 5:
LOGMASKED(LOG_REG, "AUXB = %02X\n", data & 0x1f);
+ // force interrupt line update if polarity is changed
+ if ((data ^ m_auxb) & REG_AUXB_INT_ACTIVE_LOW)
+ m_intr_out = !m_intr_out;
m_auxb = data;
break;
case 3:
diff --git a/src/devices/machine/i8355.cpp b/src/devices/machine/i8355.cpp
index caa31eb7e1a..501120ae79d 100644
--- a/src/devices/machine/i8355.cpp
+++ b/src/devices/machine/i8355.cpp
@@ -87,13 +87,13 @@ inline void i8355_device::write_port(int port, u8 data)
// i8355_device - constructor
//-------------------------------------------------
-i8355_device::i8355_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, I8355, tag, owner, clock),
- m_in_pa_cb(*this),
- m_out_pa_cb(*this),
- m_in_pb_cb(*this),
- m_out_pb_cb(*this),
- m_rom(*this, DEVICE_SELF)
+i8355_device::i8355_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, I8355, tag, owner, clock),
+ m_in_pa_cb(*this, 0),
+ m_out_pa_cb(*this),
+ m_in_pb_cb(*this, 0),
+ m_out_pb_cb(*this),
+ m_rom(*this, DEVICE_SELF)
{
}
@@ -103,12 +103,6 @@ i8355_device::i8355_device(const machine_config &mconfig, const char *tag, devic
void i8355_device::device_start()
{
- // resolve callbacks
- m_in_pa_cb.resolve_safe(0);
- m_in_pb_cb.resolve_safe(0);
- m_out_pa_cb.resolve_safe();
- m_out_pb_cb.resolve_safe();
-
// register for state saving
save_item(NAME(m_output));
save_item(NAME(m_ddr));
diff --git a/src/devices/machine/ibm21s850.cpp b/src/devices/machine/ibm21s850.cpp
index 3afb88b27a1..c77d3077a01 100644
--- a/src/devices/machine/ibm21s850.cpp
+++ b/src/devices/machine/ibm21s850.cpp
@@ -12,9 +12,9 @@
#include "emu.h"
#include "ibm21s850.h"
-#define LOG_READS (1 << 1)
-#define LOG_WRITES (1 << 2)
-#define LOG_UNKNOWNS (1 << 3)
+#define LOG_READS (1U << 1)
+#define LOG_WRITES (1U << 2)
+#define LOG_UNKNOWNS (1U << 3)
#define LOG_ALL (LOG_READS | LOG_WRITES | LOG_UNKNOWNS)
#define VERBOSE (LOG_ALL)
@@ -43,9 +43,7 @@ void ibm21s85x_base_device::device_start()
{
save_item(NAME(m_regs));
- m_reset_timer = timer_alloc(TIMER_RESET);
-
- m_reset_cb.resolve_safe();
+ m_reset_timer = timer_alloc(FUNC(ibm21s85x_base_device::reset_tick), this);
}
void ibm21s85x_base_device::device_reset()
@@ -81,20 +79,17 @@ void ibm21s851_device::device_reset()
m_regs[REG_COUNT_OFFS] |= 0x0b; // 11 registers following the standard block on 21S851
}
-void ibm21s85x_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ibm21s85x_base_device::reset_tick)
{
- if (id == TIMER_RESET)
+ if (param)
+ {
+ m_reset_cb(0);
+ m_reset_timer->adjust(attotime::never);
+ }
+ else
{
- if (param)
- {
- m_reset_cb(0);
- m_reset_timer->adjust(attotime::never);
- }
- else
- {
- m_reset_cb(1);
- m_reset_timer->adjust(attotime::from_usec(26266), 1); // RC reset circuit, 3.3V in, 2.3V out, 10KOhm resistor, 2.2uF capacitor
- }
+ m_reset_cb(1);
+ m_reset_timer->adjust(attotime::from_usec(26266), 1); // RC reset circuit, 3.3V in, 2.3V out, 10KOhm resistor, 2.2uF capacitor
}
}
diff --git a/src/devices/machine/ibm21s850.h b/src/devices/machine/ibm21s850.h
index 3853a7c9799..dde6cf59a4d 100644
--- a/src/devices/machine/ibm21s850.h
+++ b/src/devices/machine/ibm21s850.h
@@ -30,11 +30,10 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- void power_on_reset();
+ TIMER_CALLBACK_MEMBER(reset_tick);
- static const device_timer_id TIMER_RESET = 0;
+ void power_on_reset();
enum : uint32_t
{
diff --git a/src/devices/machine/icd2061a.cpp b/src/devices/machine/icd2061a.cpp
new file mode 100644
index 00000000000..1dfe44a1e06
--- /dev/null
+++ b/src/devices/machine/icd2061a.cpp
@@ -0,0 +1,323 @@
+// license:BSD-3-Clause
+// copyright-holders:windyfairy
+/***************************************************************************
+
+ IC Designs 2061A Dual Programmable Graphics Clock Generator
+ ____ ____
+ SEL0/CLK -> 1 | \_/ | 16 <- /PWRDWN
+ SEL1/DATA -> 2 | | 15 <- INTCLK
+ AVDD -> 3 | | 14 <- INIT1
+ /OUTDIS -> 4 | ICD2061A | 13 <- VDD
+ GND -> 5 | | 12 <- INIT0
+ XTALIN -> 6 | | 11 <- FEATCLK
+ XTALOUT <- 7 | | 10 -> /ERROUT
+ MCLKOUT <- 8 |___________| 9 -> VCLKOUT
+
+
+ TODO:
+ - Not handled: MCLKOUT_HIGH_Z, VCLKOUT_HIGH_Z, VCLKOUT_FORCED_HIGH
+
+***************************************************************************/
+
+#include "emu.h"
+#include "icd2061a.h"
+
+#define LOG_PINS (1 << 1)
+#define LOG_STATE (1 << 2)
+#define LOG_TODO (1 << 3)
+
+// #define VERBOSE (LOG_GENERAL | LOG_PINS | LOG_STATE | LOG_TODO)
+#define VERBOSE (LOG_TODO)
+
+#include "logmacro.h"
+
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
+
+DEFINE_DEVICE_TYPE(ICD2061A, icd2061a_device, "icd2061a", "IC Designs 2061A Dual Programmable Graphics Clock Generator")
+
+
+icd2061a_device::icd2061a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ICD2061A, tag, owner, clock)
+ , m_vclkout_changed_cb(*this)
+ , m_mclkout_changed_cb(*this)
+ , m_errout_cb(*this)
+ , m_init0(0), m_init1(0)
+ , m_outdis(1), m_pwrdwn(1)
+ , m_intclk(0)
+{
+}
+
+void icd2061a_device::device_start()
+{
+ save_item(NAME(m_state));
+ save_item(NAME(m_unlock_step));
+ save_item(NAME(m_cur_bit));
+ save_item(NAME(m_data));
+ save_item(NAME(m_data_prev));
+ save_item(NAME(m_clk));
+ save_item(NAME(m_cmd));
+
+ save_item(NAME(m_init0));
+ save_item(NAME(m_init1));
+ save_item(NAME(m_sel0));
+ save_item(NAME(m_sel1));
+ save_item(NAME(m_outdis));
+ save_item(NAME(m_pwrdwn));
+ save_item(NAME(m_intclk));
+ save_item(NAME(m_vclkout_select));
+ save_item(NAME(m_mclkout_select));
+
+ save_item(NAME(m_reg_clocks));
+ save_item(NAME(m_prescale));
+ save_item(NAME(m_powerdown_mode));
+ save_item(NAME(m_muxref_vclkout_source));
+ save_item(NAME(m_timeout_interval));
+ save_item(NAME(m_muxref_adjust));
+
+ save_item(NAME(m_featclock));
+ save_item(NAME(m_vclkout_clock));
+ save_item(NAME(m_mclkout_clock));
+
+ m_watchdog_timer = timer_alloc(FUNC(icd2061a_device::watchdog_callback), this);
+ m_watchdog_timer->adjust(attotime::never);
+
+ m_update_timer = timer_alloc(FUNC(icd2061a_device::update_clock_callback), this);
+ m_update_timer->adjust(attotime::never);
+
+ m_state = CLOCKGEN_UNLOCK;
+ m_unlock_step = 0;
+ m_cur_bit = 0;
+ m_data = m_data_prev = 1;
+ m_clk = 1;
+ m_cmd = 0;
+
+ std::fill(std::begin(m_prescale), std::end(m_prescale), 2);
+ m_powerdown_mode = 0;
+ m_muxref_vclkout_source = 0;
+ m_timeout_interval = 5;
+ m_muxref_adjust = 1;
+ m_powerdown_divisor = 8;
+ m_sel0 = m_sel1 = 0;
+ m_vclkout_select = m_mclkout_select = -1;
+ m_vclkout_clock = m_mclkout_clock = 0;
+
+ // Are these values derived from the XTALIN at all?
+ // The manual only gives the frequencies as these values,
+ // not p/q/m values that could be used to derive it from XTALIN
+ if (m_init0 == 0 && m_init1 == 0) {
+ m_reg_clocks[MREG] = 32'500'000;
+ m_reg_clocks[REG0] = 25'175'000;
+ m_reg_clocks[REG1] = m_reg_clocks[REG2] = 28'322'000;
+ } else if (m_init0 == 0 && m_init1 == 1) {
+ m_reg_clocks[MREG] = 40'000'000;
+ m_reg_clocks[REG0] = 25'175'000;
+ m_reg_clocks[REG1] = m_reg_clocks[REG2] = 28'322'000;
+ } else if (m_init0 == 1 && m_init1 == 0) {
+ m_reg_clocks[MREG] = 50'350'000;
+ m_reg_clocks[REG0] = 40'000'000;
+ m_reg_clocks[REG1] = m_reg_clocks[REG2] = 28'322'000;
+ } else if (m_init0 == 1 && m_init1 == 1) {
+ m_reg_clocks[MREG] = 56'644'000;
+ m_reg_clocks[REG0] = 40'000'000;
+ m_reg_clocks[REG1] = m_reg_clocks[REG2] = 50'350'000;
+ }
+
+ m_errout_cb(1); // set no error start
+ update_clock_callback(0);
+}
+
+void icd2061a_device::set_featclock(const uint32_t clock)
+{
+ m_featclock = clock;
+}
+
+TIMER_CALLBACK_MEMBER( icd2061a_device::watchdog_callback )
+{
+ // If the timeout is hit then rearm the locked mode and accept the last values as sel0/sel1
+ LOG("watchdog timed out, setting sel0 = %d, sel1 = %d\n", m_clk, m_data);
+
+ if (m_sel0 != m_clk || m_sel1 != m_data) {
+ m_sel0 = m_clk;
+ m_sel1 = m_data;
+
+ update_clock();
+ }
+
+ m_state = CLOCKGEN_UNLOCK;
+ m_unlock_step = 0;
+ m_unlock_step = 0;
+ m_cur_bit = 0;
+ m_cmd = 0;
+}
+
+TIMER_CALLBACK_MEMBER( icd2061a_device::update_clock_callback )
+{
+ // mclkout
+ if (m_outdis == 0)
+ m_mclkout_select = MCLKOUT_HIGH_Z;
+ else if (m_outdis == 1 && m_pwrdwn == 1)
+ m_mclkout_select = MCLKOUT_MREG;
+ else if (m_outdis == 1 && m_pwrdwn == 0)
+ m_mclkout_select = MCLKOUT_PWRDWN;
+
+ if (m_mclkout_select == MCLKOUT_PWRDWN) {
+ if (m_powerdown_mode == 1 || m_powerdown_divisor == 0)
+ m_reg_clocks[MREG] = 0;
+ else
+ m_reg_clocks[MREG] = clock() / ((17 - m_powerdown_divisor) * 2); // 1 = divisor of 32, 15 = divisor of 4
+ } else if (m_mclkout_select == MCLKOUT_MREG) {
+ const int a = BIT(m_regs[MREG], 21, 2); // register addr
+ const int p = BIT(m_regs[MREG], 10, 7) + 3; // p counter value
+ const int m = BIT(m_regs[MREG], 7, 3); // post-vco divisor
+ const int q = BIT(m_regs[MREG], 0, 7) + 2; // q counter value
+ m_reg_clocks[MREG] = (clock() * m_prescale[a] * (p / double(q))) / (1 << m);
+ } else {
+ LOGTODO("unimplemented mclkout selected %d\n", m_mclkout_select);
+ }
+
+ if (m_reg_clocks[MREG] != m_mclkout_clock) {
+ m_mclkout_changed_cb(m_reg_clocks[MREG]);
+ m_mclkout_clock = m_reg_clocks[MREG];
+ }
+
+ // vclkout
+ if (m_outdis == 0)
+ m_vclkout_select = VCLKOUT_HIGH_Z;
+ else if (m_outdis == 1 && m_pwrdwn == 0)
+ m_vclkout_select = VCLKOUT_FORCED_HIGH;
+ else if (m_outdis == 1 && m_pwrdwn == 1 && m_sel1 == 0 && m_sel0 == 0)
+ m_vclkout_select = VCLKOUT_REG0;
+ else if (m_outdis == 1 && m_pwrdwn == 1 && m_sel1 == 0 && m_sel0 == 1)
+ m_vclkout_select = VCLKOUT_REG1;
+ else if (m_outdis == 1 && m_pwrdwn == 1 && m_intclk == 0 && m_sel1 == 1 && m_sel0 == 0)
+ m_vclkout_select = VCLKOUT_FEATCLK;
+ else if (m_outdis == 1 && m_pwrdwn == 1 && m_sel1 == 1 && (m_intclk == 1 || m_sel0 == 1))
+ m_vclkout_select = VCLKOUT_REG2;
+
+ uint32_t vclkout_clock = m_vclkout_clock;
+ if (m_vclkout_select == VCLKOUT_FEATCLK) {
+ vclkout_clock = m_featclock;
+ } else if (m_vclkout_select >= VCLKOUT_REG0 && m_vclkout_select <= VCLKOUT_REG2) {
+ const int a = BIT(m_regs[m_vclkout_select], 21, 2); // register addr
+ const int p = BIT(m_regs[m_vclkout_select], 10, 7) + 3; // p counter value
+ const int m = BIT(m_regs[m_vclkout_select], 7, 3); // post-vco divisor
+ const int q = BIT(m_regs[m_vclkout_select], 0, 7) + 2; // q counter value
+ vclkout_clock = m_reg_clocks[m_vclkout_select] = (clock() * m_prescale[a] * (p / double(q))) / (1 << m);
+ } else {
+ LOGTODO("unimplemented vclkout selected %d\n", m_vclkout_select);
+ }
+
+ if (vclkout_clock != m_vclkout_clock) {
+ m_vclkout_clock = vclkout_clock;
+ m_vclkout_changed_cb(vclkout_clock);
+ }
+}
+
+void icd2061a_device::update_clock()
+{
+ // Set muxed clock during transition period
+ m_vclkout_changed_cb(m_muxref_vclkout_source ? m_mclkout_clock : clock());
+
+ m_watchdog_timer->adjust(attotime::never);
+ m_update_timer->adjust(attotime::from_msec(m_timeout_interval));
+}
+
+void icd2061a_device::data_w(int state)
+{
+ LOGMASKED(LOG_PINS, "data_w %d\n", state);
+
+ m_watchdog_timer->adjust(attotime::from_msec(m_timeout_interval));
+
+ m_data = state;
+}
+
+void icd2061a_device::clk_w(int state)
+{
+ LOGMASKED(LOG_PINS, "clk_w %d\n", state);
+
+ m_watchdog_timer->adjust(attotime::from_msec(m_timeout_interval));
+
+ if (!m_clk && state) {
+ if (m_state == CLOCKGEN_UNLOCK && m_data == 1) {
+ // Any number of 1s can be read until the final transition with data low
+ m_errout_cb(1); // clear any previous errors since we're in a good state now
+
+ m_unlock_step++;
+ LOGMASKED(LOG_STATE, "unlock count = %d\n", m_unlock_step);
+ } else if (m_state == CLOCKGEN_UNLOCK && m_data == 0 && m_unlock_step >= 5) {
+ // Found last part of unlock sequence, move on to start bit
+ m_state = CLOCKGEN_START_BIT;
+ m_unlock_step = 0;
+ LOGMASKED(LOG_STATE, "found unlock end, state = CLOCKGEN_START_BIT\n");
+ } else if (m_state == CLOCKGEN_START_BIT && m_data == 0) {
+ // Found start bit transition, move on to data
+ m_state = CLOCKGEN_DATA;
+ m_cur_bit = 0;
+ m_cmd = 0;
+ LOGMASKED(LOG_STATE, "found start bit, state = CLOCKGEN_DATA\n");
+ } else if (m_state == CLOCKGEN_DATA && m_data_prev != m_data && m_cur_bit < 24) {
+ // Data uses modified Manchester encoding so the data bit read on each edge must be different
+ // Must read exactly 24 bits of data here
+ m_cmd |= m_data << m_cur_bit;
+ LOGMASKED(LOG_STATE, "data %d %06x\n", m_cur_bit, m_cmd);
+ m_cur_bit++;
+ } else if (m_state == CLOCKGEN_DATA && m_data == 1 && m_cur_bit == 24) {
+ // Found end bit transition, accept data and then rearm lock
+ const int idx = BIT(m_cmd, 21, 3);
+
+ if (idx == 4) {
+ const int p = BIT(m_cmd, 17, 4);
+ LOG("PWRDWN register %06x p[%d]\n", m_cmd, p);
+ m_powerdown_divisor = p;
+ } else if (idx == 6) {
+ const int c = BIT(m_cmd, 15, 6);
+ const int ps = BIT(m_cmd, 12, 3);
+
+ m_powerdown_mode = BIT(c, 5);
+ m_muxref_vclkout_source = BIT(c, 4);
+ m_timeout_interval = 5 * (1 << BIT(c, 3));
+ m_muxref_adjust = BIT(c, 1);
+
+ m_prescale[0] = 2 << BIT(ps, 0);
+ m_prescale[1] = 2 << BIT(ps, 1);
+ m_prescale[2] = 2 << BIT(ps, 2);
+
+ LOG("CNTL program %06x c[%d] ps[%d]\n", m_cmd, c, ps);
+ } else if (idx <= 3) {
+ const int a = BIT(m_cmd, 21, 2); // register addr
+ const int i = BIT(m_cmd, 17, 4); // index, used to make sure clock is in expected range
+ const int p = BIT(m_cmd, 10, 7) + 3; // p counter value
+ const int m = BIT(m_cmd, 7, 3); // post-vco divisor
+ const int q = BIT(m_cmd, 0, 7) + 2; // q counter value
+ const double outclock = (clock() * m_prescale[a] * (p / double(q))) / 1000000.0;
+ const double outclock_scaled = outclock / (1 << m);
+
+ m_regs[idx] = m_cmd;
+
+ LOG("VCO program %06x a[%d] i[%d] p[%d] m[%d] q[%d] prescale[%d] clock[%lf] clock_scaled[%lf]\n", m_cmd, a, i, p, m, q, m_prescale[a], outclock, outclock_scaled);
+ } else {
+ LOG("Unknown register selected: %06x %d\n", m_cmd, idx);
+ }
+
+ m_state = CLOCKGEN_UNLOCK;
+ m_unlock_step = 0;
+
+ LOGMASKED(LOG_STATE, "accepted\n");
+
+ update_clock();
+ } else {
+ // Error state, rearm lock
+ m_state = CLOCKGEN_UNLOCK;
+ m_unlock_step = 0;
+
+ m_errout_cb(0); // notify of error
+
+ LOGMASKED(LOG_STATE, "error\n");
+ }
+ } else {
+ m_data_prev = m_data;
+ }
+
+ m_clk = state;
+}
diff --git a/src/devices/machine/icd2061a.h b/src/devices/machine/icd2061a.h
new file mode 100644
index 00000000000..2308d2e9288
--- /dev/null
+++ b/src/devices/machine/icd2061a.h
@@ -0,0 +1,105 @@
+// license:BSD-3-Clause
+// copyright-holders:windyfairy
+/***************************************************************************
+
+ IC Designs 2061ASC-1 Programmable Clock Generator
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_ICD2061A_H
+#define MAME_MACHINE_ICD2061A_H
+
+#pragma once
+
+class icd2061a_device : public device_t
+{
+public:
+ icd2061a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto vclkout_changed() { return m_vclkout_changed_cb.bind(); }
+ auto mclkout_changed() { return m_mclkout_changed_cb.bind(); }
+ auto errout() { return m_errout_cb.bind(); }
+
+ void init0_w(int state) { m_init0 = state; }
+ void init1_w(int state) { m_init1 = state; }
+ void outdis_w(int state) { m_outdis = state; }
+ void pwrdwn_w(int state) { m_pwrdwn = state; }
+ void intclk_w(int state) { m_intclk = state; }
+
+ void set_featclock(const uint32_t clock);
+
+ void data_w(int state);
+ void clk_w(int state);
+
+protected:
+ virtual void device_start() override;
+
+private:
+ enum : uint8_t {
+ CLOCKGEN_UNLOCK = 0,
+ CLOCKGEN_START_BIT,
+ CLOCKGEN_DATA,
+ };
+
+ enum : int8_t {
+ VCLKOUT_REG0 = 0,
+ VCLKOUT_REG1,
+ VCLKOUT_REG2,
+ VCLKOUT_HIGH_Z,
+ VCLKOUT_FORCED_HIGH,
+ VCLKOUT_FEATCLK,
+
+ MCLKOUT_MREG = 0,
+ MCLKOUT_HIGH_Z,
+ MCLKOUT_PWRDWN,
+ };
+
+ enum {
+ REG0 = 0,
+ REG1,
+ REG2,
+ MREG,
+ };
+
+ TIMER_CALLBACK_MEMBER( watchdog_callback );
+ TIMER_CALLBACK_MEMBER( update_clock_callback );
+
+ void update_clock();
+
+ emu_timer *m_watchdog_timer;
+ emu_timer *m_update_timer;
+
+ devcb_write32 m_vclkout_changed_cb, m_mclkout_changed_cb;
+ devcb_write_line m_errout_cb;
+
+ uint8_t m_init0, m_init1;
+ uint8_t m_sel0, m_sel1;
+ uint8_t m_outdis;
+ uint8_t m_pwrdwn;
+ uint8_t m_intclk;
+ int8_t m_vclkout_select, m_mclkout_select;
+
+ uint8_t m_state;
+ uint8_t m_unlock_step;
+ uint8_t m_cur_bit;
+ uint8_t m_data, m_data_prev;
+ uint8_t m_clk;
+ uint32_t m_cmd;
+
+ uint32_t m_regs[4];
+ uint32_t m_reg_clocks[4];
+ uint8_t m_prescale[4];
+ uint8_t m_powerdown_mode;
+ uint8_t m_muxref_vclkout_source;
+ uint8_t m_timeout_interval;
+ uint8_t m_muxref_adjust;
+ uint8_t m_powerdown_divisor;
+
+ uint32_t m_featclock;
+ uint32_t m_vclkout_clock, m_mclkout_clock;
+};
+
+
+DECLARE_DEVICE_TYPE(ICD2061A, icd2061a_device)
+
+#endif // MAME_MACHINE_ICD2061A_H
diff --git a/src/devices/machine/icm7170.cpp b/src/devices/machine/icm7170.cpp
index c66d1b6bcc7..97be23ee0d2 100644
--- a/src/devices/machine/icm7170.cpp
+++ b/src/devices/machine/icm7170.cpp
@@ -8,6 +8,7 @@
#include "emu.h"
#include "icm7170.h"
+
#include "coreutil.h"
#define VERBOSE (0)
@@ -59,8 +60,6 @@ enum
IRQ_BIT_ALARM = 0x01
};
-static constexpr int ICM7170_TIMER_ID = 0;
-
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
@@ -84,10 +83,7 @@ icm7170_device::icm7170_device(const machine_config &mconfig, const char *tag, d
void icm7170_device::device_start()
{
- // resolve callbacks
- m_out_irq_cb.resolve_safe();
-
- m_timer = timer_alloc(ICM7170_TIMER_ID);
+ m_timer = timer_alloc(FUNC(icm7170_device::clock_tick), this);
// TODO: frequency should be based on input clock and divisor
m_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
@@ -109,10 +105,10 @@ void icm7170_device::device_reset()
}
//-------------------------------------------------
-// device_timer - handles timer events
+// clock_tick - advance the RTC's counters
//-------------------------------------------------
-void icm7170_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(icm7170_device::clock_tick)
{
// advance hundredths
m_irq_status |= IRQ_BIT_100TH_SECOND;
@@ -121,11 +117,11 @@ void icm7170_device::device_timer(emu_timer &timer, device_timer_id id, int para
m_regs[REG_CNT_100TH_SEC] = 0;
if (m_regs[REG_COMMAND] & CMD_REG_24_HOUR)
- LOG("device_timer %02d-%02d-%02d %02d:%02d:%02d\n",
+ LOG("clock_tick %02d-%02d-%02d %02d:%02d:%02d\n",
m_regs[REG_CNT_YEAR], m_regs[REG_CNT_MONTH], m_regs[REG_CNT_DAY],
m_regs[REG_CNT_HOURS], m_regs[REG_CNT_MINUTES], m_regs[REG_CNT_SECONDS]);
else
- LOG("device_timer %02d-%02d-%02d %02d:%02d:%02d %s\n",
+ LOG("clock_tick %02d-%02d-%02d %02d:%02d:%02d %s\n",
m_regs[REG_CNT_YEAR], m_regs[REG_CNT_MONTH], m_regs[REG_CNT_DAY],
m_regs[REG_CNT_HOURS] & 0xf, m_regs[REG_CNT_MINUTES], m_regs[REG_CNT_SECONDS],
(m_regs[REG_CNT_HOURS] & 0x80) ? "pm" : "am");
@@ -259,9 +255,10 @@ void icm7170_device::nvram_default()
// .nv file
//-------------------------------------------------
-void icm7170_device::nvram_read(emu_file &file)
+bool icm7170_device::nvram_read(util::read_stream &file)
{
- file.read(m_regs, 0x20);
+ auto const [err, actual] = util::read(file, m_regs, 0x20);
+ return !err && (actual == 0x20);
}
@@ -270,9 +267,10 @@ void icm7170_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void icm7170_device::nvram_write(emu_file &file)
+bool icm7170_device::nvram_write(util::write_stream &file)
{
- file.write(m_regs, 0x20);
+ auto const [err, actual] = util::write(file, m_regs, 0x20);
+ return !err;
}
// non-inherited device functions
diff --git a/src/devices/machine/icm7170.h b/src/devices/machine/icm7170.h
index e38a556b06c..2fef930fa04 100644
--- a/src/devices/machine/icm7170.h
+++ b/src/devices/machine/icm7170.h
@@ -61,15 +61,16 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ TIMER_CALLBACK_MEMBER(clock_tick);
private:
void recalc_irqs();
diff --git a/src/devices/machine/idectrl.h b/src/devices/machine/idectrl.h
index e81ffeae346..bcca567e39a 100644
--- a/src/devices/machine/idectrl.h
+++ b/src/devices/machine/idectrl.h
@@ -105,7 +105,8 @@ class bus_master_ide_controller_device : public ide_controller_32_device
{
public:
bus_master_ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- template <typename T> void set_bus_master_space(T &&bmtag, int bmspace) { m_dma_space.set_tag(std::forward<T>(bmtag), bmspace); }
+ template <typename... T> void set_bus_master_space(T &&... args) { m_dma_space.set_tag(std::forward<T>(args)...); }
+ template <bool R> void set_bus_master_space(const address_space_finder<R> &finder) { m_dma_space.set_tag(finder); }
template <typename T> bus_master_ide_controller_device &master(T &&opts, const char *dflt = nullptr, bool fixed = false)
{
diff --git a/src/devices/machine/ie15.cpp b/src/devices/machine/ie15.cpp
index 1555e1cb645..bf8c9294878 100644
--- a/src/devices/machine/ie15.cpp
+++ b/src/devices/machine/ie15.cpp
@@ -12,14 +12,13 @@
****************************************************************************/
#include "emu.h"
-#include "machine/ie15.h"
+#include "ie15.h"
#include "emupal.h"
#include "ie15.lh"
-//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already
#define LOG_RAM (1U << 1)
#define LOG_CPU (1U << 2)
#define LOG_KBD (1U << 3)
@@ -166,7 +165,7 @@ void ie15_device::beep_w(uint8_t data)
{
LOG("beep (%s)\n", m_long_beep ? "short" : "long");
}
- machine().scheduler().timer_set(attotime::from_msec(length), timer_expired_delegate(FUNC(ie15_device::ie15_beepoff),this));
+ m_beepoff_timer->adjust(attotime::from_msec(length));
m_beeper->set_state(1);
}
@@ -229,29 +228,24 @@ uint8_t ie15_device::kb_s_lin_r()
return m_io_keyboard->read() & ie15_keyboard_device::IE_KB_LIN ? IE_TRUE : 0;
}
-/* serial port */
-
-void ie15_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ie15_device::hblank_onoff_tick)
{
- switch (id)
+ if (m_hblank) // Transitioning from in blanking to out of blanking
{
- case TIMER_HBLANK:
- if (m_hblank) // Transitioning from in blanking to out of blanking
- {
- m_hblank = 0;
- m_hblank_timer->adjust(m_screen->time_until_pos((m_vpos + 1) % IE15_TOTAL_VERT, 0));
- scanline_callback();
- }
- else // Transitioning from out of blanking to in blanking
- {
- m_hblank = 1;
- m_hblank_timer->adjust(m_screen->time_until_pos(m_vpos, IE15_HORZ_START));
- }
- break;
+ m_hblank = 0;
+ m_hblank_timer->adjust(m_screen->time_until_pos((m_vpos + 1) % IE15_TOTAL_VERT, 0));
+ scanline_callback();
+ }
+ else // Transitioning from out of blanking to in blanking
+ {
+ m_hblank = 1;
+ m_hblank_timer->adjust(m_screen->time_until_pos(m_vpos, IE15_HORZ_START));
}
}
-WRITE_LINE_MEMBER(ie15_device::rs232_conn_rxd_w)
+/* serial port */
+
+void ie15_device::rs232_conn_rxd_w(int state)
{
device_serial_interface::rx_w(state);
}
@@ -307,7 +301,7 @@ void ie15_device::serial_speed_w(uint8_t data)
return;
}
-WRITE_LINE_MEMBER(ie15_device::update_serial)
+void ie15_device::update_serial(int state)
{
int startbits = 1;
int databits = m_rs232_databits->read();
@@ -471,18 +465,11 @@ void ie15_device::kbd_put(uint16_t data)
}
}
-WRITE_LINE_MEMBER( ie15_device::kbd_sdv )
+void ie15_device::kbd_sdv(int state)
{
m_kbd_sdv = state;
}
-void ie15_device::device_resolve_objects()
-{
- m_rs232_conn_dtr_handler.resolve_safe();
- m_rs232_conn_rts_handler.resolve_safe();
- m_rs232_conn_txd_handler.resolve_safe();
-}
-
void ie15_device::device_start()
{
m_lat_led.resolve();
@@ -494,9 +481,10 @@ void ie15_device::device_start()
m_sdv_led.resolve();
m_prd_led.resolve();
- m_hblank_timer = timer_alloc(TIMER_HBLANK);
+ m_hblank_timer = timer_alloc(FUNC(ie15_device::hblank_onoff_tick), this);
m_hblank_timer->adjust(attotime::never);
+ m_beepoff_timer = timer_alloc(FUNC(ie15_device::ie15_beepoff), this);
m_video.ptr1 = m_video.ptr2 = m_latch = 0;
m_tmpbmp = std::make_unique<uint32_t[]>(IE15_TOTAL_HORZ * IE15_TOTAL_VERT);
@@ -506,7 +494,7 @@ void ie15_device::device_reset()
{
update_serial(0);
- memset(&m_video, 0, sizeof(m_video));
+ m_video = decltype(m_video)();
m_kb_ruslat = m_long_beep = m_kb_control = m_kb_data = m_kb_flag0 = 0;
m_kb_flag = IE_TRUE;
m_kbd_sdv = false;
@@ -616,8 +604,8 @@ void ie15_device::update_leds()
/*
VBlank is active for 3 topmost on-screen rows and 1 at the bottom.
- However, control flag 3 overrides VBlank, allowing status line
- to be switched on and off.
+ However, control flag 3 overrides VBlank, allowing status line
+ to be switched on and off.
*/
void ie15_device::scanline_callback()
{
@@ -677,7 +665,7 @@ GFXDECODE_END
void ie15_device::ie15core(machine_config &config)
{
/* Basic machine hardware */
- IE15_CPU(config, m_maincpu, XTAL(30'800'000)/10);
+ IE15_CPU(config, m_maincpu, XTAL(30'800'000) / 10);
m_maincpu->set_addrmap(AS_PROGRAM, &ie15_device::ie15_mem);
m_maincpu->set_addrmap(AS_IO, &ie15_device::ie15_io);
diff --git a/src/devices/machine/ie15.h b/src/devices/machine/ie15.h
index 3bd93567d22..eb82cada227 100644
--- a/src/devices/machine/ie15.h
+++ b/src/devices/machine/ie15.h
@@ -42,32 +42,31 @@ public:
auto rs232_conn_txd_handler() { return m_rs232_conn_txd_handler.bind(); }
auto rs232_conn_dtr_handler() { return m_rs232_conn_dtr_handler.bind(); }
auto rs232_conn_rts_handler() { return m_rs232_conn_rts_handler.bind(); }
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_dcd_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_dsr_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_ri_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_cts_w);
- DECLARE_WRITE_LINE_MEMBER(rs232_conn_rxd_w);
+ void rs232_conn_dcd_w(int state);
+ void rs232_conn_dsr_w(int state);
+ void rs232_conn_ri_w(int state);
+ void rs232_conn_cts_w(int state);
+ void rs232_conn_rxd_w(int state);
- DECLARE_WRITE_LINE_MEMBER(update_serial);
+ void update_serial(int state);
protected:
ie15_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
virtual const tiny_rom_entry *device_rom_region() const override;
+ TIMER_CALLBACK_MEMBER(hblank_onoff_tick);
+
virtual void rcv_complete() override;
virtual void tra_callback() override;
virtual void tra_complete() override;
private:
- static const device_timer_id TIMER_HBLANK = 0;
void scanline_callback();
void update_leds();
void draw_scanline(uint32_t *p, uint16_t offset, uint8_t scanline);
@@ -76,7 +75,7 @@ private:
void ie15core(machine_config &config);
void kbd_put(uint16_t data);
- DECLARE_WRITE_LINE_MEMBER(kbd_sdv);
+ void kbd_sdv(int state);
void mem_w(uint8_t data);
uint8_t mem_r();
void mem_addr_lo_w(uint8_t data);
@@ -106,32 +105,33 @@ private:
std::unique_ptr<uint32_t[]> m_tmpbmp;
- emu_timer *m_hblank_timer;
+ emu_timer *m_hblank_timer = nullptr;
+ emu_timer *m_beepoff_timer = nullptr;
- uint8_t m_long_beep;
- uint8_t m_kb_control;
- uint8_t m_kb_data;
- uint8_t m_kb_flag0;
- uint8_t m_kb_flag;
- uint8_t m_kb_ruslat;
- uint8_t m_latch;
+ uint8_t m_long_beep = 0;
+ uint8_t m_kb_control = 0;
+ uint8_t m_kb_data = 0;
+ uint8_t m_kb_flag0 = 0;
+ uint8_t m_kb_flag = 0;
+ uint8_t m_kb_ruslat = 0;
+ uint8_t m_latch = 0;
struct
{
- uint8_t cursor;
- uint8_t enable;
- uint8_t line25;
- uint32_t ptr1;
- uint32_t ptr2;
+ uint8_t cursor = 0;
+ uint8_t enable = 0;
+ uint8_t line25 = 0;
+ uint32_t ptr1 = 0;
+ uint32_t ptr2 = 0;
} m_video;
- uint8_t m_serial_rx_ready;
- uint8_t m_serial_rx_char;
- uint8_t m_serial_tx_ready;
- int m_hblank;
- int m_vpos;
- int m_marker_scanline;
- bool m_kbd_sdv;
+ uint8_t m_serial_rx_ready = 0;
+ uint8_t m_serial_rx_char = 0;
+ uint8_t m_serial_tx_ready = 0;
+ int m_hblank = 0;
+ int m_vpos = 0;
+ int m_marker_scanline = 0;
+ bool m_kbd_sdv = 0;
required_device<cpu_device> m_maincpu;
required_region_ptr<u8> m_p_videoram;
diff --git a/src/devices/machine/ie15_kbd.cpp b/src/devices/machine/ie15_kbd.cpp
index 24120fc5734..8052b862ad7 100644
--- a/src/devices/machine/ie15_kbd.cpp
+++ b/src/devices/machine/ie15_kbd.cpp
@@ -8,7 +8,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/ie15_kbd.h"
+#include "ie15_kbd.h"
#include "machine/keyboard.ipp"
@@ -22,6 +22,7 @@ ie15_keyboard_device::ie15_keyboard_device(const machine_config &mconfig, device
: device_t(mconfig, type, tag, owner, clock)
, device_matrix_keyboard_interface(mconfig, *this, "TERM_LINE0", "TERM_LINE1", "TERM_LINE2", "TERM_LINE3")
, m_io_kbdc(*this, "TERM_LINEC")
+ , m_rom(*this, "ie15kbd")
, m_keyboard_cb(*this)
, m_sdv_cb(*this)
{
@@ -49,9 +50,9 @@ void ie15_keyboard_device::key_make(uint8_t row, uint8_t column)
row += 8;
if (column < 16)
- key_code = m_rom [(row << 4) + column];
+ key_code = m_rom[(row << 4) + column];
else
- key_code = m_rom [(row << 4) + (column - 16) * 2 + 256];
+ key_code = m_rom[(row << 4) + (column - 16) * 2 + 256];
if (ctrl)
key_code &= 0x1f;
@@ -76,16 +77,12 @@ ROM_END
const tiny_rom_entry *ie15_keyboard_device::device_rom_region() const
{
- return ROM_NAME( ie15_keyboard );
+ return ROM_NAME(ie15_keyboard);
}
void ie15_keyboard_device::device_start()
{
- m_keyboard_cb.resolve_safe();
- m_sdv_cb.resolve_safe();
-
- m_rom = (uint8_t*)memregion("ie15kbd")->base();
}
void ie15_keyboard_device::device_reset()
diff --git a/src/devices/machine/ie15_kbd.h b/src/devices/machine/ie15_kbd.h
index 3302bbda8a2..f8ff57e963e 100644
--- a/src/devices/machine/ie15_kbd.h
+++ b/src/devices/machine/ie15_kbd.h
@@ -52,11 +52,10 @@ protected:
required_ioport m_io_kbdc;
private:
- bool m_ruslat;
- uint8_t *m_rom;
-
+ required_region_ptr<uint8_t> m_rom;
devcb_write16 m_keyboard_cb;
devcb_write_line m_sdv_cb;
+ bool m_ruslat;
};
DECLARE_DEVICE_TYPE(IE15_KEYBOARD, ie15_keyboard_device)
diff --git a/src/devices/machine/im6402.cpp b/src/devices/machine/im6402.cpp
index 6a52867bdbd..db3521c8d4b 100644
--- a/src/devices/machine/im6402.cpp
+++ b/src/devices/machine/im6402.cpp
@@ -89,12 +89,6 @@ im6402_device::im6402_device(const machine_config &mconfig, const char *tag, dev
void im6402_device::device_start()
{
- // resolve callbacks
- m_write_tro.resolve_safe();
- m_write_dr.resolve_safe();
- m_write_tbre.resolve_safe();
- m_write_tre.resolve_safe();
-
// create the timers
if (m_rrc > 0)
{
@@ -180,15 +174,6 @@ void im6402_device::tra_complete()
//-------------------------------------------------
-// rcv_callback -
-//-------------------------------------------------
-
-void im6402_device::rcv_callback()
-{
-}
-
-
-//-------------------------------------------------
// rcv_complete -
//-------------------------------------------------
@@ -391,10 +376,12 @@ void im6402_device::epe_w(int state)
m_epe = state;
}
-void im6402_device::write_rri(int state)
+
+//-------------------------------------------------
+// rri_w - receiver register input
+//-------------------------------------------------
+
+void im6402_device::rri_w(int state)
{
- // HACK derive clock from data line as wangpckb sends bytes instantly to make up for mcs51 serial implementation
- receive_register_update_bit(state);
- rx_clock_w(1);
- rx_clock_w(0);
+ rx_w(state);
}
diff --git a/src/devices/machine/im6402.h b/src/devices/machine/im6402.h
index d36853353c2..b7918abcfcb 100644
--- a/src/devices/machine/im6402.h
+++ b/src/devices/machine/im6402.h
@@ -74,7 +74,7 @@ public:
int fe_r() { return m_fe; }
int oe_r() { return m_oe; }
- void write_rri(int state); // receiver register input
+ void rri_w(int state);
void rrc_w(int state);
void trc_w(int state);
void rrd_w(int state);
@@ -96,7 +96,6 @@ protected:
// device_serial_interface overrides
virtual void tra_callback() override;
virtual void tra_complete() override;
- virtual void rcv_callback() override;
virtual void rcv_complete() override;
private:
diff --git a/src/devices/machine/input_merger.cpp b/src/devices/machine/input_merger.cpp
index 28652cdb66f..51c052fc096 100644
--- a/src/devices/machine/input_merger.cpp
+++ b/src/devices/machine/input_merger.cpp
@@ -2,10 +2,27 @@
// copyright-holders:Dirk Best, Vas Crabb
/***************************************************************************
- Input Merger
-
- Used to connect multiple lines to a single device input while
- keeping it pulled high or low
+Input Merger
+
+Used to connect multiple lines to a single device input while keeping it
+pulled high or low.
+
+Default initial input pin(s) state:
+- ANY_HIGH: 0
+- ALL_HIGH: 1
+- ANY_LOW: 1
+- ALL_LOW: 0
+
+TODO:
+- Change the strange initial input state, eg. right now it's all 1 for an AND
+ gate. All 0 for all devices would be more intuitive, but that would need a
+ config handler for setting the number of input pins since otherwise it can't
+ know if the state is active or not.
+- Call m_output_handler at reset, eg. a NOR gate whose inputs are low at power-on
+ should output 1 (to avoid surprises, this should be done after machine_reset).
+- Related to currently not calling m_output_handler at reset, if the hardware
+ 1st value written equals the initial state, m_output_handler is not called,
+ eg. writing 1 to an AND gate pin when the default initial state is 1.
***************************************************************************/
@@ -23,10 +40,10 @@
// DEVICE DEFINITIONS
//**************************************************************************
-DEFINE_DEVICE_TYPE(INPUT_MERGER_ANY_HIGH, input_merger_any_high_device, "ipt_merge_any_hi", "Input Merger (any high)")
-DEFINE_DEVICE_TYPE(INPUT_MERGER_ALL_HIGH, input_merger_all_high_device, "ipt_merge_all_hi", "Input Merger (all high)")
-DEFINE_DEVICE_TYPE(INPUT_MERGER_ANY_LOW, input_merger_any_low_device, "ipt_merge_any_lo", "Input Merger (any low)")
-DEFINE_DEVICE_TYPE(INPUT_MERGER_ALL_LOW, input_merger_all_low_device, "ipt_merge_all_lo", "Input Merger (all low)")
+DEFINE_DEVICE_TYPE(INPUT_MERGER_ANY_HIGH, input_merger_any_high_device, "ipt_merge_any_hi", "Input Merger (any high)") // OR
+DEFINE_DEVICE_TYPE(INPUT_MERGER_ALL_HIGH, input_merger_all_high_device, "ipt_merge_all_hi", "Input Merger (all high)") // AND
+DEFINE_DEVICE_TYPE(INPUT_MERGER_ANY_LOW, input_merger_any_low_device, "ipt_merge_any_lo", "Input Merger (any low)") // NAND
+DEFINE_DEVICE_TYPE(INPUT_MERGER_ALL_LOW, input_merger_all_low_device, "ipt_merge_all_lo", "Input Merger (all low)") // NOR
//**************************************************************************
@@ -69,7 +86,6 @@ input_merger_device::~input_merger_device()
void input_merger_device::device_start()
{
- m_output_handler.resolve_safe();
save_item(NAME(m_state));
m_state = m_initval;
}
@@ -93,12 +109,12 @@ TIMER_CALLBACK_MEMBER(input_merger_device::update_state)
// SPECIALISATIONS
//**************************************************************************
-input_merger_any_high_device::input_merger_any_high_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
+input_merger_any_high_device::input_merger_any_high_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
: input_merger_device(mconfig, INPUT_MERGER_ANY_HIGH, tag, owner, clock, u32(0), u32(0), 1)
{
}
-input_merger_all_high_device::input_merger_all_high_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
+input_merger_all_high_device::input_merger_all_high_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
: input_merger_device(mconfig, INPUT_MERGER_ALL_HIGH, tag, owner, clock, ~u32(0), ~u32(0), 0)
{
}
diff --git a/src/devices/machine/input_merger.h b/src/devices/machine/input_merger.h
index 10c400b4a74..073072d0d4b 100644
--- a/src/devices/machine/input_merger.h
+++ b/src/devices/machine/input_merger.h
@@ -4,9 +4,6 @@
Input Merger
- Used to connect multiple lines to a single device input while
- keeping it pulled high or low
-
***************************************************************************/
#ifndef MAME_MACHINE_INPUT_MERGER_H
@@ -22,13 +19,13 @@
class input_merger_device : public device_t
{
public:
- // callback
+ // configuration
auto output_handler() { return m_output_handler.bind(); }
// input lines
- template <unsigned Bit> DECLARE_WRITE_LINE_MEMBER(in_w) { static_assert(Bit < 32, "invalid bit"); machine().scheduler().synchronize(timer_expired_delegate(FUNC(input_merger_device::update_state), this), (Bit << 1) | (state ? 1U : 0U)); }
- template <unsigned Bit> void in_set(u8 data) { in_w<Bit>(1); }
- template <unsigned Bit> void in_clear(u8 data) { in_w<Bit>(0); }
+ template <unsigned Bit> void in_w(int state) { static_assert(Bit < 32, "invalid bit"); machine().scheduler().synchronize(timer_expired_delegate(FUNC(input_merger_device::update_state), this), (Bit << 1) | (state ? 1U : 0U)); }
+ template <unsigned Bit> void in_set(u8 data = 0) { in_w<Bit>(1); }
+ template <unsigned Bit> void in_clear(u8 data = 0) { in_w<Bit>(0); }
protected:
// constructor/destructor
@@ -50,7 +47,8 @@ protected:
devcb_write_line m_output_handler;
- u32 const m_initval, m_xorval;
+ u32 const m_initval;
+ u32 const m_xorval;
int const m_active;
u32 m_state;
};
diff --git a/src/devices/machine/ins8154.cpp b/src/devices/machine/ins8154.cpp
index 0ce0dbd11d8..15b65fa03e7 100644
--- a/src/devices/machine/ins8154.cpp
+++ b/src/devices/machine/ins8154.cpp
@@ -14,7 +14,7 @@
#include "emu.h"
#include "ins8154.h"
-#define LOG_BITS (1U << 1)
+#define LOG_BITS (1U << 1)
//#define VERBOSE (LOG_BITS) // (LOG_GENERAL|LOG_BITS)
#include "logmacro.h"
@@ -48,9 +48,9 @@ DEFINE_DEVICE_TYPE(INS8154, ins8154_device, "ins8154", "INS8154 RAM I/O")
ins8154_device::ins8154_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, INS8154, tag, owner, clock)
- , m_in_a_cb(*this)
+ , m_in_a_cb(*this, 0xff)
, m_out_a_cb(*this)
- , m_in_b_cb(*this)
+ , m_in_b_cb(*this, 0xff)
, m_out_b_cb(*this)
, m_out_irq_cb(*this)
, m_in_a(0), m_in_b(0), m_out_a(0), m_out_b(0), m_mdr(0), m_odra(0), m_odrb(0)
@@ -63,13 +63,6 @@ ins8154_device::ins8154_device(const machine_config &mconfig, const char *tag, d
void ins8154_device::device_start()
{
- /* resolve callbacks */
- m_in_a_cb.resolve();
- m_out_a_cb.resolve_safe();
- m_in_b_cb.resolve();
- m_out_b_cb.resolve_safe();
- m_out_irq_cb.resolve_safe();
-
/* register for state saving */
save_item(NAME(m_in_a));
save_item(NAME(m_in_b));
@@ -111,14 +104,12 @@ uint8_t ins8154_device::read_io(offs_t offset)
switch (offset)
{
case 0x20:
- if (!m_in_a_cb.isnull())
- val = m_in_a_cb(0);
+ val = m_in_a_cb(0);
m_in_a = val;
break;
case 0x21:
- if (!m_in_b_cb.isnull())
- val = m_in_b_cb(0);
+ val = m_in_b_cb(0);
m_in_b = val;
break;
@@ -126,7 +117,7 @@ uint8_t ins8154_device::read_io(offs_t offset)
val = 0;
if (offset < 0x08) // Read a bit in Port A
{
- if (!m_in_a_cb.isnull())
+ if (!m_in_a_cb.isunset())
{
//val = (m_in_a_cb(0) << (8 - offset)) & 0x80;
val = (m_in_a_cb(0) & ~m_odra & (1 << (offset & 0x07))) ? 0x80 : 0x00;
@@ -135,7 +126,7 @@ uint8_t ins8154_device::read_io(offs_t offset)
}
else // Read a bit in Port B
{
- if (!m_in_b_cb.isnull())
+ if (!m_in_b_cb.isunset())
{
val = (m_in_b_cb(0) & ~m_odrb & (1 << (offset & 0x07))) ? 0x80 : 0x00;
}
diff --git a/src/devices/machine/ins8250.cpp b/src/devices/machine/ins8250.cpp
index 3a4dabf688a..cfbe099beed 100644
--- a/src/devices/machine/ins8250.cpp
+++ b/src/devices/machine/ins8250.cpp
@@ -81,7 +81,7 @@ ASCII/EBCDIC control character recognition, timed interrupts and more.
Known issues:
-- MESS does currently not handle all these model specific features.
+- MAME does currently not handle all these model specific features.
History:
@@ -95,7 +95,7 @@ History:
**********************************************************************/
#include "emu.h"
-#include "machine/ins8250.h"
+#include "ins8250.h"
#include <algorithm>
@@ -179,7 +179,7 @@ static constexpr u8 INS8250_LCR_2STOP_BITS = 0x04;
//static constexpr u8 INS8250_LCR_PEN = 0x08;
//static constexpr u8 INS8250_LCR_EVEN_PAR = 0x10;
//static constexpr u8 INS8250_LCR_PARITY = 0x20;
-//static constexpr u8 INS8250_LCR_BREAK = 0x40;
+static constexpr u8 INS8250_LCR_BREAK = 0x40;
static constexpr u8 INS8250_LCR_DLAB = 0x80;
/* ints will continue to be set for as long as there are ints pending */
@@ -241,7 +241,7 @@ void ins8250_uart_device::clear_int(int flag)
update_interrupt();
}
-READ_LINE_MEMBER(ins8250_uart_device::intrpt_r)
+int ins8250_uart_device::intrpt_r()
{
return !BIT(m_regs.iir, 0);
}
@@ -299,9 +299,11 @@ void ins8250_uart_device::ins8250_w(offs_t offset, u8 data)
set_fcr(data);
break;
case 3:
+ {
+ bool break_state_changed = bool((m_regs.lcr ^ data) & INS8250_LCR_BREAK);
+
m_regs.lcr = data;
- {
int data_bit_count = (m_regs.lcr & INS8250_LCR_BITCOUNT_MASK) + 5;
parity_t parity;
stop_bits_t stop_bits;
@@ -336,6 +338,19 @@ void ins8250_uart_device::ins8250_w(offs_t offset, u8 data)
else
stop_bits = STOP_BITS_2;
+ if (break_state_changed)
+ {
+ int new_out_val = (m_regs.lcr & INS8250_LCR_BREAK) ? 0 : m_txd;
+
+ if (m_regs.mcr & INS8250_MCR_LOOPBACK)
+ {
+ device_serial_interface::rx_w(new_out_val);
+ }
+ else
+ {
+ m_out_tx_cb(new_out_val);
+ }
+ }
set_data_frame(1, data_bit_count, parity, stop_bits);
}
break;
@@ -349,7 +364,10 @@ void ins8250_uart_device::ins8250_w(offs_t offset, u8 data)
if (m_regs.mcr & INS8250_MCR_LOOPBACK)
{
m_out_tx_cb(1);
- device_serial_interface::rx_w(m_txd);
+ if ((m_regs.lcr & INS8250_LCR_BREAK) == 0)
+ {
+ device_serial_interface::rx_w(m_txd);
+ }
m_out_dtr_cb(1);
m_out_rts_cb(1);
m_out_out1_cb(1);
@@ -357,7 +375,10 @@ void ins8250_uart_device::ins8250_w(offs_t offset, u8 data)
}
else
{
- m_out_tx_cb(m_txd);
+ if ((m_regs.lcr & INS8250_LCR_BREAK) == 0)
+ {
+ m_out_tx_cb(m_txd);
+ }
device_serial_interface::rx_w(m_rxd);
m_out_dtr_cb((m_regs.mcr & INS8250_MCR_DTR) ? 0 : 1);
m_out_rts_cb((m_regs.mcr & INS8250_MCR_RTS) ? 0 : 1);
@@ -390,13 +411,16 @@ void ins8250_uart_device::ins8250_w(offs_t offset, u8 data)
*/
m_regs.msr = (m_regs.msr & 0xf0) | (data & 0x0f);
- if ( m_regs.msr & 0x0f )
+ if (m_regs.msr & 0x0f)
trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER);
else
clear_int(COM_INT_PENDING_MODEM_STATUS_REGISTER);
break;
case 7:
- m_regs.scr = data;
+ if (m_device_type >= dev_type::INS8250A)
+ {
+ m_regs.scr = data;
+ }
break;
}
}
@@ -469,7 +493,10 @@ u8 ins8250_uart_device::ins8250_r(offs_t offset)
}
break;
case 7:
- data = m_regs.scr;
+ if (m_device_type >= dev_type::INS8250A)
+ {
+ data = m_regs.scr;
+ }
break;
}
return data;
@@ -568,6 +595,13 @@ void ins8250_uart_device::tra_complete()
void ins8250_uart_device::tra_callback()
{
m_txd = transmit_register_get_data_bit();
+
+ if (m_regs.lcr & INS8250_LCR_BREAK)
+ {
+ // in break mode, don't change transmitted bit
+ return;
+ }
+
if (m_regs.mcr & INS8250_MCR_LOOPBACK)
{
device_serial_interface::rx_w(m_txd);
@@ -585,7 +619,7 @@ void ins8250_uart_device::update_msr()
if (m_regs.mcr & INS8250_MCR_LOOPBACK)
{
- data = (((m_regs.mcr & (INS8250_MCR_OUT1|INS8250_MCR_OUT2)) << 4) | \
+ data = (((m_regs.mcr & (INS8250_MCR_OUT1|INS8250_MCR_OUT2)) << 4) |
((m_regs.mcr & INS8250_MCR_DTR) << 5) | ((m_regs.mcr & INS8250_MCR_RTS) << 3));
change = (m_regs.msr ^ data) >> 4;
if(!(m_regs.msr & 0x40) && (data & 0x40))
@@ -603,31 +637,31 @@ void ins8250_uart_device::update_msr()
trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER);
}
-WRITE_LINE_MEMBER(ins8250_uart_device::dcd_w)
+void ins8250_uart_device::dcd_w(int state)
{
m_dcd = state;
update_msr();
}
-WRITE_LINE_MEMBER(ins8250_uart_device::dsr_w)
+void ins8250_uart_device::dsr_w(int state)
{
m_dsr = state;
update_msr();
}
-WRITE_LINE_MEMBER(ins8250_uart_device::ri_w)
+void ins8250_uart_device::ri_w(int state)
{
m_ri = state;
update_msr();
}
-WRITE_LINE_MEMBER(ins8250_uart_device::cts_w)
+void ins8250_uart_device::cts_w(int state)
{
m_cts = state;
update_msr();
}
-WRITE_LINE_MEMBER(ins8250_uart_device::rx_w)
+void ins8250_uart_device::rx_w(int state)
{
m_rxd = state;
@@ -637,12 +671,6 @@ WRITE_LINE_MEMBER(ins8250_uart_device::rx_w)
void ins8250_uart_device::device_start()
{
- m_out_tx_cb.resolve_safe();
- m_out_dtr_cb.resolve_safe();
- m_out_rts_cb.resolve_safe();
- m_out_int_cb.resolve_safe();
- m_out_out1_cb.resolve_safe();
- m_out_out2_cb.resolve_safe();
set_tra_rate(0);
set_rcv_rate(0);
@@ -689,7 +717,7 @@ void ins8250_uart_device::device_reset()
void ns16550_device::device_start()
{
- m_timeout = timer_alloc();
+ m_timeout = timer_alloc(FUNC(ns16550_device::timeout_expired), this);
ins8250_uart_device::device_start();
save_item(NAME(m_rintlvl));
save_item(NAME(m_rfifo));
@@ -713,13 +741,10 @@ void ns16550_device::device_reset()
ins8250_uart_device::device_reset();
}
-void ns16550_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ns16550_device::timeout_expired)
{
- if(!id)
- {
- trigger_int(COM_INT_PENDING_CHAR_TIMEOUT);
- m_timeout->adjust(attotime::never);
- }
+ trigger_int(COM_INT_PENDING_CHAR_TIMEOUT);
+ m_timeout->adjust(attotime::never);
}
void ns16550_device::push_tx(u8 data)
diff --git a/src/devices/machine/ins8250.h b/src/devices/machine/ins8250.h
index 5f9a6bd1793..8cfff435ae8 100644
--- a/src/devices/machine/ins8250.h
+++ b/src/devices/machine/ins8250.h
@@ -30,12 +30,12 @@ public:
void ins8250_w(offs_t offset, u8 data);
u8 ins8250_r(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER(dcd_w);
- DECLARE_WRITE_LINE_MEMBER(dsr_w);
- DECLARE_WRITE_LINE_MEMBER(ri_w);
- DECLARE_WRITE_LINE_MEMBER(cts_w);
- DECLARE_WRITE_LINE_MEMBER(rx_w);
- DECLARE_READ_LINE_MEMBER(intrpt_r);
+ void dcd_w(int state);
+ void dsr_w(int state);
+ void ri_w(int state);
+ void cts_w(int state);
+ void rx_w(int state);
+ int intrpt_r();
protected:
enum class dev_type {
@@ -117,12 +117,14 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
+
virtual void rcv_complete() override;
virtual void tra_complete() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void set_fcr(u8 data) override;
virtual void push_tx(u8 data) override;
virtual u8 pop_rx() override;
+
+ TIMER_CALLBACK_MEMBER(timeout_expired);
private:
void set_timer() { m_timeout->adjust(attotime::from_hz((clock()*4*8)/(m_regs.dl*16))); }
int m_rintlvl;
diff --git a/src/devices/machine/intelfsh.cpp b/src/devices/machine/intelfsh.cpp
index af8e50dc2d0..d4a417567e1 100644
--- a/src/devices/machine/intelfsh.cpp
+++ b/src/devices/machine/intelfsh.cpp
@@ -38,7 +38,10 @@ enum
FM_ERASEAMD4, // part 4 of AMD erase sequence
FM_BYTEPROGRAM,
FM_BANKSELECT,
- FM_WRITEPAGEATMEL
+ FM_WRITEPAGEATMEL,
+ FM_WRITEBUFFER1, // part 1 of write to buffer sequence
+ FM_WRITEBUFFER2, // part 2 of write to buffer sequence
+ FM_FAST_RESET,
};
@@ -67,6 +70,7 @@ enum
MFG_SYNCMOS = 0x40,
MFG_TI = 0x97,
MFG_TI_OLD = 0x01,
+ MFG_TOSHIBA = 0x98,
MFG_WINBOND_NEX = 0xef,
MFG_WINBOND = 0xda
};
@@ -78,49 +82,56 @@ enum
//**************************************************************************
// device type definition
-DEFINE_DEVICE_TYPE(INTEL_28F016S5, intel_28f016s5_device, "intel_28f016s5", "Intel 28F016S5 Flash")
-DEFINE_DEVICE_TYPE(SHARP_LH28F016S, sharp_lh28f016s_device, "sharp_lh28f016s", "Sharp LH28F016S Flash")
-DEFINE_DEVICE_TYPE(SHARP_LH28F016S_16BIT, sharp_lh28f016s_16bit_device, "sharp_lh28f016s_16bit", "Sharp LH28F016S Flash (16-bit)")
-DEFINE_DEVICE_TYPE(ATMEL_29C010, atmel_29c010_device, "atmel_29c010", "Atmel 29C010 Flash")
-DEFINE_DEVICE_TYPE(AMD_29F010, amd_29f010_device, "amd_29f010", "AMD 29F010 Flash")
-DEFINE_DEVICE_TYPE(AMD_29F040, amd_29f040_device, "amd_29f040", "AMD 29F040 Flash")
-DEFINE_DEVICE_TYPE(AMD_29F080, amd_29f080_device, "amd_29f080", "AMD 29F080 Flash")
-DEFINE_DEVICE_TYPE(AMD_29F400T, amd_29f400t_device, "amd_29f400t", "AMD 29F400T Flash")
-DEFINE_DEVICE_TYPE(AMD_29F800T, amd_29f800t_device, "amd_29f800t", "AMD 29F800T Flash")
-DEFINE_DEVICE_TYPE(AMD_29F800B_16BIT, amd_29f800b_16bit_device, "amd_29f800b_16bit", "AMD 29F800B Flash (16-bit)")
-DEFINE_DEVICE_TYPE(AMD_29LV200T, amd_29lv200t_device, "amd_29lv200t", "AMD 29LV200T Flash")
-DEFINE_DEVICE_TYPE(FUJITSU_29F160TE, fujitsu_29f160te_device, "mbm29f160te", "Fujitsu MBM29F160TE Flash")
-DEFINE_DEVICE_TYPE(FUJITSU_29F016A, fujitsu_29f016a_device, "mbm29f016a", "Fujitsu MBM29F016A Flash")
-DEFINE_DEVICE_TYPE(FUJITSU_29DL164BD, fujitsu_29dl164bd_device, "mbm29dl164bd", "Fujitsu MBM29DL164BD Flash")
-DEFINE_DEVICE_TYPE(FUJITSU_29LV002TC, fujitsu_29lv002tc_device, "mbm29lv002tc", "Fujitsu MBM29LV002TC Flash")
-DEFINE_DEVICE_TYPE(FUJITSU_29LV800B, fujitsu_29lv800b_device, "mbm29lv800b", "Fujitsu MBM29LV800B Flash")
-DEFINE_DEVICE_TYPE(INTEL_E28F400B, intel_e28f400b_device, "intel_e28f400b", "Intel E28F400B Flash")
-DEFINE_DEVICE_TYPE(MACRONIX_29L001MC, macronix_29l001mc_device, "macronix_29l001mc", "Macronix 29L001MC Flash")
-DEFINE_DEVICE_TYPE(MACRONIX_29LV160TMC, macronix_29lv160tmc_device, "macronix_29lv160tmc", "Macronix 29LV160TMC Flash")
-DEFINE_DEVICE_TYPE(TMS_29F040, tms_29f040_device, "tms_29f040", "Texas Instruments 29F040 Flash")
-
-DEFINE_DEVICE_TYPE(PANASONIC_MN63F805MNP, panasonic_mn63f805mnp_device, "panasonic_mn63f805mnp", "Panasonic MN63F805MNP Flash")
-DEFINE_DEVICE_TYPE(SANYO_LE26FV10N1TS, sanyo_le26fv10n1ts_device, "sanyo_le26fv10n1ts", "Sanyo LE26FV10N1TS Flash")
-DEFINE_DEVICE_TYPE(SST_28SF040, sst_28sf040_device, "sst_28sf040", "SST 28SF040 Flash")
-DEFINE_DEVICE_TYPE(SST_39SF040, sst_39sf040_device, "sst_39sf040", "SST 39SF040 Flash")
-DEFINE_DEVICE_TYPE(SST_39VF020, sst_39vf020_device, "sst_39vf020", "SST 39VF020 Flash")
-DEFINE_DEVICE_TYPE(SST_49LF020, sst_49lf020_device, "sst_49lf020", "SST 49LF020 Flash")
-
-DEFINE_DEVICE_TYPE(SHARP_LH28F400, sharp_lh28f400_device, "sharp_lh28f400", "Sharp LH28F400 Flash")
-DEFINE_DEVICE_TYPE(INTEL_E28F008SA, intel_e28f008sa_device, "intel_e28f008sa", "Intel E28F008SA Flash")
-DEFINE_DEVICE_TYPE(INTEL_TE28F160, intel_te28f160_device, "intel_te28f160", "Intel TE28F160 Flash")
-DEFINE_DEVICE_TYPE(SHARP_LH28F160S3, sharp_lh28f160s3_device, "sharp_lh28f160s3", "Sharp LH28F160S3 Flash")
-DEFINE_DEVICE_TYPE(INTEL_TE28F320, intel_te28f320_device, "intel_te28f320", "Intel TE28F320 Flash")
-DEFINE_DEVICE_TYPE(SHARP_LH28F320BF, sharp_lh28f320bf_device, "sharp_lh28f320bf", "Sharp LH28F320BFHE-PBTL Flash")
-DEFINE_DEVICE_TYPE(INTEL_28F320J3D, intel_28f320j3d_device, "intel_28f320j3d", "Intel 28F320J3D Flash")
-DEFINE_DEVICE_TYPE(SPANSION_S29GL064S, spansion_s29gl064s_device, "spansion_s29gl064s", "Spansion / Cypress S29GL064S Flash" )
-DEFINE_DEVICE_TYPE(INTEL_28F320J5, intel_28f320j5_device, "intel_28f320j5", "Intel 28F320J5 Flash")
-
-DEFINE_DEVICE_TYPE(SST_39VF400A, sst_39vf400a_device, "sst_39vf400a", "SST 39VF400A Flash")
-
-DEFINE_DEVICE_TYPE(ATMEL_49F4096, atmel_49f4096_device, "atmel_49f4096", "Atmel AT49F4096 Flash")
-
-DEFINE_DEVICE_TYPE(CAT28F020, cat28f020_device, "cat28f020", "CSI CAT28F020 Flash")
+DEFINE_DEVICE_TYPE(INTEL_28F016S5, intel_28f016s5_device, "intel_28f016s5", "Intel 28F016S5 Flash")
+DEFINE_DEVICE_TYPE(SHARP_LH28F016S, sharp_lh28f016s_device, "sharp_lh28f016s", "Sharp LH28F016S Flash")
+DEFINE_DEVICE_TYPE(SHARP_LH28F016S_16BIT, sharp_lh28f016s_16bit_device, "sharp_lh28f016s_16bit", "Sharp LH28F016S Flash (16-bit)")
+DEFINE_DEVICE_TYPE(ATMEL_29C010, atmel_29c010_device, "atmel_29c010", "Atmel 29C010 Flash")
+DEFINE_DEVICE_TYPE(AMD_29F010, amd_29f010_device, "amd_29f010", "AMD 29F010 Flash")
+DEFINE_DEVICE_TYPE(AMD_29F040, amd_29f040_device, "amd_29f040", "AMD 29F040 Flash")
+DEFINE_DEVICE_TYPE(AMD_29F080, amd_29f080_device, "amd_29f080", "AMD 29F080 Flash")
+DEFINE_DEVICE_TYPE(AMD_29F400T, amd_29f400t_device, "amd_29f400t", "AMD 29F400T Flash")
+DEFINE_DEVICE_TYPE(AMD_29F800T, amd_29f800t_device, "amd_29f800t", "AMD 29F800T Flash")
+DEFINE_DEVICE_TYPE(AMD_29F800B_16BIT, amd_29f800b_16bit_device, "amd_29f800b_16bit", "AMD 29F800B Flash (16-bit)")
+DEFINE_DEVICE_TYPE(AMD_29LV200T, amd_29lv200t_device, "amd_29lv200t", "AMD 29LV200T Flash")
+DEFINE_DEVICE_TYPE(FUJITSU_29F160TE, fujitsu_29f160te_device, "mbm29f160te", "Fujitsu MBM29F160TE Flash")
+DEFINE_DEVICE_TYPE(FUJITSU_29F160TE_16BIT, fujitsu_29f160te_16bit_device, "mbm29f160te_16bit", "Fujitsu MBM29F160TE Flash (16-bit)")
+DEFINE_DEVICE_TYPE(FUJITSU_29F016A, fujitsu_29f016a_device, "mbm29f016a", "Fujitsu MBM29F016A Flash")
+DEFINE_DEVICE_TYPE(FUJITSU_29DL164BD, fujitsu_29dl164bd_device, "mbm29dl164bd", "Fujitsu MBM29DL164BD Flash")
+DEFINE_DEVICE_TYPE(FUJITSU_29LV002TC, fujitsu_29lv002tc_device, "mbm29lv002tc", "Fujitsu MBM29LV002TC Flash")
+DEFINE_DEVICE_TYPE(FUJITSU_29LV800B, fujitsu_29lv800b_device, "mbm29lv800b", "Fujitsu MBM29LV800B Flash")
+DEFINE_DEVICE_TYPE(INTEL_E28F400B, intel_e28f400b_device, "intel_e28f400b", "Intel E28F400B Flash")
+DEFINE_DEVICE_TYPE(MACRONIX_29F008TC, macronix_29f008tc_device, "macronix_29f008tc", "Macronix 29F008TC Flash")
+DEFINE_DEVICE_TYPE(MACRONIX_29F1610MC, macronix_29f1610mc_device, "macronix_29f1610mc", "Macronix 29F1610MC Flash")
+DEFINE_DEVICE_TYPE(MACRONIX_29F1610MC_16BIT, macronix_29f1610mc_16bit_device, "macronix_29f1610mc_16bit", "Macronix 29F1610MC Flash (16-bit)")
+DEFINE_DEVICE_TYPE(MACRONIX_29L001MC, macronix_29l001mc_device, "macronix_29l001mc", "Macronix 29L001MC Flash")
+DEFINE_DEVICE_TYPE(MACRONIX_29LV160TMC, macronix_29lv160tmc_device, "macronix_29lv160tmc", "Macronix 29LV160TMC Flash")
+DEFINE_DEVICE_TYPE(TMS_29F040, tms_29f040_device, "tms_29f040", "Texas Instruments 29F040 Flash")
+
+DEFINE_DEVICE_TYPE(PANASONIC_MN63F805MNP, panasonic_mn63f805mnp_device, "panasonic_mn63f805mnp", "Panasonic MN63F805MNP Flash")
+DEFINE_DEVICE_TYPE(SANYO_LE26FV10N1TS, sanyo_le26fv10n1ts_device, "sanyo_le26fv10n1ts", "Sanyo LE26FV10N1TS Flash")
+DEFINE_DEVICE_TYPE(SST_28SF040, sst_28sf040_device, "sst_28sf040", "SST 28SF040 Flash")
+DEFINE_DEVICE_TYPE(SST_39SF040, sst_39sf040_device, "sst_39sf040", "SST 39SF040 Flash")
+DEFINE_DEVICE_TYPE(SST_39VF020, sst_39vf020_device, "sst_39vf020", "SST 39VF020 Flash")
+DEFINE_DEVICE_TYPE(SST_49LF020, sst_49lf020_device, "sst_49lf020", "SST 49LF020 Flash")
+
+DEFINE_DEVICE_TYPE(SHARP_LH28F400, sharp_lh28f400_device, "sharp_lh28f400", "Sharp LH28F400 Flash")
+DEFINE_DEVICE_TYPE(INTEL_E28F008SA, intel_e28f008sa_device, "intel_e28f008sa", "Intel E28F008SA Flash")
+DEFINE_DEVICE_TYPE(INTEL_TE28F160, intel_te28f160_device, "intel_te28f160", "Intel TE28F160 Flash")
+DEFINE_DEVICE_TYPE(SHARP_LH28F160S3, sharp_lh28f160s3_device, "sharp_lh28f160s3", "Sharp LH28F160S3 Flash")
+DEFINE_DEVICE_TYPE(INTEL_TE28F320, intel_te28f320_device, "intel_te28f320", "Intel TE28F320 Flash")
+DEFINE_DEVICE_TYPE(SHARP_LH28F320BF, sharp_lh28f320bf_device, "sharp_lh28f320bf", "Sharp LH28F320BFHE-PBTL Flash")
+DEFINE_DEVICE_TYPE(INTEL_28F320J3D, intel_28f320j3d_device, "intel_28f320j3d", "Intel 28F320J3D Flash")
+DEFINE_DEVICE_TYPE(SPANSION_S29GL064S, spansion_s29gl064s_device, "spansion_s29gl064s", "Spansion / Cypress S29GL064S Flash")
+DEFINE_DEVICE_TYPE(INTEL_28F320J5, intel_28f320j5_device, "intel_28f320j5", "Intel 28F320J5 Flash")
+DEFINE_DEVICE_TYPE(INTEL_28F640J5, intel_28f640j5_device, "intel_28f640j5", "Intel 28F640J5 Flash")
+
+DEFINE_DEVICE_TYPE(SST_39VF400A, sst_39vf400a_device, "sst_39vf400a", "SST 39VF400A Flash")
+
+DEFINE_DEVICE_TYPE(ATMEL_49F4096, atmel_49f4096_device, "atmel_49f4096", "Atmel AT49F4096 Flash")
+
+DEFINE_DEVICE_TYPE(CAT28F020, cat28f020_device, "cat28f020", "CSI CAT28F020 Flash")
+
+DEFINE_DEVICE_TYPE(TC58FVT800, tc58fvt800_device, "tc58fvt800", "Toshiba TC58FVT800 Flash")
@@ -132,16 +143,15 @@ DEFINE_DEVICE_TYPE(CAT28F020, cat28f020_device, "cat28f0
// intelfsh_device - constructor
//-------------------------------------------------
-intelfsh_device::intelfsh_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant)
+intelfsh_device::intelfsh_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t bits, uint32_t size, uint8_t maker_id, uint16_t device_id)
: device_t(mconfig, type, tag, owner, clock),
device_nvram_interface(mconfig, *this),
m_region(*this, DEVICE_SELF),
- m_type(variant),
- m_size(0),
- m_bits(8),
+ m_size(size),
+ m_bits(bits),
m_addrmask(0),
- m_device_id(0),
- m_maker_id(0),
+ m_device_id(device_id),
+ m_maker_id(maker_id),
m_sector_is_4k(false),
m_sector_is_16k(false),
m_top_boot_sector(false),
@@ -151,377 +161,160 @@ intelfsh_device::intelfsh_device(const machine_config &mconfig, device_type type
m_flash_mode(FM_NORMAL),
m_flash_master_lock(false),
m_timer(nullptr),
- m_bank(0)
+ m_bank(0),
+ m_fast_mode(false)
{
- switch( variant )
- {
- case FLASH_INTEL_28F016S5:
- case FLASH_SHARP_LH28F016S:
- m_bits = 8;
- m_size = 0x200000;
- m_maker_id = MFG_INTEL;
- m_device_id = 0xaa;
- break;
- case FLASH_SHARP_LH28F016S_16BIT:
- m_bits = 16;
- m_size = 0x200000;
- m_maker_id = MFG_INTEL;
- m_device_id = 0xaa;
- break;
- case FLASH_ATMEL_29C010:
- m_bits = 8;
- m_size = 0x20000;
- m_page_size = 0x80;
- m_maker_id = MFG_ATMEL;
- m_device_id = 0xd5;
- break;
- case FLASH_ATMEL_49F4096:
- m_bits = 16;
- m_size = 0x80000;
- m_maker_id = MFG_ATMEL;
- m_device_id = 0x92;
- m_sector_is_16k = true;
- break;
- case FLASH_AMD_29F010:
- m_bits = 8;
- m_size = 0x20000;
- m_maker_id = MFG_AMD;
- m_device_id = 0x20;
- break;
- case FLASH_AMD_29F040:
- m_bits = 8;
- m_size = 0x80000;
- m_maker_id = MFG_AMD;
- m_device_id = 0xa4;
- break;
- case FLASH_AMD_29F080:
- m_bits = 8;
- m_size = 0x100000;
- m_addrmask = 0x7ff;
- m_maker_id = MFG_AMD;
- m_device_id = 0xd5;
- break;
- case FLASH_AMD_29F400T:
- m_bits = 8;
- m_size = 0x80000;
- m_maker_id = MFG_AMD;
- m_device_id = 0x23;
- m_top_boot_sector = true;
- break;
- case FLASH_AMD_29F800T:
- m_bits = 8;
- m_size = 0x100000;
- m_maker_id = MFG_AMD;
- m_device_id = 0xda;
- m_top_boot_sector = true;
- break;
- case FLASH_AMD_29F800B_16BIT:
- m_bits = 16;
- m_size = 0x100000;
- m_maker_id = MFG_AMD;
- m_device_id = 0x2258;
- m_top_boot_sector = false;
- break;
- case FLASH_AMD_29LV200T:
- m_bits = 8;
- m_size = 0x40000;
- m_maker_id = MFG_AMD;
- m_device_id = 0x3b;
- break;
- case FLASH_CAT28F020:
- m_bits = 8;
- m_size = 0x40000;
- m_maker_id = MFG_CATALYST;
- m_device_id = 0xbd;
- break;
- case FLASH_INTEL_28F320J3D:
- m_bits = 16;
- m_size = 0x400000;
- m_maker_id = MFG_INTEL;
- m_device_id = 0x16;
- m_sector_is_4k = true;
- break;
- case FLASH_SPANSION_S29GL064S: // senbbs
- m_bits = 16;
- m_size = 0x800000;
- m_maker_id = MFG_SPANSION;
- m_device_id = 0x227e;
- m_sector_is_4k = false;
- break;
- case FLASH_INTEL_28F320J5: // funkball
- m_bits = 16;
- m_size = 0x400000;
- m_maker_id = MFG_INTEL;
- m_device_id = 0x14;
-// m_sector_is_4k = true; 128kb?
- break;
- case FLASH_SST_39SF040:
- m_bits = 8;
- m_size = 0x80000;
- m_maker_id = MFG_SST;
- m_device_id = 0xb7;
- m_sector_is_4k = true;
- break;
- case FLASH_SST_39VF020:
- m_bits = 8;
- m_size = 0x40000;
- m_maker_id = MFG_SST;
- m_device_id = 0xd6;
- m_sector_is_4k = true;
- break;
- case FLASH_SST_49LF020:
- m_bits = 8;
- m_size = 0x40000;
- m_maker_id = MFG_SST;
- m_device_id = 0x61;
- m_sector_is_4k = true;
- break;
- case FLASH_SST_39VF400A:
- m_bits = 16;
- m_size = 0x80000;
- m_maker_id = MFG_SST;
- m_device_id = 0xd6;
- m_sector_is_4k = true;
- break;
- case FLASH_SHARP_LH28F400:
- m_bits = 16;
- m_size = 0x80000;
- m_maker_id = MFG_SHARP;
- m_device_id = 0xed;
- break;
- case FLASH_INTEL_E28F400B:
- m_bits = 16;
- m_size = 0x80000;
- m_maker_id = MFG_INTEL;
- m_device_id = 0x4471;
- break;
- case FLASH_FUJITSU_29F160TE:
- m_bits = 8;
- m_size = 0x200000;
- m_maker_id = MFG_FUJITSU;
- m_device_id = 0xd2;
- m_top_boot_sector = true;
- break;
- case FLASH_FUJITSU_29F016A:
- m_bits = 8;
- m_size = 0x200000;
- m_maker_id = MFG_FUJITSU;
- m_device_id = 0xad;
- break;
- case FLASH_FUJITSU_29DL164BD:
- m_bits = 8;
- m_size = 0x200000;
- m_maker_id = MFG_FUJITSU;
- m_device_id = 0x35;
- break;
- case FLASH_FUJITSU_29LV002TC:
- m_bits = 8;
- m_size = 0x40000;
- m_maker_id = MFG_FUJITSU;
- m_device_id = 0x40;
- break;
- case FLASH_FUJITSU_29LV800B:
- m_bits = 16;
- m_size = 0x100000;
- m_maker_id = MFG_FUJITSU;
- m_device_id = 0x225b;
- m_bot_boot_sector = true;
- break;
- case FLASH_INTEL_E28F008SA:
- m_bits = 8;
- m_size = 0x100000;
- m_maker_id = MFG_INTEL;
- m_device_id = 0xa2;
- break;
- case FLASH_INTEL_TE28F160:
- case FLASH_SHARP_LH28F160S3:
- m_bits = 16;
- m_size = 0x200000;
- m_maker_id = MFG_SHARP;
- m_device_id = 0xd0;
- break;
- case FLASH_INTEL_TE28F320:
- m_bits = 16;
- m_size = 0x400000;
- m_maker_id = MFG_INTEL;
- m_device_id = 0x8896;
- break;
- case FLASH_SHARP_LH28F320BF:
- m_bits = 16;
- m_size = 0x400000;
- m_maker_id = MFG_SHARP;
- m_device_id = 0xb5;
- break;
- case FLASH_MACRONIX_29L001MC:
- m_bits = 8;
- m_size = 0x20000;
- m_maker_id = MFG_MACRONIX;
- m_device_id = 0x51;
- break;
- case FLASH_MACRONIX_29LV160TMC:
- m_bits = 8;
- m_size = 0x20000;
- m_maker_id = MFG_MACRONIX;
- m_device_id = 0x49;
- m_sector_is_16k = true;
- break;
- case FLASH_PANASONIC_MN63F805MNP:
- m_bits = 8;
- m_size = 0x10000;
- m_maker_id = MFG_PANASONIC;
- m_device_id = 0x1b;
- m_sector_is_4k = true;
- break;
- case FLASH_SANYO_LE26FV10N1TS:
- m_bits = 8;
- m_size = 0x20000;
- m_maker_id = MFG_SANYO;
- m_device_id = 0x13;
- m_sector_is_4k = true;
- break;
- case FLASH_SST_28SF040:
- m_bits = 8;
- m_size = 0x80000;
- m_maker_id = MFG_SST;
- m_device_id = 0x04;
- break;
- case FLASH_TMS_29F040:
- m_bits = 8;
- m_addrmask = 0x7fff;
- m_size = 0x80000;
- m_maker_id = MFG_AMD;
- m_device_id = 0xa4;
- break;
- }
-
- int addrbits;
- for (addrbits = 24; addrbits > 0; addrbits--)
- if ((m_size & (1 << addrbits)) != 0)
- break;
+ assert(bits == 8 || bits == 16);
+ assert(size != 0);
}
-intelfsh8_device::intelfsh8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant)
- : intelfsh_device(mconfig, type, tag, owner, clock, variant) { }
+intelfsh8_device::intelfsh8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t size, uint8_t maker_id, uint16_t device_id)
+ : intelfsh_device(mconfig, type, tag, owner, clock, 8, size, maker_id, device_id) { }
-intelfsh16_device::intelfsh16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant)
- : intelfsh_device(mconfig, type, tag, owner, clock, variant) { }
+intelfsh16_device::intelfsh16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t size, uint8_t maker_id, uint16_t device_id)
+ : intelfsh_device(mconfig, type, tag, owner, clock, 16, size, maker_id, device_id) { }
intel_28f016s5_device::intel_28f016s5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, INTEL_28F016S5, tag, owner, clock, FLASH_INTEL_28F016S5) { }
+ : intelfsh8_device(mconfig, INTEL_28F016S5, tag, owner, clock, 0x200000, MFG_INTEL, 0xaa) { }
fujitsu_29f160te_device::fujitsu_29f160te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, FUJITSU_29F160TE, tag, owner, clock, FLASH_FUJITSU_29F160TE) { }
+ : intelfsh8_device(mconfig, FUJITSU_29F160TE, tag, owner, clock, 0x200000, MFG_FUJITSU, 0xd2) { m_top_boot_sector = true; }
+
+fujitsu_29f160te_16bit_device::fujitsu_29f160te_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : intelfsh16_device(mconfig, FUJITSU_29F160TE_16BIT, tag, owner, clock, 0x200000, MFG_FUJITSU, 0xd2) { m_top_boot_sector = true; m_sector_is_4k = true; }
fujitsu_29f016a_device::fujitsu_29f016a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, FUJITSU_29F016A, tag, owner, clock, FLASH_FUJITSU_29F016A) { }
+ : intelfsh8_device(mconfig, FUJITSU_29F016A, tag, owner, clock, 0x200000, MFG_FUJITSU, 0xad) { }
fujitsu_29dl164bd_device::fujitsu_29dl164bd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, FUJITSU_29DL164BD, tag, owner, clock, FLASH_FUJITSU_29DL164BD) { }
+ : intelfsh8_device(mconfig, FUJITSU_29DL164BD, tag, owner, clock, 0x200000, MFG_FUJITSU, 0x35) { }
fujitsu_29lv002tc_device::fujitsu_29lv002tc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, FUJITSU_29LV002TC, tag, owner, clock, FLASH_FUJITSU_29LV002TC) { }
+ : intelfsh8_device(mconfig, FUJITSU_29LV002TC, tag, owner, clock, 0x40000, MFG_FUJITSU, 0x40) { }
fujitsu_29lv800b_device::fujitsu_29lv800b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, FUJITSU_29LV800B, tag, owner, clock, FLASH_FUJITSU_29LV800B) { }
+ : intelfsh16_device(mconfig, FUJITSU_29LV800B, tag, owner, clock, 0x100000, MFG_FUJITSU, 0x225b) { m_bot_boot_sector = true; }
sharp_lh28f016s_device::sharp_lh28f016s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, SHARP_LH28F016S, tag, owner, clock, FLASH_SHARP_LH28F016S) { }
+ : intelfsh8_device(mconfig, SHARP_LH28F016S, tag, owner, clock, 0x200000, MFG_INTEL, 0xaa) { }
sharp_lh28f016s_16bit_device::sharp_lh28f016s_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, SHARP_LH28F016S_16BIT, tag, owner, clock, FLASH_SHARP_LH28F016S_16BIT) { }
+ : intelfsh16_device(mconfig, SHARP_LH28F016S_16BIT, tag, owner, clock, 0x200000, MFG_INTEL, 0xaa) { }
atmel_29c010_device::atmel_29c010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, ATMEL_29C010, tag, owner, clock, FLASH_ATMEL_29C010) { }
+ : intelfsh8_device(mconfig, ATMEL_29C010, tag, owner, clock, 0x20000, MFG_ATMEL, 0xd5) { m_page_size = 0x80; }
atmel_49f4096_device::atmel_49f4096_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, ATMEL_49F4096, tag, owner, clock, FLASH_ATMEL_49F4096) { }
+ : intelfsh16_device(mconfig, ATMEL_49F4096, tag, owner, clock, 0x80000, MFG_ATMEL, 0x92) { m_sector_is_16k = true; }
amd_29f010_device::amd_29f010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, AMD_29F010, tag, owner, clock, FLASH_AMD_29F010) { }
+ : intelfsh8_device(mconfig, AMD_29F010, tag, owner, clock, 0x20000, MFG_AMD, 0x20) { }
amd_29f040_device::amd_29f040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, AMD_29F040, tag, owner, clock, FLASH_AMD_29F040) { }
+ : intelfsh8_device(mconfig, AMD_29F040, tag, owner, clock, 0x80000, MFG_AMD, 0xa4) { }
amd_29f080_device::amd_29f080_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, AMD_29F080, tag, owner, clock, FLASH_AMD_29F080) { }
+ : intelfsh8_device(mconfig, AMD_29F080, tag, owner, clock, 0x100000, MFG_AMD, 0xd5) { m_addrmask = 0x7ff; }
amd_29f400t_device::amd_29f400t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, AMD_29F400T, tag, owner, clock, FLASH_AMD_29F400T) { }
+ : intelfsh8_device(mconfig, AMD_29F400T, tag, owner, clock, 0x80000, MFG_AMD, 0x23) { m_top_boot_sector = true; }
amd_29f800t_device::amd_29f800t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, AMD_29F800T, tag, owner, clock, FLASH_AMD_29F800T) { }
+ : intelfsh8_device(mconfig, AMD_29F800T, tag, owner, clock, 0x100000, MFG_AMD, 0xda) { m_top_boot_sector = true; }
amd_29f800b_16bit_device::amd_29f800b_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, AMD_29F800B_16BIT, tag, owner, clock, FLASH_AMD_29F800B_16BIT) { }
+ : intelfsh16_device(mconfig, AMD_29F800B_16BIT, tag, owner, clock, 0x100000, MFG_AMD, 0x2258) { m_top_boot_sector = false; }
amd_29lv200t_device::amd_29lv200t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, AMD_29LV200T, tag, owner, clock, FLASH_AMD_29LV200T) { }
+ : intelfsh8_device(mconfig, AMD_29LV200T, tag, owner, clock, 0x40000, MFG_AMD, 0x3b) { }
cat28f020_device::cat28f020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, CAT28F020, tag, owner, clock, FLASH_CAT28F020) { }
+ : intelfsh8_device(mconfig, CAT28F020, tag, owner, clock, 0x40000, MFG_CATALYST, 0xbd) { }
intel_e28f008sa_device::intel_e28f008sa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, INTEL_E28F008SA, tag, owner, clock, FLASH_INTEL_E28F008SA) { }
+ : intelfsh8_device(mconfig, INTEL_E28F008SA, tag, owner, clock, 0x100000, MFG_INTEL, 0xa2) { }
+
+macronix_29f008tc_device::macronix_29f008tc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : intelfsh8_device(mconfig, MACRONIX_29F008TC, tag, owner, clock, 0x100000, MFG_MACRONIX, 0x81) { m_sector_is_4k = true; }
+
+macronix_29f1610mc_device::macronix_29f1610mc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : intelfsh8_device(mconfig, MACRONIX_29F1610MC, tag, owner, clock, 0x200000, MFG_MACRONIX, 0xfa) { }
+
+macronix_29f1610mc_16bit_device::macronix_29f1610mc_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : intelfsh16_device(mconfig, MACRONIX_29F1610MC_16BIT, tag, owner, clock, 0x100000, MFG_MACRONIX, 0xfa) { }
macronix_29l001mc_device::macronix_29l001mc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, MACRONIX_29L001MC, tag, owner, clock, FLASH_MACRONIX_29L001MC) { }
+ : intelfsh8_device(mconfig, MACRONIX_29L001MC, tag, owner, clock, 0x20000, MFG_MACRONIX, 0x51) { }
macronix_29lv160tmc_device::macronix_29lv160tmc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, MACRONIX_29LV160TMC, tag, owner, clock, FLASH_MACRONIX_29LV160TMC) { }
+ : intelfsh8_device(mconfig, MACRONIX_29LV160TMC, tag, owner, clock, 0x20000, MFG_MACRONIX, 0x49) { m_sector_is_16k = true; }
panasonic_mn63f805mnp_device::panasonic_mn63f805mnp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, PANASONIC_MN63F805MNP, tag, owner, clock, FLASH_PANASONIC_MN63F805MNP) { }
+ : intelfsh8_device(mconfig, PANASONIC_MN63F805MNP, tag, owner, clock, 0x10000, MFG_PANASONIC, 0x1b) { m_sector_is_4k = true; }
sanyo_le26fv10n1ts_device::sanyo_le26fv10n1ts_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, SANYO_LE26FV10N1TS, tag, owner, clock, FLASH_SANYO_LE26FV10N1TS) { }
+ : intelfsh8_device(mconfig, SANYO_LE26FV10N1TS, tag, owner, clock, 0x20000, MFG_SANYO, 0x13) { m_sector_is_4k = true; }
sst_28sf040_device::sst_28sf040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, SST_28SF040, tag, owner, clock, FLASH_SST_28SF040) { }
+ : intelfsh8_device(mconfig, SST_28SF040, tag, owner, clock, 0x80000, MFG_SST, 0x04) { }
sst_39sf040_device::sst_39sf040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, SST_39SF040, tag, owner, clock, FLASH_SST_39SF040) { }
+ : intelfsh8_device(mconfig, SST_39SF040, tag, owner, clock, 0x80000, MFG_SST, 0xb7) { m_addrmask = 0x7fff; }
sst_39vf020_device::sst_39vf020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, SST_39VF020, tag, owner, clock, FLASH_SST_39VF020) { }
+ : intelfsh8_device(mconfig, SST_39VF020, tag, owner, clock, 0x40000, MFG_SST, 0xd6) { m_sector_is_4k = true; }
sst_49lf020_device::sst_49lf020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, SST_49LF020, tag, owner, clock, FLASH_SST_49LF020) { }
+ : intelfsh8_device(mconfig, SST_49LF020, tag, owner, clock, 0x40000, MFG_SST, 0x61) { m_sector_is_4k = true; }
sharp_lh28f400_device::sharp_lh28f400_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, SHARP_LH28F400, tag, owner, clock, FLASH_SHARP_LH28F400) { }
+ : intelfsh16_device(mconfig, SHARP_LH28F400, tag, owner, clock, 0x80000, MFG_SHARP, 0xed) { }
intel_te28f160_device::intel_te28f160_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, INTEL_TE28F160, tag, owner, clock, FLASH_INTEL_TE28F160) { }
+ : intelfsh16_device(mconfig, INTEL_TE28F160, tag, owner, clock, 0x200000, MFG_SHARP, 0xd0) { }
sharp_lh28f160s3_device::sharp_lh28f160s3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, SHARP_LH28F160S3, tag, owner, clock, FLASH_SHARP_LH28F160S3) { }
+ : intelfsh16_device(mconfig, SHARP_LH28F160S3, tag, owner, clock, 0x200000, MFG_SHARP, 0xd0) { }
intel_te28f320_device::intel_te28f320_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, INTEL_TE28F320, tag, owner, clock, FLASH_INTEL_TE28F320) { }
+ : intelfsh16_device(mconfig, INTEL_TE28F320, tag, owner, clock, 0x400000, MFG_INTEL, 0x8896) { }
spansion_s29gl064s_device::spansion_s29gl064s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, SPANSION_S29GL064S, tag, owner, clock, FLASH_SPANSION_S29GL064S) { }
+ : intelfsh16_device(mconfig, SPANSION_S29GL064S, tag, owner, clock, 0x800000, MFG_SPANSION, 0x227e)
+{
+ // senbbs
+ m_sector_is_4k = false;
+}
intel_e28f400b_device::intel_e28f400b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, INTEL_E28F400B, tag, owner, clock, FLASH_INTEL_E28F400B) { }
+ : intelfsh16_device(mconfig, INTEL_E28F400B, tag, owner, clock, 0x80000, MFG_INTEL, 0x4471) { }
sharp_lh28f320bf_device::sharp_lh28f320bf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, SHARP_LH28F320BF, tag, owner, clock, FLASH_SHARP_LH28F320BF) { }
+ : intelfsh16_device(mconfig, SHARP_LH28F320BF, tag, owner, clock, 0x400000, MFG_SHARP, 0xb5) { }
intel_28f320j3d_device::intel_28f320j3d_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, INTEL_28F320J3D, tag, owner, clock, FLASH_INTEL_28F320J3D) { }
+ : intelfsh16_device(mconfig, INTEL_28F320J3D, tag, owner, clock, 0x400000, MFG_INTEL, 0x16) { m_sector_is_4k = true; }
intel_28f320j5_device::intel_28f320j5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, INTEL_28F320J5, tag, owner, clock, FLASH_INTEL_28F320J5) { }
+ : intelfsh16_device(mconfig, INTEL_28F320J5, tag, owner, clock, 0x400000, MFG_INTEL, 0x14)
+{
+ // funkball
+// m_sector_is_4k = true; 128kb?
+}
+intel_28f640j5_device::intel_28f640j5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : intelfsh16_device(mconfig, INTEL_28F640J5, tag, owner, clock, 0x800000, MFG_INTEL, 0x15) { }
sst_39vf400a_device::sst_39vf400a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh16_device(mconfig, SST_39VF400A, tag, owner, clock, FLASH_SST_39VF400A) { }
+ : intelfsh16_device(mconfig, SST_39VF400A, tag, owner, clock, 0x80000, MFG_SST, 0xd6) { m_sector_is_4k = true; }
tms_29f040_device::tms_29f040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : intelfsh8_device(mconfig, TMS_29F040, tag, owner, clock, FLASH_TMS_29F040) { }
+ : intelfsh8_device(mconfig, TMS_29F040, tag, owner, clock, 0x80000, MFG_AMD, 0xa4) { m_addrmask = 0x7fff; }
+
+tc58fvt800_device::tc58fvt800_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : intelfsh16_device(mconfig, TC58FVT800, tag, owner, clock, 0x100000, MFG_TOSHIBA, 0x4f) { m_top_boot_sector = true; }
//-------------------------------------------------
// device_start - device-specific startup
@@ -530,20 +323,30 @@ tms_29f040_device::tms_29f040_device(const machine_config &mconfig, const char *
void intelfsh_device::device_start()
{
m_data = std::make_unique<uint8_t []>(m_size);
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(intelfsh_device::delay_tick), this);
save_item( NAME(m_status) );
save_item( NAME(m_flash_mode) );
save_item( NAME(m_flash_master_lock) );
+ save_item( NAME(m_fast_mode) );
save_pointer( &m_data[0], "m_data", m_size);
}
+//-------------------------------------------------
+// is_ready - emulates the *Busy/Ready pin on some
+// flash devices.
+//-------------------------------------------------
+
+bool intelfsh_device::is_ready()
+{
+ return (m_status & 0x80) ? true : false;
+}
//-------------------------------------------------
-// device_timer - handler timer events
+// delay_tick - handle delayed commands/events
//-------------------------------------------------
-void intelfsh_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(intelfsh_device::delay_tick)
{
switch( m_flash_mode )
{
@@ -553,6 +356,7 @@ void intelfsh_device::device_timer(emu_timer &timer, device_timer_id id, int par
case FM_ERASEAMD4:
m_flash_mode = FM_NORMAL;
+ m_status = 0x80;
break;
}
}
@@ -598,9 +402,10 @@ void intelfsh_device::nvram_default()
// .nv file
//-------------------------------------------------
-void intelfsh_device::nvram_read(emu_file &file)
+bool intelfsh_device::nvram_read(util::read_stream &file)
{
- file.read(&m_data[0], m_size);
+ auto const [err, actual] = read(file, &m_data[0], m_size);
+ return !err && (actual == m_size);
}
@@ -609,9 +414,10 @@ void intelfsh_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void intelfsh_device::nvram_write(emu_file &file)
+bool intelfsh_device::nvram_write(util::write_stream &file)
{
- file.write(&m_data[0], m_size);
+ auto const [err, actual] = write(file, &m_data[0], m_size);
+ return !err;
}
@@ -639,8 +445,12 @@ uint32_t intelfsh_device::read_full(uint32_t address)
}
break;
case FM_READSTATUS:
+ case FM_WRITEBUFFER2:
data = m_status;
break;
+ case FM_WRITEBUFFER1:
+ data = 0x80; // extended status register for write buffer flag
+ break;
case FM_READAMDID3:
if ((m_maker_id == MFG_FUJITSU && m_device_id == 0x35) || (m_maker_id == MFG_AMD && m_device_id == 0x3b))
{
@@ -701,7 +511,10 @@ uint32_t intelfsh_device::read_full(uint32_t address)
break;
case FM_ERASEAMD4:
// reads outside of the erasing sector return normal data
- if ((address < m_erase_sector) || (address >= m_erase_sector+(64*1024)))
+ if (
+ !(m_maker_id == MFG_FUJITSU && m_device_id == 0xad) /* Firebeat: pop'n music will poll sector 0 for status updates even when clearing section 1 and beyond */
+ && ((address < m_erase_sector) || (address >= m_erase_sector+(64*1024)))
+ )
{
switch( m_bits )
{
@@ -750,15 +563,18 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
case 0xff: // reset chip mode
m_flash_mode = FM_NORMAL;
break;
- case 0x90: // read ID
- m_flash_mode = FM_READID;
+ case 0x90:
+ if ( m_fast_mode && m_maker_id == MFG_FUJITSU ) // reset from fast mode (when fast mode is enabled)
+ m_flash_mode = FM_FAST_RESET;
+ else // read ID
+ m_flash_mode = FM_READID;
break;
case 0x40:
case 0x10: // program
m_flash_mode = FM_WRITEPART1;
break;
case 0x50: // clear status reg
- if ((m_type == FLASH_SST_49LF020) && (m_flash_mode == FM_NORMAL))
+ if ((m_maker_id == MFG_SST && m_device_id == 0x61) && (m_flash_mode == FM_NORMAL))
logerror("Invalid flash mode byte %x\n", data & 0xff);
else
{
@@ -767,7 +583,7 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
}
break;
case 0x20: // block erase
- if (m_type == FLASH_SST_49LF020)
+ if (m_maker_id == MFG_SST && m_device_id == 0x61)
logerror("Unknown flash mode byte %x\n", data & 0xff);
else
m_flash_mode = FM_CLEARPART1;
@@ -778,6 +594,12 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
case 0x70: // read status
m_flash_mode = FM_READSTATUS;
break;
+ case 0xa0: // fast program (fast mode must be enabled)
+ if ( m_fast_mode && m_maker_id == MFG_FUJITSU )
+ m_flash_mode = FM_BYTEPROGRAM;
+ else
+ logerror( "%s: Unknown flash mode byte %x\n", machine().describe_context(), data & 0xff );
+ break;
case 0xaa: // AMD ID select part 1
if( ( address & 0xfff ) == 0x555 )
{
@@ -788,8 +610,15 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
m_flash_mode = FM_READAMDID1;
}
break;
+ case 0xe8:
+ // Write to buffer (Intel StrataFlash series)
+ if ( m_maker_id == MFG_INTEL && m_device_id >= 0x14 && m_device_id <= 0x16 )
+ m_flash_mode = FM_WRITEBUFFER1;
+ else
+ logerror( "%s: Unknown flash mode byte %x\n", machine().describe_context(), data & 0xff );
+ break;
default:
- logerror( "Unknown flash mode byte %x\n", data & 0xff );
+ logerror( "%s: Unknown flash mode byte %x\n", machine().describe_context(), data & 0xff );
break;
}
break;
@@ -848,7 +677,7 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
}
else if( ( address & 0xffff ) == 0x5555 && ( data & 0xff ) == 0xa0 )
{
- if (m_type == FLASH_ATMEL_29C010)
+ if (m_maker_id == MFG_ATMEL && m_device_id == 0xd5)
{
m_flash_mode = FM_WRITEPAGEATMEL;
m_byte_count = 0;
@@ -896,6 +725,12 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
{
m_flash_mode = FM_NORMAL;
}
+ // Fast mode
+ else if( ( ( address & 0xfff ) == 0xaaa || ( address & 0xfff ) == 0x555 ) && ( data & 0xff ) == 0x20 )
+ {
+ m_flash_mode = FM_NORMAL;
+ m_fast_mode = true;
+ }
else
{
logerror( "unexpected %08x=%02x in FM_READAMDID2\n", address, data & 0xff );
@@ -1092,7 +927,7 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
break;
}
m_status = 0x80;
- if (m_type == FLASH_SST_28SF040)
+ if (m_maker_id == MFG_SST && m_device_id == 0x04)
m_flash_mode = FM_NORMAL;
else
m_flash_mode = FM_READSTATUS;
@@ -1122,7 +957,7 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
case FM_CLEARPART1:
if( ( data & 0xff ) == 0xd0 )
{
- if (m_type == FLASH_SST_28SF040)
+ if (m_maker_id == MFG_SST && m_device_id == 0x04)
{
// clear the 256 bytes block containing the current address to all 0xffs
uint32_t base = address * ((m_bits == 16) ? 2 : 1);
@@ -1130,7 +965,7 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
m_timer->adjust( attotime::from_msec( 4 ) );
}
- else if (m_type == FLASH_INTEL_E28F400B)
+ else if (m_maker_id == MFG_INTEL && m_device_id == 0x4471)
{
// 00000-03fff - 16KB boot block (may be write protected via external pins)
// 04000-05fff - 8KB parameter block
@@ -1203,11 +1038,79 @@ void intelfsh_device::write_full(uint32_t address, uint32_t data)
logerror( "unexpected %08x=%02x in FM_SETMASTER:\n", address, data & 0xff );
break;
}
- m_flash_mode = FM_NORMAL;
+ m_flash_mode = FM_READSTATUS;
+ break;
+ case FM_WRITEBUFFER1:
+ // Datasheets don't specify what happens when the word count is outside of
+ // the valid range so clamp and pray
+ if ( m_bits == 16 )
+ m_write_buffer_count = std::min<uint32_t>(data, 0xf) + 1;
+ else
+ m_write_buffer_count = std::min<uint32_t>(data, 0x1f) + 1;
+
+ m_status = 0x80;
+ m_flash_mode = FM_WRITEBUFFER2;
+ m_byte_count = 0;
+ break;
+ case FM_WRITEBUFFER2:
+ {
+ if ( m_byte_count < m_write_buffer_count )
+ {
+ if ( m_byte_count == 0 )
+ m_write_buffer_start_address = address;
+
+ if ( address >= m_write_buffer_start_address + m_write_buffer_count )
+ {
+ // All subsequent addresses must lie within the start address plus the count
+ // Set error bits and abort
+ m_status = (1 << 4) | (1 << 5);
+ m_flash_mode = FM_READSTATUS;
+ }
+ else
+ {
+ if ( m_bits == 8 )
+ {
+ m_write_buffer[m_byte_count] = data;
+ }
+ else
+ {
+ m_write_buffer[m_byte_count * 2] = data >> 8;
+ m_write_buffer[m_byte_count * 2 + 1] = data;
+ }
+
+ m_byte_count++;
+ }
+ }
+ else
+ {
+ if ( ( data & 0xff ) == 0xd0 )
+ {
+ // Confirmation byte received, commit buffered data
+ uint32_t base = m_write_buffer_start_address * ((m_bits == 16) ? 2 : 1);
+ uint32_t len = m_write_buffer_count * ((m_bits == 16) ? 2 : 1);
+ memcpy(&m_data[base], m_write_buffer, len);
+ m_status = 0x80;
+ }
+ else
+ {
+ // Invalid Command/Sequence, set error bits and abort
+ m_status = (1 << 4) | (1 << 5);
+ }
+
+ m_flash_mode = FM_READSTATUS;
+ }
+ }
break;
case FM_BANKSELECT:
m_bank = data & 0xff;
m_flash_mode = FM_NORMAL;
break;
+ case FM_FAST_RESET:
+ if ( ( data & 0xff ) == 0xf0 || ( data & 0xff ) == 0 ) {
+ m_fast_mode = false;
+ m_flash_mode = FM_NORMAL;
+ } else
+ logerror( "unexpected %08x=%02x in FM_FAST_RESET:\n", address, data & 0xff );
+ break;
}
}
diff --git a/src/devices/machine/intelfsh.h b/src/devices/machine/intelfsh.h
index 8001b2fc5ce..9f17487c6be 100644
--- a/src/devices/machine/intelfsh.h
+++ b/src/devices/machine/intelfsh.h
@@ -13,94 +13,57 @@ class intelfsh_device : public device_t,
public device_nvram_interface
{
public:
- enum
- {
- // 8-bit variants
- FLASH_INTEL_28F016S5 = 0x0800,
- FLASH_FUJITSU_29F160TE,
- FLASH_FUJITSU_29F016A,
- FLASH_FUJITSU_29DL164BD,
- FLASH_FUJITSU_29LV002TC,
- FLASH_FUJITSU_29LV800B,
- FLASH_ATMEL_29C010,
- FLASH_AMD_29F010,
- FLASH_AMD_29F040,
- FLASH_AMD_29F080,
- FLASH_AMD_29F400T,
- FLASH_AMD_29F800T,
- FLASH_AMD_29F800B_16BIT,
- FLASH_AMD_29LV200T,
- FLASH_CAT28F020,
- FLASH_SHARP_LH28F016S,
- FLASH_SHARP_LH28F016S_16BIT,
- FLASH_INTEL_E28F008SA,
- FLASH_MACRONIX_29L001MC,
- FLASH_MACRONIX_29LV160TMC,
- FLASH_PANASONIC_MN63F805MNP,
- FLASH_SANYO_LE26FV10N1TS,
- FLASH_SST_28SF040,
- FLASH_SST_39SF040,
- FLASH_SST_39VF020,
- FLASH_SST_49LF020,
- FLASH_TMS_29F040,
-
- // 16-bit variants
- FLASH_SHARP_LH28F400 = 0x1000,
- FLASH_INTEL_E28F400B,
- FLASH_INTEL_TE28F160,
- FLASH_SHARP_LH28F160S3,
- FLASH_INTEL_TE28F320,
- FLASH_SHARP_LH28F320BF,
- FLASH_INTEL_28F320J3D,
- FLASH_SPANSION_S29GL064S,
- FLASH_INTEL_28F320J5,
- FLASH_SST_39VF400A,
- FLASH_ATMEL_49F4096
- };
-
uint8_t *base() { return &m_data[0]; }
+ bool is_ready();
+
protected:
// construction/destruction
- intelfsh_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
+ intelfsh_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t bits, uint32_t size, uint8_t maker_id, uint16_t device_id);
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
// derived helpers
uint32_t read_full(uint32_t offset);
void write_full(uint32_t offset, uint32_t data);
+ TIMER_CALLBACK_MEMBER(delay_tick);
+
optional_memory_region m_region;
// configuration state
- uint32_t m_type;
- int32_t m_size;
- uint8_t m_bits;
- uint32_t m_addrmask;
- uint16_t m_device_id;
- uint8_t m_maker_id;
+ uint32_t m_size;
+ uint8_t m_bits;
+ uint32_t m_addrmask;
+ uint16_t m_device_id;
+ uint8_t m_maker_id;
bool m_sector_is_4k;
bool m_sector_is_16k;
bool m_top_boot_sector;
bool m_bot_boot_sector;
- uint8_t m_page_size;
+ uint8_t m_page_size;
// internal state
std::unique_ptr<uint8_t[]> m_data;
- uint8_t m_status;
- int32_t m_erase_sector;
- int32_t m_flash_mode;
+ uint8_t m_status;
+ int32_t m_erase_sector;
+ int32_t m_flash_mode;
bool m_flash_master_lock;
emu_timer * m_timer;
- int32_t m_bank;
- uint8_t m_byte_count;
+ int32_t m_bank;
+ uint8_t m_byte_count;
+
+ uint8_t m_write_buffer[32];
+ uint32_t m_write_buffer_start_address;
+ uint32_t m_write_buffer_count;
+
+ bool m_fast_mode;
};
@@ -118,7 +81,7 @@ public:
protected:
// construction/destruction
- intelfsh8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
+ intelfsh8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t size, uint8_t maker_id, uint16_t device_id);
};
@@ -136,7 +99,7 @@ public:
protected:
// construction/destruction
- intelfsh16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
+ intelfsh16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t size, uint8_t maker_id, uint16_t device_id);
};
@@ -173,12 +136,6 @@ public:
fujitsu_29lv002tc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
-class fujitsu_29lv800b_device : public intelfsh16_device
-{
-public:
- fujitsu_29lv800b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
-};
-
class atmel_29c010_device : public intelfsh8_device
{
public:
@@ -215,12 +172,6 @@ public:
amd_29f800t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
-class amd_29f800b_16bit_device : public intelfsh16_device
-{
-public:
- amd_29f800b_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
-};
-
class amd_29lv200t_device : public intelfsh8_device
{
public:
@@ -233,16 +184,22 @@ public:
sharp_lh28f016s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
-class sharp_lh28f016s_16bit_device : public intelfsh16_device
+class intel_e28f008sa_device : public intelfsh8_device
{
public:
- sharp_lh28f016s_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ intel_e28f008sa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
-class intel_e28f008sa_device : public intelfsh8_device
+class macronix_29f008tc_device : public intelfsh8_device
{
public:
- intel_e28f008sa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ macronix_29f008tc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class macronix_29f1610mc_device : public intelfsh8_device
+{
+public:
+ macronix_29f1610mc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
class macronix_29l001mc_device : public intelfsh8_device
@@ -299,7 +256,19 @@ public:
tms_29f040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
+class cat28f020_device : public intelfsh8_device
+{
+public:
+ cat28f020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
// 16-bit variants
+class fujitsu_29f160te_16bit_device : public intelfsh16_device
+{
+public:
+ fujitsu_29f160te_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
class sharp_lh28f400_device : public intelfsh16_device
{
public:
@@ -354,6 +323,12 @@ public:
intel_28f320j5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
+class intel_28f640j5_device : public intelfsh16_device
+{
+public:
+ intel_28f640j5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
class sst_39vf400a_device : public intelfsh16_device
{
public:
@@ -366,53 +341,83 @@ public:
atmel_49f4096_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
-class cat28f020_device : public intelfsh8_device
+class tc58fvt800_device : public intelfsh16_device
{
public:
- cat28f020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ tc58fvt800_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class fujitsu_29lv800b_device : public intelfsh16_device
+{
+public:
+ fujitsu_29lv800b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class amd_29f800b_16bit_device : public intelfsh16_device
+{
+public:
+ amd_29f800b_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class sharp_lh28f016s_16bit_device : public intelfsh16_device
+{
+public:
+ sharp_lh28f016s_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class macronix_29f1610mc_16bit_device : public intelfsh16_device
+{
+public:
+ macronix_29f1610mc_16bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
// device type definition
-DECLARE_DEVICE_TYPE(INTEL_28F016S5, intel_28f016s5_device)
-DECLARE_DEVICE_TYPE(SHARP_LH28F016S, sharp_lh28f016s_device)
-DECLARE_DEVICE_TYPE(SHARP_LH28F016S_16BIT, sharp_lh28f016s_16bit_device)
-DECLARE_DEVICE_TYPE(ATMEL_29C010, atmel_29c010_device)
-DECLARE_DEVICE_TYPE(AMD_29F010, amd_29f010_device)
-DECLARE_DEVICE_TYPE(AMD_29F040, amd_29f040_device)
-DECLARE_DEVICE_TYPE(AMD_29F080, amd_29f080_device)
-DECLARE_DEVICE_TYPE(AMD_29F400T, amd_29f400t_device)
-DECLARE_DEVICE_TYPE(AMD_29F800T, amd_29f800t_device)
-DECLARE_DEVICE_TYPE(AMD_29F800B_16BIT, amd_29f800b_16bit_device)
-DECLARE_DEVICE_TYPE(AMD_29LV200T, amd_29lv200t_device)
-DECLARE_DEVICE_TYPE(FUJITSU_29F160TE, fujitsu_29f160te_device)
-DECLARE_DEVICE_TYPE(FUJITSU_29F016A, fujitsu_29f016a_device)
-DECLARE_DEVICE_TYPE(FUJITSU_29DL164BD, fujitsu_29dl164bd_device)
-DECLARE_DEVICE_TYPE(FUJITSU_29LV002TC, fujitsu_29lv002tc_device)
-DECLARE_DEVICE_TYPE(FUJITSU_29LV800B, fujitsu_29lv800b_device)
-DECLARE_DEVICE_TYPE(INTEL_E28F400B, intel_e28f400b_device)
-DECLARE_DEVICE_TYPE(MACRONIX_29L001MC, macronix_29l001mc_device)
-DECLARE_DEVICE_TYPE(MACRONIX_29LV160TMC, macronix_29lv160tmc_device)
-DECLARE_DEVICE_TYPE(TMS_29F040, tms_29f040_device)
-
-DECLARE_DEVICE_TYPE(PANASONIC_MN63F805MNP, panasonic_mn63f805mnp_device)
-DECLARE_DEVICE_TYPE(SANYO_LE26FV10N1TS, sanyo_le26fv10n1ts_device)
-DECLARE_DEVICE_TYPE(SST_28SF040, sst_28sf040_device)
-DECLARE_DEVICE_TYPE(SST_39SF040, sst_39sf040_device)
-DECLARE_DEVICE_TYPE(SST_39VF020, sst_39vf020_device)
-DECLARE_DEVICE_TYPE(SST_49LF020, sst_49lf020_device)
-
-DECLARE_DEVICE_TYPE(SHARP_LH28F400, sharp_lh28f400_device)
-DECLARE_DEVICE_TYPE(INTEL_E28F008SA, intel_e28f008sa_device)
-DECLARE_DEVICE_TYPE(INTEL_TE28F160, intel_te28f160_device)
-DECLARE_DEVICE_TYPE(SHARP_LH28F160S3, sharp_lh28f160s3_device)
-DECLARE_DEVICE_TYPE(INTEL_TE28F320, intel_te28f320_device)
-DECLARE_DEVICE_TYPE(SPANSION_S29GL064S, spansion_s29gl064s_device)
-DECLARE_DEVICE_TYPE(SHARP_LH28F320BF, sharp_lh28f320bf_device)
-DECLARE_DEVICE_TYPE(INTEL_28F320J3D, intel_28f320j3d_device)
-DECLARE_DEVICE_TYPE(INTEL_28F320J5, intel_28f320j5_device)
-DECLARE_DEVICE_TYPE(SST_39VF400A, sst_39vf400a_device)
-DECLARE_DEVICE_TYPE(ATMEL_49F4096, atmel_49f4096_device)
-DECLARE_DEVICE_TYPE(CAT28F020, cat28f020_device)
+DECLARE_DEVICE_TYPE(INTEL_28F016S5, intel_28f016s5_device)
+DECLARE_DEVICE_TYPE(SHARP_LH28F016S, sharp_lh28f016s_device)
+DECLARE_DEVICE_TYPE(SHARP_LH28F016S_16BIT, sharp_lh28f016s_16bit_device)
+DECLARE_DEVICE_TYPE(ATMEL_29C010, atmel_29c010_device)
+DECLARE_DEVICE_TYPE(AMD_29F010, amd_29f010_device)
+DECLARE_DEVICE_TYPE(AMD_29F040, amd_29f040_device)
+DECLARE_DEVICE_TYPE(AMD_29F080, amd_29f080_device)
+DECLARE_DEVICE_TYPE(AMD_29F400T, amd_29f400t_device)
+DECLARE_DEVICE_TYPE(AMD_29F800T, amd_29f800t_device)
+DECLARE_DEVICE_TYPE(AMD_29F800B_16BIT, amd_29f800b_16bit_device)
+DECLARE_DEVICE_TYPE(AMD_29LV200T, amd_29lv200t_device)
+DECLARE_DEVICE_TYPE(FUJITSU_29F160TE, fujitsu_29f160te_device)
+DECLARE_DEVICE_TYPE(FUJITSU_29F160TE_16BIT, fujitsu_29f160te_16bit_device)
+DECLARE_DEVICE_TYPE(FUJITSU_29F016A, fujitsu_29f016a_device)
+DECLARE_DEVICE_TYPE(FUJITSU_29DL164BD, fujitsu_29dl164bd_device)
+DECLARE_DEVICE_TYPE(FUJITSU_29LV002TC, fujitsu_29lv002tc_device)
+DECLARE_DEVICE_TYPE(FUJITSU_29LV800B, fujitsu_29lv800b_device)
+DECLARE_DEVICE_TYPE(INTEL_E28F400B, intel_e28f400b_device)
+DECLARE_DEVICE_TYPE(MACRONIX_29F008TC, macronix_29f008tc_device)
+DECLARE_DEVICE_TYPE(MACRONIX_29F1610MC, macronix_29f1610mc_device)
+DECLARE_DEVICE_TYPE(MACRONIX_29F1610MC_16BIT,macronix_29f1610mc_16bit_device)
+DECLARE_DEVICE_TYPE(MACRONIX_29L001MC, macronix_29l001mc_device)
+DECLARE_DEVICE_TYPE(MACRONIX_29LV160TMC, macronix_29lv160tmc_device)
+DECLARE_DEVICE_TYPE(TMS_29F040, tms_29f040_device)
+
+DECLARE_DEVICE_TYPE(PANASONIC_MN63F805MNP, panasonic_mn63f805mnp_device)
+DECLARE_DEVICE_TYPE(SANYO_LE26FV10N1TS, sanyo_le26fv10n1ts_device)
+DECLARE_DEVICE_TYPE(SST_28SF040, sst_28sf040_device)
+DECLARE_DEVICE_TYPE(SST_39SF040, sst_39sf040_device)
+DECLARE_DEVICE_TYPE(SST_39VF020, sst_39vf020_device)
+DECLARE_DEVICE_TYPE(SST_49LF020, sst_49lf020_device)
+
+DECLARE_DEVICE_TYPE(SHARP_LH28F400, sharp_lh28f400_device)
+DECLARE_DEVICE_TYPE(INTEL_E28F008SA, intel_e28f008sa_device)
+DECLARE_DEVICE_TYPE(INTEL_TE28F160, intel_te28f160_device)
+DECLARE_DEVICE_TYPE(SHARP_LH28F160S3, sharp_lh28f160s3_device)
+DECLARE_DEVICE_TYPE(INTEL_TE28F320, intel_te28f320_device)
+DECLARE_DEVICE_TYPE(SPANSION_S29GL064S, spansion_s29gl064s_device)
+DECLARE_DEVICE_TYPE(SHARP_LH28F320BF, sharp_lh28f320bf_device)
+DECLARE_DEVICE_TYPE(INTEL_28F320J3D, intel_28f320j3d_device)
+DECLARE_DEVICE_TYPE(INTEL_28F320J5, intel_28f320j5_device)
+DECLARE_DEVICE_TYPE(INTEL_28F640J5, intel_28f640j5_device)
+DECLARE_DEVICE_TYPE(SST_39VF400A, sst_39vf400a_device)
+DECLARE_DEVICE_TYPE(ATMEL_49F4096, atmel_49f4096_device)
+DECLARE_DEVICE_TYPE(CAT28F020, cat28f020_device)
+DECLARE_DEVICE_TYPE(TC58FVT800, tc58fvt800_device)
#endif // MAME_MACHINE_INTELFSH_H
diff --git a/src/devices/machine/iopdma.cpp b/src/devices/machine/iopdma.cpp
index 784bc16b515..8ca904d1747 100644
--- a/src/devices/machine/iopdma.cpp
+++ b/src/devices/machine/iopdma.cpp
@@ -14,6 +14,8 @@
#include "cpu/mips/ps2vu.h"
+#include <algorithm>
+
DEFINE_DEVICE_TYPE(SONYIOP_DMA, iop_dma_device, "iopdma", "PlayStation 2 IOP DMAC")
@@ -72,8 +74,8 @@ void iop_dma_device::device_start()
void iop_dma_device::device_reset()
{
- memset(m_channels, 0, sizeof(channel_t) * 16);
- memset(m_int_ctrl, 0, sizeof(intctrl_t) * 2);
+ std::fill(std::begin(m_channels), std::end(m_channels), channel_t());
+ std::fill(std::begin(m_int_ctrl), std::end(m_int_ctrl), intctrl_t{ 0, 0, false });
m_dpcr[0] = 0;
m_dpcr[1] = 0;
m_dicr[0] = 0;
diff --git a/src/devices/machine/iopsio2.cpp b/src/devices/machine/iopsio2.cpp
index 6ffe90c0737..c5b6de09546 100644
--- a/src/devices/machine/iopsio2.cpp
+++ b/src/devices/machine/iopsio2.cpp
@@ -32,7 +32,7 @@ iop_sio2_device::~iop_sio2_device()
void iop_sio2_device::device_start()
{
if (!m_response_timer)
- m_response_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_sio2_device::response_timer), this));
+ m_response_timer = timer_alloc(FUNC(iop_sio2_device::response_timer), this);
save_item(NAME(m_buffer));
save_item(NAME(m_curr_byte));
diff --git a/src/devices/machine/ioptimer.cpp b/src/devices/machine/ioptimer.cpp
index 487c795ef26..62f19d77988 100644
--- a/src/devices/machine/ioptimer.cpp
+++ b/src/devices/machine/ioptimer.cpp
@@ -36,13 +36,11 @@ iop_timer_device::iop_timer_device(const machine_config &mconfig, const char *ta
void iop_timer_device::device_start()
{
- m_int_cb.resolve_safe();
-
if (!m_compare_timer)
- m_compare_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_timer_device::compare), this));
+ m_compare_timer = timer_alloc(FUNC(iop_timer_device::compare), this);
if (!m_overflow_timer)
- m_overflow_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(iop_timer_device::overflow), this));
+ m_overflow_timer = timer_alloc(FUNC(iop_timer_device::overflow), this);
}
void iop_timer_device::device_reset()
@@ -79,11 +77,8 @@ void iop_timer_device::update_gate()
void iop_timer_device::update_interrupts()
{
- if (!m_int_cb.isnull())
- {
- bool interrupt = m_ienable && ((m_ovf_int && m_ovf_int_enabled) || (m_cmp_int && m_cmp_int_enabled));
- m_int_cb(interrupt);
- }
+ bool interrupt = m_ienable && ((m_ovf_int && m_ovf_int_enabled) || (m_cmp_int && m_cmp_int_enabled));
+ m_int_cb(interrupt);
}
void iop_timer_device::update_compare_timer()
diff --git a/src/devices/machine/it8705f.cpp b/src/devices/machine/it8705f.cpp
new file mode 100644
index 00000000000..5a001cb9af0
--- /dev/null
+++ b/src/devices/machine/it8705f.cpp
@@ -0,0 +1,593 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+Winbond IT8705F LPC Super I/O
+
+TODO:
+- Move stuff from sis950_lpc;
+- shutms11 fails detecting FDC;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "it8705f.h"
+
+#include "formats/naslite_dsk.h"
+
+#include <algorithm>
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(IT8705F, it8705f_device, "it8705f", "ITE IT8705F LPC Super I/O")
+
+it8705f_device::it8705f_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, IT8705F, tag, owner, clock)
+ , device_isa16_card_interface(mconfig, *this)
+ , device_memory_interface(mconfig, *this)
+ , m_space_config("superio_config_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(it8705f_device::config_map), this))
+ , m_pc_fdc(*this, "fdc")
+ , m_pc_com(*this, "uart%d", 0U)
+ , m_pc_lpt(*this, "lpta")
+ , m_logical_view(*this, "logical_view")
+ , m_irq1_callback(*this)
+ , m_irq8_callback(*this)
+ , m_irq9_callback(*this)
+ , m_txd1_callback(*this)
+ , m_ndtr1_callback(*this)
+ , m_nrts1_callback(*this)
+ , m_txd2_callback(*this)
+ , m_ndtr2_callback(*this)
+ , m_nrts2_callback(*this)
+ , m_index(0)
+ , m_logical_index(0)
+ , m_lock_sequence_index(0)
+{
+ std::fill(std::begin(m_activate), std::end(m_activate), false);
+}
+
+it8705f_device::~it8705f_device()
+{
+}
+
+void it8705f_device::device_start()
+{
+ set_isa_device();
+ m_isa->set_dma_channel(0, this, true);
+ m_isa->set_dma_channel(1, this, true);
+ m_isa->set_dma_channel(2, this, true);
+ m_isa->set_dma_channel(3, this, true);
+ remap(AS_IO, 0, 0x400);
+
+}
+
+void it8705f_device::device_reset()
+{
+ m_index = 0;
+ m_lock_sequence_index = 0;
+
+ m_pc_fdc_irq_line = 6;
+ m_pc_fdc_drq_line = 2;
+// m_pc_fdc_mode = ;
+ m_pc_fdc_address = 0x3f0;
+
+ m_pc_lpt_address = 0x0378;
+ m_pc_lpt_irq_line = 7;
+ m_pc_lpt_drq_line = 4; // disabled
+// m_pc_lpt_mode = 0x3f;
+
+ m_pc_fdc->set_rate(500000);
+}
+
+device_memory_interface::space_config_vector it8705f_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+static void pc_hd_floppies(device_slot_interface &device)
+{
+ device.option_add("525hd", FLOPPY_525_HD);
+ device.option_add("35hd", FLOPPY_35_HD);
+ device.option_add("525dd", FLOPPY_525_DD);
+ device.option_add("35dd", FLOPPY_35_DD);
+}
+
+void it8705f_device::floppy_formats(format_registration &fr)
+{
+ fr.add_pc_formats();
+ fr.add(FLOPPY_NASLITE_FORMAT);
+}
+
+void it8705f_device::device_add_mconfig(machine_config &config)
+{
+ // 82077 compatible
+ N82077AA(config, m_pc_fdc, XTAL(24'000'000), upd765_family_device::mode_t::AT);
+ m_pc_fdc->intrq_wr_callback().set(FUNC(it8705f_device::irq_floppy_w));
+ m_pc_fdc->drq_wr_callback().set(FUNC(it8705f_device::drq_floppy_w));
+ FLOPPY_CONNECTOR(config, "fdc:0", pc_hd_floppies, "35hd", it8705f_device::floppy_formats);
+ FLOPPY_CONNECTOR(config, "fdc:1", pc_hd_floppies, "35hd", it8705f_device::floppy_formats);
+
+ NS16550(config, m_pc_com[0], XTAL(24'000'000) / 13);
+ m_pc_com[0]->out_int_callback().set(FUNC(it8705f_device::irq_serial1_w));
+ m_pc_com[0]->out_tx_callback().set(FUNC(it8705f_device::txd_serial1_w));
+ m_pc_com[0]->out_dtr_callback().set(FUNC(it8705f_device::dtr_serial1_w));
+ m_pc_com[0]->out_rts_callback().set(FUNC(it8705f_device::rts_serial1_w));
+
+ NS16550(config, m_pc_com[1], XTAL(24'000'000) / 13);
+ m_pc_com[1]->out_int_callback().set(FUNC(it8705f_device::irq_serial2_w));
+ m_pc_com[1]->out_tx_callback().set(FUNC(it8705f_device::txd_serial2_w));
+ m_pc_com[1]->out_dtr_callback().set(FUNC(it8705f_device::dtr_serial2_w));
+ m_pc_com[1]->out_rts_callback().set(FUNC(it8705f_device::rts_serial2_w));
+
+ PC_LPT(config, m_pc_lpt);
+ m_pc_lpt->irq_handler().set(FUNC(it8705f_device::irq_parallel_w));
+
+}
+
+
+void it8705f_device::remap(int space_id, offs_t start, offs_t end)
+{
+ if (space_id == AS_IO)
+ {
+ // TODO: apparently installs two ports, an alias at 0x4e/0x4f
+ m_isa->install_device(0x002e, 0x002f, read8sm_delegate(*this, FUNC(it8705f_device::read)), write8sm_delegate(*this, FUNC(it8705f_device::write)));
+
+ if (m_activate[0])
+ {
+ m_isa->install_device(m_pc_fdc_address, m_pc_fdc_address + 7, *m_pc_fdc, &n82077aa_device::map);
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ if (m_activate[i + 1])
+ {
+ const u16 uart_addr = m_pc_com_address[i];
+ m_isa->install_device(uart_addr, uart_addr + 7, read8sm_delegate(*m_pc_com[i], FUNC(ns16450_device::ins8250_r)), write8sm_delegate(*m_pc_com[i], FUNC(ns16450_device::ins8250_w)));
+ }
+ }
+
+ // can't map below 0x100
+ if (m_activate[3] & 1 && m_pc_lpt_address & 0xf00)
+ {
+ m_isa->install_device(m_pc_lpt_address, m_pc_lpt_address + 3, read8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::read)), write8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::write)));
+ }
+ }
+}
+
+uint8_t it8705f_device::read(offs_t offset)
+{
+ if (m_lock_sequence_index != 4)
+ return 0;
+
+ if (offset == 0)
+ return m_index;
+
+ return space().read_byte(m_index);
+}
+
+void it8705f_device::write(offs_t offset, u8 data)
+{
+ if (offset == 0)
+ {
+ if (m_lock_sequence_index == 4)
+ m_index = data;
+ else
+ {
+ // TODO: 0xaa for lock_seq[3] with 0x4e alias
+ const u8 lock_seq[4] = { 0x87, 0x01, 0x55, 0x55 };
+ if (data == lock_seq[m_lock_sequence_index])
+ m_lock_sequence_index ++;
+ else
+ m_lock_sequence_index = 0;
+ }
+ }
+ else
+ {
+ if (m_lock_sequence_index == 4)
+ space().write_byte(m_index, data);
+ }
+}
+
+void it8705f_device::config_map(address_map &map)
+{
+ map(0x02, 0x02).lw8(
+ NAME([this] (offs_t offset, u8 data) {
+ if (BIT(data, 1))
+ m_lock_sequence_index = 0;
+ // TODO: bit 0 for global reset
+ })
+ );
+ map(0x07, 0x07).lr8(NAME([this] () { return m_logical_index; })).w(FUNC(it8705f_device::logical_device_select_w));
+ map(0x20, 0x20).lr8(NAME([] () { return 0x87; })); // device ID
+ map(0x21, 0x21).lr8(NAME([] () { return 0x05; })); // revision
+// map(0x22, 0x22) Configuration Select and Chip Version
+// map(0x23, 0x23) Software Suspend
+// map(0x24, 0x24) Clock Selection and Flash ROM I/F control
+// map(0x25, 0x2a) LDN5 GPIO set multi-function pins
+// map(0x2b, 0x2b) LDN4 alternate GPIO set multi-function pins
+// map(0x2e, 0x2f) LDNF4 Test Modes
+
+ map(0x30, 0xff).view(m_logical_view);
+ // FDC
+ m_logical_view[0](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<0>), FUNC(it8705f_device::activate_w<0>));
+ m_logical_view[0](0x60, 0x61).lrw8(
+ NAME([this] (offs_t offset) {
+ return (m_pc_fdc_address >> (offset * 8)) & 0xff;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ const u8 shift = offset * 8;
+ m_pc_fdc_address &= 0xff << shift;
+ m_pc_fdc_address |= data << (shift ^ 8);
+ m_pc_fdc_address &= ~0xf007;
+ LOG("LDN0 (FDC): remap %04x ([%d] %02x)\n", m_pc_fdc_address, offset, data);
+
+ remap(AS_IO, 0, 0x400);
+ })
+ );
+ m_logical_view[0](0x70, 0x70).lrw8(
+ NAME([this] () {
+ return m_pc_fdc_irq_line;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_pc_fdc_irq_line = data & 0xf;
+ LOG("LDN0 (FDC): irq routed to %02x\n", m_pc_lpt_irq_line);
+ })
+ );
+ m_logical_view[0](0x74, 0x74).lrw8(
+ NAME([this] () {
+ return m_pc_lpt_drq_line;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_pc_fdc_drq_line = data & 0x7;
+ LOG("LDN0 (FDC): drq %s (%02x)\n", BIT(m_pc_lpt_drq_line, 2) ? "disabled" : "enabled", data);
+ })
+ );
+ // TODO: m_logical_view[0](0xf0, 0xf1) FDC config
+
+ // UART1
+ m_logical_view[1](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<1>), FUNC(it8705f_device::activate_w<1>));
+ m_logical_view[1](0x60, 0x61).rw(FUNC(it8705f_device::uart_address_r<0>), FUNC(it8705f_device::uart_address_w<0>));
+ m_logical_view[1](0x70, 0x70).rw(FUNC(it8705f_device::uart_irq_r<0>), FUNC(it8705f_device::uart_irq_w<0>));
+ m_logical_view[1](0xf0, 0xf0).rw(FUNC(it8705f_device::uart_config_r<0>), FUNC(it8705f_device::uart_config_w<0>));
+
+ // UART2
+ m_logical_view[2](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<2>), FUNC(it8705f_device::activate_w<2>));
+ m_logical_view[2](0x60, 0x61).rw(FUNC(it8705f_device::uart_address_r<1>), FUNC(it8705f_device::uart_address_w<1>));
+ m_logical_view[2](0x70, 0x70).rw(FUNC(it8705f_device::uart_irq_r<1>), FUNC(it8705f_device::uart_irq_w<1>));
+ m_logical_view[2](0xf0, 0xf0).rw(FUNC(it8705f_device::uart_config_r<1>), FUNC(it8705f_device::uart_config_w<1>));
+
+ // LPT
+ m_logical_view[3](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<3>), FUNC(it8705f_device::activate_w<3>));
+ m_logical_view[3](0x60, 0x61).lrw8(
+ NAME([this] (offs_t offset) {
+ return (m_pc_lpt_address >> (offset * 8)) & 0xff;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ const u8 shift = offset * 8;
+ m_pc_lpt_address &= 0xff << shift;
+ m_pc_lpt_address |= data << (shift ^ 8);
+ m_pc_lpt_address &= ~0xf003;
+ LOG("LDN3 (LPT): remap %04x ([%d] %02x)\n", m_pc_lpt_address, offset, data);
+
+ remap(AS_IO, 0, 0x400);
+ })
+ );
+ //m_logical_view[3](0x62, 0x63) secondary base address
+ //m_logical_view[3](0x64, 0x65) POST data port base address
+ m_logical_view[3](0x70, 0x70).lrw8(
+ NAME([this] () {
+ return m_pc_lpt_irq_line;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_pc_lpt_irq_line = data & 0xf;
+ LOG("LDN3 (LPT): irq routed to %02x\n", m_pc_lpt_irq_line);
+ })
+ );
+ m_logical_view[3](0x74, 0x74).lrw8(
+ NAME([this] () {
+ return m_pc_lpt_drq_line;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_pc_lpt_drq_line = data & 0x7;
+ LOG("LDN3 (LPT): drq %s (%02x)\n", BIT(m_pc_lpt_drq_line, 2) ? "disabled" : "enabled", data);
+ })
+ );
+
+ // Environment controller / HW monitor
+ m_logical_view[4](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<4>), FUNC(it8705f_device::activate_w<4>));
+ m_logical_view[4](0x31, 0xff).unmaprw();
+
+ // GPIO
+ m_logical_view[5](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<5>), FUNC(it8705f_device::activate_w<5>));
+ m_logical_view[5](0x31, 0xff).unmaprw();
+
+ // Game port
+ m_logical_view[6](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<6>), FUNC(it8705f_device::activate_w<6>));
+ m_logical_view[6](0x31, 0xff).unmaprw();
+
+ // Consumer IR
+ m_logical_view[7](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<7>), FUNC(it8705f_device::activate_w<7>));
+ m_logical_view[7](0x31, 0xff).unmaprw();
+
+ // MIDI port
+ m_logical_view[8](0x30, 0x30).rw(FUNC(it8705f_device::activate_r<8>), FUNC(it8705f_device::activate_w<8>));
+ m_logical_view[8](0x31, 0xff).unmaprw();
+}
+
+/*
+ * Global register space
+ */
+
+void it8705f_device::logical_device_select_w(offs_t offset, u8 data)
+{
+ m_logical_index = data;
+ if (m_logical_index <= 0x8)
+ m_logical_view.select(m_logical_index);
+ else
+ LOG("Attempt to select an unmapped device with %02x\n", data);
+}
+
+template <unsigned N> u8 it8705f_device::activate_r(offs_t offset)
+{
+ return m_activate[N];
+}
+
+template <unsigned N> void it8705f_device::activate_w(offs_t offset, u8 data)
+{
+ m_activate[N] = data & 1;
+ LOG("LDN%d Device %s\n", N, data & 1 ? "enabled" : "disabled");
+ remap(AS_IO, 0, 0x400);
+}
+
+void it8705f_device::request_irq(int irq, int state)
+{
+ switch (irq)
+ {
+ case 1:
+ m_irq1_callback(state);
+ break;
+ case 3:
+ m_isa->irq3_w(state);
+ break;
+ case 4:
+ m_isa->irq4_w(state);
+ break;
+ case 5:
+ m_isa->irq5_w(state);
+ break;
+ case 6:
+ m_isa->irq6_w(state);
+ break;
+ case 7:
+ m_isa->irq7_w(state);
+ break;
+ case 8:
+ m_irq8_callback(state);
+ break;
+ case 9:
+ m_irq9_callback(state);
+ break;
+ case 10:
+ m_isa->irq10_w(state);
+ break;
+ case 11:
+ m_isa->irq11_w(state);
+ break;
+ case 12:
+ m_isa->irq12_w(state);
+ break;
+ case 14:
+ m_isa->irq14_w(state);
+ break;
+ case 15:
+ m_isa->irq15_w(state);
+ break;
+ }
+}
+
+void it8705f_device::request_dma(int dreq, int state)
+{
+ switch (dreq)
+ {
+ case 0:
+ m_isa->drq0_w(state);
+ break;
+ case 1:
+ m_isa->drq1_w(state);
+ break;
+ case 2:
+ m_isa->drq2_w(state);
+ break;
+ case 3:
+ m_isa->drq3_w(state);
+ break;
+ }
+}
+
+/*
+ * Device #0 (FDC)
+ */
+
+void it8705f_device::irq_floppy_w(int state)
+{
+ if (!m_activate[0])
+ return;
+ request_irq(m_pc_fdc_irq_line, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void it8705f_device::drq_floppy_w(int state)
+{
+ if (!m_activate[0])
+ return;
+ request_dma(m_pc_fdc_drq_line, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+/*
+ * Device #1/#2 (UART)
+ */
+
+template <unsigned N> u8 it8705f_device::uart_address_r(offs_t offset)
+{
+ return (m_pc_com_address[N] >> (offset * 8)) & 0xff;
+}
+
+template <unsigned N> void it8705f_device::uart_address_w(offs_t offset, u8 data)
+{
+ const u8 shift = offset * 8;
+ m_pc_com_address[N] &= 0xff << shift;
+ m_pc_com_address[N] |= data << (shift ^ 8);
+ m_pc_com_address[N] &= ~0xf007;
+ LOG("LDN%d (COM%d): remap %04x ([%d] %02x)\n", N, N + 1, m_pc_com_address[N], offset, data);
+
+ remap(AS_IO, 0, 0x400);
+}
+
+template <unsigned N> u8 it8705f_device::uart_irq_r(offs_t offset)
+{
+ return m_pc_com_irq_line[N];
+}
+
+template <unsigned N> void it8705f_device::uart_irq_w(offs_t offset, u8 data)
+{
+ m_pc_com_irq_line[N] = data & 0xf;
+ LOG("LDN%d (UART): irq routed to %02x\n", N, m_pc_com_irq_line[N]);
+}
+
+template <unsigned N> u8 it8705f_device::uart_config_r(offs_t offset)
+{
+ return m_pc_com_control[N];
+}
+
+/*
+ * ---- -xx- Clock Source
+ * ---- -00- 24 MHz/13
+ * ---- -??- <reserved>
+ * ---- ---x IRQ sharing enable
+ */
+template <unsigned N> void it8705f_device::uart_config_w(offs_t offset, u8 data)
+{
+ m_pc_com_control[N] = data;
+ LOG("LDN%d (UART): control %02x\n", N, m_pc_com_control[N]);
+}
+
+void it8705f_device::irq_serial1_w(int state)
+{
+ if (!m_activate[1])
+ return;
+ request_irq(m_pc_com_irq_line[0], state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void it8705f_device::irq_serial2_w(int state)
+{
+ if (!m_activate[2])
+ return;
+ request_irq(m_pc_com_irq_line[1], state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void it8705f_device::txd_serial1_w(int state)
+{
+ if (!m_activate[1])
+ return;
+ m_txd1_callback(state);
+}
+
+void it8705f_device::txd_serial2_w(int state)
+{
+ if (!m_activate[2])
+ return;
+ m_txd2_callback(state);
+}
+
+void it8705f_device::dtr_serial1_w(int state)
+{
+ if (!m_activate[1])
+ return;
+ m_ndtr1_callback(state);
+}
+
+void it8705f_device::dtr_serial2_w(int state)
+{
+ if (!m_activate[2])
+ return;
+ m_ndtr2_callback(state);
+}
+
+void it8705f_device::rts_serial1_w(int state)
+{
+ if (!m_activate[1])
+ return;
+ m_nrts1_callback(state);
+}
+
+void it8705f_device::rts_serial2_w(int state)
+{
+ if (!m_activate[2])
+ return;
+ m_nrts2_callback(state);
+}
+
+void it8705f_device::rxd1_w(int state)
+{
+ m_pc_com[0]->rx_w(state);
+}
+
+void it8705f_device::ndcd1_w(int state)
+{
+ m_pc_com[0]->dcd_w(state);
+}
+
+void it8705f_device::ndsr1_w(int state)
+{
+ m_pc_com[0]->dsr_w(state);
+}
+
+void it8705f_device::nri1_w(int state)
+{
+ m_pc_com[0]->ri_w(state);
+}
+
+void it8705f_device::ncts1_w(int state)
+{
+ m_pc_com[0]->cts_w(state);
+}
+
+void it8705f_device::rxd2_w(int state)
+{
+ m_pc_com[1]->rx_w(state);
+}
+
+void it8705f_device::ndcd2_w(int state)
+{
+ m_pc_com[1]->dcd_w(state);
+}
+
+void it8705f_device::ndsr2_w(int state)
+{
+ m_pc_com[1]->dsr_w(state);
+}
+
+void it8705f_device::nri2_w(int state)
+{
+ m_pc_com[1]->ri_w(state);
+}
+
+void it8705f_device::ncts2_w(int state)
+{
+ m_pc_com[1]->cts_w(state);
+}
+
+/*
+ * Device #3 (Parallel)
+ */
+
+void it8705f_device::irq_parallel_w(int state)
+{
+ if (m_activate[3] == false)
+ return;
+ request_irq(m_pc_lpt_irq_line, state ? ASSERT_LINE : CLEAR_LINE);
+}
diff --git a/src/devices/machine/it8705f.h b/src/devices/machine/it8705f.h
new file mode 100644
index 00000000000..810d75c0258
--- /dev/null
+++ b/src/devices/machine/it8705f.h
@@ -0,0 +1,131 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_IT8705F_H
+#define MAME_MACHINE_IT8705F_H
+
+#pragma once
+
+#include "bus/isa/isa.h"
+#include "imagedev/floppy.h"
+#include "machine/8042kbdc.h"
+#include "machine/ds128x.h"
+#include "machine/ins8250.h"
+#include "machine/pc_lpt.h"
+#include "machine/upd765.h"
+
+class it8705f_device : public device_t,
+ public device_isa16_card_interface,
+ public device_memory_interface
+{
+public:
+ it8705f_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual ~it8705f_device();
+
+ void remap(int space_id, offs_t start, offs_t end) override;
+
+ auto irq1() { return m_irq1_callback.bind(); }
+ auto irq8() { return m_irq8_callback.bind(); }
+ auto irq9() { return m_irq9_callback.bind(); }
+ auto txd1() { return m_txd1_callback.bind(); }
+ auto ndtr1() { return m_ndtr1_callback.bind(); }
+ auto nrts1() { return m_nrts1_callback.bind(); }
+ auto txd2() { return m_txd2_callback.bind(); }
+ auto ndtr2() { return m_ndtr2_callback.bind(); }
+ auto nrts2() { return m_nrts2_callback.bind(); }
+
+ void rxd1_w(int state);
+ void ndcd1_w(int state);
+ void ndsr1_w(int state);
+ void nri1_w(int state);
+ void ncts1_w(int state);
+ void rxd2_w(int state);
+ void ndcd2_w(int state);
+ void ndsr2_w(int state);
+ void nri2_w(int state);
+ void ncts2_w(int state);
+
+ static void floppy_formats(format_registration &fr);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual space_config_vector memory_space_config() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ const address_space_config m_space_config;
+
+ required_device<n82077aa_device> m_pc_fdc;
+ required_device_array<ns16550_device, 2> m_pc_com;
+ required_device<pc_lpt_device> m_pc_lpt;
+ memory_view m_logical_view;
+
+ devcb_write_line m_irq1_callback;
+ devcb_write_line m_irq8_callback;
+ devcb_write_line m_irq9_callback;
+ devcb_write_line m_txd1_callback;
+ devcb_write_line m_ndtr1_callback;
+ devcb_write_line m_nrts1_callback;
+ devcb_write_line m_txd2_callback;
+ devcb_write_line m_ndtr2_callback;
+ devcb_write_line m_nrts2_callback;
+
+ u8 m_index = 0;
+ u8 m_logical_index = 0;
+ bool m_activate[9]{};
+
+ u8 m_lock_sequence_index = 0;
+
+ uint8_t read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+ void config_map(address_map &map);
+
+ void logical_device_select_w(offs_t offset, u8 data);
+ template <unsigned N> u8 activate_r(offs_t offset);
+ template <unsigned N> void activate_w(offs_t offset, u8 data);
+
+ void request_irq(int irq, int state);
+ void request_dma(int dreq, int state);
+
+ u8 m_pc_fdc_irq_line = 6;
+ u8 m_pc_fdc_drq_line = 2;
+// u8 m_pc_fdc_mode;
+ u16 m_pc_fdc_address = 0x3f0;
+
+ void irq_floppy_w(int state);
+ void drq_floppy_w(int state);
+
+ u8 m_pc_lpt_irq_line = 7;
+ u8 m_pc_lpt_drq_line = 4;
+// u8 m_pc_lpt_mode;
+ u16 m_pc_lpt_address = 0x378;
+
+ void irq_parallel_w(int state);
+
+ u16 m_pc_com_address[2]{};
+ u8 m_pc_com_irq_line[2]{};
+ u8 m_pc_com_control[2]{};
+
+ void irq_serial1_w(int state);
+ void txd_serial1_w(int state);
+ void dtr_serial1_w(int state);
+ void rts_serial1_w(int state);
+ void irq_serial2_w(int state);
+ void txd_serial2_w(int state);
+ void dtr_serial2_w(int state);
+ void rts_serial2_w(int state);
+
+ template <unsigned N> u8 uart_address_r(offs_t offset);
+ template <unsigned N> void uart_address_w(offs_t offset, u8 data);
+ template <unsigned N> u8 uart_irq_r(offs_t offset);
+ template <unsigned N> void uart_irq_w(offs_t offset, u8 data);
+ template <unsigned N> u8 uart_config_r(offs_t offset);
+ template <unsigned N> void uart_config_w(offs_t offset, u8 data);
+};
+
+DECLARE_DEVICE_TYPE(IT8705F, it8705f_device);
+
+#endif // MAME_MACHINE_IT8705F_H
diff --git a/src/devices/machine/iwm.cpp b/src/devices/machine/iwm.cpp
index 385561978b2..76d2e116739 100644
--- a/src/devices/machine/iwm.cpp
+++ b/src/devices/machine/iwm.cpp
@@ -11,6 +11,14 @@
#include "emu.h"
#include "iwm.h"
+#define LOG_CONTROL (1U << 1)
+#define LOG_MODE (1U << 2)
+#define VERBOSE 0
+#include "logmacro.h"
+
+#define LOGCNTRL(...) LOGMASKED(LOG_CONTROL, __VA_ARGS__)
+#define LOGMODE(...) LOGMASKED(LOG_MODE, __VA_ARGS__)
+
DEFINE_DEVICE_TYPE(IWM, iwm_device, "iwm", "Apple IWM floppy controller")
iwm_device::iwm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t q3_clock) :
@@ -18,27 +26,15 @@ iwm_device::iwm_device(const machine_config &mconfig, const char *tag, device_t
m_floppy(nullptr),
m_q3_clock(q3_clock)
{
- if (q3_clock != 0)
- m_q3_fclk_ratio = double(clock)/double(q3_clock); // ~0.25
- if (clock != 0)
- m_fclk_q3_ratio = double(q3_clock)/double(clock); // ~4
-}
-
-u64 iwm_device::q3_to_fclk(u64 cycles) const
-{
- return u64(m_q3_fclk_ratio * double(cycles) + 0.5);
-}
-
-u64 iwm_device::fclk_to_q3(u64 cycles) const
-{
- return u64(m_fclk_q3_ratio * double(cycles) + 0.5);
+ m_q3_fclk_ratio = q3_clock ? double(clock)/double(q3_clock) : 0; // ~0.25
+ m_fclk_q3_ratio = q3_clock ? double(q3_clock)/double(clock) : 0; // ~4
}
void iwm_device::device_start()
{
applefdintf_device::device_start();
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(iwm_device::update_timer_tick), this);
save_item(NAME(m_last_sync));
save_item(NAME(m_next_state_change));
save_item(NAME(m_sync_update));
@@ -47,6 +43,7 @@ void iwm_device::device_start()
save_item(NAME(m_flux_write));
save_item(NAME(m_flux_write_count));
save_item(NAME(m_q3_clock));
+ save_item(NAME(m_q3_clock_active));
save_item(NAME(m_active));
save_item(NAME(m_rw));
save_item(NAME(m_rw_state));
@@ -57,6 +54,8 @@ void iwm_device::device_start()
save_item(NAME(m_control));
save_item(NAME(m_rsh));
save_item(NAME(m_wsh));
+ save_item(NAME(m_rw_bit_count));
+ save_item(NAME(m_devsel));
}
void iwm_device::device_reset()
@@ -69,7 +68,7 @@ void iwm_device::device_reset()
m_rw = MODE_IDLE;
m_rw_state = S_IDLE;
m_data = 0x00;
- m_whd = 0xff;
+ m_whd = 0xbf;
m_mode = 0x00;
m_status = 0x00;
m_control = 0x00;
@@ -77,16 +76,25 @@ void iwm_device::device_reset()
m_rsh = 0x00;
m_flux_write_start = 0;
m_flux_write_count = 0;
- m_devsel_cb(1);
+ m_rw_bit_count = 0;
+ m_devsel = 0;
+ m_devsel_cb(0);
+ m_q3_clock_active = false;
}
-void iwm_device::device_timer(emu_timer &, device_timer_id, int, void *)
+TIMER_CALLBACK_MEMBER(iwm_device::update_timer_tick)
{
if(m_active == MODE_DELAY) {
+ flush_write();
m_active = MODE_IDLE;
+ m_rw = MODE_IDLE;
+ m_rw_state = S_IDLE;
if(m_floppy)
m_floppy->mon_w(true);
+ m_devsel_cb(0);
+ m_devsel = 0;
m_status &= ~0x20;
+ m_whd &= ~0x40;
}
}
@@ -96,11 +104,14 @@ void iwm_device::set_floppy(floppy_image_device *floppy)
return;
sync();
+ flush_write();
- if(m_floppy)
+ LOG("floppy %s\n", floppy ? floppy->tag() : "-");
+
+ if(m_floppy && (m_control & 0x10))
m_floppy->mon_w(true);
m_floppy = floppy;
- if(m_active)
+ if(m_floppy && (m_control & 0x10))
m_floppy->mon_w(false);
update_phases();
}
@@ -120,27 +131,41 @@ void iwm_device::write(offs_t offset, u8 data)
control(offset, data);
}
-void iwm_device::flush_write()
+void iwm_device::flush_write(u64 when)
{
- if(m_floppy && m_last_sync > m_flux_write_start) {
- if(m_flux_write_count && m_flux_write[m_flux_write_count-1] == m_last_sync)
+ if(!m_flux_write_start)
+ return;
+
+ if(!when)
+ when = m_last_sync;
+
+ if(when > m_flux_write_start) {
+ bool last_on_edge = m_flux_write_count && m_flux_write[m_flux_write_count-1] == when;
+ if(last_on_edge)
m_flux_write_count--;
+
attotime start = cycles_to_time(m_flux_write_start);
- attotime end = cycles_to_time(m_last_sync);
+ attotime end = cycles_to_time(when);
std::vector<attotime> fluxes(m_flux_write_count);
for(u32 i=0; i != m_flux_write_count; i++)
fluxes[i] = cycles_to_time(m_flux_write[i]);
- m_floppy->write_flux(start, end, m_flux_write_count, m_flux_write_count ? &fluxes[0] : nullptr);
- }
- m_flux_write_count = 0;
- m_flux_write_start = m_last_sync;
+
+ if(m_floppy)
+ m_floppy->write_flux(start, end, m_flux_write_count, m_flux_write_count ? &fluxes[0] : nullptr);
+
+ m_flux_write_count = 0;
+ if(last_on_edge)
+ m_flux_write[m_flux_write_count++] = when;
+ m_flux_write_start = when;
+
+ } else
+ m_flux_write_count = 0;
}
u8 iwm_device::control(int offset, u8 data)
{
sync();
- logerror("control trigger %x, %02x\n", offset, data);
- u8 changed = m_control | (m_phases & 0xf);
+
if(offset < 8) {
if(offset & 1)
m_phases |= 1 << (offset >> 1);
@@ -154,62 +179,69 @@ u8 iwm_device::control(int offset, u8 data)
m_control &= ~(1 << (offset >> 1));
}
- changed ^= m_control | (m_phases & 0xf);
-
- if(changed & 0x20)
- m_devsel_cb(m_control & 0x20 ? 2 : 1);
-
- if(changed & 0x10) {
- if(m_control & 0x10) {
+ if(m_control & 0x10) {
+ if(m_active != MODE_ACTIVE) {
m_active = MODE_ACTIVE;
+ m_status |= 0x20;
if(m_floppy)
m_floppy->mon_w(false);
- m_status |= 0x20;
+ }
+
+ if((m_control & 0x80) == 0x00) {
+ if(m_rw != MODE_READ) {
+ if(m_rw == MODE_WRITE) {
+ flush_write();
+ write_clock_stop();
+ }
+ m_rw = MODE_READ;
+ m_rw_state = S_IDLE;
+ m_next_state_change = 0;
+ m_sync_update = 0;
+ m_async_update = 0;
+ m_data = 0x00;
+ }
+
} else {
+ if(m_rw != MODE_WRITE) {
+ m_rw = MODE_WRITE;
+ m_rw_state = S_IDLE;
+ m_whd |= 0x40;
+ m_next_state_change = 0;
+ write_clock_start();
+ if(m_floppy)
+ m_floppy->set_write_splice(cycles_to_time(m_flux_write_start));
+ }
+ }
+ } else {
+ if(m_active == MODE_ACTIVE) {
+ flush_write();
if(m_mode & 0x04) {
+ write_clock_stop();
m_active = MODE_IDLE;
- if(m_floppy) {
- m_floppy->mon_w(true);
- m_floppy->seek_phase_w(0);
- }
+ m_rw = MODE_IDLE;
+ m_rw_state = S_IDLE;
m_status &= ~0x20;
+ m_whd &= ~0x40;
+ if(m_floppy)
+ m_floppy->mon_w(true);
} else {
+ m_devsel_cb(m_control & 0x20 ? 2 : 1);
m_active = MODE_DELAY;
m_timer->adjust(cycles_to_time(8388608));
}
}
}
- if(changed & 0xd0) {
- if((m_control & 0xc0) == 0x00 && m_active) {
- if(m_rw == MODE_WRITE)
- flush_write();
- m_rw = MODE_READ;
- m_rw_state = S_IDLE;
- m_next_state_change = 0;
- m_sync_update = 0;
- m_async_update = 0;
- m_data = 0x00;
-
- } else if((m_control & 0xc0) == 0xc0 && (changed & 0xc0) == 0x40 && m_active && m_rw != MODE_WRITE) {
- m_rw = MODE_WRITE;
- m_rw_state = S_IDLE;
- m_next_state_change = 0;
- m_flux_write_start = m_last_sync;
- m_flux_write_count = 0;
- if(m_floppy)
- m_floppy->set_write_splice(cycles_to_time(m_flux_write_start));
-
- } else if(m_rw == MODE_WRITE) {
- if(!(m_control & 0x80)) {
- flush_write();
- m_rw = MODE_IDLE;
- }
- } else
- m_rw = MODE_IDLE;
+ u8 devsel = m_active != MODE_IDLE ? m_control & 0x20 ? 2 : 1 : 0;
+ if(devsel != m_devsel) {
+ m_devsel = devsel;
+ m_devsel_cb(devsel);
}
- if(changed || 1) {
+ if((m_control & 0xc0) == 0x40 && m_active == MODE_ACTIVE && m_rw == MODE_READ)
+ m_rsh = 0;
+
+ if(0) {
u8 s = m_control & 0xc0;
const char *slot = "?";
if(s == 0x00 && !m_active)
@@ -225,7 +257,8 @@ u8 iwm_device::control(int offset, u8 data)
if(s == 0xc0 && m_active)
slot = "write load / write data";
- logerror("control %c%c %c%c %c%c%c%c (%s) [%s, %s]\n",
+ LOGCNTRL("%s control %c%c %c%c %c%c%c%c (%s) [%s, %s] whd=%02x data=%02x\n",
+ machine().time().to_string(),
m_control & 0x80 ? '1' : '0',
m_control & 0x40 ? '1' : '0',
m_control & 0x20 ? 'b' : 'a',
@@ -236,15 +269,16 @@ u8 iwm_device::control(int offset, u8 data)
m_phases & 0x01 ? '#' : '.',
slot,
m_active == MODE_IDLE ? "idle" : m_active == MODE_DELAY ? "delay" : "active",
- m_rw == MODE_IDLE ? "idle" : m_rw == MODE_READ ? "read" : "write");
+ m_rw == MODE_IDLE ? "idle" : m_rw == MODE_READ ? "read" : "write",
+ m_whd, m_data);
}
- if(m_active && !(m_control & 0xc0) && !is_sync() && (m_data & 0x80))
+ if(m_active && !(m_control & 0x80) && !is_sync() && (m_data & 0x80))
m_async_update = m_last_sync + 14;
switch(m_control & 0xc0) {
case 0x00: return m_active ? m_data : 0xff;
- case 0x40: return m_status;
+ case 0x40: return (m_status & 0x7f) | ((!m_floppy || m_floppy->wpt_r()) ? 0x80 : 0x00);
case 0x80: return m_whd;
case 0xc0: if(offset & 1) { if(m_active) data_w(data); else mode_w(data); } return 0xff;
}
@@ -256,7 +290,7 @@ void iwm_device::mode_w(u8 data)
{
m_mode = data;
m_status = (m_status & 0xe0) | (data & 0x1f);
- logerror("mode %02x%s%s%s%s%s%s%s\n", m_mode,
+ LOGMODE("mode %02x%s%s%s%s%s%s%s\n", m_mode,
m_mode & 0x80 ? " b7" : "",
m_mode & 0x40 ? " mz-reset" : "",
m_mode & 0x20 ? " test" : " normal",
@@ -272,16 +306,18 @@ void iwm_device::data_w(u8 data)
m_data = data;
if(is_sync() && m_rw == MODE_WRITE)
m_wsh = data;
+ if(m_mode & 0x01)
+ m_whd &= 0x7f;
}
u64 iwm_device::time_to_cycles(const attotime &tm) const
{
- return tm.as_ticks(clock());
+ return tm.as_ticks(m_q3_clock_active ? m_q3_clock : clock());
}
attotime iwm_device::cycles_to_time(u64 cycles) const
{
- return attotime::from_ticks(cycles, clock());
+ return attotime::from_ticks(cycles, m_q3_clock_active ? m_q3_clock : clock());
}
bool iwm_device::is_sync() const
@@ -291,6 +327,9 @@ bool iwm_device::is_sync() const
u64 iwm_device::half_window_size() const
{
+ if(m_q3_clock_active)
+ return m_mode & 0x08 ? 2 : 4;
+
switch(m_mode & 0x18) {
case 0x00: return 14;
case 0x08: return 7;
@@ -302,6 +341,9 @@ u64 iwm_device::half_window_size() const
u64 iwm_device::window_size() const
{
+ if(m_q3_clock_active)
+ return m_mode & 0x08 ? 4 : 8;
+
switch(m_mode & 0x18) {
case 0x00: return 28;
case 0x08: return 14;
@@ -316,9 +358,23 @@ u64 iwm_device::read_register_update_delay() const
return m_mode & 0x08 ? 4 : 8;
}
-u64 iwm_device::write_sync_half_window_size() const
+void iwm_device::write_clock_start()
+{
+ if(is_sync() && m_q3_clock) {
+ m_q3_clock_active = true;
+ m_last_sync = machine().time().as_ticks(m_q3_clock);
+ }
+ m_flux_write_start = m_last_sync;
+ m_flux_write_count = 0;
+}
+
+void iwm_device::write_clock_stop()
{
- return m_mode & 0x08 ? 2 : 4;
+ if(m_q3_clock_active) {
+ m_q3_clock_active = false;
+ m_last_sync = machine().time().as_ticks(clock());
+ }
+ m_flux_write_start = 0;
}
void iwm_device::sync()
@@ -326,7 +382,7 @@ void iwm_device::sync()
if(!m_active)
return;
- u64 next_sync = machine().time().as_ticks(clock());
+ u64 next_sync = machine().time().as_ticks(m_q3_clock_active ? m_q3_clock : clock());
switch(m_rw) {
case MODE_IDLE:
m_last_sync = next_sync;
@@ -383,6 +439,7 @@ void iwm_device::sync()
} else if(m_rsh >= 0x80) {
m_data = m_rsh;
+ m_async_update = 0;
m_rsh = 0;
}
break;
@@ -395,9 +452,8 @@ void iwm_device::sync()
m_sync_update = 0;
}
if(m_async_update && m_async_update <= m_last_sync) {
- if(!is_sync()) {
+ if(!is_sync())
m_data = 0;
- }
m_async_update = 0;
}
break;
@@ -405,7 +461,7 @@ void iwm_device::sync()
case MODE_WRITE: {
while(next_sync > m_last_sync) {
- if(next_sync < m_next_state_change) {
+ if(next_sync < m_next_state_change || !(m_whd & 0x40)) {
m_last_sync = next_sync;
break;
}
@@ -413,29 +469,68 @@ void iwm_device::sync()
m_last_sync = m_next_state_change;
switch(m_rw_state) {
case S_IDLE:
- m_wsh = m_data;
- m_rw_state = SW_WINDOW_MIDDLE;
- m_next_state_change = q3_to_fclk(fclk_to_q3(m_last_sync) + write_sync_half_window_size());
m_flux_write_count = 0;
+ if(m_mode & 0x02) {
+ m_rw_state = SW_WINDOW_LOAD;
+ m_rw_bit_count = 8;
+ m_next_state_change = m_last_sync + 7;
+ } else {
+ m_wsh = m_data;
+ m_rw_state = SW_WINDOW_MIDDLE;
+ m_next_state_change = m_last_sync + half_window_size();
+ }
+ break;
+
+ case SW_WINDOW_LOAD:
+ if(m_whd & 0x80) {
+ logerror("underrun\n");
+ flush_write(next_sync);
+ write_clock_stop();
+ m_whd &= ~0x40;
+ m_last_sync = next_sync;
+ m_rw_state = SW_UNDERRUN;
+
+ } else {
+ m_wsh = m_data;
+ m_rw_state = SW_WINDOW_MIDDLE;
+ m_whd |= 0x80;
+ m_next_state_change = m_last_sync + half_window_size() - 7;
+ }
break;
case SW_WINDOW_MIDDLE:
if(m_wsh & 0x80)
m_flux_write[m_flux_write_count++] = m_last_sync;
m_wsh <<= 1;
- m_next_state_change = q3_to_fclk(fclk_to_q3(m_last_sync) + write_sync_half_window_size());
-
m_rw_state = SW_WINDOW_END;
+ m_next_state_change = m_last_sync + half_window_size();
break;
+
case SW_WINDOW_END:
if(m_flux_write_count == m_flux_write.size())
flush_write();
- m_next_state_change = q3_to_fclk(fclk_to_q3(m_last_sync) + write_sync_half_window_size());
- m_rw_state = SW_WINDOW_MIDDLE;
+ if(m_mode & 0x02) {
+ m_rw_bit_count --;
+ if(m_rw_bit_count == 0) {
+ m_rw_state = SW_WINDOW_LOAD;
+ m_rw_bit_count = 8;
+ m_next_state_change = m_last_sync + 7;
+ } else {
+ m_rw_state = SW_WINDOW_MIDDLE;
+ m_next_state_change = m_last_sync + half_window_size();
+ }
+ } else {
+ m_next_state_change = m_last_sync + half_window_size();
+ m_rw_state = SW_WINDOW_MIDDLE;
+ }
+ break;
+
+ case SW_UNDERRUN:
+ m_last_sync = next_sync;
break;
}
}
break;
}
-}
+ }
}
diff --git a/src/devices/machine/iwm.h b/src/devices/machine/iwm.h
index 7ef2b8a4b4c..73045890d0d 100644
--- a/src/devices/machine/iwm.h
+++ b/src/devices/machine/iwm.h
@@ -32,10 +32,13 @@ public:
virtual void set_floppy(floppy_image_device *floppy) override;
virtual floppy_image_device *get_floppy() const override;
+ virtual void sync() override;
+
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_timer_tick);
private:
enum {
@@ -49,8 +52,10 @@ private:
S_IDLE,
SR_WINDOW_EDGE_0,
SR_WINDOW_EDGE_1,
+ SW_WINDOW_LOAD,
SW_WINDOW_MIDDLE,
- SW_WINDOW_END
+ SW_WINDOW_END,
+ SW_UNDERRUN,
};
floppy_image_device *m_floppy;
@@ -58,19 +63,18 @@ private:
double m_q3_fclk_ratio, m_fclk_q3_ratio;
u64 m_last_sync, m_next_state_change, m_sync_update, m_async_update;
u64 m_flux_write_start;
- std::array<u64, 16> m_flux_write;
+ std::array<u64, 65536> m_flux_write;
u32 m_flux_write_count;
u32 m_q3_clock;
int m_active, m_rw, m_rw_state;
- u8 m_data, m_whd, m_mode, m_status, m_control;
+ u8 m_data, m_whd, m_mode, m_status, m_control, m_rw_bit_count;
u8 m_rsh, m_wsh;
+ u8 m_devsel;
+ bool m_q3_clock_active;
- void sync();
u8 control(int offset, u8 data);
u64 time_to_cycles(const attotime &tm) const;
attotime cycles_to_time(u64 cycles) const;
- u64 fclk_to_q3(u64 cycles) const;
- u64 q3_to_fclk(u64 cycles) const;
void mode_w(u8 data);
void data_w(u8 data);
@@ -78,9 +82,10 @@ private:
u64 window_size() const;
u64 half_window_size() const;
u64 read_register_update_delay() const;
- u64 write_sync_half_window_size() const;
inline bool is_sync() const;
- void flush_write();
+ void flush_write(u64 when = 0);
+ void write_clock_start();
+ void write_clock_stop();
};
DECLARE_DEVICE_TYPE(IWM, iwm_device)
diff --git a/src/devices/machine/jvsdev.cpp b/src/devices/machine/jvsdev.cpp
index f55a836cd01..e752df0cf4f 100644
--- a/src/devices/machine/jvsdev.cpp
+++ b/src/devices/machine/jvsdev.cpp
@@ -73,12 +73,18 @@ void jvs_device::message(uint8_t dest, const uint8_t *send_buffer, uint32_t send
} else
s += len;
}
- recv_size = d - recv_buffer;
+
+ // d will always have at least a 1 byte difference due to adding the status code byte before processing messages.
+ // Don't count the status code in the received message size unless we're at the end of the device chain so the
+ // message buffer can be chained to slave devices. Required for resets to be chained.
+ const uint32_t new_recv_size = d - recv_buffer;
+ if (!next_device || new_recv_size > 1)
+ recv_size = new_recv_size;
}
// Pass along the message if the device hasn't replied
// Should we cumulate answers instead?
- if(next_device && !recv_size)
+ if(next_device && (dest == 0xff || !recv_size))
next_device->message(dest, send_buffer, send_size, recv_buffer, recv_size);
}
diff --git a/src/devices/machine/jvsdev.h b/src/devices/machine/jvsdev.h
index 7a93b3ead04..f7dba299c97 100644
--- a/src/devices/machine/jvsdev.h
+++ b/src/devices/machine/jvsdev.h
@@ -37,6 +37,7 @@ protected:
virtual bool analogs(uint8_t *&buf, uint8_t count);
virtual bool swoutputs(uint8_t count, const uint8_t *vals);
virtual bool swoutputs(uint8_t id, uint8_t val);
+ virtual int handle_message(const uint8_t *send_buffer, uint32_t send_size, uint8_t *&recv_buffer);
required_device<jvs_host> host;
@@ -45,7 +46,6 @@ private:
uint8_t jvs_address;
uint32_t jvs_reset_counter;
- int handle_message(const uint8_t *send_buffer, uint32_t send_size, uint8_t *&recv_buffer);
};
#endif // MAME_MACHINE_JVSDEV_H
diff --git a/src/devices/machine/jvshost.cpp b/src/devices/machine/jvshost.cpp
index 1f720b4fa00..c083aff2715 100644
--- a/src/devices/machine/jvshost.cpp
+++ b/src/devices/machine/jvshost.cpp
@@ -126,14 +126,14 @@ void jvs_host::encode(uint8_t *buffer, uint32_t &size)
for(uint32_t i=0; i<size; i++)
if(buffer[i] == 0xd0 || buffer[i] == 0xe0)
add++;
- for(uint32_t i=size; i; i--) {
+ for(uint32_t i=size,j=add; i; i--) {
uint8_t t = buffer[i-1];
if(t == 0xd0 || t == 0xe0) {
- buffer[i+add-1] = t-1;
- buffer[i+add-2] = 0xd0;
- add--;
+ buffer[i+j-1] = t-1;
+ buffer[i+j-2] = 0xd0;
+ j--;
} else
- buffer[i+add-1] = t;
+ buffer[i+j-1] = t;
}
buffer[0] = 0xe0;
size += add;
diff --git a/src/devices/machine/k033906.cpp b/src/devices/machine/k033906.cpp
index d3debafd75d..0ced32fd8f0 100644
--- a/src/devices/machine/k033906.cpp
+++ b/src/devices/machine/k033906.cpp
@@ -24,6 +24,7 @@ DEFINE_DEVICE_TYPE(K033906, k033906_device, "k033906", "K033906 PCI bridge")
k033906_device::k033906_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, K033906, tag, owner, clock)
, m_reg_set(0)
+ , m_voodoo_pciid(0x0001121a) // PCI Vendor ID (0x121a = 3dfx), Device ID (0x0001 = Voodoo 1)
, m_voodoo(*this, finder_base::DUMMY_TAG)
, m_reg(nullptr)
, m_ram(nullptr)
@@ -46,7 +47,7 @@ void k033906_device::device_start()
}
-WRITE_LINE_MEMBER(k033906_device::set_reg)
+void k033906_device::set_reg(int state)
{
m_reg_set = state & 1;
}
@@ -55,10 +56,11 @@ uint32_t k033906_device::reg_r(int reg)
{
switch (reg)
{
- case 0x00: return 0x0001121a; // PCI Vendor ID (0x121a = 3dfx), Device ID (0x0001 = Voodoo)
+ case 0x00: return m_voodoo_pciid;
case 0x02: return 0x04000000; // Revision ID
case 0x04: return m_reg[0x04]; // memBaseAddr
case 0x0f: return m_reg[0x0f]; // interrupt_line, interrupt_pin, min_gnt, max_lat
+ case 0x14: return m_reg[0x14]; // ??? must be able to read the same value (0xf47c6451) that was written, used by Silent Scope when using Voodoo 2
default:
fatalerror("%s: k033906_reg_r: %08X\n", machine().describe_context().c_str(), reg);
@@ -98,7 +100,7 @@ void k033906_device::reg_w(int reg, uint32_t data)
case 0x10: // initEnable
{
- m_voodoo->voodoo_set_init_enable(data);
+ m_voodoo->set_init_enable(data);
break;
}
@@ -106,6 +108,10 @@ void k033906_device::reg_w(int reg, uint32_t data)
case 0x12: // busSnoop1
break;
+ case 0x14: // ???
+ m_reg[reg] = data;
+ break;
+
case 0x38: // ???
break;
diff --git a/src/devices/machine/k033906.h b/src/devices/machine/k033906.h
index 3184b210a90..68b1e171ece 100644
--- a/src/devices/machine/k033906.h
+++ b/src/devices/machine/k033906.h
@@ -26,9 +26,11 @@ public:
k033906_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ void set_pciid(uint32_t pciid) { m_voodoo_pciid = pciid; }
+
u32 read(offs_t offset);
void write(offs_t offset, u32 data);
- DECLARE_WRITE_LINE_MEMBER(set_reg);
+ void set_reg(int state);
protected:
// device-level overrides
@@ -44,8 +46,9 @@ private:
/* i/o lines */
int m_reg_set; // 1 = access reg / 0 = access ram
+ uint32_t m_voodoo_pciid;
- required_device<voodoo_device> m_voodoo;
+ required_device<generic_voodoo_device> m_voodoo;
std::unique_ptr<u32[]> m_reg;
std::unique_ptr<u32[]> m_ram;
diff --git a/src/devices/machine/k053252.cpp b/src/devices/machine/k053252.cpp
index 6972d0f5c96..3645ac70d8a 100644
--- a/src/devices/machine/k053252.cpp
+++ b/src/devices/machine/k053252.cpp
@@ -62,6 +62,8 @@ TODO:
#include "emu.h"
#include "k053252.h"
+#include "multibyte.h"
+
DEFINE_DEVICE_TYPE(K053252, k053252_device, "k053252", "K053252 Timing/Interrupt Controller")
@@ -86,12 +88,6 @@ k053252_device::k053252_device(const machine_config &mconfig, const char *tag, d
void k053252_device::device_start()
{
- m_int1_en_cb.resolve_safe();
- m_int2_en_cb.resolve_safe();
- m_int1_ack_cb.resolve_safe();
- m_int2_ack_cb.resolve_safe();
- m_int_time_cb.resolve_safe();
-
save_item(NAME(m_regs));
save_item(NAME(m_hc));
save_item(NAME(m_hfp));
@@ -196,23 +192,20 @@ void k053252_device::write(offs_t offset, uint8_t data)
{
case 0x00:
case 0x01:
- m_hc = (m_regs[1]&0xff);
- m_hc |= ((m_regs[0]&0x03)<<8);
+ m_hc = get_u16be(&m_regs[0])&0x03ff;
m_hc++;
logerror("%d (%04x) HC set\n",m_hc,m_hc);
res_change();
break;
case 0x02:
case 0x03:
- m_hfp = (m_regs[3]&0xff);
- m_hfp |= ((m_regs[2]&0x01)<<8);
+ m_hfp = get_u16be(&m_regs[2])&0x01ff;
logerror("%d (%04x) HFP set\n",m_hfp,m_hfp);
res_change();
break;
case 0x04:
case 0x05:
- m_hbp = (m_regs[5]&0xff);
- m_hbp |= ((m_regs[4]&0x01)<<8);
+ m_hbp = get_u16be(&m_regs[4])&0x01ff;
logerror("%d (%04x) HBP set\n",m_hbp,m_hbp);
res_change();
break;
@@ -220,26 +213,25 @@ void k053252_device::write(offs_t offset, uint8_t data)
case 0x07: m_int2_en_cb(data); break;
case 0x08:
case 0x09:
- m_vc = (m_regs[9]&0xff);
- m_vc |= ((m_regs[8]&0x01)<<8);
+ m_vc = get_u16be(&m_regs[8])&0x01ff;
m_vc++;
logerror("%d (%04x) VC set\n",m_vc,m_vc);
res_change();
break;
case 0x0a:
- m_vfp = (m_regs[0x0a]&0xff);
+ m_vfp = (m_regs[0x0a]&0xff);
logerror("%d (%04x) VFP set\n",m_vfp,m_vfp);
res_change();
break;
case 0x0b:
- m_vbp = (m_regs[0x0b]&0xff);
+ m_vbp = (m_regs[0x0b]&0xff);
m_vbp++;
logerror("%d (%04x) VBP set\n",m_vbp,m_vbp);
res_change();
break;
case 0x0c:
- m_vsw = ((m_regs[0x0c]&0xf0) >> 4) + 1;
- m_hsw = ((m_regs[0x0c]&0x0f) >> 0) + 1;
+ m_vsw = ((m_regs[0x0c]&0xf0) >> 4) + 1;
+ m_hsw = ((m_regs[0x0c]&0x0f) >> 0) + 1;
logerror("%02x VSW / %02x HSW set\n",m_vsw,m_hsw);
res_change();
break;
diff --git a/src/devices/machine/k056230.cpp b/src/devices/machine/k056230.cpp
index 55d0e22177d..68f1a718197 100644
--- a/src/devices/machine/k056230.cpp
+++ b/src/devices/machine/k056230.cpp
@@ -17,101 +17,111 @@ TODO: nearly everything
***************************************************************************/
#include "emu.h"
+
#include "k056230.h"
+#define LOG_REG_READS (1U << 1)
+#define LOG_REG_WRITES (1U << 2)
+#define LOG_RAM_READS (1U << 3)
+#define LOG_RAM_WRITES (1U << 4)
+#define LOG_UNKNOWNS (1U << 5)
+#define LOG_ALL (LOG_REG_READS | LOG_REG_WRITES | LOG_RAM_READS | LOG_RAM_WRITES | LOG_UNKNOWNS)
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
+#define VERBOSE (0)
+#include "logmacro.h"
-// device type definition
DEFINE_DEVICE_TYPE(K056230, k056230_device, "k056230", "K056230 LANC")
-//-------------------------------------------------
-// k056230_device - constructor
-//-------------------------------------------------
-k056230_device::k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+k056230_device::k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, K056230, tag, owner, clock)
- , m_is_thunderh(0)
- , m_cpu(*this, finder_base::DUMMY_TAG)
+ , m_ram(*this, "lanc_ram", 0x800U * 4, ENDIANNESS_BIG)
+ , m_irq_cb(*this)
{
}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
void k056230_device::device_start()
{
- save_item(NAME(m_ram));
-}
+ m_irq_state = CLEAR_LINE;
+ save_item(NAME(m_irq_state));
+}
-uint8_t k056230_device::read(offs_t offset)
+u8 k056230_device::regs_r(offs_t offset)
{
+ u8 data = 0;
+
switch (offset)
{
case 0: // Status register
- {
- return 0x08;
- }
- }
+ data = 0x08;
+ LOGMASKED(LOG_REG_READS, "%s: regs_r: Status Register: %02x\n", machine().describe_context(), data);
+ break;
-// logerror("k056230_r: %d %s\n", offset, machine().describe_context());
+ case 1: // CRC Error register
+ data = 0x00;
+ LOGMASKED(LOG_REG_READS, "%s: regs_r: CRC Error Register: %02x\n", machine().describe_context(), data);
+ break;
- return 0;
-}
+ default:
+ LOGMASKED(LOG_REG_READS, "%s: regs_r: Unknown Register [%02x]: %02x\n", machine().describe_context(), offset, data);
+ break;
+ }
-TIMER_CALLBACK_MEMBER(k056230_device::network_irq_clear)
-{
- if (m_cpu)
- m_cpu->set_input_line(INPUT_LINE_IRQ2, CLEAR_LINE);
+ return data;
}
-
-void k056230_device::write(offs_t offset, uint8_t data)
+void k056230_device::regs_w(offs_t offset, u8 data)
{
- switch(offset)
+ switch (offset)
{
case 0: // Mode register
- {
+ LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Mode Register = %02x\n", machine().describe_context(), data);
break;
- }
+
case 1: // Control register
{
- if(data & 0x20)
+ LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Control Register = %02x\n", machine().describe_context(), data);
+ // TODO: This is a literal translation of the previous device behaviour, and seems pretty likely to be incorrect.
+ const int old_state = m_irq_state;
+ if (BIT(data, 5))
+ {
+ LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Asserting IRQ\n", machine().describe_context());
+ m_irq_state = ASSERT_LINE;
+ }
+ if (!BIT(data, 0))
{
- // Thunder Hurricane breaks otherwise...
- if (!m_is_thunderh)
- {
- if (m_cpu)
- m_cpu->set_input_line(INPUT_LINE_IRQ2, ASSERT_LINE);
-
- machine().scheduler().timer_set(attotime::from_usec(10), timer_expired_delegate(FUNC(k056230_device::network_irq_clear), this));
- }
+ LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Clearing IRQ\n", machine().describe_context());
+ m_irq_state = CLEAR_LINE;
+ }
+ if (old_state != m_irq_state)
+ {
+ m_irq_cb(m_irq_state);
}
-// else
-// m_cpu->set_input_line(INPUT_LINE_IRQ2, CLEAR_LINE);
break;
}
+
case 2: // Sub ID register
- {
+ LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Sub ID Register = %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOGMASKED(LOG_REG_WRITES | LOG_UNKNOWNS, "%s: regs_w: Unknown Register [%02x] = %02x\n", machine().describe_context(), offset, data);
break;
- }
}
-// logerror("k056230_w: %d, %02X at %08X\n", offset, data, machine().describe_context());
}
-uint32_t k056230_device::lanc_ram_r(offs_t offset, uint32_t mem_mask)
+u32 k056230_device::ram_r(offs_t offset, u32 mem_mask)
{
- //logerror("LANC_RAM_r: %08X, %08X %s\n", offset, mem_mask, machine().describe_context());
- return m_ram[offset & 0x7ff];
+ const auto lanc_ram = util::big_endian_cast<const u32>(m_ram.target());
+ u32 data = lanc_ram[offset & 0x7ff];
+ LOGMASKED(LOG_RAM_READS, "%s: Network RAM read [%04x (%03x)]: %08x & %08x\n", machine().describe_context(), offset << 2, (offset & 0x7ff) << 2, data, mem_mask);
+ return data;
}
-void k056230_device::lanc_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void k056230_device::ram_w(offs_t offset, u32 data, u32 mem_mask)
{
- //logerror("LANC_RAM_w: %08X, %08X, %08X %s\n", data, offset, mem_mask, machine().describe_context());
- COMBINE_DATA(m_ram + (offset & 0x7ff));
+ const auto lanc_ram = util::big_endian_cast<u32>(m_ram.target());
+ LOGMASKED(LOG_RAM_WRITES, "%s: Network RAM write [%04x (%03x)] = %08x & %08x\n", machine().describe_context(), offset << 2, (offset & 0x7ff) << 2, data, mem_mask);
+ COMBINE_DATA(&lanc_ram[offset & 0x7ff]);
}
diff --git a/src/devices/machine/k056230.h b/src/devices/machine/k056230.h
index bfedc22d475..7df76c26e53 100644
--- a/src/devices/machine/k056230.h
+++ b/src/devices/machine/k056230.h
@@ -2,7 +2,7 @@
// copyright-holders:Fabio Priuli
/***************************************************************************
- Konami 056230
+ Konami 056230 LAN controller skeleton device
***************************************************************************/
@@ -15,35 +15,25 @@ class k056230_device : public device_t
{
public:
// construction/destruction
- template <typename T>
- k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu_tag)
- : k056230_device(mconfig, tag, owner, (uint32_t)0)
- {
- m_cpu.set_tag(std::forward<T>(cpu_tag));
- }
+ k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
- k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ auto irq_cb() { return m_irq_cb.bind(); }
- void set_thunderh_hack(bool thunderh) { m_is_thunderh = thunderh; }
+ u32 ram_r(offs_t offset, u32 mem_mask = ~0);
+ void ram_w(offs_t offset, u32 data, u32 mem_mask = ~0);
- uint32_t lanc_ram_r(offs_t offset, uint32_t mem_mask = ~0);
- void lanc_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
-
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
-
- TIMER_CALLBACK_MEMBER(network_irq_clear);
+ u8 regs_r(offs_t offset);
+ void regs_w(offs_t offset, u8 data);
protected:
// device-level overrides
virtual void device_start() override;
-private:
-
- bool m_is_thunderh;
+ memory_share_creator<u32> m_ram;
- required_device<cpu_device> m_cpu;
- uint32_t m_ram[0x2000];
+ devcb_write_line m_irq_cb;
+ int m_irq_state;
+ u8 m_ctrl_reg;
};
diff --git a/src/devices/machine/kb3600.cpp b/src/devices/machine/kb3600.cpp
index 5400d8ac1a8..5ebc9c56e0c 100644
--- a/src/devices/machine/kb3600.cpp
+++ b/src/devices/machine/kb3600.cpp
@@ -40,17 +40,17 @@ DEFINE_DEVICE_TYPE(AY3600, ay3600_device, "ay3600", "AY-5-3600 Keyboard Encoder"
ay3600_device::ay3600_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, AY3600, tag, owner, clock),
- m_read_x0(*this),
- m_read_x1(*this),
- m_read_x2(*this),
- m_read_x3(*this),
- m_read_x4(*this),
- m_read_x5(*this),
- m_read_x6(*this),
- m_read_x7(*this),
- m_read_x8(*this),
- m_read_shift(*this),
- m_read_control(*this),
+ m_read_x0(*this, 0),
+ m_read_x1(*this, 0),
+ m_read_x2(*this, 0),
+ m_read_x3(*this, 0),
+ m_read_x4(*this, 0),
+ m_read_x5(*this, 0),
+ m_read_x6(*this, 0),
+ m_read_x7(*this, 0),
+ m_read_x8(*this, 0),
+ m_read_shift(*this, 0),
+ m_read_control(*this, 0),
m_write_data_ready(*this),
m_write_ako(*this)
{
@@ -66,23 +66,8 @@ ay3600_device::ay3600_device(const machine_config &mconfig, const char *tag, dev
void ay3600_device::device_start()
{
- // resolve callbacks
- m_read_x0.resolve_safe(0);
- m_read_x1.resolve_safe(0);
- m_read_x2.resolve_safe(0);
- m_read_x3.resolve_safe(0);
- m_read_x4.resolve_safe(0);
- m_read_x5.resolve_safe(0);
- m_read_x6.resolve_safe(0);
- m_read_x7.resolve_safe(0);
- m_read_x8.resolve_safe(0);
- m_read_shift.resolve_safe(0);
- m_read_control.resolve_safe(0);
- m_write_data_ready.resolve_safe();
- m_write_ako.resolve_safe();
-
// allocate timers
- m_scan_timer = timer_alloc();
+ m_scan_timer = timer_alloc(FUNC(ay3600_device::perform_scan), this);
m_scan_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60));
m_ako = 0;
@@ -103,10 +88,10 @@ void ay3600_device::device_reset()
}
//-------------------------------------------------
-// device_timer - handler timer events
+// perform_scan - scan the keyboard matrix
//-------------------------------------------------
-void ay3600_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ay3600_device::perform_scan)
{
int ako = 0;
diff --git a/src/devices/machine/kb3600.h b/src/devices/machine/kb3600.h
index fce1eab7646..c65bbea3a6f 100644
--- a/src/devices/machine/kb3600.h
+++ b/src/devices/machine/kb3600.h
@@ -83,7 +83,8 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(perform_scan);
devcb_read16 m_read_x0, m_read_x1, m_read_x2, m_read_x3, m_read_x4, m_read_x5, m_read_x6, m_read_x7, m_read_x8;
devcb_read_line m_read_shift, m_read_control;
diff --git a/src/devices/machine/keyboard.cpp b/src/devices/machine/keyboard.cpp
index eacd6786689..d307d637d27 100644
--- a/src/devices/machine/keyboard.cpp
+++ b/src/devices/machine/keyboard.cpp
@@ -22,6 +22,10 @@ void xxx_state::kbd_put(u8 data)
(if your machine uses function keys, add your conversion code here)
}
+In a device, at the top of the device's .cpp file in the appropriate spot:
+
+#include "machine/keyboard.ipp"
+
***************************************************************************/
#include "emu.h"
@@ -272,7 +276,7 @@ ioport_constructor generic_keyboard_device::device_input_ports() const
void generic_keyboard_device::device_start()
{
- m_keyboard_cb.resolve();
+ m_keyboard_cb.resolve_safe();
save_item(NAME(m_last_modifiers));
}
@@ -303,7 +307,6 @@ void generic_keyboard_device::key_repeat(u8 row, u8 column)
void generic_keyboard_device::send_key(u8 code)
{
- assert(!m_keyboard_cb.isnull());
m_keyboard_cb(code);
}
diff --git a/src/devices/machine/keyboard.ipp b/src/devices/machine/keyboard.ipp
index 12221dde05c..12dfb7b1a5a 100644
--- a/src/devices/machine/keyboard.ipp
+++ b/src/devices/machine/keyboard.ipp
@@ -106,8 +106,8 @@ void device_matrix_keyboard_interface<ROW_COUNT>::typematic_stop()
template <uint8_t ROW_COUNT>
TIMER_CALLBACK_MEMBER(device_matrix_keyboard_interface<ROW_COUNT>::scan_row)
{
- assert(m_next_row < ARRAY_LENGTH(m_key_rows));
- assert(m_next_row < ARRAY_LENGTH(m_key_states));
+ assert(m_next_row < std::size(m_key_rows));
+ assert(m_next_row < std::size(m_key_states));
will_scan_row(m_next_row);
@@ -128,7 +128,7 @@ TIMER_CALLBACK_MEMBER(device_matrix_keyboard_interface<ROW_COUNT>::scan_row)
}
}
- m_next_row = (m_next_row + 1) % ARRAY_LENGTH(m_key_rows);
+ m_next_row = (m_next_row + 1) % std::size(m_key_rows);
if (m_next_row == 0)
scan_complete();
}
diff --git a/src/devices/machine/keytronic_l2207.cpp b/src/devices/machine/keytronic_l2207.cpp
new file mode 100644
index 00000000000..2cd5db800e0
--- /dev/null
+++ b/src/devices/machine/keytronic_l2207.cpp
@@ -0,0 +1,311 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Keytronic L2207 83-key keyboard
+
+ This was sold by Keytronic as a generic VT100-lookalike ASCII
+ keyboard. Its normal configuration communicates via 300 baud
+ asynchronous TTL-level serial, but populating a few additional
+ components and using an alternate connector gives it a parallel
+ interface for outputs. The PCB additionally supports a "minimum"
+ interface that eliminates the MCU and provides a raw interface to
+ the capacitive key matrix ASICs (22-950-003 decoder & 22-908-003
+ detector, as described in U.S. Patent 4,277,780) and LED latch.
+
+ Keys generating non-ASCII codes:
+
+ No Scroll B0
+ 0 (keypad) B1
+ . (keypad) B2
+ 1 (keypad) C0
+ 2 (keypad) C1
+ 3 (keypad) C2
+ Enter (keypad) C3
+ 4 (keypad) D0
+ 5 (keypad) D1
+ 6 (keypad) D2
+ , (keypad) D3
+ Break E0
+ 7 (keypad) E1
+ 8 (keypad) E2
+ 9 (keypad) E3
+ - (keypad) E4
+ Ctrl+3 E5
+ ↑ F1
+ ↓ F2
+ ← F3
+ → F4
+ PF1 F6
+ PF2 F7
+ PF3 F8
+ PF4 F9
+ Set-Up FE
+
+ Several other codes (A0-A5, D4, D6, F0, F5) are assigned to
+ 9 additional switches which are not normally populated. The
+ presently dumped firmware also sends AA in response to the
+ undocumented test command below.
+
+ List of commands (delivered through serial input):
+
+ D7 D6 D5 D4 D3 D2 D1 D0
+
+ l8 l7 l6 l5 l4 l3 l2 1 Set LED data
+ - - - - - - 1 0 Short beep
+ - - - - - 1 0 0 Long beep
+ - - - - 1 0 0 0 Key click off
+ - - - 1 0 0 0 0 Test? (undocumented)
+ - - - 0 0 0 0 0 Key click on
+
+ An alternate version of this keyboard, whose solder side is
+ labeled "PCB-251 / KTC A65-02675-051." has differently styled
+ keytops and a different EPROM but is otherwise identical in layout
+ and functionality.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "keytronic_l2207.h"
+
+#include "speaker.h"
+
+DEFINE_DEVICE_TYPE(KEYTRONIC_L2207, keytronic_l2207_device, "keytronic_l2207", "Keytronic L2207 serial keyboard")
+
+keytronic_l2207_device::keytronic_l2207_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, KEYTRONIC_L2207, tag, owner, clock)
+ , m_mcu(*this, "mcu")
+ , m_beeper(*this, "beeper")
+ , m_keys(*this, "KEYS%d", 0U)
+ , m_leds(*this, "kbd_led%d", 1U)
+ , m_all_caps(*this, "all_caps")
+ , m_ser_out_callback(*this)
+ , m_p1_in(0xff)
+ , m_p2_out(0)
+ , m_beeper_latch(false)
+{
+}
+
+void keytronic_l2207_device::device_resolve_objects()
+{
+ m_leds.resolve();
+ m_all_caps.resolve();
+}
+
+void keytronic_l2207_device::device_start()
+{
+ save_item(NAME(m_p1_in));
+ save_item(NAME(m_p2_out));
+ save_item(NAME(m_beeper_latch));
+}
+
+void keytronic_l2207_device::ser_in_w(int state)
+{
+ m_mcu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE);
+}
+
+u8 keytronic_l2207_device::led_latch_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ u8 led_data = m_mcu->p1_r();
+
+ if (BIT(m_p2_out, 6))
+ m_beeper->level_w(BIT(led_data, 0));
+ m_beeper_latch = BIT(led_data, 0);
+
+ m_leds[0] = !BIT(led_data, 1);
+ for (int n = 1; n < 8; n++)
+ m_leds[n] = BIT(led_data, n);
+ }
+
+ return 0;
+}
+
+u8 keytronic_l2207_device::p1_r()
+{
+ return m_p1_in;
+}
+
+void keytronic_l2207_device::p2_w(u8 data)
+{
+ if (BIT(data, 5) != BIT(m_p2_out, 5))
+ m_ser_out_callback(BIT(data, 5));
+
+ if (!BIT(data, 4))
+ m_p1_in = 0xff;
+ else if (!BIT(m_p2_out, 4))
+ {
+ u8 j = m_mcu->p1_r() & 0x0f;
+ if (j < 12)
+ m_p1_in = m_keys[j]->read();
+ }
+
+ if (m_beeper_latch && BIT(data, 6) != BIT(m_p2_out, 6))
+ m_beeper->level_w(BIT(data, 6));
+
+ m_all_caps = BIT(data, 7);
+
+ m_p2_out = data;
+}
+
+void keytronic_l2207_device::prog_map(address_map &map)
+{
+ map.global_mask(0x7ff);
+ map(0x000, 0x7ff).rom().region("eprom", 0);
+}
+
+void keytronic_l2207_device::ext_map(address_map &map)
+{
+ map(0x00, 0xff).r(FUNC(keytronic_l2207_device::led_latch_r)).nopw(); // WR connected for parallel interface only
+}
+
+static INPUT_PORTS_START(keytronic_l2207)
+ PORT_START("KEYS0")
+ PORT_BIT(0x0d, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Set-Up") PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CODE(KEYCODE_ESC)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CHAR(UCHAR_SHIFT_2) PORT_CODE(KEYCODE_LCONTROL)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_CODE(KEYCODE_CAPSLOCK)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CHAR(UCHAR_SHIFT_1) PORT_CODE(KEYCODE_LSHIFT)
+
+ PORT_START("KEYS1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CHAR(0x1b) PORT_CODE(KEYCODE_TILDE)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('1') PORT_CHAR('!') PORT_CODE(KEYCODE_1)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CHAR(0x09) PORT_CODE(KEYCODE_TAB)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11) PORT_CODE(KEYCODE_Q)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01) PORT_CODE(KEYCODE_A)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("S") PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13) PORT_CODE(KEYCODE_S)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("No Scrl") PORT_CODE(KEYCODE_LALT)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("KEYS2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('2') PORT_CHAR('@') PORT_CODE(KEYCODE_2)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(u8"3 # £") PORT_CHAR('3') PORT_CHAR('#', 0x00a3) PORT_CODE(KEYCODE_3)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W") PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17) PORT_CODE(KEYCODE_W)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E") PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05) PORT_CODE(KEYCODE_E)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D") PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04) PORT_CODE(KEYCODE_D)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F") PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06) PORT_CODE(KEYCODE_F)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a) PORT_CODE(KEYCODE_Z)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18) PORT_CODE(KEYCODE_X)
+
+ PORT_START("KEYS3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('4') PORT_CHAR('$') PORT_CODE(KEYCODE_4)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('5') PORT_CHAR('%') PORT_CODE(KEYCODE_5)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("R") PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12) PORT_CODE(KEYCODE_R)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T") PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14) PORT_CODE(KEYCODE_T)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G Bell") PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07) PORT_CODE(KEYCODE_G)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H") PORT_CHAR('h') PORT_CHAR('H') PORT_CODE(KEYCODE_H)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C") PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03) PORT_CODE(KEYCODE_C)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V") PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16) PORT_CODE(KEYCODE_V)
+
+ PORT_START("KEYS4")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('6') PORT_CHAR('^') PORT_CODE(KEYCODE_6)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('7') PORT_CHAR('&') PORT_CODE(KEYCODE_7)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y") PORT_CHAR('y') PORT_CHAR('y') PORT_CHAR(0x19) PORT_CODE(KEYCODE_Y)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U") PORT_CHAR('u') PORT_CHAR('u') PORT_CHAR(0x15) PORT_CODE(KEYCODE_U)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("J") PORT_CHAR('j') PORT_CHAR('j') PORT_CODE(KEYCODE_J)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("K") PORT_CHAR('k') PORT_CHAR('k') PORT_CHAR(0x0b) PORT_CODE(KEYCODE_K)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B") PORT_CHAR('b') PORT_CHAR('b') PORT_CHAR(0x02) PORT_CODE(KEYCODE_B)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N") PORT_CHAR('n') PORT_CHAR('n') PORT_CHAR(0x0e) PORT_CODE(KEYCODE_N)
+
+ PORT_START("KEYS5")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('8') PORT_CHAR('*') PORT_CODE(KEYCODE_8)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('9') PORT_CHAR('(') PORT_CODE(KEYCODE_9)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I") PORT_CHAR('i') PORT_CHAR('I') PORT_CODE(KEYCODE_I)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O") PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f) PORT_CODE(KEYCODE_O)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L") PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c) PORT_CODE(KEYCODE_L)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(';') PORT_CHAR(':') PORT_CODE(KEYCODE_COLON)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M") PORT_CHAR('m') PORT_CHAR('M') PORT_CODE(KEYCODE_M)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(',') PORT_CHAR('<') PORT_CODE(KEYCODE_COMMA)
+
+ PORT_START("KEYS6")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('0') PORT_CHAR(')') PORT_CODE(KEYCODE_0)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('-') PORT_CHAR('_') PORT_CODE(KEYCODE_MINUS)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P") PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10) PORT_CODE(KEYCODE_P)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('[') PORT_CHAR('{') PORT_CODE(KEYCODE_OPENBRACE)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\'') PORT_CHAR('"') PORT_CODE(KEYCODE_QUOTE)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CHAR(0x0d) PORT_CODE(KEYCODE_ENTER)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('.') PORT_CHAR('>') PORT_CODE(KEYCODE_STOP)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('/') PORT_CHAR('?') PORT_CODE(KEYCODE_SLASH)
+
+ PORT_START("KEYS7")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('=') PORT_CHAR('+') PORT_CODE(KEYCODE_EQUALS)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('`') PORT_CHAR('~') PORT_CODE(KEYCODE_BACKSLASH)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(']') PORT_CHAR('}') PORT_CODE(KEYCODE_CLOSEBRACE)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR('\\') PORT_CHAR('|') PORT_CODE(KEYCODE_PGUP)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) PORT_CODE(KEYCODE_1_PAD)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) PORT_CODE(KEYCODE_0_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CHAR(0x0a) PORT_CODE(KEYCODE_PGDN)
+
+ PORT_START("KEYS8")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Back Space") PORT_CHAR(0x08) PORT_CODE(KEYCODE_BACKSPACE)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_INSERT)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Del") PORT_CHAR(UCHAR_MAMEKEY(DEL)) PORT_CODE(KEYCODE_DEL)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) PORT_CODE(KEYCODE_4_PAD)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) PORT_CODE(KEYCODE_2_PAD)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) PORT_CODE(KEYCODE_3_PAD)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) PORT_CODE(KEYCODE_DEL_PAD)
+
+ PORT_START("KEYS9")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) PORT_CODE(KEYCODE_7_PAD)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) PORT_CODE(KEYCODE_8_PAD)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) PORT_CODE(KEYCODE_6_PAD)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF2") PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CODE(KEYCODE_F2)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF1") PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CODE(KEYCODE_F1)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CODE(KEYCODE_DOWN)
+
+ PORT_START("KEYS10")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) PORT_CODE(KEYCODE_9_PAD)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) PORT_CODE(KEYCODE_MINUS_PAD)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) PORT_CODE(KEYCODE_PLUS_PAD)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF4") PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CODE(KEYCODE_F4)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF3") PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CODE(KEYCODE_F3)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_CODE(KEYCODE_UP)
+
+ PORT_START("KEYS11")
+ PORT_BIT(0x5f, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_CODE(KEYCODE_ENTER_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(' ') PORT_CODE(KEYCODE_SPACE)
+INPUT_PORTS_END
+
+ioport_constructor keytronic_l2207_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(keytronic_l2207);
+}
+
+void keytronic_l2207_device::device_add_mconfig(machine_config &config)
+{
+ I8035(config, m_mcu, 3.579545_MHz_XTAL); // P8035HL + 48-00300-010 XTAL
+ m_mcu->set_addrmap(AS_PROGRAM, &keytronic_l2207_device::prog_map);
+ m_mcu->set_addrmap(AS_IO, &keytronic_l2207_device::ext_map);
+ m_mcu->p1_in_cb().set(FUNC(keytronic_l2207_device::p1_r));
+ m_mcu->p2_out_cb().set(FUNC(keytronic_l2207_device::p2_w));
+ m_mcu->t0_in_cb().set_constant(1); // tied to EA
+ m_mcu->t1_in_cb().set_constant(0); // pulled up for inverted parallel output
+ m_mcu->bus_out_cb().set_nop(); // WR connected for parallel interface only
+ m_mcu->prog_out_cb().set_nop(); // STB on parallel connector
+
+ SPEAKER(config, "mono").front_center(); // 48-00125-000 + flyback diode
+ SPEAKER_SOUND(config, m_beeper).add_route(ALL_OUTPUTS, "mono", 0.5);
+}
+
+ROM_START(keytronic_l2207)
+ ROM_REGION(0x800, "eprom", 0)
+ ROM_SYSTEM_BIOS(0, "a65_02207", "A65-02207-051/2510") // from Wicat System 150
+ ROMX_LOAD("w150_ns2758.bin", 0x000, 0x400, CRC(f65e1ca5) SHA1(7919385fe8badbb610b793a3f5e4077982094aaa), ROM_BIOS(0))
+ ROM_RELOAD(0x400, 0x400)
+ ROM_SYSTEM_BIOS(1, "a65_02675", "A65-02675-051")
+ ROMX_LOAD("key_05__162092859__8-23-82.bin", 0x000, 0x800, CRC(970b11a3) SHA1(a1c9c505eb3ccf132307b2ac0e04b0326f50621e), ROM_BIOS(1)) // MM2716Q
+ROM_END
+
+const tiny_rom_entry *keytronic_l2207_device::device_rom_region() const
+{
+ return ROM_NAME(keytronic_l2207);
+}
diff --git a/src/devices/machine/keytronic_l2207.h b/src/devices/machine/keytronic_l2207.h
new file mode 100644
index 00000000000..bad5c635fc6
--- /dev/null
+++ b/src/devices/machine/keytronic_l2207.h
@@ -0,0 +1,75 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Keytronic L2207 83-key keyboard
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_KEYTRONIC_L2207_H
+#define MAME_MACHINE_KEYTRONIC_L2207_H
+
+#pragma once
+
+#include "cpu/mcs48/mcs48.h"
+#include "sound/spkrdev.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> keytronic_l2207_device
+
+class keytronic_l2207_device : public device_t
+{
+public:
+ // device type constructor
+ keytronic_l2207_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ static constexpr feature_type imperfect_features() { return feature::SOUND; }
+
+ // callback configuration
+ auto ser_out_callback() { return m_ser_out_callback.bind(); }
+
+ // serial line input
+ void ser_in_w(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_resolve_objects() override;
+ virtual void device_start() override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+
+private:
+ // MCU handlers
+ u8 led_latch_r();
+ u8 p1_r();
+ void p2_w(u8 data);
+
+ // address maps
+ void prog_map(address_map &map);
+ void ext_map(address_map &map);
+
+ // object finders
+ required_device<mcs48_cpu_device> m_mcu;
+ required_device<speaker_sound_device> m_beeper;
+ required_ioport_array<12> m_keys;
+ output_finder<8> m_leds;
+ output_finder<> m_all_caps;
+
+ // output callback
+ devcb_write_line m_ser_out_callback;
+
+ // internal state
+ u8 m_p1_in;
+ u8 m_p2_out;
+ bool m_beeper_latch;
+};
+
+// device type declarations
+DECLARE_DEVICE_TYPE(KEYTRONIC_L2207, keytronic_l2207_device)
+
+#endif // MAME_MACHINE_KEYTRONIC_L2207_H
diff --git a/src/devices/machine/kr1601rr1.cpp b/src/devices/machine/kr1601rr1.cpp
new file mode 100644
index 00000000000..b3ebb561675
--- /dev/null
+++ b/src/devices/machine/kr1601rr1.cpp
@@ -0,0 +1,154 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/***************************************************************************
+
+ KR1601RR1 1024x4 bit EAROM
+
+ Same geometry as GI ER2401, but not pin-compatible.
+
+ To do:
+ - realistic timing esp. for ERASE_ALL
+ - alternate wirings
+
+***************************************************************************/
+
+#include "emu.h"
+#include "kr1601rr1.h"
+
+#include <algorithm>
+
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC printf
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(KR1601RR1, kr1601rr1_device, "kr1601rr1", "KR1601RR1 EAROM")
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+kr1601rr1_device::kr1601rr1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, KR1601RR1, tag, owner, clock)
+ , device_nvram_interface(mconfig, *this)
+{
+}
+
+uint8_t kr1601rr1_device::read(offs_t offset)
+{
+ assert(EAROM_SIZE > offset);
+ if (m_earom_mode == EAROM_READ)
+ {
+ LOG("earom R %03x == %x\n", offset, m_earom[offset] & 15);
+ return m_earom[offset] & 15;
+ }
+ else return 0;
+}
+
+/*
+ * wiring hardcoded for ms6102:
+ *
+ * b7..b4 = CS _PR _ER RD
+ * b3..b0 = data
+ */
+void kr1601rr1_device::write(offs_t offset, uint8_t data)
+{
+ assert(EAROM_SIZE > offset);
+
+ switch (data >> 4)
+ {
+ case 0x0: case 0x1: case 0x2: case 0x3:
+ case 0x4: case 0x5: case 0x6: case 0x7:
+ m_earom_mode = EAROM_IDLE;
+ break;
+
+ case 0x8:
+ m_earom_mode = EAROM_ERASE;
+ break;
+
+ case 0xa:
+ m_earom_mode = EAROM_WRITE;
+ break;
+
+ case 0xc:
+ m_earom_mode = EAROM_ERASE_ALL;
+ break;
+
+ case 0xf:
+ m_earom_mode = EAROM_READ;
+ break;
+ }
+ LOG("earom new mode = %u (from %02X)\n", m_earom_mode, data);
+
+ switch (m_earom_mode)
+ {
+ case EAROM_WRITE:
+ LOG("earom W %03x <- %x\n", offset, data & 15);
+ m_earom[offset] |= (data & 15);
+ break;
+
+ case EAROM_ERASE:
+ LOG("earom erase %03x\n", offset);
+ m_earom[offset] = 0;
+ break;
+
+ case EAROM_ERASE_ALL:
+ LOG("earom erase all\n");
+ std::fill(std::begin(m_earom), std::end(m_earom), 0);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void kr1601rr1_device::nvram_default()
+{
+ std::fill(std::begin(m_earom), std::end(m_earom), 0);
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+bool kr1601rr1_device::nvram_read(util::read_stream &file)
+{
+ auto const [err, actual] = util::read(file, m_earom, EAROM_SIZE);
+ return !err && (actual == EAROM_SIZE);
+}
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+bool kr1601rr1_device::nvram_write(util::write_stream &file)
+{
+ auto const [err, actual] = util::write(file, m_earom, EAROM_SIZE);
+ return !err;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+void kr1601rr1_device::device_start()
+{
+ /* register for save states */
+ save_item(NAME(m_earom));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void kr1601rr1_device::device_reset()
+{
+ m_earom_mode = EAROM_IDLE;
+}
diff --git a/src/devices/machine/kr1601rr1.h b/src/devices/machine/kr1601rr1.h
new file mode 100644
index 00000000000..49837e42c32
--- /dev/null
+++ b/src/devices/machine/kr1601rr1.h
@@ -0,0 +1,77 @@
+// license:BSD-3-Clause
+// copyright-holders:Sergey Svishchev
+/***************************************************************************
+
+ KR1601RR1 1024x4 bit EAROM
+
+ Same geometry as GI ER2401, but not pin-compatible.
+
+ CS ER PR RD Ax
+ -- -- -- -- --
+ 0 x x x x idle
+ 1 0 1 0 x erase all
+ 1 0 0 0 A erase single
+ 1 1 0 0 A write
+ 1 1 1 1 A read
+
+****************************************************************************
+ _____ _____
+ A9 1 |* \_/ | 24
+ CS 2 | | 23 A8
+ D0 3 | | 22 A7
+ _OV 4 | | 21 A6
+ D1 5 | | 20 A5
+ A0 6 | | 19 A4
+ A3 7 | KR1601RR1 | 18 _ER
+ A1 8 | | 17
+ A2 9 | | 16
+ D2 10 | | 15 _UPR
+ D3 11 | | 14 _PR
+ _U1 12 |_____________| 13 RD
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_KR1601RR1_H
+#define MAME_MACHINE_KR1601RR1_H
+
+#pragma once
+
+
+// ======================> kr1601rr1_device
+
+class kr1601rr1_device : public device_t, public device_nvram_interface
+{
+public:
+ // construction/destruction
+ kr1601rr1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ uint8_t read(offs_t offset);
+ void write(offs_t offset, uint8_t data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_nvram_interface overrides
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+private:
+ enum { EAROM_SIZE = 1024 };
+ enum {
+ EAROM_IDLE,
+ EAROM_READ,
+ EAROM_WRITE,
+ EAROM_ERASE,
+ EAROM_ERASE_ALL
+ } m_earom_mode = EAROM_IDLE;
+
+ uint8_t m_earom[EAROM_SIZE];
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(KR1601RR1, kr1601rr1_device)
+
+#endif // MAME_MACHINE_KR1601RR1_H
diff --git a/src/devices/machine/kr2376.cpp b/src/devices/machine/kr2376.cpp
index 7d59c4ea317..ff2c1d00bec 100644
--- a/src/devices/machine/kr2376.cpp
+++ b/src/devices/machine/kr2376.cpp
@@ -11,13 +11,13 @@
DEFINE_DEVICE_TYPE(KR2376_ST, kr2376_st_device, "kr2376_st", "SMC KR2376-ST Keyboard Encoder")
-//DEFINE_DEVICE_TYPE(KR2376_12, kr2376_12_device, "kr2376_12", "SMC KR2376-12 Keyboard Encoder")
+DEFINE_DEVICE_TYPE(KR2376_12, kr2376_12_device, "kr2376_12", "SMC KR2376-12 Keyboard Encoder")
kr2376_device::kr2376_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
- m_read_x(*this),
- m_read_shift(*this),
- m_read_control(*this),
+ m_read_x(*this, 0x7ff),
+ m_read_shift(*this, 0),
+ m_read_control(*this, 0),
m_write_strobe(*this)
{
}
@@ -85,55 +85,80 @@ uint8_t kr2376_st_device::key_codes(int mode, int x, int y)
return KEY_CODES[mode][x][y];
}
-// TODO: determine ROM contents of KR2376-12
-//kr2376_12_device::kr2376_12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
-// : kr2376_device(mconfig, KR2376_12, tag, owner, clock)
-//{}
-//uint8_t kr2376_12_device::key_codes(int mode, int x, int y)
-//{
-// static const uint8_t KEY_CODES[3][8][11] =
-// {
-// // normal
-// {
-// // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10
-// { 0x33, 0x32, 0x31, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00 }, // X0
-// { 0x36, 0x35, 0x34, 0x7d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // X1
-// { 0x39, 0x38, 0x37, 0x5b, 0x02, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00 }, // X2
-// { 0x08, 0x0a, 0x09, 0x0b, 0x00, 0x7c, 0x00, 0x00, 0x0d, 0x20, 0x00 }, // X3
-// { 0x2d, 0x2f, 0x2e, 0x2c, 0x6d, 0x6e, 0x62, 0x76, 0x63, 0x78, 0x7a }, // X4
-// { 0x3a, 0x3b, 0x6c, 0x6b, 0x6a, 0x68, 0x67, 0x66, 0x64, 0x73, 0x61 }, // X5
-// { 0x60, 0x70, 0x6f, 0x69, 0x75, 0x79, 0x74, 0x72, 0x65, 0x77, 0x71 }, // X6
-// { 0x2d, 0x30, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31 } // X7
-// },
-//
-// // shift
-// {
-// // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10
-// { 0x33, 0x32, 0x31, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00 }, // X0
-// { 0x36, 0x35, 0x34, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // X1
-// { 0x39, 0x38, 0x37, 0x7b, 0x04, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00 }, // X2
-// { 0x08, 0x0a, 0x09, 0x0b, 0x00, 0x5c, 0x00, 0x00, 0x0d, 0x20, 0x00 }, // X3
-// { 0x2d, 0x3f, 0x3e, 0x3c, 0x4d, 0x4e, 0x42, 0x56, 0x43, 0x58, 0x5a }, // X4
-// { 0x2a, 0x2b, 0x4c, 0x4b, 0x4a, 0x48, 0x47, 0x46, 0x44, 0x53, 0x41 }, // X5
-// { 0x40, 0x50, 0x4f, 0x49, 0x55, 0x59, 0x54, 0x52, 0x45, 0x57, 0x51 }, // X6
-// { 0x3d, 0x30, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21 } // X7
-// },
-//
-// // control
-// {
-// // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10
-// { 0x33, 0x32, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // X0
-// { 0x36, 0x35, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // X1
-// { 0x39, 0x38, 0x37, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00 }, // X2
-// { 0x08, 0x0a, 0x09, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x20, 0x00 }, // X3
-// { 0x1f, 0x2f, 0x2e, 0x2c, 0x0d, 0x0e, 0x02, 0x16, 0x03, 0x18, 0x1a }, // X4
-// { 0x3a, 0x3b, 0x0c, 0x0b, 0x0a, 0x08, 0x07, 0x06, 0x04, 0x13, 0x01 }, // X5
-// { 0x00, 0x10, 0x0f, 0x09, 0x15, 0x19, 0x14, 0x12, 0x05, 0x17, 0x11 }, // X6
-// { 0x2d, 0x30, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31 } // X7
-// }
-// };
-// return KEY_CODES[mode][x][y];
-//}
+kr2376_12_device::kr2376_12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : kr2376_device(mconfig, KR2376_12, tag, owner, clock)
+{
+}
+
+uint8_t kr2376_12_device::key_codes(int mode, int x, int y)
+{
+ static const uint8_t KEY_CODES[3][8][11] =
+ {
+ // normal
+ {
+ // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10
+ // 3 2 1 RS SUB GS SYN STX NAK DC4 NUL
+ { 0x33, 0x32, 0x31, 0x1e, 0x1a, 0x1d, 0x16, 0x02, 0x15, 0x14, 0x00 }, // X0
+ // 6 5 4 ] [ ETX CAN GS DEL DLE SOH
+ { 0x36, 0x35, 0x34, 0x5d, 0x5b, 0x03, 0x18, 0x1d, 0x7f, 0x10, 0x01 }, // X1
+ // 9 8 7 | ~ FS EM ESC SUB HT ACK
+ { 0x39, 0x38, 0x37, 0x7c, 0x7e, 0x1c, 0x19, 0x1b, 0x1a, 0x09, 0x06 }, // X2
+ // US VT DC1 BS SI HT LF FF CR SP ETB
+ { 0x1f, 0x0b, 0x11, 0x08, 0x0f, 0x09, 0x0a, 0x0c, 0x0d, 0x20, 0x17 }, // X3
+ // - 0 9 8 7 6 5 4 3 2 1
+ { 0x2d, 0x30, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31 }, // X4
+ // \ p o i u y t r e w q
+ { 0x5c, 0x70, 0x6f, 0x69, 0x75, 0x79, 0x74, 0x72, 0x65, 0x77, 0x71 }, // X5
+ // : ; l k j h g f d s a
+ { 0x3a, 0x3b, 0x6c, 0x6b, 0x6a, 0x68, 0x67, 0x66, 0x64, 0x73, 0x61 }, // X6
+ // _ / . , m n b v c x z
+ { 0x5f, 0x2f, 0x2e, 0x2c, 0x6d, 0x6e, 0x62, 0x76, 0x63, 0x78, 0x7a } // X7
+ },
+
+ // shift
+ {
+ // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10
+ // 3 2 1 RS SUB DC2 SYN STX NAK DC4 NUL
+ { 0x33, 0x32, 0x31, 0x1e, 0x1a, 0x12, 0x16, 0x02, 0x15, 0x14, 0x00 }, // X0
+ // 6 5 4 } { ETX CAN GS DEL DLE SOH
+ { 0x36, 0x35, 0x34, 0x7d, 0x7b, 0x03, 0x18, 0x1d, 0x7f, 0x10, 0x01 }, // X1
+ // 9 8 7 \ ^ FS EM ESC SUB HT ACK
+ { 0x39, 0x38, 0x37, 0x5c, 0x5e, 0x1c, 0x19, 0x1b, 0x1a, 0x09, 0x06 }, // X2
+ // US VT DC1 BS SO DC3 LF FF CR SP ETB
+ { 0x1f, 0x0b, 0x11, 0x08, 0x0e, 0x13, 0x0a, 0x0c, 0x0d, 0x20, 0x17 }, // X3
+ // = 0 ) ( ' & % $ # " !
+ { 0x3d, 0x30, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21 }, // X4
+ // @ P O I U Y T R E W Q
+ { 0x40, 0x50, 0x4f, 0x49, 0x55, 0x59, 0x54, 0x52, 0x45, 0x57, 0x51 }, // X5
+ // * + L K J H G F D S A
+ { 0x2a, 0x2b, 0x4c, 0x4b, 0x4a, 0x48, 0x47, 0x46, 0x44, 0x53, 0x41 }, // X6
+ // _ ? > < M N B V C X Z
+ { 0x5f, 0x3f, 0x3e, 0x3c, 0x4d, 0x4e, 0x42, 0x56, 0x43, 0x58, 0x5a } // X7
+ },
+
+ // control
+ {
+ // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10
+ // 3 2 1 RS SUB GS SYN STX NAK DC4 NUL
+ { 0x33, 0x32, 0x31, 0x1e, 0x1a, 0x1d, 0x16, 0x02, 0x15, 0x14, 0x00 }, // X0
+ // 6 5 4 GS ESC ETX CAN GS DEL DLE SOH
+ { 0x36, 0x35, 0x34, 0x1d, 0x1b, 0x03, 0x18, 0x1d, 0x7f, 0x10, 0x01 }, // X1
+ // 9 8 7 FS RS FS EM ESC SUB HT ACK
+ { 0x39, 0x38, 0x37, 0x1c, 0x1e, 0x1c, 0x19, 0x1b, 0x1a, 0x09, 0x06 }, // X2
+ // US VT DC1 BS SI HT LF FF CR SP ETB
+ { 0x1f, 0x0b, 0x11, 0x08, 0x0f, 0x09, 0x0a, 0x0c, 0x0d, 0x20, 0x17 }, // X3
+ // - 0 9 8 7 6 5 4 3 2 1
+ { 0x2d, 0x30, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31 }, // X4
+ // NUL DLE SI HT NAK EM DC4 DC2 ENQ ETB DC1
+ { 0x00, 0x10, 0x0f, 0x09, 0x15, 0x19, 0x14, 0x12, 0x05, 0x17, 0x11 }, // X5
+ // : ; FF VT LF BS BEL ACK EOT DC3 SOH
+ { 0x3a, 0x3b, 0x0c, 0x0b, 0x0a, 0x08, 0x07, 0x06, 0x04, 0x13, 0x01 }, // X6
+ // US / . , CR SO STX SYN ETX CAN SUB
+ { 0x1f, 0x2f, 0x2e, 0x2c, 0x0d, 0x0e, 0x02, 0x16, 0x03, 0x18, 0x1a } // X7
+ }
+ };
+ return KEY_CODES[mode][x][y];
+}
//-------------------------------------------------
// device_start - device-specific startup
@@ -141,12 +166,6 @@ uint8_t kr2376_st_device::key_codes(int mode, int x, int y)
void kr2376_device::device_start()
{
- /* resolve callbacks */
- m_read_x.resolve_all_safe(0x7ff);
- m_read_shift.resolve_safe(0);
- m_read_control.resolve_safe(0);
- m_write_strobe.resolve_safe();
-
/* set initial values */
m_ring11 = 0;
m_ring8 = 0;
@@ -158,7 +177,7 @@ void kr2376_device::device_start()
change_output_lines();
/* create the timers */
- m_scan_timer = timer_alloc(TIMER_SCAN_TICK);
+ m_scan_timer = timer_alloc(FUNC(kr2376_device::perform_scan), this);
m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
/* register for state saving */
@@ -263,16 +282,11 @@ void kr2376_device::detect_keypress()
}
}
-void kr2376_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(kr2376_device::perform_scan)
{
- switch (id)
- {
- case TIMER_SCAN_TICK:
- change_output_lines();
- clock_scan_counters();
- detect_keypress();
- break;
- }
+ change_output_lines();
+ clock_scan_counters();
+ detect_keypress();
}
/* Keyboard Data */
diff --git a/src/devices/machine/kr2376.h b/src/devices/machine/kr2376.h
index ab5a4c3f82c..2345ade8c5e 100644
--- a/src/devices/machine/kr2376.h
+++ b/src/devices/machine/kr2376.h
@@ -71,9 +71,10 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual uint8_t key_codes(int mode, int x, int y) { return 0x00; }
+ TIMER_CALLBACK_MEMBER(perform_scan);
+
private:
// internal state
int m_pins[41];
@@ -92,11 +93,6 @@ private:
devcb_read_line m_read_shift, m_read_control;
devcb_write_line m_write_strobe;
- enum
- {
- TIMER_SCAN_TICK
- };
-
void change_output_lines();
void clock_scan_counters();
void detect_keypress();
@@ -110,16 +106,15 @@ protected:
virtual uint8_t key_codes(int mode, int x, int y) override;
};
-//class kr2376_12_device : public kr2376_device
-//{
-//public:
-// // construction/destruction
-// kr2376_12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-//protected:
-// virtual uint8_t key_codes(int mode, int x, int y) override;
-//};
+class kr2376_12_device : public kr2376_device
+{
+public:
+ kr2376_12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+protected:
+ virtual uint8_t key_codes(int mode, int x, int y) override;
+};
DECLARE_DEVICE_TYPE(KR2376_ST, kr2376_st_device)
-//DECLARE_DEVICE_TYPE(KR2376_12, kr2376_12_device)
+DECLARE_DEVICE_TYPE(KR2376_12, kr2376_12_device)
#endif // MAME_MACHINE_KR2376_H
diff --git a/src/devices/machine/laserdsc.cpp b/src/devices/machine/laserdsc.cpp
index d04d3c1201a..246369f15ef 100644
--- a/src/devices/machine/laserdsc.cpp
+++ b/src/devices/machine/laserdsc.cpp
@@ -10,12 +10,13 @@
#include "emu.h"
#include "laserdsc.h"
-#include "avhuff.h"
-#include "vbiparse.h"
+
#include "config.h"
#include "render.h"
#include "romload.h"
+
#include "chd.h"
+#include "xmlfile.h"
@@ -23,7 +24,9 @@
// DEBUGGING
//**************************************************************************
-#define LOG_SLIDER 0
+#define LOG_SLIDER (1U << 1)
+#define VERBOSE (0)
+#include "logmacro.h"
@@ -54,48 +57,57 @@ const uint32_t VIRTUAL_LEAD_OUT_TRACKS = LEAD_OUT_MIN_SIZE_IN_UM * 1000 / NOMINA
// CORE IMPLEMENTATION
//**************************************************************************
+ALLOW_SAVE_TYPE(laserdisc_device::player_state);
+ALLOW_SAVE_TYPE(laserdisc_device::slider_position);
+
+parallel_laserdisc_device::parallel_laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : laserdisc_device(mconfig, type, tag, owner, clock)
+{
+}
+
//-------------------------------------------------
// laserdisc_device - constructor
//-------------------------------------------------
laserdisc_device::laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- device_video_interface(mconfig, *this),
- m_getdisc_callback(*this),
- m_audio_callback(*this),
- m_overwidth(0),
- m_overheight(0),
- m_overclip(0, -1, 0, -1),
- m_overupdate_rgb32(*this),
- m_disc(nullptr),
- m_width(0),
- m_height(0),
- m_fps_times_1million(0),
- m_samplerate(0),
- m_readresult(CHDERR_NONE),
- m_chdtracks(0),
- m_work_queue(osd_work_queue_alloc(WORK_QUEUE_FLAG_IO)),
- m_audiosquelch(0),
- m_videosquelch(0),
- m_fieldnum(0),
- m_curtrack(0),
- m_maxtrack(0),
- m_attospertrack(0),
- m_sliderupdate(attotime::zero),
- m_videoindex(0),
- m_stream(nullptr),
- m_audiobufsize(0),
- m_audiobufin(0),
- m_audiobufout(0),
- m_audiocursamples(0),
- m_audiomaxsamples(0),
- m_videoenable(false),
- m_videotex(nullptr),
- m_videopalette(nullptr),
- m_overenable(false),
- m_overindex(0),
- m_overtex(nullptr)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , device_video_interface(mconfig, *this)
+ , m_getdisc_callback(*this)
+ , m_audio_callback(*this)
+ , m_overwidth(0)
+ , m_overheight(0)
+ , m_overclip(0, -1, 0, -1)
+ , m_overupdate_rgb32(*this)
+ , m_disc(nullptr)
+ , m_is_cav_disc(false)
+ , m_width(0)
+ , m_height(0)
+ , m_fps_times_1million(0)
+ , m_samplerate(0)
+ , m_readresult()
+ , m_chdtracks(0)
+ , m_work_queue(osd_work_queue_alloc(WORK_QUEUE_FLAG_IO))
+ , m_audiosquelch(0)
+ , m_videosquelch(0)
+ , m_fieldnum(0)
+ , m_curtrack(0)
+ , m_maxtrack(0)
+ , m_attospertrack(0)
+ , m_sliderupdate(attotime::zero)
+ , m_videoindex(0)
+ , m_stream(nullptr)
+ , m_audiobufsize(0)
+ , m_audiobufin(0)
+ , m_audiobufout(0)
+ , m_audiocursamples(0)
+ , m_audiomaxsamples(0)
+ , m_videoenable(false)
+ , m_videotex(nullptr)
+ , m_videopalette(nullptr)
+ , m_overenable(false)
+ , m_overindex(0)
+ , m_overtex(nullptr)
{
// initialize overlay_config
m_orig_config.m_overposx = m_orig_config.m_overposy = 0.0f;
@@ -187,8 +199,10 @@ uint32_t laserdisc_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
screen.container().empty();
// add the video texture
- if (m_videoenable)
- screen.container().add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0xff,0xff,0xff), m_videotex, PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
+ rgb_t videocolor = 0xffffffff; // Fully visible, white
+ if (!m_videoenable)
+ videocolor = 0xff000000; // Blank the texture's RGB of the texture
+ screen.container().add_quad(0.0f, 0.0f, 1.0f, 1.0f, videocolor, m_videotex, PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1));
// add the overlay
if (m_overenable && overbitmap.valid())
@@ -201,7 +215,7 @@ uint32_t laserdisc_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
}
// swap to the next bitmap
- m_overindex = (m_overindex + 1) % ARRAY_LENGTH(m_overbitmap);
+ m_overindex = (m_overindex + 1) % std::size(m_overbitmap);
}
return 0;
}
@@ -222,8 +236,81 @@ void laserdisc_device::device_start()
init_video();
init_audio();
+ // register our timer
+ m_vbi_fetch_timer = timer_alloc(FUNC(laserdisc_device::fetch_vbi_data), this);
+
// register callbacks
- machine().configuration().config_register("laserdisc", config_load_delegate(&laserdisc_device::config_load, this), config_save_delegate(&laserdisc_device::config_save, this));
+ machine().configuration().config_register(
+ "laserdisc",
+ configuration_manager::load_delegate(&laserdisc_device::config_load, this),
+ configuration_manager::save_delegate(&laserdisc_device::config_save, this));
+
+ // register state
+ save_item(NAME(m_player_state.m_state));
+ save_item(NAME(m_player_state.m_substate));
+ save_item(NAME(m_player_state.m_param));
+ save_item(NAME(m_player_state.m_endtime));
+
+ save_item(NAME(m_saved_state.m_state));
+ save_item(NAME(m_saved_state.m_substate));
+ save_item(NAME(m_saved_state.m_param));
+ save_item(NAME(m_saved_state.m_endtime));
+
+ save_item(NAME(m_overposx));
+ save_item(NAME(m_overposy));
+ save_item(NAME(m_overscalex));
+ save_item(NAME(m_overscaley));
+
+ save_item(NAME(m_orig_config.m_overposx));
+ save_item(NAME(m_orig_config.m_overposy));
+ save_item(NAME(m_orig_config.m_overscalex));
+ save_item(NAME(m_orig_config.m_overscaley));
+
+ save_item(NAME(m_overwidth));
+ save_item(NAME(m_overheight));
+ save_item(NAME(m_overclip.min_x));
+ save_item(NAME(m_overclip.max_x));
+ save_item(NAME(m_overclip.min_y));
+ save_item(NAME(m_overclip.max_y));
+
+ save_item(NAME(m_vbidata));
+ save_item(NAME(m_is_cav_disc));
+ save_item(NAME(m_width));
+ save_item(NAME(m_height));
+ save_item(NAME(m_fps_times_1million));
+ save_item(NAME(m_samplerate));
+ save_item(NAME(m_chdtracks));
+
+ save_item(NAME(m_audiosquelch));
+ save_item(NAME(m_videosquelch));
+ save_item(NAME(m_fieldnum));
+ save_item(NAME(m_curtrack));
+ save_item(NAME(m_maxtrack));
+ save_item(NAME(m_attospertrack));
+ save_item(NAME(m_sliderupdate));
+
+ save_item(STRUCT_MEMBER(m_frame, m_numfields));
+ save_item(STRUCT_MEMBER(m_frame, m_lastfield));
+ save_item(NAME(m_videoindex));
+
+ save_item(NAME(m_audiobuffer[0]));
+ save_item(NAME(m_audiobuffer[1]));
+ save_item(NAME(m_audiobufsize));
+ save_item(NAME(m_audiobufin));
+ save_item(NAME(m_audiobufout));
+ save_item(NAME(m_audiocursamples));
+ save_item(NAME(m_audiomaxsamples));
+
+ save_item(STRUCT_MEMBER(m_metadata, white));
+ save_item(STRUCT_MEMBER(m_metadata, line16));
+ save_item(STRUCT_MEMBER(m_metadata, line17));
+ save_item(STRUCT_MEMBER(m_metadata, line18));
+ save_item(STRUCT_MEMBER(m_metadata, line1718));
+
+ save_item(NAME(m_videoenable));
+
+ save_item(NAME(m_overenable));
+ save_item(NAME(m_overindex));
}
@@ -275,35 +362,30 @@ void laserdisc_device::device_validity_check(validity_checker &valid) const
{
}
+
//-------------------------------------------------
-// device_timer - handle timers set by this
-// device
+// fetch_vbi_data - perform an update and
+// process the track that was read, including
+// VBI data
//-------------------------------------------------
-void laserdisc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(laserdisc_device::fetch_vbi_data)
{
- switch (id)
- {
- case TID_VBI_FETCH:
- {
- // wait for previous read and decode to finish
- process_track_data();
+ // wait for previous read and decode to finish
+ process_track_data();
- // update current track based on slider speed
- update_slider_pos();
+ // update current track based on slider speed
+ update_slider_pos();
- // update the state
- add_and_clamp_track(player_update(m_metadata[m_fieldnum], m_fieldnum, machine().time()));
+ // update the state
+ add_and_clamp_track(player_update(m_metadata[m_fieldnum], m_fieldnum, machine().time()));
- // flush any audio before we read more
- m_stream->update();
+ // flush any audio before we read more
+ m_stream->update();
- // start reading the track data for the next round
- m_fieldnum ^= 1;
- read_track_data();
- break;
- }
- }
+ // start reading the track data for the next round
+ m_fieldnum ^= 1;
+ read_track_data();
}
@@ -376,29 +458,30 @@ void laserdisc_device::sound_stream_update(sound_stream &stream, std::vector<rea
//-------------------------------------------------
// set_slider_speed - dynamically change the
-// slider speed
+// slider speed, supports fractional values
//-------------------------------------------------
-void laserdisc_device::set_slider_speed(int32_t tracks_per_vsync)
+void laserdisc_device::set_slider_speed(const double tracks_per_vsync)
{
// update to the current time
update_slider_pos();
// if 0, set the time to 0
- attotime vsyncperiod = screen().frame_period();
+ double vsyncperiod = screen().frame_period().as_double();
if (tracks_per_vsync == 0)
m_attospertrack = 0;
// positive values store positive times
else if (tracks_per_vsync > 0)
- m_attospertrack = (vsyncperiod / tracks_per_vsync).as_attoseconds();
+ m_attospertrack = DOUBLE_TO_ATTOSECONDS(vsyncperiod / tracks_per_vsync);
// negative values store negative times
else
- m_attospertrack = -(vsyncperiod / -tracks_per_vsync).as_attoseconds();
+ {
+ m_attospertrack = DOUBLE_TO_ATTOSECONDS(-vsyncperiod / -tracks_per_vsync);
+ }
- if (LOG_SLIDER)
- printf("Slider speed = %d\n", tracks_per_vsync);
+ LOGMASKED(LOG_SLIDER, "Slider speed = %f\n", tracks_per_vsync);
}
@@ -414,8 +497,7 @@ void laserdisc_device::advance_slider(int32_t numtracks)
// then update the track position
add_and_clamp_track(numtracks);
- if (LOG_SLIDER)
- printf("Advance by %d\n", numtracks);
+ LOGMASKED(LOG_SLIDER, "Advance by %d\n", numtracks);
}
@@ -658,8 +740,9 @@ void laserdisc_device::init_disc()
// read the metadata
std::string metadata;
- chd_error err = m_disc->read_metadata(AV_METADATA_TAG, 0, metadata);
- if (err != CHDERR_NONE)
+ std::error_condition err;
+ err = m_disc->read_metadata(AV_METADATA_TAG, 0, metadata);
+ if (err)
throw emu_fatalerror("Non-A/V CHD file specified");
// extract the metadata
@@ -679,8 +762,25 @@ void laserdisc_device::init_disc()
// allocate memory for the precomputed per-frame metadata
err = m_disc->read_metadata(AV_LD_METADATA_TAG, 0, m_vbidata);
- if (err != CHDERR_NONE || m_vbidata.size() != totalhunks * VBI_PACKED_BYTES)
+ if (err || (m_vbidata.size() != totalhunks * VBI_PACKED_BYTES))
throw emu_fatalerror("Precomputed VBI metadata missing or incorrect size");
+
+ m_is_cav_disc = false;
+ vbi_metadata vbidata_even = { 0 };
+ vbi_metadata_unpack(&vbidata_even, nullptr, &m_vbidata[m_chdtracks * VBI_PACKED_BYTES]);
+ if ((vbidata_even.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ {
+ m_is_cav_disc = true;
+ }
+ else
+ {
+ vbi_metadata vbidata_odd = { 0 };
+ vbi_metadata_unpack(&vbidata_odd, nullptr, &m_vbidata[(m_chdtracks + 1) * VBI_PACKED_BYTES]);
+ if ((vbidata_odd.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ {
+ m_is_cav_disc = true;
+ }
+ }
}
m_maxtrack = std::max(m_maxtrack, VIRTUAL_LEAD_IN_TRACKS + VIRTUAL_LEAD_OUT_TRACKS + m_chdtracks);
}
@@ -854,8 +954,8 @@ void laserdisc_device::vblank_state_changed(screen_device &screen, bool vblank_s
// call the player's VSYNC callback
player_vsync(m_metadata[m_fieldnum], m_fieldnum, machine().time());
- // set a timer to begin fetching the next frame just before the VBI data would be fetched
- timer_set(screen.time_until_pos(16*2), TID_VBI_FETCH);
+ // set our timer to begin fetching the next frame just before the VBI data would be fetched
+ m_vbi_fetch_timer->adjust(screen.time_until_pos(16*2));
}
}
@@ -870,7 +970,7 @@ laserdisc_device::frame_data &laserdisc_device::current_frame()
// determine the most recent live set of frames
frame_data *frame = &m_frame[m_videoindex];
if (frame->m_numfields < 2)
- frame = &m_frame[(m_videoindex + ARRAY_LENGTH(m_frame) - 1) % ARRAY_LENGTH(m_frame)];
+ frame = &m_frame[(m_videoindex + std::size(m_frame) - 1) % std::size(m_frame)];
return *frame;
}
@@ -899,14 +999,14 @@ void laserdisc_device::read_track_data()
vbidata.line16 = 0;
vbidata.line17 = vbidata.line18 = vbidata.line1718 = VBI_CODE_LEADIN;
}
-//printf("track %5d.%d: %06X %06X %06X\n", m_curtrack, m_fieldnum, vbidata.line16, vbidata.line17, vbidata.line18);
+ LOGMASKED(LOG_SLIDER, "track %5d.%d: %06X %06X %06X\n", m_curtrack, m_fieldnum, vbidata.line16, vbidata.line17, vbidata.line18);
// if we're about to read the first field in a frame, advance
frame_data *frame = &m_frame[m_videoindex];
if ((vbidata.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
{
if (frame->m_numfields >= 2)
- m_videoindex = (m_videoindex + 1) % ARRAY_LENGTH(m_frame);
+ m_videoindex = (m_videoindex + 1) % std::size(m_frame);
frame = &m_frame[m_videoindex];
frame->m_numfields = 0;
}
@@ -956,14 +1056,14 @@ void laserdisc_device::read_track_data()
}
// configure the codec and then read
- m_readresult = CHDERR_FILE_NOT_FOUND;
- if (m_disc != nullptr && !m_videosquelch)
+ m_readresult = std::errc::no_such_file_or_directory;
+ if (m_disc && !m_videosquelch)
{
m_readresult = m_disc->codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &m_avhuff_config);
- if (m_readresult == CHDERR_NONE)
+ if (!m_readresult)
{
m_queued_hunknum = readhunk;
- m_readresult = CHDERR_OPERATION_PENDING;
+ m_readresult = chd_file::error::OPERATION_PENDING;
osd_work_item_queue(m_work_queue, read_async_static, this, WORK_ITEM_FLAG_AUTO_RELEASE);
}
}
@@ -991,12 +1091,12 @@ void *laserdisc_device::read_async_static(void *param, int threadid)
void laserdisc_device::process_track_data()
{
// wait for the async operation to complete
- if (m_readresult == CHDERR_OPERATION_PENDING)
+ if (m_readresult == chd_file::error::OPERATION_PENDING)
osd_work_queue_wait(m_work_queue, osd_ticks_per_second() * 10);
- assert(m_readresult != CHDERR_OPERATION_PENDING);
+ assert(m_readresult != chd_file::error::OPERATION_PENDING);
// remove the video if we had an error
- if (m_readresult != CHDERR_NONE)
+ if (m_readresult)
m_avhuff_video.reset();
// count the field as read if we are successful
@@ -1040,20 +1140,16 @@ void laserdisc_device::process_track_data()
// configuration file
//-------------------------------------------------
-void laserdisc_device::config_load(config_type cfg_type, util::xml::data_node const *parentnode)
+void laserdisc_device::config_load(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode)
{
- // we only care about game files
- if (cfg_type != config_type::GAME)
- return;
-
- // might not have any data
- if (parentnode == nullptr)
+ // we only care system-specific configuration
+ if ((cfg_type != config_type::SYSTEM) || !parentnode)
return;
// iterate over overlay nodes
for (util::xml::data_node const *ldnode = parentnode->get_child("device"); ldnode != nullptr; ldnode = ldnode->get_next_sibling("device"))
{
- const char *devtag = ldnode->get_attribute_string("tag", "");
+ char const *const devtag = ldnode->get_attribute_string("tag", "");
if (strcmp(devtag, tag()) == 0)
{
// handle the overlay node
@@ -1078,13 +1174,13 @@ void laserdisc_device::config_load(config_type cfg_type, util::xml::data_node co
void laserdisc_device::config_save(config_type cfg_type, util::xml::data_node *parentnode)
{
- // we only care about game files
- if (cfg_type != config_type::GAME)
+ // we only save system-specific configuration
+ if (cfg_type != config_type::SYSTEM)
return;
// create a node
util::xml::data_node *const ldnode = parentnode->add_child("device", nullptr);
- if (ldnode != nullptr)
+ if (ldnode)
{
// output the basics
ldnode->set_attribute("tag", tag());
diff --git a/src/devices/machine/laserdsc.h b/src/devices/machine/laserdsc.h
index d55b5980a54..b66029d7ee5 100644
--- a/src/devices/machine/laserdsc.h
+++ b/src/devices/machine/laserdsc.h
@@ -18,8 +18,10 @@
#include "vbiparse.h"
#include "avhuff.h"
-#include <type_traits>
+#include <algorithm>
+#include <system_error>
#include <utility>
+#include <vector>
//**************************************************************************
@@ -148,15 +150,8 @@ public:
}
protected:
- // timer IDs
- enum
- {
- TID_VBI_FETCH,
- TID_FIRST_PLAYER_TIMER
- };
-
// common laserdisc states
- enum player_state
+ enum player_state : uint32_t
{
LDSTATE_NONE, // unspecified state
LDSTATE_EJECTING, // in the process of ejecting
@@ -188,7 +183,7 @@ protected:
};
// slider position
- enum slider_position
+ enum slider_position : uint32_t
{
SLIDER_MINIMUM, // at the minimum value
SLIDER_VIRTUAL_LEADIN, // within the virtual lead-in area
@@ -202,8 +197,8 @@ protected:
struct player_state_info
{
player_state m_state; // current state
- int32_t m_substate; // internal sub-state; starts at 0 on any state change
- int32_t m_param; // parameter for current state
+ int32_t m_substate; // internal sub-state; starts at 0 on any state change
+ int32_t m_param; // parameter for current state
attotime m_endtime; // minimum ending time for current state
};
@@ -216,21 +211,23 @@ protected:
virtual void device_start() override;
virtual void device_stop() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_validity_check(validity_checker &valid) const override;
// device_sound_interface overrides
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+ virtual TIMER_CALLBACK_MEMBER(fetch_vbi_data);
+
// subclass helpers
void set_audio_squelch(bool squelchleft, bool squelchright) { m_stream->update(); m_audiosquelch = (squelchleft ? 1 : 0) | (squelchright ? 2 : 0); }
void set_video_squelch(bool squelch) { m_videosquelch = squelch; }
- void set_slider_speed(int32_t tracks_per_vsync);
+ void set_slider_speed(const double tracks_per_vsync);
void advance_slider(int32_t numtracks);
slider_position get_slider_position();
int32_t generic_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime, player_state_info &curstate);
// general helpers
+ bool is_cav_disc() const { return m_is_cav_disc; }
bool is_start_of_frame(const vbi_metadata &vbi);
int frame_from_metadata(const vbi_metadata &metadata);
int chapter_from_metadata(const vbi_metadata &metadata);
@@ -238,14 +235,16 @@ protected:
player_state_info m_player_state; // active state
player_state_info m_saved_state; // saved state during temporary operations
+ emu_timer *m_vbi_fetch_timer; // fetcher for our VBI data
+
private:
// internal type definitions
struct frame_data
{
bitmap_yuy16 m_bitmap; // cached bitmap
bitmap_yuy16 m_visbitmap; // wrapper around bitmap with only visible lines
- uint8_t m_numfields; // number of fields in this frame
- int32_t m_lastfield; // last absolute field number
+ uint8_t m_numfields; // number of fields in this frame
+ int32_t m_lastfield; // last absolute field number
};
// internal helpers
@@ -260,26 +259,27 @@ private:
void read_track_data();
static void *read_async_static(void *param, int threadid);
void process_track_data();
- void config_load(config_type cfg_type, util::xml::data_node const *parentnode);
+ void config_load(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode);
void config_save(config_type cfg_type, util::xml::data_node *parentnode);
// configuration
get_disc_delegate m_getdisc_callback;
audio_delegate m_audio_callback; // audio streaming callback
laserdisc_overlay_config m_orig_config; // original overlay configuration
- uint32_t m_overwidth; // overlay screen width
- uint32_t m_overheight; // overlay screen height
+ uint32_t m_overwidth; // overlay screen width
+ uint32_t m_overheight; // overlay screen height
rectangle m_overclip; // overlay visarea
screen_update_rgb32_delegate m_overupdate_rgb32; // overlay update delegate
// disc parameters
chd_file * m_disc; // handle to the disc itself
- std::vector<uint8_t> m_vbidata; // pointer to precomputed VBI data
+ std::vector<uint8_t> m_vbidata; // pointer to precomputed VBI data
+ bool m_is_cav_disc; // precomputed check if the mounted disc is CAV
int m_width; // width of video
int m_height; // height of video
uint32_t m_fps_times_1million; // frame rate of video
int m_samplerate; // audio samplerate
- int m_readresult; // result of the most recent read
+ std::error_condition m_readresult; // result of the most recent read
uint32_t m_chdtracks; // number of tracks in the CHD
bitmap_yuy16 m_avhuff_video; // decompresed frame buffer
avhuff_decoder::config m_avhuff_config; // decompression configuration
@@ -304,12 +304,12 @@ private:
// audio data
sound_stream * m_stream;
- std::vector<int16_t> m_audiobuffer[2]; // buffer for audio samples
- uint32_t m_audiobufsize; // size of buffer
- uint32_t m_audiobufin; // input index
- uint32_t m_audiobufout; // output index
- uint32_t m_audiocursamples; // current samples this track
- uint32_t m_audiomaxsamples; // maximum samples per track
+ std::vector<int16_t> m_audiobuffer[2]; // buffer for audio samples
+ uint32_t m_audiobufsize; // size of buffer
+ uint32_t m_audiobufin; // input index
+ uint32_t m_audiobufout; // output index
+ uint32_t m_audiocursamples; // current samples this track
+ uint32_t m_audiomaxsamples; // maximum samples per track
// metadata
vbi_metadata m_metadata[2]; // metadata parsed from the stream, for each field
@@ -335,6 +335,25 @@ typedef device_interface_enumerator<laserdisc_device> laserdisc_device_enumerato
// INLINE FUNCTIONS
//**************************************************************************
+// ======================> parallel_laserdisc_device
+
+class parallel_laserdisc_device : public laserdisc_device
+{
+public:
+
+ virtual void data_w(u8 data) = 0;
+ virtual u8 data_r() = 0;
+ virtual void enter_w(int state) {}
+ virtual int data_available_r() { return CLEAR_LINE; }
+ virtual int status_strobe_r() { return CLEAR_LINE; }
+ virtual int ready_r() { return ASSERT_LINE; }
+
+protected:
+ parallel_laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock = 0);
+
+ virtual void player_overlay(bitmap_yuy16 &bitmap) override { }
+};
+
//-------------------------------------------------
// is_start_of_frame - return true if this is
// the start of a frame
diff --git a/src/devices/machine/latch8.cpp b/src/devices/machine/latch8.cpp
index 4db3d302195..2bb8e1ddbb0 100644
--- a/src/devices/machine/latch8.cpp
+++ b/src/devices/machine/latch8.cpp
@@ -13,7 +13,7 @@
void latch8_device::update(uint8_t new_val, uint8_t mask)
{
- uint8_t old_val = m_value;
+ const uint8_t old_val = m_value;
m_value = (m_value & ~mask) | (new_val & mask);
@@ -21,33 +21,31 @@ void latch8_device::update(uint8_t new_val, uint8_t mask)
{
uint8_t changed = old_val ^ m_value;
for (int i = 0; i < 8; i++)
- if (BIT(changed, i) && !m_write_cb[i].isnull())
+ if (BIT(changed, i))
m_write_cb[i](BIT(m_value, i));
}
}
TIMER_CALLBACK_MEMBER( latch8_device::timerproc )
{
- uint8_t new_val = param & 0xFF;
- uint8_t mask = param >> 8;
+ const uint8_t new_val = param & 0xff;
+ const uint8_t mask = param >> 8;
- update( new_val, mask);
+ update(new_val, mask);
}
/* ----------------------------------------------------------------------- */
uint8_t latch8_device::read(offs_t offset)
{
- uint8_t res;
-
assert(offset == 0);
- res = m_value;
+ uint8_t res = m_value;
if (m_has_read)
{
for (int i = 0; i < 8; i++)
{
- if (!m_read_cb[i].isnull())
+ if (!m_read_cb[i].isunset())
res = (res & ~(1 << i)) | (m_read_cb[i]() << i);
}
}
@@ -60,9 +58,9 @@ void latch8_device::write(offs_t offset, uint8_t data)
assert(offset == 0);
if (m_nosync != 0xff)
- machine().scheduler().synchronize(timer_expired_delegate(FUNC(latch8_device::timerproc),this), (0xFF << 8) | data);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(latch8_device::timerproc),this), (0xff << 8) | data);
else
- update(data, 0xFF);
+ update(data, 0xff);
}
@@ -73,15 +71,15 @@ void latch8_device::reset_w(offs_t offset, uint8_t data)
m_value = 0;
}
-/* write bit x from data into bit determined by offset */
-/* latch = (latch & ~(1<<offset)) | (((data >> x) & 0x01) << offset) */
+// write bit x from data into bit determined by offset
+// latch = (latch & ~(1<<offset)) | (((data >> x) & 0x01) << offset)
-void latch8_device::bitx_w(int bit, offs_t offset, uint8_t data)
+template <int Bit> inline void latch8_device::bitx_w(offs_t offset, uint8_t data)
{
- uint8_t mask = (1<<offset);
- uint8_t masked_data = (((data >> bit) & 0x01) << offset);
+ const uint8_t mask = 1 << offset;
+ const uint8_t masked_data = BIT(data, Bit) << offset;
- assert( offset < 8);
+ assert(offset < 8);
/* No need to synchronize ? */
if (m_nosync & mask)
@@ -90,27 +88,27 @@ void latch8_device::bitx_w(int bit, offs_t offset, uint8_t data)
machine().scheduler().synchronize(timer_expired_delegate(FUNC(latch8_device::timerproc),this), (mask << 8) | masked_data);
}
-void latch8_device::bit0_w(offs_t offset, uint8_t data) { bitx_w(0, offset, data); }
-void latch8_device::bit1_w(offs_t offset, uint8_t data) { bitx_w(1, offset, data); }
-void latch8_device::bit2_w(offs_t offset, uint8_t data) { bitx_w(2, offset, data); }
-void latch8_device::bit3_w(offs_t offset, uint8_t data) { bitx_w(3, offset, data); }
-void latch8_device::bit4_w(offs_t offset, uint8_t data) { bitx_w(4, offset, data); }
-void latch8_device::bit5_w(offs_t offset, uint8_t data) { bitx_w(5, offset, data); }
-void latch8_device::bit6_w(offs_t offset, uint8_t data) { bitx_w(6, offset, data); }
-void latch8_device::bit7_w(offs_t offset, uint8_t data) { bitx_w(7, offset, data); }
+void latch8_device::bit0_w(offs_t offset, uint8_t data) { bitx_w<0>(offset, data); }
+void latch8_device::bit1_w(offs_t offset, uint8_t data) { bitx_w<1>(offset, data); }
+void latch8_device::bit2_w(offs_t offset, uint8_t data) { bitx_w<2>(offset, data); }
+void latch8_device::bit3_w(offs_t offset, uint8_t data) { bitx_w<3>(offset, data); }
+void latch8_device::bit4_w(offs_t offset, uint8_t data) { bitx_w<4>(offset, data); }
+void latch8_device::bit5_w(offs_t offset, uint8_t data) { bitx_w<5>(offset, data); }
+void latch8_device::bit6_w(offs_t offset, uint8_t data) { bitx_w<6>(offset, data); }
+void latch8_device::bit7_w(offs_t offset, uint8_t data) { bitx_w<7>(offset, data); }
DEFINE_DEVICE_TYPE(LATCH8, latch8_device, "latch8", "8-bit latch")
latch8_device::latch8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, LATCH8, tag, owner, clock)
+ , m_write_cb(*this)
+ , m_read_cb(*this, 0)
, m_value(0)
- , m_has_write(0)
- , m_has_read(0)
+ , m_has_write(false)
+ , m_has_read(false)
, m_maskout(0)
, m_xorvalue(0)
, m_nosync(0)
- , m_write_cb(*this)
- , m_read_cb(*this)
{
}
@@ -123,7 +121,7 @@ latch8_device::latch8_device(const machine_config &mconfig, const char *tag, dev
void latch8_device::device_validity_check(validity_checker &valid) const
{
for (int i = 0; i < 8; i++)
- if (!m_read_cb[i].isnull() && !m_write_cb[i].isnull())
+ if (!m_read_cb[i].isunset() && !m_write_cb[i].isunset())
osd_printf_error("Device %s: Bit %d already has a handler.\n", tag(), i);
}
@@ -133,18 +131,18 @@ void latch8_device::device_validity_check(validity_checker &valid) const
void latch8_device::device_start()
{
- /* setup nodemap */
+ // setup nodemap
for (auto &cb : m_write_cb)
{
- if (!cb.isnull()) m_has_write = 1;
- cb.resolve();
+ if (!cb.isunset())
+ m_has_write = true;
}
- /* setup device read handlers */
+ // setup device read handlers
for (auto &cb : m_read_cb)
{
- if (!cb.isnull()) m_has_read = 1;
- cb.resolve();
+ if (!cb.isunset())
+ m_has_read = true;
}
save_item(NAME(m_value));
diff --git a/src/devices/machine/latch8.h b/src/devices/machine/latch8.h
index 750a9c752b5..ece626422ae 100644
--- a/src/devices/machine/latch8.h
+++ b/src/devices/machine/latch8.h
@@ -16,49 +16,60 @@
#ifndef MAME_MACHINE_LATCH8_H
#define MAME_MACHINE_LATCH8_H
-#include "sound/discrete.h"
+#pragma once
+
class latch8_device : public device_t
{
public:
latch8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- /* write & read full byte */
+ // Write bit to discrete node
+ template <unsigned N> auto write_cb() { return m_write_cb[N].bind(); }
+
+ // Upon read, replace bits by reading from another device handler
+ template <unsigned N> auto read_cb() { return m_read_cb[N].bind(); }
+
+ // Bit mask specifying bits to be masked *out*
+ void set_maskout(uint32_t maskout) { m_maskout = maskout; }
+
+ // Bit mask specifying bits to be inverted
+ void set_xorvalue(uint32_t xorvalue) { m_xorvalue = xorvalue; }
+
+ // Bit mask specifying bits not needing cpu synchronization.
+ void set_nosync(uint32_t nosync) { m_nosync = nosync; }
+ // write & read full byte
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- /* reset the latch */
-
+ // reset the latch
void reset_w(offs_t offset, uint8_t data);
- /* read bit x */
- /* return (latch >> x) & 0x01 */
-
- DECLARE_READ_LINE_MEMBER( bit0_r ) { return BIT(m_value, 0); }
- DECLARE_READ_LINE_MEMBER( bit1_r ) { return BIT(m_value, 1); }
- DECLARE_READ_LINE_MEMBER( bit2_r ) { return BIT(m_value, 2); }
- DECLARE_READ_LINE_MEMBER( bit3_r ) { return BIT(m_value, 3); }
- DECLARE_READ_LINE_MEMBER( bit4_r ) { return BIT(m_value, 4); }
- DECLARE_READ_LINE_MEMBER( bit5_r ) { return BIT(m_value, 5); }
- DECLARE_READ_LINE_MEMBER( bit6_r ) { return BIT(m_value, 6); }
- DECLARE_READ_LINE_MEMBER( bit7_r ) { return BIT(m_value, 7); }
-
- /* read inverted bit x */
- /* return (latch >> x) & 0x01 */
-
- DECLARE_READ_LINE_MEMBER( bit0_q_r ) { return BIT(m_value, 0) ^ 1; }
- DECLARE_READ_LINE_MEMBER( bit1_q_r ) { return BIT(m_value, 1) ^ 1; }
- DECLARE_READ_LINE_MEMBER( bit2_q_r ) { return BIT(m_value, 2) ^ 1; }
- DECLARE_READ_LINE_MEMBER( bit3_q_r ) { return BIT(m_value, 3) ^ 1; }
- DECLARE_READ_LINE_MEMBER( bit4_q_r ) { return BIT(m_value, 4) ^ 1; }
- DECLARE_READ_LINE_MEMBER( bit5_q_r ) { return BIT(m_value, 5) ^ 1; }
- DECLARE_READ_LINE_MEMBER( bit6_q_r ) { return BIT(m_value, 6) ^ 1; }
- DECLARE_READ_LINE_MEMBER( bit7_q_r ) { return BIT(m_value, 7) ^ 1; }
-
- /* write bit x from data into bit determined by offset */
- /* latch = (latch & ~(1<<offset)) | (((data >> x) & 0x01) << offset) */
-
+ // read bit x
+ // FIXME: does not honour read callbacks or XOR mask
+ int bit0_r() { return BIT(m_value, 0); }
+ int bit1_r() { return BIT(m_value, 1); }
+ int bit2_r() { return BIT(m_value, 2); }
+ int bit3_r() { return BIT(m_value, 3); }
+ int bit4_r() { return BIT(m_value, 4); }
+ int bit5_r() { return BIT(m_value, 5); }
+ int bit6_r() { return BIT(m_value, 6); }
+ int bit7_r() { return BIT(m_value, 7); }
+
+ // read inverted bit
+ // FIXME: does not honour read callbacks or XOR mask
+ int bit0_q_r() { return BIT(~m_value, 0); }
+ int bit1_q_r() { return BIT(~m_value, 1); }
+ int bit2_q_r() { return BIT(~m_value, 2); }
+ int bit3_q_r() { return BIT(~m_value, 3); }
+ int bit4_q_r() { return BIT(~m_value, 4); }
+ int bit5_q_r() { return BIT(~m_value, 5); }
+ int bit6_q_r() { return BIT(~m_value, 6); }
+ int bit7_q_r() { return BIT(~m_value, 7); }
+
+ // write bit x from data into bit determined by offset
+ // latch = (latch & ~(1<<offset)) | (((data >> x) & 0x01) << offset)
void bit0_w(offs_t offset, uint8_t data);
void bit1_w(offs_t offset, uint8_t data);
void bit2_w(offs_t offset, uint8_t data);
@@ -68,21 +79,6 @@ public:
void bit6_w(offs_t offset, uint8_t data);
void bit7_w(offs_t offset, uint8_t data);
- /* Bit mask specifying bits to be masked *out* */
- void set_maskout(uint32_t maskout) { m_maskout = maskout; }
-
- /* Bit mask specifying bits to be inverted */
- void set_xorvalue(uint32_t xorvalue) { m_xorvalue = xorvalue; }
-
- /* Bit mask specifying bits not needing cpu synchronization. */
- void set_nosync(uint32_t nosync) { m_nosync = nosync; }
-
- /* Write bit to discrete node */
- template <unsigned N> auto write_cb() { return m_write_cb[N].bind(); }
-
- /* Upon read, replace bits by reading from another device handler */
- template <unsigned N> auto read_cb() { return m_read_cb[N].bind(); }
-
protected:
// device-level overrides
virtual void device_start() override;
@@ -91,21 +87,21 @@ protected:
TIMER_CALLBACK_MEMBER( timerproc );
void update(uint8_t new_val, uint8_t mask);
- inline void bitx_w(int bit, offs_t offset, uint8_t data);
+ template <int Bit> void bitx_w(offs_t offset, uint8_t data);
private:
+ devcb_write_line::array<8> m_write_cb;
+ devcb_read_line::array<8> m_read_cb;
+
// internal state
uint8_t m_value;
- uint8_t m_has_write;
- uint8_t m_has_read;
+ bool m_has_write;
+ bool m_has_read;
- /* only for byte reads, does not affect bit reads and node_map */
+ // only for byte reads, does not affect bit reads and node_map
uint32_t m_maskout;
- uint32_t m_xorvalue; /* after mask */
+ uint32_t m_xorvalue; // after mask
uint32_t m_nosync;
-
- devcb_write_line::array<8> m_write_cb;
- devcb_read_line::array<8> m_read_cb;
};
DECLARE_DEVICE_TYPE(LATCH8, latch8_device)
diff --git a/src/devices/machine/ldp1000.cpp b/src/devices/machine/ldp1000.cpp
index 42f8cb796fe..64a2ec48faa 100644
--- a/src/devices/machine/ldp1000.cpp
+++ b/src/devices/machine/ldp1000.cpp
@@ -12,7 +12,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/ldp1000.h"
+#include "ldp1000.h"
#define DUMP_BCD 1
#define FIFO_MAX 0x10
diff --git a/src/devices/machine/ldp1450.cpp b/src/devices/machine/ldp1450.cpp
index 2b4d037cab4..a0cf8e11e9e 100644
--- a/src/devices/machine/ldp1450.cpp
+++ b/src/devices/machine/ldp1450.cpp
@@ -11,7 +11,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/ldp1450.h"
+#include "ldp1450.h"
#define DUMP_BCD 1
#define FIFO_MAX 0x10
diff --git a/src/devices/machine/ldpr8210.cpp b/src/devices/machine/ldpr8210.cpp
index 64392ed0c90..0b9cd4049a7 100644
--- a/src/devices/machine/ldpr8210.cpp
+++ b/src/devices/machine/ldpr8210.cpp
@@ -27,9 +27,12 @@
// DEBUGGING
//**************************************************************************
-#define LOG_VBLANK_VBI 0
-#define LOG_SERIAL 0
-#define LOG_SIMUTREK 0
+#define LOG_VBLANK_VBI (1U << 1)
+#define LOG_SERIAL (1U << 2)
+#define LOG_SIMUTREK (1U << 3)
+#define LOG_UNKNOWNS (1U << 4)
+#define VERBOSE (0)
+#include "logmacro.h"
@@ -226,8 +229,7 @@ void pioneer_pr8210_device::control_w(uint8_t data)
{
m_firstbittime = curtime;
m_accumulator = 0x5555;
- if (LOG_SERIAL)
- logerror("Reset accumulator\n");
+ LOGMASKED(LOG_SERIAL, "Reset accumulator\n");
}
// 0 bit delta is 1.05 msec, 1 bit delta is 2.11 msec
@@ -235,11 +237,7 @@ void pioneer_pr8210_device::control_w(uint8_t data)
m_accumulator = (m_accumulator << 1) | longpulse;
// log the deltas for debugging
- if (LOG_SERIAL)
- {
- int usecdiff = (int)(delta.attoseconds() / ATTOSECONDS_IN_USEC(1));
- logerror("bitdelta = %5d (%d) - accum = %04X\n", usecdiff, longpulse, m_accumulator);
- }
+ LOGMASKED(LOG_SERIAL, "bitdelta = %5d (%d) - accum = %04X\n", delta.as_ticks(1'000'000), longpulse, m_accumulator);
// if we have a complete command, signal it
// a complete command is 0,0,1 followed by 5 bits, followed by 0,0
@@ -260,8 +258,7 @@ void pioneer_pr8210_device::control_w(uint8_t data)
m_lastcommand = m_pia.porta;
// log the command and wait for a keypress
- if (LOG_SERIAL)
- logerror("--- Command = %02X\n", m_pia.porta >> 3);
+ LOGMASKED(LOG_SERIAL, "--- Command = %02X\n", m_pia.porta >> 3);
// reset the first bit time so that the accumulator clears on the next write
m_firstbittime = curtime - SERIAL_MAX_WORD_TIME;
@@ -276,6 +273,10 @@ void pioneer_pr8210_device::control_w(uint8_t data)
void pioneer_pr8210_device::device_start()
{
+ // alocate timers
+ m_process_vbi_timer = timer_alloc(FUNC(pioneer_pr8210_device::process_vbi_data), this);
+ m_vsync_off_timer = timer_alloc(FUNC(pioneer_pr8210_device::vsync_off), this);
+
// resolve outputs
m_audio1.resolve();
m_audio2.resolve();
@@ -312,71 +313,63 @@ void pioneer_pr8210_device::device_reset()
//-------------------------------------------------
-// device_timer - handle timers set by this
-// device
+// process_vbi_data - process VBI data which was
+// fetched by the parent device
//-------------------------------------------------
-void pioneer_pr8210_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pioneer_pr8210_device::process_vbi_data)
{
- switch (id)
- {
- // update the VBI data in the PIA as soon as it is ready;
- // this must happen early in the frame because the player
- // logic relies on fetching it here
- case TID_VBI_DATA_FETCH:
+ // update the VBI data in the PIA as soon as it is ready;
+ // this must happen early in the frame because the player
+ // logic relies on fetching it here
- // logging
- if (LOG_VBLANK_VBI)
- {
- uint32_t line1718 = get_field_code(LASERDISC_CODE_LINE1718, false);
- if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
- logerror("%3d:VBI(%05d)\n", screen().vpos(), VBI_CAV_PICTURE(line1718));
- else
- logerror("%3d:VBI()\n", screen().vpos());
- }
+ // logging
+ uint32_t line1718 = get_field_code(LASERDISC_CODE_LINE1718, false);
+ if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ LOGMASKED(LOG_VBLANK_VBI, "%3d:VBI(%05d)\n", screen().vpos(), VBI_CAV_PICTURE(line1718));
+ else
+ LOGMASKED(LOG_VBLANK_VBI, "%3d:VBI()\n", screen().vpos());
- // update PIA registers based on vbi code
- m_pia.vbi1 = 0xff;
- m_pia.vbi2 = 0xff;
- if (focus_on() && laser_on())
- {
- uint32_t line16 = get_field_code(LASERDISC_CODE_LINE16, false);
- uint32_t line1718 = get_field_code(LASERDISC_CODE_LINE1718, false);
- if (line1718 == VBI_CODE_LEADIN)
- m_pia.vbi1 &= ~0x01;
- if (line1718 == VBI_CODE_LEADOUT)
- m_pia.vbi1 &= ~0x02;
- if (line16 == VBI_CODE_STOP)
- m_pia.vbi1 &= ~0x04;
- // unsure what this bit means: m_pia.vbi1 &= ~0x08;
- if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
- {
- m_pia.vbi1 &= ~0x10;
- m_pia.frame[2] = 0xf0 | ((line1718 >> 16) & 0x07);
- m_pia.frame[3] = 0xf0 | ((line1718 >> 12) & 0x0f);
- m_pia.frame[4] = 0xf0 | ((line1718 >> 8) & 0x0f);
- m_pia.frame[5] = 0xf0 | ((line1718 >> 4) & 0x0f);
- m_pia.frame[6] = 0xf0 | ((line1718 >> 0) & 0x0f);
- }
- if ((line1718 & VBI_MASK_CHAPTER) == VBI_CODE_CHAPTER)
- {
- m_pia.vbi2 &= ~0x01;
- m_pia.frame[0] = 0xf0 | ((line1718 >> 16) & 0x07);
- m_pia.frame[1] = 0xf0 | ((line1718 >> 12) & 0x0f);
- }
- }
- break;
+ // update PIA registers based on vbi code
+ m_pia.vbi1 = 0xff;
+ m_pia.vbi2 = 0xff;
+ if (focus_on() && laser_on())
+ {
+ uint32_t line16 = get_field_code(LASERDISC_CODE_LINE16, false);
+ uint32_t line1718 = get_field_code(LASERDISC_CODE_LINE1718, false);
+ if (line1718 == VBI_CODE_LEADIN)
+ m_pia.vbi1 &= ~0x01;
+ if (line1718 == VBI_CODE_LEADOUT)
+ m_pia.vbi1 &= ~0x02;
+ if (line16 == VBI_CODE_STOP)
+ m_pia.vbi1 &= ~0x04;
+ // unsure what this bit means: m_pia.vbi1 &= ~0x08;
+ if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ {
+ m_pia.vbi1 &= ~0x10;
+ m_pia.frame[2] = 0xf0 | ((line1718 >> 16) & 0x07);
+ m_pia.frame[3] = 0xf0 | ((line1718 >> 12) & 0x0f);
+ m_pia.frame[4] = 0xf0 | ((line1718 >> 8) & 0x0f);
+ m_pia.frame[5] = 0xf0 | ((line1718 >> 4) & 0x0f);
+ m_pia.frame[6] = 0xf0 | ((line1718 >> 0) & 0x0f);
+ }
+ if ((line1718 & VBI_MASK_CHAPTER) == VBI_CODE_CHAPTER)
+ {
+ m_pia.vbi2 &= ~0x01;
+ m_pia.frame[0] = 0xf0 | ((line1718 >> 16) & 0x07);
+ m_pia.frame[1] = 0xf0 | ((line1718 >> 12) & 0x0f);
+ }
+ }
+}
- // clear the VSYNC flag
- case TID_VSYNC_OFF:
- m_vsync = false;
- break;
- // pass everything else onto the parent
- default:
- laserdisc_device::device_timer(timer, id, param, ptr);
- break;
- }
+//-------------------------------------------------
+// vsync_off - clear the VSYNC flag
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_pr8210_device::vsync_off)
+{
+ m_vsync = false;
}
@@ -415,20 +408,17 @@ void pioneer_pr8210_device::device_add_mconfig(machine_config &config)
void pioneer_pr8210_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
{
// logging
- if (LOG_VBLANK_VBI)
- {
- if ((vbi.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
- logerror("%3d:VSYNC(%d,%05d)\n", screen().vpos(), fieldnum, VBI_CAV_PICTURE(vbi.line1718));
- else
- logerror("%3d:VSYNC(%d)\n", screen().vpos(), fieldnum);
- }
+ if ((vbi.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
+ LOGMASKED(LOG_VBLANK_VBI, "%3d:VSYNC(%d,%05d)\n", screen().vpos(), fieldnum, VBI_CAV_PICTURE(vbi.line1718));
+ else
+ LOGMASKED(LOG_VBLANK_VBI, "%3d:VSYNC(%d)\n", screen().vpos(), fieldnum);
// signal VSYNC and set a timer to turn it off
m_vsync = true;
- timer_set(screen().scan_period() * 4, TID_VSYNC_OFF);
+ m_vsync_off_timer->adjust(screen().scan_period() * 4);
// also set a timer to fetch the VBI data when it is ready
- timer_set(screen().time_until_pos(19*2), TID_VBI_DATA_FETCH);
+ m_process_vbi_timer->adjust(screen().time_until_pos(19*2));
}
@@ -440,8 +430,7 @@ void pioneer_pr8210_device::player_vsync(const vbi_metadata &vbi, int fieldnum,
int32_t pioneer_pr8210_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
{
// logging
- if (LOG_VBLANK_VBI)
- logerror("%3d:Update(%d)\n", screen().vpos(), fieldnum);
+ LOGMASKED(LOG_VBLANK_VBI, "%3d:Update(%d)\n", screen().vpos(), fieldnum);
// if the spindle is on, we advance by 1 track after completing field #1
return spdl_on() ? fieldnum : 0;
@@ -507,20 +496,18 @@ uint8_t pioneer_pr8210_device::i8049_pia_r(offs_t offset)
// (C0) VBI decoding state 1
case 0xc0:
- if (LOG_VBLANK_VBI)
- logerror("%3d:PIA(C0)\n", screen().vpos());
+ LOGMASKED(LOG_VBLANK_VBI, "%3d:PIA(C0)\n", screen().vpos());
result = m_pia.vbi1;
break;
// (E0) VBI decoding state 2
case 0xe0:
- if (LOG_VBLANK_VBI)
- logerror("%3d:PIA(E0)\n", screen().vpos());
+ LOGMASKED(LOG_VBLANK_VBI, "%3d:PIA(E0)\n", screen().vpos());
result = m_pia.vbi2;
break;
default:
- logerror("%s Unknown PR-8210 PIA read from offset %02X\n", machine().describe_context(), offset);
+ LOGMASKED(LOG_UNKNOWNS, "%s Unknown PR-8210 PIA read from offset %02X\n", machine().describe_context(), offset);
break;
}
return result;
@@ -592,7 +579,7 @@ void pioneer_pr8210_device::i8049_pia_w(offs_t offset, uint8_t data)
// no other writes known
default:
- logerror("%s Unknown PR-8210 PIA write to offset %02X = %02X\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_UNKNOWNS, "%s Unknown PR-8210 PIA write to offset %02X = %02X\n", machine().describe_context(), offset, data);
break;
}
}
@@ -673,12 +660,13 @@ void pioneer_pr8210_device::i8049_port1_w(uint8_t data)
// special override for the Simutrek, which takes over control of this is some situations
if (!override_control())
{
- if (LOG_SIMUTREK)
- logerror("%3d:JUMP TRG\n", screen().vpos());
+ LOGMASKED(LOG_SIMUTREK, "%3d:JUMP TRG\n", screen().vpos());
advance_slider(direction);
}
- else if (LOG_SIMUTREK)
- logerror("%3d:Skipped JUMP TRG\n", screen().vpos());
+ else
+ {
+ LOGMASKED(LOG_SIMUTREK, "%3d:Skipped JUMP TRG\n", screen().vpos());
+ }
}
// bit 1 low enables scanning
@@ -905,9 +893,8 @@ simutrek_special_device::simutrek_special_device(const machine_config &mconfig,
void simutrek_special_device::data_w(uint8_t data)
{
- synchronize(TID_LATCH_DATA, data);
- if (LOG_SIMUTREK)
- logerror("%03d:**** Simutrek Command = %02X\n", screen().vpos(), data);
+ m_latch_data_timer->adjust(attotime::zero, data);
+ LOGMASKED(LOG_SIMUTREK, "%03d:**** Simutrek Command = %02X\n", screen().vpos(), data);
}
@@ -918,8 +905,8 @@ void simutrek_special_device::data_w(uint8_t data)
void simutrek_special_device::set_external_audio_squelch(int state)
{
- if (LOG_SIMUTREK && m_audio_squelch != (state == 0))
- logerror("--> audio squelch = %d\n", state == 0);
+ if (m_audio_squelch != (state == 0))
+ LOGMASKED(LOG_SIMUTREK, "--> audio squelch = %d\n", state == 0);
m_audio_squelch = (state == 0);
update_audio_squelch();
}
@@ -940,17 +927,15 @@ void simutrek_special_device::player_vsync(const vbi_metadata &vbi, int fieldnum
}
// call the parent
- if (LOG_SIMUTREK)
- logerror("%3d:VSYNC(%d)\n", screen().vpos(), fieldnum);
+ LOGMASKED(LOG_SIMUTREK, "%3d:VSYNC(%d)\n", screen().vpos(), fieldnum);
pioneer_pr8210_device::player_vsync(vbi, fieldnum, curtime);
// process data
if (m_data_ready)
{
- if (LOG_SIMUTREK)
- logerror("%3d:VSYNC IRQ\n", screen().vpos());
+ LOGMASKED(LOG_SIMUTREK, "%3d:VSYNC IRQ\n", screen().vpos());
m_i8748_cpu->set_input_line(MCS48_INPUT_IRQ, ASSERT_LINE);
- timer_set(screen().scan_period(), TID_IRQ_OFF);
+ m_irq_off_timer->adjust(screen().scan_period());
}
}
@@ -961,6 +946,10 @@ void simutrek_special_device::player_vsync(const vbi_metadata &vbi, int fieldnum
void simutrek_special_device::device_start()
{
+ // alocate timers
+ m_irq_off_timer = timer_alloc(FUNC(simutrek_special_device::irq_off), this);
+ m_latch_data_timer = timer_alloc(FUNC(simutrek_special_device::latch_data), this);
+
// pass through to the parent
pioneer_pr8210_device::device_start();
}
@@ -982,30 +971,23 @@ void simutrek_special_device::device_reset()
//-------------------------------------------------
-// device_timer - handle timers set by this
-// device
+// irq_off - clear the 8748 IRQ
//-------------------------------------------------
-void simutrek_special_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(simutrek_special_device::irq_off)
{
- switch (id)
- {
- // clear the 8748 IRQ
- case TID_IRQ_OFF:
- m_i8748_cpu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE);
- break;
+ m_i8748_cpu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE);
+}
- // latch data
- case TID_LATCH_DATA:
- m_data = param;
- m_data_ready = true;
- break;
- // pass everything else onto the parent
- default:
- pioneer_pr8210_device::device_timer(timer, id, param, ptr);
- break;
- }
+//-------------------------------------------------
+// latch_data - perform delayed latching of data
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(simutrek_special_device::latch_data)
+{
+ m_data = param;
+ m_data_ready = true;
}
@@ -1068,19 +1050,18 @@ void simutrek_special_device::i8748_port2_w(uint8_t data)
if (!(data & 0x10) && (prev & 0x10))
{
int direction = (data & 0x08) ? 1 : -1;
- if (LOG_SIMUTREK)
- logerror("%3d:JUMP TRG %s\n", screen().vpos(), machine().describe_context());
+ LOGMASKED(LOG_SIMUTREK, "%3d:JUMP TRG %s\n", screen().vpos(), machine().describe_context());
advance_slider(direction);
}
// bit $04 controls who owns the JUMP TRG command
- if (LOG_SIMUTREK && ((data ^ prev) & 0x04))
- logerror("%3d:Simutrek ownership line = %d %s\n", screen().vpos(), (data >> 2) & 1, machine().describe_context());
+ if ((data ^ prev) & 0x04)
+ LOGMASKED(LOG_SIMUTREK, "%3d:Simutrek ownership line = %d %s\n", screen().vpos(), (data >> 2) & 1, machine().describe_context());
m_controlnext = (~data >> 2) & 1;
// bits $03 control something (status?)
- if (LOG_SIMUTREK && ((data ^ prev) & 0x03))
- logerror("Simutrek Status = %d\n", data & 0x03);
+ if ((data ^ prev) & 0x03)
+ LOGMASKED(LOG_SIMUTREK, "Simutrek Status = %d\n", data & 0x03);
}
diff --git a/src/devices/machine/ldpr8210.h b/src/devices/machine/ldpr8210.h
index 217159e0cd1..4bc4615c03c 100644
--- a/src/devices/machine/ldpr8210.h
+++ b/src/devices/machine/ldpr8210.h
@@ -44,20 +44,11 @@ public:
void control_w(uint8_t data);
protected:
- // timer IDs
- enum
- {
- TID_VSYNC_OFF = TID_FIRST_PLAYER_TIMER,
- TID_VBI_DATA_FETCH,
- TID_FIRST_SUBCLASS_TIMER
- };
-
pioneer_pr8210_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
@@ -67,6 +58,8 @@ protected:
virtual void player_overlay(bitmap_yuy16 &bitmap) override;
// internal helpers
+ TIMER_CALLBACK_MEMBER(process_vbi_data);
+ TIMER_CALLBACK_MEMBER(vsync_off);
bool focus_on() const { return !(m_i8049_port1 & 0x08); }
bool spdl_on() const { return !(m_i8049_port1 & 0x10); }
bool laser_on() const { return !(m_i8049_port2 & 0x01); }
@@ -115,6 +108,10 @@ protected:
output_finder<> m_pause;
output_finder<> m_standby;
+ // timers
+ emu_timer *m_process_vbi_timer;
+ emu_timer *m_vsync_off_timer;
+
// internal state
uint8_t m_control; // control line state
uint8_t m_lastcommand; // last command seen
@@ -153,20 +150,12 @@ public:
void set_external_audio_squelch(int state);
protected:
- // timer IDs
- enum
- {
- TID_IRQ_OFF = TID_FIRST_SUBCLASS_TIMER,
- TID_LATCH_DATA
- };
-
// subclass overrides
virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
@@ -175,6 +164,9 @@ protected:
virtual void update_audio_squelch() override { set_audio_squelch(m_audio_squelch, m_audio_squelch); }
private:
+ TIMER_CALLBACK_MEMBER(irq_off);
+ TIMER_CALLBACK_MEMBER(latch_data);
+
// internal read/write handlers
uint8_t i8748_data_r();
uint8_t i8748_port2_r();
@@ -185,10 +177,12 @@ private:
// internal state
required_device<i8748_device> m_i8748_cpu;
- uint8_t m_audio_squelch; // audio squelch value
+ emu_timer *m_irq_off_timer;
+ emu_timer *m_latch_data_timer;
+ uint8_t m_audio_squelch; // audio squelch value
uint8_t m_data; // parallel data for simutrek
- bool m_data_ready; // ready flag for simutrek data
- uint8_t m_i8748_port2; // 8748 port 2 state
+ bool m_data_ready; // ready flag for simutrek data
+ uint8_t m_i8748_port2; // 8748 port 2 state
uint8_t m_controlnext; // latch to control next pair of fields
uint8_t m_controlthis; // latched value for our control over the current pair of fields
};
diff --git a/src/devices/machine/ldstub.cpp b/src/devices/machine/ldstub.cpp
index c0c9a7ac05a..3fabac8cc45 100644
--- a/src/devices/machine/ldstub.cpp
+++ b/src/devices/machine/ldstub.cpp
@@ -22,12 +22,12 @@ DEFINE_DEVICE_TYPE(PHILIPS_22VP932, philips_22vp932_device, "22vp932", "Philips
pioneer_pr7820_device::pioneer_pr7820_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : laserdisc_device(mconfig, PIONEER_PR7820, tag, owner, clock)
+ : parallel_laserdisc_device(mconfig, PIONEER_PR7820, tag, owner, clock)
{
}
philips_22vp932_device::philips_22vp932_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : laserdisc_device(mconfig, PHILIPS_22VP932, tag, owner, clock)
+ : parallel_laserdisc_device(mconfig, PHILIPS_22VP932, tag, owner, clock)
{
}
diff --git a/src/devices/machine/ldstub.h b/src/devices/machine/ldstub.h
index 9fbc756b240..77eba3d67da 100644
--- a/src/devices/machine/ldstub.h
+++ b/src/devices/machine/ldstub.h
@@ -31,18 +31,15 @@ DECLARE_DEVICE_TYPE(PHILIPS_22VP932, philips_22vp932_device)
// ======================> pioneer_pr7820_device
-class pioneer_pr7820_device : public laserdisc_device
+class pioneer_pr7820_device : public parallel_laserdisc_device
{
public:
// construction/destruction
pioneer_pr7820_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// input/output
- uint8_t data_available_r() { return CLEAR_LINE; }
- uint8_t ready_r() { return ASSERT_LINE; }
- uint8_t data_r() { return 0; }
- void data_w(uint8_t data) { }
- void enter_w(uint8_t data) { }
+ virtual void data_w(uint8_t data) override { }
+ virtual uint8_t data_r() override { return 0; }
protected:
// subclass overrides
@@ -54,16 +51,15 @@ protected:
// ======================> philips_22vp932_device
-class philips_22vp932_device : public laserdisc_device
+class philips_22vp932_device : public parallel_laserdisc_device
{
public:
// construction/destruction
philips_22vp932_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// input/output
- uint8_t data_r() { return 0; }
- void data_w(uint8_t data) { }
- void enter_w(uint8_t data) { }
+ virtual void data_w(uint8_t data) override { }
+ virtual uint8_t data_r() override { return 0; }
protected:
// subclass overrides
diff --git a/src/devices/machine/ldv1000.cpp b/src/devices/machine/ldv1000.cpp
index 8d94650e9db..4ee45b098d0 100644
--- a/src/devices/machine/ldv1000.cpp
+++ b/src/devices/machine/ldv1000.cpp
@@ -18,9 +18,10 @@
#include "emu.h"
#include "ldv1000.h"
+
+#include "cpu/z80/z80.h"
#include "machine/i8255.h"
#include "machine/z80ctc.h"
-#include "cpu/z80/z80.h"
#include "machine/z80daisy.h"
@@ -29,11 +30,13 @@
// DEBUGGING
//**************************************************************************
-#define LOG_PORT_IO 0
-#define LOG_STATUS_CHANGES 0
-#define LOG_FRAMES_SEEN 0
-#define LOG_COMMANDS 0
+#define LOG_PORT_IO (1U << 1)
+#define LOG_STATUS_CHANGES (1U << 2)
+#define LOG_FRAMES_SEEN (1U << 3)
+#define LOG_COMMANDS (1U << 4)
+#define VERBOSE (0)
+#include "logmacro.h"
//**************************************************************************
@@ -102,7 +105,7 @@ ROM_END
//-------------------------------------------------
pioneer_ldv1000_device::pioneer_ldv1000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : laserdisc_device(mconfig, PIONEER_LDV1000, tag, owner, clock),
+ : parallel_laserdisc_device(mconfig, PIONEER_LDV1000, tag, owner, clock),
m_z80_cpu(*this, "ldv1000"),
m_z80_ctc(*this, "ldvctc"),
m_multitimer(nullptr),
@@ -131,17 +134,7 @@ pioneer_ldv1000_device::pioneer_ldv1000_device(const machine_config &mconfig, co
void pioneer_ldv1000_device::data_w(uint8_t data)
{
m_command = data;
- if (LOG_COMMANDS)
- logerror("-> COMMAND = %02X (%s)\n", data, (m_portc1 & 0x10) ? "valid" : "invalid");
-}
-
-
-//-------------------------------------------------
-// enter_w - set the state of the ENTER strobe
-//-------------------------------------------------
-
-void pioneer_ldv1000_device::enter_w(uint8_t data)
-{
+ LOGMASKED(LOG_COMMANDS, "-> COMMAND = %02X (%s)\n", data, (m_portc1 & 0x10) ? "valid" : "invalid");
}
@@ -155,9 +148,9 @@ void pioneer_ldv1000_device::device_start()
laserdisc_device::device_start();
// allocate timers
- m_multitimer = timer_alloc(TID_MULTIJUMP);
-
- m_command_strobe_cb.resolve_safe();
+ m_multitimer = timer_alloc(FUNC(pioneer_ldv1000_device::multijump_tick), this);
+ m_vsync_off_timer = timer_alloc(FUNC(pioneer_ldv1000_device::vsync_off), this);
+ m_process_vbi_timer = timer_alloc(FUNC(pioneer_ldv1000_device::process_vbi_data), this);
}
@@ -187,73 +180,72 @@ void pioneer_ldv1000_device::device_reset()
//-------------------------------------------------
-// device_timer - handle timers set by this
-// device
+// vsync_off - clear the VSYNC flag
//-------------------------------------------------
-void pioneer_ldv1000_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000_device::vsync_off)
{
- switch (id)
- {
- case TID_MULTIJUMP:
- {
- // bit 5 of port B on PPI 1 selects the direction of slider movement
- int direction = (m_portb1 & 0x20) ? 1 : -1;
- advance_slider(direction);
-
- // update down counter and reschedule
- if (--m_counter != 0)
- timer.adjust(MULTIJUMP_TRACK_TIME);
- break;
- }
+ m_vsync = false;
+}
+
- case TID_VSYNC_OFF:
- m_vsync = false;
- break;
+//-------------------------------------------------
+// multijump_tick - move the slider across
+// multiple tracks
+//-------------------------------------------------
- case TID_VBI_DATA_FETCH:
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000_device::multijump_tick)
+{
+ // bit 5 of port B on PPI 1 selects the direction of slider movement
+ int direction = (m_portb1 & 0x20) ? 1 : -1;
+ advance_slider(direction);
+
+ // update down counter and reschedule
+ if (--m_counter != 0)
+ m_multitimer->adjust(MULTIJUMP_TRACK_TIME);
+}
+
+
+//-------------------------------------------------
+// process_vbi_data - process VBI data which was
+// fetched by the parent device
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000_device::process_vbi_data)
+{
+ // appears to return data in reverse order
+ uint32_t lines[3];
+ lines[0] = get_field_code(LASERDISC_CODE_LINE1718, false);
+ lines[1] = get_field_code(LASERDISC_CODE_LINE17, false);
+ lines[2] = get_field_code(LASERDISC_CODE_LINE16, false);
+
+ // fill in the details
+ memset(m_vbi, 0, sizeof(m_vbi));
+ if (focus_on() && laser_on())
+ {
+ // loop over lines
+ for (int line = 0; line < 3; line++)
{
- // appears to return data in reverse order
- uint32_t lines[3];
- lines[0] = get_field_code(LASERDISC_CODE_LINE1718, false);
- lines[1] = get_field_code(LASERDISC_CODE_LINE17, false);
- lines[2] = get_field_code(LASERDISC_CODE_LINE16, false);
-
- // fill in the details
- memset(m_vbi, 0, sizeof(m_vbi));
- if (focus_on() && laser_on())
+ uint8_t *dest = &m_vbi[line * 7];
+ uint32_t data = lines[line];
+
+ // the logic only processes leadin/leadout/frame number codes
+ if (data == VBI_CODE_LEADIN || data == VBI_CODE_LEADOUT || (data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
{
- // loop over lines
- for (int line = 0; line < 3; line++)
- {
- uint8_t *dest = &m_vbi[line * 7];
- uint32_t data = lines[line];
-
- // the logic only processes leadin/leadout/frame number codes
- if (data == VBI_CODE_LEADIN || data == VBI_CODE_LEADOUT || (data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE)
- {
- *dest++ = 0x09 | (((data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) ? 0x02 : 0x00);
- *dest++ = 0x08;
- *dest++ = (data >> 16) & 0x0f;
- *dest++ = (data >> 12) & 0x0f;
- *dest++ = (data >> 8) & 0x0f;
- *dest++ = (data >> 4) & 0x0f;
- *dest++ = (data >> 0) & 0x0f;
- }
- }
+ *dest++ = 0x09 | (((data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) ? 0x02 : 0x00);
+ *dest++ = 0x08;
+ *dest++ = (data >> 16) & 0x0f;
+ *dest++ = (data >> 12) & 0x0f;
+ *dest++ = (data >> 8) & 0x0f;
+ *dest++ = (data >> 4) & 0x0f;
+ *dest++ = (data >> 0) & 0x0f;
}
-
- // signal that data is ready and reset the readback index
- m_vbiready = true;
- m_vbiindex = 0;
- break;
}
-
- // pass everything else onto the parent
- default:
- laserdisc_device::device_timer(timer, id, param, ptr);
- break;
}
+
+ // signal that data is ready and reset the readback index
+ m_vbiready = true;
+ m_vbiindex = 0;
}
@@ -309,13 +301,13 @@ void pioneer_ldv1000_device::player_vsync(const vbi_metadata &vbi, int fieldnum,
// signal VSYNC and set a timer to turn it off
m_vsync = true;
- timer_set(screen().scan_period() * 4, TID_VSYNC_OFF);
+ m_vsync_off_timer->adjust(screen().scan_period() * 4);
// also set a timer to fetch the VBI data when it is ready
- timer_set(screen().time_until_pos(19*2), TID_VBI_DATA_FETCH);
+ m_process_vbi_timer->adjust(screen().time_until_pos(19*2));
// boost interleave for the first 1ms to improve communications
- machine().scheduler().boost_interleave(attotime::zero, attotime::from_msec(1));
+ machine().scheduler().perfect_quantum(attotime::from_msec(1));
}
@@ -326,11 +318,9 @@ void pioneer_ldv1000_device::player_vsync(const vbi_metadata &vbi, int fieldnum,
int32_t pioneer_ldv1000_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
{
- if (LOG_FRAMES_SEEN)
- {
- int frame = frame_from_metadata(vbi);
- if (frame != FRAME_NOT_PRESENT) logerror("== %d\n", frame);
- }
+ int frame = frame_from_metadata(vbi);
+ if (frame != FRAME_NOT_PRESENT)
+ LOGMASKED(LOG_FRAMES_SEEN, "== %d\n", frame);
return fieldnum;
}
@@ -392,7 +382,7 @@ uint8_t pioneer_ldv1000_device::z80_decoder_display_port_r(offs_t offset)
if (m_portselect == 4)
{
m_vbiready = false;
- result = m_vbi[m_vbiindex++ % ARRAY_LENGTH(m_vbi)];
+ result = m_vbi[m_vbiindex++ % std::size(m_vbi)];
}
}
return result;
@@ -419,8 +409,8 @@ uint8_t pioneer_ldv1000_device::z80_controller_r()
void pioneer_ldv1000_device::z80_controller_w(uint8_t data)
{
- if (LOG_STATUS_CHANGES && data != m_status)
- logerror("%s:CONTROLLER.W=%02X\n", machine().describe_context(), data);
+ if (data != m_status)
+ LOGMASKED(LOG_STATUS_CHANGES, "%s:CONTROLLER.W=%02X\n", machine().describe_context(), data);
m_status = data;
}
@@ -433,8 +423,7 @@ void pioneer_ldv1000_device::z80_controller_w(uint8_t data)
void pioneer_ldv1000_device::ppi0_porta_w(uint8_t data)
{
m_counter_start = data;
- if (LOG_PORT_IO)
- logerror("%s:PORTA.0=%02X\n", machine().describe_context(), data);
+ LOGMASKED(LOG_PORT_IO, "%s:PORTA.0=%02X\n", machine().describe_context(), data);
}
@@ -489,9 +478,9 @@ void pioneer_ldv1000_device::ppi0_portc_w(uint8_t data)
// set the new value
uint8_t prev = m_portc0;
m_portc0 = data;
- if (LOG_PORT_IO && ((data ^ prev) & 0x0f) != 0)
+ if ((data ^ prev) & 0x0f)
{
- logerror("%s:PORTC.0=%02X%s%s%s\n", machine().describe_context(), data,
+ LOGMASKED(LOG_PORT_IO, "%s:PORTC.0=%02X%s%s%s\n", machine().describe_context(), data,
(data & 0x01) ? " PRELOAD" : "",
!(data & 0x02) ? " /MULTIJUMP" : "",
(data & 0x04) ? " SCANMODE" : "");
@@ -578,9 +567,9 @@ void pioneer_ldv1000_device::ppi1_portb_w(uint8_t data)
// set the new value
uint8_t prev = m_portb1;
m_portb1 = data;
- if (LOG_PORT_IO && ((data ^ prev) & 0xff) != 0)
+ if ((data ^ prev) & 0xff)
{
- logerror("%s:PORTB.1=%02X: %s%s%s%s%s%s\n", machine().describe_context(), data,
+ LOGMASKED(LOG_PORT_IO, "%s:PORTB.1=%02X: %s%s%s%s%s%s\n", machine().describe_context(), data,
!(data & 0x01) ? " FOCSON" : "",
!(data & 0x02) ? " SPDLRUN" : "",
!(data & 0x04) ? " JUMPTRIG" : "",
@@ -631,9 +620,9 @@ void pioneer_ldv1000_device::ppi1_portc_w(uint8_t data)
// set the new value
uint8_t prev = m_portc1;
m_portc1 = data;
- if (LOG_PORT_IO && ((data ^ prev) & 0xcf) != 0)
+ if ((data ^ prev) & 0xcf)
{
- logerror("%s:PORTC.1=%02X%s%s%s%s%s%s%s%s\n", machine().describe_context(), data,
+ LOGMASKED(LOG_PORT_IO, "%s:PORTC.1=%02X%s%s%s%s%s%s%s%s\n", machine().describe_context(), data,
(data & 0x01) ? " AUD1" : "",
(data & 0x02) ? " AUD2" : "",
(data & 0x04) ? " AUDEN" : "",
diff --git a/src/devices/machine/ldv1000.h b/src/devices/machine/ldv1000.h
index 2d19b81c4e3..7c4fb58425a 100644
--- a/src/devices/machine/ldv1000.h
+++ b/src/devices/machine/ldv1000.h
@@ -35,7 +35,7 @@ DECLARE_DEVICE_TYPE(PIONEER_LDV1000, pioneer_ldv1000_device)
// ======================> pioneer_ldv1000_device
// base ldv1000 class
-class pioneer_ldv1000_device : public laserdisc_device
+class pioneer_ldv1000_device : public parallel_laserdisc_device
{
public:
// construction/destruction
@@ -44,25 +44,16 @@ public:
auto command_strobe_callback() { return m_command_strobe_cb.bind(); }
// input and output
- void data_w(uint8_t data);
- void enter_w(uint8_t data);
- uint8_t status_r() const { return m_status; }
- uint8_t status_strobe_r() const { return (m_portc1 & 0x20) ? ASSERT_LINE : CLEAR_LINE; }
- uint8_t command_strobe_r() const { return (m_portc1 & 0x10) ? ASSERT_LINE : CLEAR_LINE; }
+ virtual void data_w(uint8_t data) override;
+ virtual void enter_w(int state) override { }
+ virtual uint8_t data_r() override { return m_status; }
+ virtual int status_strobe_r() override { return BIT(m_portc1, 5); }
+ virtual int ready_r() override { return BIT(m_portc1, 4); }
protected:
- // timer IDs
- enum
- {
- TID_MULTIJUMP = TID_FIRST_PLAYER_TIMER,
- TID_VSYNC_OFF,
- TID_VBI_DATA_FETCH
- };
-
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
@@ -71,6 +62,10 @@ protected:
virtual int32_t player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
virtual void player_overlay(bitmap_yuy16 &bitmap) override { }
+ TIMER_CALLBACK_MEMBER(vsync_off);
+ TIMER_CALLBACK_MEMBER(multijump_tick);
+ TIMER_CALLBACK_MEMBER(process_vbi_data);
+
private:
// internal helpers
bool focus_on() const { return !(m_portb1 & 0x01); }
@@ -97,19 +92,21 @@ private:
void ldv1000_portmap(address_map &map);
// internal state
- required_device<z80_device> m_z80_cpu; /* CPU index of the Z80 */
- required_device<z80ctc_device> m_z80_ctc; /* CTC device */
- emu_timer * m_multitimer; /* multi-jump timer device */
+ required_device<z80_device> m_z80_cpu; /* CPU index of the Z80 */
+ required_device<z80ctc_device> m_z80_ctc; /* CTC device */
+ emu_timer * m_multitimer; /* multi-jump timer device */
+ emu_timer * m_vsync_off_timer; /* vsync-shutoff timer device */
+ emu_timer * m_process_vbi_timer; /* VBI processing timer device */
devcb_write_line m_command_strobe_cb;
/* communication status */
- uint8_t m_command; /* command byte to the player */
+ uint8_t m_command; /* command byte to the player */
uint8_t m_status; /* status byte from the player */
- bool m_vsync; /* VSYNC state */
+ bool m_vsync; /* VSYNC state */
/* I/O port states */
uint8_t m_counter_start; /* starting value for counter */
- uint8_t m_counter; /* current counter value */
+ uint8_t m_counter; /* current counter value */
uint8_t m_portc0; /* port C on PPI 0 */
uint8_t m_portb1; /* port B on PPI 1 */
uint8_t m_portc1; /* port C on PPI 1 */
@@ -118,9 +115,9 @@ private:
uint8_t m_portselect; /* selection of which port to access */
uint8_t m_display[2][20]; /* display lines */
uint8_t m_dispindex; /* index within the display line */
- uint8_t m_vbi[7*3]; /* VBI data */
- bool m_vbiready; /* VBI ready flag */
- uint8_t m_vbiindex; /* index within the VBI data */
+ uint8_t m_vbi[7*3]; /* VBI data */
+ bool m_vbiready; /* VBI ready flag */
+ uint8_t m_vbiindex; /* index within the VBI data */
};
diff --git a/src/devices/machine/ldv1000hle.cpp b/src/devices/machine/ldv1000hle.cpp
new file mode 100644
index 00000000000..8d67db64186
--- /dev/null
+++ b/src/devices/machine/ldv1000hle.cpp
@@ -0,0 +1,1046 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*************************************************************************
+
+ ldv1000hle.cpp
+
+ Pioneer LDV-1000 laserdisc player simulation.
+
+**************************************************************************
+
+ To do:
+
+ * On-screen display support
+ * Commands that Dragon's Lair doesn't use
+
+*************************************************************************/
+
+
+#include "emu.h"
+#include "ldv1000hle.h"
+
+
+#define LOG_COMMAND_BYTES (1U << 1)
+#define LOG_COMMANDS (1U << 2)
+#define LOG_REPLIES (1U << 3)
+#define LOG_SEARCHES (1U << 4)
+#define LOG_STOPS (1U << 5)
+#define LOG_SQUELCHES (1U << 6)
+#define LOG_FRAMES (1U << 7)
+#define LOG_ALL (LOG_COMMAND_BYTES | LOG_COMMANDS | LOG_REPLIES | LOG_SEARCHES | LOG_STOPS | LOG_SQUELCHES | LOG_FRAMES)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(PIONEER_LDV1000HLE, pioneer_ldv1000hle_device, "ldv1000hle", "Pioneer LDV-1000 HLE")
+
+
+//-------------------------------------------------
+// pioneer_ldv1000hle_device - constructor
+//-------------------------------------------------
+
+pioneer_ldv1000hle_device::pioneer_ldv1000hle_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : parallel_laserdisc_device(mconfig, PIONEER_LDV1000HLE, tag, owner, clock)
+ , m_vbi_fetch(nullptr)
+ , m_stop_timer(nullptr)
+ , m_park_strobe_timer(nullptr)
+ , m_assert_status_strobe_timer(nullptr)
+ , m_deassert_status_strobe_timer(nullptr)
+ , m_assert_command_strobe_timer(nullptr)
+ , m_deassert_command_strobe_timer(nullptr)
+ , m_cmd_length(0)
+ , m_status(STATUS_PARK | STATUS_READY)
+ , m_pre_stop_status(0)
+ , m_mode(MODE_PARK)
+ , m_curr_frame(0)
+ , m_search_frame(~0U)
+ , m_stop_frame(~0U)
+ , m_cmd_number_length(0)
+ , m_curr_register(0)
+ , m_scan_speed(60)
+ , m_scan_speed_accum(0)
+ , m_play_speed(0.0)
+ , m_status_strobe(true)
+ , m_command_strobe(true)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device initialization
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::device_start()
+{
+ // pass through to the parent
+ parallel_laserdisc_device::device_start();
+
+ // allocate timers
+ m_vbi_fetch = timer_alloc(FUNC(pioneer_ldv1000hle_device::process_vbi_data), this);
+ m_stop_timer = timer_alloc(FUNC(pioneer_ldv1000hle_device::resume_from_stop), this);
+ m_park_strobe_timer = timer_alloc(FUNC(pioneer_ldv1000hle_device::park_strobe_tick), this);
+ m_assert_status_strobe_timer = timer_alloc(FUNC(pioneer_ldv1000hle_device::assert_status_strobe), this);
+ m_deassert_status_strobe_timer = timer_alloc(FUNC(pioneer_ldv1000hle_device::deassert_status_strobe), this);
+ m_assert_command_strobe_timer = timer_alloc(FUNC(pioneer_ldv1000hle_device::assert_command_strobe), this);
+ m_deassert_command_strobe_timer = timer_alloc(FUNC(pioneer_ldv1000hle_device::deassert_command_strobe), this);
+
+ // register state saving
+ save_item(NAME(m_cmd_buffer));
+ save_item(NAME(m_cmd_length));
+ save_item(NAME(m_status));
+ save_item(NAME(m_pre_stop_status));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_curr_frame));
+ save_item(NAME(m_search_frame));
+ save_item(NAME(m_stop_frame));
+ save_item(NAME(m_cmd_number));
+ save_item(NAME(m_cmd_number_length));
+ save_item(NAME(m_user_ram));
+ save_item(NAME(m_curr_register));
+ save_item(NAME(m_scan_speed));
+ save_item(NAME(m_scan_speed_accum));
+ save_item(NAME(m_play_speed));
+ save_item(NAME(m_audio_enable));
+ save_item(NAME(m_status_strobe));
+ save_item(NAME(m_command_strobe));
+}
+
+
+//-------------------------------------------------
+// device_reset - device reset
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::device_reset()
+{
+ // pass through to the parent
+ parallel_laserdisc_device::device_reset();
+
+ // reset our state
+ m_vbi_fetch->adjust(attotime::never);
+
+ std::fill_n(m_cmd_buffer, std::size(m_cmd_buffer), 0);
+ m_cmd_length = 0;
+ m_status = STATUS_PARK | STATUS_READY;
+ m_pre_stop_status = 0;
+ m_mode = MODE_PARK;
+ m_curr_frame = 0;
+ m_search_frame = ~0U;
+ m_stop_frame = ~0U;
+ m_cmd_number_length = 0;
+ m_curr_register = 0;
+ m_scan_speed = 0;
+ m_scan_speed_accum = 0;
+ m_audio_enable[0] = true;
+ m_audio_enable[1] = true;
+ m_status_strobe = true;
+ m_command_strobe = true;
+
+ set_video_squelch(false);
+
+ m_park_strobe_timer->adjust(attotime::from_msec(21), 0, attotime::from_msec(21));
+}
+
+
+//-------------------------------------------------
+// data_w - handle a new data byte
+// received over the parallel link
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::data_w(u8 data)
+{
+ LOGMASKED(LOG_COMMAND_BYTES, "data_w: Command byte added: %02x\n", data);
+ if (m_cmd_length < std::size(m_cmd_buffer))
+ {
+ m_cmd_buffer[m_cmd_length] = data;
+ m_cmd_length++;
+ }
+
+ if (is_command_byte(data))
+ {
+ LOGMASKED(LOG_COMMAND_BYTES, "data_w: %02x is a command byte, processing command buffer\n", data);
+ process_command_buffer();
+ }
+ else
+ {
+ LOGMASKED(LOG_COMMAND_BYTES, "data_w: %02x is not a command byte, leaving in the queue for now\n", data);
+ }
+}
+
+
+//-------------------------------------------------
+// data_r - returns the current status byte or
+// reply data when necessary
+//-------------------------------------------------
+
+u8 pioneer_ldv1000hle_device::data_r()
+{
+ u8 data = m_status;
+ LOGMASKED(LOG_REPLIES, "Sending reply %02x\n", data);
+ return data;
+}
+
+
+//-------------------------------------------------
+// enter_w - used to request service by a host
+// application, not currently implemented
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::enter_w(int state)
+{
+}
+
+
+//-------------------------------------------------
+// player_vsync - VSYNC callback, called at the
+// start of the blanking period
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
+{
+ // set a timer to fetch the VBI data when it is ready
+ if (m_mode != MODE_PARK)
+ {
+ m_vbi_fetch->adjust(screen().time_until_pos(19*2), fieldnum);
+ }
+}
+
+
+//-------------------------------------------------
+// player_update - update callback, called on
+// the first visible line of the frame
+//-------------------------------------------------
+
+s32 pioneer_ldv1000hle_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
+{
+ if (m_mode != MODE_PARK)
+ {
+ m_assert_status_strobe_timer->adjust(attotime::from_usec(500));
+ }
+
+ if (!fieldnum)
+ return 0;
+
+ if (m_mode == MODE_SCAN_FORWARD || m_mode == MODE_SCAN_REVERSE)
+ {
+ m_scan_speed_accum += m_scan_speed;
+ int elapsed_tracks = m_scan_speed_accum / 60;
+ m_scan_speed_accum -= elapsed_tracks * 60;
+ if (m_mode == MODE_SCAN_REVERSE)
+ elapsed_tracks *= -1;
+
+ if (m_stop_frame != ~0U)
+ {
+ const int next_frame = (int)m_curr_frame + elapsed_tracks;
+ if (next_frame >= m_stop_frame)
+ {
+ // If we've landed on (or exceeded) our desired frame and are in a SKIP FORWARD command, resume from the desired frame.
+ elapsed_tracks = (int)m_stop_frame - (int)m_curr_frame;
+ m_stop_frame = ~0U;
+ set_playing(STATUS_FORWARD, m_play_speed);
+ }
+ }
+ return elapsed_tracks;
+ }
+
+ if (m_mode == MODE_PLAY || m_mode == MODE_SEARCH)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// process_vbi_data - process VBI data and
+// act on search/play seeking
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000hle_device::process_vbi_data)
+{
+ if (param == 0)
+ {
+ update_video_enable();
+ update_audio_enable();
+ }
+
+ uint32_t line = get_field_code(LASERDISC_CODE_LINE1718, false);
+ if ((line & 0xf00000) == 0xf00000 || line == VBI_CODE_LEADIN || line == VBI_CODE_LEADOUT)
+ {
+ uint32_t old_frame = m_curr_frame;
+ if (line == VBI_CODE_LEADIN)
+ m_curr_frame = 0;
+ else if (line == VBI_CODE_LEADOUT)
+ m_curr_frame = 54000;
+ else
+ m_curr_frame = bcd_to_literal(line & 0x7ffff);
+
+ LOGMASKED(LOG_FRAMES, "Current frame is %d (VBI 16: %06x, VBI 17: %06x, VBI 18: %06x, VBI 1718: %06x\n", m_curr_frame,
+ get_field_code(LASERDISC_CODE_LINE16, false),
+ get_field_code(LASERDISC_CODE_LINE17, false),
+ get_field_code(LASERDISC_CODE_LINE18, false),
+ line);
+
+ if (m_mode != MODE_STOP)
+ {
+ if (m_stop_frame != ~0U && m_search_frame == ~0U)
+ {
+ s32 old_delta = (s32)m_stop_frame - (s32)old_frame;
+ s32 curr_delta = (s32)m_stop_frame - (s32)m_curr_frame;
+ LOGMASKED(LOG_STOPS, "%s: Stop frame is currently %d, old frame is %d, current frame is %d, old delta %d, curr delta %d\n", machine().describe_context(), m_stop_frame, old_frame, m_curr_frame, old_delta, curr_delta);
+ if (curr_delta == 0 || (old_delta < 0) != (curr_delta < 0))
+ {
+ m_stop_frame = ~0U;
+ LOGMASKED(LOG_STOPS, "%s: Stop frame: Zero delta, entering stop mode\n", machine().describe_context());
+ set_stopped((m_status & STATUS_READY) | STATUS_STOP);
+ }
+ }
+
+ if (m_search_frame != ~0U)
+ {
+ s32 delta = (s32)m_search_frame - (s32)m_curr_frame;
+ LOGMASKED(LOG_SEARCHES, "%s: Searching from current frame %d with delta %d\n", machine().describe_context(), m_curr_frame, delta);
+ if (delta == 0)
+ {
+ // We've found our frame, enter play, pause or still mode.
+ m_search_frame = ~0U;
+ LOGMASKED(LOG_SEARCHES, "%s: Search Mark: Zero delta, entering still mode\n", machine().describe_context());
+ set_stopped(STATUS_SEARCH_FINISH);
+ }
+ else if (delta <= 2 && delta > 0)
+ {
+ LOGMASKED(LOG_SEARCHES, "%s: Positive near delta, letting disc run to current\n", machine().describe_context());
+ // We're approaching our frame, let it run up.
+ }
+ else
+ {
+ if (delta < 0)
+ {
+ advance_slider(std::min(-2, delta / 2));
+ }
+ else
+ {
+ advance_slider(std::max(1, delta / 2));
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// resume_from_stop - resume from a previous
+// STOP command
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000hle_device::resume_from_stop)
+{
+ set_playing(m_pre_stop_status, m_play_speed);
+}
+
+
+//-------------------------------------------------
+// park_strobe_tick - used to trigger periodic
+// status strobes when the player is parked
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000hle_device::park_strobe_tick)
+{
+ m_status_strobe = false;
+ m_deassert_status_strobe_timer->adjust(attotime::from_usec(26));
+ m_assert_command_strobe_timer->adjust(attotime::from_usec(54));
+}
+
+
+//-------------------------------------------------
+// assert_status_strobe - assert the status
+// strobe signal to a host application at the
+// appropriate time, and prepare for command
+// strobe
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000hle_device::assert_status_strobe)
+{
+ m_status_strobe = false;
+ m_deassert_status_strobe_timer->adjust(attotime::from_usec(26));
+ m_assert_command_strobe_timer->adjust(attotime::from_usec(54));
+}
+
+
+//-------------------------------------------------
+// deassert_status_strobe
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000hle_device::deassert_status_strobe)
+{
+ m_status_strobe = true;
+}
+
+
+//-------------------------------------------------
+// assert_command_strobe
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000hle_device::assert_command_strobe)
+{
+ m_command_strobe = false;
+ m_deassert_command_strobe_timer->adjust(attotime::from_usec(25));
+}
+
+
+//-------------------------------------------------
+// deassert_command_strobe
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv1000hle_device::deassert_command_strobe)
+{
+ m_command_strobe = true;
+}
+
+
+//-------------------------------------------------
+// process_command_buffer - process a command
+// line sent from the host
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::process_command_buffer()
+{
+ size_t cmd_index = 0;
+ while (cmd_index < m_cmd_length)
+ {
+ process_command(cmd_index);
+ cmd_index++;
+ }
+
+ m_cmd_length = 0;
+}
+
+
+//-------------------------------------------------
+// is_command_byte - returns whether or not a
+// given byte is a recognized command
+//-------------------------------------------------
+
+bool pioneer_ldv1000hle_device::is_command_byte(const u8 data)
+{
+ switch (data)
+ {
+ case CMD_CLEAR:
+ case CMD_0:
+ case CMD_1:
+ case CMD_2:
+ case CMD_3:
+ case CMD_4:
+ case CMD_5:
+ case CMD_6:
+ case CMD_7:
+ case CMD_8:
+ case CMD_9:
+ case CMD_STORE:
+ case CMD_RECALL:
+ case CMD_DISPLAY:
+ case CMD_AUDIO1:
+ case CMD_AUDIO2:
+ case CMD_PLAY:
+ case CMD_STOP:
+ case CMD_AUTOSTOP:
+ case CMD_SEARCH:
+ case CMD_SCAN_FWD:
+ case CMD_SCAN_REV:
+ case CMD_STEP_FWD:
+ case CMD_STEP_REV:
+ case CMD_REJECT:
+ case CMD_NO_ENTRY:
+ case CMD_LOAD:
+ case CMD_DISPLAY_DISABLE:
+ case CMD_DISPLAY_ENABLE:
+ case CMD_GET_FRAME_NUM:
+ case CMD_GET_2ND_DISPLAY:
+ case CMD_GET_1ST_DISPLAY:
+ case CMD_TRANSFER_MEMORY:
+ case CMD_FWD_X0:
+ case CMD_FWD_X1_4:
+ case CMD_FWD_X1_2:
+ case CMD_FWD_X1:
+ case CMD_FWD_X2:
+ case CMD_FWD_X3:
+ case CMD_FWD_X4:
+ case CMD_FWD_X5:
+ case CMD_SKIP_FWD_10:
+ case CMD_SKIP_FWD_20:
+ case CMD_SKIP_FWD_30:
+ case CMD_SKIP_FWD_40:
+ case CMD_SKIP_FWD_50:
+ case CMD_SKIP_FWD_60:
+ case CMD_SKIP_FWD_70:
+ case CMD_SKIP_FWD_80:
+ case CMD_SKIP_FWD_90:
+ case CMD_SKIP_FWD_100:
+ return true;
+ }
+ return false;
+}
+
+
+//-------------------------------------------------
+// is_command_number - returns whether or not a
+// given byte is a number-command
+//-------------------------------------------------
+
+bool pioneer_ldv1000hle_device::is_command_number(const u8 data)
+{
+ switch (data)
+ {
+ case CMD_0:
+ case CMD_1:
+ case CMD_2:
+ case CMD_3:
+ case CMD_4:
+ case CMD_5:
+ case CMD_6:
+ case CMD_7:
+ case CMD_8:
+ case CMD_9:
+ return true;
+ }
+ return false;
+}
+
+
+//-------------------------------------------------
+// process_command - processes a single command
+// from the command buffer
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::process_command(size_t cmd_index)
+{
+ const u8 command = m_cmd_buffer[cmd_index];
+ LOGMASKED(LOG_COMMAND_BYTES, "process_command: Command byte %02x with status %02x\n", command, m_status);
+ if (BIT(m_status, 7))
+ {
+ m_status &= ~STATUS_READY;
+
+ switch (command)
+ {
+ case CMD_CLEAR:
+ LOGMASKED(LOG_COMMANDS, "process_command: Clear\n");
+ break;
+
+ case CMD_0:
+ case CMD_1:
+ case CMD_2:
+ case CMD_3:
+ case CMD_4:
+ case CMD_5:
+ case CMD_6:
+ case CMD_7:
+ case CMD_8:
+ case CMD_9:
+ m_cmd_number[m_cmd_number_length] = cmd_to_number(command);
+ LOGMASKED(LOG_COMMANDS, "process_command: %d (number length now %d)\n", m_cmd_number[m_cmd_number_length], m_cmd_number_length);
+ m_cmd_number_length++;
+ break;
+
+ case CMD_STORE:
+ if (m_cmd_number_length == 0)
+ {
+ LOGMASKED(LOG_COMMANDS, "process_command: Store (no value specified, storing current frame in current register)\n");
+ m_user_ram[m_curr_register] = literal_to_bcd(m_curr_frame);
+ }
+ else
+ {
+ m_user_ram[m_curr_register] = cmd_number_to_bcd();
+ LOGMASKED(LOG_COMMANDS, "process_command: Store %05d\n", m_user_ram[m_curr_register]);
+ }
+ break;
+
+ case CMD_RECALL:
+ LOGMASKED(LOG_COMMANDS, "process_command: Recall (not yet implemented)\n");
+ break;
+
+ case CMD_DISPLAY:
+ LOGMASKED(LOG_COMMANDS, "process_command: Display %d (not yet implemented)\n", cmd_number_to_bcd());
+ break;
+
+ case CMD_AUDIO1:
+ if (m_cmd_number_length == 0)
+ {
+ m_audio_enable[0] = !m_audio_enable[0];
+ LOGMASKED(LOG_COMMANDS, "process_command: Audio1, toggling audio enable, channels now %d/%d\n", m_audio_enable[0], m_audio_enable[1]);
+ }
+ else
+ {
+ const u32 cmd_number = cmd_number_to_bcd();
+ m_audio_enable[0] = BIT(cmd_number, 0);
+ LOGMASKED(LOG_COMMANDS, "process_command: Audio1, setting audio enable, channels now %d/%d\n", m_audio_enable[0], m_audio_enable[1]);
+ }
+ break;
+
+ case CMD_AUDIO2:
+ if (m_cmd_number_length == 0)
+ {
+ m_audio_enable[1] = !m_audio_enable[1];
+ LOGMASKED(LOG_COMMANDS, "process_command: Audio2, toggling audio enable, channels now %d/%d\n", m_audio_enable[0], m_audio_enable[1]);
+ }
+ else
+ {
+ const u32 cmd_number = cmd_number_to_bcd();
+ m_audio_enable[1] = BIT(cmd_number, 0);
+ LOGMASKED(LOG_COMMANDS, "process_command: Audio2, setting audio enable, channels now %d/%d\n", m_audio_enable[0], m_audio_enable[1]);
+ }
+ break;
+
+ case CMD_PLAY:
+ LOGMASKED(LOG_COMMANDS, "process_command: Play\n");
+ cmd_play();
+ break;
+
+ case CMD_STOP:
+ cmd_stop();
+ break;
+
+ case CMD_AUTOSTOP:
+ {
+ const u32 value = bcd_to_literal(cmd_number_to_bcd());
+ LOGMASKED(LOG_COMMANDS, "process_command: Autostop (at frame %d)\n", m_stop_frame);
+ if (value < m_curr_frame)
+ {
+ // Autostop with a frame number less than the current one will cause a search.
+ LOGMASKED(LOG_COMMANDS, "process_command: Requested autostop frame is less than current frame (%d), performing a search instead.\n", m_curr_frame);
+ cmd_search(value);
+ break;
+ }
+ m_status = STATUS_AUTOSTOP;
+ break;
+ }
+
+ case CMD_SEARCH:
+ {
+ const u32 value = bcd_to_literal(cmd_number_to_bcd());
+ LOGMASKED(LOG_COMMANDS, "process_command: Search (to frame %d)\n", value);
+ cmd_search(value);
+ break;
+ }
+
+ case CMD_SCAN_FWD:
+ case CMD_SCAN_REV:
+ LOGMASKED(LOG_COMMANDS, "process_command: Scan %s\n", command == CMD_SCAN_FWD ? "Forward" : "Reverse");
+ set_mode(command == CMD_SCAN_FWD ? MODE_SCAN_FORWARD : MODE_SCAN_REVERSE);
+ m_status = STATUS_SCAN;
+ m_scan_speed = 4000; // "The two SCAN commands move the player's optical head at the rate of approximately 2000 frames per second in the direction specified"
+ m_scan_speed_accum = 0;
+ m_stop_frame = ~0U;
+ m_search_frame = ~0U;
+ break;
+
+ case CMD_STEP_FWD:
+ LOGMASKED(LOG_COMMANDS, "process_command: Step Forward\n");
+ cmd_step(1);
+ break;
+
+ case CMD_STEP_REV:
+ LOGMASKED(LOG_COMMANDS, "process_command: Step Reverse\n");
+ cmd_step(-1);
+ break;
+
+ case CMD_REJECT:
+ LOGMASKED(LOG_COMMANDS, "process_command: Reject\n");
+ set_mode(MODE_PARK);
+ m_status = STATUS_PARK;
+ m_stop_frame = ~0U;
+ m_search_frame = ~0U;
+ break;
+
+ case CMD_NO_ENTRY:
+ LOGMASKED(LOG_COMMANDS, "process_command: No Entry\n");
+ m_status |= STATUS_READY;
+ break;
+
+ case CMD_LOAD:
+ LOGMASKED(LOG_COMMANDS, "process_command: Load (not yet implemented)\n");
+ break;
+
+ case CMD_DISPLAY_DISABLE:
+ LOGMASKED(LOG_COMMANDS, "process_command: Display Disable (not yet implemented)\n");
+ break;
+
+ case CMD_DISPLAY_ENABLE:
+ LOGMASKED(LOG_COMMANDS, "process_command: Display Enable (not yet implemented)\n");
+ break;
+
+ case CMD_GET_FRAME_NUM:
+ LOGMASKED(LOG_COMMANDS, "process_command: Get Frame Number (not yet implemented)\n");
+ break;
+
+ case CMD_GET_2ND_DISPLAY:
+ LOGMASKED(LOG_COMMANDS, "process_command: Get 2nd Display (not yet implemented)\n");
+ break;
+
+ case CMD_GET_1ST_DISPLAY:
+ LOGMASKED(LOG_COMMANDS, "process_command: Get 1st Display (not yet implemented)\n");
+ break;
+
+ case CMD_TRANSFER_MEMORY:
+ LOGMASKED(LOG_COMMANDS, "process_command: Transfer Memory (not yet implemented)\n");
+ break;
+
+ case CMD_FWD_X0:
+ cmd_play_forward(0.0);
+ break;
+
+ case CMD_FWD_X1_4:
+ cmd_play_forward(0.25);
+ break;
+
+ case CMD_FWD_X1_2:
+ cmd_play_forward(0.5);
+ break;
+
+ case CMD_FWD_X1:
+ cmd_play_forward(1.0);
+ break;
+
+ case CMD_FWD_X2:
+ cmd_play_forward(2.0);
+ break;
+
+ case CMD_FWD_X3:
+ cmd_play_forward(3.0);
+ break;
+
+ case CMD_FWD_X4:
+ cmd_play_forward(4.0);
+ break;
+
+ case CMD_FWD_X5:
+ cmd_play_forward(5.0);
+ break;
+
+ case CMD_SKIP_FWD_10:
+ cmd_skip_forward(10);
+ break;
+
+ case CMD_SKIP_FWD_20:
+ cmd_skip_forward(20);
+ break;
+
+ case CMD_SKIP_FWD_30:
+ cmd_skip_forward(30);
+ break;
+
+ case CMD_SKIP_FWD_40:
+ cmd_skip_forward(40);
+ break;
+
+ case CMD_SKIP_FWD_50:
+ cmd_skip_forward(50);
+ break;
+
+ case CMD_SKIP_FWD_60:
+ cmd_skip_forward(60);
+ break;
+
+ case CMD_SKIP_FWD_70:
+ cmd_skip_forward(70);
+ break;
+
+ case CMD_SKIP_FWD_80:
+ cmd_skip_forward(80);
+ break;
+
+ case CMD_SKIP_FWD_90:
+ cmd_skip_forward(90);
+ break;
+
+ case CMD_SKIP_FWD_100:
+ cmd_skip_forward(100);
+ break;
+ }
+
+ if (!is_command_number(command))
+ {
+ m_cmd_number_length = 0;
+ }
+
+ LOGMASKED(LOG_COMMAND_BYTES, "process_command: Status is now %02x\n", m_status);
+ }
+ else if (command == CMD_NO_ENTRY)
+ {
+ m_status |= STATUS_READY;
+ LOGMASKED(LOG_COMMAND_BYTES, "process_command: Received no-entry command while busy, setting ready, status is now %02x\n", m_status);
+ }
+ else
+ {
+ m_status &= ~STATUS_READY;
+ LOGMASKED(LOG_COMMAND_BYTES, "process_command: Received command %02x while busy, clearing ready, status is now %02x\n", command, m_status);
+ }
+}
+
+
+//-------------------------------------------------
+// bcd_to_literal - converts a BCD value used in
+// commands a direct numeric value
+//-------------------------------------------------
+
+u32 pioneer_ldv1000hle_device::bcd_to_literal(u32 bcd)
+{
+ u32 value = 0;
+ u32 shift = 28;
+ u32 multiplier = 10000000;
+ for (u32 i = 0; i < 8; i++)
+ {
+ u32 digit = (bcd >> shift) & 0xf;
+ bcd &= ~(0xf << shift);
+
+ value += digit * multiplier;
+
+ multiplier /= 10;
+ shift -= 4;
+ }
+ return value;
+}
+
+
+//-------------------------------------------------
+// literal_to_bcd - converts a literal value
+// into a BCD representation for commands
+//-------------------------------------------------
+
+u32 pioneer_ldv1000hle_device::literal_to_bcd(u32 value)
+{
+ LOGMASKED(LOG_COMMANDS, "literal_to_bcd: Converting %08x to BCD\n", value);
+ u32 bcd_value = 0;
+ u32 shift = 28;
+ u32 multiplier = 10000000;
+ for (u32 i = 0; i < 8; i++)
+ {
+ u32 digit = value / multiplier;
+ bcd_value |= digit << shift;
+
+ value -= digit * multiplier;
+ multiplier /= 10;
+ shift -= 4;
+ }
+ LOGMASKED(LOG_COMMANDS, "literal_to_bcd: Result: %08x\n", bcd_value);
+ return bcd_value;
+}
+
+
+//-------------------------------------------------
+// literal_to_bcd - converts a literal value
+// into a BCD representation for commands
+//-------------------------------------------------
+
+u32 pioneer_ldv1000hle_device::cmd_number_to_bcd()
+{
+ if (m_cmd_number_length == 0)
+ {
+ LOGMASKED(LOG_COMMANDS, "cmd_number_to_bcd: No command number length, returning 0\n");
+ return 0;
+ }
+ u32 bcd_value = 0;
+ size_t shift = 0;
+ for (int i = (int)m_cmd_number_length - 1; i >= 0; i--)
+ {
+ bcd_value |= m_cmd_number[i] << shift;
+ shift += 4;
+ }
+ LOGMASKED(LOG_COMMANDS, "cmd_number_to_bcd: %05x\n", bcd_value);
+ return bcd_value;
+}
+
+
+//-------------------------------------------------
+// set_mode - set the current high-level player
+// mode, updating any enables as necessary
+//-------------------------------------------------
+
+u8 pioneer_ldv1000hle_device::cmd_to_number(const u8 cmd)
+{
+ switch (cmd)
+ {
+ case CMD_0: return 0;
+ case CMD_1: return 1;
+ case CMD_2: return 2;
+ case CMD_3: return 3;
+ case CMD_4: return 4;
+ case CMD_5: return 5;
+ case CMD_6: return 6;
+ case CMD_7: return 7;
+ case CMD_8: return 8;
+ case CMD_9: return 9;
+ }
+ return 0;
+}
+
+
+//-------------------------------------------------
+// set_mode - set the current high-level player
+// mode, updating any enables as necessary
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::set_mode(const u8 mode)
+{
+ if (m_mode == mode)
+ {
+ return;
+ }
+
+ m_mode = mode;
+ if (mode != MODE_PARK)
+ {
+ m_park_strobe_timer->adjust(attotime::never);
+ }
+ else
+ {
+ m_park_strobe_timer->adjust(attotime::from_msec(21), 0, attotime::from_msec(21));
+ }
+}
+
+
+//-------------------------------------------------
+// set_playing - general-purpose function for
+// setting a forward play mode
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::set_playing(const u8 new_status, const double fields_per_vsync)
+{
+ set_mode(MODE_PLAY);
+ m_status = new_status;
+ m_play_speed = fields_per_vsync;
+ m_search_frame = ~0U;
+ m_stop_frame = ~0U;
+}
+
+
+//-------------------------------------------------
+// set_playing - general-purpose function for
+// setting a forward play mode
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::set_stopped(const u8 new_status)
+{
+ set_mode(MODE_STOP);
+ m_status = new_status;
+}
+
+
+//-------------------------------------------------
+// cmd_play - play forward at 1x speed
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::cmd_play()
+{
+ LOGMASKED(LOG_COMMANDS, "process_command: Play\n");
+ set_slider_speed(0);
+ set_playing(STATUS_PLAY, 1.0);
+}
+
+
+//-------------------------------------------------
+// cmd_stop - stop/pause/freeze-frame
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::cmd_stop()
+{
+ if (m_cmd_number_length > 0)
+ {
+ const u32 command_value = cmd_number_to_bcd();
+ m_stop_timer->adjust(attotime::from_msec(100 * command_value));
+ m_pre_stop_status = m_status;
+ LOGMASKED(LOG_COMMANDS, "process_command: Stop (for %d.%d seconds)\n", command_value / 10, command_value % 10);
+ }
+ else
+ {
+ LOGMASKED(LOG_COMMANDS, "process_command: Stop\n");
+ }
+ set_stopped(STATUS_STOP);
+}
+
+
+//-------------------------------------------------
+// cmd_step - step one frame forward or backward
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::cmd_step(const int direction)
+{
+ advance_slider(direction);
+ set_stopped(STATUS_STOP);
+ m_stop_frame = ~0U;
+ m_search_frame = ~0U;
+}
+
+
+//-------------------------------------------------
+// cmd_play_forward - play forward at a specific
+// multiplier
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::cmd_play_forward(const double fields_per_vsync)
+{
+ LOGMASKED(LOG_COMMANDS, "process_command: Forward x%f\n", fields_per_vsync);
+ set_slider_speed(fields_per_vsync);
+ set_playing(STATUS_FORWARD, fields_per_vsync);
+}
+
+
+//-------------------------------------------------
+// cmd_search - begin a search operation to a
+// specific frame
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::cmd_search(const u32 frame)
+{
+ set_mode(MODE_SEARCH);
+ m_status = STATUS_SEARCH;
+ m_search_frame = frame;
+ m_stop_frame = ~0U;
+}
+
+
+//-------------------------------------------------
+// cmd_skip_forward - skip forward a specific
+// number of frames while in forward-play mode
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::cmd_skip_forward(const s32 amount)
+{
+ LOGMASKED(LOG_COMMANDS, "Command: Skip Forward %d\n", amount);
+ set_mode(MODE_SEARCH);
+ m_search_frame = ~0U;
+ m_stop_frame = m_curr_frame + amount;
+ m_scan_speed = amount;
+}
+
+
+//-------------------------------------------------
+// update_video_enable - set video enable state
+// on the base device based on our video switch
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::update_video_enable()
+{
+ LOGMASKED(LOG_SQUELCHES, "%s: Updating video enable (mode %d), video %s enabled\n", machine().describe_context(), m_mode, m_mode != MODE_PARK ? "is" : "is not");
+ video_enable(m_mode == MODE_PLAY || m_mode == MODE_STOP);
+}
+
+
+//-------------------------------------------------
+// update_audio_enable - set audio enable state
+// depending on our current mode or channel mute
+//-------------------------------------------------
+
+void pioneer_ldv1000hle_device::update_audio_enable()
+{
+ if (m_mode == MODE_PLAY && m_play_speed == 1.0)
+ {
+ LOGMASKED(LOG_SQUELCHES, "%s: Updating audio enable (playing at 1x, channels %d/%d)\n", machine().describe_context(), m_audio_enable[0], m_audio_enable[1]);
+ set_audio_squelch(!m_audio_enable[0], !m_audio_enable[1]);
+ }
+ else
+ {
+ LOGMASKED(LOG_SQUELCHES, "%s: Updating audio enable (muted, mode %d, speed %f)\n", machine().describe_context(), m_mode, m_play_speed);
+ set_audio_squelch(true, true);
+ }
+}
diff --git a/src/devices/machine/ldv1000hle.h b/src/devices/machine/ldv1000hle.h
new file mode 100644
index 00000000000..8484e27825b
--- /dev/null
+++ b/src/devices/machine/ldv1000hle.h
@@ -0,0 +1,201 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*************************************************************************
+
+ ldv1000hle.h
+
+ Pioneer LDV-1000 laserdisc player simulation.
+
+*************************************************************************/
+
+#ifndef MAME_MACHINE_LDV1000HLE_H
+#define MAME_MACHINE_LDV1000HLE_H
+
+#pragma once
+
+#include "laserdsc.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DECLARE_DEVICE_TYPE(PIONEER_LDV1000HLE, pioneer_ldv1000hle_device)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class pioneer_ldv1000hle_device : public parallel_laserdisc_device
+{
+public:
+ // construction/destruction
+ pioneer_ldv1000hle_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ virtual void data_w(u8 data) override;
+ virtual u8 data_r() override;
+ virtual void enter_w(int state) override;
+ virtual int status_strobe_r() override { return m_status_strobe; }
+ virtual int ready_r() override { return m_command_strobe; }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // laserdisc overrides
+ virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
+ virtual s32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
+
+ TIMER_CALLBACK_MEMBER(process_vbi_data);
+ TIMER_CALLBACK_MEMBER(resume_from_stop);
+ TIMER_CALLBACK_MEMBER(park_strobe_tick);
+ TIMER_CALLBACK_MEMBER(assert_status_strobe);
+ TIMER_CALLBACK_MEMBER(deassert_status_strobe);
+ TIMER_CALLBACK_MEMBER(assert_command_strobe);
+ TIMER_CALLBACK_MEMBER(deassert_command_strobe);
+
+private:
+ enum player_command : u8
+ {
+ CMD_CLEAR = 0xbf,
+ CMD_0 = 0x3f,
+ CMD_1 = 0x0f,
+ CMD_2 = 0x8f,
+ CMD_3 = 0x4f,
+ CMD_4 = 0x2f,
+ CMD_5 = 0xaf,
+ CMD_6 = 0x6f,
+ CMD_7 = 0x1f,
+ CMD_8 = 0x9f,
+ CMD_9 = 0x5f,
+ CMD_STORE = 0xf5,
+ CMD_RECALL = 0x7f,
+ CMD_DISPLAY = 0xf1,
+ CMD_AUDIO1 = 0xf4,
+ CMD_AUDIO2 = 0xfc,
+ CMD_PLAY = 0xfd,
+ CMD_STOP = 0xfb,
+ CMD_AUTOSTOP = 0xf3,
+ CMD_SEARCH = 0xf7,
+ CMD_SCAN_FWD = 0xf0,
+ CMD_SCAN_REV = 0xf8,
+ CMD_STEP_FWD = 0xf6,
+ CMD_STEP_REV = 0xfe,
+ CMD_REJECT = 0xf9,
+ CMD_NO_ENTRY = 0xff,
+ CMD_LOAD = 0xcc,
+ CMD_DISPLAY_DISABLE = 0xcd,
+ CMD_DISPLAY_ENABLE = 0xce,
+ CMD_GET_FRAME_NUM = 0xc2,
+ CMD_GET_2ND_DISPLAY = 0xc3,
+ CMD_GET_1ST_DISPLAY = 0xc4,
+ CMD_TRANSFER_MEMORY = 0xc8,
+ CMD_FWD_X0 = 0xa0,
+ CMD_FWD_X1_4 = 0xa1,
+ CMD_FWD_X1_2 = 0xa2,
+ CMD_FWD_X1 = 0xa3,
+ CMD_FWD_X2 = 0xa4,
+ CMD_FWD_X3 = 0xa5,
+ CMD_FWD_X4 = 0xa6,
+ CMD_FWD_X5 = 0xa7,
+ CMD_SKIP_FWD_10 = 0xb1,
+ CMD_SKIP_FWD_20 = 0xb2,
+ CMD_SKIP_FWD_30 = 0xb3,
+ CMD_SKIP_FWD_40 = 0xb4,
+ CMD_SKIP_FWD_50 = 0xb5,
+ CMD_SKIP_FWD_60 = 0xb6,
+ CMD_SKIP_FWD_70 = 0xb7,
+ CMD_SKIP_FWD_80 = 0xb8,
+ CMD_SKIP_FWD_90 = 0xb9,
+ CMD_SKIP_FWD_100 = 0xba
+ };
+
+ enum player_status : u8
+ {
+ STATUS_PARK = 0x7c,
+ STATUS_PLAY = 0x64,
+ STATUS_STOP = 0x65,
+ STATUS_SEARCH = 0x50,
+ STATUS_SEARCH_FINISH = 0xd0,
+ STATUS_SEARCH_ERROR = 0x90,
+ STATUS_AUTOSTOP = 0x54,
+ STATUS_SCAN = 0x4c,
+ STATUS_FORWARD = 0x2e,
+ STATUS_LOAD = 0x48,
+ STATUS_LOAD_END = 0xc8,
+ STATUS_LOAD_ERROR = 0xc4,
+ STATUS_FOCUS_UNLOCK = 0xbc,
+ STATUS_LEADIN = 0x58,
+ STATUS_LEADOUT = 0x5c,
+ STATUS_REJECT = 0x60,
+ STATUS_READY = 0x80
+ };
+
+ enum player_mode : u8
+ {
+ MODE_PARK,
+ MODE_PLAY,
+ MODE_SCAN_FORWARD,
+ MODE_SCAN_REVERSE,
+ MODE_SEARCH,
+ MODE_STOP
+ };
+
+ void process_command_buffer();
+ bool is_command_byte(const u8 data);
+ bool is_command_number(const u8 data);
+ void process_command(size_t cmd_index);
+
+ static u32 bcd_to_literal(u32 bcd);
+ u32 literal_to_bcd(u32 value);
+ u32 cmd_number_to_bcd();
+ u8 cmd_to_number(const u8 cmd);
+
+ void set_mode(const u8 mode);
+ void set_playing(const u8 new_status, const double fields_per_vsync);
+ void set_stopped(const u8 new_status);
+ void cmd_play();
+ void cmd_stop();
+ void cmd_step(const int direction);
+ void cmd_play_forward(const double fields_per_vsync);
+ void cmd_search(const u32 frame);
+ void cmd_skip_forward(const s32 amount);
+
+ void update_video_enable();
+ void update_audio_enable();
+
+ // internal state
+ emu_timer * m_vbi_fetch;
+ emu_timer * m_stop_timer;
+ emu_timer * m_park_strobe_timer;
+ emu_timer * m_assert_status_strobe_timer;
+ emu_timer * m_deassert_status_strobe_timer;
+ emu_timer * m_assert_command_strobe_timer;
+ emu_timer * m_deassert_command_strobe_timer;
+ u8 m_cmd_buffer[21];
+ u32 m_cmd_length;
+ u8 m_status;
+ u8 m_pre_stop_status;
+
+ u8 m_mode; // current player mode
+ u32 m_curr_frame; // frame number
+ u32 m_search_frame;
+ u32 m_stop_frame;
+ u8 m_cmd_number[5];
+ u32 m_cmd_number_length;
+
+ u16 m_user_ram[1024];
+ u32 m_curr_register;
+ u32 m_scan_speed;
+ u32 m_scan_speed_accum;
+ double m_play_speed;
+ bool m_audio_enable[2];
+ bool m_status_strobe;
+ bool m_command_strobe;
+};
+
+#endif // MAME_MACHINE_LDV1000HLE_H
diff --git a/src/devices/machine/ldv4200hle.cpp b/src/devices/machine/ldv4200hle.cpp
new file mode 100644
index 00000000000..c95c0f1ec3d
--- /dev/null
+++ b/src/devices/machine/ldv4200hle.cpp
@@ -0,0 +1,979 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*************************************************************************
+
+ ldv4200hle.cpp
+
+ Pioneer LD-V4200 laserdisc player simulation.
+
+**************************************************************************
+
+ To do:
+
+ * On-screen display support
+ * Better CLV support
+ * Chapter-search support
+ * Commands that Time Traveler doesn't use:
+ - Door Open/Close
+ - Reject
+ - Pause/Still
+ - Scan Forward/Reverse
+ - Multitrack-Jump Forward/Reverse
+ - Clear
+ - Leadout Symbol
+ - Key Lock and on-screen functions
+ - Status Requests
+ - Registers A-D
+
+*************************************************************************/
+
+
+#include "emu.h"
+#include "ldv4200hle.h"
+
+
+#define LOG_COMMAND_BYTES (1U << 1)
+#define LOG_COMMANDS (1U << 2)
+#define LOG_COMMAND_BUFFERS (1U << 3)
+#define LOG_REPLIES (1U << 4)
+#define LOG_REPLY_BYTES (1U << 5)
+#define LOG_SEARCHES (1U << 6)
+#define LOG_STOPS (1U << 7)
+#define LOG_SQUELCHES (1U << 8)
+#define LOG_FRAMES (1U << 9)
+#define LOG_ALL (LOG_COMMAND_BYTES | LOG_COMMANDS | LOG_COMMAND_BUFFERS | LOG_REPLY_BYTES | LOG_SEARCHES | LOG_STOPS | LOG_SQUELCHES | LOG_FRAMES)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+DEFINE_DEVICE_TYPE(PIONEER_LDV4200HLE, pioneer_ldv4200hle_device, "ldv4200hle", "Pioneer LD-V4200 HLE")
+
+
+
+//**************************************************************************
+// PIONEER LD-V4200 HLE IMPLEMENTATION
+//**************************************************************************
+
+//-------------------------------------------------
+// pioneer_ldv4200hle_device - constructor
+//-------------------------------------------------
+
+pioneer_ldv4200hle_device::pioneer_ldv4200hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : laserdisc_device(mconfig, PIONEER_LDV4200HLE, tag, owner, clock)
+ , device_serial_interface(mconfig, *this)
+ , m_serial_tx(*this)
+ , m_vbi_fetch(nullptr)
+ , m_cmd_length(0)
+ , m_cmd_running(false)
+ , m_reply_write_index(0)
+ , m_reply_read_index(0)
+ , m_mode(MODE_PARK)
+ , m_chapter(0)
+ , m_time(0)
+ , m_frame(0)
+ , m_search_chapter(~uint32_t(0))
+ , m_search_frame(~uint32_t(0))
+ , m_mark_chapter(~uint32_t(0))
+ , m_mark_frame(~uint32_t(0))
+ , m_key_lock(0)
+ , m_video_switch(1)
+ , m_audio_switch(0)
+ , m_display_switch(0)
+ , m_address_flag(ADDRESS_FRAME)
+ , m_speed(60)
+ , m_speed_accum(0)
+ , m_comm_ctrl(3)
+ , m_reg_a(3)
+ , m_reg_b(0)
+ , m_reg_c(0)
+ , m_reg_d(0)
+ , m_aux_port(3)
+ , m_curr_frame(0)
+{
+}
+
+
+//-------------------------------------------------
+// add_command_byte - handle a new data byte
+// received over the serial link
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::add_command_byte(uint8_t data)
+{
+ // Space and L/F codes are ignored in command sequences, per LD-V4400 Level I & III User's Manual, pg. 4-8
+ if (data == 0x20 || data == 0x0a)
+ return;
+
+ LOGMASKED(LOG_COMMAND_BYTES, "Command byte added: %02x\n", data);
+ if (m_cmd_length < std::size(m_cmd_buffer))
+ {
+ m_cmd_buffer[m_cmd_length] = data;
+ m_cmd_length++;
+ }
+ if (data == 0x0d)
+ {
+ normalize_command_buffer();
+ process_command_buffer();
+ m_cmd_length = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// queue_reply - queues a reply string to send
+// back to the host
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::queue_reply(const char *reply)
+{
+ char print_buf[128];
+
+ uint8_t max_writable = (uint8_t)std::size(m_reply_buffer);
+ for (uint8_t i = 0; i < max_writable && reply[i] != 0; i++)
+ {
+ m_reply_buffer[m_reply_write_index] = reply[i];
+ m_reply_write_index = (m_reply_write_index + 1) % max_writable;
+ print_buf[i] = (reply[i] == '\x0d' ? 0 : reply[i]);
+ }
+ LOGMASKED(LOG_REPLIES, "Sending reply: %s\n", print_buf);
+
+ if (!m_replying)
+ {
+ m_replying = true;
+ LOGMASKED(LOG_REPLY_BYTES, "Sending reply byte: %02x\n", (uint8_t)m_reply_buffer[m_reply_read_index]);
+ transmit_register_setup(m_reply_buffer[m_reply_read_index]);
+ }
+}
+
+
+//-------------------------------------------------
+// queue_error - queues an error-code string to
+// send back to the host
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::queue_error(error_code err)
+{
+ char buf[5] = { 'E', '0', '0', '\x0d', '\0' };
+ buf[1] += err / 10;
+ buf[2] += err % 10;
+ queue_reply(buf);
+}
+
+
+//-------------------------------------------------
+// normalize_command_buffer - ensure any alphabet
+// characters in the command buffer are
+// upper-cased for matching purposes.
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::normalize_command_buffer()
+{
+ char print_buf[64];
+ for (uint8_t i = 0; i < m_cmd_length; i++)
+ {
+ if (m_cmd_buffer[i] >= 'a' && m_cmd_buffer[i] <= 'z')
+ {
+ m_cmd_buffer[i] &= ~0x20;
+ }
+ print_buf[i] = (char)m_cmd_buffer[i];
+ }
+ print_buf[m_cmd_length - 1] = '\0';
+ LOGMASKED(LOG_COMMAND_BUFFERS, "Command Buffer: %02d:%02d:%02d: %s\n", (int)(machine().time().seconds() / 60), (int)(machine().time().seconds()) % 60, (machine().time() * 100).seconds() % 100, print_buf);
+}
+
+
+//-------------------------------------------------
+// process_command_buffer - process a command
+// line sent from the host
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::process_command_buffer()
+{
+ if (m_cmd_length <= 1)
+ return;
+
+ error_code err = ERR_NONE;
+ uint8_t cmd_index = 0;
+ bool send_reply = true;
+ while (cmd_index < m_cmd_length && err == ERR_NONE)
+ {
+ if (cmd_index == (m_cmd_length - 1) && m_cmd_buffer[cmd_index] == 0x0d)
+ {
+ break;
+ }
+
+ uint32_t value = ~uint32_t(0);
+ if (is_number(m_cmd_buffer[cmd_index]))
+ {
+ cmd_index += parse_numeric_value(cmd_index, value, err);
+ }
+ if (err == ERR_NONE)
+ {
+ cmd_index += process_command(cmd_index, value, err);
+ if (m_cmd_running)
+ {
+ send_reply = false;
+ }
+ }
+ }
+
+ if (send_reply)
+ {
+ if (err == ERR_NONE)
+ {
+ queue_reply("R\x0d");
+ }
+ else
+ {
+ queue_error(err);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// bcd_to_literal - converts a BCD value used in
+// commands a direct numeric value
+//-------------------------------------------------
+
+uint32_t pioneer_ldv4200hle_device::bcd_to_literal(uint32_t bcd)
+{
+ uint32_t value = 0;
+ uint32_t shift = 28;
+ uint32_t multiplier = 10000000;
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ uint32_t digit = (bcd >> shift) & 0xf;
+ bcd &= ~(0xf << shift);
+
+ value += digit * multiplier;
+
+ multiplier /= 10;
+ shift -= 4;
+ }
+ return value;
+}
+
+
+//-------------------------------------------------
+// is_number - indicates if a given character is
+// a numeric value
+//-------------------------------------------------
+
+bool pioneer_ldv4200hle_device::is_number(char value)
+{
+ return value >= '0' && value <= '9';
+}
+
+
+//-------------------------------------------------
+// parse_numeric_value - parses a numeric value
+// from the command buffer
+//-------------------------------------------------
+
+uint8_t pioneer_ldv4200hle_device::parse_numeric_value(uint8_t cmd_index, uint32_t &value, error_code &err)
+{
+ static const uint8_t MAX_NUMBER_LENGTH = 7;
+ uint8_t number_length = 0;
+ value = 0;
+ while (number_length < MAX_NUMBER_LENGTH && is_number(m_cmd_buffer[cmd_index]) && cmd_index < m_cmd_length)
+ {
+ value *= 10;
+ value += m_cmd_buffer[cmd_index] - '0';
+ cmd_index++;
+ number_length++;
+ }
+
+ if (cmd_index == m_cmd_length)
+ {
+ err = ERR_COMMUNICATION;
+ return number_length;
+ }
+
+ if (number_length == MAX_NUMBER_LENGTH && is_number(m_cmd_buffer[cmd_index]))
+ {
+ err = ERR_MISSING_ARGUMENT;
+ return number_length;
+ }
+
+ return number_length;
+}
+
+
+//-------------------------------------------------
+// process_command - processes a single command
+// from the command buffer
+//-------------------------------------------------
+
+uint8_t pioneer_ldv4200hle_device::process_command(uint8_t cmd_index, uint32_t value, error_code &err)
+{
+ const uint8_t remaining_bytes = m_cmd_length - cmd_index;
+ if (remaining_bytes == 1 && m_cmd_buffer[cmd_index] == 0x0d)
+ {
+ // Done processing
+ return remaining_bytes;
+ }
+ else if (remaining_bytes < 3)
+ {
+ // Not enough data in the buffer to form a valid command
+ err = ERR_COMMUNICATION;
+ return remaining_bytes;
+ }
+
+ uint16_t command = (m_cmd_buffer[cmd_index] << 8) | m_cmd_buffer[cmd_index + 1];
+ switch (command)
+ {
+ case CMD_DOOR_OPEN:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Door Open\n", machine().describe_context());
+ break;
+ case CMD_DOOR_CLOSE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Door Close\n", machine().describe_context());
+ break;
+ case CMD_REJECT:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Reject\n", machine().describe_context());
+ break;
+ case CMD_START:
+ LOGMASKED(LOG_COMMANDS | LOG_SQUELCHES, "%s: Command: Start (squelching audio, unsquelching + disabling video)\n", machine().describe_context());
+ m_mode = MODE_PAUSE;
+ video_enable(false);
+ set_video_squelch(false);
+ set_audio_squelch(true, true);
+ break;
+ case CMD_PLAY:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Play [%d] (cancelling search)\n", machine().describe_context(), value == ~uint32_t(0) ? 0 : value);
+ m_speed_accum = 0;
+ m_mode = MODE_PLAY;
+ update_audio_squelch();
+ update_video_enable();
+ if (value != ~uint32_t(0))
+ {
+ LOGMASKED(LOG_COMMANDS, "%s: Setting stop frame\n", machine().describe_context());
+ m_mark_frame = value + 1;
+ m_cmd_running = true;
+ }
+ m_search_frame = ~uint32_t(0);
+ m_search_chapter = ~uint32_t(0);
+ break;
+ case CMD_PAUSE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Pause\n", machine().describe_context());
+ m_mode = MODE_PAUSE;
+ video_enable(false);
+ set_audio_squelch(true, true);
+ break;
+ case CMD_STILL:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Still\n", machine().describe_context());
+ m_mode = MODE_STILL;
+ set_audio_squelch(true, true);
+ break;
+ case CMD_STEP_FORWARD:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Step Forward\n", machine().describe_context());
+ m_mode = MODE_STILL;
+ set_audio_squelch(true, true);
+ m_mark_frame = ~uint32_t(0);
+ advance_slider(1);
+ break;
+ case CMD_STEP_REVERSE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Step Reverse\n", machine().describe_context());
+ m_mode = MODE_STILL;
+ set_audio_squelch(true, true);
+ m_mark_frame = ~uint32_t(0);
+ advance_slider(-1);
+ break;
+ case CMD_SCAN_FORWARD:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Scan Forward\n", machine().describe_context());
+ break;
+ case CMD_SCAN_REVERSE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Scan Reverse\n", machine().describe_context());
+ break;
+ case CMD_MULTISPEED_FORWARD:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Speed Forward (%d) (cancelling search)\n", machine().describe_context(), value == ~uint32_t(0) ? 0 : value);
+ m_search_frame = ~uint32_t(0);
+ m_search_chapter = ~uint32_t(0);
+ if (value + 1 == m_curr_frame)
+ {
+ LOGMASKED(LOG_COMMANDS, "%s: Already at desired frame, entering still/pause\n", machine().describe_context(), value == ~uint32_t(0) ? 0 : value);
+ if (is_cav_disc())
+ {
+ m_mode = MODE_STILL;
+ update_video_enable();
+ }
+ else
+ {
+ m_mode = MODE_PAUSE;
+ video_enable(false);
+ }
+ }
+ else
+ {
+ m_mode = MODE_MS_FORWARD;
+ if (value != ~uint32_t(0))
+ {
+ LOGMASKED(LOG_COMMANDS, "%s: Setting stop frame\n", machine().describe_context());
+ m_mark_frame = value + 1;
+ m_cmd_running = true;
+ }
+ }
+ break;
+ case CMD_MULTISPEED_REVERSE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Speed Reverse (%d) (cancelling search)\n", machine().describe_context(), value == ~uint32_t(0) ? 0 : value);
+ m_search_frame = ~uint32_t(0);
+ m_search_chapter = ~uint32_t(0);
+ if (value + 1 == m_curr_frame)
+ {
+ LOGMASKED(LOG_COMMANDS, "%s: Already at desired frame, entering still/pause\n", machine().describe_context(), value == ~uint32_t(0) ? 0 : value);
+ if (is_cav_disc())
+ {
+ m_mode = MODE_STILL;
+ update_video_enable();
+ }
+ else
+ {
+ m_mode = MODE_PAUSE;
+ video_enable(false);
+ }
+ }
+ else
+ {
+ m_mode = MODE_MS_REVERSE;
+ if (value != ~uint32_t(0))
+ {
+ LOGMASKED(LOG_COMMANDS, "%s: Setting stop frame\n", machine().describe_context());
+ m_mark_frame = value + 1;
+ m_cmd_running = true;
+ }
+ }
+ break;
+ case CMD_SPEED_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Speed Set %05d\n", machine().describe_context(), value);
+ if (is_cav_disc())
+ {
+ m_speed = value;
+ if (m_speed == 0)
+ {
+ m_speed = 1;
+ }
+ else if (m_speed > 255)
+ {
+ m_speed = 255;
+ }
+ }
+ else
+ {
+ err = ERR_NOT_AVAILABLE;
+ }
+ break;
+ case CMD_SEARCH:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Search %d\n", machine().describe_context(), value);
+ begin_search(value);
+ m_cmd_running = true;
+ m_mode = MODE_SEARCH;
+ break;
+ case CMD_MULTITRACK_FORWARD:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Track Jump Forward %05d\n", machine().describe_context(), value);
+ break;
+ case CMD_MULTITRACK_REVERSE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Multi-Track Jump Reverse %05d\n", machine().describe_context(), value);
+ break;
+ case CMD_STOP_MARKER:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Stop Marker %d\n", machine().describe_context(), value);
+ if (m_address_flag == ADDRESS_FRAME)
+ {
+ m_mark_frame = value + 1;
+ }
+ else if (m_address_flag == ADDRESS_CHAPTER)
+ {
+ m_mark_chapter = value;
+ }
+ break;
+ case CMD_FRAME_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Frame Set\n", machine().describe_context());
+ m_address_flag = ADDRESS_FRAME;
+ break;
+ case CMD_TIME_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Time Set\n", machine().describe_context());
+ if (!is_cav_disc())
+ {
+ m_address_flag = ADDRESS_TIME;
+ }
+ else
+ {
+ err = ERR_NOT_AVAILABLE;
+ }
+ break;
+ case CMD_CHAPTER_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Chapter Set\n", machine().describe_context());
+ m_address_flag = ADDRESS_CHAPTER;
+ break;
+ case CMD_CLEAR:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Clear\n", machine().describe_context());
+ break;
+ case CMD_LEADOUT_SYMBOL:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Lead-Out Symbol\n", machine().describe_context());
+ break;
+ case CMD_AUDIO_CTRL:
+ m_audio_switch = value;
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Audio Control %05d\n", machine().describe_context(), value);
+ update_audio_squelch();
+ break;
+ case CMD_VIDEO_CTRL:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Video Control %05d\n", machine().describe_context(), value);
+ m_video_switch = value;
+ update_video_enable();
+ break;
+ case CMD_KEY_LOCK:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Key Lock %05d\n", machine().describe_context(), value);
+ break;
+ case CMD_DISPLAY_CONTROL:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Display Control %05d\n", machine().describe_context(), value);
+ break;
+ case CMD_CLEAR_SCREEN:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Clear Screen\n", machine().describe_context());
+ break;
+ case CMD_PRINT_CHAR:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Print Character %05d\n", machine().describe_context(), value);
+ break;
+ case CMD_REQ_FRAME_NUMBER:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Frame Number Request\n", machine().describe_context());
+ break;
+ case CMD_REQ_TIME_CODE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Time Code Request\n", machine().describe_context());
+ break;
+ case CMD_REQ_CHAPTER_NUMBER:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Chapter Number Request\n", machine().describe_context());
+ break;
+ case CMD_REQ_PLAYER_MODE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Player Active Mode Request\n", machine().describe_context());
+ break;
+ case CMD_REQ_DISC_STATUS:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Disc Status Request\n", machine().describe_context());
+ break;
+ case CMD_REQ_LDP_MODEL:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: LDP Model Name Request\n", machine().describe_context());
+ break;
+ case CMD_REQ_PIONEER_DISC_ID:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Pioneer User's Code Request (Disc ID)\n", machine().describe_context());
+ break;
+ case CMD_REQ_STANDARD_DISC_ID:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Standard User's Code Request (Disc ID)\n", machine().describe_context());
+ break;
+ case CMD_REQ_TV_SYSTEM:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Television System Request\n", machine().describe_context());
+ break;
+ case CMD_COMMUNICATION_CTRL:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Communication Control %05d\n", machine().describe_context(), value);
+ break;
+ case CMD_REQ_CCR_MODE:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: CCR Mode Request\n", machine().describe_context());
+ break;
+ case CMD_REGISTER_A_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register A Set (Display) %d\n", machine().describe_context(), value);
+ break;
+ case CMD_REGISTER_B_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register B Set (Squelch Control) %d\n", machine().describe_context(), value);
+ break;
+ case CMD_REGISTER_C_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register C Set (Miscellaneous) %d\n", machine().describe_context(), value);
+ break;
+ case CMD_REGISTER_D_SET:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register D Set (RS-232) %d\n", machine().describe_context(), value);
+ break;
+ case CMD_REQ_REGISTER_A:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register A Request (Display)\n", machine().describe_context());
+ break;
+ case CMD_REQ_REGISTER_B:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register B Request (Squelch Control)\n", machine().describe_context());
+ break;
+ case CMD_REQ_REGISTER_C:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register C Request (Miscellaneous)\n", machine().describe_context());
+ break;
+ case CMD_REQ_REGISTER_D:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Register D Request (RS-232)\n", machine().describe_context());
+ break;
+ case CMD_REQ_INPUT_UNIT:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Input Unit Request\n", machine().describe_context());
+ break;
+ case CMD_INPUT_NUMBER_WAIT:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Input Number Wait\n", machine().describe_context());
+ break;
+ default:
+ LOGMASKED(LOG_COMMANDS, "%s: Command: Unknown (%c%c)\n", machine().describe_context(), m_cmd_buffer[cmd_index], m_cmd_buffer[cmd_index + 1]);
+ err = ERR_NOT_AVAILABLE;
+ break;
+ }
+
+ return 2;
+}
+
+
+//-------------------------------------------------
+// begin_search - initiates a search operation
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::begin_search(uint32_t value)
+{
+ if (m_address_flag == ADDRESS_FRAME)
+ {
+ m_search_frame = value + 1;
+ LOGMASKED(LOG_SEARCHES, "%s: Beginning search from frame address %d\n", machine().describe_context(), value);
+ }
+ else if (m_address_flag == ADDRESS_CHAPTER)
+ {
+ m_search_chapter = value;
+ LOGMASKED(LOG_SEARCHES, "%s: Beginning search from chapter address %d\n", machine().describe_context(), value);
+ }
+
+ set_audio_squelch(true, true);
+
+ if (std::abs((int32_t)m_search_frame - (int32_t)m_curr_frame) > 100)
+ {
+ LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search distance is outside +/- 100 frames, squelching audio+video\n", machine().describe_context());
+ video_enable(false);
+ set_audio_squelch(true, true);
+ }
+ else
+ {
+ LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search distance is within +/- 100 frames, squelching audio and doing live search\n", machine().describe_context());
+ }
+}
+
+
+//-------------------------------------------------
+// update_audio_squelch - set audio squelch state
+// on the base device based on our audio switch
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::update_audio_squelch()
+{
+ const bool squelch_both = (m_mode == MODE_STILL || m_mode == MODE_PAUSE || m_mode == MODE_SEARCH);
+ const bool squelch_left = !(m_audio_switch == 1 || m_audio_switch == 3) || squelch_both;
+ const bool squelch_right = !(m_audio_switch == 2 || m_audio_switch == 3) || squelch_both;
+ set_audio_squelch(squelch_left, squelch_right);
+ LOGMASKED(LOG_SQUELCHES, "%s: Updating audio squelch (L:%d, R:%d)\n", machine().describe_context(), squelch_left, squelch_right);
+}
+
+
+//-------------------------------------------------
+// update_video_enable - set video enable state
+// on the base device based on our video switch
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::update_video_enable()
+{
+ video_enable(m_video_switch == 1 && (m_mode == MODE_STILL || m_mode == MODE_PLAY || m_mode == MODE_MS_FORWARD || m_mode == MODE_MS_REVERSE));
+ LOGMASKED(LOG_SQUELCHES, "%s: Updating video enable (Switch:%d, Mode:%d)\n", machine().describe_context(), m_video_switch, m_mode);
+}
+
+
+//-------------------------------------------------
+// device_start - device initialization
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::device_start()
+{
+ // pass through to the parent
+ laserdisc_device::device_start();
+
+ // allocate timers
+ m_vbi_fetch = timer_alloc(FUNC(pioneer_ldv4200hle_device::process_vbi_data), this);
+
+ // register state saving
+ save_item(NAME(m_cmd_buffer));
+ save_item(NAME(m_cmd_length));
+ save_item(NAME(m_cmd_running));
+ save_item(NAME(m_reply_buffer));
+ save_item(NAME(m_reply_write_index));
+ save_item(NAME(m_reply_read_index));
+ save_item(NAME(m_replying));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_chapter));
+ save_item(NAME(m_time));
+ save_item(NAME(m_frame));
+ save_item(NAME(m_search_chapter));
+ save_item(NAME(m_search_frame));
+ save_item(NAME(m_mark_chapter));
+ save_item(NAME(m_mark_frame));
+ save_item(NAME(m_key_lock));
+ save_item(NAME(m_video_switch));
+ save_item(NAME(m_audio_switch));
+ save_item(NAME(m_display_switch));
+ save_item(NAME(m_address_flag));
+ save_item(NAME(m_speed));
+ save_item(NAME(m_speed_accum));
+ save_item(NAME(m_comm_ctrl));
+ save_item(NAME(m_reg_a));
+ save_item(NAME(m_reg_b));
+ save_item(NAME(m_reg_c));
+ save_item(NAME(m_reg_d));
+ save_item(NAME(m_aux_port));
+ save_item(NAME(m_curr_frame));
+}
+
+
+//-------------------------------------------------
+// device_reset - device reset
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::device_reset()
+{
+ // pass through to the parent
+ laserdisc_device::device_reset();
+
+ // initialize diserial
+ set_tra_rate(attotime::from_hz(4800));
+ set_rcv_rate(attotime::from_hz(4800));
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
+
+ // reset our state
+ m_vbi_fetch->adjust(attotime::never);
+
+ std::fill_n(m_cmd_buffer, std::size(m_cmd_buffer), 0);
+ m_cmd_length = 0;
+ m_cmd_running = false;
+ std::fill_n(m_reply_buffer, std::size(m_reply_buffer), 0);
+ m_reply_write_index = 0;
+ m_reply_read_index = 0;
+ m_replying = false;
+ m_mode = MODE_PARK;
+ m_chapter = 0;
+ m_time = 0;
+ m_frame = 0;
+ m_search_chapter = ~uint32_t(0);
+ m_search_frame = ~uint32_t(0);
+ m_mark_chapter = ~uint32_t(0);
+ m_mark_frame = ~uint32_t(0);
+ m_key_lock = 0;
+ m_video_switch = 1;
+ m_audio_switch = 0;
+ m_display_switch = 0;
+ m_address_flag = ADDRESS_FRAME;
+ m_speed = 60;
+ m_speed_accum = 0;
+ m_comm_ctrl = 3;
+ m_reg_a = 3;
+ m_reg_b = 0;
+ m_reg_c = 0;
+ m_reg_d = 0;
+ m_aux_port = 3;
+ m_curr_frame = 0;
+
+ video_enable(false);
+ set_audio_squelch(true, true);
+}
+
+
+//-------------------------------------------------
+// process_vbi_data - process VBI data and
+// act on search/play seeking
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pioneer_ldv4200hle_device::process_vbi_data)
+{
+ uint32_t line = get_field_code(LASERDISC_CODE_LINE1718, false);
+ if ((line & 0xf80000) == 0xf80000 || line == VBI_CODE_LEADIN || line == VBI_CODE_LEADOUT)
+ {
+ uint32_t old_frame = m_curr_frame;
+ if (line == VBI_CODE_LEADIN)
+ m_curr_frame = 0;
+ else if (line == VBI_CODE_LEADOUT)
+ m_curr_frame = 54000;
+ else
+ m_curr_frame = bcd_to_literal(line & 0x7ffff);
+
+ LOGMASKED(LOG_FRAMES, "Current frame is %d (VBI 16: %06x, VBI 17: %06x, VBI 18: %06x, VBI 1718: %06x\n", m_curr_frame,
+ get_field_code(LASERDISC_CODE_LINE16, false),
+ get_field_code(LASERDISC_CODE_LINE17, false),
+ get_field_code(LASERDISC_CODE_LINE18, false),
+ line);
+
+ if (m_mode != MODE_STILL && m_mode != MODE_PAUSE)
+ {
+ if (m_mark_frame != ~uint32_t(0) && m_search_frame == ~uint32_t(0))
+ {
+ int32_t old_delta = (int32_t)m_mark_frame - (int32_t)old_frame;
+ int32_t curr_delta = (int32_t)m_mark_frame - (int32_t)m_curr_frame;
+ LOGMASKED(LOG_STOPS, "%s: Stop Mark is currently %d, old frame is %d, current frame is %d, old delta %d, curr delta %d\n", machine().describe_context(), m_mark_frame, old_frame, m_curr_frame, old_delta, curr_delta);
+ if (curr_delta == 0 || (old_delta < 0) != (curr_delta < 0))
+ {
+ m_mark_frame = ~uint32_t(0);
+ if (is_cav_disc())
+ {
+ LOGMASKED(LOG_STOPS | LOG_SQUELCHES, "%s: Stop Mark: Zero delta w/ CAV disc, entering still mode and squelching audio\n", machine().describe_context());
+ m_mode = MODE_STILL;
+ update_video_enable();
+ }
+ else
+ {
+ LOGMASKED(LOG_STOPS | LOG_SQUELCHES, "%s: Stop Mark: Zero delta w/ CLV disc, entering still mode and squelching video+audio\n", machine().describe_context());
+ m_mode = MODE_PAUSE;
+ video_enable(false);
+ }
+
+ set_audio_squelch(true, true);
+
+ if (m_cmd_running)
+ {
+ LOGMASKED(LOG_SEARCHES | LOG_COMMANDS, "%s: Stop Mark: Command running, sending reply\n", machine().describe_context());
+ m_cmd_running = false;
+ queue_reply("R\x0d");
+ }
+ }
+ }
+
+ if (m_search_frame != ~uint32_t(0))
+ {
+ // TODO: Chapter-search support
+ int32_t delta = (int32_t)m_search_frame - (int32_t)m_curr_frame;
+ LOGMASKED(LOG_SEARCHES, "%s: Searching from current frame %d with delta %d\n", machine().describe_context(), m_curr_frame, delta);
+ if (delta == 0)
+ {
+ // We've found our frame, enter play, pause or still mode.
+ m_search_frame = ~uint32_t(0);
+ if (is_cav_disc())
+ {
+ LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search Mark: Zero delta w/ CAV disc, entering still mode and squelching audio\n", machine().describe_context());
+ m_mode = MODE_STILL;
+ update_video_enable();
+ }
+ else
+ {
+ LOGMASKED(LOG_SEARCHES | LOG_SQUELCHES, "%s: Search Mark: Zero delta w/ CLV disc, entering still mode and squelching video+audio\n", machine().describe_context());
+ m_mode = MODE_PAUSE;
+ video_enable(false);
+ }
+
+ set_audio_squelch(true, true);
+
+ if (m_cmd_running)
+ {
+ LOGMASKED(LOG_SEARCHES | LOG_COMMANDS, "%s: Search Mark: Command running, sending reply\n", machine().describe_context());
+ m_cmd_running = false;
+ queue_reply("R\x0d");
+ }
+ }
+ else if (delta <= 2 && delta > 0)
+ {
+ LOGMASKED(LOG_SEARCHES, "%s: Positive near delta, letting disc run to current\n", machine().describe_context());
+ // We're approaching our frame, let it run up.
+ }
+ else
+ {
+ if (delta < 0)
+ {
+ advance_slider(std::min(-2, delta / 2));
+ }
+ else
+ {
+ advance_slider(std::max(1, delta / 2));
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// player_vsync - VSYNC callback, called at the
+// start of the blanking period
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
+{
+ // set a timer to fetch the VBI data when it is ready
+ if (m_mode > MODE_DOOR_OPEN)
+ {
+ m_vbi_fetch->adjust(screen().time_until_pos(19*2));
+ }
+}
+
+
+//-------------------------------------------------
+// player_update - update callback, called on
+// the first visible line of the frame
+//-------------------------------------------------
+
+int32_t pioneer_ldv4200hle_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
+{
+ if (!fieldnum)
+ return 0;
+
+ if (m_mode == MODE_MS_FORWARD || m_mode == MODE_MS_REVERSE)
+ {
+ m_speed_accum += m_speed;
+ int elapsed_tracks = m_speed_accum / 60;
+ m_speed_accum -= elapsed_tracks * 60;
+ if (m_mode == MODE_MS_REVERSE)
+ elapsed_tracks *= -1;
+
+ if (m_mark_frame != ~uint32_t(0))
+ {
+ int32_t jump_frame = (int32_t)m_curr_frame + elapsed_tracks;
+ int32_t curr_delta = (int32_t)m_mark_frame - (int32_t)m_curr_frame;
+ int32_t next_delta = (int32_t)m_mark_frame - (int32_t)jump_frame;
+ if ((curr_delta < 0) != (next_delta < 0))
+ {
+ elapsed_tracks = curr_delta;
+ }
+ }
+ return elapsed_tracks;
+ }
+
+
+ if (m_mode == MODE_PLAY || m_mode == MODE_SEARCH)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// rcv_complete - called by diserial when we
+// have received a complete byte
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::rcv_complete()
+{
+ receive_register_extract();
+ add_command_byte(get_received_char());
+}
+
+
+//-------------------------------------------------
+// tra_complete - called by diserial when we
+// have transmitted a complete byte
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::tra_complete()
+{
+ m_reply_read_index = (m_reply_read_index + 1) % (uint8_t)std::size(m_reply_buffer);
+ if (m_reply_read_index != m_reply_write_index)
+ {
+ uint8_t data = (uint8_t)m_reply_buffer[m_reply_read_index];
+ LOGMASKED(LOG_REPLY_BYTES, "Sending reply byte: %02x\n", data);
+ transmit_register_setup(data);
+ }
+ else
+ {
+ m_replying = false;
+ }
+}
+
+
+//-------------------------------------------------
+// tra_callback - called by diserial when we
+// transmit a single bit
+//-------------------------------------------------
+
+void pioneer_ldv4200hle_device::tra_callback()
+{
+ m_serial_tx(transmit_register_get_data_bit());
+}
diff --git a/src/devices/machine/ldv4200hle.h b/src/devices/machine/ldv4200hle.h
new file mode 100644
index 00000000000..3c282667010
--- /dev/null
+++ b/src/devices/machine/ldv4200hle.h
@@ -0,0 +1,212 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*************************************************************************
+
+ ldv4200hle.h
+
+ Pioneer LD-V4200 laserdisc player simulation.
+
+*************************************************************************/
+
+#ifndef MAME_MACHINE_LDV4200_H
+#define MAME_MACHINE_LDV4200_H
+
+#pragma once
+
+#include "laserdsc.h"
+#include "diserial.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DECLARE_DEVICE_TYPE(PIONEER_LDV4200HLE, pioneer_ldv4200hle_device)
+
+
+
+//**************************************************************************
+// GLOBAL HELPERS
+//**************************************************************************
+
+// Note: This should be included within the class rather than the global namespace.
+// However, doing so results in a "called in a constant expression before its definition is complete" error for the enum values.
+static constexpr uint16_t make_ldv4000_command(const char *str) { return ((uint8_t)str[0] << 8) | (uint8_t)str[1]; }
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> pioneer_ldv4200hle_device
+
+class pioneer_ldv4200hle_device : public laserdisc_device, public device_serial_interface
+{
+public:
+ // construction/destruction
+ pioneer_ldv4200hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ auto serial_tx() { return m_serial_tx.bind(); }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // laserdisc overrides
+ virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
+ virtual int32_t player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
+ virtual void player_overlay(bitmap_yuy16 &bitmap) override { }
+
+ // diserial overrides
+ virtual void rcv_complete() override;
+ virtual void tra_complete() override;
+ virtual void tra_callback() override;
+
+ TIMER_CALLBACK_MEMBER(process_vbi_data);
+
+private:
+ enum player_command : uint16_t
+ {
+ CMD_DOOR_OPEN = make_ldv4000_command("OP"),
+ CMD_DOOR_CLOSE = make_ldv4000_command("CO"),
+ CMD_REJECT = make_ldv4000_command("RJ"),
+ CMD_START = make_ldv4000_command("SA"),
+ CMD_PLAY = make_ldv4000_command("PL"),
+ CMD_PAUSE = make_ldv4000_command("PA"),
+ CMD_STILL = make_ldv4000_command("ST"),
+ CMD_STEP_FORWARD = make_ldv4000_command("SF"),
+ CMD_STEP_REVERSE = make_ldv4000_command("SR"),
+ CMD_SCAN_FORWARD = make_ldv4000_command("NF"),
+ CMD_SCAN_REVERSE = make_ldv4000_command("NR"),
+ CMD_MULTISPEED_FORWARD = make_ldv4000_command("MF"),
+ CMD_MULTISPEED_REVERSE = make_ldv4000_command("MR"),
+ CMD_SPEED_SET = make_ldv4000_command("SP"),
+ CMD_SEARCH = make_ldv4000_command("SE"),
+ CMD_MULTITRACK_FORWARD = make_ldv4000_command("JF"),
+ CMD_MULTITRACK_REVERSE = make_ldv4000_command("JR"),
+ CMD_STOP_MARKER = make_ldv4000_command("SM"),
+ CMD_FRAME_SET = make_ldv4000_command("FR"),
+ CMD_TIME_SET = make_ldv4000_command("TM"),
+ CMD_CHAPTER_SET = make_ldv4000_command("CH"),
+ CMD_CLEAR = make_ldv4000_command("CL"),
+ CMD_LEADOUT_SYMBOL = make_ldv4000_command("LO"),
+ CMD_AUDIO_CTRL = make_ldv4000_command("AD"),
+ CMD_VIDEO_CTRL = make_ldv4000_command("VD"),
+ CMD_KEY_LOCK = make_ldv4000_command("KL"),
+ CMD_DISPLAY_CONTROL = make_ldv4000_command("DS"),
+ CMD_CLEAR_SCREEN = make_ldv4000_command("CS"),
+ CMD_PRINT_CHAR = make_ldv4000_command("PR"),
+ CMD_REQ_FRAME_NUMBER = make_ldv4000_command("?F"),
+ CMD_REQ_TIME_CODE = make_ldv4000_command("?T"),
+ CMD_REQ_CHAPTER_NUMBER = make_ldv4000_command("?C"),
+ CMD_REQ_PLAYER_MODE = make_ldv4000_command("?P"),
+ CMD_REQ_DISC_STATUS = make_ldv4000_command("?D"),
+ CMD_REQ_LDP_MODEL = make_ldv4000_command("?X"),
+ CMD_REQ_PIONEER_DISC_ID = make_ldv4000_command("?U"),
+ CMD_REQ_STANDARD_DISC_ID = make_ldv4000_command("$Y"),
+ CMD_REQ_TV_SYSTEM = make_ldv4000_command("?S"),
+ CMD_COMMUNICATION_CTRL = make_ldv4000_command("CM"),
+ CMD_REQ_CCR_MODE = make_ldv4000_command("?M"),
+ CMD_REGISTER_A_SET = make_ldv4000_command("RA"),
+ CMD_REGISTER_B_SET = make_ldv4000_command("RB"),
+ CMD_REGISTER_C_SET = make_ldv4000_command("RC"),
+ CMD_REGISTER_D_SET = make_ldv4000_command("RD"),
+ CMD_REQ_REGISTER_A = make_ldv4000_command("$A"),
+ CMD_REQ_REGISTER_B = make_ldv4000_command("$B"),
+ CMD_REQ_REGISTER_C = make_ldv4000_command("$C"),
+ CMD_REQ_REGISTER_D = make_ldv4000_command("$D"),
+ CMD_REQ_INPUT_UNIT = make_ldv4000_command("#I"),
+ CMD_INPUT_NUMBER_WAIT = make_ldv4000_command("?N")
+ };
+
+ enum player_mode : uint8_t
+ {
+ MODE_PARK,
+ MODE_DOOR_OPEN,
+ MODE_PAUSE,
+ MODE_PLAY,
+ MODE_MS_FORWARD,
+ MODE_MS_REVERSE,
+ MODE_SEARCH,
+ MODE_STILL
+ };
+
+ enum address_mode : uint8_t
+ {
+ ADDRESS_FRAME,
+ ADDRESS_TIME,
+ ADDRESS_CHAPTER
+ };
+
+ enum error_code : uint8_t
+ {
+ ERR_NONE = 0xff,
+ ERR_COMMUNICATION = 0,
+ ERR_NOT_AVAILABLE = 4,
+ ERR_MISSING_ARGUMENT = 6,
+ ERR_DISC_NOT_LOADED = 11,
+ ERR_SEARCH = 12,
+ ERR_DEFOCUS = 13,
+ ERR_PICTURE_STOP = 15,
+ ERR_OTHER_INPUT = 16,
+ ERR_PANIC = 99
+ };
+
+ void add_command_byte(uint8_t data);
+
+ void queue_reply(const char *reply);
+ void queue_error(error_code err);
+
+ void normalize_command_buffer();
+ void process_command_buffer();
+
+ static uint32_t bcd_to_literal(uint32_t bcd);
+ static bool is_number(char value);
+ uint8_t parse_numeric_value(uint8_t cmd_index, uint32_t &value, error_code &err);
+ uint8_t process_command(uint8_t cmd_index, uint32_t value, error_code &err);
+
+ void begin_search(uint32_t value);
+
+ void update_audio_squelch();
+ void update_video_enable();
+
+ // internal state
+ devcb_write_line m_serial_tx;
+ emu_timer * m_vbi_fetch;
+ char m_cmd_buffer[21];
+ uint8_t m_cmd_length;
+ bool m_cmd_running;
+ char m_reply_buffer[64];
+ uint8_t m_reply_write_index;
+ uint8_t m_reply_read_index;
+ bool m_replying;
+
+ uint8_t m_mode; // current player mode
+ uint32_t m_chapter;
+ uint32_t m_time;
+ uint32_t m_frame; // raw frame index (CAV mode)
+ uint32_t m_search_chapter;
+ uint32_t m_search_frame;
+ uint32_t m_mark_chapter;
+ uint32_t m_mark_frame;
+
+ uint8_t m_key_lock;
+ uint8_t m_video_switch;
+ uint8_t m_audio_switch;
+ uint8_t m_display_switch;
+ uint8_t m_address_flag;
+ uint16_t m_speed;
+ uint32_t m_speed_accum;
+ uint8_t m_comm_ctrl;
+ uint8_t m_reg_a;
+ uint8_t m_reg_b;
+ uint8_t m_reg_c;
+ uint8_t m_reg_d;
+ uint8_t m_aux_port;
+ uint32_t m_curr_frame;
+};
+
+#endif // MAME_MACHINE_LDV4200_H
diff --git a/src/devices/machine/ldvp931.cpp b/src/devices/machine/ldvp931.cpp
index 094447391cf..a92a8bed283 100644
--- a/src/devices/machine/ldvp931.cpp
+++ b/src/devices/machine/ldvp931.cpp
@@ -25,9 +25,10 @@
// DEBUGGING
//**************************************************************************
-#define LOG_COMMANDS 0
-#define LOG_PORTS 0
-
+#define LOG_COMMANDS (1U << 1)
+#define LOG_PORTS (1U << 2)
+#define VERBOSE (0)
+#include "logmacro.h"
//**************************************************************************
@@ -80,7 +81,11 @@ ROM_END
philips_22vp931_device::philips_22vp931_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: laserdisc_device(mconfig, PHILIPS_22VP931, tag, owner, clock),
m_i8049_cpu(*this, "vp931"),
- m_tracktimer(nullptr),
+ m_process_vbi_timer(nullptr),
+ m_irq_off_timer(nullptr),
+ m_strobe_off_timer(nullptr),
+ m_erp_off_timer(nullptr),
+ m_track_timer(nullptr),
m_i8049_out0(0),
m_i8049_out1(0),
m_i8049_port1(0),
@@ -130,7 +135,7 @@ uint8_t philips_22vp931_device::data_r()
}
// also boost interleave for 4 scanlines to ensure proper communications
- machine().scheduler().boost_interleave(attotime::zero, screen().scan_period() * 4);
+ machine().scheduler().perfect_quantum(screen().scan_period() * 4);
return m_tocontroller;
}
@@ -144,8 +149,13 @@ void philips_22vp931_device::device_start()
// pass through to the parent
laserdisc_device::device_start();
- // allocate a timer
- m_tracktimer = timer_alloc(TID_HALF_TRACK);
+ // allocate timers
+ m_initial_vbi_timer = timer_alloc(FUNC(philips_22vp931_device::process_vbi_data), this);
+ m_process_vbi_timer = timer_alloc(FUNC(philips_22vp931_device::process_vbi_data), this);
+ m_irq_off_timer = timer_alloc(FUNC(philips_22vp931_device::irq_off), this);
+ m_strobe_off_timer = timer_alloc(FUNC(philips_22vp931_device::data_strobe_off), this);
+ m_erp_off_timer = timer_alloc(FUNC(philips_22vp931_device::erp_off), this);
+ m_track_timer = timer_alloc(FUNC(philips_22vp931_device::half_track_tick), this);
}
@@ -181,92 +191,110 @@ void philips_22vp931_device::device_reset()
//-------------------------------------------------
-// device_timer - handle timers set by this
-// device
+// process_vbi_data - process VBI data which was
+// fetched by the parent device
//-------------------------------------------------
-void philips_22vp931_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(philips_22vp931_device::process_vbi_data)
{
- switch (id)
+ uint32_t line = param >> 2;
+ int which = param & 3;
+ uint32_t code = 0;
+
+ // fetch the code and compute the DATIC latched value
+ if (line >= LASERDISC_CODE_LINE16 && line <= LASERDISC_CODE_LINE18)
+ code = get_field_code(laserdisc_field_code(line), false);
+
+ // at the start of each line, signal an interrupt and use a timer to turn it off
+ if (which == 0)
{
- case TID_VBI_DATA_FETCH:
- {
- uint32_t line = param >> 2;
- int which = param & 3;
- uint32_t code = 0;
-
- // fetch the code and compute the DATIC latched value
- if (line >= LASERDISC_CODE_LINE16 && line <= LASERDISC_CODE_LINE18)
- code = get_field_code(laserdisc_field_code(line), false);
-
- // at the start of each line, signal an interrupt and use a timer to turn it off
- if (which == 0)
- {
- m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, ASSERT_LINE);
- timer_set(attotime::from_nsec(5580), TID_IRQ_OFF);
- }
-
- // clock the data strobe on each subsequent callback
- else if (code != 0)
- {
- m_daticval = code >> (8 * (3 - which));
- m_datastrobe = 1;
- timer_set(attotime::from_nsec(5000), TID_DATA_STROBE_OFF);
- }
-
- // determine the next bit to fetch and reprime ourself
- if (++which == 4)
- {
- which = 0;
- line++;
- }
- if (line <= LASERDISC_CODE_LINE18 + 1)
- timer_set(screen().time_until_pos(line*2, which * 2 * screen().width() / 4), TID_VBI_DATA_FETCH, (line << 2) + which);
- break;
- }
+ m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, ASSERT_LINE);
+ m_irq_off_timer->adjust(attotime::from_nsec(5580));
+ }
+
+ // clock the data strobe on each subsequent callback
+ else if (code != 0)
+ {
+ m_daticval = code >> (8 * (3 - which));
+ m_datastrobe = 1;
+ m_strobe_off_timer->adjust(attotime::from_nsec(5000));
+ }
+
+ // determine the next bit to fetch and reprime ourself
+ if (++which == 4)
+ {
+ which = 0;
+ line++;
+ }
+ if (line <= LASERDISC_CODE_LINE18 + 1)
+ m_process_vbi_timer->adjust(screen().time_until_pos(line*2, which * 2 * screen().width() / 4), (line << 2) + which);
+}
+
- case TID_DEFERRED_DATA:
- // set the value and mark it pending
- if (LOG_COMMANDS && m_fromcontroller_pending)
- printf("Dropped previous command byte\n");
- m_fromcontroller = param;
- m_fromcontroller_pending = true;
-
- // track the commands for debugging purposes
- if (m_cmdcount < ARRAY_LENGTH(m_cmdbuf))
- {
- m_cmdbuf[m_cmdcount++ % 3] = param;
- if (LOG_COMMANDS && m_cmdcount % 3 == 0)
- printf("Cmd: %02X %02X %02X\n", m_cmdbuf[0], m_cmdbuf[1], m_cmdbuf[2]);
- }
- break;
-
- case TID_IRQ_OFF:
- m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE);
- break;
-
- case TID_DATA_STROBE_OFF:
- m_datastrobe = 0;
- break;
-
- case TID_ERP_OFF:
- m_daticerp = 0;
- break;
-
- case TID_HALF_TRACK:
- // advance by the count and toggle the state
- m_trackstate ^= 1;
- if ((m_trackdir < 0 && !m_trackstate) || (m_trackdir > 0 && m_trackstate))
- {
- advance_slider(m_trackdir);
- m_advanced += m_trackdir;
- }
- break;
-
- // pass everything else onto the parent
- default:
- laserdisc_device::device_timer(timer, id, param, ptr);
- break;
+//-------------------------------------------------
+// process_deferred_data -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(philips_22vp931_device::process_deferred_data)
+{
+ // set the value and mark it pending
+ if (m_fromcontroller_pending)
+ LOGMASKED(LOG_COMMANDS, "Dropped previous command byte\n");
+ m_fromcontroller = param;
+ m_fromcontroller_pending = true;
+
+ // track the commands for debugging purposes
+ if (m_cmdcount < std::size(m_cmdbuf))
+ {
+ m_cmdbuf[m_cmdcount++ % 3] = param;
+ if (m_cmdcount % 3 == 0)
+ LOGMASKED(LOG_COMMANDS, "Cmd: %02X %02X %02X\n", m_cmdbuf[0], m_cmdbuf[1], m_cmdbuf[2]);
+ }
+}
+
+
+//-------------------------------------------------
+// irq_off -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(philips_22vp931_device::irq_off)
+{
+ m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// data_strobe_off -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(philips_22vp931_device::data_strobe_off)
+{
+ m_datastrobe = 0;
+}
+
+
+//-------------------------------------------------
+// erp_off -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(philips_22vp931_device::erp_off)
+{
+ m_daticerp = 0;
+}
+
+
+//-------------------------------------------------
+// half_track_tick - advance the slider by the
+// current count and toggle the track state
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(philips_22vp931_device::half_track_tick)
+{
+ m_trackstate ^= 1;
+ if ((m_trackdir < 0 && !m_trackstate) || (m_trackdir > 0 && m_trackstate))
+ {
+ advance_slider(m_trackdir);
+ m_advanced += m_trackdir;
}
}
@@ -311,7 +339,7 @@ void philips_22vp931_device::player_vsync(const vbi_metadata &vbi, int fieldnum,
// set the ERP signal to 1 to indicate start of frame, and set a timer to turn it off
m_daticerp = 1;
- timer_set(screen().time_until_pos(15*2), TID_ERP_OFF);
+ m_erp_off_timer->adjust(screen().time_until_pos(15*2));
}
@@ -322,8 +350,9 @@ void philips_22vp931_device::player_vsync(const vbi_metadata &vbi, int fieldnum,
int32_t philips_22vp931_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime)
{
- // set the first VBI timer to go at the start of line 16
- timer_set(screen().time_until_pos(16*2), TID_VBI_DATA_FETCH, LASERDISC_CODE_LINE16 << 2);
+ // player_update is invoked by the parent device at line 16, so call our VBI processing timer directly
+ m_initial_vbi_timer->adjust(screen().time_until_pos(16*2), LASERDISC_CODE_LINE16 << 2);
+ //process_vbi_data(LASERDISC_CODE_LINE16 << 2);
// play forward by default
return fieldnum;
@@ -348,7 +377,7 @@ void philips_22vp931_device::i8049_output0_w(uint8_t data)
$01 = inverted -> VIDEO MUTE
*/
- if (LOG_PORTS && (m_i8049_out0 ^ data) & 0xff)
+ if ((VERBOSE & LOG_PORTS) && (m_i8049_out0 ^ data) & 0xff)
{
std::string flags;
if ( (data & 0x80)) flags += " ???";
@@ -389,7 +418,7 @@ void philips_22vp931_device::i8049_output1_w(uint8_t data)
int32_t speed;
- if (LOG_PORTS && (m_i8049_out1 ^ data) & 0x08)
+ if ((VERBOSE & LOG_PORTS) && (m_i8049_out1 ^ data) & 0x08)
{
std::string flags;
if (!(data & 0x08)) flags += " SMS";
@@ -500,7 +529,7 @@ void philips_22vp931_device::i8049_to_controller_w(uint8_t data)
m_data_ready(*this, true);
// also boost interleave for 4 scanlines to ensure proper communications
- machine().scheduler().boost_interleave(attotime::zero, screen().scan_period() * 4);
+ machine().scheduler().perfect_quantum(screen().scan_period() * 4);
}
@@ -537,7 +566,7 @@ void philips_22vp931_device::i8049_port1_w(uint8_t data)
$01 = P10 = (out) D100 -> some op-amp then to C334, B56, B332
*/
- if (LOG_PORTS && (m_i8049_port1 ^ data) & 0x1f)
+ if ((VERBOSE & LOG_PORTS) && (m_i8049_port1 ^ data) & 0x1f)
{
std::string flags;
if (!(data & 0x10)) flags += " SPEED";
@@ -572,22 +601,18 @@ void philips_22vp931_device::i8049_port1_w(uint8_t data)
}
}
- // if we have a timer, adjust it
- if (m_tracktimer != nullptr)
- {
- // turn it off if we're not tracking
- if (m_trackdir == 0)
- m_tracktimer->reset();
+ // turn off the track timer if we're not tracking
+ if (m_trackdir == 0)
+ m_track_timer->reset();
- // if we just started tracking, or if the speed was changed, reprime the timer
- else if (((m_i8049_port1 ^ data) & 0x11) != 0)
- {
- // speeds here are just guesses, but work with the player logic; this is the time per half-track
- attotime speed = (data & 0x10) ? attotime::from_usec(60) : attotime::from_usec(10);
+ // if we just started tracking, or if the speed was changed, reprime the timer
+ else if (((m_i8049_port1 ^ data) & 0x11) != 0)
+ {
+ // speeds here are just guesses, but work with the player logic; this is the time per half-track
+ attotime speed = (data & 0x10) ? attotime::from_usec(60) : attotime::from_usec(10);
- // always start with an initial long delay; the code expects this
- m_tracktimer->adjust(attotime::from_usec(100), 0, speed);
- }
+ // always start with an initial long delay; the code expects this
+ m_track_timer->adjust(attotime::from_usec(100), 0, speed);
}
m_i8049_port1 = data;
diff --git a/src/devices/machine/ldvp931.h b/src/devices/machine/ldvp931.h
index c492f0cb699..cffc81cc9dc 100644
--- a/src/devices/machine/ldvp931.h
+++ b/src/devices/machine/ldvp931.h
@@ -43,7 +43,7 @@ public:
philips_22vp931_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// input and output
- void data_w(uint8_t data) { synchronize(TID_DEFERRED_DATA, data); }
+ void data_w(uint8_t data) { machine().scheduler().synchronize(timer_expired_delegate(FUNC(philips_22vp931_device::process_deferred_data), this), data); }
void reset_w(uint8_t data);
uint8_t data_r();
uint8_t ready_r() { return m_fromcontroller_pending ? CLEAR_LINE : ASSERT_LINE; }
@@ -53,21 +53,9 @@ public:
void set_data_ready_callback(data_ready_delegate callback) { m_data_ready = callback; }
protected:
- // timer IDs
- enum
- {
- TID_IRQ_OFF = TID_FIRST_PLAYER_TIMER,
- TID_DATA_STROBE_OFF,
- TID_ERP_OFF,
- TID_HALF_TRACK,
- TID_VBI_DATA_FETCH,
- TID_DEFERRED_DATA
- };
-
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
@@ -76,6 +64,13 @@ protected:
virtual int32_t player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) override;
virtual void player_overlay(bitmap_yuy16 &bitmap) override { }
+ TIMER_CALLBACK_MEMBER(process_vbi_data);
+ TIMER_CALLBACK_MEMBER(process_deferred_data);
+ TIMER_CALLBACK_MEMBER(irq_off);
+ TIMER_CALLBACK_MEMBER(data_strobe_off);
+ TIMER_CALLBACK_MEMBER(erp_off);
+ TIMER_CALLBACK_MEMBER(half_track_tick);
+
private:
// internal read/write handlers
void i8049_output0_w(uint8_t data);
@@ -96,9 +91,14 @@ private:
void vp931_portmap(address_map &map);
// internal state
- required_device<i8049_device> m_i8049_cpu; // CPU index of the 8049
- emu_timer * m_tracktimer; // timer device
- data_ready_delegate m_data_ready; // data ready callback
+ required_device<i8049_device> m_i8049_cpu; // CPU index of the 8049
+ emu_timer * m_initial_vbi_timer;
+ emu_timer * m_process_vbi_timer;
+ emu_timer * m_irq_off_timer;
+ emu_timer * m_strobe_off_timer;
+ emu_timer * m_erp_off_timer;
+ emu_timer * m_track_timer; // half-track timer device
+ data_ready_delegate m_data_ready; // data ready callback
// I/O port states
uint8_t m_i8049_out0; // output 0 state
@@ -111,11 +111,11 @@ private:
uint8_t m_datastrobe; // DATA STROBE line from DATIC
// communication status
- //uint8_t m_reset_state; // state of the reset input
+ //uint8_t m_reset_state; // state of the reset input
uint8_t m_fromcontroller; // command byte from the controller
- bool m_fromcontroller_pending; // true if data is pending
+ bool m_fromcontroller_pending; // true if data is pending
uint8_t m_tocontroller; // command byte to the controller
- bool m_tocontroller_pending; // true if data is pending
+ bool m_tocontroller_pending; // true if data is pending
// tracking
int8_t m_trackdir; // direction of tracking
diff --git a/src/devices/machine/legscsi.cpp b/src/devices/machine/legscsi.cpp
index c379c797f73..58853716aad 100644
--- a/src/devices/machine/legscsi.cpp
+++ b/src/devices/machine/legscsi.cpp
@@ -116,13 +116,7 @@ uint8_t legacy_scsi_host_adapter::get_status()
scsihle_device *scsidev = get_device(m_selected);
if (scsidev != nullptr)
{
- void *image;
-
- scsidev->GetDevice(&image);
- if (image != nullptr)
- return 0x00;
-
- return 0x02;
+ return scsidev->exists() ? 0x00 : 0x02;
}
else
{
diff --git a/src/devices/machine/lh5810.cpp b/src/devices/machine/lh5810.cpp
index 054a532dff0..8b2602cef8b 100644
--- a/src/devices/machine/lh5810.cpp
+++ b/src/devices/machine/lh5810.cpp
@@ -50,9 +50,9 @@ DEFINE_DEVICE_TYPE(LH5810, lh5810_device, "lh5810", "LH5810 I/O Port")
lh5810_device::lh5810_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, LH5810, tag, owner, clock)
- , m_porta_r_cb(*this)
+ , m_porta_r_cb(*this, 0)
, m_porta_w_cb(*this)
- , m_portb_r_cb(*this)
+ , m_portb_r_cb(*this, 0)
, m_portb_w_cb(*this)
, m_portc_w_cb(*this)
, m_out_int_cb(*this)
@@ -67,14 +67,6 @@ lh5810_device::lh5810_device(const machine_config &mconfig, const char *tag, dev
void lh5810_device::device_start()
{
- // resolve callbacks
- m_porta_r_cb.resolve_safe(0);
- m_porta_w_cb.resolve_safe();
- m_portb_r_cb.resolve_safe(0);
- m_portb_w_cb.resolve_safe();
- m_portc_w_cb.resolve_safe();
- m_out_int_cb.resolve_safe();
-
// register for state saving
save_item(NAME(m_irq));
save_item(NAME(m_reg));
diff --git a/src/devices/machine/linflash.cpp b/src/devices/machine/linflash.cpp
index 25b5257dd0b..dcb87a685ba 100644
--- a/src/devices/machine/linflash.cpp
+++ b/src/devices/machine/linflash.cpp
@@ -21,6 +21,11 @@ void linear_flash_pccard_device::device_start()
m_space = &space(0);
}
+void linear_flash_pccard_device::device_reset()
+{
+ m_slot->card_detect_w(1);
+}
+
device_memory_interface::space_config_vector linear_flash_pccard_device::memory_space_config() const
{
return space_config_vector{ std::make_pair(0, &m_space_config) };
diff --git a/src/devices/machine/linflash.h b/src/devices/machine/linflash.h
index 20f4559e98d..5cc489af25f 100644
--- a/src/devices/machine/linflash.h
+++ b/src/devices/machine/linflash.h
@@ -21,6 +21,7 @@ protected:
// device-level overrides
virtual void device_start() override;
+ virtual void device_reset() override;
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
diff --git a/src/devices/machine/locomo.cpp b/src/devices/machine/locomo.cpp
new file mode 100644
index 00000000000..e3da2e35d56
--- /dev/null
+++ b/src/devices/machine/locomo.cpp
@@ -0,0 +1,376 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Sharp LoCoMo peripheral chip emulation skeleton
+
+***************************************************************************/
+
+#include "emu.h"
+#include "locomo.h"
+
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_READS (1U << 2)
+#define LOG_WRITES (1U << 3)
+#define LOG_ALL (LOG_UNKNOWN | LOG_READS | LOG_WRITES)
+
+#define VERBOSE (LOG_ALL)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(LOCOMO, locomo_device, "locomo", "Sharp LoCoMo Peripheral")
+
+locomo_device::locomo_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, LOCOMO, tag, owner, clock)
+{
+}
+
+void locomo_device::device_start()
+{
+ save_item(NAME(m_kbd_cmd));
+ save_item(NAME(m_kbd_row));
+ save_item(NAME(m_kbd_col));
+ save_item(NAME(m_kbd_level));
+}
+
+void locomo_device::device_reset()
+{
+ m_kbd_cmd = 0;
+ m_kbd_row = 0;
+ m_kbd_col = 0;
+ m_kbd_level = 0;
+}
+
+uint32_t locomo_device::read(offs_t offset, uint32_t mem_mask)
+{
+ switch (offset)
+ {
+ case 0x00/4:
+ LOGMASKED(LOG_READS, "%s: read: Version Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x04/4:
+ LOGMASKED(LOG_READS, "%s: read: Pin Status Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x08/4:
+ LOGMASKED(LOG_READS, "%s: read: C32K(?) Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x0c/4:
+ LOGMASKED(LOG_READS, "%s: read: Interrupt Control Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x10/4:
+ LOGMASKED(LOG_READS, "%s: read: Memory Chip Select 0 Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x14/4:
+ LOGMASKED(LOG_READS, "%s: read: Memory Chip Select 1 Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x18/4:
+ LOGMASKED(LOG_READS, "%s: read: Memory Chip Select 2 Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x1c/4:
+ LOGMASKED(LOG_READS, "%s: read: Memory Chip Select 3 Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x20/4:
+ LOGMASKED(LOG_READS, "%s: read: A/D Start Delay Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x24/4:
+ LOGMASKED(LOG_READS, "%s: read: HSYS Delay Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x28/4:
+ LOGMASKED(LOG_READS, "%s: read: HSYS Period Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x30/4:
+ LOGMASKED(LOG_READS, "%s: read: Tablet ADC Clock Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x38/4:
+ LOGMASKED(LOG_READS, "%s: read: TFT Backlight Control Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x3c/4:
+ LOGMASKED(LOG_READS, "%s: read: TFT CPS Delay Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x40/4:
+ LOGMASKED(LOG_READS, "%s: read: Keyboard Level Register: %08x & %08x\n", machine().describe_context(), m_kbd_level, mem_mask);
+ return m_kbd_level;
+ case 0x44/4:
+ LOGMASKED(LOG_READS, "%s: read: Keyboard Strobe Control Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x48/4:
+ LOGMASKED(LOG_READS, "%s: read: Keyboard Strobe Command Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x4c/4:
+ LOGMASKED(LOG_READS, "%s: read: Keyboard Interrupt Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x54/4:
+ LOGMASKED(LOG_READS, "%s: read: Audio Clock Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x60/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Mode Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x64/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Control Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x68/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Status Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x70/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Interrupt Status Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x74/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Interrupt Status Write-Enable Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x78/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Interrupt Enable Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x7c/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Interrupt Request Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x80/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Transmit Data Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x84/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Receive Data Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x88/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Transmit Shift Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x8c/4:
+ LOGMASKED(LOG_READS, "%s: read: SPI Receive Shift Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x90/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Direction Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x94/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Input Enable Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x98/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Level Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0x9c/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Output Latch Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xa0/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Rising-Edge Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xa4/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Falling-Edge Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xa8/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Edge-Detect Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xac/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Status Write-Enable Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xb0/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Interrupt Enable Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xb4/4:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Interrupt Status Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xc8/4:
+ LOGMASKED(LOG_READS, "%s: read: Front Light Cycle Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xcc/4:
+ LOGMASKED(LOG_READS, "%s: read: Front Light Duty Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xd8/4:
+ LOGMASKED(LOG_READS, "%s: read: Long-Time Clock Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xdc/4:
+ LOGMASKED(LOG_READS, "%s: read: Long-Time Clock Interrupt Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xe0/4:
+ LOGMASKED(LOG_READS, "%s: read: DAC Control Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xe8/4:
+ LOGMASKED(LOG_READS, "%s: read: LED 0 Control Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ case 0xec/4:
+ LOGMASKED(LOG_READS, "%s: read: LED 1 Control Register: %08x & %08x\n", machine().describe_context(), 0, mem_mask);
+ return 0;
+ default:
+ LOGMASKED(LOG_READS | LOG_UNKNOWN, "%s: read: Unknown Register: %08x & %08x\n", machine().describe_context(), offset << 2, mem_mask);
+ return 0;
+ }
+}
+
+void locomo_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ switch (offset)
+ {
+ case 0x00/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Version Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x04/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Pin Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x08/4:
+ LOGMASKED(LOG_WRITES, "%s: write: C32K(?) Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x0c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Interrupt Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x10/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Memory Chip Select 0 Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x14/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Memory Chip Select 1 Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x18/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Memory Chip Select 2 Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x1c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Memory Chip Select 3 Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x20/4:
+ LOGMASKED(LOG_WRITES, "%s: write: A/D Start Delay Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x24/4:
+ LOGMASKED(LOG_WRITES, "%s: write: HSYS Delay Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x28/4:
+ LOGMASKED(LOG_WRITES, "%s: write: HSYS Period Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x30/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Tablet ADC Clock Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x38/4:
+ LOGMASKED(LOG_WRITES, "%s: write: TFT Backlight Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x3c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: TFT CPS Delay Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x40/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Keyboard Level Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x44/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Keyboard Strobe Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ if (m_kbd_cmd == 1)
+ {
+ if (m_kbd_row == 0)
+ {
+ m_kbd_row = (uint16_t)data;
+ }
+ else if (m_kbd_col == 0)
+ {
+ m_kbd_col = (uint16_t)data;
+ if (m_kbd_col == 0xffff)
+ {
+ m_kbd_cmd = 0;
+ m_kbd_level = 0;
+ }
+ else
+ {
+ // HACK: Something about this value causes the Zaurus updater to begin booting.
+ // TODO: Work out the proper keyboard matrix.
+ m_kbd_level = 0xffff;
+ }
+ m_kbd_row = 0;
+ m_kbd_col = 0;
+ }
+ }
+ break;
+ case 0x48/4:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: Keyboard Strobe Command Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const uint16_t old = m_kbd_cmd;
+ m_kbd_cmd = (uint16_t)data;
+ if (old == 0)
+ {
+ m_kbd_row = 0;
+ m_kbd_col = 0;
+ }
+ break;
+ }
+ case 0x4c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Keyboard Interrupt Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x54/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Audio Clock Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x60/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Mode Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x64/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x68/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x70/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Interrupt Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x74/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Interrupt Status Write-Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x78/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Interrupt Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x7c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Interrupt Request Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x80/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Transmit Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x84/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Receive Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x88/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Transmit Shift Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x8c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: SPI Receive Shift Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x90/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Direction Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x94/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Input Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x98/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Level Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0x9c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Output Latch Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xa0/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Rising-Edge Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xa4/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Falling-Edge Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xa8/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Edge-Detect Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xac/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Status Write-Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xb0/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Interrupt Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xb4/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Interrupt Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xc8/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Front Light Cycle Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xcc/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Front Light Duty Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xd8/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Long-Time Clock Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xdc/4:
+ LOGMASKED(LOG_WRITES, "%s: write: Long-Time Clock Interrupt Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xe0/4:
+ LOGMASKED(LOG_WRITES, "%s: write: DAC Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xe8/4:
+ LOGMASKED(LOG_WRITES, "%s: write: LED 0 Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ case 0xec/4:
+ LOGMASKED(LOG_WRITES, "%s: write: LED 1 Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ break;
+ default:
+ LOGMASKED(LOG_WRITES | LOG_UNKNOWN, "%s: write: Unknown Register: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+ break;
+ }
+}
diff --git a/src/devices/machine/locomo.h b/src/devices/machine/locomo.h
new file mode 100644
index 00000000000..ac240959d9f
--- /dev/null
+++ b/src/devices/machine/locomo.h
@@ -0,0 +1,34 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Sharp LoCoMo peripheral chip emulation skeleton
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_LOCOMO
+#define MAME_MACHINE_LOCOMO
+
+#pragma once
+
+class locomo_device : public device_t
+{
+public:
+ locomo_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ uint32_t read(offs_t offset, uint32_t mem_mask = ~0U);
+ void write(offs_t offset, uint32_t data, uint32_t mem_mask = ~0U);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ uint16_t m_kbd_cmd;
+ uint16_t m_kbd_row;
+ uint16_t m_kbd_col;
+ uint16_t m_kbd_level;
+};
+
+DECLARE_DEVICE_TYPE(LOCOMO, locomo_device)
+
+#endif // MAME_MACHINE_LOCOMO
diff --git a/src/devices/machine/lpci.cpp b/src/devices/machine/lpci.cpp
index 8c2fd6393e0..5f378108020 100644
--- a/src/devices/machine/lpci.cpp
+++ b/src/devices/machine/lpci.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Olivier Galibert
/***************************************************************************
- machine/lpci.c
+ machine/lpci.cpp
Legacy PCI bus
@@ -72,7 +72,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/lpci.h"
+#include "lpci.h"
//#define VERBOSE 1
#include "logmacro.h"
@@ -95,7 +95,7 @@ pci_bus_legacy_device::pci_bus_legacy_device(const machine_config &mconfig, cons
device_t(mconfig, PCI_BUS_LEGACY, tag, owner, clock),
m_read_callback(*this),
m_write_callback(*this),
- m_father(nullptr),
+ m_father(*this, finder_base::DUMMY_TAG),
m_siblings_count(0)
{
std::fill(std::begin(m_siblings), std::end(m_siblings), nullptr);
@@ -262,11 +262,8 @@ void pci_bus_legacy_device::device_start()
m_read_callback.resolve_all();
m_write_callback.resolve_all();
- if (m_father) {
- pci_bus_legacy_device *father = machine().device<pci_bus_legacy_device>(m_father);
- if (father)
- father->add_sibling(this, m_busnum);
- }
+ if (m_father.found())
+ m_father->add_sibling(this, m_busnum);
/* register pci states */
save_item(NAME(m_address));
diff --git a/src/devices/machine/lpci.h b/src/devices/machine/lpci.h
index 4b98054bb8d..fb289d5538f 100644
--- a/src/devices/machine/lpci.h
+++ b/src/devices/machine/lpci.h
@@ -40,7 +40,8 @@ public:
void write_64be(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
void set_busnum(int busnum) { m_busnum = busnum; }
- void set_father(const char *father) { m_father = father; }
+ template <typename T>
+ void set_father(T &&tag) { m_father.set_tag(std::forward<T>(tag)); }
template <typename F, typename G>
void set_device(int num, F &&read, const char *rname, G &&write, const char *wname)
@@ -69,7 +70,7 @@ private:
uint8_t m_busnum;
pci_bus_legacy_read_delegate::array<32> m_read_callback;
pci_bus_legacy_write_delegate::array<32> m_write_callback;
- const char * m_father;
+ optional_device<pci_bus_legacy_device> m_father;
pci_bus_legacy_device * m_siblings[8];
uint8_t m_siblings_busnum[8];
int m_siblings_count;
diff --git a/src/devices/machine/m3002.cpp b/src/devices/machine/m3002.cpp
index fd93666a55f..8c9fe20db05 100644
--- a/src/devices/machine/m3002.cpp
+++ b/src/devices/machine/m3002.cpp
@@ -65,25 +65,13 @@ m3000_device::m3000_device(const machine_config &mconfig, const char *tag, devic
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void m3002_device::device_resolve_objects()
-{
- m_irq_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void m3002_device::device_start()
{
// Setup timer
- m_second_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m3002_device::second_timer), this));
+ m_second_timer = timer_alloc(FUNC(m3002_device::second_timer), this);
// Save internal state
save_item(NAME(m_ram));
@@ -110,9 +98,10 @@ void m3002_device::device_clock_changed()
// nvram_read - read NVRAM from the file
//-------------------------------------------------
-void m3002_device::nvram_read(emu_file &file)
+bool m3002_device::nvram_read(util::read_stream &file)
{
- file.read(&m_ram[0], 0x10);
+ auto const [err, actual] = util::read(file, &m_ram[0], 0x10);
+ return !err && (actual == 0x10);
}
@@ -120,9 +109,10 @@ void m3002_device::nvram_read(emu_file &file)
// nvram_write - write NVRAM to the file
//-------------------------------------------------
-void m3002_device::nvram_write(emu_file &file)
+bool m3002_device::nvram_write(util::write_stream &file)
{
- file.write(&m_ram[0], 0x10);
+ auto const [err, actual] = util::write(file, &m_ram[0], 0x10);
+ return !err;
}
@@ -220,7 +210,7 @@ void m3002_device::bcd_increment(u8 location)
u8 m3002_device::max_date() const
{
if (m_ram[4] == 0x02)
- return (m_ram[5] & 0x03) == 0x00 ? 0x29 : 0x28;
+ return (m_ram[5] & 0x03) == ((m_ram[5] & 0x10) >> 3) ? 0x29 : 0x28;
else
return BIT(0x20250, m_ram[4]) ? 0x30 : 0x31;
}
diff --git a/src/devices/machine/m3002.h b/src/devices/machine/m3002.h
index ef13c360e47..8f34e5aaa49 100644
--- a/src/devices/machine/m3002.h
+++ b/src/devices/machine/m3002.h
@@ -44,23 +44,22 @@ public:
void write(u8 data);
// status output polling
- DECLARE_READ_LINE_MEMBER(busy_r) { return internal_busy() ? 0 : 1; }
- DECLARE_READ_LINE_MEMBER(irq_r) { return m_irq_active ? 0 : 1; }
+ int busy_r() { return internal_busy() ? 0 : 1; }
+ int irq_r() { return m_irq_active ? 0 : 1; }
protected:
m3002_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_clock_changed() override;
- // device_nvram_interface overrides
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ // device_nvram_interface implementation
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
virtual void nvram_default() override;
- // device_rtc_interface overrides
+ // device_rtc_interface implementation
virtual bool rtc_feature_y2k() const override { return false; }
virtual bool rtc_feature_leap_year() const override { return true; }
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
diff --git a/src/devices/machine/m68sfdc.cpp b/src/devices/machine/m68sfdc.cpp
index 1f9b37acf4c..f235f25bfd5 100644
--- a/src/devices/machine/m68sfdc.cpp
+++ b/src/devices/machine/m68sfdc.cpp
@@ -64,17 +64,11 @@ ioport_constructor m68sfdc_device::device_input_ports() const
return INPUT_PORTS_NAME(m68sfdc);
}
-void m68sfdc_device::device_resolve_objects()
-{
-}
-
void m68sfdc_device::device_start()
{
- m_irq_handler.resolve_safe();
- m_nmi_handler.resolve_safe();
+ m_timer_head_load = timer_alloc(FUNC(m68sfdc_device::head_load_update), this);
+ m_timer_timeout = timer_alloc(FUNC(m68sfdc_device::timeout_expired), this);
- m_timer_head_load = timer_alloc(TM_HEAD_LOAD);
- m_timer_timeout = timer_alloc(TM_TIMEOUT);
save_item(NAME(m_select_0));
save_item(NAME(m_select_1));
save_item(NAME(m_select_2));
@@ -86,7 +80,6 @@ void m68sfdc_device::device_start()
save_item(NAME(m_head_load));
save_item(NAME(m_crc));
save_item(NAME(m_last_crc));
- save_item(NAME(m_pia_ca1));
save_item(NAME(m_pia_cb2));
save_item(NAME(m_reset));
save_item(NAME(m_enable_drive_write));
@@ -98,7 +91,7 @@ void m68sfdc_device::device_start()
m_floppy = nullptr;
- t_gen = timer_alloc(TM_GEN);
+ t_gen = timer_alloc(FUNC(m68sfdc_device::general_update), this);
}
void m68sfdc_device::device_reset()
@@ -114,7 +107,6 @@ void m68sfdc_device::device_reset()
m_head_load = 0;
m_crc = 0;
m_last_crc = 0;
- m_pia_ca1 = 0;
m_pia_cb2 = 0;
m_reset = 1;
m_enable_drive_write = 0;
@@ -140,48 +132,40 @@ void m68sfdc_device::set_floppies_4(floppy_connector *f0, floppy_connector *f1,
}
}
-WRITE_LINE_MEMBER(m68sfdc_device::handle_irq)
+void m68sfdc_device::handle_irq(int state)
{
m_irq_handler(state);
}
-WRITE_LINE_MEMBER(m68sfdc_device::handle_nmi)
+void m68sfdc_device::handle_nmi(int state)
{
m_nmi_handler(state);
}
-void m68sfdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(m68sfdc_device::head_load_update)
{
- switch (id)
- {
- case TM_HEAD_LOAD:
- {
- live_sync();
- m_head_load2 = 0;
- u8 head_load = m_head_load1 && m_head_load2;
- if (head_load != m_head_load)
- {
- // TODO sound?
- m_head_load = head_load;
- }
- break;
- }
- case TM_TIMEOUT:
+ live_sync();
+ m_head_load2 = 0;
+ u8 head_load = m_head_load1 && m_head_load2;
+ if (head_load != m_head_load)
{
- live_sync();
- m_pia->ca1_w(0);
- m_pia_ca1 = 0;
- break;
- }
- case TM_GEN:
- live_sync();
- live_run();
- break;
- default:
- throw emu_fatalerror("Unknown id in m68sfdc_device::device_timer");
+ // TODO sound?
+ m_head_load = head_load;
}
}
+TIMER_CALLBACK_MEMBER(m68sfdc_device::timeout_expired)
+{
+ live_sync();
+ m_pia->ca1_w(0);
+}
+
+TIMER_CALLBACK_MEMBER(m68sfdc_device::general_update)
+{
+ live_sync();
+ live_run();
+}
+
uint8_t m68sfdc_device::flip_bits(uint8_t data)
@@ -386,11 +370,6 @@ void m68sfdc_device::pia_pa_w(u8 data)
}
}
-int m68sfdc_device::pia_ca1_r()
-{
- return m_pia_ca1;
-}
-
void m68sfdc_device::pia_ca2_w(int state)
{
if (m_floppy)
@@ -493,7 +472,6 @@ void m68sfdc_device::pia_cb2_w(int state)
{
// Trigger the timeout timer on a high to low transition of CB2
m_pia->ca1_w(1);
- m_pia_ca1 = 1;
m_timer_timeout->reset(attotime::from_msec(800));
}
m_pia_cb2 = state;
@@ -851,10 +829,10 @@ bool m68sfdc_device::pll_write_next_bit(bool bit, attotime &tm, floppy_image_dev
void m68sfdc_device::device_add_mconfig(machine_config &config)
{
- PIA6821(config, m_pia, 0);
+ PIA6821(config, m_pia);
m_pia->readpa_handler().set(FUNC(m68sfdc_device::pia_pa_r));
m_pia->writepa_handler().set(FUNC(m68sfdc_device::pia_pa_w));
- m_pia->readca1_handler().set(FUNC(m68sfdc_device::pia_ca1_r));
+ m_pia->ca1_w(0);
m_pia->ca2_handler().set(FUNC(m68sfdc_device::pia_ca2_w));
m_pia->readpb_handler().set(FUNC(m68sfdc_device::pia_pb_r));
m_pia->writepb_handler().set(FUNC(m68sfdc_device::pia_pb_w));
diff --git a/src/devices/machine/m68sfdc.h b/src/devices/machine/m68sfdc.h
index aa7dfcb00ee..a545c987af1 100644
--- a/src/devices/machine/m68sfdc.h
+++ b/src/devices/machine/m68sfdc.h
@@ -30,6 +30,11 @@ public:
void set_floppies_4(floppy_connector*, floppy_connector*, floppy_connector*, floppy_connector*);
private:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+
required_device<pia6821_device> m_pia;
required_device<mc6852_device> m_ssda;
emu_timer *m_timer_head_load;
@@ -37,13 +42,13 @@ private:
devcb_write_line m_irq_handler;
devcb_write_line m_nmi_handler;
- DECLARE_WRITE_LINE_MEMBER(handle_irq);
- DECLARE_WRITE_LINE_MEMBER(handle_nmi);
+
+ void handle_irq(int state);
+ void handle_nmi(int state);
uint8_t flip_bits(uint8_t data);
uint8_t pia_pa_r();
void pia_pa_w(u8 data);
- int pia_ca1_r();
void pia_ca2_w(int state);
uint8_t pia_pb_r();
void pia_pb_w(u8 data);
@@ -60,7 +65,6 @@ private:
u8 m_head_load;
u8 m_crc;
u8 m_last_crc;
- u8 m_pia_ca1;
u8 m_pia_cb2;
u8 m_reset;
u8 m_enable_drive_write;
@@ -81,16 +85,12 @@ private:
floppy_connector *m_floppy0, *m_floppy1, *m_floppy2, *m_floppy3;
floppy_image_device *m_floppy; // Currently selected floppy.
- virtual void device_resolve_objects() override;
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void device_add_mconfig(machine_config &config) override;
- virtual ioport_constructor device_input_ports() const override;
-
- enum { TM_HEAD_LOAD, TM_TIMEOUT, TM_GEN };
+ TIMER_CALLBACK_MEMBER(head_load_update);
+ TIMER_CALLBACK_MEMBER(timeout_expired);
+ TIMER_CALLBACK_MEMBER(general_update);
- enum {
+ enum
+ {
// General "doing nothing" state
IDLE,
@@ -105,7 +105,8 @@ private:
WRITE_BITS,
};
- struct live_info {
+ struct live_info
+ {
enum { PT_NONE, PT_CRC_1, PT_CRC_2 };
attotime tm;
diff --git a/src/devices/machine/m6m80011ap.cpp b/src/devices/machine/m6m80011ap.cpp
index 79d7073c331..92d13fe5de5 100644
--- a/src/devices/machine/m6m80011ap.cpp
+++ b/src/devices/machine/m6m80011ap.cpp
@@ -2,8 +2,7 @@
// copyright-holders:Angelo Salese
#include "emu.h"
-#include "machine/m6m80011ap.h"
-
+#include "m6m80011ap.h"
//**************************************************************************
@@ -76,9 +75,10 @@ void m6m80011ap_device::nvram_default()
// .nv file
//-------------------------------------------------
-void m6m80011ap_device::nvram_read(emu_file &file)
+bool m6m80011ap_device::nvram_read(util::read_stream &file)
{
- file.read(m_eeprom_data, 0x100);
+ auto const [err, actual] = read(file, m_eeprom_data, 0x100);
+ return !err && (actual == 0x100);
}
@@ -87,9 +87,10 @@ void m6m80011ap_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void m6m80011ap_device::nvram_write(emu_file &file)
+bool m6m80011ap_device::nvram_write(util::write_stream &file)
{
- file.write(m_eeprom_data, 0x100);
+ auto const [err, actual] = write(file, m_eeprom_data, 0x100);
+ return !err;
}
//**************************************************************************
@@ -97,17 +98,17 @@ void m6m80011ap_device::nvram_write(emu_file &file)
//**************************************************************************
-READ_LINE_MEMBER( m6m80011ap_device::read_bit )
+int m6m80011ap_device::read_bit()
{
return m_read_latch;
}
-READ_LINE_MEMBER( m6m80011ap_device::ready_line )
+int m6m80011ap_device::ready_line()
{
return 1; // TODO
}
-WRITE_LINE_MEMBER( m6m80011ap_device::set_cs_line )
+void m6m80011ap_device::set_cs_line(int state)
{
m_reset_line = state;
@@ -120,12 +121,12 @@ WRITE_LINE_MEMBER( m6m80011ap_device::set_cs_line )
}
-WRITE_LINE_MEMBER( m6m80011ap_device::write_bit )
+void m6m80011ap_device::write_bit(int state)
{
m_latch = state;
}
-WRITE_LINE_MEMBER( m6m80011ap_device::set_clock_line )
+void m6m80011ap_device::set_clock_line(int state)
{
if (m_reset_line == CLEAR_LINE)
{
diff --git a/src/devices/machine/m6m80011ap.h b/src/devices/machine/m6m80011ap.h
index 01ccfe2f31a..0e628c2662c 100644
--- a/src/devices/machine/m6m80011ap.h
+++ b/src/devices/machine/m6m80011ap.h
@@ -13,11 +13,11 @@ public:
m6m80011ap_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 32'768); /* TODO: frequency */
// I/O operations
- DECLARE_READ_LINE_MEMBER( read_bit );
- DECLARE_READ_LINE_MEMBER( ready_line );
- DECLARE_WRITE_LINE_MEMBER( set_cs_line );
- DECLARE_WRITE_LINE_MEMBER( set_clock_line );
- DECLARE_WRITE_LINE_MEMBER( write_bit );
+ int read_bit();
+ int ready_line();
+ void set_cs_line(int state);
+ void set_clock_line(int state);
+ void write_bit(int state);
protected:
// device-level overrides
@@ -26,8 +26,8 @@ protected:
virtual void device_reset() override;
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
enum eeprom_cmd_t
diff --git a/src/devices/machine/m950x0.cpp b/src/devices/machine/m950x0.cpp
new file mode 100644
index 00000000000..9d42166804c
--- /dev/null
+++ b/src/devices/machine/m950x0.cpp
@@ -0,0 +1,207 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ m950x0.cpp
+
+ STmicro M95010/20/40 SPI-bus EEPROM
+
+ Common characteristics:
+ - 16-byte page size
+ - Write protection selectable in quarter, half, or full sizes
+
+ Part variants with a -DF designation have additional support for an
+ identification page, which is not currently emulated.
+
+ Sizes:
+ M95010 - 1kbit
+ M95020 - 2kbit
+ M95040 - 4kbit, slightly altered instructions for 9th address bit
+
+ Current issues:
+ - Implementation currently operates in a parallel manner, rather than
+ serial.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "m950x0.h"
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(M95010, m95010_device, "m95010", "STmicro M95010 1kbit SPI EEPROM")
+DEFINE_DEVICE_TYPE(M95020, m95020_device, "m95020", "STmicro M95020 2kbit SPI EEPROM")
+DEFINE_DEVICE_TYPE(M95040, m95040_device, "m95040", "STmicro M95040 4kbit SPI EEPROM")
+
+m950x0_device::m950x0_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int capacity)
+ : eeprom_base_device(mconfig, type, tag, owner)
+ , m_check_a8(capacity > 0x100)
+ , m_addr_mask((uint16_t)capacity - 1)
+ , m_state(STATE_IDLE)
+{
+ size(capacity, 8);
+}
+
+m95010_device::m95010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : m950x0_device(mconfig, M95010, tag, owner, 0x80)
+{
+}
+
+m95020_device::m95020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : m950x0_device(mconfig, M95020, tag, owner, 0x100)
+{
+}
+
+m95040_device::m95040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : m950x0_device(mconfig, M95040, tag, owner, 0x200)
+{
+}
+
+void m950x0_device::device_start()
+{
+ eeprom_base_device::device_start();
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_selected));
+ save_item(NAME(m_status));
+ save_item(NAME(m_addr));
+}
+
+void m950x0_device::device_reset()
+{
+ eeprom_base_device::device_reset();
+
+ m_state = STATE_IDLE;
+ m_selected = false;
+ m_status = 0xf0;
+ m_addr = 0;
+}
+
+uint8_t m950x0_device::access(uint8_t data)
+{
+ if (!m_selected)
+ return 0;
+
+ uint8_t response = 0;
+
+ switch (m_state)
+ {
+ case STATE_IDLE:
+ process_instruction(data);
+ break;
+
+ case STATE_RDSR:
+ response = m_status;
+ m_state = STATE_IDLE;
+ LOG("Status Register read, value: %02x\n", response);
+ break;
+
+ case STATE_WRSR:
+ m_status &= 0xf0;
+ m_status |= data & 0x0f;
+ m_state = STATE_IDLE;
+ LOG("Status Register write, new value: %02x\n", m_status);
+ break;
+
+ case STATE_READ_ADDR:
+ m_addr |= data;
+ m_state = STATE_READ_DATA;
+ LOG("Read command, starting address: %03x, entering read-data state\n", m_addr);
+ break;
+
+ case STATE_WRITE_ADDR:
+ m_addr |= data;
+ m_state = STATE_WRITE_DATA;
+ LOG("Write command, starting address: %03x, entering write-data state\n", m_addr);
+ break;
+
+ case STATE_READ_DATA:
+ response = (uint8_t)internal_read(m_addr);
+ LOG("Read command, data: %02x, at address %03x\n", response, m_addr);
+ m_addr++;
+ m_addr &= m_addr_mask;
+ break;
+
+ case STATE_WRITE_DATA:
+ internal_write(m_addr, data);
+ LOG("Write command, data: %02x to address %03x\n", data, m_addr);
+ m_addr++;
+ m_addr &= m_addr_mask;
+ break;
+ }
+
+ return response;
+}
+
+void m950x0_device::process_instruction(const uint8_t insn)
+{
+ switch (insn)
+ {
+ case INSN_WREN0:
+ case INSN_WREN1:
+ LOG("Instruction: Write enable\n");
+ m_status |= (1 << STATUS_WEL_BIT);
+ break;
+
+ case INSN_WRDI0:
+ case INSN_WRDI1:
+ LOG("Instruction: Write disable\n");
+ m_status &= ~(1 << STATUS_WEL_BIT);
+ break;
+
+ case INSN_RDSR0:
+ case INSN_RDSR1:
+ LOG("Instruction: Read status register\n");
+ m_state = STATE_RDSR;
+ break;
+
+ case INSN_WRSR0:
+ case INSN_WRSR1:
+ LOG("Instruction: Write status register\n");
+ m_state = STATE_WRSR;
+ break;
+
+ case INSN_READ0:
+ LOG("Instruction: Read, A8=0\n");
+ m_state = STATE_READ_ADDR;
+ break;
+ case INSN_READ1:
+ LOG("Instruction: Read, A8=1\n");
+ m_state = STATE_READ_ADDR;
+ if (m_check_a8)
+ m_addr |= 0x100;
+ break;
+
+ case INSN_WRITE0:
+ LOG("Instruction: Write, A8=0\n");
+ m_state = STATE_WRITE_ADDR;
+ break;
+ case INSN_WRITE1:
+ LOG("Instruction: Write, A8=1\n");
+ m_state = STATE_WRITE_ADDR;
+ if (m_check_a8)
+ m_addr |= 0x100;
+ break;
+
+ default:
+ LOG("Unrecognized instruction byte: %02x, deselecting\n", insn);
+ m_selected = false;
+ break;
+ }
+}
+
+void m950x0_device::select_w(int selected)
+{
+ if (m_selected == (bool)selected)
+ return;
+
+ m_selected = (bool)selected;
+
+ if (!selected)
+ {
+ LOG("Deselected, resetting address to 0 and entering idle state.\n");
+ m_state = STATE_IDLE;
+ m_addr = 0;
+ }
+}
diff --git a/src/devices/machine/m950x0.h b/src/devices/machine/m950x0.h
new file mode 100644
index 00000000000..0eceb6fab21
--- /dev/null
+++ b/src/devices/machine/m950x0.h
@@ -0,0 +1,97 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ m950x0.h
+
+ STmicro M95010/20/40 SPI-bus EEPROM
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_M950X0_H
+#define MAME_MACHINE_M950X0_H
+
+#pragma once
+
+#include "machine/eeprom.h"
+
+class m950x0_device : public eeprom_base_device
+{
+public:
+ uint8_t access(uint8_t data);
+ void select_w(int selected);
+
+protected:
+ m950x0_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int capacity);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void process_instruction(const uint8_t insn);
+
+ enum : uint32_t
+ {
+ STATE_IDLE,
+
+ // Status-register accesses expect two sequential bytes (instruction + status)
+ STATE_RDSR,
+ STATE_WRSR,
+
+ // Reads and writes expect a minimum of 3 bytes (instruction + address + data)
+ STATE_READ_ADDR,
+ STATE_READ_DATA,
+ STATE_WRITE_ADDR,
+ STATE_WRITE_DATA
+ };
+
+ enum : uint8_t
+ {
+ INSN_WRSR0 = 0x01,
+ INSN_WRITE0 = 0x02,
+ INSN_READ0 = 0x03,
+ INSN_WRDI0 = 0x04,
+ INSN_RDSR0 = 0x05,
+ INSN_WREN0 = 0x06,
+
+ INSN_WRSR1 = 0x09,
+ INSN_WRITE1 = 0x0a,
+ INSN_READ1 = 0x0b,
+ INSN_WRDI1 = 0x0c,
+ INSN_RDSR1 = 0x0d,
+ INSN_WREN1 = 0x0e,
+
+ STATUS_WEL_BIT = 1
+ };
+
+ const bool m_check_a8;
+ const uint16_t m_addr_mask;
+
+ uint32_t m_state;
+ bool m_selected;
+ uint8_t m_status;
+ uint16_t m_addr;
+};
+
+class m95010_device : public m950x0_device
+{
+public:
+ m95010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class m95020_device : public m950x0_device
+{
+public:
+ m95020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class m95040_device : public m950x0_device
+{
+public:
+ m95040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+DECLARE_DEVICE_TYPE(M95010, m95010_device)
+DECLARE_DEVICE_TYPE(M95020, m95020_device)
+DECLARE_DEVICE_TYPE(M95040, m95040_device)
+
+#endif // MAME_MACHINE_M950X0_H
diff --git a/src/devices/machine/mb14241.cpp b/src/devices/machine/mb14241.cpp
index c9d08eb503e..4e087ade8a3 100644
--- a/src/devices/machine/mb14241.cpp
+++ b/src/devices/machine/mb14241.cpp
@@ -7,7 +7,7 @@
****************************************************************************/
#include "emu.h"
-#include "machine/mb14241.h"
+#include "mb14241.h"
//-------------------------------------------------
diff --git a/src/devices/machine/mb3773.cpp b/src/devices/machine/mb3773.cpp
index 948fdd7a75e..50ea4ed4e39 100644
--- a/src/devices/machine/mb3773.cpp
+++ b/src/devices/machine/mb3773.cpp
@@ -41,7 +41,7 @@ mb3773_device::mb3773_device( const machine_config &mconfig, const char *tag, de
void mb3773_device::device_start()
{
- m_watchdog_timer = timer_alloc();
+ m_watchdog_timer = timer_alloc(FUNC(mb3773_device::watchdog_expired), this);
save_item( NAME(m_ck) );
}
@@ -56,7 +56,7 @@ void mb3773_device::device_reset()
reset_timer();
}
-void mb3773_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mb3773_device::watchdog_expired)
{
logerror("Reset caused by watchdog\n");
@@ -72,7 +72,7 @@ void mb3773_device::reset_timer()
m_watchdog_timer->adjust( attotime::from_seconds( 5 ) );
}
-WRITE_LINE_MEMBER( mb3773_device::write_line_ck )
+void mb3773_device::write_line_ck(int state)
{
if( state == 0 && m_ck != 0 )
{
diff --git a/src/devices/machine/mb3773.h b/src/devices/machine/mb3773.h
index e6f8bf4c955..fd25d83e599 100644
--- a/src/devices/machine/mb3773.h
+++ b/src/devices/machine/mb3773.h
@@ -20,14 +20,14 @@ public:
mb3773_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
// I/O operations
- WRITE_LINE_MEMBER( write_line_ck );
+ void write_line_ck(int state);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ TIMER_CALLBACK_MEMBER(watchdog_expired);
private:
void reset_timer();
diff --git a/src/devices/machine/mb8421.cpp b/src/devices/machine/mb8421.cpp
index 53a19a70be8..62eb69c035d 100644
--- a/src/devices/machine/mb8421.cpp
+++ b/src/devices/machine/mb8421.cpp
@@ -18,7 +18,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/mb8421.h"
+#include "mb8421.h"
template class dual_port_mailbox_ram_base<u8, 10, 8>;
template class dual_port_mailbox_ram_base<u8, 11, 8>;
diff --git a/src/devices/machine/mb8421.h b/src/devices/machine/mb8421.h
index f112f1e1484..6415a053667 100644
--- a/src/devices/machine/mb8421.h
+++ b/src/devices/machine/mb8421.h
@@ -147,7 +147,8 @@ public:
return m_ram[offset];
}
- DECLARE_READ_LINE_MEMBER(busy_r) { return 0; } // _BUSY pin - not emulated
+ int left_busy_r() { return 0; } // _BUSY pin - not emulated
+ int right_busy_r() { return 0; } // "
protected:
dual_port_mailbox_ram_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
@@ -158,20 +159,7 @@ protected:
{
}
- // device-level overrides
-
- //-------------------------------------------------
- // device_resolve_objects - resolve objects that
- // may be needed for other devices to set
- // initial conditions at start time
- //-------------------------------------------------
-
- virtual void device_resolve_objects() override
- {
- // resolve callbacks
- m_intl_callback.resolve_safe();
- m_intr_callback.resolve_safe();
- }
+ // device_t implementation
//-------------------------------------------------
// device_start - device-specific startup
@@ -179,7 +167,7 @@ protected:
virtual void device_start() override
{
- m_ram = make_unique_clear<Type[]>(RAM_SIZE);
+ m_ram = make_unique_clear<Type []>(RAM_SIZE);
// state save
save_pointer(NAME(m_ram), RAM_SIZE);
diff --git a/src/devices/machine/mb87030.cpp b/src/devices/machine/mb87030.cpp
index a9c87cfc11b..ad60af82e42 100644
--- a/src/devices/machine/mb87030.cpp
+++ b/src/devices/machine/mb87030.cpp
@@ -1,6 +1,12 @@
// license:BSD-3-Clause
// copyright-holders:Sven Schnelle
+/*
+ * The MB89351 and MB89352 are both based on the MB87030, with the main
+ * programmer-visible difference being an interrupt-driven option for the
+ * program transfer mode.
+*/
+
#include "emu.h"
#include "mb87030.h"
@@ -9,10 +15,24 @@
DEFINE_DEVICE_TYPE(MB87030, mb87030_device, "mb87030", "Fujitsu MB87030 SCSI controller")
+DEFINE_DEVICE_TYPE(MB89351, mb89351_device, "mb89351", "Fujitsu MB89351 SCSI controller")
+DEFINE_DEVICE_TYPE(MB89352, mb89352_device, "mb89352", "Fujitsu MB89352 SCSI controller")
+
+ALLOW_SAVE_TYPE(mb87030_device::State)
mb87030_device::mb87030_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
mb87030_device(mconfig, MB87030, tag, owner, clock)
{
+}
+
+mb89351_device::mb89351_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ mb87030_device(mconfig, MB89351, tag, owner, clock)
+{
+}
+
+mb89352_device::mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ mb87030_device(mconfig, MB89352, tag, owner, clock)
+{
}
@@ -20,7 +40,8 @@ mb87030_device::mb87030_device(const machine_config &mconfig, device_type type,
nscsi_device(mconfig, type, tag, owner, clock),
nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF),
m_irq_handler(*this),
- m_dreq_handler(*this)
+ m_dreq_handler(*this),
+ m_irq_state(false)
{
}
@@ -45,6 +66,46 @@ void mb87030_device::map(address_map &map)
map(0x0f, 0x0f).rw(FUNC(mb87030_device::exbf_r), FUNC(mb87030_device::exbf_w));
}
+void mb89351_device::map(address_map &map)
+{
+ map(0x00, 0x00).rw(FUNC(mb89351_device::bdid_r), FUNC(mb89351_device::bdid_w));
+ map(0x01, 0x01).rw(FUNC(mb89351_device::sctl_r), FUNC(mb89351_device::sctl_w));
+ map(0x02, 0x02).rw(FUNC(mb89351_device::scmd_r), FUNC(mb89351_device::scmd_w));
+ // no TMOD
+ map(0x04, 0x04).rw(FUNC(mb89351_device::ints_r), FUNC(mb89351_device::ints_w));
+ map(0x05, 0x05).rw(FUNC(mb89351_device::psns_r), FUNC(mb89351_device::sdgc_w));
+ map(0x06, 0x06).r(FUNC(mb89351_device::ssts_r));
+ map(0x07, 0x07).r(FUNC(mb89351_device::serr_r));
+ map(0x08, 0x08).rw(FUNC(mb89351_device::pctl_r), FUNC(mb89351_device::pctl_w));
+ map(0x09, 0x09).r(FUNC(mb89351_device::mbc_r));
+ map(0x0a, 0x0a).rw(FUNC(mb89351_device::dreg_r), FUNC(mb89351_device::dreg_w));
+ map(0x0b, 0x0b).rw(FUNC(mb89351_device::temp_r), FUNC(mb89351_device::temp_w));
+ map(0x0c, 0x0c).rw(FUNC(mb89351_device::tch_r), FUNC(mb89351_device::tch_w));
+ map(0x0d, 0x0d).rw(FUNC(mb89351_device::tcm_r), FUNC(mb89351_device::tcm_w));
+ map(0x0e, 0x0e).rw(FUNC(mb89351_device::tcl_r), FUNC(mb89351_device::tcl_w));
+ // no EXBF
+}
+
+void mb89352_device::map(address_map &map)
+{
+ map(0x00, 0x00).rw(FUNC(mb89352_device::bdid_r), FUNC(mb89352_device::bdid_w));
+ map(0x01, 0x01).rw(FUNC(mb89352_device::sctl_r), FUNC(mb89352_device::sctl_w));
+ map(0x02, 0x02).rw(FUNC(mb89352_device::scmd_r), FUNC(mb89352_device::scmd_w));
+ // no TMOD
+ map(0x04, 0x04).rw(FUNC(mb89352_device::ints_r), FUNC(mb89352_device::ints_w));
+ map(0x05, 0x05).rw(FUNC(mb89352_device::psns_r), FUNC(mb89352_device::sdgc_w));
+ map(0x06, 0x06).r(FUNC(mb89352_device::ssts_r));
+ map(0x07, 0x07).r(FUNC(mb89352_device::serr_r));
+ map(0x08, 0x08).rw(FUNC(mb89352_device::pctl_r), FUNC(mb89352_device::pctl_w));
+ map(0x09, 0x09).r(FUNC(mb89352_device::mbc_r));
+ map(0x0a, 0x0a).rw(FUNC(mb89352_device::dreg_r), FUNC(mb89352_device::dreg_w));
+ map(0x0b, 0x0b).rw(FUNC(mb89352_device::temp_r), FUNC(mb89352_device::temp_w));
+ map(0x0c, 0x0c).rw(FUNC(mb89352_device::tch_r), FUNC(mb89352_device::tch_w));
+ map(0x0d, 0x0d).rw(FUNC(mb89352_device::tcm_r), FUNC(mb89352_device::tcm_w));
+ map(0x0e, 0x0e).rw(FUNC(mb89352_device::tcl_r), FUNC(mb89352_device::tcl_w));
+ // no EXBF
+}
+
void mb87030_device::device_reset()
{
m_bdid = 0;
@@ -64,6 +125,7 @@ void mb87030_device::device_reset()
m_tc = 0;
m_exbf = 0;
m_fifo.clear();
+ m_dreq_handler(false);
scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL);
update_state(State::Idle, 0);
scsi_set_ctrl(0, S_ALL);
@@ -85,10 +147,10 @@ auto mb87030_device::get_state_name(State state) const
return "ArbitrationWait";
case State::ArbitrationAssertSEL:
return "ArbitrationAssertSEL";
- case State::ArbitrationDeAssertBSY:
- return "ArbitrationDeAssertBSY";
case State::SelectionWaitBusFree:
return "SelectionWaitBusFree";
+ case State::SelectionAssertID:
+ return "SelectionAssertID";
case State::SelectionWaitBSY:
return "SelectionWaitBSY";
case State::SelectionAssertSEL:
@@ -101,16 +163,8 @@ auto mb87030_device::get_state_name(State state) const
return "TransferSendAck";
case State::TransferSendData:
return "TransferSendData";
- case State::TransferSendDataDMAReq:
- return "TransferSendDataDMAReq";
- case State::TransferSendDataDMAResp:
- return "TransferSendDataDMAResp";
case State::TransferRecvData:
return "TransferRecvData";
- case State::TransferRecvDataDMAReq:
- return "TransferRecvDataDMAReq";
- case State::TransferRecvDataDMAResp:
- return "TransferRecvDataDMAResp";
case State::TransferWaitDeassertREQ:
return "TransferWaitDeassertREQ";
@@ -122,8 +176,8 @@ auto mb87030_device::get_state_name(State state) const
void mb87030_device::update_state(mb87030_device::State new_state, int delay, int timeout)
{
- LOG("new state: %s -> %s (delay %d, timeout %d)\n", get_state_name(m_state),
- get_state_name(new_state), delay, timeout);
+ LOG("new state: %s -> %s (delay %d, timeout %d, %s)\n", get_state_name(m_state),
+ get_state_name(new_state), delay, timeout, machine().time().to_string());
m_state = new_state;
if (delay)
m_delay_timer->adjust(clocks_to_attotime(delay));
@@ -149,21 +203,13 @@ TIMER_CALLBACK_MEMBER(mb87030_device::delay_timeout)
void mb87030_device::scsi_command_complete()
{
+ LOG("%s\n", __FUNCTION__);
m_ints |= INTS_COMMAND_COMPLETE;
m_ssts &= ~(SSTS_SPC_BUSY|SSTS_XFER_IN_PROGRESS);
update_ints();
update_state(State::Idle);
}
-void mb87030_device::scsi_disconnect_timeout()
-{
- scsi_set_ctrl(0, S_ALL);
- scsi_bus->data_w(scsi_refid, 0);
- m_ints = INTS_SPC_TIMEOUT;
- update_ints();
- update_state(State::Idle);
-}
-
void mb87030_device::scsi_disconnect()
{
LOG("%s: m_tc %d\n", __FUNCTION__, m_tc);
@@ -190,7 +236,7 @@ void mb87030_device::scsi_set_ctrl(uint32_t value, uint32_t mask)
}
}
-uint32_t mb87030_device::scsi_get_ctrl(void)
+uint32_t mb87030_device::scsi_get_ctrl()
{
if (m_sctl & SCTL_DIAG_MODE) {
uint32_t ret = 0;
@@ -227,13 +273,15 @@ void mb87030_device::step(bool timeout)
timeout ? " timeout" : "", data,
ctrl, m_tc);
- if (m_sctl & SCTL_RESET_AND_DISABLE && m_state != State::Idle) {
+ if ((m_sctl & SCTL_RESET_AND_DISABLE) && m_state != State::Idle) {
scsi_set_ctrl(0, S_ALL);
+ m_ssts &= ~SSTS_SPC_BUSY;
update_state(State::Idle);
return;
}
- if ((m_ssts & SSTS_INIT_CONNECTED) && !(ctrl & S_BSY)) {
+ // FIXME: bus free and disconnected interrupt logic is not correct
+ if ((m_ssts & SSTS_INIT_CONNECTED) && !(ctrl & S_BSY) && (m_state != State::SelectionAssertID) && (m_state != State::SelectionAssertSEL) && (m_state != State::SelectionWaitBSY)) {
LOG("SCSI disconnect\n");
scsi_disconnect();
scsi_set_ctrl(0, S_ALL);
@@ -250,12 +298,12 @@ void mb87030_device::step(bool timeout)
case State::ArbitrationWaitBusFree:
if (!(ctrl & (S_BSY|S_SEL)))
update_state(State::ArbitrationAssertBSY, 1);
-
break;
+
case State::ArbitrationAssertBSY:
scsi_set_ctrl(S_BSY, S_BSY);
scsi_bus->data_w(scsi_refid, (1 << m_bdid));
- update_state(State::ArbitrationWait, 1);
+ update_state(State::ArbitrationWait, 32);
break;
case State::ArbitrationWait:
@@ -263,7 +311,10 @@ void mb87030_device::step(bool timeout)
LOG("check %d\n", id);
if (data & id) {
LOG("arbitration lost, winner %d\n", id);
- scsi_disconnect_timeout();
+ scsi_set_ctrl(0, S_BSY);
+ scsi_bus->data_w(scsi_refid, 0);
+ m_ssts &= ~SSTS_SPC_BUSY;
+ update_state(State::Idle);
break;
}
}
@@ -273,50 +324,57 @@ void mb87030_device::step(bool timeout)
case State::ArbitrationAssertSEL:
scsi_set_ctrl(S_SEL, S_SEL);
- update_state(State::ArbitrationDeAssertBSY, 1);
- break;
-
- case State::ArbitrationDeAssertBSY:
- scsi_set_ctrl(0, S_BSY);
- update_state(State::SelectionAssertSEL, 1);
+ update_state(State::SelectionAssertID, 10);
break;
case State::SelectionWaitBusFree:
if (!(ctrl & (S_BSY|S_SEL)))
- update_state(State::SelectionAssertSEL, 10);
+ update_state(State::SelectionAssertID, 10);
break;
- case State::SelectionAssertSEL:
+ case State::SelectionAssertID:
+ m_ssts |= SSTS_INIT_CONNECTED;
+ m_ssts &= ~SSTS_TARG_CONNECTED;
scsi_bus->data_w(scsi_refid, m_temp);
- scsi_set_ctrl(0, S_SEL); //XXX: needed?
+ update_state(State::SelectionAssertSEL, 10);
+ break;
+
+ case State::SelectionAssertSEL:
+ // deassert BSY for arbitrating systems, assert SEL for non-arbitrating systems
scsi_set_ctrl(S_SEL | (m_send_atn_during_selection ? S_ATN : 0), S_ATN|S_SEL|S_BSY);
scsi_bus->ctrl_wait(scsi_refid, S_BSY, S_BSY);
- update_state(State::SelectionWaitBSY, 0, m_tc / 8);
+ update_state(State::SelectionWaitBSY, 0, ((m_tc & ~0xff) + 15) * 2);
break;
case State::SelectionWaitBSY:
- if (timeout) {
+ if (timeout || (m_ints & INTS_SPC_TIMEOUT)) {
LOG("select timeout\n");
- scsi_disconnect_timeout();
+ m_tc = 0;
+ m_ints = INTS_SPC_TIMEOUT;
+ update_ints();
break;
}
m_timer->reset();
if ((ctrl & (S_REQ|S_BSY|S_MSG|S_CTL|S_INP)) == S_BSY)
update_state(State::Selection, 1);
-
break;
case State::Selection:
+ // avoid duplicate command completion caused by deassertion of SEL
+ if (!(ctrl & S_SEL))
+ break;
+
LOG("selection success\n");
scsi_set_ctrl(0, S_SEL);
- m_ssts |= SSTS_INIT_CONNECTED|SSTS_XFER_IN_PROGRESS;
- m_ssts &= ~(SSTS_TARG_CONNECTED|SSTS_SPC_BUSY);
- update_ssts();
scsi_command_complete();
break;
case State::TransferWaitReq:
if (!m_tc && !(m_scmd & SCMD_TERM_MODE)) {
+ // transfer command completes only when fifo is empty
+ if (!m_fifo.empty())
+ break;
+
LOG("TransferWaitReq: tc == 0\n");
scsi_bus->data_w(scsi_refid, 0);
scsi_command_complete();
@@ -328,6 +386,7 @@ void mb87030_device::step(bool timeout)
m_ints |= INTS_SERVICE_REQUIRED;
m_ssts &= ~SSTS_SPC_BUSY;
update_ints();
+ update_state(State::Idle);
break;
}
@@ -336,11 +395,10 @@ void mb87030_device::step(bool timeout)
break;
}
- if (!m_dma_transfer || (m_scmd & SCMD_TERM_MODE)) {
- update_state((ctrl & S_INP) ? State::TransferRecvData : State::TransferSendData, 1);
- } else {
- update_state((ctrl & S_INP) ? State::TransferRecvDataDMAReq : State::TransferSendDataDMAReq, 1);
- }
+ if (m_dma_transfer && m_tc && !(ctrl & S_INP) && !m_fifo.full())
+ m_dreq_handler(true);
+
+ update_state((ctrl & S_INP) ? State::TransferRecvData : State::TransferSendData, 1);
break;
case State::TransferRecvData:
@@ -352,53 +410,40 @@ void mb87030_device::step(bool timeout)
if (!m_tc || m_fifo.full())
break;
- m_bus_data = data;
- update_state(State::TransferSendAck, 10);
- break;
+ LOG("pushing read data: %02X (%d filled)\n", data, m_fifo.queue_length() + 1);
+ m_fifo.enqueue(data);
+ if (m_dma_transfer)
+ m_dreq_handler(true);
- case State::TransferRecvDataDMAReq:
- m_hdb = data;
- m_hdb_loaded = true;
- update_state(State::TransferRecvDataDMAResp, 10);
- m_dreq_handler(true);
- break;
+ if (m_sdgc & SDGC_XFER_ENABLE) {
+ m_serr |= SERR_XFER_OUT;
+ update_ints();
+ }
- case State::TransferRecvDataDMAResp:
- if (m_hdb_loaded)
- break;
update_state(State::TransferSendAck, 10);
- m_dreq_handler(false);
break;
case State::TransferSendData:
+ if (m_tc && m_fifo.empty() && (m_sdgc & SDGC_XFER_ENABLE)) {
+ m_serr |= SERR_XFER_OUT;
+ update_ints();
+ break;
+ }
+
if (m_tc && !m_fifo.empty()) {
- scsi_bus->data_w(scsi_refid, m_fifo.peek());
+ LOG("pulling write data: %02X (%d left)\n", data, m_fifo.queue_length() - 1);
+ scsi_bus->data_w(scsi_refid, m_fifo.dequeue());
update_state(State::TransferSendAck, 10);
break;
}
- if (!m_tc && (m_scmd & SCMD_TERM_MODE)) {
+ if (!m_tc && (m_scmd & SCMD_TERM_MODE)) {
scsi_bus->data_w(scsi_refid, m_temp);
update_state(State::TransferSendAck, 10);
break;
}
break;
- case State::TransferSendDataDMAReq:
- m_hdb_loaded = false;
- update_state(State::TransferSendDataDMAResp, 10);
- m_dreq_handler(true);
- break;
-
- case State::TransferSendDataDMAResp:
- if (!m_hdb_loaded)
- break;
- m_hdb_loaded = false;
- m_dreq_handler(false);
- scsi_bus->data_w(scsi_refid, m_hdb);
- update_state(State::TransferSendAck, 10);
- break;
-
case State::TransferSendAck:
if (!(m_scmd & SCMD_TERM_MODE) && !(ctrl & S_INP))
m_temp = data;
@@ -415,17 +460,15 @@ void mb87030_device::step(bool timeout)
case State::TransferDeassertACK:
m_tc--;
- if (!m_dma_transfer) {
- if (!(ctrl & S_INP)) {
- m_fifo.dequeue();
- } else {
- LOG("pushing read data: %02X\n", m_bus_data);
- m_fifo.enqueue(m_bus_data);
- }
- }
update_state(State::TransferWaitReq, 10);
scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
- scsi_set_ctrl(0, S_ACK);
+
+ // deassert ATN after last byte of message out phase
+ if (!m_tc && (ctrl & S_PHASE_MASK) == S_PHASE_MSG_OUT && m_send_atn_during_selection)
+ scsi_set_ctrl(0, S_ATN|S_ACK);
+ // deassert ACK except for last byte of message in phase
+ else if (m_tc || (ctrl & S_PHASE_MASK) != S_PHASE_MSG_IN)
+ scsi_set_ctrl(0, S_ACK);
break;
}
@@ -433,10 +476,8 @@ void mb87030_device::step(bool timeout)
void mb87030_device::device_start()
{
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb87030_device::timeout), this));
- m_delay_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb87030_device::delay_timeout), this));
- m_irq_handler.resolve_safe();
- m_dreq_handler.resolve_safe();
+ m_timer = timer_alloc(FUNC(mb87030_device::timeout), this);
+ m_delay_timer = timer_alloc(FUNC(mb87030_device::delay_timeout), this);
save_item(NAME(m_bdid));
save_item(NAME(m_sctl));
@@ -454,19 +495,18 @@ void mb87030_device::device_start()
save_item(NAME(m_tcm));
save_item(NAME(m_tc));
save_item(NAME(m_exbf));
- save_item(NAME(m_hdb));
- save_item(NAME(m_hdb_loaded));
save_item(NAME(m_send_atn_during_selection));
// save_item(NAME(m_fifo));
save_item(NAME(m_scsi_phase));
save_item(NAME(m_scsi_ctrl));
save_item(NAME(m_dma_transfer));
- save_item(NAME(m_bus_data));
-// save_item(NAME(m_state));
+ save_item(NAME(m_state));
+ save_item(NAME(m_irq_state));
}
void mb87030_device::scsi_ctrl_changed()
{
+ LOG("%s: %02x\n", __FUNCTION__, scsi_bus->ctrl_r());
if (m_delay_timer->remaining() == attotime::never)
step(false);
}
@@ -498,13 +538,18 @@ void mb87030_device::update_ssts()
void mb87030_device::update_ints()
{
- LOG("%s: %s\n", __FUNCTION__, (m_ints && (m_sctl & 1)) ? "true" : "false");
- m_irq_handler(m_ints && (m_sctl & 1));// || (m_ints & INTS_DISCONNECTED));
+ bool const irq_state = (m_sctl & 1) && (m_ints || (m_serr & SERR_XFER_OUT));
+
+ if (irq_state != m_irq_state) {
+ m_irq_state = irq_state;
+ LOG("%s: %s\n", __FUNCTION__, m_irq_state ? "true" : "false");
+ m_irq_handler(m_irq_state);
+ }
}
uint8_t mb87030_device::bdid_r()
{
- LOG("%s %02X\n", __FUNCTION__, (1 << m_bdid));
+ LOG("%s: %02X\n", __FUNCTION__, (1 << m_bdid));
return 1 << m_bdid;
}
@@ -541,10 +586,16 @@ void mb87030_device::scmd_w(uint8_t data)
switch (m_scmd & SCMD_CMD_MASK) {
case SCMD_CMD_BUS_RELEASE:
LOG("%s: Bus release\n", __FUNCTION__);
+ m_send_atn_during_selection = false;
+ if (m_state == State::SelectionWaitBusFree) {
+ m_ssts &= ~(SSTS_INIT_CONNECTED|SSTS_TARG_CONNECTED|SSTS_SPC_BUSY|SSTS_XFER_IN_PROGRESS);
+ update_state(State::Idle);
+ }
break;
case SCMD_CMD_SELECT:
LOG("%s: Select\n", __FUNCTION__);
+ m_ssts |= SSTS_SPC_BUSY;
if (m_sctl & SCTL_ARBITRATION_ENABLE)
update_state(State::ArbitrationWaitBusFree, 10);
else
@@ -574,6 +625,8 @@ void mb87030_device::scmd_w(uint8_t data)
m_dma_transfer = !(data & 0x04);
LOG("%s Transfer\n", m_dma_transfer ? "DMA" : "Program");
+ if (!m_dma_transfer)
+ m_dreq_handler(false);
m_ssts |= SSTS_SPC_BUSY|SSTS_XFER_IN_PROGRESS;
update_state(State::TransferWaitReq, 5);
break;
@@ -623,13 +676,25 @@ void mb87030_device::tmod_w(uint8_t data)
uint8_t mb87030_device::ints_r()
{
- LOG("%s: %02X\n", __FUNCTION__, m_ints);
+ //LOG("%s: %02X\n", __FUNCTION__, m_ints);
return m_ints;
}
void mb87030_device::ints_w(uint8_t data)
{
LOG("%s: %02X\n", __FUNCTION__, data);
+ if (m_state == State::SelectionWaitBSY && (m_ints & data & INTS_SPC_TIMEOUT)) {
+ if (!m_tc) {
+ // terminate selection/reselection
+ m_ssts &= ~(SSTS_INIT_CONNECTED|SSTS_TARG_CONNECTED|SSTS_SPC_BUSY);
+ scsi_set_ctrl(0, S_ALL);
+ scsi_bus->data_w(scsi_refid, 0);
+ update_state(State::Idle);
+ } else {
+ // restart selection/reselection
+ update_state(State::SelectionAssertID, 1);
+ }
+ }
m_ints &= ~(data);
update_ints();
}
@@ -652,13 +717,16 @@ uint8_t mb87030_device::psns_r()
void mb87030_device::sdgc_w(uint8_t data)
{
LOG("%s: %02X\n", __FUNCTION__, data);
+ if (type() == MB87030)
+ data &= ~SDGC_XFER_ENABLE;
m_sdgc = data;
scsi_ctrl_changed();
+ update_ints();
}
uint8_t mb87030_device::ssts_r()
{
- LOG("%s: %02X\n", __FUNCTION__, m_ssts);
+ //LOG("%s: %02X\n", __FUNCTION__, m_ssts);
update_ssts();
return m_ssts;
}
@@ -692,10 +760,20 @@ uint8_t mb87030_device::mbc_r()
uint8_t mb87030_device::dreg_r()
{
- step(false);
+ if (machine().side_effects_disabled())
+ return m_fifo.peek();
+
if (!m_fifo.empty())
- m_dreg = m_fifo.dequeue();
+ m_dreg = m_fifo.dequeue();
LOG("%s: %02X\n", __FUNCTION__, m_dreg);
+
+ if (m_serr & SERR_XFER_OUT) {
+ m_serr &= ~SERR_XFER_OUT;
+ update_ints();
+ }
+
+ step(false);
+
return m_dreg;
}
@@ -705,6 +783,12 @@ void mb87030_device::dreg_w(uint8_t data)
m_dreg = data;
if (!m_fifo.full())
m_fifo.enqueue(data);
+
+ if (m_serr & SERR_XFER_OUT) {
+ m_serr &= ~SERR_XFER_OUT;
+ update_ints();
+ }
+
step(false);
}
@@ -782,22 +866,28 @@ void mb87030_device::exbf_w(uint8_t data)
void mb87030_device::dma_w(uint8_t data)
{
- if (machine().side_effects_disabled())
- return;
- LOG("dma_w: %02X\n", data);
- m_hdb = data;
- m_hdb_loaded = true;
+ LOG("dma_w: %02X (%d entered)\n", data, m_fifo.queue_length() + 1);
+ m_dreg = data;
+ if (!m_fifo.full()) {
+ m_fifo.enqueue(data);
+ if (m_fifo.full())
+ m_dreq_handler(false);
+ }
step(false);
}
-uint8_t mb87030_device::dma_r(void)
+uint8_t mb87030_device::dma_r()
{
- uint8_t val = m_hdb;
-
if (machine().side_effects_disabled())
- return 0;
- LOG("dma_r: %02X\n", val);
- m_hdb_loaded = false;
+ return m_fifo.peek();
+
+ if (!m_fifo.empty()) {
+ m_dreg = m_fifo.dequeue();
+ if (m_fifo.empty())
+ m_dreq_handler(false);
+ }
+
+ LOG("dma_r: %02X (%d left)\n", m_dreg, m_fifo.queue_length());
step(false);
- return val;
+ return m_dreg;
}
diff --git a/src/devices/machine/mb87030.h b/src/devices/machine/mb87030.h
index c4d113107cd..2040ecf1cd2 100644
--- a/src/devices/machine/mb87030.h
+++ b/src/devices/machine/mb87030.h
@@ -56,7 +56,7 @@ public:
void dma_w(uint8_t val);
void ctrl_write(uint32_t value, uint32_t mask) { scsi_bus->ctrl_w(scsi_refid, value, mask); scsi_ctrl_changed(); }
- uint32_t data_read() { return scsi_bus->data_r(); };
+ uint32_t data_read() { return scsi_bus->data_r(); }
protected:
mb87030_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -74,9 +74,9 @@ private:
constexpr static uint8_t SCTL_RESET_AND_DISABLE = 0x80;
constexpr static uint8_t SCMD_TERM_MODE = 0x01;
- constexpr static uint8_t SCMD_PRG_XFER = 0x02;
- constexpr static uint8_t SCMD_INTERCEPT_XFER = 0x04;
- constexpr static uint8_t SCMD_RST_OUT = 0x08;
+ constexpr static uint8_t SCMD_PRG_XFER = 0x04;
+ constexpr static uint8_t SCMD_INTERCEPT_XFER = 0x08;
+ constexpr static uint8_t SCMD_RST_OUT = 0x10;
constexpr static uint8_t SCMD_CMD_BUS_RELEASE = 0x00;
constexpr static uint8_t SCMD_CMD_SELECT = 0x20;
constexpr static uint8_t SCMD_CMD_RESET_ATN = 0x40;
@@ -128,6 +128,7 @@ private:
constexpr static uint8_t SERR_SHORT_PERIOD = 0x02;
constexpr static uint8_t SERR_PHASE_ERROR = 0x04;
constexpr static uint8_t SERR_TC_P_ERROR = 0x08;
+ constexpr static uint8_t SERR_XFER_OUT = 0x20; // MB89351/2 only
constexpr static uint8_t SERR_DATA_ERROR_SPC = 0x40;
constexpr static uint8_t SERR_DATA_ERROR_SCSI = 0x80;
@@ -135,6 +136,7 @@ private:
constexpr static uint8_t SDGC_DIAG_CD = 0x02;
constexpr static uint8_t SDGC_DIAG_MSG = 0x04;
constexpr static uint8_t SDGC_DIAG_BSY = 0x08;
+ constexpr static uint8_t SDGC_XFER_ENABLE = 0x20; // MB89351/2 only
constexpr static uint8_t SDGC_DIAG_ACK = 0x40;
constexpr static uint8_t SDGC_DIAG_REQ = 0x80;
@@ -151,30 +153,25 @@ private:
ArbitrationAssertBSY,
ArbitrationWait,
ArbitrationAssertSEL,
- ArbitrationDeAssertBSY,
SelectionWaitBusFree,
+ SelectionAssertID,
SelectionAssertSEL,
SelectionWaitBSY,
Selection,
TransferWaitReq,
TransferSendData,
- TransferSendDataDMAReq,
- TransferSendDataDMAResp,
TransferRecvData,
- TransferRecvDataDMAReq,
- TransferRecvDataDMAResp,
TransferSendAck,
TransferWaitDeassertREQ,
TransferDeassertACK
//TransferCommand,
} m_state;
- void update_ssts(void);
- void update_ints(void);
+ void update_ssts();
+ void update_ints();
- void scsi_disconnect_timeout(void);
- void scsi_command_complete(void);
- void scsi_disconnect(void);
+ void scsi_command_complete();
+ void scsi_disconnect();
void update_state(mb87030_device::State new_state, int delay = 0, int timeout = 0);
auto get_state_name(State state) const;
void scsi_set_ctrl(uint32_t val, uint32_t mask);
@@ -205,9 +202,6 @@ private:
uint32_t m_tc;
uint8_t m_exbf;
- uint8_t m_bus_data;
- uint8_t m_hdb;
- bool m_hdb_loaded;
bool m_send_atn_during_selection;
util::fifo <uint8_t, 8> m_fifo;
@@ -215,9 +209,27 @@ private:
uint32_t m_scsi_ctrl;
bool m_dma_transfer;
+ bool m_irq_state;
};
+class mb89351_device : public mb87030_device
+{
+public:
+ mb89351_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+};
+
+class mb89352_device : public mb87030_device
+{
+public:
+ mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+};
DECLARE_DEVICE_TYPE(MB87030, mb87030_device)
+DECLARE_DEVICE_TYPE(MB89351, mb89351_device)
+DECLARE_DEVICE_TYPE(MB89352, mb89352_device)
#endif // MAME_MACHINE_MB87030_H
diff --git a/src/devices/machine/mb87078.cpp b/src/devices/machine/mb87078.cpp
index eed6f53297a..b32207ccd51 100644
--- a/src/devices/machine/mb87078.cpp
+++ b/src/devices/machine/mb87078.cpp
@@ -70,7 +70,7 @@
*****************************************************************************/
#include "emu.h"
-#include "machine/mb87078.h"
+#include "mb87078.h"
/*****************************************************************************
@@ -91,8 +91,6 @@ mb87078_device::mb87078_device(const machine_config &mconfig, const char *tag, d
void mb87078_device::device_start()
{
- m_gain_changed_cb.resolve_safe();
-
m_data = 0;
m_control = 0;
diff --git a/src/devices/machine/mb8795.cpp b/src/devices/machine/mb8795.cpp
index 4f6d08d9aca..7d619a18d90 100644
--- a/src/devices/machine/mb8795.cpp
+++ b/src/devices/machine/mb8795.cpp
@@ -38,22 +38,17 @@ void mb8795_device::check_irq()
bool old_irq_rx = irq_rx;
irq_tx = txstat & txmask;
irq_rx = rxstat & rxmask;
- if(irq_tx != old_irq_tx && !irq_tx_cb.isnull())
+ if(irq_tx != old_irq_tx)
irq_tx_cb(irq_tx);
- if(irq_rx != old_irq_rx && !irq_rx_cb.isnull())
+ if(irq_rx != old_irq_rx)
irq_rx_cb(irq_rx);
}
void mb8795_device::device_start()
{
- irq_tx_cb.resolve();
- irq_rx_cb.resolve();
- drq_tx_cb.resolve();
- drq_rx_cb.resolve();
-
memset(mac, 0, 6);
- timer_tx = timer_alloc(TIMER_TX);
- timer_rx = timer_alloc(TIMER_RX);
+ timer_tx = timer_alloc(FUNC(mb8795_device::tx_update), this);
+ timer_rx = timer_alloc(FUNC(mb8795_device::rx_update), this);
}
void mb8795_device::device_reset()
@@ -185,7 +180,7 @@ void mb8795_device::mac_w(offs_t offset, uint8_t data)
{
if(offset < 6) {
mac[offset] = data;
- set_mac((const char *)mac);
+ set_mac(mac);
}
}
@@ -203,8 +198,7 @@ void mb8795_device::tx_dma_w(uint8_t data, bool eof)
}
drq_tx = false;
- if(!drq_tx_cb.isnull())
- drq_tx_cb(drq_tx);
+ drq_tx_cb(drq_tx);
if(eof) {
logerror("send packet, dest=%02x.%02x.%02x.%02x.%02x.%02x len=%04x loopback=%s\n",
@@ -232,8 +226,7 @@ void mb8795_device::tx_dma_w(uint8_t data, bool eof)
void mb8795_device::rx_dma_r(uint8_t &data, bool &eof)
{
drq_rx = false;
- if(!drq_rx_cb.isnull())
- drq_rx_cb(drq_rx);
+ drq_rx_cb(drq_rx);
if(rxlen) {
data = rxbuf[0];
@@ -323,17 +316,16 @@ 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)
+TIMER_CALLBACK_MEMBER(mb8795_device::tx_update)
{
- if(id == TIMER_TX) {
- drq_tx = true;
- if(!drq_tx_cb.isnull())
- drq_tx_cb(drq_tx);
- }
+ drq_tx = true;
+ drq_tx_cb(drq_tx);
+}
- if(id == TIMER_RX && rxlen) {
+TIMER_CALLBACK_MEMBER(mb8795_device::rx_update)
+{
+ if(rxlen) {
drq_rx = true;
- if(!drq_rx_cb.isnull())
- drq_rx_cb(drq_rx);
+ drq_rx_cb(drq_rx);
}
}
diff --git a/src/devices/machine/mb8795.h b/src/devices/machine/mb8795.h
index 1298a6295cc..57daf378f66 100644
--- a/src/devices/machine/mb8795.h
+++ b/src/devices/machine/mb8795.h
@@ -3,6 +3,8 @@
#ifndef MAME_MACHINE_MB8795_H
#define MAME_MACHINE_MB8795_H
+#include "dinetwork.h"
+
class mb8795_device : public device_t,
public device_network_interface
{
@@ -22,10 +24,12 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void recv_cb(uint8_t *buf, int len) override;
+ TIMER_CALLBACK_MEMBER(tx_update);
+ TIMER_CALLBACK_MEMBER(rx_update);
+
private:
enum { TIMER_TX, TIMER_RX };
diff --git a/src/devices/machine/mb89352.cpp b/src/devices/machine/mb89352.cpp
deleted file mode 100644
index 62b9adb78bb..00000000000
--- a/src/devices/machine/mb89352.cpp
+++ /dev/null
@@ -1,671 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Barry Rodewald
-/*
- * 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)
- * Also used in Sega's Soreike Kokology 1/2 (drives CD-ROM)
- *
- * 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 "mb89352.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
-
-
-/*
- * Device config
- */
-
-DEFINE_DEVICE_TYPE(MB89352A, mb89352_device, "mb89352", "Fujitsu MB89352A")
-
-
-/*
- * Device
- */
-
-mb89352_device::mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- legacy_scsi_host_adapter(mconfig, MB89352A, tag, owner, clock),
- m_irq_cb(*this),
- m_drq_cb(*this)
-{
-}
-
-void mb89352_device::device_start()
-{
- legacy_scsi_host_adapter::device_start();
-
- m_phase = SCSI_PHASE_BUS_FREE;
- m_target = 0;
- m_command_index = 0;
- m_line_status = 0x00;
- m_spc_status = 0x01; // presumably the data reg is empty to start with
- m_error_status = 0x00;
- m_transfer_count = 0;
- if(m_transfer_count == 0)
- m_spc_status |= SSTS_TC_ZERO;
- m_ints = 0x00;
-
- m_irq_cb.resolve_safe();
- m_drq_cb.resolve_safe();
-
- // allocate read timer
- m_transfer_timer = timer_alloc(TIMER_TRANSFER);
-}
-
-void mb89352_device::device_reset()
-{
- m_phase = SCSI_PHASE_BUS_FREE;
- m_target = 0;
- m_command_index = 0;
- m_line_status = 0x00;
- m_error_status = 0x00;
- m_transfer_count = 0;
- m_spc_status = 0x05; // presumably the data reg is empty to start with
- m_busfree_int_enable = 0;
-}
-
-void mb89352_device::device_stop()
-{
-}
-
-// get the length of a SCSI command based on it's command byte type
-int mb89352_device::get_scsi_cmd_len(uint8_t cbyte)
-{
- int group;
-
- group = (cbyte>>5) & 7;
-
- if (group == 0) return 6;
- if (group == 1 || group == 2) return 10;
- if (group == 5) return 12;
-
- fatalerror("MB89352: Unknown SCSI command group %d\n", group);
-
- // never executed
- //return 6;
-}
-
-void mb89352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch(id)
- {
- case TIMER_TRANSFER:
- // TODO: check interrupts are actually enabled
- {
- m_drq_cb(1);
- }
- break;
- }
-}
-
-void mb89352_device::set_phase(int phase)
-{
- m_phase = phase;
- switch(phase)
- {
- case SCSI_PHASE_BUS_FREE:
- m_line_status = 0;
- m_spc_status &= ~SSTS_XFER_IN_PROGRESS;
- break;
- case SCSI_PHASE_COMMAND:
- m_line_status |= MB89352_LINE_REQ;
- m_line_status &= ~MB89352_LINE_ACK;
- m_line_status &= ~MB89352_LINE_MSG;
- m_line_status |= MB89352_LINE_CD;
- m_line_status &= ~MB89352_LINE_IO;
- break;
- case SCSI_PHASE_STATUS:
-// m_line_status |= MB89352_LINE_REQ;
-// m_line_status &= ~MB89352_LINE_ACK;
- m_line_status &= ~MB89352_LINE_MSG;
- m_line_status |= MB89352_LINE_CD;
- m_line_status |= MB89352_LINE_IO;
- break;
- case SCSI_PHASE_DATAIN:
-// m_line_status |= MB89352_LINE_REQ;
-// m_line_status &= ~MB89352_LINE_ACK;
- m_line_status &= ~MB89352_LINE_MSG;
- m_line_status &= ~MB89352_LINE_CD;
- m_line_status |= MB89352_LINE_IO;
- break;
- case SCSI_PHASE_DATAOUT:
-// m_line_status |= MB89352_LINE_REQ;
-// m_line_status &= ~MB89352_LINE_ACK;
- m_line_status &= ~MB89352_LINE_MSG;
- m_line_status &= ~MB89352_LINE_CD;
- m_line_status &= ~MB89352_LINE_IO;
- break;
- case SCSI_PHASE_MESSAGE_IN:
-// m_line_status |= MB89352_LINE_REQ;
-// m_line_status &= ~MB89352_LINE_ACK;
- m_line_status |= MB89352_LINE_MSG;
- m_line_status |= MB89352_LINE_CD;
- m_line_status |= MB89352_LINE_IO;
- break;
- case SCSI_PHASE_MESSAGE_OUT:
-// m_line_status |= MB89352_LINE_REQ;
-// m_line_status &= ~MB89352_LINE_ACK;
- m_line_status |= MB89352_LINE_MSG;
- m_line_status |= MB89352_LINE_CD;
- m_line_status &= ~MB89352_LINE_IO;
- break;
- }
- logerror("MB89352: phase set to %i\n",m_phase);
-}
-
-uint8_t mb89352_device::mb89352_r(offs_t offset)
-{
- uint8_t ret;
- switch(offset & 0x0f)
- {
- case 0x00: // BDID - Bus Device ID
- return (1 << m_bdid);
- case 0x01: // SCTL - SPC Control
- ret = 0x00;
- if(m_arbit_enable)
- ret |= 0x10;
- if(m_parity_enable)
- ret |= 0x08;
- if(m_sel_enable)
- ret |= 0x04;
- if(m_resel_enable)
- ret |= 0x02;
- if(m_int_enable)
- ret |= 0x01;
- return ret;
- case 0x02: // SCMD - Command
- return m_scmd;
- case 0x03: // Unused
- return 0xff;
- case 0x04: // INTS - Interrupt Sense
- return m_ints;
- case 0x05: // PSNS - Phase Sense
- return m_line_status; // active low -- but Human68k expects it to be zero?
- case 0x06: // SSTS - SPC Status
- return m_spc_status;
- case 0x07: // SERR - SPC Error Status
- /* #define SERR_SCSI_PAR 0x80
- #define SERR_SPC_PAR 0x40
- #define SERR_TC_PAR 0x08
- #define SERR_PHASE_ERR 0x04
- #define SERR_SHORT_XFR 0x02
- #define SERR_OFFSET 0x01*/
- return 0;
- case 0x08: // PCTL - Phase Control
- return ((m_busfree_int_enable) ? (m_line_status & 0x07) | 0x80 : (m_line_status & 0x07));
- case 0x0a: // DREG - Data register (for data transfers)
- if(m_spc_status & SSTS_XFER_IN_PROGRESS)
- {
- m_data = m_buffer[m_transfer_index % 512];
- m_transfer_index++;
- m_transfer_count--;
- if(m_transfer_index % 512 == 0)
- read_data(m_buffer, 512);
- if(m_transfer_count == 0)
- {
- // End of transfer
- m_spc_status &= ~SSTS_XFER_IN_PROGRESS;
- m_spc_status |= SSTS_DREG_EMPTY;
- m_ints |= INTS_COMMAND_COMPLETE;
- if(m_int_enable != 0)
- m_irq_cb(1);
- if(m_phase == SCSI_PHASE_MESSAGE_IN)
- set_phase(SCSI_PHASE_BUS_FREE);
- else if(m_phase == SCSI_PHASE_DATAIN)
- set_phase(SCSI_PHASE_STATUS);
- }
- }
- return m_data;
- case 0x0b: // TEMP - Temporary
- logerror("mb89352: read temporary register.\n");
- return m_temp;
- case 0x0c: // TCH - Transfer Counter High
- return (m_transfer_count & 0x00ff0000) >> 16;
- case 0x0d: // TCM - Transfer Counter Mid
- return (m_transfer_count & 0x0000ff00) >> 8;
- case 0x0e: // TCL - Transfer Counter Low
- return (m_transfer_count & 0x000000ff);
- default:
- logerror("mb89352: read from register %02x\n",offset & 0x0f);
- }
- return 0xff;
-}
-
-void mb89352_device::mb89352_w(offs_t offset, uint8_t data)
-{
- switch(offset & 0x0f)
- {
- case 0x00: // BDID - Bus Device ID
- m_bdid = data;
- m_spc_status &= ~SSTS_TARG_CONNECTED;
- m_spc_status |= SSTS_INIT_CONNECTED;
- logerror("mb89352: BDID set to %i\n",data);
- break;
- case 0x01: // SCTL - SPC Control
- if(data & 0x80) // reset and disable
- {
- device_reset();
- logerror("mb89352: SCTL: Reset and disable.\n");
- }
- if(data & 0x10)
- {
- m_arbit_enable = 1;
- logerror("mb89352: SCTL: Arbitration enabled.\n");
- }
- else
- m_arbit_enable = 0;
- if(data & 0x08)
- {
- m_parity_enable = 1;
- logerror("mb89352: SCTL: Parity enabled.\n");
- }
- else
- m_parity_enable = 0;
- if(data & 0x04)
- {
- m_sel_enable = 1;
- logerror("mb89352: SCTL: Selection enabled.\n");
- }
- else
- m_sel_enable = 0;
- if(data & 0x02)
- {
- m_resel_enable = 1;
- logerror("mb89352: SCTL: Reselection enabled.\n");
- }
- else
- m_resel_enable = 0;
- if(data & 0x01)
- {
- m_int_enable = 1;
- logerror("mb89352: SCTL: Interrupts enabled.\n");
- }
- else
- {
- m_int_enable = 0;
- logerror("mb89352: SCTL: Interrupts disabled.\n");
- }
- break;
- case 0x02: // SCMD - Command
- /* From NetBSD/x68k source
- #define SCMD_BUS_REL 0x00
- #define SCMD_SELECT 0x20
- #define SCMD_RST_ATN 0x40
- #define SCMD_SET_ATN 0x60
- #define SCMD_XFR 0x80
- #define SCMD_XFR_PAUSE 0xa0
- #define SCMD_RST_ACK 0xc0
- #define SCMD_SET_ACK 0xe0
- */
- m_scmd = data;
- switch((data & 0xe0) >> 5)
- {
- case 0x00:
- // Bus Free
- m_line_status = 0;
- m_spc_status &= ~SSTS_TARG_CONNECTED;
- m_spc_status &= ~SSTS_INIT_CONNECTED;
- m_spc_status &= ~SSTS_XFER_IN_PROGRESS;
- set_phase(SCSI_PHASE_BUS_FREE);
- if(m_busfree_int_enable)
- {
- if(m_int_enable != 0)
- m_irq_cb(1);
- }
- logerror("mb89352: SCMD: Bus free\n");
- break;
- case 0x01:
- // Selection
- m_target = m_temp;
- m_target &= ~(1 << m_bdid); // mask off the bit relating to initiator
- switch(m_target)
- {
- case 0x01: m_target = 0; break;
- case 0x02: m_target = 1; break;
- case 0x04: m_target = 2; break;
- case 0x08: m_target = 3; break;
- case 0x10: m_target = 4; break;
- case 0x20: m_target = 5; break;
- case 0x40: m_target = 6; break;
- case 0x80: m_target = 7; break;
- }
- if(m_sel_enable != 0)
- {
- //m_ints |= INTS_SELECTION;
- }
- select(m_target);
- set_phase(SCSI_PHASE_COMMAND); // straight to command phase, may need a delay between selection and command phases
- m_line_status |= MB89352_LINE_SEL;
- m_line_status |= MB89352_LINE_BSY;
- m_spc_status &= ~SSTS_TARG_CONNECTED;
- m_spc_status |= SSTS_INIT_CONNECTED;
- m_spc_status |= SSTS_SPC_BSY;
- m_ints |= INTS_COMMAND_COMPLETE;
- if(m_int_enable != 0)
- m_irq_cb(1);
- logerror("mb89352: SCMD: Selection (SCSI ID%i)\n",m_target);
- break;
- case 0x02: // Reset ATN
- m_line_status &= ~MB89352_LINE_ATN;
- logerror("mb89352: SCMD: Reset ATN\n");
- break;
- case 0x03: // Set ATN
- m_line_status |= MB89352_LINE_ATN;
- logerror("mb89352: SCMD: Set ATN\n");
- break;
- case 0x04: // Transfer
- m_transfer_index = 0;
- m_spc_status |= SSTS_XFER_IN_PROGRESS;
- if(m_phase == SCSI_PHASE_DATAIN) // if we are reading data...
- {
- m_spc_status &= ~SSTS_DREG_EMPTY; // DREG is no longer empty
- logerror("data-in\n");
- read_data(m_buffer, 512);
- }
- if(m_phase == SCSI_PHASE_MESSAGE_IN)
- {
- m_spc_status &= ~SSTS_DREG_EMPTY; // DREG is no longer empty
- m_data = 0;
- m_temp = 0x00;
- set_phase(SCSI_PHASE_BUS_FREE);
- logerror("message-in\n");
- m_spc_status &= ~SSTS_XFER_IN_PROGRESS;
- m_command_index = 0;
- }
- if(m_phase == SCSI_PHASE_COMMAND)
- {
- logerror("command-in\n");
- m_spc_status |= SSTS_SPC_BSY;
- }
- logerror("mb89352: SCMD: Start Transfer %02x\n",m_phase);
- break;
- case 0x05: // Transfer pause
- logerror("mb89352: SCMD: Pause Transfer\n");
- break;
- case 0x06: // reset REQ/ACK
- m_line_status &= ~MB89352_LINE_ACK;
- if(m_phase != SCSI_PHASE_BUS_FREE)
- {
- m_line_status |= MB89352_LINE_REQ;
- }
- else
- {
- m_spc_status &= ~SSTS_INIT_CONNECTED;
- m_spc_status &= ~SSTS_TARG_CONNECTED;
- m_spc_status &= ~SSTS_SPC_BSY;
- }
- logerror("mb89352: SCMD: Reset REQ/ACK\n");
- break;
- case 0x07: // set REQ/ACK
- m_line_status &= ~MB89352_LINE_REQ;
- m_line_status |= MB89352_LINE_ACK;
- logerror("mb89352: SCMD: Set REQ/ACK\n");
- if(m_phase == SCSI_PHASE_COMMAND)
- {
- m_command[m_command_index++] = m_temp; // temp register puts data onto the SCSI bus
- if(m_command_index >= get_scsi_cmd_len(m_command[0]))
- {
- int x;
- int phase;
- // execute SCSI command
- send_command(m_command, m_command_index);
- phase = get_phase();
- if(m_command[0] == 1) // Rezero Unit - not implemented in SCSI code
- set_phase(SCSI_PHASE_STATUS);
- else
- set_phase(phase);
- logerror("Command executed: ");
- //m_spc_status &= ~SSTS_SPC_BSY;
- //m_ints |= INTS_COMMAND_COMPLETE;
-
- for(x=0;x<m_command_index;x++)
- logerror(" %02x",m_command[x]);
- logerror("\n");
- }
- return;
- }
- if(m_phase == SCSI_PHASE_STATUS)
- {
- m_temp = get_status();
- 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_cb(0); // clear IRQ
- logerror("mb89352: Reset INTS status bits %02x\n",data);
- break;
- case 0x08: // PCTL - Phase control
- if((data & 0x80) == 0 && (m_phase == SCSI_PHASE_SELECT)) // if writing 0 to bit 7, selection phase is reset
- {
- m_ints &= ~INTS_SELECTION;
- m_target = 0;
- logerror("mb89352: PCTL selection cancelled\n");
- }
- // writing to the low 3 bits sets the phase
- if((m_phase & 0x07) != (data & 0x07))
- set_phase(data & 0x07);
- m_busfree_int_enable = data & 0x80;
- logerror("mb89352: PCTL write %02x\n",data);
- break;
- case 0x0a: // DREG - Data register
- if(m_phase == SCSI_PHASE_COMMAND)
- {
- m_command[m_command_index++] = data;
- if(m_command_index >= get_scsi_cmd_len(m_command[0]))
- {
- int x;
- int phase;
- // execute SCSI command
- send_command(m_command, m_command_index);
- phase = get_phase();
- if(m_command[0] == 1) // Rezero Unit - not implemented in SCSI code
- set_phase(SCSI_PHASE_STATUS);
- else
- set_phase(phase);
- logerror("Command executed: ");
- //m_ints |= INTS_COMMAND_COMPLETE;
-
- 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)
- write_data(m_buffer, 512);
- if(m_transfer_count == 0)
- {
- // End of transfer
- m_spc_status &= ~SSTS_XFER_IN_PROGRESS;
- m_spc_status |= SSTS_DREG_EMPTY;
- m_ints |= INTS_COMMAND_COMPLETE;
- if(m_int_enable != 0)
- m_irq_cb(1);
- 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/devices/machine/mb89352.h b/src/devices/machine/mb89352.h
deleted file mode 100644
index 7454e63a352..00000000000
--- a/src/devices/machine/mb89352.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Barry Rodewald
-/*
- * mb89352.h
- *
- * Created on: 16/01/2011
- */
-
-#ifndef MAME_MACHINE_MB89352_H
-#define MAME_MACHINE_MB89352_H
-
-#include "legscsi.h"
-
-class mb89352_device : public legacy_scsi_host_adapter
-{
-public:
- // construction/destruction
- mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
-
- auto irq_cb() { return m_irq_cb.bind(); }
- auto drq_cb() { return m_drq_cb.bind(); }
-
- // any publically accessible interfaces needed for runtime
- uint8_t mb89352_r(offs_t offset);
- void mb89352_w(offs_t offset, uint8_t data);
-
- void set_phase(int phase);
-
-protected:
- // device-level overrides (none are required, but these are common)
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_stop() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
-private:
- // internal device state goes here
- static const device_timer_id TIMER_TRANSFER = 0;
-
- int get_scsi_cmd_len(uint8_t cbyte);
- //void set_ints(uint8_t flag);
-
- devcb_write_line m_irq_cb; /* irq callback */
- devcb_write_line m_drq_cb; /* drq callback */
-
- uint8_t m_phase; // current SCSI phase
- uint8_t m_target; // current SCSI target
- uint8_t m_bdid; // Bus device ID (SCSI ID of the bus?)
- uint8_t m_ints; // Interrupt Sense
- uint8_t m_temp; // Temporary register (To/From SCSI bus)
- uint8_t m_data; // Data register
- uint8_t m_scmd; // SPC Command register
- uint32_t m_transfer_count; // byte transfer counter, also used as a timeout counter for selection.
- uint8_t m_int_enable;
- uint8_t m_sel_enable;
- uint8_t m_resel_enable;
- uint8_t m_parity_enable;
- uint8_t m_arbit_enable;
- uint8_t m_busfree_int_enable;
- uint8_t m_line_status;
- uint8_t m_spc_status;
- uint8_t m_error_status;
- uint8_t m_command_index;
- uint8_t m_command[16];
- uint32_t m_transfer_index;
- uint8_t m_buffer[512];
-
- emu_timer* m_transfer_timer;
-};
-
-DECLARE_DEVICE_TYPE(MB89352A, mb89352_device)
-
-#endif // MAME_MACHINE_MB89352_H
diff --git a/src/devices/machine/mb89363b.cpp b/src/devices/machine/mb89363b.cpp
index dae0d4a3372..56d1bf83350 100644
--- a/src/devices/machine/mb89363b.cpp
+++ b/src/devices/machine/mb89363b.cpp
@@ -77,28 +77,28 @@
*/
#include "emu.h"
-#include "machine/mb89363b.h"
+#include "mb89363b.h"
DEFINE_DEVICE_TYPE(MB89363B, mb89363b_device, "mb89363b", "Fujitsu MB89363B I/O")
-mb89363b_device::mb89363b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MB89363B, tag, owner, clock),
- m_i8255_a(*this, "i8255_a"),
- m_i8255_b(*this, "i8255_b"),
- m_in_a_pa_cb(*this),
- m_in_a_pb_cb(*this),
- m_in_a_pc_cb(*this),
- m_out_a_pa_cb(*this),
- m_out_a_pb_cb(*this),
- m_out_a_pc_cb(*this),
- m_in_b_pa_cb(*this),
- m_in_b_pb_cb(*this),
- m_in_b_pc_cb(*this),
- m_out_b_pa_cb(*this),
- m_out_b_pb_cb(*this),
- m_out_b_pc_cb(*this)
+mb89363b_device::mb89363b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MB89363B, tag, owner, clock),
+ m_i8255_a(*this, "i8255_a"),
+ m_i8255_b(*this, "i8255_b"),
+ m_in_a_pa_cb(*this, 0xff),
+ m_in_a_pb_cb(*this, 0xff),
+ m_in_a_pc_cb(*this, 0xff),
+ m_out_a_pa_cb(*this),
+ m_out_a_pb_cb(*this),
+ m_out_a_pc_cb(*this),
+ m_in_b_pa_cb(*this, 0xff),
+ m_in_b_pb_cb(*this, 0xff),
+ m_in_b_pc_cb(*this, 0xff),
+ m_out_b_pa_cb(*this),
+ m_out_b_pb_cb(*this),
+ m_out_b_pc_cb(*this)
{
}
@@ -156,20 +156,6 @@ void mb89363b_device::device_add_mconfig(machine_config &config)
void mb89363b_device::device_start()
{
- m_in_a_pa_cb.resolve_safe(0xff);
- m_in_a_pb_cb.resolve_safe(0xff);
- m_in_a_pc_cb.resolve_safe(0xff);
- m_out_a_pa_cb.resolve_safe();
- m_out_a_pb_cb.resolve_safe();
- m_out_a_pc_cb.resolve_safe();
-
- m_in_b_pa_cb.resolve_safe(0xff);
- m_in_b_pb_cb.resolve_safe(0xff);
- m_in_b_pc_cb.resolve_safe(0xff);
- m_out_b_pa_cb.resolve_safe();
- m_out_b_pb_cb.resolve_safe();
- m_out_b_pc_cb.resolve_safe();
-
}
void mb89363b_device::device_reset()
diff --git a/src/devices/machine/mb89374.cpp b/src/devices/machine/mb89374.cpp
index 7cad4c899d6..a2dacb9c47b 100644
--- a/src/devices/machine/mb89374.cpp
+++ b/src/devices/machine/mb89374.cpp
@@ -131,10 +131,6 @@ void mb89374_device::device_start()
// set our instruction counter
set_icountptr(m_icount);
- // resolve callbacks
- m_out_irq_cb.resolve_safe();
- m_out_po_cb.resolve_all_safe();
-
// state saving
save_item(NAME(m_irq));
save_item(NAME(m_po));
diff --git a/src/devices/machine/mb89374.h b/src/devices/machine/mb89374.h
index c70781b49aa..4ea6878641f 100644
--- a/src/devices/machine/mb89374.h
+++ b/src/devices/machine/mb89374.h
@@ -35,7 +35,7 @@ Data Link Controller
#pragma once
-#include "osdcore.h"
+#include "osdfile.h"
class mb89374_device : public device_t,
diff --git a/src/devices/machine/mc14411.cpp b/src/devices/machine/mc14411.cpp
index 64bf476e2c4..66f53b2ec67 100644
--- a/src/devices/machine/mc14411.cpp
+++ b/src/devices/machine/mc14411.cpp
@@ -33,23 +33,15 @@
MACROS
***************************************************************************/
-//#define LOG_GENERAL (1U << 0) // Already defined in logmacro.h
-#define LOG_SETUP (1U << 1)
+#define LOG_SETUP (1U << 1)
//#define VERBOSE (LOG_GENERAL|LOG_SETUP)
//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
-//#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__) // Already defined in logmacro.h
#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
-#ifdef _MSC_VER
-#define FUNCNAME __func__
-#else
-#define FUNCNAME __PRETTY_FUNCTION__
-#endif
-
/***************************************************************************
INTERNAL TABLES
@@ -115,20 +107,20 @@ mc14411_device::mc14411_device(const machine_config &mconfig, device_type type,
void mc14411_device::device_start()
{
- LOGSETUP("%s\n", FUNCNAME);
+ LOGSETUP("mc14411_device::device_start\n");
for (int i = TIMER_F1; i <= TIMER_F16; i++)
{
- m_out_fx_cbs[i].resolve();
- m_fx_timer[i] = timer_alloc(i);
- m_timer_enabled[i] = !m_out_fx_cbs[i].isnull();
+ m_fx_timers[i].timer = timer_alloc(FUNC(mc14411_device::timer_tick), this);
+ m_fx_timers[i].enabled = true;
}
save_item(NAME(m_divider));
save_item(NAME(m_reset));
- save_item(NAME(m_timer_enabled));
+ save_item(STRUCT_MEMBER(m_fx_timers, state));
+ save_item(STRUCT_MEMBER(m_fx_timers, enabled));
- m_reset_timer = timer_alloc(TIMER_ID_RESET);
+ m_reset_timer = timer_alloc(FUNC(mc14411_device::reset_tick), this);
}
@@ -141,7 +133,7 @@ void mc14411_device::device_clock_changed()
{
for (int i = TIMER_F1; i <= TIMER_F16; i++)
{
- if (m_timer_enabled[i])
+ if (m_fx_timers[i].enabled)
arm_timer(i);
}
}
@@ -154,18 +146,18 @@ void mc14411_device::device_clock_changed()
void mc14411_device::timer_enable(timer_id i, bool enable)
{
assert(i >= TIMER_F1 && i <= TIMER_F16);
- m_timer_enabled[i] = enable;
+ m_fx_timers[i].enabled = enable;
if (!enable)
- m_fx_timer[i]->enable(false);
- else if (!m_fx_timer[i]->enabled())
+ m_fx_timers[i].timer->enable(false);
+ else if (!m_fx_timers[i].timer->enabled())
arm_timer(i);
}
void mc14411_device::timer_disable_all()
{
for (int i = TIMER_F1; i <= TIMER_F16; i++)
- timer_enable((timer_id) i, false);
+ timer_enable((timer_id)i, false);
}
//-------------------------------------------------
@@ -175,13 +167,13 @@ void mc14411_device::timer_disable_all()
void mc14411_device::arm_timer(int i)
{
- assert(!m_out_fx_cbs[i].isnull());
-
+ if (m_out_fx_cbs[i].isunset())
+ return;
int divider = s_counter_divider[i];
if (i < TIMER_F15)
divider *= s_divider_select[m_divider];
attotime half_cycle = clocks_to_attotime(divider) / 2; // 2 flanks per cycle
- m_fx_timer[i]->adjust(half_cycle, i, half_cycle);
+ m_fx_timers[i].timer->adjust(half_cycle, i, half_cycle);
LOGSETUP(" - arming timer for F%d at %fHz (/%d)\n", i + 1, double(clock()) / divider, divider);
}
@@ -193,47 +185,47 @@ void mc14411_device::arm_timer(int i)
void mc14411_device::device_reset()
{
- LOGSETUP("%s\n", FUNCNAME);
+ LOGSETUP("mc14411_device::device_reset\n");
for (int i = TIMER_F1; i <= TIMER_F16; i++)
{
- if (!m_out_fx_cbs[i].isnull())
- {
- // Reset line according to datasheet and remember it for transitions to come
- (m_out_fx_cbs[i])(m_fx_state[i] = (i < TIMER_F15 ? 0 : 1));
- }
+ // Reset line according to datasheet and remember it for transitions to come
+ m_fx_timers[i].state = !(i < TIMER_F15);
+ if (!m_out_fx_cbs[i].isunset())
+ m_out_fx_cbs[i](m_fx_timers[i].state);
}
if (m_reset == ASSERT_LINE)
{
- m_reset_timer->adjust(attotime::from_nsec((double)900), TIMER_ID_RESET, attotime::from_nsec((double)900));
+ m_reset_timer->adjust(attotime::from_nsec(900));
}
}
//-------------------------------------------------
-// device_timer - handler timer events
+// timer_tick - update the output state for a
+// given Fx timer
//-------------------------------------------------
-void mc14411_device::device_timer(emu_timer &timer, device_timer_id id, int32_t param, void *ptr)
+TIMER_CALLBACK_MEMBER(mc14411_device::timer_tick)
{
- if (id >= TIMER_F1 && id <= TIMER_F16)
- {
- (m_out_fx_cbs[id])(m_fx_state[id]++ & 1);
- }
- else if (id == TIMER_ID_RESET)
- {
- // NOTE: This check could be triggered by either faulty hardware design or non accurate emulation so is just informative if the reset line is handled
- // explicitelly instead of relying on calling device_reset
- if (!(m_reset == ASSERT_LINE))
- {
- LOG("Reset pulse is too short, should be 900nS minimum");
- logerror("Reset pulse is too short, should be 900nS minimum");
- }
- }
- else
+ m_out_fx_cbs[param](m_fx_timers[param].state);
+ m_fx_timers[param].state = !m_fx_timers[param].state;
+}
+
+
+//-------------------------------------------------
+// reset_tick - log information if the device's
+// reset pulse is too short
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(mc14411_device::reset_tick)
+{
+ // NOTE: This check could be triggered by either faulty hardware design or non accurate emulation so is just informative if the reset line is handled
+ // explicitelly instead of relying on calling device_reset
+ if (!(m_reset == ASSERT_LINE))
{
- LOG("Unhandled Timer ID %d\n", id);
+ LOG("Reset pulse is too short, should be 900nS minimum");
}
}
@@ -246,12 +238,13 @@ void mc14411_device::device_timer(emu_timer &timer, device_timer_id id, int32_t
void mc14411_device::rate_select_w(uint8_t data)
{
- LOGSETUP("%s %02x\n", FUNCNAME, data);
+ LOGSETUP("mc14411_device::rate_select_w %02x\n", data);
if (m_divider != (data & 3))
{
m_divider = data & 3;
- notify_clock_changed();
+ if (started())
+ notify_clock_changed();
}
}
@@ -262,12 +255,13 @@ void mc14411_device::rate_select_w(uint8_t data)
void mc14411_device::rsa_w(int state)
{
- LOGSETUP("%s %02x\n", FUNCNAME, state);
+ LOGSETUP("mc14411_device::rsa_w %02x\n", state);
if ((m_divider & RSA) != (state == ASSERT_LINE ? RSA : 0))
{
m_divider = (m_divider & ~RSA) | (state == ASSERT_LINE ? RSA : 0);
- notify_clock_changed();
+ if (started())
+ notify_clock_changed();
}
}
@@ -278,12 +272,13 @@ void mc14411_device::rsa_w(int state)
void mc14411_device::rsb_w(int state)
{
- LOGSETUP("%s %02x\n", FUNCNAME, state);
+ LOGSETUP("mc14411_device::rsb_w %02x\n", state);
if ((m_divider & RSB) != (state == ASSERT_LINE ? RSB : 0))
{
m_divider = (m_divider & ~RSB) | (state == ASSERT_LINE ? RSB : 0);
- notify_clock_changed();
+ if (started())
+ notify_clock_changed();
}
}
@@ -294,7 +289,7 @@ void mc14411_device::rsb_w(int state)
void mc14411_device::reset_w(int state)
{
- LOGSETUP("%s %02x\n", FUNCNAME, state);
+ LOGSETUP("mc14411_device::reset_w %02x\n", state);
m_reset = state;
diff --git a/src/devices/machine/mc14411.h b/src/devices/machine/mc14411.h
index 99cc8309c96..422e381bcb2 100644
--- a/src/devices/machine/mc14411.h
+++ b/src/devices/machine/mc14411.h
@@ -29,26 +29,25 @@
class mc14411_device : public device_t
{
public:
- // timers
- enum timer_id // indexes
+ // timer indices
+ enum timer_id : int
{
- TIMER_F1 = 0,
- TIMER_F2 = 1,
- TIMER_F3 = 2,
- TIMER_F4 = 3,
- TIMER_F5 = 4,
- TIMER_F6 = 5,
- TIMER_F7 = 6,
- TIMER_F8 = 7,
- TIMER_F9 = 8,
- TIMER_F10 = 9,
- TIMER_F11 = 10,
- TIMER_F12 = 11,
- TIMER_F13 = 12,
- TIMER_F14 = 13,
- TIMER_F15 = 14,
- TIMER_F16 = 15,
- TIMER_ID_RESET = 16
+ TIMER_F1,
+ TIMER_F2,
+ TIMER_F3,
+ TIMER_F4,
+ TIMER_F5,
+ TIMER_F6,
+ TIMER_F7,
+ TIMER_F8,
+ TIMER_F9,
+ TIMER_F10,
+ TIMER_F11,
+ TIMER_F12,
+ TIMER_F13,
+ TIMER_F14,
+ TIMER_F15,
+ TIMER_F16
};
// rate select inputs
@@ -78,26 +77,31 @@ protected:
virtual void device_start() override;
virtual void device_clock_changed() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(timer_tick);
+ TIMER_CALLBACK_MEMBER(reset_tick);
private:
void arm_timer(int i);
- emu_timer *m_fx_timer[16];
- emu_timer *m_reset_timer;
-
- uint32_t m_fx_state[16]; // F1-F16 output line states
+ struct fx_timer
+ {
+ emu_timer *timer;
+ bool state;
+ bool enabled;
+ };
- // divider matrix
- static const int s_counter_divider[16];
- static const int s_divider_select[4];
+ fx_timer m_fx_timers[16];
+ emu_timer *m_reset_timer;
devcb_write_line::array<16> m_out_fx_cbs;
uint32_t m_divider; // main divider to use, 0-3 column index into counter_divider
uint32_t m_reset; // Reset line state
- bool m_timer_enabled[16];
+ // divider matrix
+ static const int s_counter_divider[16];
+ static const int s_divider_select[4];
};
DECLARE_DEVICE_TYPE(MC14411, mc14411_device)
diff --git a/src/devices/machine/mc146818.cpp b/src/devices/machine/mc146818.cpp
index cbce9ced926..ae03165b819 100644
--- a/src/devices/machine/mc146818.cpp
+++ b/src/devices/machine/mc146818.cpp
@@ -12,8 +12,9 @@
*********************************************************************/
#include "emu.h"
+#include "mc146818.h"
+
#include "coreutil.h"
-#include "machine/mc146818.h"
//#define VERBOSE 1
#include "logmacro.h"
@@ -22,6 +23,8 @@
// device type definition
DEFINE_DEVICE_TYPE(MC146818, mc146818_device, "mc146818", "MC146818 RTC")
+DEFINE_DEVICE_TYPE(DS1287, ds1287_device, "ds1287", "DS1287 RTC")
+DEFINE_DEVICE_TYPE(DS1397, ds1397_device, "ds1397", "DS1397 RAMified RTC")
//-------------------------------------------------
// mc146818_device - constructor
@@ -30,23 +33,45 @@ DEFINE_DEVICE_TYPE(MC146818, mc146818_device, "mc146818", "MC146818 RTC")
mc146818_device::mc146818_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc146818_device(mconfig, MC146818, tag, owner, clock)
{
+ switch (clock)
+ {
+ case 4'194'304:
+ case 1'048'576:
+ m_tuc = 248;
+ break;
+ case 32'768:
+ m_tuc = 1984;
+ break;
+ }
+}
+
+ds1287_device::ds1287_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mc146818_device(mconfig, DS1287, tag, owner, clock)
+{
+}
+
+ds1397_device::ds1397_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mc146818_device(mconfig, DS1397, tag, owner, clock)
+{
}
mc146818_device::mc146818_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
device_nvram_interface(mconfig, *this),
+ device_rtc_interface(mconfig, *this),
m_region(*this, DEVICE_SELF),
m_index(0),
- m_last_refresh(attotime::zero), m_clock_timer(nullptr), m_periodic_timer(nullptr),
+ m_clock_timer(nullptr),
+ m_update_timer(nullptr),
+ m_periodic_timer(nullptr),
m_write_irq(*this),
m_write_sqw(*this),
m_century_index(-1),
m_epoch(0),
- m_use_utc(false),
m_binary(false),
m_hour(false),
- m_binyear(false),
- m_sqw_state(false)
+ m_sqw_state(false),
+ m_tuc(0)
{
}
@@ -57,12 +82,9 @@ mc146818_device::mc146818_device(const machine_config &mconfig, device_type type
void mc146818_device::device_start()
{
m_data = make_unique_clear<uint8_t[]>(data_size());
- m_last_refresh = machine().time();
- m_clock_timer = timer_alloc(TIMER_CLOCK);
- m_periodic_timer = timer_alloc(TIMER_PERIODIC);
-
- m_write_irq.resolve_safe();
- m_write_sqw.resolve_safe();
+ m_clock_timer = timer_alloc(FUNC(mc146818_device::clock_tick), this);
+ m_update_timer = timer_alloc(FUNC(mc146818_device::time_tick), this);
+ m_periodic_timer = timer_alloc(FUNC(mc146818_device::periodic_tick), this);
save_pointer(NAME(m_data), data_size());
save_item(NAME(m_index));
@@ -87,124 +109,136 @@ void mc146818_device::device_reset()
}
//-------------------------------------------------
-// device_timer - handler timer events
+// timer events
//-------------------------------------------------
-void mc146818_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mc146818_device::periodic_tick)
{
- switch (id)
+ m_sqw_state = !m_sqw_state;
+
+ if (m_data[REG_B] & REG_B_SQWE)
+ m_write_sqw(m_sqw_state);
+
+ // periodic flag/interrupt on rising edge of periodic timer
+ if (m_sqw_state)
+ {
+ m_data[REG_C] |= REG_C_PF;
+ update_irq();
+ }
+}
+
+TIMER_CALLBACK_MEMBER(mc146818_device::clock_tick)
+{
+ if (!(m_data[REG_B] & REG_B_SET))
{
- case TIMER_PERIODIC:
- m_sqw_state = !m_sqw_state;
+ m_data[REG_A] |= REG_A_UIP;
- if (m_data[REG_B] & REG_B_SQWE)
- m_write_sqw(m_sqw_state);
+ m_update_timer->adjust(attotime::from_usec(244));
+ }
+}
- // periodic flag/interrupt on rising edge of periodic timer
- if (m_sqw_state)
+TIMER_CALLBACK_MEMBER(mc146818_device::time_tick)
+{
+ if (!param)
+ {
+ /// TODO: find out how the real chip deals with updates when binary/bcd values are already outside the normal range
+ int seconds = get_seconds() + 1;
+ if (seconds < 60)
{
- m_data[REG_C] |= REG_C_PF;
- update_irq();
+ set_seconds(seconds);
}
- break;
-
- case TIMER_CLOCK:
- if (!(m_data[REG_B] & REG_B_SET))
+ else
{
- /// TODO: find out how the real chip deals with updates when binary/bcd values are already outside the normal range
- int seconds = get_seconds() + 1;
- if (seconds < 60)
+ set_seconds(0);
+
+ int minutes = get_minutes() + 1;
+ if (minutes < 60)
{
- set_seconds(seconds);
+ set_minutes(minutes);
}
else
{
- set_seconds(0);
+ set_minutes(0);
- int minutes = get_minutes() + 1;
- if (minutes < 60)
+ int hours = get_hours() + 1;
+ if (hours < 24)
{
- set_minutes(minutes);
+ set_hours(hours);
}
else
{
- set_minutes(0);
+ set_hours(0);
- int hours = get_hours() + 1;
- if (hours < 24)
+ int dayofweek = get_dayofweek() + 1;
+ if (dayofweek <= 7)
{
- set_hours(hours);
+ set_dayofweek(dayofweek);
}
else
{
- set_hours(0);
+ set_dayofweek(1);
+ }
- int dayofweek = get_dayofweek() + 1;
- if (dayofweek <= 7)
- {
- set_dayofweek(dayofweek);
- }
- else
- {
- set_dayofweek(1);
- }
+ int dayofmonth = get_dayofmonth() + 1;
+ if (dayofmonth <= gregorian_days_in_month(get_month(), get_year() + 2000))
+ {
+ set_dayofmonth(dayofmonth);
+ }
+ else
+ {
+ set_dayofmonth(1);
- int dayofmonth = get_dayofmonth() + 1;
- if (dayofmonth <= gregorian_days_in_month(get_month(), get_year() + 2000))
+ int month = get_month() + 1;
+ if (month <= 12)
{
- set_dayofmonth(dayofmonth);
+ set_month(month);
}
else
{
- set_dayofmonth(1);
+ set_month(1);
- int month = get_month() + 1;
- if (month <= 12)
+ int year = get_year() + 1;
+ if (year <= 99)
{
- set_month(month);
+ set_year(year);
}
else
{
- set_month(1);
+ set_year(0);
- int year = get_year() + 1;
- if (year <= 99)
+ if (century_count_enabled())
{
- set_year(year);
- }
- else
- {
- set_year(0);
-
- if (century_count_enabled())
- {
- set_century((get_century() + 1) % 100);
- }
+ set_century((get_century() + 1) % 100);
}
}
}
}
}
}
+ }
- if ((m_data[REG_ALARM_SECONDS] == m_data[REG_SECONDS] || (m_data[REG_ALARM_SECONDS] & ALARM_DONTCARE) == ALARM_DONTCARE) &&
- (m_data[REG_ALARM_MINUTES] == m_data[REG_MINUTES] || (m_data[REG_ALARM_MINUTES] & ALARM_DONTCARE) == ALARM_DONTCARE) &&
- (m_data[REG_ALARM_HOURS] == m_data[REG_HOURS] || (m_data[REG_ALARM_HOURS] & ALARM_DONTCARE) == ALARM_DONTCARE))
- {
- // set the alarm interrupt flag AF
- m_data[REG_C] |= REG_C_AF;
- }
-
- // set the update-ended interrupt Flag UF
- m_data[REG_C] |= REG_C_UF;
- update_irq();
+ if ((m_data[REG_ALARM_SECONDS] == m_data[REG_SECONDS] || (m_data[REG_ALARM_SECONDS] & ALARM_DONTCARE) == ALARM_DONTCARE) &&
+ (m_data[REG_ALARM_MINUTES] == m_data[REG_MINUTES] || (m_data[REG_ALARM_MINUTES] & ALARM_DONTCARE) == ALARM_DONTCARE) &&
+ (m_data[REG_ALARM_HOURS] == m_data[REG_HOURS] || (m_data[REG_ALARM_HOURS] & ALARM_DONTCARE) == ALARM_DONTCARE))
+ {
+ // set the alarm interrupt flag AF
+ m_data[REG_C] |= REG_C_AF;
+ }
- m_last_refresh = machine().time();
+ // defer the update end sequence if update cycle time is non-zero
+ if (m_tuc)
+ {
+ m_update_timer->adjust(attotime::from_usec(m_tuc), 1);
+ return;
}
- break;
}
-}
+ // clear update in progress and set update ended
+ m_data[REG_A] &= ~REG_A_UIP;
+ m_data[REG_C] |= REG_C_UF;
+
+ update_irq();
+}
//-------------------------------------------------
// nvram_default - called to initialize NVRAM to
@@ -233,7 +267,6 @@ void mc146818_device::nvram_default()
if(m_hour)
m_data[REG_B] |= REG_B_24_12;
- set_base_datetime();
update_timer();
update_irq();
}
@@ -244,13 +277,17 @@ void mc146818_device::nvram_default()
// .nv file
//-------------------------------------------------
-void mc146818_device::nvram_read(emu_file &file)
+bool mc146818_device::nvram_read(util::read_stream &file)
{
- file.read(&m_data[0], data_size());
+ size_t const size = data_size();
+ auto const [err, actual] = read(file, &m_data[0], size);
+ if (err || (actual != size))
+ return false;
- set_base_datetime();
update_timer();
update_irq();
+
+ return true;
}
@@ -259,9 +296,11 @@ void mc146818_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void mc146818_device::nvram_write(emu_file &file)
+bool mc146818_device::nvram_write(util::write_stream &file)
{
- file.write(&m_data[0], data_size());
+ size_t const size = data_size();
+ auto const [err, actual] = write(file, &m_data[0], size);
+ return !err;
}
@@ -415,36 +454,29 @@ void mc146818_device::set_century(int century)
//-------------------------------------------------
-// set_base_datetime - update clock with real time
+// rtc_clock_updated - update clock with real time
//-------------------------------------------------
-void mc146818_device::set_base_datetime()
+void mc146818_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
{
- system_time systime;
- system_time::full_time current_time;
-
- machine().base_datetime(systime);
-
- current_time = (m_use_utc) ? systime.utc_time: systime.local_time;
-
// logerror("mc146818_set_base_datetime %02d/%02d/%02d %02d:%02d:%02d\n",
-// current_time.year % 100, current_time.month + 1, current_time.mday,
-// current_time.hour,current_time.minute, current_time.second);
-
- set_seconds(current_time.second);
- set_minutes(current_time.minute);
- set_hours(current_time.hour);
- set_dayofweek(current_time.weekday + 1);
- set_dayofmonth(current_time.mday);
- set_month(current_time.month + 1);
-
- if(m_binyear)
- set_year((current_time.year - m_epoch) % (m_data[REG_B] & REG_B_DM ? 0x100 : 100)); // pcd actually depends on this
+// year, month, day,
+// hour, minute, second);
+
+ set_seconds(second);
+ set_minutes(minute);
+ set_hours(hour);
+ set_dayofweek(day_of_week);
+ set_dayofmonth(day);
+ set_month(month);
+
+ if (m_epoch != 0)
+ set_year((year - m_epoch) % (m_data[REG_B] & REG_B_DM ? 0x100 : 100)); // pcd actually depends on this
else
- set_year((current_time.year - m_epoch) % 100);
+ set_year(year % 100);
if (m_century_index >= 0)
- set_century(current_time.year / 100);
+ set_century(year / 100);
}
@@ -553,20 +585,12 @@ void mc146818_device::update_irq()
// read - I/O handler for reading
//-------------------------------------------------
-uint8_t mc146818_device::read(offs_t offset)
+uint8_t mc146818_device::data_r()
{
- uint8_t data = 0;
- switch (offset)
- {
- case 0:
- data = m_index;
- break;
+ uint8_t data = internal_read(m_index);
- case 1:
- data = internal_read(m_index);
+ if (!machine().side_effects_disabled())
LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", m_index, data);
- break;
- }
return data;
}
@@ -579,7 +603,8 @@ uint8_t mc146818_device::read_direct(offs_t offset)
uint8_t data = internal_read(offset);
- LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", offset, data);
+ if (!machine().side_effects_disabled())
+ LOG("mc146818_port_r(): offset=0x%02x data=0x%02x\n", offset, data);
return data;
}
@@ -588,19 +613,16 @@ uint8_t mc146818_device::read_direct(offs_t offset)
// write - I/O handler for writing
//-------------------------------------------------
-void mc146818_device::write(offs_t offset, uint8_t data)
+void mc146818_device::address_w(uint8_t data)
{
- switch (offset)
- {
- case 0:
- internal_set_address(data % data_logical_size());
- break;
+ internal_set_address(data % data_logical_size());
+}
- case 1:
- LOG("mc146818_port_w(): offset=0x%02x data=0x%02x\n", m_index, data);
- internal_write(m_index, data);
- break;
- }
+void mc146818_device::data_w(uint8_t data)
+{
+ LOG("mc146818_port_w(): offset=0x%02x data=0x%02x\n", m_index, data);
+
+ internal_write(m_index, data);
}
void mc146818_device::write_direct(offs_t offset, uint8_t data)
@@ -627,11 +649,6 @@ uint8_t mc146818_device::internal_read(offs_t offset)
{
case REG_A:
data = m_data[REG_A];
- // Update In Progress (UIP) time for 32768 Hz is 244+1984usec
- /// TODO: support other dividers
- /// TODO: don't set this if update is stopped
- if ((machine().time() - m_last_refresh) < attotime::from_usec(244+1984))
- data |= REG_A_UIP;
break;
case REG_C:
@@ -697,3 +714,33 @@ void mc146818_device::internal_write(offs_t offset, uint8_t data)
break;
}
}
+
+void ds1397_device::device_start()
+{
+ mc146818_device::device_start();
+
+ save_item(NAME(m_xram_page));
+}
+
+void ds1397_device::device_reset()
+{
+ mc146818_device::device_reset();
+
+ m_xram_page = 0;
+}
+
+u8 ds1397_device::xram_r(offs_t offset)
+{
+ if (offset < 0x20)
+ return m_data[0x40 + m_xram_page * 0x20 + offset];
+ else
+ return m_xram_page;
+}
+
+void ds1397_device::xram_w(offs_t offset, u8 data)
+{
+ if (offset < 0x20)
+ m_data[0x40 + m_xram_page * 0x20 + offset] = data;
+ else
+ m_xram_page = data & 0x7f;
+}
diff --git a/src/devices/machine/mc146818.h b/src/devices/machine/mc146818.h
index 83d45292dbc..1bee70ec6c9 100644
--- a/src/devices/machine/mc146818.h
+++ b/src/devices/machine/mc146818.h
@@ -16,9 +16,12 @@
#pragma once
+#include "dirtc.h"
+
class mc146818_device : public device_t,
- public device_nvram_interface
+ public device_nvram_interface,
+ public device_rtc_interface
{
public:
// construction/destruction
@@ -31,34 +34,38 @@ public:
// The MC146818 doesn't have century support (some variants do), but when syncing the date & time at startup we can optionally store the century.
void set_century_index(int century_index) { assert(!century_count_enabled()); m_century_index = century_index; }
- // The MC146818 doesn't have UTC support, but when syncing the data & time at startup we can use UTC instead of local time.
- void set_use_utc(bool use_utc) { m_use_utc = use_utc; }
-
void set_binary(bool binary) { m_binary = binary; }
void set_24hrs(bool hour) { m_hour = hour; }
void set_epoch(int epoch) { m_epoch = epoch; }
- void set_binary_year(int bin) { m_binyear = bin; }
// read/write access
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
+ void address_w(uint8_t data);
+ uint8_t data_r();
+ void data_w(uint8_t data);
// direct-mapped read/write access
uint8_t read_direct(offs_t offset);
void write_direct(offs_t offset, uint8_t data);
+ // FIXME: Addresses are read-only on a standard MC146818. Do some chipsets permit readback?
+ uint8_t get_address() const { return m_index; }
+
protected:
mc146818_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return m_epoch != 0 || m_century_index >= 0; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
static constexpr unsigned char ALARM_DONTCARE = 0xc0;
static constexpr unsigned char HOURS_PM = 0x80;
@@ -71,6 +78,10 @@ protected:
virtual uint8_t internal_read(offs_t offset);
virtual void internal_write(offs_t offset, uint8_t data);
+ TIMER_CALLBACK_MEMBER(periodic_tick);
+ TIMER_CALLBACK_MEMBER(clock_tick);
+ TIMER_CALLBACK_MEMBER(time_tick);
+
enum
{
REG_SECONDS = 0,
@@ -129,7 +140,6 @@ protected:
// internal helpers
int to_ram(int a) const;
int from_ram(int a) const;
- void set_base_datetime();
void update_irq();
void update_timer();
virtual int get_timer_bypass() const;
@@ -157,23 +167,44 @@ protected:
uint8_t m_index;
std::unique_ptr<uint8_t[]> m_data;
- attotime m_last_refresh;
-
- static const device_timer_id TIMER_CLOCK = 0;
- static const device_timer_id TIMER_PERIODIC = 1;
-
emu_timer *m_clock_timer;
+ emu_timer *m_update_timer;
emu_timer *m_periodic_timer;
devcb_write_line m_write_irq;
devcb_write_line m_write_sqw;
int m_century_index, m_epoch;
- bool m_use_utc, m_binary, m_hour, m_binyear;
+ bool m_binary, m_hour;
bool m_sqw_state;
+ unsigned m_tuc; // update cycle time
+};
+
+class ds1287_device : public mc146818_device
+{
+public:
+ ds1287_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
+class ds1397_device : public mc146818_device
+{
+public:
+ ds1397_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ u8 xram_r(offs_t offset);
+ void xram_w(offs_t offset, u8 data);
+
+protected:
+ virtual int data_size() const override { return 64 + 4096; }
+
+ u8 m_xram_page;
+};
// device type definition
DECLARE_DEVICE_TYPE(MC146818, mc146818_device)
+DECLARE_DEVICE_TYPE(DS1287, ds1287_device)
+DECLARE_DEVICE_TYPE(DS1397, ds1397_device)
#endif // MAME_MACHINE_MC146818_H
diff --git a/src/devices/machine/mc68328.cpp b/src/devices/machine/mc68328.cpp
index e3690287710..2429130654d 100644
--- a/src/devices/machine/mc68328.cpp
+++ b/src/devices/machine/mc68328.cpp
@@ -9,359 +9,49 @@
**********************************************************************/
#include "emu.h"
-#include "machine/mc68328.h"
-
-
-#define SCR_BETO 0x80
-#define SCR_WPV 0x40
-#define SCR_PRV 0x20
-#define SCR_BETEN 0x10
-#define SCR_SO 0x08
-#define SCR_DMAP 0x04
-#define SCR_WDTH8 0x01
-
-#define ICR_POL6 0x0100
-#define ICR_POL3 0x0200
-#define ICR_POL2 0x0400
-#define ICR_POL1 0x0800
-#define ICR_ET6 0x1000
-#define ICR_ET3 0x2000
-#define ICR_ET2 0x4000
-#define ICR_ET1 0x8000
-
-#define INT_SPIM 0x000001
-#define INT_TIMER2 0x000002
-#define INT_UART 0x000004
-#define INT_WDT 0x000008
-#define INT_RTC 0x000010
-#define INT_RESERVED 0x000020
-#define INT_KB 0x000040
-#define INT_PWM 0x000080
-#define INT_INT0 0x000100
-#define INT_INT1 0x000200
-#define INT_INT2 0x000400
-#define INT_INT3 0x000800
-#define INT_INT4 0x001000
-#define INT_INT5 0x002000
-#define INT_INT6 0x004000
-#define INT_INT7 0x008000
-#define INT_KBDINTS 0x00ff00
-#define INT_IRQ1 0x010000
-#define INT_IRQ2 0x020000
-#define INT_IRQ3 0x040000
-#define INT_IRQ6 0x080000
-#define INT_PEN 0x100000
-#define INT_SPIS 0x200000
-#define INT_TIMER1 0x400000
-#define INT_IRQ7 0x800000
-
-#define INT_M68K_LINE1 (INT_IRQ1)
-#define INT_M68K_LINE2 (INT_IRQ2)
-#define INT_M68K_LINE3 (INT_IRQ3)
-#define INT_M68K_LINE4 (INT_INT0 | INT_INT1 | INT_INT2 | INT_INT3 | INT_INT4 | INT_INT5 | INT_INT6 | INT_INT7 | \
- INT_PWM | INT_KB | INT_RTC | INT_WDT | INT_UART | INT_TIMER2 | INT_SPIM)
-#define INT_M68K_LINE5 (INT_PEN)
-#define INT_M68K_LINE6 (INT_IRQ6 | INT_TIMER1 | INT_SPIS)
-#define INT_M68K_LINE7 (INT_IRQ7)
-#define INT_M68K_LINE67 (INT_M68K_LINE6 | INT_M68K_LINE7)
-#define INT_M68K_LINE567 (INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
-#define INT_M68K_LINE4567 (INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
-#define INT_M68K_LINE34567 (INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
-#define INT_M68K_LINE234567 (INT_M68K_LINE2 | INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
-
-#define INT_IRQ1_SHIFT 0x000001
-#define INT_IRQ2_SHIFT 0x000002
-#define INT_IRQ3_SHIFT 0x000004
-#define INT_IRQ6_SHIFT 0x000008
-#define INT_PEN_SHIFT 0x000010
-#define INT_SPIS_SHIFT 0x000020
-#define INT_TIMER1_SHIFT 0x000040
-#define INT_IRQ7_SHIFT 0x000080
-
-#define INT_ACTIVE 1
-#define INT_INACTIVE 0
-
-#define GRPBASE_BASE_ADDR 0xfff0
-#define GRPBASE_VALID 0x0001
-
-#define GRPMASK_BASE_MASK 0xfff0
-
-#define CSAB_COMPARE 0xff000000
-#define CSAB_BSW 0x00010000
-#define CSAB_MASK 0x0000ff00
-#define CSAB_RO 0x00000008
-#define CSAB_WAIT 0x00000007
-
-#define CSCD_COMPARE 0xfff00000
-#define CSCD_BSW 0x00010000
-#define CSCD_MASK 0x0000fff0
-#define CSCD_RO 0x00000008
-#define CSCD_WAIT 0x00000007
-
-#define PLLCR_PIXCLK_SEL 0x3800
-#define PLLCR_PIXCLK_SEL_DIV2 0x0000
-#define PLLCR_PIXCLK_SEL_DIV4 0x0800
-#define PLLCR_PIXCLK_SEL_DIV8 0x1000
-#define PLLCR_PIXCLK_SEL_DIV16 0x1800
-#define PLLCR_PIXCLK_SEL_DIV1_0 0x2000
-#define PLLCR_PIXCLK_SEL_DIV1_1 0x2800
-#define PLLCR_PIXCLK_SEL_DIV1_2 0x3000
-#define PLLCR_PIXCLK_SEL_DIV1_3 0x3800
-#define PLLCR_SYSCLK_SEL 0x0700
-#define PLLCR_SYSCLK_SEL_DIV2 0x0000
-#define PLLCR_SYSCLK_SEL_DIV4 0x0100
-#define PLLCR_SYSCLK_SEL_DIV8 0x0200
-#define PLLCR_SYSCLK_SEL_DIV16 0x0300
-#define PLLCR_SYSCLK_SEL_DIV1_0 0x0400
-#define PLLCR_SYSCLK_SEL_DIV1_1 0x0500
-#define PLLCR_SYSCLK_SEL_DIV1_2 0x0600
-#define PLLCR_SYSCLK_SEL_DIV1_3 0x0700
-#define PLLCR_CLKEN 0x0010
-#define PLLCR_DISPLL 0x0008
-
-#define PLLFSR_CLK32 0x8000
-#define PLLFSR_PROT 0x4000
-#define PLLFSR_QCNT 0x0f00
-#define PLLFSR_PCNT 0x00ff
-
-#define PCTLR_PC_EN 0x80
-#define PCTLR_STOP 0x40
-#define PCTLR_WIDTH 0x1f
-
-#define CXP_CC 0xc000
-#define CXP_CC_XLU 0x0000
-#define CXP_CC_BLACK 0x4000
-#define CXP_CC_INVERSE 0x8000
-#define CXP_CC_INVALID 0xc000
-#define CXP_MASK 0x03ff
-
-#define CYP_MASK 0x01ff
-
-#define CWCH_CW 0x1f00
-#define CWCH_CH 0x001f
-
-#define BLKC_BKEN 0x80
-#define BLKC_BD 0x7f
-
-#define LPICF_PBSIZ 0x06
-#define LPICF_PBSIZ_1 0x00
-#define LPICF_PBSIZ_2 0x02
-#define LPICF_PBSIZ_4 0x04
-#define LPICF_PBSIZ_INVALID 0x06
-
-#define LPOLCF_LCKPOL 0x08
-#define LPOLCF_FLMPOL 0x04
-#define LPOLCF_LPPOL 0x02
-#define LPOLCF_PIXPOL 0x01
-
-#define LACDRC_MASK 0x0f
-
-#define LPXCD_MASK 0x3f
-
-#define LCKCON_LCDC_EN 0x80
-#define LCKCON_LCDON 0x80
-#define LCKCON_DMA16 0x40
-#define LCKCON_WS 0x30
-#define LCKCON_WS_1 0x00
-#define LCKCON_WS_2 0x10
-#define LCKCON_WS_3 0x20
-#define LCKCON_WS_4 0x30
-#define LCKCON_DWIDTH 0x02
-#define LCKCON_PCDS 0x01
-
-#define LBAR_MASK 0x7f
-
-#define LPOSR_BOS 0x08
-#define LPOSR_POS 0x07
-
-#define LFRCM_XMOD 0xf0
-#define LFRCM_YMOD 0x0f
-
-#define LGPMR_PAL1 0x7000
-#define LGPMR_PAL0 0x0700
-#define LGPMR_PAL3 0x0070
-#define LGPMR_PAL2 0x0007
-
-#define RTCHMSR_HOURS 0x1f000000
-#define RTCHMSR_MINUTES 0x003f0000
-#define RTCHMSR_SECONDS 0x0000003f
-
-#define RTCCTL_38_4 0x0020
-#define RTCCTL_ENABLE 0x0080
-
-#define RTCINT_STOPWATCH 0x0001
-#define RTCINT_MINUTE 0x0002
-#define RTCINT_ALARM 0x0004
-#define RTCINT_DAY 0x0008
-#define RTCINT_SECOND 0x0010
-
-#define RTCSTPWTCH_MASK 0x003f
-
-#define TCTL_TEN 0x0001
-#define TCTL_TEN_ENABLE 0x0001
-#define TCTL_CLKSOURCE 0x000e
-#define TCTL_CLKSOURCE_STOP 0x0000
-#define TCTL_CLKSOURCE_SYSCLK 0x0002
-#define TCTL_CLKSOURCE_SYSCLK16 0x0004
-#define TCTL_CLKSOURCE_TIN 0x0006
-#define TCTL_CLKSOURCE_32KHZ4 0x0008
-#define TCTL_CLKSOURCE_32KHZ5 0x000a
-#define TCTL_CLKSOURCE_32KHZ6 0x000c
-#define TCTL_CLKSOURCE_32KHZ7 0x000e
-#define TCTL_IRQEN 0x0010
-#define TCTL_IRQEN_ENABLE 0x0010
-#define TCTL_OM 0x0020
-#define TCTL_OM_ACTIVELOW 0x0000
-#define TCTL_OM_TOGGLE 0x0020
-#define TCTL_CAPTURE 0x00c0
-#define TCTL_CAPTURE_NOINT 0x0000
-#define TCTL_CAPTURE_RISING 0x0040
-#define TCTL_CAPTURE_FALLING 0x0080
-#define TCTL_CAPTURE_BOTH 0x00c0
-#define TCTL_FRR 0x0100
-#define TCTL_FRR_RESTART 0x0000
-#define TCTL_FRR_FREERUN 0x0100
-
-#define TSTAT_COMP 0x0001
-#define TSTAT_CAPT 0x0002
-
-#define WCTLR_WDRST 0x0008
-#define WCTLR_LOCK 0x0004
-#define WCTLR_FI 0x0002
-#define WCTLR_WDEN 0x0001
-
-#define USTCNT_UART_EN 0x8000
-#define USTCNT_RX_EN 0x4000
-#define USTCNT_TX_EN 0x2000
-#define USTCNT_RX_CLK_CONT 0x1000
-#define USTCNT_PARITY_EN 0x0800
-#define USTCNT_ODD_EVEN 0x0400
-#define USTCNT_STOP_BITS 0x0200
-#define USTCNT_8_7 0x0100
-#define USTCNT_GPIO_DELTA_EN 0x0080
-#define USTCNT_CTS_DELTA_EN 0x0040
-#define USTCNT_RX_FULL_EN 0x0020
-#define USTCNT_RX_HALF_EN 0x0010
-#define USTCNT_RX_RDY_EN 0x0008
-#define USTCNT_TX_EMPTY_EN 0x0004
-#define USTCNT_TX_HALF_EN 0x0002
-#define USTCNT_TX_AVAIL_EN 0x0001
-
-#define UBAUD_GPIO_DELTA 0x8000
-#define UBAUD_GPIO 0x4000
-#define UBAUD_GPIO_DIR 0x2000
-#define UBAUD_GPIO_SRC 0x1000
-#define UBAUD_BAUD_SRC 0x0800
-#define UBAUD_DIVIDE 0x0700
-#define UBAUD_DIVIDE_1 0x0000
-#define UBAUD_DIVIDE_2 0x0100
-#define UBAUD_DIVIDE_4 0x0200
-#define UBAUD_DIVIDE_8 0x0300
-#define UBAUD_DIVIDE_16 0x0400
-#define UBAUD_DIVIDE_32 0x0500
-#define UBAUD_DIVIDE_64 0x0600
-#define UBAUD_DIVIDE_128 0x0700
-#define UBAUD_PRESCALER 0x00ff
-
-#define URX_FIFO_FULL 0x8000
-#define URX_FIFO_HALF 0x4000
-#define URX_DATA_READY 0x2000
-#define URX_OVRUN 0x0800
-#define URX_FRAME_ERROR 0x0400
-#define URX_BREAK 0x0200
-#define URX_PARITY_ERROR 0x0100
-
-#define UTX_FIFO_EMPTY 0x8000
-#define UTX_FIFO_HALF 0x4000
-#define UTX_TX_AVAIL 0x2000
-#define UTX_SEND_BREAK 0x1000
-#define UTX_IGNORE_CTS 0x0800
-#define UTX_CTS_STATUS 0x0200
-#define UTX_CTS_DELTA 0x0100
-
-#define UMISC_CLK_SRC 0x4000
-#define UMISC_FORCE_PERR 0x2000
-#define UMISC_LOOP 0x1000
-#define UMISC_RTS_CONT 0x0080
-#define UMISC_RTS 0x0040
-#define UMISC_IRDA_ENABLE 0x0020
-#define UMISC_IRDA_LOOP 0x0010
-
-#define SPIS_SPIS_IRQ 0x8000
-#define SPIS_IRQEN 0x4000
-#define SPIS_ENPOL 0x2000
-#define SPIS_DATA_RDY 0x1000
-#define SPIS_OVRWR 0x0800
-#define SPIS_PHA 0x0400
-#define SPIS_POL 0x0200
-#define SPIS_SPISEN 0x0100
-
-#define SPIM_CLOCK_COUNT 0x000f
-#define SPIM_POL 0x0010
-#define SPIM_POL_HIGH 0x0000
-#define SPIM_POL_LOW 0x0010
-#define SPIM_PHA 0x0020
-#define SPIM_PHA_NORMAL 0x0000
-#define SPIM_PHA_OPPOSITE 0x0020
-#define SPIM_IRQEN 0x0040
-#define SPIM_SPIMIRQ 0x0080
-#define SPIM_XCH 0x0100
-#define SPIM_XCH_IDLE 0x0000
-#define SPIM_XCH_INIT 0x0100
-#define SPIM_SPMEN 0x0200
-#define SPIM_SPMEN_DISABLE 0x0000
-#define SPIM_SPMEN_ENABLE 0x0200
-#define SPIM_RATE 0xe000
-#define SPIM_RATE_4 0x0000
-#define SPIM_RATE_8 0x2000
-#define SPIM_RATE_16 0x4000
-#define SPIM_RATE_32 0x6000
-#define SPIM_RATE_64 0x8000
-#define SPIM_RATE_128 0xa000
-#define SPIM_RATE_256 0xc000
-#define SPIM_RATE_512 0xe000
-
-#define PWMC_PWMIRQ 0x8000
-#define PWMC_IRQEN 0x4000
-#define PWMC_LOAD 0x0100
-#define PWMC_PIN 0x0080
-#define PWMC_POL 0x0040
-#define PWMC_PWMEN 0x0010
-#define PWMC_CLKSEL 0x0007
-
-
-#define VERBOSE_LEVEL (0)
-
-static inline void ATTR_PRINTF(3,4) verboselog(device_t &device, int n_level, const char *s_fmt, ...)
-{
- if (VERBOSE_LEVEL >= n_level)
- {
- va_list v;
- char buf[32768];
- va_start(v, s_fmt);
- vsprintf(buf, s_fmt, v);
- va_end(v);
- device.logerror("%s: %s", device.machine().describe_context(), buf);
- }
-}
-
-DEFINE_DEVICE_TYPE(MC68328, mc68328_device, "mc68328", "MC68328 DragonBall Integrated Processor")
-
-
-void mc68328_device::internal_map(address_map &map)
-{
- map(0xfff000, 0xffffff).rw(FUNC(mc68328_device::internal_read), FUNC(mc68328_device::internal_write));
-}
-
-void mc68328_device::cpu_space_map(address_map &map)
-{
- map(0xfffff0, 0xffffff).r(FUNC(mc68328_device::irq_callback)).umask16(0x00ff);
-}
-
-
-mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : m68000_device(mconfig, tag, owner, clock, MC68328, 16, 24, address_map_constructor(FUNC(mc68328_device::internal_map), this))
- , m_rtc(nullptr), m_pwm(nullptr)
+#include "mc68328.h"
+
+#define LOG_SCR (1U << 1)
+#define LOG_CS_GRP (1U << 2)
+#define LOG_CS_SEL (1U << 3)
+#define LOG_PLL (1U << 4)
+#define LOG_INTS (1U << 5)
+#define LOG_GPIO_A (1U << 6)
+#define LOG_GPIO_B (1U << 7)
+#define LOG_GPIO_C (1U << 8)
+#define LOG_GPIO_D (1U << 9)
+#define LOG_GPIO_E (1U << 10)
+#define LOG_GPIO_F (1U << 11)
+#define LOG_GPIO_G (1U << 12)
+#define LOG_GPIO_J (1U << 13)
+#define LOG_GPIO_K (1U << 14)
+#define LOG_GPIO_M (1U << 15)
+#define LOG_PWM (1U << 16)
+#define LOG_TIMERS (1U << 17)
+#define LOG_TSTAT (1U << 18)
+#define LOG_WATCHDOG (1U << 19)
+#define LOG_SPIS (1U << 20)
+#define LOG_SPIM (1U << 21)
+#define LOG_UART (1U << 22)
+#define LOG_LCD (1U << 23)
+#define LOG_RTC (1U << 24)
+#define LOG_ALL (LOG_SCR | LOG_PLL | LOG_INTS | LOG_GPIO_A | LOG_GPIO_B | LOG_GPIO_C | LOG_GPIO_D | LOG_GPIO_E \
+ | LOG_GPIO_F | LOG_GPIO_G | LOG_GPIO_J | LOG_GPIO_K | LOG_GPIO_M | LOG_PWM | LOG_TIMERS | LOG_TSTAT | LOG_WATCHDOG | LOG_SPIS \
+ | LOG_SPIM | LOG_UART | LOG_LCD | LOG_RTC)
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(MC68328, mc68328_device, "mc68328", "MC68328 DragonBall Processor")
+DEFINE_DEVICE_TYPE(MC68EZ328, mc68ez328_device, "mc68ez328", "MC68EZ328 DragonBall-EZ Processor")
+
+const u32 mc68328_base_device::VCO_DIVISORS[8] = { 2, 4, 8, 16, 1, 1, 1, 1 };
+
+mc68328_base_device::mc68328_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : m68000_device(mconfig, type, tag, owner, clock)
+ , m_pwm(nullptr)
+ , m_rtc(nullptr)
+ , m_spim(nullptr)
, m_out_port_a_cb(*this)
, m_out_port_b_cb(*this)
, m_out_port_c_cb(*this)
@@ -369,25 +59,262 @@ mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, d
, m_out_port_e_cb(*this)
, m_out_port_f_cb(*this)
, m_out_port_g_cb(*this)
+ , m_in_port_a_cb(*this, 0)
+ , m_in_port_b_cb(*this, 0)
+ , m_in_port_c_cb(*this, 0)
+ , m_in_port_d_cb(*this, 0)
+ , m_in_port_e_cb(*this, 0)
+ , m_in_port_f_cb(*this, 0)
+ , m_in_port_g_cb(*this, 0)
+ , m_out_pwm_cb(*this)
+ , m_out_spim_cb(*this)
+ , m_in_spim_cb(*this, 0)
+ , m_out_flm_cb(*this)
+ , m_out_llp_cb(*this)
+ , m_out_lsclk_cb(*this)
+ , m_out_ld_cb(*this)
+ , m_lcd_info_changed_cb(*this)
+{
+}
+
+mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : mc68328_base_device(mconfig, MC68328, tag, owner, clock)
, m_out_port_j_cb(*this)
, m_out_port_k_cb(*this)
, m_out_port_m_cb(*this)
- , m_in_port_a_cb(*this)
- , m_in_port_b_cb(*this)
- , m_in_port_c_cb(*this)
- , m_in_port_d_cb(*this)
- , m_in_port_e_cb(*this)
- , m_in_port_f_cb(*this)
- , m_in_port_g_cb(*this)
- , m_in_port_j_cb(*this)
- , m_in_port_k_cb(*this)
- , m_in_port_m_cb(*this)
- , m_out_pwm_cb(*this)
- , m_out_spim_cb(*this)
- , m_in_spim_cb(*this)
- , m_spim_xch_trigger_cb(*this)
+ , m_in_port_j_cb(*this, 0)
+ , m_in_port_k_cb(*this, 0)
+ , m_in_port_m_cb(*this, 0)
{
m_cpu_space_config.m_internal_map = address_map_constructor(FUNC(mc68328_device::cpu_space_map), this);
+ auto imap = address_map_constructor(FUNC(mc68328_device::internal_map), this);
+ m_program_config.m_internal_map = imap;
+ m_opcodes_config.m_internal_map = imap;
+ m_uprogram_config.m_internal_map = imap;
+ m_uopcodes_config.m_internal_map = imap;
+}
+
+mc68ez328_device::mc68ez328_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : mc68328_base_device(mconfig, MC68EZ328, tag, owner, clock)
+{
+ m_cpu_space_config.m_internal_map = address_map_constructor(FUNC(mc68ez328_device::cpu_space_map), this);
+ m_cpu_space_config.m_addr_width = 32;
+ m_program_config.m_addr_width = 32;
+ m_opcodes_config.m_addr_width = 32;
+ m_uprogram_config.m_addr_width = 32;
+ m_uopcodes_config.m_addr_width = 32;
+ auto imap = address_map_constructor(FUNC(mc68ez328_device::internal_map), this);
+ m_program_config.m_internal_map = imap;
+ m_opcodes_config.m_internal_map = imap;
+ m_uprogram_config.m_internal_map = imap;
+ m_uopcodes_config.m_internal_map = imap;
+}
+
+void mc68328_base_device::base_internal_map(u32 addr_bits, address_map &map)
+{
+ map(addr_bits | 0x000, addr_bits | 0x000).rw(FUNC(mc68328_base_device::scr_r), FUNC(mc68328_base_device::scr_w));
+ map(addr_bits | 0x100, addr_bits | 0x101).rw(FUNC(mc68328_base_device::grpbasea_r), FUNC(mc68328_base_device::grpbasea_w));
+ map(addr_bits | 0x102, addr_bits | 0x103).rw(FUNC(mc68328_base_device::grpbaseb_r), FUNC(mc68328_base_device::grpbaseb_w));
+ map(addr_bits | 0x104, addr_bits | 0x105).rw(FUNC(mc68328_base_device::grpbasec_r), FUNC(mc68328_base_device::grpbasec_w));
+ map(addr_bits | 0x106, addr_bits | 0x107).rw(FUNC(mc68328_base_device::grpbased_r), FUNC(mc68328_base_device::grpbased_w));
+
+ map(addr_bits | 0x200, addr_bits | 0x201).rw(FUNC(mc68328_base_device::pllcr_r), FUNC(mc68328_base_device::pllcr_w));
+ map(addr_bits | 0x202, addr_bits | 0x203).rw(FUNC(mc68328_base_device::pllfsr_r), FUNC(mc68328_base_device::pllfsr_w));
+ map(addr_bits | 0x207, addr_bits | 0x207).rw(FUNC(mc68328_base_device::pctlr_r), FUNC(mc68328_base_device::pctlr_w));
+
+ map(addr_bits | 0x300, addr_bits | 0x300).rw(FUNC(mc68328_base_device::ivr_r), FUNC(mc68328_base_device::ivr_w));
+ map(addr_bits | 0x302, addr_bits | 0x303).rw(FUNC(mc68328_base_device::icr_r), FUNC(mc68328_base_device::icr_w));
+ map(addr_bits | 0x304, addr_bits | 0x305).rw(FUNC(mc68328_base_device::imr_msw_r), FUNC(mc68328_base_device::imr_msw_w));
+ map(addr_bits | 0x306, addr_bits | 0x307).rw(FUNC(mc68328_base_device::imr_lsw_r), FUNC(mc68328_base_device::imr_lsw_w));
+ map(addr_bits | 0x30c, addr_bits | 0x30d).rw(FUNC(mc68328_base_device::isr_msw_r), FUNC(mc68328_base_device::isr_msw_w));
+ map(addr_bits | 0x30e, addr_bits | 0x30f).rw(FUNC(mc68328_base_device::isr_lsw_r), FUNC(mc68328_base_device::isr_lsw_w));
+ map(addr_bits | 0x310, addr_bits | 0x311).rw(FUNC(mc68328_base_device::ipr_msw_r), FUNC(mc68328_base_device::ipr_msw_w));
+ map(addr_bits | 0x312, addr_bits | 0x313).rw(FUNC(mc68328_base_device::ipr_lsw_r), FUNC(mc68328_base_device::ipr_lsw_w));
+
+ map(addr_bits | 0x400, addr_bits | 0x400).rw(FUNC(mc68328_base_device::padir_r), FUNC(mc68328_base_device::padir_w));
+ map(addr_bits | 0x401, addr_bits | 0x401).rw(FUNC(mc68328_base_device::padata_r), FUNC(mc68328_base_device::padata_w));
+ map(addr_bits | 0x408, addr_bits | 0x408).rw(FUNC(mc68328_base_device::pbdir_r), FUNC(mc68328_base_device::pbdir_w));
+ map(addr_bits | 0x409, addr_bits | 0x409).rw(FUNC(mc68328_base_device::pbdata_r), FUNC(mc68328_base_device::pbdata_w));
+ map(addr_bits | 0x40b, addr_bits | 0x40b).rw(FUNC(mc68328_base_device::pbsel_r), FUNC(mc68328_base_device::pbsel_w));
+ map(addr_bits | 0x410, addr_bits | 0x410).rw(FUNC(mc68328_base_device::pcdir_r), FUNC(mc68328_base_device::pcdir_w));
+ map(addr_bits | 0x411, addr_bits | 0x411).rw(FUNC(mc68328_base_device::pcdata_r), FUNC(mc68328_base_device::pcdata_w));
+ map(addr_bits | 0x413, addr_bits | 0x413).rw(FUNC(mc68328_base_device::pcsel_r), FUNC(mc68328_base_device::pcsel_w));
+ map(addr_bits | 0x418, addr_bits | 0x418).rw(FUNC(mc68328_base_device::pddir_r), FUNC(mc68328_base_device::pddir_w));
+ map(addr_bits | 0x419, addr_bits | 0x419).rw(FUNC(mc68328_base_device::pddata_r), FUNC(mc68328_base_device::pddata_w));
+ map(addr_bits | 0x41a, addr_bits | 0x41a).rw(FUNC(mc68328_base_device::pdpuen_r), FUNC(mc68328_base_device::pdpuen_w));
+ map(addr_bits | 0x41c, addr_bits | 0x41c).rw(FUNC(mc68328_base_device::pdpol_r), FUNC(mc68328_base_device::pdpol_w));
+ map(addr_bits | 0x41d, addr_bits | 0x41d).rw(FUNC(mc68328_base_device::pdirqen_r), FUNC(mc68328_base_device::pdirqen_w));
+ map(addr_bits | 0x41f, addr_bits | 0x41f).rw(FUNC(mc68328_base_device::pdirqedge_r), FUNC(mc68328_base_device::pdirqedge_w));
+ map(addr_bits | 0x420, addr_bits | 0x420).rw(FUNC(mc68328_base_device::pedir_r), FUNC(mc68328_base_device::pedir_w));
+ map(addr_bits | 0x421, addr_bits | 0x421).rw(FUNC(mc68328_base_device::pedata_r), FUNC(mc68328_base_device::pedata_w));
+ map(addr_bits | 0x422, addr_bits | 0x422).rw(FUNC(mc68328_base_device::pepuen_r), FUNC(mc68328_base_device::pepuen_w));
+ map(addr_bits | 0x423, addr_bits | 0x423).rw(FUNC(mc68328_base_device::pesel_r), FUNC(mc68328_base_device::pesel_w));
+ map(addr_bits | 0x428, addr_bits | 0x428).rw(FUNC(mc68328_base_device::pfdir_r), FUNC(mc68328_base_device::pfdir_w));
+ map(addr_bits | 0x429, addr_bits | 0x429).rw(FUNC(mc68328_base_device::pfdata_r), FUNC(mc68328_base_device::pfdata_w));
+ map(addr_bits | 0x42a, addr_bits | 0x42a).rw(FUNC(mc68328_base_device::pfpuen_r), FUNC(mc68328_base_device::pfpuen_w));
+ map(addr_bits | 0x42b, addr_bits | 0x42b).rw(FUNC(mc68328_base_device::pfsel_r), FUNC(mc68328_base_device::pfsel_w));
+ map(addr_bits | 0x430, addr_bits | 0x430).rw(FUNC(mc68328_base_device::pgdir_r), FUNC(mc68328_base_device::pgdir_w));
+ map(addr_bits | 0x431, addr_bits | 0x431).rw(FUNC(mc68328_base_device::pgdata_r), FUNC(mc68328_base_device::pgdata_w));
+ map(addr_bits | 0x432, addr_bits | 0x432).rw(FUNC(mc68328_base_device::pgpuen_r), FUNC(mc68328_base_device::pgpuen_w));
+ map(addr_bits | 0x433, addr_bits | 0x433).rw(FUNC(mc68328_base_device::pgsel_r), FUNC(mc68328_base_device::pgsel_w));
+
+ map(addr_bits | 0x500, addr_bits | 0x501).rw(FUNC(mc68328_base_device::pwmc_r), FUNC(mc68328_base_device::pwmc_w));
+
+ map(addr_bits | 0x600, addr_bits | 0x601).rw(FUNC(mc68328_base_device::tctl_r<0>), FUNC(mc68328_base_device::tctl_w<0>));
+ map(addr_bits | 0x602, addr_bits | 0x603).rw(FUNC(mc68328_base_device::tprer_r<0>), FUNC(mc68328_base_device::tprer_w<0>));
+ map(addr_bits | 0x604, addr_bits | 0x605).rw(FUNC(mc68328_base_device::tcmp_r<0>), FUNC(mc68328_base_device::tcmp_w<0>));
+ map(addr_bits | 0x606, addr_bits | 0x607).rw(FUNC(mc68328_base_device::tcr_r<0>), FUNC(mc68328_base_device::tcr_w<0>));
+ map(addr_bits | 0x608, addr_bits | 0x609).rw(FUNC(mc68328_base_device::tcn_r<0>), FUNC(mc68328_base_device::tcn_w<0>));
+ map(addr_bits | 0x60a, addr_bits | 0x60b).rw(FUNC(mc68328_base_device::tstat_r<0>), FUNC(mc68328_base_device::tstat_w<0>));
+
+ map(addr_bits | 0x800, addr_bits | 0x801).rw(FUNC(mc68328_base_device::spimdata_r), FUNC(mc68328_base_device::spimdata_w));
+ map(addr_bits | 0x802, addr_bits | 0x803).rw(FUNC(mc68328_base_device::spimcont_r), FUNC(mc68328_base_device::spimcont_w));
+
+ map(addr_bits | 0x900, addr_bits | 0x901).rw(FUNC(mc68328_base_device::ustcnt_r), FUNC(mc68328_base_device::ustcnt_w));
+ map(addr_bits | 0x902, addr_bits | 0x903).rw(FUNC(mc68328_base_device::ubaud_r), FUNC(mc68328_base_device::ubaud_w));
+ map(addr_bits | 0x904, addr_bits | 0x905).rw(FUNC(mc68328_base_device::urx_r), FUNC(mc68328_base_device::urx_w));
+ map(addr_bits | 0x906, addr_bits | 0x907).rw(FUNC(mc68328_base_device::utx_r), FUNC(mc68328_base_device::utx_w));
+ map(addr_bits | 0x908, addr_bits | 0x909).rw(FUNC(mc68328_base_device::umisc_r), FUNC(mc68328_base_device::umisc_w));
+
+ map(addr_bits | 0xa00, addr_bits | 0xa01).rw(FUNC(mc68328_base_device::lssa_msw_r), FUNC(mc68328_base_device::lssa_msw_w));
+ map(addr_bits | 0xa02, addr_bits | 0xa03).rw(FUNC(mc68328_base_device::lssa_lsw_r), FUNC(mc68328_base_device::lssa_lsw_w));
+ map(addr_bits | 0xa05, addr_bits | 0xa05).rw(FUNC(mc68328_base_device::lvpw_r), FUNC(mc68328_base_device::lvpw_w));
+ map(addr_bits | 0xa08, addr_bits | 0xa09).rw(FUNC(mc68328_base_device::lxmax_r), FUNC(mc68328_base_device::lxmax_w));
+ map(addr_bits | 0xa0a, addr_bits | 0xa0b).rw(FUNC(mc68328_base_device::lymax_r), FUNC(mc68328_base_device::lymax_w));
+ map(addr_bits | 0xa18, addr_bits | 0xa19).rw(FUNC(mc68328_base_device::lcxp_r), FUNC(mc68328_base_device::lcxp_w));
+ map(addr_bits | 0xa1a, addr_bits | 0xa1b).rw(FUNC(mc68328_base_device::lcyp_r), FUNC(mc68328_base_device::lcyp_w));
+ map(addr_bits | 0xa1c, addr_bits | 0xa1d).rw(FUNC(mc68328_base_device::lcwch_r), FUNC(mc68328_base_device::lcwch_w));
+ map(addr_bits | 0xa1f, addr_bits | 0xa1f).rw(FUNC(mc68328_base_device::lblkc_r), FUNC(mc68328_base_device::lblkc_w));
+ map(addr_bits | 0xa20, addr_bits | 0xa20).rw(FUNC(mc68328_base_device::lpicf_r), FUNC(mc68328_base_device::lpicf_w));
+ map(addr_bits | 0xa21, addr_bits | 0xa21).rw(FUNC(mc68328_base_device::lpolcf_r), FUNC(mc68328_base_device::lpolcf_w));
+ map(addr_bits | 0xa23, addr_bits | 0xa23).rw(FUNC(mc68328_base_device::lacdrc_r), FUNC(mc68328_base_device::lacdrc_w));
+ map(addr_bits | 0xa25, addr_bits | 0xa25).rw(FUNC(mc68328_base_device::lpxcd_r), FUNC(mc68328_base_device::lpxcd_w));
+ map(addr_bits | 0xa27, addr_bits | 0xa27).rw(FUNC(mc68328_base_device::lckcon_r), FUNC(mc68328_base_device::lckcon_w));
+ map(addr_bits | 0xa2d, addr_bits | 0xa2d).rw(FUNC(mc68328_base_device::lposr_r), FUNC(mc68328_base_device::lposr_w));
+ map(addr_bits | 0xa31, addr_bits | 0xa31).rw(FUNC(mc68328_base_device::lfrcm_r), FUNC(mc68328_base_device::lfrcm_w));
+
+ map(addr_bits | 0xb00, addr_bits | 0xb01).rw(FUNC(mc68328_base_device::hmsr_msw_r), FUNC(mc68328_base_device::hmsr_msw_w));
+ map(addr_bits | 0xb02, addr_bits | 0xb03).rw(FUNC(mc68328_base_device::hmsr_lsw_r), FUNC(mc68328_base_device::hmsr_lsw_w));
+ map(addr_bits | 0xb04, addr_bits | 0xb05).rw(FUNC(mc68328_base_device::alarm_msw_r), FUNC(mc68328_base_device::alarm_msw_w));
+ map(addr_bits | 0xb06, addr_bits | 0xb07).rw(FUNC(mc68328_base_device::alarm_lsw_r), FUNC(mc68328_base_device::alarm_lsw_w));
+ map(addr_bits | 0xb0e, addr_bits | 0xb0f).rw(FUNC(mc68328_base_device::rtcisr_r), FUNC(mc68328_base_device::rtcisr_w));
+ map(addr_bits | 0xb10, addr_bits | 0xb11).rw(FUNC(mc68328_base_device::rtcienr_r), FUNC(mc68328_base_device::rtcienr_w));
+ map(addr_bits | 0xb12, addr_bits | 0xb13).rw(FUNC(mc68328_base_device::stpwtch_r), FUNC(mc68328_base_device::stpwtch_w));
+}
+
+void mc68328_device::internal_map(address_map &map)
+{
+ base_internal_map(0xfff000, map);
+ map(0xfff108, 0xfff109).rw(FUNC(mc68328_device::grpmaska_r), FUNC(mc68328_device::grpmaska_w));
+ map(0xfff10a, 0xfff10b).rw(FUNC(mc68328_device::grpmaskb_r), FUNC(mc68328_device::grpmaskb_w));
+ map(0xfff10c, 0xfff10d).rw(FUNC(mc68328_device::grpmaskc_r), FUNC(mc68328_device::grpmaskc_w));
+ map(0xfff10e, 0xfff10f).rw(FUNC(mc68328_device::grpmaskd_r), FUNC(mc68328_device::grpmaskd_w));
+ map(0xfff110, 0xfff111).rw(FUNC(mc68328_device::csa_msw_r<0>), FUNC(mc68328_device::csa_msw_w<0>));
+ map(0xfff112, 0xfff113).rw(FUNC(mc68328_device::csa_lsw_r<0>), FUNC(mc68328_device::csa_lsw_w<0>));
+ map(0xfff114, 0xfff115).rw(FUNC(mc68328_device::csa_msw_r<1>), FUNC(mc68328_device::csa_msw_w<1>));
+ map(0xfff116, 0xfff117).rw(FUNC(mc68328_device::csa_lsw_r<1>), FUNC(mc68328_device::csa_lsw_w<1>));
+ map(0xfff118, 0xfff119).rw(FUNC(mc68328_device::csa_msw_r<2>), FUNC(mc68328_device::csa_msw_w<2>));
+ map(0xfff11a, 0xfff11b).rw(FUNC(mc68328_device::csa_lsw_r<2>), FUNC(mc68328_device::csa_lsw_w<2>));
+ map(0xfff11c, 0xfff11d).rw(FUNC(mc68328_device::csa_msw_r<3>), FUNC(mc68328_device::csa_msw_w<3>));
+ map(0xfff11e, 0xfff11f).rw(FUNC(mc68328_device::csa_lsw_r<3>), FUNC(mc68328_device::csa_lsw_w<3>));
+ map(0xfff120, 0xfff121).rw(FUNC(mc68328_device::csb_msw_r<0>), FUNC(mc68328_device::csb_msw_w<0>));
+ map(0xfff122, 0xfff123).rw(FUNC(mc68328_device::csb_lsw_r<0>), FUNC(mc68328_device::csb_lsw_w<0>));
+ map(0xfff124, 0xfff125).rw(FUNC(mc68328_device::csb_msw_r<1>), FUNC(mc68328_device::csb_msw_w<1>));
+ map(0xfff126, 0xfff127).rw(FUNC(mc68328_device::csb_lsw_r<1>), FUNC(mc68328_device::csb_lsw_w<1>));
+ map(0xfff128, 0xfff129).rw(FUNC(mc68328_device::csb_msw_r<2>), FUNC(mc68328_device::csb_msw_w<2>));
+ map(0xfff12a, 0xfff12b).rw(FUNC(mc68328_device::csb_lsw_r<2>), FUNC(mc68328_device::csb_lsw_w<2>));
+ map(0xfff12c, 0xfff12d).rw(FUNC(mc68328_device::csb_msw_r<3>), FUNC(mc68328_device::csb_msw_w<3>));
+ map(0xfff12e, 0xfff12f).rw(FUNC(mc68328_device::csb_lsw_r<3>), FUNC(mc68328_device::csb_lsw_w<3>));
+ map(0xfff130, 0xfff131).rw(FUNC(mc68328_device::csc_msw_r<0>), FUNC(mc68328_device::csc_msw_w<0>));
+ map(0xfff132, 0xfff133).rw(FUNC(mc68328_device::csc_lsw_r<0>), FUNC(mc68328_device::csc_lsw_w<0>));
+ map(0xfff134, 0xfff135).rw(FUNC(mc68328_device::csc_msw_r<1>), FUNC(mc68328_device::csc_msw_w<1>));
+ map(0xfff136, 0xfff137).rw(FUNC(mc68328_device::csc_lsw_r<1>), FUNC(mc68328_device::csc_lsw_w<1>));
+ map(0xfff138, 0xfff139).rw(FUNC(mc68328_device::csc_msw_r<2>), FUNC(mc68328_device::csc_msw_w<2>));
+ map(0xfff13a, 0xfff13b).rw(FUNC(mc68328_device::csc_lsw_r<2>), FUNC(mc68328_device::csc_lsw_w<2>));
+ map(0xfff13c, 0xfff13d).rw(FUNC(mc68328_device::csc_msw_r<3>), FUNC(mc68328_device::csc_msw_w<3>));
+ map(0xfff13e, 0xfff13f).rw(FUNC(mc68328_device::csc_lsw_r<3>), FUNC(mc68328_device::csc_lsw_w<3>));
+ map(0xfff140, 0xfff141).rw(FUNC(mc68328_device::csd_msw_r<0>), FUNC(mc68328_device::csd_msw_w<0>));
+ map(0xfff142, 0xfff143).rw(FUNC(mc68328_device::csd_lsw_r<0>), FUNC(mc68328_device::csd_lsw_w<0>));
+ map(0xfff144, 0xfff145).rw(FUNC(mc68328_device::csd_msw_r<1>), FUNC(mc68328_device::csd_msw_w<1>));
+ map(0xfff146, 0xfff147).rw(FUNC(mc68328_device::csd_lsw_r<1>), FUNC(mc68328_device::csd_lsw_w<1>));
+ map(0xfff148, 0xfff149).rw(FUNC(mc68328_device::csd_msw_r<2>), FUNC(mc68328_device::csd_msw_w<2>));
+ map(0xfff14a, 0xfff14b).rw(FUNC(mc68328_device::csd_lsw_r<2>), FUNC(mc68328_device::csd_lsw_w<2>));
+ map(0xfff14c, 0xfff14d).rw(FUNC(mc68328_device::csd_msw_r<3>), FUNC(mc68328_device::csd_msw_w<3>));
+ map(0xfff14e, 0xfff14f).rw(FUNC(mc68328_device::csd_lsw_r<3>), FUNC(mc68328_device::csd_lsw_w<3>));
+
+ map(0xfff308, 0xfff309).rw(FUNC(mc68328_device::iwr_msw_r), FUNC(mc68328_device::iwr_msw_w));
+ map(0xfff30a, 0xfff30b).rw(FUNC(mc68328_device::iwr_lsw_r), FUNC(mc68328_device::iwr_lsw_w));
+
+ map(0xfff403, 0xfff403).rw(FUNC(mc68328_device::pasel_r), FUNC(mc68328_device::pasel_w));
+
+ map(0xfff438, 0xfff438).rw(FUNC(mc68328_device::pjdir_r), FUNC(mc68328_device::pjdir_w));
+ map(0xfff439, 0xfff439).rw(FUNC(mc68328_device::pjdata_r), FUNC(mc68328_device::pjdata_w));
+ map(0xfff43b, 0xfff43b).rw(FUNC(mc68328_device::pjsel_r), FUNC(mc68328_device::pjsel_w));
+ map(0xfff440, 0xfff440).rw(FUNC(mc68328_device::pkdir_r), FUNC(mc68328_device::pkdir_w));
+ map(0xfff441, 0xfff441).rw(FUNC(mc68328_device::pkdata_r), FUNC(mc68328_device::pkdata_w));
+ map(0xfff442, 0xfff442).rw(FUNC(mc68328_device::pkpuen_r), FUNC(mc68328_device::pkpuen_w));
+ map(0xfff443, 0xfff443).rw(FUNC(mc68328_device::pksel_r), FUNC(mc68328_device::pksel_w));
+ map(0xfff448, 0xfff448).rw(FUNC(mc68328_device::pmdir_r), FUNC(mc68328_device::pmdir_w));
+ map(0xfff449, 0xfff449).rw(FUNC(mc68328_device::pmdata_r), FUNC(mc68328_device::pmdata_w));
+ map(0xfff44a, 0xfff44a).rw(FUNC(mc68328_device::pmpuen_r), FUNC(mc68328_device::pmpuen_w));
+ map(0xfff44b, 0xfff44b).rw(FUNC(mc68328_device::pmsel_r), FUNC(mc68328_device::pmsel_w));
+
+ map(0xfff502, 0xfff503).rw(FUNC(mc68328_device::pwmp_r), FUNC(mc68328_device::pwmp_w));
+ map(0xfff504, 0xfff505).rw(FUNC(mc68328_device::pwmw_r), FUNC(mc68328_device::pwmw_w));
+ map(0xfff506, 0xfff507).rw(FUNC(mc68328_device::pwmcnt_r), FUNC(mc68328_device::pwmcnt_w));
+
+ map(0xfff60c, 0xfff60d).rw(FUNC(mc68328_device::tctl_r<1>), FUNC(mc68328_device::tctl_w<1>));
+ map(0xfff60e, 0xfff60f).rw(FUNC(mc68328_device::tprer_r<1>), FUNC(mc68328_device::tprer_w<1>));
+ map(0xfff610, 0xfff611).rw(FUNC(mc68328_device::tcmp_r<1>), FUNC(mc68328_device::tcmp_w<1>));
+ map(0xfff612, 0xfff613).rw(FUNC(mc68328_device::tcr_r<1>), FUNC(mc68328_device::tcr_w<1>));
+ map(0xfff614, 0xfff615).rw(FUNC(mc68328_device::tcn_r<1>), FUNC(mc68328_device::tcn_w<1>));
+ map(0xfff616, 0xfff617).rw(FUNC(mc68328_device::tstat_r<1>), FUNC(mc68328_device::tstat_w<1>));
+ map(0xfff618, 0xfff619).rw(FUNC(mc68328_device::wctlr_r), FUNC(mc68328_device::wctlr_w));
+ map(0xfff61a, 0xfff61b).rw(FUNC(mc68328_device::wcmpr_r), FUNC(mc68328_device::wcmpr_w));
+ map(0xfff61c, 0xfff61d).rw(FUNC(mc68328_device::wcn_r), FUNC(mc68328_device::wcn_w));
+
+ map(0xfff700, 0xfff701).rw(FUNC(mc68328_device::spisr_r), FUNC(mc68328_device::spisr_w));
+
+ map(0xfffa29, 0xfffa29).rw(FUNC(mc68328_device::llbar_r), FUNC(mc68328_device::llbar_w));
+ map(0xfffa2b, 0xfffa2b).rw(FUNC(mc68328_device::lotcr_r), FUNC(mc68328_device::lotcr_w));
+ map(0xfffa32, 0xfffa33).rw(FUNC(mc68328_device::lgpmr_r), FUNC(mc68328_device::lgpmr_w));
+
+ map(0xfffb0c, 0xfffb0d).rw(FUNC(mc68328_device::rtcctl_r), FUNC(mc68328_device::rtcctl_w));
+}
+
+void mc68ez328_device::internal_map(address_map &map)
+{
+ base_internal_map(0xfffff000, map);
+
+ map(0xfffff004, 0xfffff007).r(FUNC(mc68ez328_device::revision_r));
+
+ map(0xfffff110, 0xfffff111).rw(FUNC(mc68ez328_device::csa_r), FUNC(mc68ez328_device::csa_w));
+ map(0xfffff112, 0xfffff113).rw(FUNC(mc68ez328_device::csb_r), FUNC(mc68ez328_device::csb_w));
+ map(0xfffff114, 0xfffff115).rw(FUNC(mc68ez328_device::csc_r), FUNC(mc68ez328_device::csc_w));
+ map(0xfffff116, 0xfffff117).rw(FUNC(mc68ez328_device::csd_r), FUNC(mc68ez328_device::csd_w));
+ map(0xfffff118, 0xfffff119).rw(FUNC(mc68ez328_device::emucs_r), FUNC(mc68ez328_device::emucs_w));
+
+ map(0xfffff502, 0xfffff503).rw(FUNC(mc68ez328_device::pwms_r), FUNC(mc68ez328_device::pwms_w));
+ map(0xfffff504, 0xfffff504).rw(FUNC(mc68ez328_device::pwmp_r), FUNC(mc68ez328_device::pwmp_w));
+ map(0xfffff505, 0xfffff505).rw(FUNC(mc68ez328_device::pwmcnt_r), FUNC(mc68ez328_device::pwmcnt_w));
+
+ map(0xfffffa29, 0xfffffa29).rw(FUNC(mc68ez328_device::lrra_r), FUNC(mc68ez328_device::lrra_w));
+ map(0xfffffa36, 0xfffffa37).rw(FUNC(mc68ez328_device::pwmr_r), FUNC(mc68ez328_device::pwmr_w));
+
+ map(0xfffffb0a, 0xfffffb0b).rw(FUNC(mc68ez328_device::watchdog_r), FUNC(mc68ez328_device::watchdog_w));
+ map(0xfffffb0c, 0xfffffb0d).rw(FUNC(mc68ez328_device::rtcctl_r), FUNC(mc68ez328_device::rtcctl_w));
+ map(0xfffffb1a, 0xfffffb1b).rw(FUNC(mc68ez328_device::dayr_r), FUNC(mc68ez328_device::dayr_w));
+ map(0xfffffb1c, 0xfffffb1d).rw(FUNC(mc68ez328_device::dayalarm_r), FUNC(mc68ez328_device::dayalarm_w));
+}
+
+void mc68328_device::cpu_space_map(address_map &map)
+{
+ map(0xfffff0, 0xffffff).r(FUNC(mc68328_device::irq_callback)).umask16(0x00ff);
+}
+
+void mc68ez328_device::cpu_space_map(address_map &map)
+{
+ map(0xfffffff0, 0xffffffff).r(FUNC(mc68ez328_device::irq_callback)).umask16(0x00ff);
}
//-------------------------------------------------
@@ -396,2821 +323,3655 @@ mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, d
// initial conditions at start time
//-------------------------------------------------
-void mc68328_device::device_resolve_objects()
+void mc68328_base_device::device_resolve_objects()
{
m68000_device::device_resolve_objects();
- m_out_port_a_cb.resolve();
- m_out_port_b_cb.resolve();
- m_out_port_c_cb.resolve();
- m_out_port_d_cb.resolve();
- m_out_port_e_cb.resolve();
- m_out_port_f_cb.resolve();
- m_out_port_g_cb.resolve();
- m_out_port_j_cb.resolve();
- m_out_port_k_cb.resolve();
- m_out_port_m_cb.resolve();
-
- m_in_port_a_cb.resolve();
- m_in_port_b_cb.resolve();
- m_in_port_c_cb.resolve();
- m_in_port_d_cb.resolve();
- m_in_port_e_cb.resolve();
- m_in_port_f_cb.resolve();
- m_in_port_g_cb.resolve();
- m_in_port_j_cb.resolve();
- m_in_port_k_cb.resolve();
- m_in_port_m_cb.resolve();
-
- m_out_pwm_cb.resolve();
-
- m_out_spim_cb.resolve();
- m_in_spim_cb.resolve();
-
- m_spim_xch_trigger_cb.resolve();
+ m_lcd_info_changed_cb.resolve_safe();
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
-void mc68328_device::device_start()
+void mc68328_base_device::device_start()
{
m68000_device::device_start();
- m_gptimer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::timer1_hit),this));
- m_gptimer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::timer2_hit),this));
- m_rtc = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::rtc_tick),this));
- m_pwm = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::pwm_transition),this));
+ m_refclk = timer_alloc(FUNC(mc68328_base_device::refclk_tick), this);
+ m_pwm = timer_alloc(FUNC(mc68328_base_device::pwm_tick), this);
+ m_rtc = timer_alloc(FUNC(mc68328_base_device::rtc_tick), this);
+ m_spim = timer_alloc(FUNC(mc68328_base_device::spim_tick), this);
+ m_lcd_scan = timer_alloc(FUNC(mc68328_base_device::lcd_scan_tick), this);
+
+ m_lcd_line_buffer = std::make_unique<u16[]>(1024 / 16); // 1024px wide, up to 16 pixels per word
register_state_save();
}
+void mc68328_device::device_start()
+{
+ mc68328_base_device::device_start();
+
+ m_gptimer[0] = timer_alloc(FUNC(mc68328_device::timer_tick<0>), this);
+ m_gptimer[1] = timer_alloc(FUNC(mc68328_device::timer_tick<1>), this);
+}
+
+void mc68ez328_device::device_start()
+{
+ mc68328_base_device::device_start();
+
+ m_gptimer = timer_alloc(FUNC(mc68ez328_device::timer_tick<0>), this);
+ m_rtc_sample_timer = timer_alloc(FUNC(mc68ez328_device::sample_timer_tick), this);
+
+ m_dayr = 0;
+ m_dayalarm = 0;
+ m_sam_cnt = 0;
+}
+
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
-void mc68328_device::device_reset()
+void mc68328_base_device::device_reset()
{
m68000_device::device_reset();
- m_regs.scr = 0x0c;
- m_regs.grpbasea = 0x0000;
- m_regs.grpbaseb = 0x0000;
- m_regs.grpbasec = 0x0000;
- m_regs.grpbased = 0x0000;
- m_regs.grpmaska = 0x0000;
- m_regs.grpmaskb = 0x0000;
- m_regs.grpmaskc = 0x0000;
- m_regs.grpmaskd = 0x0000;
- m_regs.csa0 = 0x00010006;
- m_regs.csa1 = 0x00010006;
- m_regs.csa2 = 0x00010006;
- m_regs.csa3 = 0x00010006;
- m_regs.csb0 = 0x00010006;
- m_regs.csb1 = 0x00010006;
- m_regs.csb2 = 0x00010006;
- m_regs.csb3 = 0x00010006;
- m_regs.csc0 = 0x00010006;
- m_regs.csc1 = 0x00010006;
- m_regs.csc2 = 0x00010006;
- m_regs.csc3 = 0x00010006;
- m_regs.csd0 = 0x00010006;
- m_regs.csd1 = 0x00010006;
- m_regs.csd2 = 0x00010006;
- m_regs.csd3 = 0x00010006;
-
- m_regs.pllcr = 0x2400;
- m_regs.pllfsr = 0x0123;
- m_regs.pctlr = 0x1f;
-
- m_regs.ivr = 0x00;
- m_regs.icr = 0x0000;
- m_regs.imr = 0x00ffffff;
- m_regs.iwr = 0x00ffffff;
- m_regs.isr = 0x00000000;
- m_regs.ipr = 0x00000000;
-
- m_regs.padir = 0x00;
- m_regs.padata = 0x00;
- m_regs.pasel = 0x00;
- m_regs.pbdir = 0x00;
- m_regs.pbdata = 0x00;
- m_regs.pbsel = 0x00;
- m_regs.pcdir = 0x00;
- m_regs.pcdata = 0x00;
- m_regs.pcsel = 0x00;
- m_regs.pddir = 0x00;
- m_regs.pddata = 0x00;
- m_regs.pdpuen = 0xff;
- m_regs.pdpol = 0x00;
- m_regs.pdirqen = 0x00;
- m_regs.pddataedge = 0x00;
- m_regs.pdirqedge = 0x00;
- m_regs.pedir = 0x00;
- m_regs.pedata = 0x00;
- m_regs.pepuen = 0x80;
- m_regs.pesel = 0x80;
- m_regs.pfdir = 0x00;
- m_regs.pfdata = 0x00;
- m_regs.pfpuen = 0xff;
- m_regs.pfsel = 0xff;
- m_regs.pgdir = 0x00;
- m_regs.pgdata = 0x00;
- m_regs.pgpuen = 0xff;
- m_regs.pgsel = 0xff;
- m_regs.pjdir = 0x00;
- m_regs.pjdata = 0x00;
- m_regs.pjsel = 0x00;
- m_regs.pkdir = 0x00;
- m_regs.pkdata = 0x00;
- m_regs.pkpuen = 0xff;
- m_regs.pksel = 0xff;
- m_regs.pmdir = 0x00;
- m_regs.pmdata = 0x00;
- m_regs.pmpuen = 0xff;
- m_regs.pmsel = 0xff;
-
- m_regs.pwmc = 0x0000;
- m_regs.pwmp = 0x0000;
- m_regs.pwmw = 0x0000;
- m_regs.pwmcnt = 0x0000;
-
- m_regs.tctl[0] = m_regs.tctl[1] = 0x0000;
- m_regs.tprer[0] = m_regs.tprer[1] = 0x0000;
- m_regs.tcmp[0] = m_regs.tcmp[1] = 0xffff;
- m_regs.tcr[0] = m_regs.tcr[1] = 0x0000;
- m_regs.tcn[0] = m_regs.tcn[1] = 0x0000;
- m_regs.tstat[0] = m_regs.tstat[1] = 0x0000;
- m_regs.wctlr = 0x0000;
- m_regs.wcmpr = 0xffff;
- m_regs.wcn = 0x0000;
-
- m_regs.spisr = 0x0000;
-
- m_regs.spimdata = 0x0000;
- m_regs.spimcont = 0x0000;
-
- m_regs.ustcnt = 0x0000;
- m_regs.ubaud = 0x003f;
- m_regs.urx = 0x0000;
- m_regs.utx = 0x0000;
- m_regs.umisc = 0x0000;
-
- m_regs.lssa = 0x00000000;
- m_regs.lvpw = 0xff;
- m_regs.lxmax = 0x03ff;
- m_regs.lymax = 0x01ff;
- m_regs.lcxp = 0x0000;
- m_regs.lcyp = 0x0000;
- m_regs.lcwch = 0x0101;
- m_regs.lblkc = 0x7f;
- m_regs.lpicf = 0x00;
- m_regs.lpolcf = 0x00;
- m_regs.lacdrc = 0x00;
- m_regs.lpxcd = 0x00;
- m_regs.lckcon = 0x40;
- m_regs.llbar = 0x3e;
- m_regs.lotcr = 0x3f;
- m_regs.lposr = 0x00;
- m_regs.lfrcm = 0xb9;
- m_regs.lgpmr = 0x1073;
-
- m_regs.hmsr = 0x00000000;
- m_regs.alarm = 0x00000000;
- m_regs.rtcctl = 0x00;
- m_regs.rtcisr = 0x00;
- m_regs.rtcienr = 0x00;
- m_regs.stpwtch = 0x00;
+ m_scr = 0x0c;
+ m_grpbasea = 0x0000;
+ m_grpbaseb = 0x0000;
+ m_grpbasec = 0x0000;
+ m_grpbased = 0x0000;
+
+ m_refclk->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768));
+ m_pllcr = 0x2400;
+ m_pllfsr = 0x0123;
+ m_pctlr = 0x1f;
+
+ m_ivr = 0x00;
+ m_icr = 0x0000;
+ m_imr = 0x00ffffff;
+ m_gisr = 0x00000000;
+ m_ipr = 0x00000000;
+
+ m_pasel = 0x00;
+ m_padir = 0x00;
+ m_padata = 0x00;
+ m_pbdir = 0x00;
+ m_pbdata = 0x00;
+ m_pbsel = 0x00;
+ m_pcdir = 0x00;
+ m_pcdata = 0x00;
+ m_pcsel = 0x00;
+ m_pddir = 0x00;
+ m_pddata = 0x00;
+ m_pdpuen = 0xff;
+ m_pdpol = 0x00;
+ m_pdirqen = 0x00;
+ m_pdirqedge = 0x00;
+ m_pdindata = 0x00;
+ m_pedir = 0x00;
+ m_pedata = 0x00;
+ m_pepuen = 0x80;
+ m_pesel = 0x80;
+ m_pfdir = 0x00;
+ m_pfdata = 0x00;
+ m_pfpuen = 0xff;
+ m_pfsel = 0xff;
+ m_pgdir = 0x00;
+ m_pgdata = 0x00;
+ m_pgpuen = 0xff;
+ m_pgsel = 0xff;
+
+ m_spimdata = 0x0000;
+ m_spimcont = 0x0000;
+ m_spmtxd = false;
+ m_spmrxd = false;
+ m_spmclk = false;
+ m_spim_bit_read_idx = 15;
+
+ m_ustcnt = 0x0000;
+ m_ubaud = 0x003f;
+ m_urx = 0x0000;
+ m_utx = 0x0000;
+ m_umisc = 0x0000;
+
+ m_lssa = 0x00000000;
+ m_lssa_end = 0x00000000;
+ m_lvpw = 0xff;
+ m_lxmax = 0x03ff;
+ m_lymax = 0x01ff;
+ m_lcxp = 0x0000;
+ m_lcyp = 0x0000;
+ m_lcwch = 0x0101;
+ m_lblkc = 0x7f;
+ m_lpicf = 0x00;
+ m_lpolcf = 0x00;
+ m_lacdrc = 0x00;
+ m_lpxcd = 0x00;
+ m_lckcon = 0x40;
+ m_lposr = 0x00;
+ m_lfrcm = 0xb9;
+ m_lcd_update_pending = true;
+
+ m_hmsr = 0x00000000;
+ m_alarm = 0x00000000;
+ m_rtcctl = 0x00;
+
+ m_rtcisr = 0x0000;
+ m_rtcienr = 0x0000;
+ m_stpwtch = 0x0000;
+
+ m_pwm->adjust(attotime::never);
+ m_pwmo = false;
m_rtc->adjust(attotime::from_hz(1), 0, attotime::from_hz(1));
+ m_spim->adjust(attotime::never);
+ m_lcd_scan->adjust(attotime::never);
+ m_lcd_sysmem_ptr = 0;
+ m_lssa_end = 0;
+ m_lcd_line_bit = 0;
+ m_lcd_line_word = 0;
+ m_lsclk = false;
}
+void mc68328_device::device_reset()
+{
+ mc68328_base_device::device_reset();
+
+ m_grpmaska = 0x0000;
+ m_grpmaskb = 0x0000;
+ m_grpmaskc = 0x0000;
+ m_grpmaskd = 0x0000;
+ std::fill(std::begin(m_csa), std::end(m_csa), 0x00010006);
+ std::fill(std::begin(m_csb), std::end(m_csb), 0x00010006);
+ std::fill(std::begin(m_csc), std::end(m_csc), 0x00010006);
+ std::fill(std::begin(m_csd), std::end(m_csd), 0x00010006);
+
+ m_iwr = 0x00ffffff;
+
+ m_pasel = 0xff;
+ m_pjdir = 0x00;
+ m_pjdata = 0x00;
+ m_pjsel = 0x00;
+ m_pkdir = 0x00;
+ m_pkdata = 0x00;
+ m_pkpuen = 0xff;
+ m_pksel = 0xff;
+ m_pmdir = 0x00;
+ m_pmdata = 0x00;
+ m_pmpuen = 0xff;
+ m_pmsel = 0xff;
+
+ m_pwmc = 0x0000;
+ m_pwmp = 0x0000;
+ m_pwmw = 0x0000;
+ m_pwmcnt = 0x0000;
+
+ m_timer_regs[0].tctl = m_timer_regs[1].tctl = 0x0000;
+ m_timer_regs[0].tprer = m_timer_regs[1].tprer = 0x0000;
+ m_timer_regs[0].tcmp = m_timer_regs[1].tcmp = 0xffff;
+ m_timer_regs[0].tcr = m_timer_regs[1].tcr = 0x0000;
+ m_timer_regs[0].tcn = m_timer_regs[1].tcn = 0x0000;
+ m_timer_regs[0].tstat = m_timer_regs[1].tstat = 0x0000;
+ m_wctlr = 0x0000;
+ m_wcmpr = 0xffff;
+ m_wcn = 0x0000;
+ m_timer_regs[0].tclear = m_timer_regs[1].tclear = 0;
+
+ m_spisr = 0x0000;
+
+ m_llbar = 0x3e;
+ m_lotcr = 0x3f;
+ m_lgpmr = 0x1073;
+
+ m_gptimer[0]->adjust(attotime::never);
+ m_gptimer[1]->adjust(attotime::never);
+}
-void mc68328_device::set_interrupt_line(uint32_t line, uint32_t active)
+void mc68ez328_device::device_reset()
{
- if (active)
+ mc68328_base_device::device_reset();
+
+ m_csa = 0x00e0;
+ m_csb = 0x0000;
+ m_csc = 0x0000;
+ m_csd = 0x0020;
+ m_emucs = 0x0060;
+
+ m_pwmc = 0x0020;
+ m_pwmp = 0xfe;
+ m_pwmcnt = 0x00;
+ std::fill(std::begin(m_pwmfifo), std::end(m_pwmfifo), 0x0000);
+ m_pwmfifo_wr = 0;
+ m_pwmfifo_rd = 0;
+ m_pwmfifo_cnt = 0;
+ m_pwm_rep_cnt = 1;
+
+ m_gptimer->adjust(attotime::never);
+
+ m_lrra = 0xff;
+ m_pwmr = 0x0000;
+
+ m_rtc_sample_timer->adjust(attotime::from_ticks(64, 32768), 0, attotime::from_ticks(64, 32768));
+ m_watchdog = 0x0001;
+ m_sam_cnt = 0;
+}
+
+void mc68328_base_device::register_state_save()
+{
+ save_item(NAME(m_scr));
+ save_item(NAME(m_grpbasea));
+ save_item(NAME(m_grpbaseb));
+ save_item(NAME(m_grpbasec));
+ save_item(NAME(m_grpbased));
+
+ save_item(NAME(m_pllcr));
+ save_item(NAME(m_pllfsr));
+ save_item(NAME(m_pctlr));
+
+ save_item(NAME(m_ivr));
+ save_item(NAME(m_icr));
+ save_item(NAME(m_imr));
+ save_item(NAME(m_gisr));
+ save_item(NAME(m_ipr));
+
+ save_item(NAME(m_padir));
+ save_item(NAME(m_padata));
+ save_item(NAME(m_pbdir));
+ save_item(NAME(m_pbdata));
+ save_item(NAME(m_pbsel));
+ save_item(NAME(m_pcdir));
+ save_item(NAME(m_pcdata));
+ save_item(NAME(m_pcsel));
+ save_item(NAME(m_pddir));
+ save_item(NAME(m_pddata));
+ save_item(NAME(m_pdpuen));
+ save_item(NAME(m_pdpol));
+ save_item(NAME(m_pdirqen));
+ save_item(NAME(m_pdirqedge));
+ save_item(NAME(m_pdindata));
+ save_item(NAME(m_pedir));
+ save_item(NAME(m_pedata));
+ save_item(NAME(m_pepuen));
+ save_item(NAME(m_pesel));
+ save_item(NAME(m_pfdir));
+ save_item(NAME(m_pfdata));
+ save_item(NAME(m_pfpuen));
+ save_item(NAME(m_pfsel));
+ save_item(NAME(m_pgdir));
+ save_item(NAME(m_pgdata));
+ save_item(NAME(m_pgpuen));
+ save_item(NAME(m_pgsel));
+
+ save_item(NAME(m_pwmc));
+ save_item(NAME(m_pwmo));
+
+ save_item(NAME(m_spimdata));
+ save_item(NAME(m_spimcont));
+ save_item(NAME(m_spmtxd));
+ save_item(NAME(m_spmrxd));
+ save_item(NAME(m_spmclk));
+ save_item(NAME(m_spim_bit_read_idx));
+
+ save_item(NAME(m_ustcnt));
+ save_item(NAME(m_ubaud));
+ save_item(NAME(m_urx));
+ save_item(NAME(m_utx));
+ save_item(NAME(m_umisc));
+
+ save_item(NAME(m_lssa));
+ save_item(NAME(m_lssa_end));
+ save_item(NAME(m_lvpw));
+ save_item(NAME(m_lxmax));
+ save_item(NAME(m_lymax));
+ save_item(NAME(m_lcxp));
+ save_item(NAME(m_lcyp));
+ save_item(NAME(m_lcwch));
+ save_item(NAME(m_lblkc));
+ save_item(NAME(m_lpicf));
+ save_item(NAME(m_lpolcf));
+ save_item(NAME(m_lacdrc));
+ save_item(NAME(m_lpxcd));
+ save_item(NAME(m_lckcon));
+ save_item(NAME(m_lposr));
+ save_item(NAME(m_lfrcm));
+ save_item(NAME(m_lcd_update_pending));
+
+ save_item(NAME(m_hmsr));
+ save_item(NAME(m_alarm));
+ save_item(NAME(m_rtcctl));
+ save_item(NAME(m_rtcisr));
+ save_item(NAME(m_rtcienr));
+ save_item(NAME(m_stpwtch));
+
+ save_item(NAME(m_lcd_sysmem_ptr));
+ save_pointer(NAME(m_lcd_line_buffer), 1024 / 8);
+ save_item(NAME(m_lcd_line_bit));
+ save_item(NAME(m_lcd_line_word));
+ save_item(NAME(m_lsclk));
+}
+
+void mc68328_device::register_state_save()
+{
+ mc68328_base_device::register_state_save();
+
+ save_item(NAME(m_grpmaska));
+ save_item(NAME(m_grpmaskb));
+ save_item(NAME(m_grpmaskc));
+ save_item(NAME(m_grpmaskd));
+ save_item(NAME(m_csa));
+ save_item(NAME(m_csb));
+ save_item(NAME(m_csc));
+ save_item(NAME(m_csd));
+
+ save_item(NAME(m_iwr));
+
+ save_item(NAME(m_pasel));
+ save_item(NAME(m_pjdir));
+ save_item(NAME(m_pjdata));
+ save_item(NAME(m_pjsel));
+ save_item(NAME(m_pkdir));
+ save_item(NAME(m_pkdata));
+ save_item(NAME(m_pkpuen));
+ save_item(NAME(m_pksel));
+ save_item(NAME(m_pmdir));
+ save_item(NAME(m_pmdata));
+ save_item(NAME(m_pmpuen));
+ save_item(NAME(m_pmsel));
+
+ save_item(NAME(m_pwmp));
+ save_item(NAME(m_pwmw));
+ save_item(NAME(m_pwmcnt));
+
+ save_item(STRUCT_MEMBER(m_timer_regs, tctl));
+ save_item(STRUCT_MEMBER(m_timer_regs, tprer));
+ save_item(STRUCT_MEMBER(m_timer_regs, tcmp));
+ save_item(STRUCT_MEMBER(m_timer_regs, tcr));
+ save_item(STRUCT_MEMBER(m_timer_regs, tcn));
+ save_item(STRUCT_MEMBER(m_timer_regs, tstat));
+ save_item(STRUCT_MEMBER(m_timer_regs, tclear));
+ save_item(NAME(m_wctlr));
+ save_item(NAME(m_wcmpr));
+ save_item(NAME(m_wcn));
+
+ save_item(NAME(m_spisr));
+
+ save_item(NAME(m_llbar));
+ save_item(NAME(m_lotcr));
+ save_item(NAME(m_lgpmr));
+}
+
+void mc68ez328_device::register_state_save()
+{
+ mc68328_base_device::register_state_save();
+
+ save_item(NAME(m_pwmp));
+ save_item(NAME(m_pwmcnt));
+ save_item(NAME(m_pwmfifo));
+ save_item(NAME(m_pwmfifo_wr));
+ save_item(NAME(m_pwmfifo_rd));
+ save_item(NAME(m_pwmfifo_cnt));
+ save_item(NAME(m_pwm_rep_cnt));
+
+ save_item(STRUCT_MEMBER(m_timer_regs, tctl));
+ save_item(STRUCT_MEMBER(m_timer_regs, tprer));
+ save_item(STRUCT_MEMBER(m_timer_regs, tcmp));
+ save_item(STRUCT_MEMBER(m_timer_regs, tcr));
+ save_item(STRUCT_MEMBER(m_timer_regs, tcn));
+ save_item(STRUCT_MEMBER(m_timer_regs, tstat));
+ save_item(STRUCT_MEMBER(m_timer_regs, tclear));
+
+ save_item(NAME(m_lrra));
+ save_item(NAME(m_pwmr));
+
+ save_item(NAME(m_watchdog));
+ save_item(NAME(m_dayr));
+ save_item(NAME(m_dayalarm));
+ save_item(NAME(m_sam_cnt));
+}
+
+//-------------------------------------------------
+// System control hardware
+//-------------------------------------------------
+
+void mc68328_base_device::scr_w(u8 data) // 0x000
+{
+ LOGMASKED(LOG_SCR, "%s: scr_w: SCR = %02x\n", machine().describe_context(), data);
+}
+
+u8 mc68328_base_device::scr_r() // 0x000
+{
+ LOGMASKED(LOG_SCR, "%s: scr_r: SCR: %02x\n", machine().describe_context(), m_scr);
+ return m_scr;
+}
+
+
+//-------------------------------------------------
+// MMU/chip-select hardware - Standard MC68328
+//-------------------------------------------------
+
+void mc68328_base_device::grpbasea_w(u16 data) // 0x100
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbasea_w: GRPBASEA = %04x\n", machine().describe_context(), data);
+ m_grpbasea = data;
+}
+
+u16 mc68328_base_device::grpbasea_r() // 0x100
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbasea_r: GRPBASEA: %04x\n", machine().describe_context(), m_grpbasea);
+ return m_grpbasea;
+}
+
+void mc68328_base_device::grpbaseb_w(u16 data) // 0x102
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbaseb_w: GRPBASEB = %04x\n", machine().describe_context(), data);
+ m_grpbaseb = data;
+}
+
+u16 mc68328_base_device::grpbaseb_r() // 0x102
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbaseb_r: GRPBASEB: %04x\n", machine().describe_context(), m_grpbaseb);
+ return m_grpbaseb;
+}
+
+void mc68328_base_device::grpbasec_w(u16 data) // 0x104
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbasec_w: GRPBASEC = %04x\n", machine().describe_context(), data);
+ m_grpbasec = data;
+}
+
+u16 mc68328_base_device::grpbasec_r() // 0x104
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbasec_r: GRPBASEC: %04x\n", machine().describe_context(), m_grpbasec);
+ return m_grpbasec;
+}
+
+void mc68328_base_device::grpbased_w(u16 data) // 0x106
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbased_w: GRPBASED = %04x\n", machine().describe_context(), data);
+ m_grpbased = data;
+}
+
+u16 mc68328_base_device::grpbased_r() // 0x106
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpbased_r: GRPBASED: %04x\n", machine().describe_context(), m_grpbased);
+ return m_grpbased;
+}
+
+void mc68328_device::grpmaska_w(u16 data) // 0x108
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaska_w: GRPMASKA = %04x\n", machine().describe_context(), data);
+ m_grpmaska = data;
+}
+
+u16 mc68328_device::grpmaska_r() // 0x108
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaska_r: GRPMASKA: %04x\n", machine().describe_context(), m_grpmaska);
+ return m_grpmaska;
+}
+
+void mc68328_device::grpmaskb_w(u16 data) // 0x10a
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaskb_w: GRPMASKB = %04x\n", machine().describe_context(), data);
+ m_grpmaskb = data;
+}
+
+u16 mc68328_device::grpmaskb_r() // 0x10a
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaskb_r: GRPMASKB: %04x\n", machine().describe_context(), m_grpmaskb);
+ return m_grpmaskb;
+}
+
+void mc68328_device::grpmaskc_w(u16 data) // 0x10c
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaskc_w: GRPMASKC = %04x\n", machine().describe_context(), data);
+ m_grpmaskc = data;
+}
+
+u16 mc68328_device::grpmaskc_r() // 0x10c
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaskc_r: GRPMASKC: %04x\n", machine().describe_context(), m_grpmaskc);
+ return m_grpmaskc;
+}
+
+void mc68328_device::grpmaskd_w(u16 data) // 0x10e
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaskd_w: GRPMASKD = %04x\n", machine().describe_context(), data);
+ m_grpmaskd = data;
+}
+
+u16 mc68328_device::grpmaskd_r() // 0x10e
+{
+ LOGMASKED(LOG_CS_GRP, "%s: grpmaskd_r: GRPMASKD: %04x\n", machine().describe_context(), m_grpmaskd);
+ return m_grpmaskd;
+}
+
+template<int ChipSelect>
+void mc68328_device::csa_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x110, 0x114, 0x118, 0x11c
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csa_msw_w<%d>: CSA%d(16) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csa[ChipSelect] &= 0xffff0000 | (~mem_mask);
+ m_csa[ChipSelect] |= data & mem_mask;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csa_msw_r() // 0x110, 0x120, 0x130, 0x140
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csa_msw_r: CSA%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csa[ChipSelect] >> 16));
+ return (u16)(m_csa[ChipSelect] >> 16);
+}
+
+template<int ChipSelect>
+void mc68328_device::csa_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x112, 0x116, 0x11a, 0x11e
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csa_lsw_w<%d>: CSA%d(0) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csa[ChipSelect] &= ~(mem_mask << 16);
+ m_csa[ChipSelect] |= (data & mem_mask) << 16;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csa_lsw_r() // 0x112, 0x122, 0x132, 0x142
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csa_lsw_r: CSA%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csa[ChipSelect]);
+ return (u16)m_csa[ChipSelect];
+}
+
+template<int ChipSelect>
+void mc68328_device::csb_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x120, 0x124, 0x128, 0x12c
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csb_msw_w<%d>: CSB%d(MSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csb[ChipSelect] &= 0xffff0000 | (~mem_mask);
+ m_csb[ChipSelect] |= data & mem_mask;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csb_msw_r() // 0x114, 0x124, 0x134, 0x144
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csb_msw_r: CSB%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csb[ChipSelect] >> 16));
+ return (u16)(m_csb[ChipSelect] >> 16);
+}
+
+template<int ChipSelect>
+void mc68328_device::csb_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x122, 0x126, 0x12a, 0x12e
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csb_lsw_w<%d>: CSB%d(LSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csb[ChipSelect] &= ~(mem_mask << 16);
+ m_csb[ChipSelect] |= (data & mem_mask) << 16;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csb_lsw_r() // 0x116, 0x126, 0x136, 0x146
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csb_lsw_r: CSB%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csb[ChipSelect]);
+ return (u16)m_csb[ChipSelect];
+}
+
+template<int ChipSelect>
+void mc68328_device::csc_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x130, 0x134, 0x138, 0x13c
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csc_msw_w<%d>: CSC%d(MSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csc[ChipSelect] &= 0xffff0000 | (~mem_mask);
+ m_csc[ChipSelect] |= data & mem_mask;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csc_msw_r() // 0x118, 0x128, 0x138, 0x148
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csc_msw_r: CSC%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csc[ChipSelect] >> 16));
+ return (u16)(m_csc[ChipSelect] >> 16);
+}
+
+template<int ChipSelect>
+void mc68328_device::csc_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x132, 0x136, 0x13a, 0x13e
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csc_lsw_w<%d>: CSC%d(LSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csc[ChipSelect] &= ~(mem_mask << 16);
+ m_csc[ChipSelect] |= (data & mem_mask) << 16;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csc_lsw_r() // 0x11a, 0x12a, 0x13a, 0x14a
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csc_lsw_r: CSC%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csc[ChipSelect]);
+ return (u16)m_csc[ChipSelect];
+}
+
+template<int ChipSelect>
+void mc68328_device::csd_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x140, 0x144, 0x148, 0x14c
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csd_msw_w<%d>: CSD%d(MSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csd[ChipSelect] &= 0xffff0000 | (~mem_mask);
+ m_csd[ChipSelect] |= data & mem_mask;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csd_msw_r() // 0x11c, 0x12c, 0x13c, 0x14c
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csd_msw_r: CSD%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csd[ChipSelect] >> 16));
+ return (u16)(m_csd[ChipSelect] >> 16);
+}
+
+template<int ChipSelect>
+void mc68328_device::csd_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x142, 0x146, 0x14a, 0x14e
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csd_lsw_w<%d>: CSD%d(LSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data);
+ m_csd[ChipSelect] &= ~(mem_mask << 16);
+ m_csd[ChipSelect] |= (data & mem_mask) << 16;
+}
+
+template<int ChipSelect>
+u16 mc68328_device::csd_lsw_r() // 0x11e, 0x12e, 0x13e, 0x14e
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csd_lsw_r: CSD%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csd[ChipSelect]);
+ return (u16)m_csd[ChipSelect];
+}
+
+
+//-------------------------------------------------
+// MMU/chip-select hardware - EZ variant
+//-------------------------------------------------
+
+u8 mc68ez328_device::revision_r(offs_t offset)
+{
+ LOGMASKED(LOG_PLL, "%s: revision_r: Silicon Revision[%d] = %02x\n", machine().describe_context(), offset, 0x01);
+ return 0x01;
+}
+
+void mc68ez328_device::csa_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ static const char *const SIZ_NAMES[8] = { "128K", "256K", "512K", "1M", "2M", "4M", "8M", "16M" };
+ static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" };
+ LOGMASKED(LOG_CS_SEL, "%s: csa_w: CSA = %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8);
+ LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No");
+ LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT));
+ m_csa = data;
+}
+
+u16 mc68ez328_device::csa_r()
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csa_r: CSA: %04x\n", machine().describe_context(), m_csa);
+ return m_csa;
+}
+
+void mc68ez328_device::csb_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ static const char *const SIZ_NAMES[8] = { "128K", "256K", "512K", "1M", "2M", "4M", "8M", "16M" };
+ static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" };
+ LOGMASKED(LOG_CS_SEL, "%s: csb_w: CSB = %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8);
+ LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No");
+ LOGMASKED(LOG_CS_SEL, "%s: Unprotected Block Size: %dK\n", machine().describe_context(), 32 << ((data & CS_UPSIZ_MASK) >> CS_UPSIZ_SHIFT));
+ LOGMASKED(LOG_CS_SEL, "%s: Read-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_ROP_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Supervisor-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_SOP_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT));
+ m_csb = data;
+}
+
+u16 mc68ez328_device::csb_r()
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csb_r: CSB: %04x\n", machine().describe_context(), m_csb);
+ return m_csb;
+}
+
+void mc68ez328_device::csc_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ static const char *const SIZ_NAMES[8] = { "32K", "64K", "128K", "256K", "512K", "1M", "2M", "4M" };
+ static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" };
+ LOGMASKED(LOG_CS_SEL, "%s: csc_w: CSC = %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8);
+ LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No");
+ LOGMASKED(LOG_CS_SEL, "%s: Unprotected Block Size: %dK\n", machine().describe_context(), 32 << ((data & CS_UPSIZ_MASK) >> CS_UPSIZ_SHIFT));
+ LOGMASKED(LOG_CS_SEL, "%s: Read-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_ROP_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Supervisor-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_SOP_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT));
+ m_csc = data;
+}
+
+u16 mc68ez328_device::csc_r()
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csc_r: CSC: %04x\n", machine().describe_context(), m_csc);
+ return m_csc;
+}
+
+void mc68ez328_device::csd_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ static const char *const SIZ_NAMES[8] = { "32K", "64K", "128K", "256K", "512K", "1M", "2M", "4M" };
+ static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" };
+ LOGMASKED(LOG_CS_SEL, "%s: csd_w: CSD = %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]);
+ LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8);
+ LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No");
+ LOGMASKED(LOG_CS_SEL, "%s: DRAM Selection: %s\n", machine().describe_context(), BIT(data, CS_DRAM_BIT) ? "Select /CAS and /RAS" : "Select /CSC[1:0] and /CSD[1:0]");
+ LOGMASKED(LOG_CS_SEL, "%s: Use /RAS0 for /RAS1: %s\n", machine().describe_context(), BIT(data, CS_COMB_BIT) ? "Yes" : "No");
+ LOGMASKED(LOG_CS_SEL, "%s: Unprotected Block Size: %dK\n", machine().describe_context(), 32 << ((data & CS_UPSIZ_MASK) >> CS_UPSIZ_SHIFT));
+ LOGMASKED(LOG_CS_SEL, "%s: Read-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_ROP_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Supervisor-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_SOP_BIT));
+ LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT));
+ m_csd = data;
+}
+
+u16 mc68ez328_device::csd_r()
+{
+ LOGMASKED(LOG_CS_SEL, "%s: csd_r: CSD: %04x\n", machine().describe_context(), m_csd);
+ return m_csd;
+}
+
+void mc68ez328_device::emucs_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" };
+ LOGMASKED(LOG_CS_SEL, "%s: emucs_w: EMUCS = %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]);
+ m_emucs = data;
+}
+
+u16 mc68ez328_device::emucs_r()
+{
+ LOGMASKED(LOG_CS_SEL, "%s: emucs_r: EMUCS: %04x\n", machine().describe_context(), m_emucs);
+ return m_emucs;
+}
+
+
+//-------------------------------------------------
+// PLL/power hardware
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(mc68328_base_device::refclk_tick)
+{
+ m_pllfsr ^= 0x8000;
+}
+
+void mc68328_base_device::pllcr_w(u16 data) // 0x200
+{
+ LOGMASKED(LOG_PLL, "%s: pllcr_w: PLLCR = %04x\n", machine().describe_context(), data);
+ m_pllcr = data;
+}
+
+u16 mc68328_base_device::pllcr_r() // 0x200
+{
+ LOGMASKED(LOG_PLL, "%s: pllcr_r: PLLCR: %04x\n", machine().describe_context(), m_pllcr);
+ return m_pllcr;
+}
+
+void mc68328_base_device::pllfsr_w(u16 data) // 0x202
+{
+ LOGMASKED(LOG_PLL, "%s: pllfsr_w: PLLFSR = %04x\n", machine().describe_context(), data);
+ m_pllfsr = data;
+}
+
+u16 mc68328_base_device::pllfsr_r() // 0x202
+{
+ LOGMASKED(LOG_PLL, "%s: pllfsr_r: PLLFSR: %04x\n", machine().describe_context(), m_pllfsr);
+ return m_pllfsr;
+}
+
+void mc68328_base_device::pctlr_w(u8 data) // 0x207
+{
+ LOGMASKED(LOG_PLL, "%s: pctlr_w: PCTLR = %02x\n", machine().describe_context(), data);
+ m_pctlr = data;
+}
+
+u8 mc68328_base_device::pctlr_r() // 0x207
+{
+ LOGMASKED(LOG_PLL, "%s: pctlr_r: PCTLR: %02x\n", machine().describe_context(), m_pctlr);
+ return m_pctlr;
+}
+
+
+//-------------------------------------------------
+// Interrupt-related hardware - standard MC68328
+//-------------------------------------------------
+
+void mc68328_base_device::update_ipr_state(u32 changed_mask)
+{
+ const int irq_level = get_irq_level_for_mask(changed_mask);
+ const u32 irq_mask = get_irq_mask_for_level(irq_level);
+
+ if (!irq_level || !irq_mask)
{
- m_regs.ipr |= line;
+ return;
+ }
- if (!(m_regs.imr & line) && !(m_regs.isr & line))
+ if (m_ipr & changed_mask)
+ {
+ // If a pending interrupt has changed, it's not masked, and it's not currently in service, raise the corresponding 68k IRQ line and mark it as
+ // in-service.
+ if ((~m_imr & irq_mask) && !(m_gisr & changed_mask))
{
- m_regs.isr |= line;
-
- if (m_regs.isr & INT_M68K_LINE7)
- {
- set_input_line(M68K_IRQ_7, ASSERT_LINE);
- }
- else if (m_regs.isr & INT_M68K_LINE6)
- {
- set_input_line(M68K_IRQ_6, ASSERT_LINE);
- }
- else if (m_regs.isr & INT_M68K_LINE5)
- {
- set_input_line(M68K_IRQ_5, ASSERT_LINE);
- }
- else if (m_regs.isr & INT_M68K_LINE4)
- {
- set_input_line(M68K_IRQ_4, ASSERT_LINE);
- }
- else if (m_regs.isr & INT_M68K_LINE3)
- {
- set_input_line(M68K_IRQ_3, ASSERT_LINE);
- }
- else if (m_regs.isr & INT_M68K_LINE2)
- {
- set_input_line(M68K_IRQ_2, ASSERT_LINE);
- }
- else if (m_regs.isr & INT_M68K_LINE1)
- {
- set_input_line(M68K_IRQ_1, ASSERT_LINE);
- }
+ m_gisr |= changed_mask;
+ set_input_line(irq_level, ASSERT_LINE);
}
}
else
{
- m_regs.isr &= ~line;
+ m_gisr &= ~changed_mask;
- if ((line & INT_M68K_LINE7) && !(m_regs.isr & INT_M68K_LINE7))
+ // If there are no other pending, unmasked interrupts at this level, lower the corresponding 68k IRQ line.
+ if (!(m_ipr & ~m_imr & irq_mask))
{
- set_input_line(M68K_IRQ_7, CLEAR_LINE);
+ set_input_line(irq_level, CLEAR_LINE);
}
- if ((line & INT_M68K_LINE6) && !(m_regs.isr & INT_M68K_LINE6))
- {
- set_input_line(M68K_IRQ_6, CLEAR_LINE);
- }
- if ((line & INT_M68K_LINE5) && !(m_regs.isr & INT_M68K_LINE5))
- {
- set_input_line(M68K_IRQ_5, CLEAR_LINE);
- }
- if ((line & INT_M68K_LINE4) && !(m_regs.isr & INT_M68K_LINE4))
- {
- set_input_line(M68K_IRQ_4, CLEAR_LINE);
- }
- if ((line & INT_M68K_LINE3) && !(m_regs.isr & INT_M68K_LINE3))
- {
- set_input_line(M68K_IRQ_3, CLEAR_LINE);
- }
- if ((line & INT_M68K_LINE2) && !(m_regs.isr & INT_M68K_LINE2))
+ }
+}
+
+void mc68328_base_device::update_imr_state(u32 changed_mask)
+{
+ int irq_level = get_irq_level_for_mask(changed_mask);
+ u32 irq_mask = get_irq_mask_for_level(irq_level);
+ u32 level_mask = irq_mask & changed_mask;
+
+ while (irq_level && irq_mask)
+ {
+ if (m_ipr & ~m_gisr & ~m_imr & level_mask)
{
- set_input_line(M68K_IRQ_2, CLEAR_LINE);
+ // If a newly-unmasked interrupt is pending and not currently in-service, raise the relevant line.
+ m_gisr |= level_mask;
+ set_input_line(irq_level, ASSERT_LINE);
}
- if ((line & INT_M68K_LINE1) && !(m_regs.isr & INT_M68K_LINE1))
+ else if (m_gisr & m_imr & level_mask)
{
- set_input_line(M68K_IRQ_1, CLEAR_LINE);
+ // If a newly-masked interrupt is in-service, lower the relevant line.
+ set_input_line(irq_level, CLEAR_LINE);
}
+
+ changed_mask &= ~irq_mask;
+ irq_level = get_irq_level_for_mask(changed_mask);
+ irq_mask = get_irq_mask_for_level(irq_level);
+ level_mask = irq_mask & changed_mask;
}
}
-void mc68328_device::poll_port_d_interrupts()
+void mc68328_base_device::set_interrupt_line(u32 line, u32 active)
{
- uint8_t line_transitions = m_regs.pddataedge & m_regs.pdirqedge;
- uint8_t line_holds = m_regs.pddata &~ m_regs.pdirqedge;
- uint8_t line_interrupts = (line_transitions | line_holds) & m_regs.pdirqen;
+ const u32 mask = 1 << line;
- if (line_interrupts)
+ if (active)
{
- set_interrupt_line(line_interrupts << 8, 1);
+ m_ipr |= mask;
}
else
{
- set_interrupt_line(INT_KBDINTS, 0);
+ m_ipr &= ~mask;
}
+
+ update_ipr_state(mask);
}
-WRITE_LINE_MEMBER( mc68328_device::set_penirq_line )
+int mc68328_device::get_irq_level_for_mask(u32 mask)
{
- if (state)
+ constexpr u32 IRQ_MASKS[8] =
{
- set_interrupt_line(INT_PEN, 1);
- }
- else
+ 0,
+ INT_IRQ1_MASK,
+ INT_IRQ2_MASK,
+ INT_IRQ3_MASK,
+ INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK
+ | INT_PWM_MASK | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_TIMER2_MASK | INT_SPIM_MASK,
+ INT_IRQ5_MASK,
+ INT_IRQ6_MASK | INT_TIMER1_MASK | INT_SPIS_MASK,
+ INT_IRQ7_MASK
+ };
+
+ for (int level = 7; level >= 1; level--)
{
- m_regs.ipr &= ~INT_PEN;
- set_interrupt_line(INT_PEN, 0);
+ if (IRQ_MASKS[level] & mask)
+ {
+ return level;
+ }
}
+ return 0;
}
-void mc68328_device::set_port_d_lines(uint8_t state, int bit)
+u32 mc68328_device::get_irq_mask_for_level(int level)
{
- uint8_t old_button_state = m_regs.pddata;
-
- if (state & (1 << bit))
+ constexpr u32 IRQ_MASKS[8] =
{
- m_regs.pddata |= (1 << bit);
- }
- else
+ 0,
+ INT_IRQ1_MASK,
+ INT_IRQ2_MASK,
+ INT_IRQ3_MASK,
+ INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK
+ | INT_PWM_MASK | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_TIMER2_MASK | INT_SPIM_MASK,
+ INT_IRQ5_MASK,
+ INT_IRQ6_MASK | INT_TIMER1_MASK | INT_SPIS_MASK,
+ INT_IRQ7_MASK
+ };
+ if (level >= 0 && level <= 7)
{
- m_regs.pddata &= ~(1 << bit);
+ return IRQ_MASKS[level];
}
+ return 0;
+}
- m_regs.pddataedge |= ~old_button_state & m_regs.pddata;
+void mc68328_base_device::irq5_w(int state)
+{
+ set_interrupt_line(INT_IRQ5, state);
+}
- poll_port_d_interrupts();
+u8 mc68328_base_device::irq_callback(offs_t offset)
+{
+ return m_ivr | offset;
}
-uint8_t mc68328_device::irq_callback(offs_t offset)
+void mc68328_base_device::ivr_w(u8 data) // 0x300
{
- return m_regs.ivr | offset;
+ LOGMASKED(LOG_INTS, "%s: ivr_w: IVR = %02x\n", machine().describe_context(), data);
+ m_ivr = data;
}
-uint32_t mc68328_device::get_timer_frequency(uint32_t index)
+u8 mc68328_base_device::ivr_r() // 0x300
{
- uint32_t frequency = 0;
+ LOGMASKED(LOG_INTS, "%s: ivr_r: IVR: %02x\n", machine().describe_context(), m_ivr);
+ return m_ivr;
+}
- switch (m_regs.tctl[index] & TCTL_CLKSOURCE)
- {
- case TCTL_CLKSOURCE_SYSCLK:
- frequency = 32768 * 506;
- break;
+void mc68328_base_device::icr_w(u8 data) // 0x302
+{
+ LOGMASKED(LOG_INTS, "%s: icr_w: ICR = %02x\n", machine().describe_context(), data);
+ m_icr = data;
+}
- case TCTL_CLKSOURCE_SYSCLK16:
- frequency = (32768 * 506) / 16;
- break;
+u16 mc68328_base_device::icr_r() // 0x302
+{
+ LOGMASKED(LOG_INTS, "%s: icr_r: ICR: %04x\n", machine().describe_context(), m_icr);
+ return m_icr;
+}
- case TCTL_CLKSOURCE_32KHZ4:
- case TCTL_CLKSOURCE_32KHZ5:
- case TCTL_CLKSOURCE_32KHZ6:
- case TCTL_CLKSOURCE_32KHZ7:
- frequency = 32768;
- break;
- }
- frequency /= (m_regs.tprer[index] + 1);
+void mc68328_base_device::imr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x304
+{
+ const u32 imr_old = m_imr;
+ LOGMASKED(LOG_INTS, "%s: imr_msw_w: IMR(MSW) = %04x\n", machine().describe_context(), data);
+ m_imr &= ~(mem_mask << 16);
+ m_imr |= (data & mem_mask) << 16;
- return frequency;
+ update_imr_state(imr_old ^ m_imr);
}
-void mc68328_device::maybe_start_timer(uint32_t index, uint32_t new_enable)
+u16 mc68328_base_device::imr_msw_r() // 0x304
{
- if ((m_regs.tctl[index] & TCTL_TEN) == TCTL_TEN_ENABLE && (m_regs.tctl[index] & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP)
- {
- if ((m_regs.tctl[index] & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN)
- {
- m_gptimer[index]->adjust(attotime::never);
- }
- else if (m_regs.tcmp[index] == 0)
- {
- m_gptimer[index]->adjust(attotime::never);
- }
- else
- {
- uint32_t frequency = get_timer_frequency(index);
- attotime period = (attotime::from_hz(frequency) * m_regs.tcmp[index]);
+ LOGMASKED(LOG_INTS, "%s: imr_msw_r: IMR(MSW): %04x\n", machine().describe_context(), (u16)(m_imr >> 16));
+ return (u16)(m_imr >> 16);
+}
- if (new_enable)
- {
- m_regs.tcn[index] = 0x0000;
- }
+void mc68328_base_device::imr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x306
+{
+ const u32 imr_old = m_imr;
+ LOGMASKED(LOG_INTS, "%s: imr_lsw_w: IMR(LSW) = %04x\n", machine().describe_context(), data);
+ m_imr &= 0xffff0000 | (~mem_mask);
+ m_imr |= data & mem_mask;
- m_gptimer[index]->adjust(period);
- }
- }
- else
- {
- m_gptimer[index]->adjust(attotime::never);
- }
+ update_imr_state(imr_old ^ m_imr);
}
-void mc68328_device::timer_compare_event(uint32_t index)
+u16 mc68328_base_device::imr_lsw_r() // 0x306
{
- m_regs.tcn[index] = m_regs.tcmp[index];
- m_regs.tstat[index] |= TSTAT_COMP;
+ LOGMASKED(LOG_INTS, "%s: imr_lsw_r: IMR(LSW): %04x\n", machine().describe_context(), (u16)m_imr);
+ return (u16)m_imr;
+}
- if ((m_regs.tctl[index] & TCTL_FRR) == TCTL_FRR_RESTART)
- {
- uint32_t frequency = get_timer_frequency(index);
+void mc68328_device::iwr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x308
+{
+ LOGMASKED(LOG_INTS, "%s: iwr_msw_w: IWR(MSW) = %04x\n", machine().describe_context(), data);
+ m_iwr &= ~(mem_mask << 16);
+ m_iwr |= (data & mem_mask) << 16;
+}
- if (frequency > 0)
- {
- attotime period = attotime::from_hz(frequency) * m_regs.tcmp[index];
+u16 mc68328_device::iwr_msw_r() // 0x308
+{
+ LOGMASKED(LOG_INTS, "%s: iwr_msw_r: IWR(MSW): %04x\n", machine().describe_context(), (u16)(m_iwr >> 16));
+ return (u16)(m_iwr >> 16);
+}
- m_regs.tcn[index] = 0x0000;
+void mc68328_device::iwr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x30a
+{
+ LOGMASKED(LOG_INTS, "%s: iwr_lsw_w: IWR(LSW) = %04x\n", machine().describe_context(), data);
+ m_iwr &= 0xffff0000 | (~mem_mask);
+ m_iwr |= data & mem_mask;
+}
- m_gptimer[index]->adjust(period);
- }
- else
- {
- m_gptimer[index]->adjust(attotime::never);
- }
+u16 mc68328_device::iwr_lsw_r() // 0x30a
+{
+ LOGMASKED(LOG_INTS, "%s: iwr_lsw_r: IWR(LSW): %04x\n", machine().describe_context(), (u16)m_iwr);
+ return (u16)m_iwr;
+}
+
+void mc68328_base_device::isr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x30c
+{
+ LOGMASKED(LOG_INTS, "%s: isr_msw_w: ISR(MSW) = %04x\n", machine().describe_context(), data);
+ // Clear edge-triggered IRQ1
+ if ((m_icr & ICR_ET1) == ICR_ET1 && ((data << 16) & INT_IRQ1_MASK) == INT_IRQ1_MASK)
+ {
+ m_gisr &= ~INT_IRQ1_MASK;
}
- else
+
+ // Clear edge-triggered IRQ2
+ if ((m_icr & ICR_ET2) == ICR_ET2 && ((data << 16) & INT_IRQ2_MASK) == INT_IRQ2_MASK)
{
- uint32_t frequency = get_timer_frequency(index);
+ m_gisr &= ~INT_IRQ2_MASK;
+ }
- if (frequency > 0)
- {
- attotime period = attotime::from_hz(frequency) * 0x10000;
+ // Clear edge-triggered IRQ3
+ if ((m_icr & ICR_ET3) == ICR_ET3 && ((data << 16) & INT_IRQ3_MASK) == INT_IRQ3_MASK)
+ {
+ m_gisr &= ~INT_IRQ3_MASK;
+ }
- m_gptimer[index]->adjust(period);
- }
- else
- {
- m_gptimer[index]->adjust(attotime::never);
- }
+ // Clear edge-triggered IRQ6
+ if ((m_icr & ICR_ET6) == ICR_ET6 && ((data << 16) & INT_IRQ6_MASK) == INT_IRQ6_MASK)
+ {
+ m_gisr &= ~INT_IRQ6_MASK;
}
- if ((m_regs.tctl[index] & TCTL_IRQEN) == TCTL_IRQEN_ENABLE)
+
+ // Clear edge-triggered IRQ7
+ if (((data << 16) & INT_IRQ7_MASK) == INT_IRQ7_MASK)
{
- set_interrupt_line((index == 0) ? INT_TIMER1 : INT_TIMER2, 1);
+ m_gisr &= ~INT_IRQ7_MASK;
}
}
-TIMER_CALLBACK_MEMBER( mc68328_device::timer1_hit )
+u16 mc68328_base_device::isr_msw_r() // 0x30c
{
- timer_compare_event(0);
+ LOGMASKED(LOG_INTS, "%s: isr_msw_r: ISR(MSW): %04x\n", machine().describe_context(), (u16)(m_gisr >> 16));
+ return (u16)(m_gisr >> 16);
}
-TIMER_CALLBACK_MEMBER( mc68328_device::timer2_hit )
+void mc68328_base_device::isr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x30e
{
- timer_compare_event(1);
+ LOGMASKED(LOG_INTS, "%s: isr_lsw_w: ISR(LSW) = %04x (Ignored)\n", machine().describe_context(), data);
}
-TIMER_CALLBACK_MEMBER( mc68328_device::pwm_transition )
+u16 mc68328_base_device::isr_lsw_r() // 0x30e
{
- if (m_regs.pwmw >= m_regs.pwmp || m_regs.pwmw == 0 || m_regs.pwmp == 0)
- {
- m_pwm->adjust(attotime::never);
- return;
- }
+ LOGMASKED(LOG_INTS, "%s: isr_lsw_r: ISR(LSW): %04x\n", machine().describe_context(), (u16)m_gisr);
+ return (u16)m_gisr;
+}
- if (((m_regs.pwmc & PWMC_POL) == 0 && (m_regs.pwmc & PWMC_PIN) != 0) ||
- ((m_regs.pwmc & PWMC_POL) != 0 && (m_regs.pwmc & PWMC_PIN) == 0))
- {
- uint32_t frequency = 32768 * 506;
- uint32_t divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot.
- attotime period;
+void mc68328_base_device::ipr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x310
+{
+ LOGMASKED(LOG_INTS, "%s: ipr_msw_w: IPR(MSW) = %04x (Ignored)\n", machine().describe_context(), data);
+}
- frequency /= divisor;
- period = attotime::from_hz(frequency) * (m_regs.pwmp - m_regs.pwmw);
+u16 mc68328_base_device::ipr_msw_r() // 0x310
+{
+ LOGMASKED(LOG_INTS, "%s: ipr_msw_r: IPR(MSW): %04x\n", machine().describe_context(), (u16)(m_ipr >> 16));
+ return (u16)(m_ipr >> 16);
+}
- m_pwm->adjust(period);
+void mc68328_base_device::ipr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x312
+{
+ LOGMASKED(LOG_INTS, "%s: ipr_lsw_w: IPR(LSW) = %04x (Ignored)\n", machine().describe_context(), data);
+}
+
+u16 mc68328_base_device::ipr_lsw_r() // 0x312
+{
+ LOGMASKED(LOG_INTS, "%s: ipr_lsw_r: IPR(LSW): %04x\n", machine().describe_context(), (u16)m_ipr);
+ return (u16)m_ipr;
+}
+
+
+//-------------------------------------------------
+// Interrupt-related hardware - EZ variant
+//-------------------------------------------------
- if (m_regs.pwmc & PWMC_IRQEN)
+int mc68ez328_device::get_irq_level_for_mask(u32 mask)
+{
+ constexpr u32 IRQ_MASKS[8] =
+ {
+ 0,
+ INT_IRQ1_MASK,
+ INT_IRQ2_MASK,
+ INT_IRQ3_MASK,
+ INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK
+ | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_SPIM_MASK,
+ INT_IRQ5_MASK,
+ INT_PWM_MASK | INT_TIMER2_MASK | INT_SPIS_MASK,
+ INT_MEMIQ_MASK,
+ };
+
+ for (int level = 1; level <= 7; level++)
+ {
+ if (IRQ_MASKS[level] & mask)
{
- set_interrupt_line(INT_PWM, 1);
+ return level;
}
}
- else
+ return 0;
+}
+
+u32 mc68ez328_device::get_irq_mask_for_level(int level)
+{
+ constexpr u32 IRQ_MASKS[8] =
{
- uint32_t frequency = 32768 * 506;
- uint32_t divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot.
- attotime period;
+ 0,
+ INT_IRQ1_MASK,
+ INT_IRQ2_MASK,
+ INT_IRQ3_MASK,
+ INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK
+ | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_SPIM_MASK,
+ INT_IRQ5_MASK,
+ INT_PWM_MASK | INT_TIMER2_MASK | INT_SPIS_MASK,
+ INT_MEMIQ_MASK,
+ };
+ if (level >= 0 && level <= 7)
+ {
+ return IRQ_MASKS[level];
+ }
+ return 0;
+}
- frequency /= divisor;
- period = attotime::from_hz(frequency) * m_regs.pwmw;
- m_pwm->adjust(period);
- }
+//-------------------------------------------------
+// GPIO hardware - Port A
+//-------------------------------------------------
- m_regs.pwmc ^= PWMC_PIN;
+void mc68328_base_device::padir_w(u8 data) // 0x400
+{
+ LOGMASKED(LOG_GPIO_A, "%s: padir_w: PADIR = %02x\n", machine().describe_context(), data);
+ m_padir = data;
+}
- if (!m_out_pwm_cb.isnull())
- {
- m_out_pwm_cb((offs_t)0, (m_regs.pwmc & PWMC_PIN) ? 1 : 0);
- }
+u8 mc68328_base_device::padir_r() // 0x400
+{
+ LOGMASKED(LOG_GPIO_A, "%s: mc68328_r: PADIR: %02x\n", machine().describe_context(), m_padir);
+ return m_padir;
}
-TIMER_CALLBACK_MEMBER( mc68328_device::rtc_tick )
+void mc68328_base_device::padata_w(u8 data) // 0x401
{
- if (m_regs.rtcctl & RTCCTL_ENABLE)
+ LOGMASKED(LOG_GPIO_A, "%s: padata_w: PADATA = %02x\n", machine().describe_context(), data);
+ m_padata = data;
+ for (int i = 0; i < 8; i++)
{
- uint32_t set_int = 0;
-
- m_regs.hmsr++;
-
- if (m_regs.rtcienr & RTCINT_SECOND)
+ if (BIT(m_padir & m_pasel, i))
{
- set_int = 1;
- m_regs.rtcisr |= RTCINT_SECOND;
+ m_out_port_a_cb[i](BIT(m_padata, i));
}
+ }
+}
- if ((m_regs.hmsr & 0x0000003f) == 0x0000003c)
+u8 mc68328_base_device::padata_r() // 0x401
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pasel, i))
{
- m_regs.hmsr &= 0xffffffc0;
- m_regs.hmsr += 0x00010000;
-
- if (m_regs.rtcienr & RTCINT_MINUTE)
+ if (BIT(m_padir, i))
{
- set_int = 1;
- m_regs.rtcisr |= RTCINT_MINUTE;
+ data |= m_padata & (1 << i);
}
-
- if ((m_regs.hmsr & 0x003f0000) == 0x003c0000)
+ else if (!m_in_port_a_cb[i].isunset())
{
- m_regs.hmsr &= 0xffc0ffff;
- m_regs.hmsr += 0x0100000;
+ data |= m_in_port_a_cb[i]() << i;
+ }
+ }
+ }
+ LOGMASKED(LOG_GPIO_A, "%s: padata_r: PADATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- if ((m_regs.hmsr & 0x1f000000) == 0x18000000)
- {
- m_regs.hmsr &= 0xe0ffffff;
+void mc68328_device::pasel_w(u8 data) // 0x403
+{
+ LOGMASKED(LOG_GPIO_A, "%s: pasel_w: PASEL = %02x\n", machine().describe_context(), data);
+ m_pasel = data;
+}
- if (m_regs.rtcienr & RTCINT_DAY)
- {
- set_int = 1;
- m_regs.rtcisr |= RTCINT_DAY;
- }
- }
- }
+u8 mc68328_device::pasel_r() // 0x403
+{
+ LOGMASKED(LOG_GPIO_A, "%s: mc68328_r: PASEL: %02x\n", machine().describe_context(), m_pasel);
+ return m_pasel;
+}
- if (m_regs.stpwtch != 0x003f)
- {
- m_regs.stpwtch--;
- m_regs.stpwtch &= 0x003f;
- if (m_regs.stpwtch == 0x003f)
- {
- if (m_regs.rtcienr & RTCINT_STOPWATCH)
- {
- set_int = 1;
- m_regs.rtcisr |= RTCINT_STOPWATCH;
- }
- }
- }
+//-------------------------------------------------
+// GPIO hardware - Port B
+//-------------------------------------------------
+
+void mc68328_base_device::pbdir_w(u8 data) // 0x408
+{
+ LOGMASKED(LOG_GPIO_B, "%s: pbdir_w: PBDIR = %02x\n", machine().describe_context(), data);
+ m_pbdir = data;
+}
+
+u8 mc68328_base_device::pbdir_r() // 0x408
+{
+ LOGMASKED(LOG_GPIO_B, "%s: pbdir_r: PBDIR: %02x\n", machine().describe_context(), m_pbdir);
+ return m_pbdir;
+}
+
+void mc68328_base_device::pbdata_w(u8 data) // 0x409
+{
+ LOGMASKED(LOG_GPIO_B, "%s: pbdata_w: PBDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pbdir & m_pbsel);
+ m_pbdata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pbdir & m_pbsel, i))
+ {
+ m_out_port_b_cb[i](BIT(m_pbdata, i));
}
+ }
+}
- if (m_regs.hmsr == m_regs.alarm)
+u8 mc68328_base_device::pbdata_r() // 0x409
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pbsel, i))
{
- if (m_regs.rtcienr & RTCINT_ALARM)
+ if (BIT(m_pbdir, i))
{
- set_int = 1;
- m_regs.rtcisr |= RTCINT_STOPWATCH;
+ data |= m_pbdata & (1 << i);
+ }
+ else if (!m_in_port_b_cb[i].isunset())
+ {
+ data |= m_in_port_b_cb[i]() << i;
}
}
+ }
+ LOGMASKED(LOG_GPIO_B, "%s: pbdata_r: PBDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- if (set_int)
+void mc68328_base_device::pbsel_w(u8 data) // 0x40b
+{
+ LOGMASKED(LOG_GPIO_B, "%s: pbsel_w: PBSEL = %02x\n", machine().describe_context(), data);
+ m_pbsel = data;
+}
+
+u8 mc68328_base_device::pbsel_r() // 0x40b
+{
+ LOGMASKED(LOG_GPIO_B, "%s: pbsel_r: PBSEL: %02x\n", machine().describe_context(), m_pbsel);
+ return m_pbsel;
+}
+
+
+//-------------------------------------------------
+// GPIO hardware - Port C
+//-------------------------------------------------
+
+void mc68328_base_device::pcdir_w(u8 data) // 0x410
+{
+ LOGMASKED(LOG_GPIO_C, "%s: pcdir_w: PCDIR = %02x\n", machine().describe_context(), data);
+ m_pcdir = data;
+}
+
+u8 mc68328_base_device::pcdir_r() // 0x410
+{
+ LOGMASKED(LOG_GPIO_C, "%s: pcdir_r: PCDIR: %02x\n", machine().describe_context(), m_pcdir);
+ return m_pcdir;
+}
+
+void mc68328_base_device::pcdata_w(u8 data) // 0x411
+{
+ LOGMASKED(LOG_GPIO_C, "%s: pcdata_w: PCDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pcdir & m_pcsel);
+ m_pcdata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pcdir & m_pcsel, i))
{
- set_interrupt_line(INT_RTC, 1);
+ m_out_port_c_cb[i](BIT(m_pcdata, i));
}
- else
+ else if (BIT(~m_pcdir & m_pcsel, i))
{
- set_interrupt_line(INT_RTC, 0);
+ m_out_port_c_cb[i](1);
}
}
}
-void mc68328_device::internal_write(offs_t offset, uint16_t data, uint16_t mem_mask)
+u8 mc68328_base_device::pcdata_r() // 0x411
{
- uint32_t address = offset << 1;
- uint16_t temp16[4] = { 0 };
- uint32_t imr_old = m_regs.imr, imr_diff;
-
- switch (address)
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
{
- case 0x000:
- if (mem_mask & 0x00ff)
+ if (BIT(m_pcsel, i))
+ {
+ if (BIT(m_pcdir, i))
{
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff001) = %02x\n", data & 0x00ff);
+ data |= m_pcdata & (1 << i);
}
- else
+ else if (!m_in_port_c_cb[i].isunset())
{
- verboselog( *this, 2, "mc68328_w: SCR = %02x\n", (data >> 8) & 0x00ff);
+ data |= m_in_port_c_cb[i]() << i;
}
- break;
-
- case 0x100:
- verboselog( *this, 2, "mc68328_w: GRPBASEA = %04x\n", data);
- m_regs.grpbasea = data;
- break;
-
- case 0x102:
- verboselog( *this, 2, "mc68328_w: GRPBASEB = %04x\n", data);
- m_regs.grpbaseb = data;
- break;
-
- case 0x104:
- verboselog( *this, 2, "mc68328_w: GRPBASEC = %04x\n", data);
- m_regs.grpbasec = data;
- break;
-
- case 0x106:
- verboselog( *this, 2, "mc68328_w: GRPBASED = %04x\n", data);
- m_regs.grpbased = data;
- break;
-
- case 0x108:
- verboselog( *this, 2, "mc68328_w: GRPMASKA = %04x\n", data);
- m_regs.grpmaska = data;
- break;
+ }
+ }
+ LOGMASKED(LOG_GPIO_C, "%s: pcdata_r: PCDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x10a:
- verboselog( *this, 2, "mc68328_w: GRPMASKB = %04x\n", data);
- m_regs.grpmaskb = data;
- break;
+void mc68328_base_device::pcsel_w(u8 data) // 0x413
+{
+ LOGMASKED(LOG_GPIO_C, "%s: pcsel_w: PCSEL = %02x\n", machine().describe_context(), data);
+ m_pcsel = data;
+}
- case 0x10c:
- verboselog( *this, 2, "mc68328_w: GRPMASKC = %04x\n", data);
- m_regs.grpmaskc = data;
- break;
+u8 mc68328_base_device::pcsel_r() // 0x413
+{
+ LOGMASKED(LOG_GPIO_C, "%s: pcsel_r: PCSEL: %02x\n", machine().describe_context(), m_pcsel);
+ return m_pcsel;
+}
- case 0x10e:
- verboselog( *this, 2, "mc68328_w: GRPMASKD = %04x\n", data);
- m_regs.grpmaskd = data;
- break;
- case 0x110:
- verboselog( *this, 5, "mc68328_w: CSA0(0) = %04x\n", data);
- m_regs.csa0 &= 0xffff0000 | (~mem_mask);
- m_regs.csa0 |= data & mem_mask;
- break;
+//-------------------------------------------------
+// GPIO hardware - Port D
+//-------------------------------------------------
- case 0x112:
- verboselog( *this, 5, "mc68328_w: CSA0(16) = %04x\n", data);
- m_regs.csa0 &= ~(mem_mask << 16);
- m_regs.csa0 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::port_d_in_w(int state, int bit)
+{
+ const u8 old_state = m_pdindata;
+ m_pdindata &= ~(1 << bit);
+ m_pdindata |= state << bit;
- case 0x114:
- verboselog( *this, 5, "mc68328_w: CSA1(0) = %04x\n", data);
- m_regs.csa1 &= 0xffff0000 | (~mem_mask);
- m_regs.csa1 |= data & mem_mask;
- break;
+ // If no bit has changed state, there's nothing to do.
+ if (old_state == m_pdindata)
+ {
+ return;
+ }
- case 0x116:
- verboselog( *this, 5, "mc68328_w: CSA1(16) = %04x\n", data);
- m_regs.csa1 &= ~(mem_mask << 16);
- m_regs.csa1 |= (data & mem_mask) << 16;
- break;
+ // If we're not edge-triggered, handle potential level-sensitive interrupts.
+ if (!BIT(m_pdirqedge, bit))
+ {
+ // If the new state is low while PDPOL is active-low (0) or vice-versa, assert the interrupt for this bit.
+ // Otherwise, clear it.
+ set_interrupt_line(INT_KBDINTS + bit, (int)(state == BIT(m_pdpol, bit)));
+ return;
+ }
- case 0x118:
- verboselog( *this, 5, "mc68328_w: CSA2(0) = %04x\n", data);
- m_regs.csa2 &= 0xffff0000 | (~mem_mask);
- m_regs.csa2 |= data & mem_mask;
- break;
+ set_interrupt_line(INT_KBDINTS + bit, 1);
+}
- case 0x11a:
- verboselog( *this, 5, "mc68328_w: CSA2(16) = %04x\n", data);
- m_regs.csa2 &= ~(mem_mask << 16);
- m_regs.csa2 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pddir_w(u8 data) // 0x418
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pddir_w: PDDIR = %02x\n", machine().describe_context(), data);
+ m_pddir = data;
+}
- case 0x11c:
- verboselog( *this, 5, "mc68328_w: CSA3(0) = %04x\n", data);
- m_regs.csa3 &= 0xffff0000 | (~mem_mask);
- m_regs.csa3 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pddir_r() // 0x418
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pddir_r: PDDIR: %02x\n", machine().describe_context(), m_pddir);
+ return m_pddir;
+}
- case 0x11e:
- verboselog( *this, 5, "mc68328_w: CSA3(16) = %04x\n", data);
- m_regs.csa3 &= ~(mem_mask << 16);
- m_regs.csa3 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pddata_w(u8 data) // 0x419
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pddata_w: PDDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pddir);
+ m_pddata = data;
- case 0x120:
- verboselog( *this, 5, "mc68328_w: CSB0(0) = %04x\n", data);
- m_regs.csb0 &= 0xffff0000 | (~mem_mask);
- m_regs.csb0 |= data & mem_mask;
- break;
+ for (int bit = 0; bit < 4; bit++)
+ {
+ if (BIT(m_pdirqedge & data, bit))
+ {
+ set_interrupt_line(INT_KBDINTS + bit, 0);
+ }
+ }
- case 0x122:
- verboselog( *this, 5, "mc68328_w: CSB0(16) = %04x\n", data);
- m_regs.csb0 &= ~(mem_mask << 16);
- m_regs.csb0 |= (data & mem_mask) << 16;
- break;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pddir, i))
+ {
+ m_out_port_d_cb[i](BIT(m_pddata, i));
+ }
+ }
+}
- case 0x124:
- verboselog( *this, 5, "mc68328_w: CSB1(0) = %04x\n", data);
- m_regs.csb1 &= 0xffff0000 | (~mem_mask);
- m_regs.csb1 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pddata_r() // 0x419
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pddir, i))
+ {
+ data |= m_pddata & (1 << i);
+ }
+ else if (!m_in_port_d_cb[i].isunset())
+ {
+ data |= m_in_port_d_cb[i]() << i;
+ }
+ else
+ {
+ data |= m_pdpuen & (1 << i);
+ }
+ }
+ LOGMASKED(LOG_GPIO_D, "%s: pddata_r: PDDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x126:
- verboselog( *this, 5, "mc68328_w: CSB1(16) = %04x\n", data);
- m_regs.csb1 &= ~(mem_mask << 16);
- m_regs.csb1 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pdpuen_w(u8 data) // 0x41a
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdpuen_w: PDPUEN = %02x\n", machine().describe_context(), data);
+ m_pdpuen = data;
+}
- case 0x128:
- verboselog( *this, 5, "mc68328_w: CSB2(0) = %04x\n", data);
- m_regs.csb2 &= 0xffff0000 | (~mem_mask);
- m_regs.csb2 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pdpuen_r() // 0x41a
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdpuen_r: PDPUEN: %02x\n", machine().describe_context(), m_pdpuen);
+ return m_pdpuen;
+}
- case 0x12a:
- verboselog( *this, 5, "mc68328_w: CSB2(16) = %04x\n", data);
- m_regs.csb2 &= ~(mem_mask << 16);
- m_regs.csb2 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pdpol_w(u8 data) // 0x41c
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdpol_w: PDPOL = %02x\n", machine().describe_context(), data);
+ m_pdpol = data;
+}
- case 0x12c:
- verboselog( *this, 5, "mc68328_w: CSB3(0) = %04x\n", data);
- m_regs.csb3 &= 0xffff0000 | (~mem_mask);
- m_regs.csb3 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pdpol_r() // 0x41c
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdpol_r: PDPOL: %02x\n", machine().describe_context(), m_pdpol);
+ return m_pdpol;
+}
- case 0x12e:
- verboselog( *this, 5, "mc68328_w: CSB3(16) = %04x\n", data);
- m_regs.csb3 &= ~(mem_mask << 16);
- m_regs.csb3 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pdirqen_w(u8 data) // 0x41d
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdirqen_w: PDIRQEN = %02x\n", machine().describe_context(), data);
+ m_pdirqen = data & 0x00ff;
+}
- case 0x130:
- verboselog( *this, 5, "mc68328_w: CSC0(0) = %04x\n", data);
- m_regs.csc0 &= 0xffff0000 | (~mem_mask);
- m_regs.csc0 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pdirqen_r() // 0x41d
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdirqen_r: PDIRQEN: %02x\n", machine().describe_context(), m_pdirqen);
+ return m_pdirqen;
+}
- case 0x132:
- verboselog( *this, 5, "mc68328_w: CSC0(16) = %04x\n", data);
- m_regs.csc0 &= ~(mem_mask << 16);
- m_regs.csc0 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pdirqedge_w(u8 data) // 0x41f
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdirqedge_w: PDIRQEDGE = %02x\n", machine().describe_context(), data);
+ m_pdirqedge = data;
+}
- case 0x134:
- verboselog( *this, 5, "mc68328_w: CSC1(0) = %04x\n", data);
- m_regs.csc1 &= 0xffff0000 | (~mem_mask);
- m_regs.csc1 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pdirqedge_r() // 0x41f
+{
+ LOGMASKED(LOG_GPIO_D, "%s: pdirqedge_r: PDIRQEDGE: %02x\n", machine().describe_context(), m_pdirqedge);
+ return m_pdirqedge;
+}
- case 0x136:
- verboselog( *this, 5, "mc68328_w: CSC1(16) = %04x\n", data);
- m_regs.csc1 &= ~(mem_mask << 16);
- m_regs.csc1 |= (data & mem_mask) << 16;
- break;
- case 0x138:
- verboselog( *this, 5, "mc68328_w: CSC2(0) = %04x\n", data);
- m_regs.csc2 &= 0xffff0000 | (~mem_mask);
- m_regs.csc2 |= data & mem_mask;
- break;
+//-------------------------------------------------
+// GPIO hardware - Port E
+//-------------------------------------------------
- case 0x13a:
- verboselog( *this, 5, "mc68328_w: CSC2(16) = %04x\n", data);
- m_regs.csc2 &= ~(mem_mask << 16);
- m_regs.csc2 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pedir_w(u8 data) // 0x420
+{
+ LOGMASKED(LOG_GPIO_E, "%s: pedir_w: PEDIR = %02x\n", machine().describe_context(), data);
+ m_pedir = data;
+}
- case 0x13c:
- verboselog( *this, 5, "mc68328_w: CSC3(0) = %04x\n", data);
- m_regs.csc3 &= 0xffff0000 | (~mem_mask);
- m_regs.csc3 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pedir_r() // 0x420
+{
+ LOGMASKED(LOG_GPIO_E, "%s: pedir_r: PEDIR: %02x\n", machine().describe_context(), m_pedir);
+ return m_pedir;
+}
- case 0x13e:
- verboselog( *this, 5, "mc68328_w: CSC3(16) = %04x\n", data);
- m_regs.csc3 &= ~(mem_mask << 16);
- m_regs.csc3 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pedata_w(u8 data) // 0x421
+{
+ LOGMASKED(LOG_GPIO_E, "%s: pedata_w: PEDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pedir & m_pesel);
+ m_pedata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pedir & m_pesel, i))
+ {
+ m_out_port_e_cb[i](BIT(m_pedata, i));
+ }
+ }
+}
- case 0x140:
- verboselog( *this, 5, "mc68328_w: CSD0(0) = %04x\n", data);
- m_regs.csd0 &= 0xffff0000 | (~mem_mask);
- m_regs.csd0 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pedata_r() // 0x421
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pesel, i))
+ {
+ if (BIT(m_pedir, i))
+ {
+ data |= m_pedata & (1 << i);
+ }
+ else if (!m_in_port_e_cb[i].isunset())
+ {
+ data |= m_in_port_e_cb[i]() << i;
+ }
+ else
+ {
+ data |= m_pepuen & (1 << i);
+ }
+ }
+ }
+ LOGMASKED(LOG_GPIO_E, "%s: pedata_r: PEDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x142:
- verboselog( *this, 5, "mc68328_w: CSD0(16) = %04x\n", data);
- m_regs.csd0 &= ~(mem_mask << 16);
- m_regs.csd0 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pepuen_w(u8 data) // 0x422
+{
+ LOGMASKED(LOG_GPIO_E, "%s: pepuen_w: PEPUEN = %02x\n", machine().describe_context(), data);
+ m_pepuen = data;
+}
- case 0x144:
- verboselog( *this, 5, "mc68328_w: CSD1(0) = %04x\n", data);
- m_regs.csd1 &= 0xffff0000 | (~mem_mask);
- m_regs.csd1 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pepuen_r() // 0x422
+{
+ LOGMASKED(LOG_GPIO_E, "%s: pepuen_r: PEPUEN: %02x\n", machine().describe_context(), m_pepuen);
+ return m_pepuen;
+}
- case 0x146:
- verboselog( *this, 5, "mc68328_w: CSD1(16) = %04x\n", data);
- m_regs.csd1 &= ~(mem_mask << 16);
- m_regs.csd1 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pesel_w(u8 data) // 0x423
+{
+ LOGMASKED(LOG_GPIO_E, "%s: pesel_w: PESEL = %02x\n", machine().describe_context(), data);
+ m_pesel = data;
+}
- case 0x148:
- verboselog( *this, 5, "mc68328_w: CSD2(0) = %04x\n", data);
- m_regs.csd2 &= 0xffff0000 | (~mem_mask);
- m_regs.csd2 |= data & mem_mask;
- break;
+u8 mc68328_base_device::pesel_r() // 0x423
+{
+ LOGMASKED(LOG_GPIO_E, "%s: pesel_r: PESEL: %02x\n", machine().describe_context(), m_pesel);
+ return m_pesel;
+}
- case 0x14a:
- verboselog( *this, 5, "mc68328_w: CSD2(16) = %04x\n", data);
- m_regs.csd2 &= ~(mem_mask << 16);
- m_regs.csd2 |= (data & mem_mask) << 16;
- break;
- case 0x14c:
- verboselog( *this, 5, "mc68328_w: CSD3(0) = %04x\n", data);
- m_regs.csd3 &= 0xffff0000 | (~mem_mask);
- m_regs.csd3 |= data & mem_mask;
- break;
+//-------------------------------------------------
+// GPIO hardware - Port F
+//-------------------------------------------------
- case 0x14e:
- verboselog( *this, 5, "mc68328_w: CSD3(16) = %04x\n", data);
- m_regs.csd3 &= ~(mem_mask << 16);
- m_regs.csd3 |= (data & mem_mask) << 16;
- break;
+void mc68328_base_device::pfdir_w(u8 data) // 0x428
+{
+ LOGMASKED(LOG_GPIO_F, "%s: pfdir_w: PFDIR = %02x\n", machine().describe_context(), data);
+ m_pfdir = data;
+}
- case 0x200:
- verboselog( *this, 2, "mc68328_w: PLLCR = %04x\n", data);
- m_regs.pllcr = data;
- break;
+u8 mc68328_base_device::pfdir_r() // 0x428
+{
+ LOGMASKED(LOG_GPIO_F, "%s: pfdir_r: PFDIR: %02x\n", machine().describe_context(), m_pfdir);
+ return m_pfdir;
+}
- case 0x202:
- verboselog( *this, 2, "mc68328_w: PLLFSR = %04x\n", data);
- m_regs.pllfsr = data;
- break;
+void mc68328_base_device::pfdata_w(u8 data) // 0x429
+{
+ LOGMASKED(LOG_GPIO_F, "%s: pfdata_w: PFDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pfdir & m_pfsel);
+ m_pfdata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pfdir & m_pfsel, i))
+ {
+ m_out_port_f_cb[i](BIT(m_pfdata, i));
+ }
+ }
+}
- case 0x206:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PCTLR = %02x\n", data & 0x00ff);
- m_regs.pctlr = data & 0x00ff;
- }
- else
+u8 mc68328_base_device::pfdata_r() // 0x429
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pfsel, i))
+ {
+ if (BIT(m_pfdir, i))
{
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff206) = %02x\n", (data >> 8) & 0x00ff);
+ data |= m_pfdata & (1 << i);
}
- break;
-
- case 0x300:
- if (mem_mask & 0x00ff)
+ else if (!m_in_port_f_cb[i].isunset())
{
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff301) = %02x\n", data & 0x00ff);
+ data |= m_in_port_f_cb[i]() << i;
}
else
{
- verboselog( *this, 2, "mc68328_w: IVR = %02x\n", (data >> 8) & 0x00f8);
- m_regs.ivr = (data >> 8) & 0x00f8;
+ data |= m_pfpuen & (1 << i);
}
- break;
+ }
+ }
+ LOGMASKED(LOG_GPIO_F, "%s: pfdata_r: PFDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x302:
- verboselog( *this, 2, "mc68328_w: ICR = %04x\n", data);
- m_regs.icr = data;
- break;
+void mc68328_base_device::pfpuen_w(u8 data) // 0x42a
+{
+ LOGMASKED(LOG_GPIO_F, "%s: pfpuen_w: PFPUEN = %02x\n", machine().describe_context(), data);
+ m_pfpuen = data;
+}
- case 0x304:
- verboselog( *this, 2, "mc68328_w: IMR(16) = %04x\n", data);
- m_regs.imr &= ~(mem_mask << 16);
- m_regs.imr |= (data & mem_mask) << 16;
- m_regs.isr &= ~((data & mem_mask) << 16);
+u8 mc68328_base_device::pfpuen_r() // 0x42a
+{
+ LOGMASKED(LOG_GPIO_F, "%s: pfpuen_r: PFPUEN: %02x\n", machine().describe_context(), m_pfpuen);
+ return m_pfpuen;
+}
- imr_diff = imr_old ^ m_regs.imr;
- set_interrupt_line(imr_diff, 0);
- break;
+void mc68328_base_device::pfsel_w(u8 data) // 0x42b
+{
+ LOGMASKED(LOG_GPIO_F, "%s: pfsel_w: PFSEL = %02x\n", machine().describe_context(), data);
+ m_pfsel = data;
+}
- case 0x306:
- verboselog( *this, 2, "mc68328_w: IMR(0) = %04x\n", data);
- m_regs.imr &= 0xffff0000 | (~mem_mask);
- m_regs.imr |= data & mem_mask;
- m_regs.isr &= ~(data & mem_mask);
+u8 mc68328_base_device::pfsel_r() // 0x42b
+{
+ LOGMASKED(LOG_GPIO_F, "%s: pfsel_r: PFSEL: %02x\n", machine().describe_context(), m_pfsel);
+ return m_pfsel;
+}
- imr_diff = imr_old ^ m_regs.imr;
- set_interrupt_line(imr_diff, 0);
- break;
- case 0x308:
- verboselog( *this, 2, "mc68328_w: IWR(16) = %04x\n", data);
- m_regs.iwr &= ~(mem_mask << 16);
- m_regs.iwr |= (data & mem_mask) << 16;
- break;
+//-------------------------------------------------
+// GPIO hardware - Port G
+//-------------------------------------------------
- case 0x30a:
- verboselog( *this, 2, "mc68328_w: IWR(0) = %04x\n", data);
- m_regs.iwr &= 0xffff0000 | (~mem_mask);
- m_regs.iwr |= data & mem_mask;
- break;
+void mc68328_base_device::pgdir_w(u8 data) // 0x430
+{
+ LOGMASKED(LOG_GPIO_G, "%s: pgdir_w: PGDIR = %02x\n", machine().describe_context(), data);
+ m_pgdir = data;
+}
- case 0x30c:
- verboselog( *this, 2, "mc68328_w: ISR(16) = %04x\n", data);
- // Clear edge-triggered IRQ1
- if ((m_regs.icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_SHIFT) == INT_IRQ1_SHIFT)
- {
- m_regs.isr &= ~INT_IRQ1;
- }
+u8 mc68328_base_device::pgdir_r() // 0x430
+{
+ LOGMASKED(LOG_GPIO_G, "%s: pgdir_r: PGDIR: %02x\n", machine().describe_context(), m_pgdir);
+ return m_pgdir;
+}
- // Clear edge-triggered IRQ2
- if ((m_regs.icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_SHIFT) == INT_IRQ2_SHIFT)
- {
- m_regs.isr &= ~INT_IRQ2;
- }
+void mc68328_base_device::pgdata_w(u8 data) // 0x431
+{
+ LOGMASKED(LOG_GPIO_G, "%s: pgdata_w: PGDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pgdir & m_pgsel);
+ m_pgdata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pgdir & m_pgsel, i))
+ {
+ m_out_port_g_cb[i](BIT(m_pgdata, i));
+ }
+ }
+}
- // Clear edge-triggered IRQ3
- if ((m_regs.icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_SHIFT) == INT_IRQ3_SHIFT)
+u8 mc68328_base_device::pgdata_r() // 0x431
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pgsel, i))
+ {
+ if (BIT(m_pgdir, i))
{
- m_regs.isr &= ~INT_IRQ3;
+ data |= m_pgdata & (1 << i);
}
-
- // Clear edge-triggered IRQ6
- if ((m_regs.icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_SHIFT) == INT_IRQ6_SHIFT)
+ else if (!m_in_port_g_cb[i].isunset())
{
- m_regs.isr &= ~INT_IRQ6;
+ data |= m_in_port_g_cb[i]() << i;
}
-
- // Clear edge-triggered IRQ7
- if ((data & INT_IRQ7_SHIFT) == INT_IRQ7_SHIFT)
+ else
{
- m_regs.isr &= ~INT_IRQ7;
+ data |= m_pgpuen & (1 << i);
}
- break;
+ }
+ }
+ LOGMASKED(LOG_GPIO_G, "%s: pgdata_r: PGDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x30e:
- verboselog( *this, 2, "mc68328_w: ISR(0) = %04x (Ignored)\n", data);
- break;
+void mc68328_base_device::pgpuen_w(u8 data) // 0x432
+{
+ LOGMASKED(LOG_GPIO_G, "%s: pgpuen_w: PGPUEN = %02x\n", machine().describe_context(), data);
+ m_pgpuen = data;
+}
- case 0x310:
- verboselog( *this, 2, "mc68328_w: IPR(16) = %04x (Ignored)\n", data);
- break;
+u8 mc68328_base_device::pgpuen_r() // 0x432
+{
+ LOGMASKED(LOG_GPIO_G, "%s: pgpuen_r: PGPUEN: %02x\n", machine().describe_context(), m_pgpuen);
+ return m_pgpuen;
+}
- case 0x312:
- verboselog( *this, 2, "mc68328_w: IPR(0) = %04x (Ignored)\n", data);
- break;
+void mc68328_base_device::pgsel_w(u8 data) // 0x433
+{
+ LOGMASKED(LOG_GPIO_G, "%s: pgsel_w: PGSEL = %02x\n", machine().describe_context(), data);
+ m_pgsel = data;
+}
- case 0x400:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PADATA = %02x\n", data & 0x00ff);
- m_regs.padata = data & 0x00ff;
- if (!m_out_port_a_cb.isnull())
- {
- m_out_port_a_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PADIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.padir = (data >> 8) & 0x00ff;
- }
- break;
+u8 mc68328_base_device::pgsel_r() // 0x433
+{
+ LOGMASKED(LOG_GPIO_G, "%s: pgsel_r: PGSEL: %02x\n", machine().describe_context(), m_pgsel);
+ return m_pgsel;
+}
- case 0x402:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PASEL = %02x\n", data & 0x00ff);
- m_regs.pasel = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff402) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
- case 0x408:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PBDATA = %02x\n", data & 0x00ff);
- m_regs.pbdata = data & 0x00ff;
- if (!m_out_port_b_cb.isnull())
- {
- m_out_port_b_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PBDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pbdir = (data >> 8) & 0x00ff;
- }
- break;
+//-------------------------------------------------
+// GPIO hardware - Port J
+//-------------------------------------------------
- case 0x40a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PBSEL = %02x\n", data & 0x00ff);
- m_regs.pbsel = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff40a) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+void mc68328_device::pjdir_w(u8 data) // 0x438
+{
+ LOGMASKED(LOG_GPIO_J, "%s: pjdir_w: PJDIR = %02x\n", machine().describe_context(), data);
+ m_pjdir = data;
+}
- case 0x410:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PCDATA = %02x\n", data & 0x00ff);
- m_regs.pcdata = data & 0x00ff;
- if (!m_out_port_c_cb.isnull())
- {
- m_out_port_c_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PCDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pcdir = (data >> 8) & 0x00ff;
- }
- break;
+u8 mc68328_device::pjdir_r() // 0x438
+{
+ LOGMASKED(LOG_GPIO_J, "%s: pjdir_r: PJDIR: %02x\n", machine().describe_context(), m_pjdir);
+ return m_pjdir;
+}
- case 0x412:
- if (mem_mask & 0x00ff)
+void mc68328_device::pjdata_w(u8 data) // 0x439
+{
+ LOGMASKED(LOG_GPIO_J, "%s: pjdata_w: PJDATA = %02x\n", machine().describe_context(), data);
+ m_pjdata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pjdir & m_pjsel, i))
+ {
+ m_out_port_j_cb[i](BIT(m_pjdata, i));
+ }
+ }
+}
+
+u8 mc68328_device::pjdata_r() // 0x439
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pjsel, i))
+ {
+ if (BIT(m_pjdir, i))
{
- verboselog( *this, 2, "mc68328_w: PCSEL = %02x\n", data & 0x00ff);
- m_regs.pcsel = data & 0x00ff;
+ data |= m_pjdata & (1 << i);
}
- else
+ else if (!m_in_port_j_cb[i].isunset())
{
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff412) = %02x\n", (data >> 8) & 0x00ff);
+ data |= m_in_port_j_cb[i]() << i;
}
- break;
+ }
+ }
+ LOGMASKED(LOG_GPIO_J, "%s: pjdata_r: PJDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x418:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PDDATA = %02x\n", data & 0x00ff);
+void mc68328_device::pjsel_w(u8 data) // 0x43b
+{
+ LOGMASKED(LOG_GPIO_J, "%s: pjsel_w: PJSEL = %02x\n", machine().describe_context(), data);
+ m_pjsel = data;
+}
- m_regs.pddataedge &= ~(data & 0x00ff);
- poll_port_d_interrupts();
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PDDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pddir = (data >> 8) & 0x00ff;
- }
- break;
+u8 mc68328_device::pjsel_r() // 0x43b
+{
+ LOGMASKED(LOG_GPIO_J, "%s: pjsel_r: PJSEL: %02x\n", machine().describe_context(), m_pjsel);
+ return m_pjsel;
+}
- case 0x41a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff41b) = %02x\n", data & 0x00ff);
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PDPUEN = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pdpuen = (data >> 8) & 0x00ff;
- }
- break;
- case 0x41c:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PDIRQEN = %02x\n", data & 0x00ff);
- m_regs.pdirqen = data & 0x00ff;
+//-------------------------------------------------
+// GPIO hardware - Port K
+//-------------------------------------------------
- poll_port_d_interrupts();
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PDPOL = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pdpol = (data >> 8) & 0x00ff;
- }
- break;
+void mc68328_device::pkdir_w(u8 data) // 0x440
+{
+ LOGMASKED(LOG_GPIO_K, "%s: pkdir_w: PKDIR = %02x\n", machine().describe_context(), data);
+ m_pkdir = data;
+}
- case 0x41e:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PDIRQEDGE = %02x\n", data & 0x00ff);
- m_regs.pdirqedge = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff41e) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+u8 mc68328_device::pkdir_r() // 0x440
+{
+ LOGMASKED(LOG_GPIO_K, "%s: pkdir_r: PKDIR: %02x\n", machine().describe_context(), m_pkdir);
+ return m_pkdir;
+}
- case 0x420:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PEDATA = %02x\n", data & 0x00ff);
- m_regs.pedata = data & 0x00ff;
- if (!m_out_port_e_cb.isnull())
- {
- m_out_port_e_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PEDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pedir = (data >> 8) & 0x00ff;
- }
- break;
+void mc68328_device::pkdata_w(u8 data) // 0x441
+{
+ LOGMASKED(LOG_GPIO_K, "%s: pkdata_w: PKDATA = %02x\n", machine().describe_context(), data);
+ m_pkdata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pkdir & m_pksel, i))
+ {
+ m_out_port_k_cb[i](BIT(m_pkdata, i));
+ }
+ }
+}
- case 0x422:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PESEL = %02x\n", data & 0x00ff);
- m_regs.pesel = data & 0x00ff;
- }
- else
+u8 mc68328_device::pkdata_r() // 0x441
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pksel, i))
+ {
+ if (BIT(m_pkdir, i))
{
- verboselog( *this, 2, "mc68328_w: PEPUEN = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pepuen = (data >> 8) & 0x00ff;
- m_regs.pedata |= m_regs.pepuen;
+ data |= m_pkdata & (1 << i);
}
- break;
-
- case 0x428:
- if (mem_mask & 0x00ff)
+ else if (!m_in_port_k_cb[i].isunset())
{
- verboselog( *this, 2, "mc68328_w: PFDATA = %02x\n", data & 0x00ff);
- m_regs.pfdata = data & 0x00ff;
- if (!m_out_port_f_cb.isnull())
- {
- m_out_port_f_cb((offs_t)0, data & 0x00ff);
- }
+ data |= m_in_port_k_cb[i]() << i;
}
else
{
- verboselog( *this, 2, "mc68328_w: PFDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pfdir = (data >> 8) & 0x00ff;
+ data |= m_pkpuen & (1 << i);
}
- break;
+ }
+ }
+ LOGMASKED(LOG_GPIO_K, "%s: pkdata_r: PKDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x42a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PFSEL = %02x\n", data & 0x00ff);
- m_regs.pfsel = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PFPUEN = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pfpuen = (data >> 8) & 0x00ff;
- }
- break;
+void mc68328_device::pkpuen_w(u8 data) // 0x442
+{
+ LOGMASKED(LOG_GPIO_K, "%s: pkpuen_w: PKPUEN = %02x\n", machine().describe_context(), data);
+ m_pkpuen = data;
+}
- case 0x430:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PGDATA = %02x\n", data & 0x00ff);
- m_regs.pgdata = data & 0x00ff;
- if (!m_out_port_g_cb.isnull())
- {
- m_out_port_g_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PGDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pgdir = (data >> 8) & 0x00ff;
- }
- break;
+u8 mc68328_device::pkpuen_r() // 0x442
+{
+ LOGMASKED(LOG_GPIO_K, "%s: pkpuen_r: PKPUEN: %02x\n", machine().describe_context(), m_pkpuen);
+ return m_pkpuen;
+}
- case 0x432:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PGSEL = %02x\n", data & 0x00ff);
- m_regs.pgsel = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PGPUEN = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pgpuen = (data >> 8) & 0x00ff;
- }
- break;
+void mc68328_device::pksel_w(u8 data) // 0x443
+{
+ LOGMASKED(LOG_GPIO_K, "%s: pksel_w: PKSEL = %02x\n", machine().describe_context(), data);
+ m_pksel = data;
+}
- case 0x438:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PJDATA = %02x\n", data & 0x00ff);
- m_regs.pjdata = data & 0x00ff;
- if (!m_out_port_j_cb.isnull())
- {
- m_out_port_j_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PJDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pjdir = (data >> 8) & 0x00ff;
- }
- break;
+u8 mc68328_device::pksel_r() // 0x443
+{
+ LOGMASKED(LOG_GPIO_K, "%s: pksel_r: PKSEL: %02x\n", machine().describe_context(), m_pksel);
+ return m_pksel;
+}
- case 0x43a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PJSEL = %02x\n", data & 0x00ff);
- m_regs.pjsel = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfff43a) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
- case 0x440:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PKDATA = %02x\n", data & 0x00ff);
- m_regs.pkdata = data & 0x00ff;
- if (!m_out_port_k_cb.isnull())
- {
- m_out_port_k_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PKDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pkdir = (data >> 8) & 0x00ff;
- }
- break;
+//-------------------------------------------------
+// GPIO hardware - Port M
+//-------------------------------------------------
- case 0x442:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PKSEL = %02x\n", data & 0x00ff);
- m_regs.pksel = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: PKPUEN = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pgpuen = (data >> 8) & 0x00ff;
- }
- break;
+void mc68328_device::pmdir_w(u8 data) // 0x448
+{
+ LOGMASKED(LOG_GPIO_M, "%s: pmdir_w: PMDIR = %02x\n", machine().describe_context(), data);
+ m_pmdir = data;
+}
- case 0x448:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: PMDATA = %02x\n", data & 0x00ff);
- m_regs.pmdata = data & 0x00ff;
- if (!m_out_port_m_cb.isnull())
- {
- m_out_port_m_cb((offs_t)0, data & 0x00ff);
- }
- }
- else
+u8 mc68328_device::pmdir_r() // 0x448
+{
+ LOGMASKED(LOG_GPIO_M, "%s: pmdir_r: PMDIR: %02x\n", machine().describe_context(), m_pmdir);
+ return m_pmdir;
+}
+
+void mc68328_device::pmdata_w(u8 data) // 0x449
+{
+ LOGMASKED(LOG_GPIO_M, "%s: pmdata_w: PMDATA = %02x\n", machine().describe_context(), data);
+ m_pmdata = data;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pmdir & m_pmsel, i))
+ {
+ m_out_port_m_cb[i](BIT(m_pmdata, i));
+ }
+ }
+}
+
+u8 mc68328_device::pmdata_r() // 0x449
+{
+ u8 data = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_pmsel, i))
+ {
+ if (BIT(m_pmdir, i))
{
- verboselog( *this, 2, "mc68328_w: PMDIR = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pmdir = (data >> 8) & 0x00ff;
+ data |= m_pmdata & (1 << i);
}
- break;
-
- case 0x44a:
- if (mem_mask & 0x00ff)
+ else if (!m_in_port_m_cb[i].isunset())
{
- verboselog( *this, 2, "mc68328_w: PMSEL = %02x\n", data & 0x00ff);
- m_regs.pmsel = data & 0x00ff;
+ data |= m_in_port_m_cb[i]() << i;
}
else
{
- verboselog( *this, 2, "mc68328_w: PMPUEN = %02x\n", (data >> 8) & 0x00ff);
- m_regs.pmpuen = (data >> 8) & 0x00ff;
+ data |= m_pmpuen & (1 << i);
}
- break;
+ }
+ }
+ LOGMASKED(LOG_GPIO_M, "%s: pmdata_r: PMDATA: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x500:
- verboselog( *this, 2, "mc68328_w: PWMC = %04x\n", data);
+void mc68328_device::pmpuen_w(u8 data) // 0x44a
+{
+ LOGMASKED(LOG_GPIO_M, "%s: pmpuen_w: PMPUEN = %02x\n", machine().describe_context(), data);
+ m_pmpuen = data;
+}
- m_regs.pwmc = data;
+u8 mc68328_device::pmpuen_r() // 0x44a
+{
+ LOGMASKED(LOG_GPIO_M, "%s: pmpuen_r: PMPUEN: %02x\n", machine().describe_context(), m_pmpuen);
+ return m_pmpuen;
+}
- if (m_regs.pwmc & PWMC_PWMIRQ)
- {
- set_interrupt_line(INT_PWM, 1);
- }
+void mc68328_device::pmsel_w(u8 data) // 0x44b
+{
+ LOGMASKED(LOG_GPIO_M, "%s: pmsel_w: PMSEL = %02x\n", machine().describe_context(), data);
+ m_pmsel = data;
+}
- m_regs.pwmc &= ~PWMC_LOAD;
+u8 mc68328_device::pmsel_r() // 0x44b
+{
+ LOGMASKED(LOG_GPIO_M, "%s: pmsel_r: PMSEL: %02x\n", machine().describe_context(), m_pmsel);
+ return m_pmsel;
+}
- if ((m_regs.pwmc & PWMC_PWMEN) != 0 && m_regs.pwmw != 0 && m_regs.pwmp != 0)
- {
- uint32_t frequency = 32768 * 506;
- uint32_t divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot.
- attotime period;
- frequency /= divisor;
- period = attotime::from_hz(frequency) * m_regs.pwmw;
- m_pwm->adjust(period);
- if (m_regs.pwmc & PWMC_IRQEN)
- {
- set_interrupt_line(INT_PWM, 1);
- }
- m_regs.pwmc ^= PWMC_PIN;
- }
- else
- {
- m_pwm->adjust(attotime::never);
- }
- break;
- case 0x502:
- verboselog( *this, 2, "mc68328_w: PWMP = %04x\n", data);
- m_regs.pwmp = data;
- break;
+//-------------------------------------------------
+// PWM hardware - Standard MC68328
+//-------------------------------------------------
- case 0x504:
- verboselog( *this, 2, "mc68328_w: PWMW = %04x\n", data);
- m_regs.pwmw = data;
- break;
+TIMER_CALLBACK_MEMBER(mc68328_device::pwm_tick)
+{
+ if (m_pwmw >= m_pwmp || !m_pwmw || !m_pwmp)
+ {
+ m_pwm->adjust(attotime::never);
+ return;
+ }
- case 0x506:
- verboselog( *this, 2, "mc68328_w: PWMCNT = %04x\n", data);
- m_regs.pwmcnt = 0;
- break;
+ const u32 divisor = 4 << (m_pwmc & PWMC_CLKSEL);
- case 0x600:
- verboselog( *this, 2, "mc68328_w: TCTL1 = %04x\n", data);
- temp16[0] = m_regs.tctl[0];
- m_regs.tctl[0] = data;
- if ((temp16[0] & TCTL_TEN) == (m_regs.tctl[0] & TCTL_TEN))
- {
- maybe_start_timer(0, 0);
- }
- else if ((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (m_regs.tctl[0] & TCTL_TEN) == TCTL_TEN_ENABLE)
- {
- maybe_start_timer(0, 1);
- }
- break;
+ if (((m_pwmc & PWMC_POL) == 0 && (m_pwmc & PWMC_PIN) != 0) ||
+ ((m_pwmc & PWMC_POL) != 0 && (m_pwmc & PWMC_PIN) == 0))
+ {
+ attotime period = attotime::from_ticks((m_pwmp - m_pwmw) * divisor, clock());
+ m_pwm->adjust(period);
- case 0x602:
- verboselog( *this, 2, "mc68328_w: TPRER1 = %04x\n", data);
- m_regs.tprer[0] = data;
- maybe_start_timer(0, 0);
- break;
+ if (m_pwmc & PWMC_IRQ_EN)
+ {
+ set_interrupt_line(INT_PWM, 1);
+ }
+ }
+ else
+ {
+ attotime period = attotime::from_ticks(m_pwmw * divisor, clock());
+ m_pwm->adjust(period);
+ }
- case 0x604:
- verboselog( *this, 2, "mc68328_w: TCMP1 = %04x\n", data);
- m_regs.tcmp[0] = data;
- maybe_start_timer(0, 0);
- break;
+ m_pwmc ^= PWMC_PIN;
- case 0x606:
- verboselog( *this, 2, "mc68328_w: TCR1 = %04x (Ignored)\n", data);
- break;
+ m_out_pwm_cb((m_pwmc & PWMC_PIN) ? 1 : 0);
+}
- case 0x608:
- verboselog( *this, 2, "mc68328_w: TCN1 = %04x (Ignored)\n", data);
- break;
+void mc68328_device::pwmc_w(u16 data) // 0x500
+{
+ LOGMASKED(LOG_PWM, "%s: pwmc_w: PWMC = %04x\n", machine().describe_context(), data);
- case 0x60a:
- verboselog( *this, 5, "mc68328_w: TSTAT1 = %04x\n", data);
- m_regs.tstat[0] &= ~m_regs.tclear[0];
- if (!(m_regs.tstat[0] & TSTAT_COMP))
- {
- set_interrupt_line(INT_TIMER1, 0);
- }
- break;
+ const u16 old_pwmc = m_pwmc;
+ m_pwmc = data;
+ const u16 changed = m_pwmc ^ old_pwmc;
- case 0x60c:
- verboselog( *this, 2, "mc68328_w: TCTL2 = %04x\n", data);
- temp16[0] = m_regs.tctl[1];
- m_regs.tctl[1] = data;
- if ((temp16[0] & TCTL_TEN) == (m_regs.tctl[1] & TCTL_TEN))
- {
- maybe_start_timer(1, 0);
- }
- else if ((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (m_regs.tctl[1] & TCTL_TEN) == TCTL_TEN_ENABLE)
+ if (m_pwmc & PWMC_IRQ)
+ {
+ set_interrupt_line(INT_PWM, 1);
+ }
+
+ if (changed & (PWMC_EN | PWMC_CLKSEL | PWMC_LOAD))
+ {
+ const bool enable_or_update = (changed & m_pwmc & PWMC_EN) || (m_pwmc & PWMC_LOAD);
+ if (enable_or_update && m_pwmw && m_pwmp)
+ {
+ const u32 divisor = 4 << (m_pwmc & PWMC_CLKSEL);
+ attotime period = attotime::from_ticks(m_pwmw * divisor, clock());
+ m_pwm->adjust(period);
+ if (m_pwmc & PWMC_IRQ_EN)
{
- maybe_start_timer(1, 1);
+ set_interrupt_line(INT_PWM, 1);
}
- break;
+ m_pwmc |= PWMC_PIN;
+ }
+ else
+ {
+ m_pwm->adjust(attotime::never);
+ }
+ }
- case 0x60e:
- verboselog( *this, 2, "mc68328_w: TPRER2 = %04x\n", data);
- m_regs.tprer[1] = data;
- maybe_start_timer(1, 0);
- break;
+ m_pwmc &= ~PWMC_LOAD;
+}
- case 0x610:
- verboselog( *this, 2, "mc68328_w: TCMP2 = %04x\n", data);
- m_regs.tcmp[1] = data;
- maybe_start_timer(1, 0);
- break;
+u16 mc68328_device::pwmc_r() // 0x500
+{
+ const u16 data = m_pwmc;
+ LOGMASKED(LOG_PWM, "%s: pwmc_r: PWMC: %04x\n", machine().describe_context(), data);
+ if (m_pwmc & PWMC_IRQ)
+ {
+ m_pwmc &= ~PWMC_IRQ;
+ if (m_pwmc & PWMC_IRQ_EN)
+ {
+ set_interrupt_line(INT_PWM, 0);
+ }
+ }
+ return data;
+}
- case 0x612:
- verboselog( *this, 2, "mc68328_w: TCR2 = %04x (Ignored)\n", data);
- break;
+void mc68328_device::pwmp_w(u16 data) // 0x502
+{
+ LOGMASKED(LOG_PWM, "%s: pwmp_w: PWMP = %04x\n", machine().describe_context(), data);
+ m_pwmp = data;
+}
- case 0x614:
- verboselog( *this, 2, "mc68328_w: TCN2 = %04x (Ignored)\n", data);
- break;
+u16 mc68328_device::pwmp_r() // 0x502
+{
+ LOGMASKED(LOG_PWM, "%s: pwmp_r: PWMP: %04x\n", machine().describe_context(), m_pwmp);
+ return m_pwmp;
+}
- case 0x616:
- verboselog( *this, 2, "mc68328_w: TSTAT2 = %04x\n", data);
- m_regs.tstat[1] &= ~m_regs.tclear[1];
- if (!(m_regs.tstat[1] & TSTAT_COMP))
- {
- set_interrupt_line(INT_TIMER2, 0);
- }
- break;
+void mc68328_device::pwmw_w(u16 data) // 0x504
+{
+ LOGMASKED(LOG_PWM, "%s: pwmw_w: PWMW = %04x\n", machine().describe_context(), data);
+ m_pwmw = data;
+}
- case 0x618:
- verboselog( *this, 2, "mc68328_w: WCTLR = %04x\n", data);
- m_regs.wctlr = data;
- break;
+u16 mc68328_device::pwmw_r() // 0x504
+{
+ LOGMASKED(LOG_PWM, "%s: pwmw_r: PWMW: %04x\n", machine().describe_context(), m_pwmw);
+ return m_pwmw;
+}
- case 0x61a:
- verboselog( *this, 2, "mc68328_w: WCMPR = %04x\n", data);
- m_regs.wcmpr = data;
- break;
+void mc68328_device::pwmcnt_w(u16 data) // 0x506
+{
+ LOGMASKED(LOG_PWM, "%s: pwmcnt_w: PWMCNT = %04x\n", machine().describe_context(), data);
+ m_pwmcnt = 0;
+}
- case 0x61c:
- verboselog( *this, 2, "mc68328_w: WCN = %04x (Ignored)\n", data);
- break;
+u16 mc68328_device::pwmcnt_r() // 0x506
+{
+ LOGMASKED(LOG_PWM, "%s: pwmcnt_r: PWMCNT: %04x\n", machine().describe_context(), m_pwmcnt);
+ return m_pwmcnt;
+}
- case 0x700:
- verboselog( *this, 2, "mc68328_w: SPISR = %04x\n", data);
- m_regs.spisr = data;
- break;
- case 0x800:
- verboselog( *this, 2, "mc68328_w: SPIMDATA = %04x\n", data);
- if (!m_out_spim_cb.isnull())
- {
- m_out_spim_cb(0, data, 0xffff);
- }
- else
- {
- m_regs.spimdata = data;
- }
- break;
+//-------------------------------------------------
+// PWM hardware - EZ variant
+//-------------------------------------------------
- case 0x802:
- verboselog( *this, 2, "mc68328_w: SPIMCONT = %04x\n", data);
- verboselog( *this, 3, " Count = %d\n", data & SPIM_CLOCK_COUNT);
- verboselog( *this, 3, " Polarity = %s\n", (data & SPIM_POL) ? "Inverted" : "Active-high");
- verboselog( *this, 3, " Phase = %s\n", (data & SPIM_PHA) ? "Opposite" : "Normal");
- verboselog( *this, 3, " IRQ Enable = %s\n", (data & SPIM_IRQEN) ? "Enable" : "Disable");
- verboselog( *this, 3, " IRQ Pending = %s\n", (data & SPIM_SPIMIRQ) ? "Yes" : "No");
- verboselog( *this, 3, " Exchange = %s\n", (data & SPIM_XCH) ? "Initiate" : "Idle");
- verboselog( *this, 3, " SPIM Enable = %s\n", (data & SPIM_SPMEN) ? "Enable" : "Disable");
- verboselog( *this, 3, " Data Rate = Divide By %d\n", 1 << ((((data & SPIM_RATE) >> 13) & 0x0007) + 2) );
- m_regs.spimcont = data;
- // $$HACK$$ We should probably emulate the ADS7843 A/D device properly.
- if (data & SPIM_XCH)
- {
- m_regs.spimcont &= ~SPIM_XCH;
- if (!m_spim_xch_trigger_cb.isnull())
- {
- m_spim_xch_trigger_cb(0);
- }
- if (data & SPIM_IRQEN)
- {
- m_regs.spimcont |= SPIM_SPIMIRQ;
- verboselog( *this, 3, "Triggering SPIM Interrupt\n" );
- set_interrupt_line(INT_SPIM, 1);
- }
- }
- if (!(data & SPIM_IRQEN))
- {
- set_interrupt_line(INT_SPIM, 0);
- }
- break;
+TIMER_CALLBACK_MEMBER(mc68ez328_device::pwm_tick)
+{
+ if (!(m_pwmc & PWMC_EN))
+ {
+ return;
+ }
- case 0x900:
- verboselog( *this, 2, "mc68328_w: USTCNT = %04x\n", data);
- m_regs.ustcnt = data;
- break;
+ if (!param)
+ {
+ m_pwm_rep_cnt--;
+ if (!m_pwm_rep_cnt)
+ {
+ m_pwm_rep_cnt = 1 << ((m_pwmc & PWMC_REPEAT) >> PWMC_REPEAT_SHIFT);
+ pwm_fifo_pop();
+ }
+ }
- case 0x902:
- verboselog( *this, 2, "mc68328_w: UBAUD = %04x\n", data);
- m_regs.ubaud = data;
- break;
+ m_pwmo = param;
+ update_pwm_period(!m_pwmo);
+ m_out_pwm_cb((int)m_pwmo);
+}
- case 0x904:
- verboselog( *this, 2, "mc68328_w: URX = %04x\n", data);
- break;
+void mc68ez328_device::update_pwm_period(bool high_cycle)
+{
+ const u32 frequency = (m_pwmc & PWMC_CLK_SRC) ? 32768 : clock();
+ const u32 prescale = ((m_pwmc & PWMC_PRESCALE) >> PWMC_PRESCALE_SHIFT) + 1;
+ const u32 divisor = 2 << (m_pwmc & PWMC_CLKSEL);
+ const u32 period_reg = (u32)std::min(m_pwmp + 1u, 0xffu);
+ u32 sample_period = period_reg;
+ if (m_pwmfifo[m_pwmfifo_rd] <= period_reg)
+ {
+ sample_period = high_cycle ? (period_reg - m_pwmfifo[m_pwmfifo_rd]) : m_pwmfifo[m_pwmfifo_rd];
+ sample_period++;
+ }
+ attotime period = attotime::from_ticks(prescale * divisor * sample_period, frequency);
+ m_pwm->adjust(period, (int)high_cycle);
+}
- case 0x906:
- verboselog( *this, 2, "mc68328_w: UTX = %04x\n", data);
- break;
+void mc68ez328_device::pwm_fifo_push(u8 data)
+{
+ if (m_pwmfifo_cnt >= std::size(m_pwmfifo))
+ {
+ return;
+ }
+ m_pwmfifo[m_pwmfifo_wr] = data;
+ m_pwmfifo_wr = (m_pwmfifo_wr + 1) % std::size(m_pwmfifo);
+ const u8 old_cnt = m_pwmfifo_cnt;
+ m_pwmfifo_cnt++;
+ if (m_pwmfifo_cnt == std::size(m_pwmfifo))
+ {
+ m_pwmc &= ~PWMC_FIFO_AV;
+ }
+ else if (old_cnt <= 1 && m_pwmfifo_cnt > 1)
+ {
+ if (m_pwmc & PWMC_IRQ)
+ {
+ m_pwmc &= ~PWMC_IRQ;
+ set_interrupt_line(INT_PWM, 0);
+ }
+ }
+}
- case 0x908:
- verboselog( *this, 2, "mc68328_w: UMISC = %04x\n", data);
- m_regs.umisc = data;
- break;
+void mc68ez328_device::pwm_fifo_pop()
+{
+ if (m_pwmfifo_cnt > 0)
+ {
+ m_pwmfifo_rd = (m_pwmfifo_rd + 1) % std::size(m_pwmfifo);
+ m_pwmfifo_cnt--;
- case 0xa00:
- verboselog( *this, 2, "mc68328_w: LSSA(16) = %04x\n", data);
- m_regs.lssa &= ~(mem_mask << 16);
- m_regs.lssa |= (data & mem_mask) << 16;
- verboselog( *this, 3, " Address: %08x\n", m_regs.lssa);
- break;
+ m_pwmc |= PWMC_FIFO_AV;
+ }
- case 0xa02:
- verboselog( *this, 2, "mc68328_w: LSSA(0) = %04x\n", data);
- m_regs.lssa &= 0xffff0000 | (~mem_mask);
- m_regs.lssa |= data & mem_mask;
- verboselog( *this, 3, " Address: %08x\n", m_regs.lssa);
- break;
+ if (m_pwmfifo_cnt <= 1)
+ {
+ if (!(m_pwmc & PWMC_IRQ))
+ {
+ m_pwmc |= PWMC_IRQ;
+ set_interrupt_line(INT_PWM, 1);
+ }
+ }
+}
- case 0xa04:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LVPW = %02x\n", data & 0x00ff);
- m_regs.lvpw = data & 0x00ff;
- verboselog( *this, 3, " Page Width: %d\n", (m_regs.lvpw + 1) * ((m_regs.lpicf & 0x01) ? 8 : 16));
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa04) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+void mc68ez328_device::pwmc_w(u16 data) // 0x500
+{
+ LOGMASKED(LOG_PWM, "%s: pwmc_w: PWMC = %04x\n", machine().describe_context(), data);
- case 0xa08:
- verboselog( *this, 2, "mc68328_w: LXMAX = %04x\n", data);
- m_regs.lxmax = data;
- verboselog( *this, 3, " Width: %d\n", (data & 0x03ff) + 1);
- break;
+ const u16 old = m_pwmc;
+ m_pwmc = (m_pwmc & PWMC_FIFO_AV) | (data & ~PWMC_FIFO_AV);
+ const u16 changed = old ^ m_pwmc;
+ if (!changed)
+ {
+ return;
+ }
- case 0xa0a:
- verboselog( *this, 2, "mc68328_w: LYMAX = %04x\n", data);
- m_regs.lymax = data;
- verboselog( *this, 3, " Height: %d\n", (data & 0x03ff) + 1);
- break;
+ bool set_irq = false;
+ if (m_pwmc & PWMC_IRQ_EN)
+ {
+ if (m_pwmc & PWMC_IRQ)
+ {
+ set_irq = true;
+ }
+ }
+ else if (old & PWMC_IRQ_EN)
+ {
+ set_interrupt_line(INT_PWM, 0);
+ }
- case 0xa18:
- verboselog( *this, 2, "mc68328_w: LCXP = %04x\n", data);
- m_regs.lcxp = data;
- verboselog( *this, 3, " X Position: %d\n", data & 0x03ff);
- switch (m_regs.lcxp >> 14)
+ const bool recalculate = (changed & PWMC_RECALC_MASK);
+ if (recalculate)
+ {
+ if (m_pwmc & PWMC_EN)
+ {
+ if (changed & PWMC_EN)
{
- case 0:
- verboselog( *this, 3, " Cursor Control: Transparent\n");
- break;
+ set_irq = true;
+ m_pwmc |= PWMC_FIFO_AV;
+ }
+ m_pwmo = true;
+ m_out_pwm_cb((int)m_pwmo);
+ update_pwm_period(false);
+ m_pwm_rep_cnt = 1 << ((m_pwmc & PWMC_REPEAT) >> PWMC_REPEAT_SHIFT);
+ }
+ else
+ {
+ m_pwmfifo_cnt = 0;
+ m_pwmo = false;
+ m_pwm->adjust(attotime::never);
+ }
+ }
- case 1:
- verboselog( *this, 3, " Cursor Control: Black\n");
- break;
+ if (set_irq && (m_pwmc & PWMC_IRQ_EN))
+ {
+ m_pwmc |= PWMC_IRQ;
+ set_interrupt_line(INT_PWM, BIT(m_pwmc, PWMC_IRQ_BIT));
+ }
+}
- case 2:
- verboselog( *this, 3, " Cursor Control: Reverse\n");
- break;
+u16 mc68ez328_device::pwmc_r() // 0x500
+{
+ const u16 data = m_pwmc;
+ LOGMASKED(LOG_PWM, "%s: pwmc_r: PWMC: %04x\n", machine().describe_context(), data);
+ if (m_pwmc & PWMC_IRQ)
+ {
+ m_pwmc &= ~PWMC_IRQ;
+ set_interrupt_line(INT_PWM, 0);
+ }
+ return data;
+}
- case 3:
- verboselog( *this, 3, " Cursor Control: Invalid\n");
- break;
- }
- break;
+void mc68ez328_device::pwms_w(offs_t offset, u16 data, u16 mem_mask) // 0x502
+{
+ LOGMASKED(LOG_PWM, "%s: pwms_w: PWMS = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ if (mem_mask == 0xffff)
+ {
+ pwm_fifo_push((u8)(data >> 8));
+ pwm_fifo_push((u8)data);
+ }
+ else if (mem_mask == 0x00ff)
+ {
+ pwm_fifo_push((u8)data);
+ }
+}
- case 0xa1a:
- verboselog( *this, 2, "mc68328_w: LCYP = %04x\n", data);
- m_regs.lcyp = data;
- verboselog( *this, 3, " Y Position: %d\n", data & 0x01ff);
- break;
+u16 mc68ez328_device::pwms_r() // 0x502
+{
+ LOGMASKED(LOG_PWM, "%s: pwms_r: PWMS: %04x\n", machine().describe_context(), m_pwmfifo[m_pwmfifo_rd]);
+ return m_pwmfifo[m_pwmfifo_rd];
+}
- case 0xa1c:
- verboselog( *this, 2, "mc68328_w: LCWCH = %04x\n", data);
- m_regs.lcwch = data;
- verboselog( *this, 3, " Width: %d\n", (data >> 8) & 0x1f);
- verboselog( *this, 3, " Height: %d\n", data & 0x1f);
- break;
+void mc68ez328_device::pwmp_w(u8 data) // 0x504
+{
+ LOGMASKED(LOG_PWM, "%s: pwmp_w: PWMP = %02x\n", machine().describe_context(), data);
+ const bool changed = (data != m_pwmp);
+ m_pwmp = data;
+ if (changed && (m_pwmc & PWMC_EN))
+ {
+ update_pwm_period(false);
+ }
+}
- case 0xa1e:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LBLKC = %02x\n", data & 0x00ff);
- m_regs.lblkc = data & 0x00ff;
- verboselog( *this, 3, " Blink Enable: %d\n", m_regs.lblkc >> 7);
- verboselog( *this, 3, " Blink Divisor: %d\n", m_regs.lblkc & 0x7f);
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa1e) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+u8 mc68ez328_device::pwmp_r() // 0x504
+{
+ LOGMASKED(LOG_PWM, "%s: pwmp_r: PWMP: %02x\n", machine().describe_context(), m_pwmp);
+ return m_pwmp;
+}
- case 0xa20:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LPOLCF = %02x\n", data & 0x00ff);
- m_regs.lpolcf = data & 0x00ff;
- verboselog( *this, 3, " LCD Shift Clock Polarity: %s\n", (m_regs.lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK");
- verboselog( *this, 3, " First-line marker polarity: %s\n", (m_regs.lpicf & 0x04) ? "Active Low" : "Active High");
- verboselog( *this, 3, " Line-pulse polarity: %s\n", (m_regs.lpicf & 0x02) ? "Active Low" : "Active High");
- verboselog( *this, 3, " Pixel polarity: %s\n", (m_regs.lpicf & 0x01) ? "Active Low" : "Active High");
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: LPICF = %02x\n", (data >> 8) & 0x00ff);
- m_regs.lpicf = (data >> 8) & 0x00ff;
- switch((m_regs.lpicf >> 1) & 0x03)
- {
- case 0:
- verboselog( *this, 3, " Bus Size: 1-bit\n");
- break;
+void mc68ez328_device::pwmcnt_w(u8 data) // 0x505
+{
+ LOGMASKED(LOG_PWM, "%s: pwmcnt_w: PWMCNT = %04x (Ignored)\n", machine().describe_context(), data);
+}
- case 1:
- verboselog( *this, 3, " Bus Size: 2-bit\n");
- break;
+u8 mc68ez328_device::pwmcnt_r() // 0x505
+{
+ u8 data = 0;
+ if (m_pwmc & PWMC_EN)
+ {
+ const u32 frequency = (m_pwmc & PWMC_CLK_SRC) ? 32768 : clock();
+ const u32 prescale = (m_pwmc & PWMC_PRESCALE) >> PWMC_PRESCALE_SHIFT;
+ const u32 divisor = 2 << (m_pwmc & PWMC_CLKSEL);
+ const u8 period = std::min(m_pwmp + 1u, 0xffu);
+ data = period - (u8)m_pwm->remaining().as_ticks(frequency) / (prescale * divisor);
+ }
- case 2:
- verboselog( *this, 3, " Bus Size: 4-bit\n");
- break;
+ LOGMASKED(LOG_PWM, "%s: pwmcnt_r: PWMCNT: %02x\n", machine().describe_context(), data);
+ return data;
+}
- case 3:
- verboselog( *this, 3, " Bus Size: unused\n");
- break;
- }
- verboselog( *this, 3, " Gray scale enable: %d\n", m_regs.lpicf & 0x01);
- }
- break;
- case 0xa22:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LACDRC = %02x\n", data & 0x00ff);
- m_regs.lacdrc = data & 0x00ff;
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa22) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+//-------------------------------------------------
+// Timer/Watchdog hardware
+//-------------------------------------------------
- case 0xa24:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LPXCD = %02x\n", data & 0x00ff);
- m_regs.lpxcd = data & 0x00ff;
- verboselog( *this, 3, " Clock Divisor: %d\n", m_regs.lpxcd + 1);
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa24) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+emu_timer *mc68328_device::get_timer(int timer)
+{
+ return m_gptimer[timer];
+}
- case 0xa26:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LCKCON = %02x\n", data & 0x00ff);
- m_regs.lckcon = data & 0x00ff;
- verboselog( *this, 3, " LCDC Enable: %d\n", (m_regs.lckcon >> 7) & 0x01);
- verboselog( *this, 3, " DMA Burst Length: %d\n", ((m_regs.lckcon >> 6) & 0x01) ? 16 : 8);
- verboselog( *this, 3, " DMA Bursting Clock Control: %d\n", ((m_regs.lckcon >> 4) & 0x03) + 1);
- verboselog( *this, 3, " Bus Width: %d\n", ((m_regs.lckcon >> 1) & 0x01) ? 8 : 16);
- verboselog( *this, 3, " Pixel Clock Divider Source: %s\n", (m_regs.lckcon & 0x01) ? "PIX" : "SYS");
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa26) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+emu_timer *mc68ez328_device::get_timer(int timer)
+{
+ return m_gptimer;
+}
- case 0xa28:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LLBAR = %02x\n", data & 0x00ff);
- m_regs.llbar = data & 0x00ff;
- verboselog( *this, 3, " Address: %d\n", (m_regs.llbar & 0x7f) * ((m_regs.lpicf & 0x01) ? 8 : 16));
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa28) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+mc68328_base_device::timer_regs &mc68328_device::get_timer_regs(int timer)
+{
+ return m_timer_regs[timer];
+}
- case 0xa2a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LOTCR = %02x\n", data & 0x00ff);
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa2a) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+mc68328_base_device::timer_regs &mc68ez328_device::get_timer_regs(int timer)
+{
+ return m_timer_regs;
+}
- case 0xa2c:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LPOSR = %02x\n", data & 0x00ff);
- m_regs.lposr = data & 0x00ff;
- verboselog( *this, 3, " Byte Offset: %d\n", (m_regs.lposr >> 3) & 0x01);
- verboselog( *this, 3, " Pixel Offset: %d\n", m_regs.lposr & 0x07);
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa2c) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+u32 mc68328_device::get_timer_int(int timer)
+{
+ constexpr u32 TIMER_INTS[2] = { INT_TIMER1, INT_TIMER2 };
+ return TIMER_INTS[timer];
+}
- case 0xa30:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_w: LFRCM = %02x\n", data & 0x00ff);
- m_regs.lfrcm = data & 0x00ff;
- verboselog( *this, 3, " X Modulation: %d\n", (m_regs.lfrcm >> 4) & 0x0f);
- verboselog( *this, 3, " Y Modulation: %d\n", m_regs.lfrcm & 0x0f);
- }
- else
- {
- verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa30) = %02x\n", (data >> 8) & 0x00ff);
- }
- break;
+u32 mc68ez328_device::get_timer_int(int timer)
+{
+ return INT_TIMER2;
+}
- case 0xa32:
- verboselog( *this, 2, "mc68328_w: LGPMR = %04x\n", data);
- m_regs.lgpmr = data;
- verboselog( *this, 3, " Palette 0: %d\n", (m_regs.lgpmr >> 8) & 0x07);
- verboselog( *this, 3, " Palette 1: %d\n", (m_regs.lgpmr >> 12) & 0x07);
- verboselog( *this, 3, " Palette 2: %d\n", (m_regs.lgpmr >> 0) & 0x07);
- verboselog( *this, 3, " Palette 3: %d\n", (m_regs.lgpmr >> 4) & 0x07);
- break;
+template <int Timer>
+u32 mc68328_base_device::get_timer_frequency()
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ u32 frequency = 0;
- case 0xb00:
- verboselog( *this, 2, "mc68328_w: HMSR(0) = %04x\n", data);
- m_regs.hmsr &= ~(mem_mask << 16);
- m_regs.hmsr |= (data & mem_mask) << 16;
- m_regs.hmsr &= 0x1f3f003f;
+ switch (regs.tctl & TCTL_CLKSOURCE)
+ {
+ case TCTL_CLKSOURCE_SYSCLK:
+ frequency = clock();
break;
- case 0xb02:
- verboselog( *this, 2, "mc68328_w: HMSR(16) = %04x\n", data);
- m_regs.hmsr &= 0xffff0000 | (~mem_mask);
- m_regs.hmsr |= data & mem_mask;
- m_regs.hmsr &= 0x1f3f003f;
+ case TCTL_CLKSOURCE_SYSCLK16:
+ frequency = clock() / 16;
break;
- case 0xb04:
- verboselog( *this, 2, "mc68328_w: ALARM(0) = %04x\n", data);
- m_regs.alarm &= ~(mem_mask << 16);
- m_regs.alarm |= (data & mem_mask) << 16;
- m_regs.alarm &= 0x1f3f003f;
+ case TCTL_CLKSOURCE_32KHZ4:
+ case TCTL_CLKSOURCE_32KHZ5:
+ case TCTL_CLKSOURCE_32KHZ6:
+ case TCTL_CLKSOURCE_32KHZ7:
+ frequency = 32768;
break;
+ }
+ frequency /= (regs.tprer + 1);
- case 0xb06:
- verboselog( *this, 2, "mc68328_w: ALARM(16) = %04x\n", data);
- m_regs.alarm &= 0xffff0000 | (~mem_mask);
- m_regs.alarm |= data & mem_mask;
- m_regs.alarm &= 0x1f3f003f;
- break;
+ return frequency;
+}
- case 0xb0c:
- verboselog( *this, 2, "mc68328_w: RTCCTL = %04x\n", data);
- m_regs.rtcctl = data & 0x00a0;
- break;
+template <int Timer>
+void mc68328_base_device::update_gptimer_state()
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ emu_timer *timer = get_timer(Timer);
+ if (BIT(regs.tctl, TCTL_TEN_BIT) && (regs.tctl & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP)
+ {
+ if ((regs.tctl & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN || regs.tcmp == 0)
+ {
+ timer->adjust(attotime::never);
+ }
+ else
+ {
+ timer->adjust(attotime::from_ticks(regs.tcmp, get_timer_frequency<Timer>()));
+ }
+ }
+ else
+ {
+ timer->adjust(attotime::never);
+ }
+}
- case 0xb0e:
- verboselog( *this, 2, "mc68328_w: RTCISR = %04x\n", data);
- m_regs.rtcisr &= ~data;
- if (m_regs.rtcisr == 0)
- {
- set_interrupt_line(INT_RTC, 0);
- }
- break;
+template <int Timer>
+TIMER_CALLBACK_MEMBER(mc68328_base_device::timer_tick)
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ emu_timer *timer = get_timer(Timer);
- case 0xb10:
- verboselog( *this, 2, "mc68328_w: RTCIENR = %04x\n", data);
- m_regs.rtcienr = data & 0x001f;
- break;
+ regs.tcn = regs.tcmp;
+ regs.tstat |= TSTAT_COMP;
- case 0xb12:
- verboselog( *this, 2, "mc68328_w: STPWTCH = %04x\n", data);
- m_regs.stpwtch = data & 0x003f;
- break;
+ if ((regs.tctl & TCTL_FRR) == TCTL_FRR_RESTART)
+ {
+ u32 frequency = get_timer_frequency<Timer>();
+ if (frequency > 0)
+ {
+ attotime period = attotime::from_hz(frequency) * regs.tcmp;
+ regs.tcn = 0x0000;
+ timer->adjust(period);
+ }
+ else
+ {
+ timer->adjust(attotime::never);
+ }
+ }
+ else
+ {
+ u32 frequency = get_timer_frequency<Timer>();
+ if (frequency > 0)
+ {
+ attotime period = attotime::from_hz(frequency) * 0x10000;
+ timer->adjust(period);
+ }
+ else
+ {
+ timer->adjust(attotime::never);
+ }
+ }
+ if ((regs.tctl & TCTL_IRQEN) == TCTL_IRQEN_ENABLE)
+ {
+ set_interrupt_line(get_timer_int(Timer), 1);
+ }
+}
- default:
- verboselog( *this, 0, "mc68328_w: Unknown address (0x%06x) = %04x (%04x)\n", 0xfff000 + address, data, mem_mask);
- break;
+template <int Timer>
+void mc68328_base_device::tctl_w(u16 data) // 0x600, 0x60c
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tctl_w<%d>: TCTL%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data);
+ const u16 old_tctl = regs.tctl;
+ regs.tctl = data;
+
+ const bool old_enable = BIT(old_tctl, TCTL_TEN_BIT);
+ const bool new_enable = BIT(regs.tctl, TCTL_TEN_BIT);
+ if (!old_enable && new_enable)
+ {
+ regs.tcn = 0x0000;
}
+ update_gptimer_state<Timer>();
+}
+
+template <int Timer>
+u16 mc68328_base_device::tctl_r() // 0x600, 0x60c
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tctl_r: TCTL%d: %04x\n", machine().describe_context(), Timer + 1, regs.tctl);
+ return regs.tctl;
}
-uint16_t mc68328_device::internal_read(offs_t offset, uint16_t mem_mask)
+template <int Timer>
+void mc68328_base_device::tprer_w(u16 data) // 0x602, 0x60e
{
- uint16_t temp16;
- uint32_t address = offset << 1;
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tprer_w<%d>: TPRER%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data);
+ regs.tprer = data;
+ update_gptimer_state<Timer>();
+}
+
+template <int Timer>
+u16 mc68328_base_device::tprer_r() // 0x602, 0x60e
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tprer_r: TPRER%d: %04x\n", machine().describe_context(), Timer + 1, regs.tprer);
+ return regs.tprer;
+}
- switch (address)
+template <int Timer>
+void mc68328_base_device::tcmp_w(u16 data) // 0x604, 0x610
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tcmp_w<%d>: TCMP%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data);
+ regs.tcmp = data;
+ update_gptimer_state<Timer>();
+}
+
+template <int Timer>
+u16 mc68328_base_device::tcmp_r() // 0x604, 0x610
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tcmp_r: TCMP%d: %04x\n", machine().describe_context(), Timer + 1, regs.tcmp);
+ return regs.tcmp;
+}
+
+template <int Timer>
+void mc68328_base_device::tcr_w(u16 data) // 0x606, 0x612
+{
+ LOGMASKED(LOG_TIMERS, "%s: tcr_w<%d>: TCR%d = %04x (Ignored)\n", machine().describe_context(), Timer, Timer + 1, data);
+}
+
+template <int Timer>
+u16 mc68328_base_device::tcr_r() // 0x606, 0x612
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tcr_r: TCR%d: %04x\n", machine().describe_context(), Timer + 1, regs.tcr);
+ return regs.tcr;
+}
+
+template <int Timer>
+void mc68328_base_device::tcn_w(u16 data) // 0x608, 0x614
+{
+ LOGMASKED(LOG_TIMERS, "%s: tcn_w<%d>: TCN%d = %04x (Ignored)\n", machine().describe_context(), Timer, Timer + 1, data);
+}
+
+template <int Timer>
+u16 mc68328_base_device::tcn_r() // 0x608, 0x614
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tcn_r: TCN%d: %04x\n", machine().describe_context(), Timer + 1, regs.tcn);
+ return regs.tcn;
+}
+
+template <int Timer>
+void mc68328_base_device::tstat_w(u16 data) // 0x60a, 0x616
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TSTAT, "%s: tstat_w<%d>: TSTAT%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data);
+ regs.tstat &= ~regs.tclear;
+ if (!(regs.tstat & TSTAT_COMP))
{
- case 0x000:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff001)\n", mem_mask);
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): SCR = %02x\n", mem_mask, m_regs.scr);
- return m_regs.scr << 8;
- }
- break;
+ set_interrupt_line(get_timer_int(Timer), 0);
+ }
+}
- case 0x100:
- verboselog( *this, 2, "mc68328_r (%04x): GRPBASEA = %04x\n", mem_mask, m_regs.grpbasea);
- return m_regs.grpbasea;
+template <int Timer>
+u16 mc68328_base_device::tstat_r() // 0x60a, 0x616
+{
+ timer_regs &regs = get_timer_regs(Timer);
+ LOGMASKED(LOG_TIMERS, "%s: tstat_r: TSTAT%d: %04x\n", machine().describe_context(), Timer + 1, regs.tstat);
+ regs.tclear |= regs.tstat;
+ return regs.tstat;
+}
- case 0x102:
- verboselog( *this, 2, "mc68328_r (%04x): GRPBASEB = %04x\n", mem_mask, m_regs.grpbaseb);
- return m_regs.grpbaseb;
+void mc68328_device::wctlr_w(u16 data) // 0x618
+{
+ LOGMASKED(LOG_WATCHDOG, "%s: wctlr_w: WCTLR = %04x\n", machine().describe_context(), data);
+ m_wctlr = data;
+}
- case 0x104:
- verboselog( *this, 2, "mc68328_r (%04x): GRPBASEC = %04x\n", mem_mask, m_regs.grpbasec);
- return m_regs.grpbasec;
+u16 mc68328_device::wctlr_r() // 0x618
+{
+ LOGMASKED(LOG_WATCHDOG, "%s: wctlr_r: WCTLR: %04x\n", machine().describe_context(), m_wctlr);
+ return m_wctlr;
+}
- case 0x106:
- verboselog( *this, 2, "mc68328_r (%04x): GRPBASED = %04x\n", mem_mask, m_regs.grpbased);
- return m_regs.grpbased;
+void mc68328_device::wcmpr_w(u16 data) // 0x61a
+{
+ LOGMASKED(LOG_WATCHDOG, "%s: wcmpr_w: WCMPR = %04x\n", machine().describe_context(), data);
+ m_wcmpr = data;
+}
- case 0x108:
- verboselog( *this, 2, "mc68328_r (%04x): GRPMASKA = %04x\n", mem_mask, m_regs.grpmaska);
- return m_regs.grpmaska;
+u16 mc68328_device::wcmpr_r() // 0x61a
+{
+ LOGMASKED(LOG_WATCHDOG, "%s: wcmpr_r: WCMPR: %04x\n", machine().describe_context(), m_wcmpr);
+ return m_wcmpr;
+}
- case 0x10a:
- verboselog( *this, 2, "mc68328_r (%04x): GRPMASKB = %04x\n", mem_mask, m_regs.grpmaskb);
- return m_regs.grpmaskb;
+void mc68328_device::wcn_w(u16 data) // 0x61c
+{
+ LOGMASKED(LOG_WATCHDOG, "%s: wcn_w: WCN = %04x (Ignored)\n", machine().describe_context(), data);
+}
+
+u16 mc68328_device::wcn_r() // 0x61c
+{
+ LOGMASKED(LOG_WATCHDOG, "%s: wcn_r: WCN: %04x\n", machine().describe_context(), m_wcn);
+ return m_wcn;
+}
- case 0x10c:
- verboselog( *this, 2, "mc68328_r (%04x): GRPMASKC = %04x\n", mem_mask, m_regs.grpmaskc);
- return m_regs.grpmaskc;
- case 0x10e:
- verboselog( *this, 2, "mc68328_r (%04x): GRPMASKD = %04x\n", mem_mask, m_regs.grpmaskd);
- return m_regs.grpmaskd;
+//-------------------------------------------------
+// SPIS hardware
+//-------------------------------------------------
- case 0x110:
- verboselog( *this, 5, "mc68328_r (%04x): CSA0(0) = %04x\n", mem_mask, m_regs.csa0 & 0x0000ffff);
- return m_regs.csa0 & 0x0000ffff;
+void mc68328_device::spisr_w(u16 data) // 0x700
+{
+ LOGMASKED(LOG_SPIS, "%s: spisr_w: SPISR = %04x\n", machine().describe_context(), data);
+ m_spisr = data;
+}
- case 0x112:
- verboselog( *this, 5, "mc68328_r (%04x): CSA0(16) = %04x\n", mem_mask, m_regs.csa0 >> 16);
- return m_regs.csa0 >> 16;
+u16 mc68328_device::spisr_r() // 0x700
+{
+ LOGMASKED(LOG_SPIS, "%s: spisr_r: SPISR: %04x\n", machine().describe_context(), m_spisr);
+ return m_spisr;
+}
- case 0x114:
- verboselog( *this, 5, "mc68328_r (%04x): CSA1(0) = %04x\n", mem_mask, m_regs.csa1 & 0x0000ffff);
- return m_regs.csa1 & 0x0000ffff;
- case 0x116:
- verboselog( *this, 5, "mc68328_r (%04x): CSA1(16) = %04x\n", mem_mask, m_regs.csa1 >> 16);
- return m_regs.csa1 >> 16;
+//-------------------------------------------------
+// SPIM hardware
+//-------------------------------------------------
- case 0x118:
- verboselog( *this, 5, "mc68328_r (%04x): CSA2(0) = %04x\n", mem_mask, m_regs.csa2 & 0x0000ffff);
- return m_regs.csa2 & 0x0000ffff;
+TIMER_CALLBACK_MEMBER(mc68328_base_device::spim_tick)
+{
+ m_spmclk = !m_spmclk;
+ const bool idle_state = BIT(m_spimcont, SPIM_POL_BIT);
+ const bool invert_phase = BIT(m_spimcont, SPIM_PHA_BIT);
- case 0x11a:
- verboselog( *this, 5, "mc68328_r (%04x): CSA2(16) = %04x\n", mem_mask, m_regs.csa2 >> 16);
- return m_regs.csa2 >> 16;
+ u16 spim_bit_index = m_spimcont & SPIM_BIT_COUNT;
- case 0x11c:
- verboselog( *this, 5, "mc68328_r (%04x): CSA3(0) = %04x\n", mem_mask, m_regs.csa3 & 0x0000ffff);
- return m_regs.csa3 & 0x0000ffff;
+ LOGMASKED(LOG_SPIM, "SPIM Tick:\n");
+ LOGMASKED(LOG_SPIM, " CLK state: %d\n", m_spmclk);
+ LOGMASKED(LOG_SPIM, " Bit index: %d\n", spim_bit_index);
+ LOGMASKED(LOG_SPIM, " Data before: %04x\n", m_spimdata);
- case 0x11e:
- verboselog( *this, 5, "mc68328_r (%04x): CSA3(16) = %04x\n", mem_mask, m_regs.csa3 >> 16);
- return m_regs.csa3 >> 16;
+ const bool clock_txd = (m_spmclk == idle_state && invert_phase) || (m_spmclk != idle_state && !invert_phase);
+ if (clock_txd)
+ {
+ m_spmtxd = BIT(m_spimdata, m_spim_bit_read_idx);
+ LOGMASKED(LOG_SPIM, " Clocking TxD: %d\n", m_spmtxd);
+ m_out_spim_cb(m_spmtxd);
+ }
+ else
+ {
+ m_spmrxd = m_in_spim_cb();
+ LOGMASKED(LOG_SPIM, " Clocking RxD: %d\n", m_spmrxd);
+ LOGMASKED(LOG_SPIM, " Shifting\n");
+ m_spimdata = (m_spimdata << 1) | m_spmrxd;
+ }
+ LOGMASKED(LOG_SPIM, " Data after: %04x\n", m_spimdata);
- case 0x120:
- verboselog( *this, 5, "mc68328_r (%04x): CSB0(0) = %04x\n", mem_mask, m_regs.csb0 & 0x0000ffff);
- return m_regs.csb0 & 0x0000ffff;
+ if (m_spmclk == idle_state)
+ {
+ if (spim_bit_index == 0)
+ {
+ LOGMASKED(LOG_SPIM, " Bit 0 clocked out, ending transfer\n");
+ m_spim->adjust(attotime::never);
- case 0x122:
- verboselog( *this, 5, "mc68328_r (%04x): CSB0(16) = %04x\n", mem_mask, m_regs.csb0 >> 16);
- return m_regs.csb0 >> 16;
+ if (BIT(m_spimcont, SPIM_IRQEN_BIT))
+ {
+ m_spimcont |= (1 << SPIM_SPIMIRQ_BIT);
+ LOGMASKED(LOG_SPIM, "Triggering SPIM Interrupt\n" );
+ set_interrupt_line(INT_SPIM, 1);
+ }
+ }
+ else
+ {
+ spim_bit_index--;
+ m_spimcont &= ~SPIM_BIT_COUNT;
+ m_spimcont |= spim_bit_index;
+ }
+ }
+}
- case 0x124:
- verboselog( *this, 5, "mc68328_r (%04x): CSB1(0) = %04x\n", mem_mask, m_regs.csb1 & 0x0000ffff);
- return m_regs.csb1 & 0x0000ffff;
+void mc68328_base_device::spimdata_w(u16 data) // 0x800
+{
+ LOGMASKED(LOG_SPIM, "%s: spimdata_w: SPIMDATA = %04x\n", machine().describe_context(), data);
+ m_spimdata = data;
+}
- case 0x126:
- verboselog( *this, 5, "mc68328_r (%04x): CSB1(16) = %04x\n", mem_mask, m_regs.csb1 >> 16);
- return m_regs.csb1 >> 16;
+u16 mc68328_base_device::spimdata_r() // 0x800
+{
+ LOGMASKED(LOG_SPIM, "%s: spimdata_r: SPIMDATA: %04x\n", machine().describe_context(), m_spimdata);
+ return m_spimdata;
+}
- case 0x128:
- verboselog( *this, 5, "mc68328_r (%04x): CSB2(0) = %04x\n", mem_mask, m_regs.csb2 & 0x0000ffff);
- return m_regs.csb2 & 0x0000ffff;
+void mc68328_base_device::spimcont_w(u16 data) // 0x802
+{
+ LOGMASKED(LOG_SPIM, "%s: spimcont_w: SPIMCONT = %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_SPIM, "%s: Count = %d\n", machine().describe_context(), data & SPIM_BIT_COUNT);
+ LOGMASKED(LOG_SPIM, "%s: Polarity = %s\n", machine().describe_context(), BIT(data, SPIM_POL_BIT) ? "Inverted" : "Active-high");
+ LOGMASKED(LOG_SPIM, "%s: Phase = %s\n", machine().describe_context(), BIT(data, SPIM_PHA_BIT) ? "Opposite" : "Normal");
+ LOGMASKED(LOG_SPIM, "%s: IRQ Enable = %s\n", machine().describe_context(), BIT(data, SPIM_IRQEN_BIT) ? "Enable" : "Disable");
+ LOGMASKED(LOG_SPIM, "%s: IRQ Pending = %s\n", machine().describe_context(), BIT(data, SPIM_SPIMIRQ_BIT) ? "Yes" : "No");
+ LOGMASKED(LOG_SPIM, "%s: Exchange = %s\n", machine().describe_context(), BIT(data, SPIM_XCH_BIT) ? "Initiate" : "Idle");
+ LOGMASKED(LOG_SPIM, "%s: SPIM Enable = %s\n", machine().describe_context(), BIT(data, SPIM_SPMEN_BIT) ? "Enable" : "Disable");
+ LOGMASKED(LOG_SPIM, "%s: Data Rate = Divide By %d\n", machine().describe_context(), 4 << ((data & SPIM_RATE_MASK) >> SPIM_RATE_SHIFT) );
+
+ const u16 old = m_spimcont;
+ m_spimcont = data;
+
+ if (BIT(data, SPIM_SPMEN_BIT) && BIT(data, SPIM_XCH_BIT) && !BIT(old, SPIM_XCH_BIT))
+ {
+ const uint64_t divisor = 2 << ((data & SPIM_RATE_MASK) >> SPIM_RATE_SHIFT);
+ const attotime rate = attotime::from_ticks(divisor, clock());
+ m_spim_bit_read_idx = m_spimcont & SPIM_BIT_COUNT;
+ m_spim->adjust(rate, 0, rate);
- case 0x12a:
- verboselog( *this, 5, "mc68328_r (%04x): CSB2(16) = %04x\n", mem_mask, m_regs.csb2 >> 16);
- return m_regs.csb2 >> 16;
+ m_spimcont &= ~(1 << SPIM_XCH_BIT);
+ }
- case 0x12c:
- verboselog( *this, 5, "mc68328_r (%04x): CSB3(0) = %04x\n", mem_mask, m_regs.csb3 & 0x0000ffff);
- return m_regs.csb3 & 0x0000ffff;
+ if (!BIT(data, SPIM_IRQEN_BIT) || !BIT(data, SPIM_SPIMIRQ_BIT))
+ {
+ set_interrupt_line(INT_SPIM, 0);
+ }
+ else
+ {
+ set_interrupt_line(INT_SPIM, 1);
+ }
+}
- case 0x12e:
- verboselog( *this, 5, "mc68328_r (%04x): CSB3(16) = %04x\n", mem_mask, m_regs.csb3 >> 16);
- return m_regs.csb3 >> 16;
+u16 mc68328_base_device::spimcont_r() // 0x802
+{
+ LOGMASKED(LOG_SPIM, "%s: spimcont_r: SPIMCONT: %04x\n", machine().describe_context(), m_spimcont);
+ return m_spimcont;
+}
- case 0x130:
- verboselog( *this, 5, "mc68328_r (%04x): CSC0(0) = %04x\n", mem_mask, m_regs.csc0 & 0x0000ffff);
- return m_regs.csc0 & 0x0000ffff;
- case 0x132:
- verboselog( *this, 5, "mc68328_r (%04x): CSC0(16) = %04x\n", mem_mask, m_regs.csc0 >> 16);
- return m_regs.csc0 >> 16;
+//-------------------------------------------------
+// UART hardware
+//-------------------------------------------------
- case 0x134:
- verboselog( *this, 5, "mc68328_r (%04x): CSC1(0) = %04x\n", mem_mask, m_regs.csc1 & 0x0000ffff);
- return m_regs.csc1 & 0x0000ffff;
+void mc68328_base_device::ustcnt_w(u16 data) // 0x900
+{
+ LOGMASKED(LOG_UART, "%s: ustcnt_w: USTCNT = %04x\n", machine().describe_context(), data);
+ m_ustcnt = data;
+}
- case 0x136:
- verboselog( *this, 5, "mc68328_r (%04x): CSC1(16) = %04x\n", mem_mask, m_regs.csc1 >> 16);
- return m_regs.csc1 >> 16;
+u16 mc68328_base_device::ustcnt_r() // 0x900
+{
+ LOGMASKED(LOG_UART, "%s: ustcnt_r: USTCNT: %04x\n", machine().describe_context(), m_ustcnt);
+ return m_ustcnt;
+}
- case 0x138:
- verboselog( *this, 5, "mc68328_r (%04x): CSC2(0) = %04x\n", mem_mask, m_regs.csc2 & 0x0000ffff);
- return m_regs.csc2 & 0x0000ffff;
+void mc68328_base_device::ubaud_w(u16 data) // 0x902
+{
+ LOGMASKED(LOG_UART, "%s: ubaud_w: UBAUD = %04x\n", machine().describe_context(), data);
+ m_ubaud = data;
+}
- case 0x13a:
- verboselog( *this, 5, "mc68328_r (%04x): CSC2(16) = %04x\n", mem_mask, m_regs.csc2 >> 16);
- return m_regs.csc2 >> 16;
+u16 mc68328_base_device::ubaud_r() // 0x902
+{
+ LOGMASKED(LOG_UART, "%s: ubaud_r: UBAUD: %04x\n", machine().describe_context(), m_ubaud);
+ return m_ubaud;
+}
- case 0x13c:
- verboselog( *this, 5, "mc68328_r (%04x): CSC3(0) = %04x\n", mem_mask, m_regs.csc3 & 0x0000ffff);
- return m_regs.csc3 & 0x0000ffff;
+void mc68328_base_device::urx_w(u16 data) // 0x904
+{
+ LOGMASKED(LOG_UART, "%s: urx_w: URX = %04x (Not Yet Implemented)\n", machine().describe_context(), data);
+}
- case 0x13e:
- verboselog( *this, 5, "mc68328_r (%04x): CSC3(16) = %04x\n", mem_mask, m_regs.csc3 >> 16);
- return m_regs.csc3 >> 16;
+u16 mc68328_base_device::urx_r() // 0x904
+{
+ LOGMASKED(LOG_UART, "%s: urx_r: URX: %04x\n", machine().describe_context(), m_urx);
+ return m_urx;
+}
- case 0x140:
- verboselog( *this, 5, "mc68328_r (%04x): CSD0(0) = %04x\n", mem_mask, m_regs.csd0 & 0x0000ffff);
- return m_regs.csd0 & 0x0000ffff;
+void mc68328_base_device::utx_w(u16 data) // 0x906
+{
+ LOGMASKED(LOG_UART, "%s: utx_w: UTX = %04x (Not Yet Implemented)\n", machine().describe_context(), data);
+}
- case 0x142:
- verboselog( *this, 5, "mc68328_r (%04x): CSD0(16) = %04x\n", mem_mask, m_regs.csd0 >> 16);
- return m_regs.csd0 >> 16;
+u16 mc68328_base_device::utx_r() // 0x906
+{
+ u16 data = m_utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL;
+ LOGMASKED(LOG_UART, "%s: utx_r: UTX: %04x\n", machine().describe_context(), data);
+ return data;
+}
- case 0x144:
- verboselog( *this, 5, "mc68328_r (%04x): CSD1(0) = %04x\n", mem_mask, m_regs.csd1 & 0x0000ffff);
- return m_regs.csd1 & 0x0000ffff;
+void mc68328_base_device::umisc_w(u16 data) // 0x908
+{
+ LOGMASKED(LOG_UART, "%s: umisc_w: UMISC = %04x (Not Yet Implemented)\n", machine().describe_context(), data);
+ m_umisc = data;
+}
- case 0x146:
- verboselog( *this, 5, "mc68328_r (%04x): CSD1(16) = %04x\n", mem_mask, m_regs.csd1 >> 16);
- return m_regs.csd1 >> 16;
+u16 mc68328_base_device::umisc_r() // 0x908
+{
+ LOGMASKED(LOG_UART, "%s: umisc_r: UMISC: %04x\n", machine().describe_context(), m_umisc);
+ return m_umisc;
+}
- case 0x148:
- verboselog( *this, 5, "mc68328_r (%04x): CSD2(0) = %04x\n", mem_mask, m_regs.csd2 & 0x0000ffff);
- return m_regs.csd2 & 0x0000ffff;
- case 0x14a:
- verboselog( *this, 5, "mc68328_r (%04x): CSD2(16) = %04x\n", mem_mask, m_regs.csd2 >> 16);
- return m_regs.csd2 >> 16;
+//-------------------------------------------------
+// LCD hardware - Shared and Standard MC68328
+//-------------------------------------------------
- case 0x14c:
- verboselog( *this, 5, "mc68328_r (%04x): CSD3(0) = %04x\n", mem_mask, m_regs.csd3 & 0x0000ffff);
- return m_regs.csd3 & 0x0000ffff;
+void mc68328_device::lcd_update_info()
+{
+ if (!m_lcd_update_pending)
+ {
+ return;
+ }
+ const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
+ attotime lcd_dma_duration = attotime::from_ticks(lcd_get_line_word_count() * sysclk_divisor, clock());
+ attotime lcd_scan_duration = lcd_get_line_rate();
+ attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1);
+ LOGMASKED(LOG_LCD, "lxmax %d, lymax %d, divisor %d, lrra %02x, lpxcd %02x\n", m_lxmax, m_lymax + 1, sysclk_divisor, m_lpxcd + 1);
- case 0x14e:
- verboselog( *this, 5, "mc68328_r (%04x): CSD3(16) = %04x\n", mem_mask, m_regs.csd3 >> 16);
- return m_regs.csd3 >> 16;
+ constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff };
+ m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), lcd_get_width(), m_lymax + 1, BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT], BIT_WIDTHS[m_lpicf & LPICF_GS]);
- case 0x200:
- verboselog( *this, 2, "mc68328_r (%04x): PLLCR = %04x\n", mem_mask, m_regs.pllcr);
- return m_regs.pllcr;
+ m_lcd_update_pending = false;
+}
- case 0x202:
- verboselog( *this, 2, "mc68328_r (%04x): PLLFSR = %04x\n", mem_mask, m_regs.pllfsr);
- m_regs.pllfsr ^= 0x8000;
- return m_regs.pllfsr;
+u16 mc68328_device::lcd_get_lxmax_mask()
+{
+ constexpr u16 LXMAX_MASK = 0x03ff;
+ return LXMAX_MASK;
+}
- case 0x206:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff206)\n", mem_mask);
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PCTLR = %02x\n", mem_mask, m_regs.pctlr);
- return m_regs.pctlr << 8;
- }
- break;
+int mc68328_device::lcd_get_width()
+{
+ return (m_lxmax & lcd_get_lxmax_mask()) + 1;
+}
- case 0x300:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff301)\n", mem_mask);
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): IVR = %02x\n", mem_mask, m_regs.ivr);
- return m_regs.ivr << 8;
- }
- break;
+u32 mc68328_device::lcd_get_line_word_count()
+{
+ return m_lvpw != m_llbar ? (m_llbar + 1) : m_llbar;
+}
- case 0x302:
- verboselog( *this, 2, "mc68328_r (%04x): ICR = %04x\n", mem_mask, m_regs.icr);
- return m_regs.icr;
+attotime mc68328_device::lcd_get_line_rate()
+{
+ const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
+ return attotime::from_ticks(m_llbar, clock() / sysclk_divisor);
+}
- case 0x304:
- verboselog( *this, 2, "mc68328_r (%04x): IMR(16) = %04x\n", mem_mask, m_regs.imr >> 16);
- return m_regs.imr >> 16;
+u8 mc68328_device::lcd_get_panel_bit_size()
+{
+ constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff };
+ return BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT];
+}
- case 0x306:
- verboselog( *this, 2, "mc68328_r (%04x): IMR(0) = %04x\n", mem_mask, m_regs.imr & 0x0000ffff);
- return m_regs.imr & 0x0000ffff;
+attotime mc68328_device::get_pixclk_rate()
+{
+ u32 divisor = 1;
+ if (BIT(m_lckcon, LCKCON_PCDS_BIT)) // Use PIXCLK from PLL
+ divisor = VCO_DIVISORS[(m_pllcr & PLLCR_PIXCLK_SEL) >> PLLCR_PIXCLK_SHIFT];
+ else // Use SYSCLK from PLL
+ divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
- case 0x308:
- verboselog( *this, 2, "mc68328_r (%04x): IWR(16) = %04x\n", mem_mask, m_regs.iwr >> 16);
- return m_regs.iwr >> 16;
+ return attotime::from_ticks((m_lpxcd & LPXCD_MASK) + 1, clock() / divisor);
+}
- case 0x30a:
- verboselog( *this, 2, "mc68328_r (%04x): IWR(0) = %04x\n", mem_mask, m_regs.iwr & 0x0000ffff);
- return m_regs.iwr & 0x0000ffff;
+void mc68328_base_device::fill_lcd_dma_buffer()
+{
+ if (m_lcd_sysmem_ptr == m_lssa)
+ {
+ lcd_update_info();
+ m_out_flm_cb(BIT(m_lpolcf, LPOLCF_FLMPOL_BIT) ? 0 : 1);
+ m_lssa_end = m_lssa + ((m_lvpw * (m_lymax + 1)) << 1);
+ }
+ else
+ {
+ m_out_flm_cb(BIT(m_lpolcf, LPOLCF_FLMPOL_BIT) ? 1 : 0);
+ }
+ m_out_llp_cb(BIT(m_lpolcf, LPOLCF_LPPOL_BIT) ? 0 : 1);
- case 0x30c:
- verboselog( *this, 2, "mc68328_r (%04x): ISR(16) = %04x\n", mem_mask, m_regs.isr >> 16);
- return m_regs.isr >> 16;
+ attotime buffer_duration = lcd_get_line_rate();
+ m_lcd_scan->adjust(buffer_duration);
- case 0x30e:
- verboselog( *this, 2, "mc68328_r (%04x): ISR(0) = %04x\n", mem_mask, m_regs.isr & 0x0000ffff);
- return m_regs.isr & 0x0000ffff;
+ address_space &prg_space = space(AS_PROGRAM);
+ const u32 word_count = lcd_get_line_word_count();
+ for (u32 word_index = 0; word_index < word_count; word_index++)
+ {
+ m_lcd_line_buffer[word_index] = prg_space.read_word(m_lcd_sysmem_ptr + (word_index << 1));
+ }
- case 0x310:
- verboselog( *this, 2, "mc68328_r (%04x): IPR(16) = %04x\n", mem_mask, m_regs.ipr >> 16);
- return m_regs.ipr >> 16;
+ m_lcd_sysmem_ptr += m_lvpw << 1;
+ if (m_lcd_sysmem_ptr >= m_lssa_end)
+ {
+ m_lcd_sysmem_ptr = m_lssa;
+ }
- case 0x312:
- verboselog( *this, 2, "mc68328_r (%04x): IPR(0) = %04x\n", mem_mask, m_regs.ipr & 0x0000ffff);
- return m_regs.ipr & 0x0000ffff;
+ m_lcd_line_bit = 15;
+ m_lcd_line_word = 0;
+}
- case 0x400:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PADATA = %02x\n", mem_mask, m_regs.padata);
- if (!m_in_port_a_cb.isnull())
- {
- return m_in_port_a_cb(0);
- }
- else
- {
- return m_regs.padata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PADIR = %02x\n", mem_mask, m_regs.padir);
- return m_regs.padir << 8;
- }
+TIMER_CALLBACK_MEMBER(mc68328_base_device::lcd_scan_tick)
+{
+ m_out_llp_cb(BIT(m_lpolcf, LPOLCF_LPPOL_BIT) ? 1 : 0);
+ m_lsclk = !m_lsclk;
- case 0x402:
- if (mem_mask & 0x00ff)
+ if (m_lsclk)
+ {
+ u8 data = 0;
+ switch (lcd_get_panel_bit_size())
+ {
+ case 1:
+ data = BIT(m_lcd_line_buffer[m_lcd_line_word], m_lcd_line_bit);
+ if (m_lcd_line_bit == 0)
{
- verboselog( *this, 2, "mc68328_r (%04x): PASEL = %02x\n", mem_mask, m_regs.pasel);
- return m_regs.pasel;
+ m_lcd_line_bit = 15;
+ m_lcd_line_word++;
}
else
{
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff402)\n", mem_mask);
+ m_lcd_line_bit--;
}
break;
-
- case 0x408:
- if (mem_mask & 0x00ff)
+ case 2:
+ data = (m_lcd_line_buffer[m_lcd_line_word] >> (m_lcd_line_bit - 1)) & 3;
+ if (m_lcd_line_bit <= 1)
{
- verboselog( *this, 2, "mc68328_r (%04x): PBDATA = %02x\n", mem_mask, m_regs.pbdata);
- if (!m_in_port_b_cb.isnull())
- {
- return m_in_port_b_cb(0);
- }
- else
- {
- return m_regs.pbdata;
- }
+ m_lcd_line_bit = 15;
+ m_lcd_line_word++;
}
else
{
- verboselog( *this, 2, "mc68328_r (%04x): PBDIR = %02x\n", mem_mask, m_regs.pbdir);
- return m_regs.pbdir << 8;
+ m_lcd_line_bit -= 2;
}
-
- case 0x40a:
- if (mem_mask & 0x00ff)
+ break;
+ case 4:
+ data = (m_lcd_line_buffer[m_lcd_line_word] >> (m_lcd_line_bit - 3)) & 15;
+ if (m_lcd_line_bit <= 3)
{
- verboselog( *this, 2, "mc68328_r (%04x): PBSEL = %02x\n", mem_mask, m_regs.pbsel);
- return m_regs.pbsel;
+ m_lcd_line_bit = 15;
+ m_lcd_line_word++;
}
else
{
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff40a)\n", mem_mask);
+ m_lcd_line_bit -= 4;
}
break;
+ default:
+ // Invalid mode; don't send anything
+ break;
+ }
+ m_out_ld_cb(data);
+ }
+ m_out_lsclk_cb(m_lsclk);
- case 0x410:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PCDATA = %02x\n", mem_mask, m_regs.pcdata);
- if (!m_in_port_c_cb.isnull())
- {
- return m_in_port_c_cb(0);
- }
- else
- {
- return m_regs.pcdata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PCDIR = %02x\n", mem_mask, m_regs.pcdir);
- return m_regs.pcdir << 8;
- }
+ if (m_lcd_line_word == lcd_get_line_word_count())
+ {
+ fill_lcd_dma_buffer();
+ }
+ else
+ {
+ m_lcd_scan->adjust(get_pixclk_rate());
+ }
+}
- case 0x412:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PCSEL = %02x\n", mem_mask, m_regs.pcsel);
- return m_regs.pcsel;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff412)\n", mem_mask);
- }
- break;
+void mc68328_base_device::lssa_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0xa00
+{
+ LOGMASKED(LOG_LCD, "%s: lssa_msw_w: LSSA(MSW) = %04x\n", machine().describe_context(), data);
+ m_lssa &= ~(mem_mask << 16);
+ m_lssa |= (data & mem_mask) << 16;
+ LOGMASKED(LOG_LCD, "%s: Address: %08x\n", machine().describe_context(), m_lssa);
+}
- case 0x418:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PDDATA = %02x\n", mem_mask, m_regs.pddata);
- if (!m_in_port_d_cb.isnull())
- {
- return m_in_port_d_cb(0);
- }
- else
- {
- return m_regs.pddata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PDDIR = %02x\n", mem_mask, m_regs.pddir);
- return m_regs.pddir << 8;
- }
+u16 mc68328_base_device::lssa_msw_r() // 0xa00
+{
+ LOGMASKED(LOG_LCD, "%s: lssa_msw_r: LSSA(MSW): %04x\n", machine().describe_context(), (u16)(m_lssa >> 16));
+ return (u16)(m_lssa >> 16);
+}
- case 0x41a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff41b)\n", mem_mask);
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PDPUEN = %02x\n", mem_mask, m_regs.pdpuen);
- return m_regs.pdpuen << 8;
- }
+void mc68328_base_device::lssa_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0xa02
+{
+ LOGMASKED(LOG_LCD, "%s: lssa_lsw_w: LSSA(LSW) = %04x\n", machine().describe_context(), data);
+ m_lssa &= 0xffff0000 | (~mem_mask);
+ m_lssa |= data & mem_mask;
+ LOGMASKED(LOG_LCD, " Address: %08x\n", machine().describe_context(), m_lssa);
+}
+
+u16 mc68328_base_device::lssa_lsw_r() // 0xa02
+{
+ LOGMASKED(LOG_LCD, "%s: lssa_lsw_r: LSSA(LSW): %04x\n", machine().describe_context(), (u16)m_lssa);
+ return (u16)m_lssa;
+}
+
+void mc68328_base_device::lvpw_w(u8 data) // 0xa05
+{
+ LOGMASKED(LOG_LCD, "%s: lvpw_w: LVPW = %02x\n", machine().describe_context(), data);
+ m_lvpw = data;
+ LOGMASKED(LOG_LCD, "%s: Virtual Page Width: %d words\n", machine().describe_context(), m_lvpw);
+}
+
+u8 mc68328_base_device::lvpw_r() // 0xa05
+{
+ LOGMASKED(LOG_LCD, "%s: lvpw_r: LVPW: %02x\n", machine().describe_context(), m_lvpw);
+ return m_lvpw;
+}
+
+void mc68328_base_device::lxmax_w(u16 data) // 0xa08
+{
+ m_lcd_update_pending = m_lcd_update_pending || (m_lxmax != (data & lcd_get_lxmax_mask()));
+ LOGMASKED(LOG_LCD, "%s: lxmax_w: LXMAX = %04x\n", machine().describe_context(), data);
+ m_lxmax = data & lcd_get_lxmax_mask();
+ LOGMASKED(LOG_LCD, "%s: Width: %d\n", machine().describe_context(), lcd_get_width());
+}
+
+u16 mc68328_base_device::lxmax_r() // 0xa08
+{
+ LOGMASKED(LOG_LCD, "%s: lxmax_r: LXMAX: %04x\n", machine().describe_context(), m_lxmax);
+ return m_lxmax;
+}
+
+void mc68328_base_device::lymax_w(u16 data) // 0xa0a
+{
+ m_lcd_update_pending = m_lcd_update_pending || (m_lxmax != (data & LYMAX_MASK));
+ LOGMASKED(LOG_LCD, "%s: lymax_w: LYMAX = %04x\n", machine().describe_context(), data);
+ m_lymax = data & LYMAX_MASK;
+ LOGMASKED(LOG_LCD, "%s: Height: %d\n", machine().describe_context(), (data & 0x03ff) + 1);
+}
+
+u16 mc68328_base_device::lymax_r() // 0xa0a
+{
+ LOGMASKED(LOG_LCD, "%s: lymax_r: LYMAX: %04x\n", machine().describe_context(), m_lymax);
+ return m_lymax;
+}
+
+void mc68328_base_device::lcxp_w(u16 data) // 0xa18
+{
+ LOGMASKED(LOG_LCD, "%s: lcxp_w: LCXP = %04x\n", machine().describe_context(), data);
+ m_lcxp = data;
+ LOGMASKED(LOG_LCD, "%s: X Position: %d\n", machine().describe_context(), data & 0x03ff);
+ switch (m_lcxp >> 14)
+ {
+ case 0:
+ LOGMASKED(LOG_LCD, "%s: Cursor Control: Transparent\n", machine().describe_context());
break;
- case 0x41c:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PDIRQEN = %02x\n", mem_mask, m_regs.pdirqen);
- return m_regs.pdirqen;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PDPOL = %02x\n", mem_mask, m_regs.pdpol);
- return m_regs.pdpol << 8;
- }
+ case 1:
+ LOGMASKED(LOG_LCD, "%s: Cursor Control: Black\n", machine().describe_context());
+ break;
- case 0x41e:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PDIRQEDGE = %02x\n", mem_mask, m_regs.pdirqedge);
- return m_regs.pdirqedge;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff41e)\n", mem_mask);
- }
+ case 2:
+ LOGMASKED(LOG_LCD, "%s: Cursor Control: Reverse\n", machine().describe_context());
break;
- case 0x420:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PEDATA = %02x\n", mem_mask, m_regs.pedata);
- if (!m_in_port_e_cb.isnull())
- {
- return m_in_port_e_cb(0);
- }
- else
- {
- return m_regs.pedata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PEDIR = %02x\n", mem_mask, m_regs.pedir);
- return m_regs.pedir << 8;
- }
+ case 3:
+ LOGMASKED(LOG_LCD, "%s: Cursor Control: Invalid\n", machine().describe_context());
+ break;
+ }
+}
- case 0x422:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PESEL = %02x\n", mem_mask, m_regs.pesel);
- return m_regs.pesel;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PEPUEN = %02x\n", mem_mask, m_regs.pepuen);
- return m_regs.pepuen << 8;
- }
+u16 mc68328_base_device::lcxp_r() // 0xa18
+{
+ LOGMASKED(LOG_LCD, "%s: lcxp_r: LCXP: %04x\n", machine().describe_context(), m_lcxp);
+ return m_lcxp;
+}
- case 0x428:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PFDATA = %02x\n", mem_mask, m_regs.pfdata);
- if (!m_in_port_f_cb.isnull())
- {
- return m_in_port_f_cb(0);
- }
- else
- {
- return m_regs.pfdata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PFDIR = %02x\n", mem_mask, m_regs.pfdir);
- return m_regs.pfdir << 8;
- }
+void mc68328_base_device::lcyp_w(u16 data) // 0xa1a
+{
+ LOGMASKED(LOG_LCD, "%s: lcyp_w: LCYP = %04x\n", machine().describe_context(), data);
+ m_lcyp = data;
+ LOGMASKED(LOG_LCD, "%s: Y Position: %d\n", machine().describe_context(), data & 0x01ff);
+}
- case 0x42a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PFSEL = %02x\n", mem_mask, m_regs.pfsel);
- return m_regs.pfsel;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PFPUEN = %02x\n", mem_mask, m_regs.pfpuen);
- return m_regs.pfpuen << 8;
- }
+u16 mc68328_base_device::lcyp_r() // 0xa1a
+{
+ LOGMASKED(LOG_LCD, "%s: lcyp_r: LCYP: %04x\n", machine().describe_context(), m_lcyp);
+ return m_lcyp;
+}
- case 0x430:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PGDATA = %02x\n", mem_mask, m_regs.pgdata);
- if (!m_in_port_g_cb.isnull())
- {
- return m_in_port_g_cb(0);
- }
- else
- {
- return m_regs.pgdata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PGDIR = %02x\n", mem_mask, m_regs.pgdir);
- return m_regs.pgdir << 8;
- }
+void mc68328_base_device::lcwch_w(u16 data) // 0xa1c
+{
+ LOGMASKED(LOG_LCD, "%s: lcwch_w: LCWCH = %04x\n", machine().describe_context(), data);
+ m_lcwch = data;
+ LOGMASKED(LOG_LCD, "%s: Width: %d\n", machine().describe_context(), (data >> 8) & 0x1f);
+ LOGMASKED(LOG_LCD, "%s: Height: %d\n", machine().describe_context(), data & 0x1f);
+}
- case 0x432:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PGSEL = %02x\n", mem_mask, m_regs.pgsel);
- return m_regs.pgsel;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PGPUEN = %02x\n", mem_mask, m_regs.pgpuen);
- return m_regs.pgpuen << 8;
- }
+u16 mc68328_base_device::lcwch_r() // 0xa1c
+{
+ LOGMASKED(LOG_LCD, "%s: lcwch_r: LCWCH: %04x\n", machine().describe_context(), m_lcwch);
+ return m_lcwch;
+}
- case 0x438:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PJDATA = %02x\n", mem_mask, m_regs.pjdata);
- if (!m_in_port_j_cb.isnull())
- {
- return m_in_port_j_cb(0);
- }
- else
- {
- return m_regs.pjdata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PJDIR = %02x\n", mem_mask, m_regs.pjdir);
- return m_regs.pjdir << 8;
- }
+void mc68328_base_device::lblkc_w(u8 data) // 0xa1f
+{
+ LOGMASKED(LOG_LCD, "%s: lblkc_w: LBLKC = %02x\n", machine().describe_context(), data);
+ m_lblkc = data;
+ LOGMASKED(LOG_LCD, "%s: Blink Enable: %d\n", machine().describe_context(), m_lblkc >> 7);
+ LOGMASKED(LOG_LCD, "%s: Blink Divisor: %d\n", machine().describe_context(), m_lblkc & 0x7f);
+}
- case 0x43a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PJSEL = %02x\n", mem_mask, m_regs.pjsel);
- return m_regs.pjsel;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff43a)\n", mem_mask);
- }
- break;
+u8 mc68328_base_device::lblkc_r() // 0xa1f
+{
+ LOGMASKED(LOG_LCD, "%s: lblkc_r: LBLKC: %02x\n", machine().describe_context(), m_lblkc);
+ return m_lblkc;
+}
- case 0x440:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PKDATA = %02x\n", mem_mask, m_regs.pkdata);
- if (!m_in_port_k_cb.isnull())
- {
- return m_in_port_k_cb(0);
- }
- else
- {
- return m_regs.pkdata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PKDIR = %02x\n", mem_mask, m_regs.pkdir);
- return m_regs.pkdir << 8;
- }
+void mc68328_device::lpicf_w(u8 data) // 0xa20
+{
+ static const char *const PBSIZ_NAMES[4] = { "1-bit", "2-bit", "4-bit", "Invalid" };
+ LOGMASKED(LOG_LCD, "%s: lpicf_w: LPICF = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_LCD, "%s: Grayscale Mode: %d\n", machine().describe_context(), data & LPICF_GS);
+ LOGMASKED(LOG_LCD, "%s: Bus Size: %s\n", machine().describe_context(), PBSIZ_NAMES[(data & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT]);
+ m_lpicf = data;
+}
- case 0x442:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PKSEL = %02x\n", mem_mask, m_regs.pksel);
- return m_regs.pksel;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PKPUEN = %02x\n", mem_mask, m_regs.pkpuen);
- return m_regs.pkpuen << 8;
- }
+u8 mc68328_base_device::lpicf_r() // 0xa20
+{
+ LOGMASKED(LOG_LCD, "%s: lpicf_r: LPICF: %02x\n", machine().describe_context(), m_lpicf);
+ return m_lpicf;
+}
- case 0x448:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PMDATA = %02x\n", mem_mask, m_regs.pmdata);
- if (!m_in_port_m_cb.isnull())
- {
- return m_in_port_m_cb(0);
- }
- else
- {
- return m_regs.pmdata;
- }
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PMDIR = %02x\n", mem_mask, m_regs.pmdir);
- return m_regs.pmdir << 8;
- }
+void mc68328_base_device::lpolcf_w(u8 data) // 0xa21
+{
+ LOGMASKED(LOG_LCD, "%s: lpolcf_w: LPOLCF = %02x\n", machine().describe_context(), data);
+ m_lpolcf = data;
+ LOGMASKED(LOG_LCD, "%s: LCD Shift Clock Polarity: %s\n", machine().describe_context(), (m_lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK");
+ LOGMASKED(LOG_LCD, "%s: First-line marker polarity: %s\n", machine().describe_context(), (m_lpicf & 0x04) ? "Active Low" : "Active High");
+ LOGMASKED(LOG_LCD, "%s: Line-pulse polarity: %s\n", machine().describe_context(), (m_lpicf & 0x02) ? "Active Low" : "Active High");
+ LOGMASKED(LOG_LCD, "%s: Pixel polarity: %s\n", machine().describe_context(), (m_lpicf & 0x01) ? "Active Low" : "Active High");
+}
- case 0x44a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): PMSEL = %02x\n", mem_mask, m_regs.pmsel);
- return m_regs.pmsel;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): PMPUEN = %02x\n", mem_mask, m_regs.pmpuen);
- return m_regs.pmpuen << 8;
- }
+u8 mc68328_base_device::lpolcf_r() // 0xa21
+{
+ LOGMASKED(LOG_LCD, "%s: lpolcf_r: LPOLCF: %02x\n", machine().describe_context(), m_lpolcf);
+ return m_lpolcf;
+}
- case 0x500:
- verboselog( *this, 2, "mc68328_r (%04x): PWMC = %04x\n", mem_mask, m_regs.pwmc);
- temp16 = m_regs.pwmc;
- if (m_regs.pwmc & PWMC_PWMIRQ)
- {
- m_regs.pwmc &= ~PWMC_PWMIRQ;
- set_interrupt_line(INT_PWM, 0);
- }
- return temp16;
+void mc68328_base_device::lacdrc_w(u8 data) // 0xa23
+{
+ LOGMASKED(LOG_LCD, "%s: lacdrc_w: LACDRC = %02x\n", machine().describe_context(), data);
+ m_lacdrc = data;
+}
- case 0x502:
- verboselog( *this, 2, "mc68328_r (%04x): PWMP = %04x\n", mem_mask, m_regs.pwmp);
- return m_regs.pwmp;
+u8 mc68328_base_device::lacdrc_r() // 0xa23
+{
+ LOGMASKED(LOG_LCD, "%s: lacdrc_r: LACDRC: %02x\n", machine().describe_context(), m_lacdrc);
+ return m_lacdrc;
+}
- case 0x504:
- verboselog( *this, 2, "mc68328_r (%04x): PWMW = %04x\n", mem_mask, m_regs.pwmw);
- return m_regs.pwmw;
+void mc68328_base_device::lpxcd_w(u8 data) // 0xa25
+{
+ LOGMASKED(LOG_LCD, "%s: lpxcd_w: LPXCD = %02x\n", machine().describe_context(), data);
+ m_lpxcd = data;
+ LOGMASKED(LOG_LCD, "%s: Clock Divisor: %d\n", machine().describe_context(), m_lpxcd + 1);
+}
- case 0x506:
- verboselog( *this, 2, "mc68328_r (%04x): PWMCNT = %04x\n", mem_mask, m_regs.pwmcnt);
- return m_regs.pwmcnt;
+u8 mc68328_base_device::lpxcd_r() // 0xa25
+{
+ LOGMASKED(LOG_LCD, "%s: lpxcd_r: LPXCD: %02x\n", machine().describe_context(), m_lpxcd);
+ return m_lpxcd;
+}
- case 0x600:
- verboselog( *this, 2, "mc68328_r (%04x): TCTL1 = %04x\n", mem_mask, m_regs.tctl[0]);
- return m_regs.tctl[0];
+void mc68328_device::lckcon_w(u8 data) // 0xa27
+{
+ LOGMASKED(LOG_LCD, "%s: lckcon_w: LCKCON = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_LCD, "%s: LCDC Enable: %d\n", machine().describe_context(), BIT(data, LCKCON_LCDON_BIT));
+ LOGMASKED(LOG_LCD, "%s: DMA Burst Length: %d\n", machine().describe_context(), BIT(data, LCKCON_DMA16_BIT) ? 16 : 8);
+ LOGMASKED(LOG_LCD, "%s: DMA Bursting Clock Control: %d\n", machine().describe_context(), ((data & LCKCON_WS) >> LCKCON_WS_SHIFT) + 1);
+ LOGMASKED(LOG_LCD, "%s: Bus Width: %d\n", machine().describe_context(), BIT(data, LCKCON_DWIDTH_BIT) ? 8 : 16);
+ LOGMASKED(LOG_LCD, "%s: Pixel Clock Divider Source: %s\n", machine().describe_context(), BIT(data, LCKCON_PCDS_BIT) ? "PIX" : "SYS");
+
+ const u16 old = m_lckcon;
+ m_lckcon = data;
+
+ lcd_update_info();
+ if (BIT(old, LCKCON_LCDON_BIT) && !BIT(m_lckcon, LCKCON_LCDON_BIT))
+ {
+ m_lcd_scan->adjust(attotime::never);
+ }
+ else if (!BIT(old, LCKCON_LCDON_BIT) && BIT(m_lckcon, LCKCON_LCDON_BIT))
+ {
+ m_lcd_scan->adjust(attotime::never);
+ m_lcd_sysmem_ptr = m_lssa;
+ fill_lcd_dma_buffer();
+ }
+}
- case 0x602:
- verboselog( *this, 2, "mc68328_r (%04x): TPRER1 = %04x\n", mem_mask, m_regs.tprer[0]);
- return m_regs.tprer[0];
+u8 mc68328_base_device::lckcon_r() // 0xa27
+{
+ LOGMASKED(LOG_LCD, "%s: lckcon_r: LCKCON: %02x\n", machine().describe_context(), m_lckcon);
+ return m_lckcon;
+}
- case 0x604:
- verboselog( *this, 2, "mc68328_r (%04x): TCMP1 = %04x\n", mem_mask, m_regs.tcmp[0]);
- return m_regs.tcmp[0];
+void mc68328_device::llbar_w(u8 data) // 0xa29
+{
+ LOGMASKED(LOG_LCD, "%s: llbar_w: LLBAR = %02x\n", machine().describe_context(), data);
+ m_llbar = data;
+ LOGMASKED(LOG_LCD, "%s: Address: %d\n", machine().describe_context(), m_llbar << (BIT(m_lpicf, LPICF_GS_BIT) ? 4 : 5));
+}
- case 0x606:
- verboselog( *this, 2, "mc68328_r (%04x): TCR1 = %04x\n", mem_mask, m_regs.tcr[0]);
- return m_regs.tcr[0];
+u8 mc68328_device::llbar_r() // 0xa29
+{
+ LOGMASKED(LOG_LCD, "%s: llbar_r: LLBAR: %02x\n", machine().describe_context(), m_llbar);
+ return m_llbar;
+}
- case 0x608:
- verboselog( *this, 2, "mc68328_r (%04x): TCN1 = %04x\n", mem_mask, m_regs.tcn[0]);
- return m_regs.tcn[0];
+void mc68328_device::lotcr_w(u8 data) // 0xa2b
+{
+ LOGMASKED(LOG_LCD, "%s: lotcr_w: LOTCR = %02x (Ignored)\n", machine().describe_context(), data);
+}
- case 0x60a:
- verboselog( *this, 5, "mc68328_r (%04x): TSTAT1 = %04x\n", mem_mask, m_regs.tstat[0]);
- m_regs.tclear[0] |= m_regs.tstat[0];
- return m_regs.tstat[0];
+u8 mc68328_device::lotcr_r() // 0xa2b
+{
+ LOGMASKED(LOG_LCD, "%s: lotcr_r: LOTCR: %02x\n", machine().describe_context(), m_lotcr);
+ return m_lotcr;
+}
- case 0x60c:
- verboselog( *this, 2, "mc68328_r (%04x): TCTL2 = %04x\n", mem_mask, m_regs.tctl[1]);
- return m_regs.tctl[1];
+void mc68328_base_device::lposr_w(u8 data) // 0xa2d
+{
+ LOGMASKED(LOG_LCD, "%s: lposr_w: LPOSR = %02x\n", machine().describe_context(), data);
+ m_lposr = data;
+ LOGMASKED(LOG_LCD, "%s: Byte Offset: %d\n", machine().describe_context(), (m_lposr >> 3) & 0x01);
+ LOGMASKED(LOG_LCD, "%s: Pixel Offset: %d\n", machine().describe_context(), m_lposr & 0x07);
+}
- case 0x60e:
- verboselog( *this, 2, "mc68328_r (%04x): TPREP2 = %04x\n", mem_mask, m_regs.tprer[1]);
- return m_regs.tprer[1];
+u8 mc68328_base_device::lposr_r() // 0xa2d
+{
+ LOGMASKED(LOG_LCD, "%s: lposr_r: LPOSR: %02x\n", machine().describe_context(), m_lposr);
+ return m_lposr;
+}
- case 0x610:
- verboselog( *this, 2, "mc68328_r (%04x): TCMP2 = %04x\n", mem_mask, m_regs.tcmp[1]);
- return m_regs.tcmp[1];
+void mc68328_base_device::lfrcm_w(u8 data) // 0xa31
+{
+ LOGMASKED(LOG_LCD, "%s: lfrcm_w: LFRCM = %02x\n", machine().describe_context(), data);
+ m_lfrcm = data;
+ LOGMASKED(LOG_LCD, "%s: X Modulation: %d\n", machine().describe_context(), (m_lfrcm >> 4) & 0x0f);
+ LOGMASKED(LOG_LCD, "%s: Y Modulation: %d\n", machine().describe_context(), m_lfrcm & 0x0f);
+}
- case 0x612:
- verboselog( *this, 2, "mc68328_r (%04x): TCR2 = %04x\n", mem_mask, m_regs.tcr[1]);
- return m_regs.tcr[1];
+u8 mc68328_base_device::lfrcm_r() // 0xa31
+{
+ LOGMASKED(LOG_LCD, "%s: lfrcm_r: LFRCM: %02x\n", machine().describe_context(), m_lfrcm);
+ return m_lfrcm;
+}
- case 0x614:
- verboselog( *this, 2, "mc68328_r (%04x): TCN2 = %04x\n", mem_mask, m_regs.tcn[1]);
- return m_regs.tcn[1];
+void mc68328_device::lgpmr_w(u8 data) // 0xa32
+{
+ LOGMASKED(LOG_LCD, "%s: lgpmr_w: LGPMR = %04x\n", machine().describe_context(), data);
+ m_lgpmr = data;
+ LOGMASKED(LOG_LCD, "%s: Palette 0: %d\n", machine().describe_context(), (m_lgpmr >> 8) & 0x07);
+ LOGMASKED(LOG_LCD, "%s: Palette 1: %d\n", machine().describe_context(), (m_lgpmr >> 12) & 0x07);
+ LOGMASKED(LOG_LCD, "%s: Palette 2: %d\n", machine().describe_context(), (m_lgpmr >> 0) & 0x07);
+ LOGMASKED(LOG_LCD, "%s: Palette 3: %d\n", machine().describe_context(), (m_lgpmr >> 4) & 0x07);
+}
- case 0x616:
- verboselog( *this, 2, "mc68328_r (%04x): TSTAT2 = %04x\n", mem_mask, m_regs.tstat[1]);
- m_regs.tclear[1] |= m_regs.tstat[1];
- return m_regs.tstat[1];
+u16 mc68328_device::lgpmr_r() // 0xa32
+{
+ LOGMASKED(LOG_LCD, "%s: lgpmr_r: LGPMR: %04x\n", machine().describe_context(), m_lgpmr);
+ return m_lgpmr;
+}
- case 0x618:
- verboselog( *this, 2, "mc68328_r (%04x): WCTLR = %04x\n", mem_mask, m_regs.wctlr);
- return m_regs.wctlr;
- case 0x61a:
- verboselog( *this, 2, "mc68328_r (%04x): WCMPR = %04x\n", mem_mask, m_regs.wcmpr);
- return m_regs.wcmpr;
+//-------------------------------------------------
+// LCD hardware - EZ variant
+//-------------------------------------------------
- case 0x61c:
- verboselog( *this, 2, "mc68328_r (%04x): WCN = %04x\n", mem_mask, m_regs.wcn);
- return m_regs.wcn;
+void mc68ez328_device::lcd_update_info()
+{
+ if (!m_lcd_update_pending)
+ {
+ return;
+ }
- case 0x700:
- verboselog( *this, 2, "mc68328_r (%04x): SPISR = %04x\n", mem_mask, m_regs.spisr);
- return m_regs.spisr;
+ const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT];
+ attotime lcd_dma_duration = attotime::from_ticks(lcd_get_line_word_count() * sysclk_divisor, clock());
+ attotime lcd_scan_duration = lcd_get_line_rate();
+ attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1) * 2;
- case 0x800:
- verboselog( *this, 2, "mc68328_r (%04x): SPIMDATA = %04x\n", mem_mask, m_regs.spimdata);
- if (!m_in_spim_cb.isnull())
- {
- return m_in_spim_cb(0, 0xffff);
- }
- return m_regs.spimdata;
+ constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff };
+ m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), lcd_get_width(), m_lymax + 1, BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT], BIT_WIDTHS[m_lpicf & LPICF_GS]);
- case 0x802:
- verboselog( *this, 2, "mc68328_r (%04x): SPIMCONT = %04x\n", mem_mask, m_regs.spimcont);
- if (m_regs.spimcont & SPIM_XCH)
- {
- m_regs.spimcont &= ~SPIM_XCH;
- m_regs.spimcont |= SPIM_SPIMIRQ;
- return ((m_regs.spimcont | SPIM_XCH) &~ SPIM_SPIMIRQ);
- }
- return m_regs.spimcont;
+ m_lcd_update_pending = false;
+}
- case 0x900:
- verboselog( *this, 2, "mc68328_r (%04x): USTCNT = %04x\n", mem_mask, m_regs.ustcnt);
- return m_regs.ustcnt;
+u16 mc68ez328_device::lcd_get_lxmax_mask()
+{
+ constexpr u16 LXMAX_MASK = 0x03f0;
+ return LXMAX_MASK;
+}
- case 0x902:
- verboselog( *this, 2, "mc68328_r (%04x): UBAUD = %04x\n", mem_mask, m_regs.ubaud);
- return m_regs.ubaud;
+int mc68ez328_device::lcd_get_width()
+{
+ return m_lxmax & lcd_get_lxmax_mask();
+}
- case 0x904:
- verboselog( *this, 5, "mc68328_r (%04x): URX = %04x\n", mem_mask, m_regs.urx);
- return m_regs.urx;
+u32 mc68ez328_device::lcd_get_line_word_count()
+{
+ const u32 pixels_per_word = 16 / (1 << (m_lpicf & LPICF_GS));
+ const u32 data = (m_lxmax & lcd_get_lxmax_mask()) / pixels_per_word;
+ return data;
+}
- case 0x906:
- verboselog( *this, 5, "mc68328_r (%04x): UTX = %04x\n", mem_mask, m_regs.utx);
- return m_regs.utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL;
+attotime mc68ez328_device::lcd_get_line_rate()
+{
+ const u32 pixclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_PIXCLK_SEL) >> PLLCR_PIXCLK_SHIFT];
+ const u32 pxcd = (m_lpxcd & LPXCD_MASK) + 1;
+ const u32 lrra_factor = 6 + m_lrra + (m_lxmax & lcd_get_lxmax_mask()) * 4;
+ const u32 ticks = lrra_factor * pxcd * pixclk_divisor;
+ return attotime::from_ticks(ticks, clock());
+}
- case 0x908:
- verboselog( *this, 2, "mc68328_r (%04x): UMISC = %04x\n", mem_mask, m_regs.umisc);
- return m_regs.umisc;
+u8 mc68ez328_device::lcd_get_panel_bit_size()
+{
+ constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 1 };
+ return BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT];
+}
- case 0xa00:
- verboselog( *this, 2, "mc68328_r (%04x): LSSA(16) = %04x\n", mem_mask, m_regs.lssa >> 16);
- return m_regs.lssa >> 16;
+attotime mc68ez328_device::get_pixclk_rate()
+{
+ u32 divisor = VCO_DIVISORS[(m_pllcr & PLLCR_PIXCLK_SEL) >> PLLCR_PIXCLK_SHIFT];
+ return attotime::from_ticks((m_lpxcd & LPXCD_MASK) + 1, clock() / divisor);
+}
- case 0xa02:
- verboselog( *this, 2, "mc68328_r (%04x): LSSA(0) = %04x\n", mem_mask, m_regs.lssa & 0x0000ffff);
- return m_regs.lssa & 0x0000ffff;
+void mc68ez328_device::lpicf_w(u8 data) // 0xa20
+{
+ static const char *const PBSIZ_NAMES[4] = { "1-bit", "2-bit", "4-bit", "Invalid" };
+ static const char *const GS_NAMES[4] = { "Monochrome", "4-level Grayscale", "16-level Grayscale", "Invalid" };
+ LOGMASKED(LOG_LCD, "%s: lpicf_w: LPICF = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_LCD, "%s: Grayscale Mode: %d\n", machine().describe_context(), GS_NAMES[data & LPICF_GS]);
+ LOGMASKED(LOG_LCD, "%s: Bus Size: %s\n", machine().describe_context(), PBSIZ_NAMES[(data & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT]);
+ m_lcd_update_pending = m_lcd_update_pending || (m_lpicf != data);
+ m_lpicf = data;
+}
- case 0xa04:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LVPW = %02x\n", mem_mask, m_regs.lvpw);
- return m_regs.lvpw;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa04)\n", mem_mask);
- }
- break;
+void mc68ez328_device::lckcon_w(u8 data) // 0xa27
+{
+ LOGMASKED(LOG_LCD, "%s: lckcon_w: LCKCON = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_LCD, "%s: LCDC Enable: %d\n", machine().describe_context(), BIT(data, LCKCON_LCDON_BIT));
+ LOGMASKED(LOG_LCD, "%s: Display Wait States: %d\n", machine().describe_context(), ((data & LCKCON_DWS) >> LCKCON_DWS_SHIFT) + 1);
+ LOGMASKED(LOG_LCD, "%s: Bus Width: %d\n", machine().describe_context(), BIT(data, LCKCON_DWIDTH_BIT) ? 8 : 16);
- case 0xa08:
- verboselog( *this, 2, "mc68328_r (%04x): LXMAX = %04x\n", mem_mask, m_regs.lxmax);
- return m_regs.lxmax;
+ const u16 old = m_lckcon;
+ m_lckcon = data;
- case 0xa0a:
- verboselog( *this, 2, "mc68328_r (%04x): LYMAX = %04x\n", mem_mask, m_regs.lymax);
- return m_regs.lymax;
+ lcd_update_info();
+ if (BIT(old, LCKCON_LCDON_BIT) && !BIT(m_lckcon, LCKCON_LCDON_BIT))
+ {
+ m_lcd_scan->adjust(attotime::never);
+ }
+ else if (!BIT(old, LCKCON_LCDON_BIT) && BIT(m_lckcon, LCKCON_LCDON_BIT))
+ {
+ m_lcd_scan->adjust(attotime::never);
+ m_lcd_sysmem_ptr = m_lssa;
+ fill_lcd_dma_buffer();
+ }
+}
- case 0xa18:
- verboselog( *this, 2, "mc68328_r (%04x): LCXP = %04x\n", mem_mask, m_regs.lcxp);
- return m_regs.lcxp;
+void mc68ez328_device::lrra_w(u8 data) // 0xa29
+{
+ LOGMASKED(LOG_LCD, "%s: lrra_w: LRRA = %02x\n", machine().describe_context(), data);
+ m_lcd_update_pending = m_lcd_update_pending || (m_lrra != data);
+ m_lrra = data;
+}
- case 0xa1a:
- verboselog( *this, 2, "mc68328_r (%04x): LCYP = %04x\n", mem_mask, m_regs.lcyp);
- return m_regs.lcyp;
+u8 mc68ez328_device::lrra_r() // 0xa29
+{
+ LOGMASKED(LOG_LCD, "%s: lrra_r: LRRA: %02x\n", machine().describe_context(), m_lrra);
+ return m_lrra;
+}
- case 0xa1c:
- verboselog( *this, 2, "mc68328_r (%04x): LCWCH = %04x\n", mem_mask, m_regs.lcwch);
- return m_regs.lcwch;
+void mc68ez328_device::pwmr_w(offs_t offset, u16 data, u16 mem_mask) // 0xa36
+{
+ LOGMASKED(LOG_LCD, "%s: pwmr_w: PWMR = %04x\n", machine().describe_context(), data);
+ m_pwmr = data;
+}
- case 0xa1e:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LBLKC = %02x\n", mem_mask, m_regs.lblkc);
- return m_regs.lblkc;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa1e)\n", mem_mask);
- }
- break;
+u16 mc68ez328_device::pwmr_r() // 0xa36
+{
+ LOGMASKED(LOG_LCD, "%s: pwmr_r: PWMR: %04x\n", machine().describe_context(), m_lrra);
+ return m_pwmr;
+}
- case 0xa20:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LPOLCF = %02x\n", mem_mask, m_regs.lpolcf);
- return m_regs.lpolcf;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): LPICF = %02x\n", mem_mask, m_regs.lpicf);
- return m_regs.lpicf << 8;
- }
- case 0xa22:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LACDRC = %02x\n", mem_mask, m_regs.lacdrc);
- return m_regs.lacdrc;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa22)\n", mem_mask);
- }
- break;
+//-------------------------------------------------
+// RTC/alarm hardware - Standard MC68328
+//-------------------------------------------------
- case 0xa24:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LPXCD = %02x\n", mem_mask, m_regs.lpxcd);
- return m_regs.lpxcd;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa24)\n", mem_mask);
- }
- break;
+TIMER_CALLBACK_MEMBER(mc68328_base_device::rtc_tick)
+{
+ if (BIT(m_rtcctl, RTCCTL_ENABLE_BIT))
+ {
+ const bool rtc_int_was_active = rtc_int_is_active();
- case 0xa26:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LCKCON = %02x\n", mem_mask, m_regs.lckcon);
- return m_regs.lckcon;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa26)\n", mem_mask);
- }
- break;
+ rtc_advance_seconds();
- case 0xa28:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LLBAR = %02x\n", mem_mask, m_regs.llbar);
- return m_regs.llbar;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa28)\n", mem_mask);
- }
- break;
+ if (rtc_get_alarm_match())
+ {
+ m_rtcisr |= RTCINT_ALARM;
+ }
- case 0xa2a:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LOTCR = %02x\n", mem_mask, m_regs.lotcr);
- return m_regs.lotcr;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa2a)\n", mem_mask);
- }
- break;
+ if (!rtc_int_was_active && rtc_int_is_active())
+ {
+ set_interrupt_line(INT_RTC, 1);
+ }
+ }
+}
- case 0xa2c:
- if (mem_mask & 0x00ff)
- {
- verboselog( *this, 2, "mc68328_r (%04x): LPOSR = %02x\n", mem_mask, m_regs.lposr);
- return m_regs.lposr;
- }
- else
- {
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa2c)\n", mem_mask);
- }
- break;
+void mc68328_base_device::rtc_advance_seconds()
+{
+ m_hmsr++;
- case 0xa30:
- if (mem_mask & 0x00ff)
+ if (m_rtcienr & RTCINT_SECOND)
+ {
+ m_rtcisr |= RTCINT_SECOND;
+ }
+
+ if ((m_hmsr & RTCHMSR_SECONDS) == 0x0000003c)
+ {
+ m_hmsr &= ~RTCHMSR_SECONDS;
+ m_hmsr += 1 << RTCHMSR_MINUTES_SHIFT;
+
+ if (m_rtcienr & RTCINT_MINUTE)
+ {
+ m_rtcisr |= RTCINT_MINUTE;
+ }
+
+ if ((m_hmsr & RTCHMSR_MINUTES) == 0x003c0000)
+ {
+ m_hmsr &= ~RTCHMSR_MINUTES;
+ m_hmsr += 1 << RTCHMSR_HOURS_SHIFT;
+
+ if ((m_hmsr & RTCHMSR_HOURS) == 0x18000000)
{
- verboselog( *this, 2, "mc68328_r (%04x): LFRCM = %02x\n", mem_mask, m_regs.lfrcm);
- return m_regs.lfrcm;
+ m_hmsr &= ~RTCHMSR_HOURS;
+
+ if (m_rtcienr & RTCINT_DAY)
+ {
+ m_rtcisr |= RTCINT_DAY;
+ }
}
- else
+ }
+
+ if (m_stpwtch != RTCSTPWTCH_MASK)
+ {
+ m_stpwtch--;
+ m_stpwtch &= RTCSTPWTCH_MASK;
+
+ if (m_stpwtch == RTCSTPWTCH_MASK)
{
- verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa30)\n", mem_mask);
+ m_rtcisr |= RTCINT_STOPWATCH;
}
- break;
+ }
+ }
+}
+
+bool mc68328_device::rtc_int_is_active()
+{
+ return m_rtcisr & m_rtcienr;
+}
- case 0xa32:
- verboselog( *this, 2, "mc68328_r (%04x): LGPMR = %04x\n", mem_mask, m_regs.lgpmr);
- return m_regs.lgpmr;
+u16 mc68328_device::rtc_get_int_mask()
+{
+ constexpr u16 RTCIENR_MASK = 0x001f;
+ return RTCIENR_MASK;
+}
- case 0xb00:
- verboselog( *this, 2, "mc68328_r (%04x): HMSR(0) = %04x\n", mem_mask, m_regs.hmsr & 0x0000ffff);
- return m_regs.hmsr & 0x0000ffff;
+bool mc68328_device::rtc_get_alarm_match()
+{
+ return m_hmsr == m_alarm;
+}
- case 0xb02:
- verboselog( *this, 2, "mc68328_r (%04x): HMSR(16) = %04x\n", mem_mask, m_regs.hmsr >> 16);
- return m_regs.hmsr >> 16;
+void mc68328_base_device::hmsr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb00
+{
+ LOGMASKED(LOG_RTC, "%s: hmsr_msw_w: HMSR(MSW) = %04x\n", machine().describe_context(), data);
+ m_hmsr &= ~(mem_mask << 16);
+ m_hmsr |= (data & mem_mask) << 16;
+ m_hmsr &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS);
+}
- case 0xb04:
- verboselog( *this, 2, "mc68328_r (%04x): ALARM(0) = %04x\n", mem_mask, m_regs.alarm & 0x0000ffff);
- return m_regs.alarm & 0x0000ffff;
+u16 mc68328_base_device::hmsr_msw_r() // 0xb00
+{
+ LOGMASKED(LOG_RTC, "%s: hmsr_msw_r: HMSR(MSW): %04x\n", machine().describe_context(), (u16)(m_hmsr >> 16));
+ return (u16)(m_hmsr >> 16);
+}
+
+void mc68328_base_device::hmsr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb02
+{
+ LOGMASKED(LOG_RTC, "%s: hmsr_lsw_w: HMSR(LSW) = %04x\n", machine().describe_context(), data);
+ m_hmsr &= 0xffff0000 | (~mem_mask);
+ m_hmsr |= data & mem_mask;
+ m_hmsr &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS);
+}
+
+u16 mc68328_base_device::hmsr_lsw_r() // 0xb02
+{
+ LOGMASKED(LOG_RTC, "%s: hmsr_lsw_r: HMSR(LSW): %04x\n", machine().describe_context(), (u16)m_hmsr);
+ return (u16)m_hmsr;
+}
- case 0xb06:
- verboselog( *this, 2, "mc68328_r (%04x): ALARM(16) = %04x\n", mem_mask, m_regs.alarm >> 16);
- return m_regs.alarm >> 16;
+void mc68328_base_device::alarm_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb04
+{
+ LOGMASKED(LOG_RTC, "%s: alarm_msw_w: ALARM(MSW) = %04x\n", machine().describe_context(), data);
+ m_alarm &= ~(mem_mask << 16);
+ m_alarm |= (data & mem_mask) << 16;
+ m_alarm &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS);
+}
- case 0xb0c:
- verboselog( *this, 2, "mc68328_r (%04x): RTCCTL = %04x\n", mem_mask, m_regs.rtcctl);
- return m_regs.rtcctl;
+u16 mc68328_base_device::alarm_msw_r() // 0xb04
+{
+ LOGMASKED(LOG_RTC, "%s: alarm_msw_r: ALARM(MSW): %04x\n", machine().describe_context(), (u16)(m_alarm >> 16));
+ return (u16)(m_alarm >> 16);
+}
- case 0xb0e:
- verboselog( *this, 2, "mc68328_r (%04x): RTCISR = %04x\n", mem_mask, m_regs.rtcisr);
- return m_regs.rtcisr;
+void mc68328_base_device::alarm_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb06
+{
+ LOGMASKED(LOG_RTC, "%s: alarm_lsw_w: ALARM(LSW) = %04x\n", machine().describe_context(), data);
+ m_alarm &= 0xffff0000 | (~mem_mask);
+ m_alarm |= data & mem_mask;
+ m_alarm &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS);
+}
- case 0xb10:
- verboselog( *this, 2, "mc68328_r (%04x): RTCIENR = %04x\n", mem_mask, m_regs.rtcienr);
- return m_regs.rtcienr;
+u16 mc68328_base_device::alarm_lsw_r() // 0xb06
+{
+ LOGMASKED(LOG_RTC, "%s: alarm_lsw_r: ALARM(LSW): %04x\n", machine().describe_context(), (u16)m_alarm);
+ return (u16)m_alarm;
+}
- case 0xb12:
- verboselog( *this, 2, "mc68328_r (%04x): STPWTCH = %04x\n", mem_mask, m_regs.stpwtch);
- return m_regs.stpwtch;
+void mc68328_base_device::rtcctl_w(offs_t offset, u16 data, u16 mem_mask) // 0xb0c
+{
+ LOGMASKED(LOG_RTC, "%s: rtcctl_w: RTCCTL = %04x\n", machine().describe_context(), data);
+ m_rtcctl = data & RTCCTL_MASK;
+}
- default:
- verboselog( *this, 0, "mc68328_r (%04x): Unknown address (0x%06x)\n", mem_mask, 0xfff000 + address);
- break;
+u16 mc68328_base_device::rtcctl_r() // 0xb0c
+{
+ LOGMASKED(LOG_RTC, "%s: rtcctl_r: RTCCTL: %04x\n", machine().describe_context(), m_rtcctl);
+ return m_rtcctl;
+}
+
+void mc68328_base_device::rtcisr_w(offs_t offset, u16 data, u16 mem_mask) // 0xb0e
+{
+ const bool rtc_int_was_active = rtc_int_is_active();
+ LOGMASKED(LOG_RTC, "%s: rtcisr_w: RTCISR = %04x\n", machine().describe_context(), data);
+ m_rtcisr &= ~data;
+
+ if (rtc_int_was_active && !rtc_int_is_active())
+ {
+ set_interrupt_line(INT_RTC, 0);
}
- return 0;
}
-/* THIS IS PRETTY MUCH TOTALLY WRONG AND DOESN'T REFLECT THE MC68328'S INTERNAL FUNCTIONALITY AT ALL! */
-uint32_t mc68328_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+u16 mc68328_base_device::rtcisr_r() // 0xb0e
+{
+ LOGMASKED(LOG_RTC, "%s: rtcisr_r: RTCISR: %04x\n", machine().describe_context(), m_rtcisr);
+ return m_rtcisr;
+}
+
+void mc68328_base_device::rtcienr_w(offs_t offset, u16 data, u16 mem_mask) // 0xb10
{
- uint32_t vram_addr = m_regs.lssa & 0x00fffffe;
+ const bool rtc_int_was_active = rtc_int_is_active();
- if (m_regs.lckcon & LCKCON_LCDC_EN)
+ LOGMASKED(LOG_RTC, "%s: rtcienr_w: RTCIENR = %04x\n", machine().describe_context(), data);
+ m_rtcienr = data & rtc_get_int_mask();
+
+ const bool is_active = rtc_int_is_active();
+ if (rtc_int_was_active != is_active)
{
- for (int y = 0; y < 160; y++)
+ set_interrupt_line(INT_RTC, (int)is_active);
+ }
+}
+
+u16 mc68328_base_device::rtcienr_r() // 0xb10
+{
+ LOGMASKED(LOG_RTC, "%s: rtcienr_r: RTCIENR: %04x\n", machine().describe_context(), m_rtcienr);
+ return m_rtcienr;
+}
+
+void mc68328_base_device::stpwtch_w(offs_t offset, u16 data, u16 mem_mask) // 0xb12
+{
+ LOGMASKED(LOG_RTC, "%s: stpwtch_w: STPWTCH = %04x\n", machine().describe_context(), data);
+ m_stpwtch = data & 0x003f;
+}
+
+u16 mc68328_base_device::stpwtch_r() // 0xb12
+{
+ LOGMASKED(LOG_RTC, "%s: stpwtch_r: STPWTCH: %04x\n", machine().describe_context(), m_stpwtch);
+ return m_stpwtch;
+}
+
+
+//-------------------------------------------------
+// RTC/alarm hardware - EZ variant
+//-------------------------------------------------
+
+bool mc68ez328_device::rtc_int_is_active()
+{
+ return (m_rtcisr & m_rtcienr) & RTCINT_RTCIRQ_MASK;
+}
+
+void mc68ez328_device::rtc_advance_seconds()
+{
+ LOGMASKED(LOG_RTC, "EZ advancing seconds!\n");
+ const u32 old_hmsr = m_hmsr;
+ mc68328_base_device::rtc_advance_seconds();
+
+ if ((old_hmsr & RTCHMSR_HOURS) != (m_hmsr & RTCHMSR_HOURS))
+ {
+ m_rtcisr |= RTCINT_HOUR;
+
+ if (((m_hmsr & RTCHMSR_HOURS) >> RTCHMSR_HOURS_SHIFT) == 0)
{
- uint16_t *const line = &bitmap.pix(y);
+ m_dayr = (m_dayr + 1) & RTC_DAYS_MASK;
+ }
+ }
- for (int x = 0; x < 160; x += 16, vram_addr += 2)
+ if (BIT(m_watchdog, WATCHDOG_EN_BIT))
+ {
+ m_watchdog += 1 << WATCHDOG_CNT_SHIFT;
+ m_watchdog &= (WATCHDOG_MASK | WATCHDOG_CNT_MASK);
+ if (((m_watchdog & WATCHDOG_CNT_MASK) >> WATCHDOG_CNT_SHIFT) == 2)
+ {
+ if (BIT(m_watchdog, WATCHDOG_ISEL_BIT))
{
- uint16_t const word = space(AS_PROGRAM).read_word(vram_addr);
- for (int b = 0; b < 16; b++)
- {
- line[x + b] = (word >> (15 - b)) & 0x0001;
- }
+ set_interrupt_line(INT_WDT, 1);
+ }
+ else
+ {
+ reset();
}
}
}
- else
+}
+
+TIMER_CALLBACK_MEMBER(mc68ez328_device::sample_timer_tick)
+{
+ if (!BIT(m_rtcctl, RTCCTL_ENABLE_BIT) && !BIT(m_watchdog, WATCHDOG_EN_BIT))
+ {
+ return;
+ }
+
+ const u8 old_sam_cnt = m_sam_cnt;
+ m_sam_cnt++;
+
+ const bool rtc_int_was_active = rtc_int_is_active();
+
+ m_rtcisr |= RTCINT_SAM0;
+ for (u8 i = 0; i < 7; i++)
{
- for (int y = 0; y < 160; y++)
+ if (BIT(old_sam_cnt, i) && !BIT(m_sam_cnt, i))
{
- uint16_t *const line = &bitmap.pix(y);
+ m_rtcisr |= RTCINT_SAM1 << i;
+ }
+ }
- for (int x = 0; x < 160; x++)
- {
- line[x] = 0;
- }
+ if (!rtc_int_was_active && rtc_int_is_active())
+ {
+ set_interrupt_line(INT_RTC, 1);
+ }
+}
+
+u16 mc68ez328_device::rtc_get_int_mask()
+{
+ constexpr u16 RTCIENR_MASK = 0xff3f;
+ return RTCIENR_MASK;
+}
+
+bool mc68ez328_device::rtc_get_alarm_match()
+{
+ return m_hmsr == m_alarm && m_dayr == m_dayalarm;
+}
+
+void mc68ez328_device::watchdog_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: watchdog_w: WATCHDOG = %04x\n", machine().describe_context(), data);
+ const u16 old_watchdog = m_watchdog;
+ m_watchdog = data & WATCHDOG_MASK;
+ if (BIT(data, WATCHDOG_INTF_BIT))
+ {
+ m_watchdog &= ~WATCHDOG_INTF;
+ if (BIT(old_watchdog, WATCHDOG_INTF_BIT))
+ {
+ set_interrupt_line(INT_WDT, 0);
}
}
- return 0;
}
+u16 mc68ez328_device::watchdog_r()
+{
+ LOGMASKED(LOG_RTC, "%s: watchdog_r: WATCHDOG: %04x\n", machine().describe_context(), m_watchdog);
+ return m_watchdog;
+}
-void mc68328_device::register_state_save()
+void mc68ez328_device::rtcctl_w(offs_t offset, u16 data, u16 mem_mask) // 0xb0c
+{
+ const u16 old_rtcctl = m_rtcctl;
+ mc68328_base_device::rtcctl_w(offset, data, mem_mask);
+
+ if (BIT(old_rtcctl, RTCCTL_38_4_BIT) != BIT(m_rtcctl, RTCCTL_38_4_BIT))
+ {
+ const u32 frequency = BIT(m_rtcctl, RTCCTL_38_4_BIT) ? 38400 : 32768;
+ m_rtc_sample_timer->adjust(attotime::from_ticks(64, frequency), 0, attotime::from_ticks(64, frequency));
+ }
+}
+
+void mc68ez328_device::dayr_w(offs_t offset, u16 data, u16 mem_mask) // 0xb1a
+{
+ LOGMASKED(LOG_RTC, "%s: dayr_w: DAYR = %04x\n", machine().describe_context(), data);
+ m_dayr = data & RTC_DAYS_MASK;
+}
+
+void mc68ez328_device::dayalarm_w(offs_t offset, u16 data, u16 mem_mask) // 0xb1c
+{
+ LOGMASKED(LOG_RTC, "%s: dayalarm_w: DAYALARM = %04x\n", machine().describe_context(), data);
+ m_dayalarm = data & RTC_DAYS_MASK;
+}
+
+u16 mc68ez328_device::dayr_r() // 0xb1a
+{
+ LOGMASKED(LOG_RTC, "%s: dayalarm_r: DAYR: %04x\n", machine().describe_context(), m_dayr);
+ return m_dayr;
+}
+
+u16 mc68ez328_device::dayalarm_r() // 0xb1c
{
- save_item(NAME(m_regs.scr));
- save_item(NAME(m_regs.grpbasea));
- save_item(NAME(m_regs.grpbaseb));
- save_item(NAME(m_regs.grpbasec));
- save_item(NAME(m_regs.grpbased));
- save_item(NAME(m_regs.grpmaska));
- save_item(NAME(m_regs.grpmaskb));
- save_item(NAME(m_regs.grpmaskc));
- save_item(NAME(m_regs.grpmaskd));
- save_item(NAME(m_regs.csa0));
- save_item(NAME(m_regs.csa1));
- save_item(NAME(m_regs.csa2));
- save_item(NAME(m_regs.csa3));
- save_item(NAME(m_regs.csb0));
- save_item(NAME(m_regs.csb1));
- save_item(NAME(m_regs.csb2));
- save_item(NAME(m_regs.csb3));
- save_item(NAME(m_regs.csc0));
- save_item(NAME(m_regs.csc1));
- save_item(NAME(m_regs.csc2));
- save_item(NAME(m_regs.csc3));
- save_item(NAME(m_regs.csd0));
- save_item(NAME(m_regs.csd1));
- save_item(NAME(m_regs.csd2));
- save_item(NAME(m_regs.csd3));
-
- save_item(NAME(m_regs.pllcr));
- save_item(NAME(m_regs.pllfsr));
- save_item(NAME(m_regs.pctlr));
-
- save_item(NAME(m_regs.ivr));
- save_item(NAME(m_regs.icr));
- save_item(NAME(m_regs.imr));
- save_item(NAME(m_regs.iwr));
- save_item(NAME(m_regs.isr));
- save_item(NAME(m_regs.ipr));
-
- save_item(NAME(m_regs.padir));
- save_item(NAME(m_regs.padata));
- save_item(NAME(m_regs.pasel));
- save_item(NAME(m_regs.pbdir));
- save_item(NAME(m_regs.pbdata));
- save_item(NAME(m_regs.pbsel));
- save_item(NAME(m_regs.pcdir));
- save_item(NAME(m_regs.pcdata));
- save_item(NAME(m_regs.pcsel));
- save_item(NAME(m_regs.pddir));
- save_item(NAME(m_regs.pddata));
- save_item(NAME(m_regs.pdpuen));
- save_item(NAME(m_regs.pdpol));
- save_item(NAME(m_regs.pdirqen));
- save_item(NAME(m_regs.pddataedge));
- save_item(NAME(m_regs.pdirqedge));
- save_item(NAME(m_regs.pedir));
- save_item(NAME(m_regs.pedata));
- save_item(NAME(m_regs.pepuen));
- save_item(NAME(m_regs.pesel));
- save_item(NAME(m_regs.pfdir));
- save_item(NAME(m_regs.pfdata));
- save_item(NAME(m_regs.pfpuen));
- save_item(NAME(m_regs.pfsel));
- save_item(NAME(m_regs.pgdir));
- save_item(NAME(m_regs.pgdata));
- save_item(NAME(m_regs.pgpuen));
- save_item(NAME(m_regs.pgsel));
- save_item(NAME(m_regs.pjdir));
- save_item(NAME(m_regs.pjdata));
- save_item(NAME(m_regs.pjsel));
- save_item(NAME(m_regs.pkdir));
- save_item(NAME(m_regs.pkdata));
- save_item(NAME(m_regs.pkpuen));
- save_item(NAME(m_regs.pksel));
- save_item(NAME(m_regs.pmdir));
- save_item(NAME(m_regs.pmdata));
- save_item(NAME(m_regs.pmpuen));
- save_item(NAME(m_regs.pmsel));
-
- save_item(NAME(m_regs.pwmc));
- save_item(NAME(m_regs.pwmp));
- save_item(NAME(m_regs.pwmw));
- save_item(NAME(m_regs.pwmcnt));
-
- save_item(NAME(m_regs.tctl[0]));
- save_item(NAME(m_regs.tctl[1]));
- save_item(NAME(m_regs.tprer[0]));
- save_item(NAME(m_regs.tprer[1]));
- save_item(NAME(m_regs.tcmp[0]));
- save_item(NAME(m_regs.tcmp[1]));
- save_item(NAME(m_regs.tcr[0]));
- save_item(NAME(m_regs.tcr[1]));
- save_item(NAME(m_regs.tcn[0]));
- save_item(NAME(m_regs.tcn[1]));
- save_item(NAME(m_regs.tstat[0]));
- save_item(NAME(m_regs.tstat[1]));
- save_item(NAME(m_regs.wctlr));
- save_item(NAME(m_regs.wcmpr));
- save_item(NAME(m_regs.wcn));
-
- save_item(NAME(m_regs.spisr));
-
- save_item(NAME(m_regs.spimdata));
- save_item(NAME(m_regs.spimcont));
-
- save_item(NAME(m_regs.ustcnt));
- save_item(NAME(m_regs.ubaud));
- save_item(NAME(m_regs.urx));
- save_item(NAME(m_regs.utx));
- save_item(NAME(m_regs.umisc));
-
- save_item(NAME(m_regs.lssa));
- save_item(NAME(m_regs.lvpw));
- save_item(NAME(m_regs.lxmax));
- save_item(NAME(m_regs.lymax));
- save_item(NAME(m_regs.lcxp));
- save_item(NAME(m_regs.lcyp));
- save_item(NAME(m_regs.lcwch));
- save_item(NAME(m_regs.lblkc));
- save_item(NAME(m_regs.lpicf));
- save_item(NAME(m_regs.lpolcf));
- save_item(NAME(m_regs.lacdrc));
- save_item(NAME(m_regs.lpxcd));
- save_item(NAME(m_regs.lckcon));
- save_item(NAME(m_regs.llbar));
- save_item(NAME(m_regs.lotcr));
- save_item(NAME(m_regs.lposr));
- save_item(NAME(m_regs.lfrcm));
- save_item(NAME(m_regs.lgpmr));
-
- save_item(NAME(m_regs.hmsr));
- save_item(NAME(m_regs.alarm));
- save_item(NAME(m_regs.rtcctl));
- save_item(NAME(m_regs.rtcisr));
- save_item(NAME(m_regs.rtcienr));
- save_item(NAME(m_regs.stpwtch));
+ LOGMASKED(LOG_RTC, "%s: dayalarm_r: DAYALARM: %04x\n", machine().describe_context(), m_dayalarm);
+ return m_dayalarm;
}
diff --git a/src/devices/machine/mc68328.h b/src/devices/machine/mc68328.h
index 8165fbe6e85..b7877e9affc 100644
--- a/src/devices/machine/mc68328.h
+++ b/src/devices/machine/mc68328.h
@@ -90,299 +90,1166 @@
#include "cpu/m68000/m68000.h"
-class mc68328_device : public m68000_device
+class mc68328_base_device : public m68000_device
{
public:
- mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto out_port_a() { return m_out_port_a_cb.bind(); }
- auto out_port_b() { return m_out_port_b_cb.bind(); }
- auto out_port_c() { return m_out_port_c_cb.bind(); }
- auto out_port_d() { return m_out_port_d_cb.bind(); }
- auto out_port_e() { return m_out_port_e_cb.bind(); }
- auto out_port_f() { return m_out_port_f_cb.bind(); }
- auto out_port_g() { return m_out_port_g_cb.bind(); }
- auto out_port_j() { return m_out_port_j_cb.bind(); }
- auto out_port_k() { return m_out_port_k_cb.bind(); }
- auto out_port_m() { return m_out_port_m_cb.bind(); }
- auto in_port_a() { return m_in_port_a_cb.bind(); }
- auto in_port_b() { return m_in_port_b_cb.bind(); }
- auto in_port_c() { return m_in_port_c_cb.bind(); }
- auto in_port_d() { return m_in_port_d_cb.bind(); }
- auto in_port_e() { return m_in_port_e_cb.bind(); }
- auto in_port_f() { return m_in_port_f_cb.bind(); }
- auto in_port_g() { return m_in_port_g_cb.bind(); }
- auto in_port_j() { return m_in_port_j_cb.bind(); }
- auto in_port_k() { return m_in_port_k_cb.bind(); }
- auto in_port_m() { return m_in_port_m_cb.bind(); }
- auto out_pwm() { return m_out_pwm_cb.bind(); }
+ typedef device_delegate<void (double, int, int, u8, u8)> lcd_info_changed_delegate;
+
+ template <int Line> auto out_port_a() { return m_out_port_a_cb[Line].bind(); }
+ template <int Line> auto out_port_b() { return m_out_port_b_cb[Line].bind(); }
+ template <int Line> auto out_port_c() { return m_out_port_c_cb[Line].bind(); }
+ template <int Line> auto out_port_d() { return m_out_port_d_cb[Line].bind(); }
+ template <int Line> auto out_port_e() { return m_out_port_e_cb[Line].bind(); }
+ template <int Line> auto out_port_f() { return m_out_port_f_cb[Line].bind(); }
+ template <int Line> auto out_port_g() { return m_out_port_g_cb[Line].bind(); }
+ template <int Line> auto in_port_a() { return m_in_port_a_cb[Line].bind(); }
+ template <int Line> auto in_port_b() { return m_in_port_b_cb[Line].bind(); }
+ template <int Line> auto in_port_c() { return m_in_port_c_cb[Line].bind(); }
+ template <int Line> auto in_port_d() { return m_in_port_d_cb[Line].bind(); }
+ template <int Line> auto in_port_e() { return m_in_port_e_cb[Line].bind(); }
+ template <int Line> auto in_port_f() { return m_in_port_f_cb[Line].bind(); }
+ template <int Line> auto in_port_g() { return m_in_port_g_cb[Line].bind(); }
+
+ void port_d_in_w(int state, int bit);
+
auto out_spim() { return m_out_spim_cb.bind(); }
auto in_spim() { return m_in_spim_cb.bind(); }
- auto spim_xch_trigger() { return m_spim_xch_trigger_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER(set_penirq_line);
- void set_port_d_lines(uint8_t state, int bit);
+ auto out_pwm() { return m_out_pwm_cb.bind(); }
+
+ auto out_flm() { return m_out_flm_cb.bind(); }
+ auto out_llp() { return m_out_llp_cb.bind(); }
+ auto out_lsclk() { return m_out_lsclk_cb.bind(); }
+ auto out_ld() { return m_out_ld_cb.bind(); }
- uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ template <typename... T>
+ void set_lcd_info_changed(T &&... args)
+ {
+ m_lcd_info_changed_cb.set(std::forward<T>(args)...);
+ }
+
+ void irq5_w(int state);
protected:
- // device-level overrides
+ mc68328_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ // device_t implementation
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
+ enum : u8
+ {
+ SCR_WDTH8 = 0x01,
+ SCR_DMAP = 0x04,
+ SCR_SO = 0x08,
+ SCR_BETEN = 0x10,
+ SCR_PRV = 0x20,
+ SCR_WPV = 0x40,
+ SCR_BETO = 0x80,
+
+ PCTLR_WIDTH = 0x1f,
+ PCTLR_STOP = 0x40,
+ PCTLR_PC_EN = 0x80,
+
+ BLKC_BD = 0x7f,
+ BLKC_BKEN = 0x80,
+
+ LPOLCF_PIXPOL = 0x01,
+ LPOLCF_LPPOL_BIT = 1,
+ LPOLCF_FLMPOL_BIT = 2,
+ LPOLCF_LCKPOL = 0x08,
+
+ LACDRC_MASK = 0x0f,
+
+ LPXCD_MASK = 0x3f,
+
+ LBAR_MASK = 0x7f,
+
+ LPOSR_POS = 0x07,
+ LPOSR_BOS = 0x08,
+
+ LFRCM_YMOD = 0x0f,
+ LFRCM_XMOD = 0xf0,
+ };
+
+ enum : u16
+ {
+ GRPBASE_VALID = 0x0001,
+ GRPBASE_BASE_ADDR = 0xfff0,
+
+ GRPMASK_BASE_MASK = 0xfff0,
+
+ PLLCR_DISPLL = 0x0008,
+ PLLCR_CLKEN = 0x0010,
+ PLLCR_SYSCLK_SEL_DIV2 = 0x0000,
+ PLLCR_SYSCLK_SEL_DIV4 = 0x0100,
+ PLLCR_SYSCLK_SEL_DIV8 = 0x0200,
+ PLLCR_SYSCLK_SEL_DIV16 = 0x0300,
+ PLLCR_SYSCLK_SEL_DIV1_0 = 0x0400,
+ PLLCR_SYSCLK_SEL_DIV1_1 = 0x0500,
+ PLLCR_SYSCLK_SEL_DIV1_2 = 0x0600,
+ PLLCR_SYSCLK_SEL_DIV1_3 = 0x0700,
+ PLLCR_SYSCLK_SEL = 0x0700,
+ PLLCR_SYSCLK_SHIFT = 8,
+ PLLCR_PIXCLK_SEL_DIV2 = 0x0000,
+ PLLCR_PIXCLK_SEL_DIV4 = 0x0800,
+ PLLCR_PIXCLK_SEL_DIV8 = 0x1000,
+ PLLCR_PIXCLK_SEL_DIV16 = 0x1800,
+ PLLCR_PIXCLK_SEL_DIV1_0 = 0x2000,
+ PLLCR_PIXCLK_SEL_DIV1_1 = 0x2800,
+ PLLCR_PIXCLK_SEL_DIV1_2 = 0x3000,
+ PLLCR_PIXCLK_SEL_DIV1_3 = 0x3800,
+ PLLCR_PIXCLK_SEL = 0x3800,
+ PLLCR_PIXCLK_SHIFT = 11,
+
+ PLLFSR_PCNT = 0x00ff,
+ PLLFSR_QCNT = 0x0f00,
+ PLLFSR_PROT = 0x4000,
+ PLLFSR_CLK32 = 0x8000,
+
+ ICR_ET6 = 0x0100,
+ ICR_ET3 = 0x0200,
+ ICR_ET2 = 0x0400,
+ ICR_ET1 = 0x0800,
+ ICR_POL6 = 0x1000,
+ ICR_POL3 = 0x2000,
+ ICR_POL2 = 0x4000,
+ ICR_POL1 = 0x8000,
+
+ PWMC_CLKSEL = 0x0007,
+ PWMC_EN = 0x0010,
+ PWMC_POL = 0x0040,
+ PWMC_PIN = 0x0080,
+ PWMC_LOAD = 0x0100,
+ PWMC_IRQ_EN = 0x4000,
+ PWMC_IRQ = 0x8000,
+
+ TCTL_TEN = 0x0001,
+ TCTL_TEN_ENABLE = 0x0001,
+ TCTL_TEN_BIT = 0,
+ TCTL_CLKSOURCE = 0x000e,
+ TCTL_CLKSOURCE_STOP = 0x0000,
+ TCTL_CLKSOURCE_SYSCLK = 0x0002,
+ TCTL_CLKSOURCE_SYSCLK16 = 0x0004,
+ TCTL_CLKSOURCE_TIN = 0x0006,
+ TCTL_CLKSOURCE_32KHZ4 = 0x0008,
+ TCTL_CLKSOURCE_32KHZ5 = 0x000a,
+ TCTL_CLKSOURCE_32KHZ6 = 0x000c,
+ TCTL_CLKSOURCE_32KHZ7 = 0x000e,
+ TCTL_IRQEN = 0x0010,
+ TCTL_IRQEN_ENABLE = 0x0010,
+ TCTL_OM = 0x0020,
+ TCTL_OM_ACTIVELOW = 0x0000,
+ TCTL_OM_TOGGLE = 0x0020,
+ TCTL_CAPTURE = 0x00c0,
+ TCTL_CAPTURE_NOINT = 0x0000,
+ TCTL_CAPTURE_RISING = 0x0040,
+ TCTL_CAPTURE_FALLING = 0x0080,
+ TCTL_CAPTURE_BOTH = 0x00c0,
+ TCTL_FRR = 0x0100,
+ TCTL_FRR_RESTART = 0x0000,
+ TCTL_FRR_FREERUN = 0x0100,
+
+ TSTAT_COMP = 0x0001,
+ TSTAT_CAPT = 0x0002,
+
+ SPIS_SPISEN = 0x0100,
+ SPIS_POL = 0x0200,
+ SPIS_PHA = 0x0400,
+ SPIS_OVRWR = 0x0800,
+ SPIS_DATA_RDY = 0x1000,
+ SPIS_ENPOL = 0x2000,
+ SPIS_IRQEN = 0x4000,
+ SPIS_SPIS_IRQ = 0x8000,
+
+ SPIM_BIT_COUNT = 0x000f,
+ SPIM_POL_BIT = 4,
+ SPIM_PHA_BIT = 5,
+ SPIM_IRQEN_BIT = 6,
+ SPIM_SPIMIRQ_BIT = 7,
+ SPIM_XCH_BIT = 8,
+ SPIM_SPMEN_BIT = 9,
+ SPIM_RATE_MASK = 0xe000,
+ SPIM_RATE_SHIFT = 13,
+
+ USTCNT_TX_AVAIL_EN = 0x0001,
+ USTCNT_TX_HALF_EN = 0x0002,
+ USTCNT_TX_EMPTY_EN = 0x0004,
+ USTCNT_RX_RDY_EN = 0x0008,
+ USTCNT_RX_HALF_EN = 0x0010,
+ USTCNT_RX_FULL_EN = 0x0020,
+ USTCNT_CTS_DELTA_EN = 0x0040,
+ USTCNT_GPIO_DELTA_EN = 0x0080,
+ USTCNT_8_7 = 0x0100,
+ USTCNT_STOP_BITS = 0x0200,
+ USTCNT_ODD_EVEN = 0x0400,
+ USTCNT_PARITY_EN = 0x0800,
+ USTCNT_RX_CLK_CONT = 0x1000,
+ USTCNT_TX_EN = 0x2000,
+ USTCNT_RX_EN = 0x4000,
+ USTCNT_UART_EN = 0x8000,
+
+ UBAUD_PRESCALER = 0x00ff,
+ UBAUD_DIVIDE = 0x0700,
+ UBAUD_DIVIDE_1 = 0x0000,
+ UBAUD_DIVIDE_2 = 0x0100,
+ UBAUD_DIVIDE_4 = 0x0200,
+ UBAUD_DIVIDE_8 = 0x0300,
+ UBAUD_DIVIDE_16 = 0x0400,
+ UBAUD_DIVIDE_32 = 0x0500,
+ UBAUD_DIVIDE_64 = 0x0600,
+ UBAUD_DIVIDE_128 = 0x0700,
+ UBAUD_BAUD_SRC = 0x0800,
+ UBAUD_GPIO_SRC = 0x1000,
+ UBAUD_GPIO_DIR = 0x2000,
+ UBAUD_GPIO = 0x4000,
+ UBAUD_GPIO_DELTA = 0x8000,
+
+ URX_PARITY_ERROR = 0x0100,
+ URX_BREAK = 0x0200,
+ URX_FRAME_ERROR = 0x0400,
+ URX_OVRUN = 0x0800,
+ URX_DATA_READY = 0x2000,
+ URX_FIFO_HALF = 0x4000,
+ URX_FIFO_FULL = 0x8000,
+
+ UTX_CTS_DELTA = 0x0100,
+ UTX_CTS_STATUS = 0x0200,
+ UTX_IGNORE_CTS = 0x0800,
+ UTX_SEND_BREAK = 0x1000,
+ UTX_TX_AVAIL = 0x2000,
+ UTX_FIFO_HALF = 0x4000,
+ UTX_FIFO_EMPTY = 0x8000,
+
+ UMISC_IRDA_LOOP = 0x0010,
+ UMISC_IRDA_ENABLE = 0x0020,
+ UMISC_RTS = 0x0040,
+ UMISC_RTS_CONT = 0x0080,
+ UMISC_LOOP = 0x1000,
+ UMISC_FORCE_PERR = 0x2000,
+ UMISC_CLK_SRC = 0x4000,
+
+ CXP_MASK = 0x03ff,
+ CXP_CC = 0xc000,
+ CXP_CC_XLU = 0x0000,
+ CXP_CC_BLACK = 0x4000,
+ CXP_CC_INVERSE = 0x8000,
+ CXP_CC_INVALID = 0xc000,
+
+ CYP_MASK = 0x01ff,
+
+ CWCH_CH = 0x001f,
+ CWCH_CW = 0x1f00,
+
+ LXMAX_MASK = 0x03ff,
+
+ LYMAX_MASK = 0x03ff,
+
+ RTCCTL_38_4_BIT = 5,
+ RTCCTL_ENABLE_BIT = 7,
+ RTCCTL_MASK = 0x00a0,
+
+ RTCINT_STOPWATCH = 0x0001,
+ RTCINT_MINUTE = 0x0002,
+ RTCINT_ALARM = 0x0004,
+ RTCINT_DAY = 0x0008,
+ RTCINT_SECOND = 0x0010,
+
+ RTCSTPWTCH_MASK = 0x003f,
+ };
+
+ enum : u32
+ {
+ CSAB_WAIT = 0x00000007,
+ CSAB_RO = 0x00000008,
+ CSAB_MASK = 0x0000ff00,
+ CSAB_BSW = 0x00010000,
+ CSAB_COMPARE = 0xff000000,
+
+ CSCD_WAIT = 0x00000007,
+ CSCD_RO = 0x00000008,
+ CSCD_MASK = 0x0000fff0,
+ CSCD_BSW = 0x00010000,
+ CSCD_COMPARE = 0xfff00000,
+
+ INT_SPIM = 0,
+ INT_SPIM_MASK = (1 << INT_SPIM),
+ INT_TIMER2 = 1,
+ INT_TIMER2_MASK = (1 << INT_TIMER2),
+ INT_UART = 2,
+ INT_UART_MASK = (1 << INT_UART),
+ INT_WDT = 3,
+ INT_WDT_MASK = (1 << INT_WDT),
+ INT_RTC = 4,
+ INT_RTC_MASK = (1 << INT_RTC),
+ INT_KB = 6,
+ INT_KB_MASK = (1 << INT_KB),
+ INT_PWM = 7,
+ INT_PWM_MASK = (1 << INT_PWM),
+ INT_INT0 = 8,
+ INT_INT0_MASK = (1 << INT_INT0),
+ INT_INT1 = 9,
+ INT_INT1_MASK = (1 << INT_INT1),
+ INT_INT2 = 10,
+ INT_INT2_MASK = (1 << INT_INT2),
+ INT_INT3 = 11,
+ INT_INT3_MASK = (1 << INT_INT3),
+ INT_INT4 = 12,
+ INT_INT4_MASK = (1 << INT_INT4),
+ INT_INT5 = 13,
+ INT_INT5_MASK = (1 << INT_INT5),
+ INT_INT6 = 14,
+ INT_INT6_MASK = (1 << INT_INT6),
+ INT_INT7 = 15,
+ INT_INT7_MASK = (1 << INT_INT7),
+ INT_KBDINTS = 8,
+ INT_KBDINTS_MASK = (1 << INT_KBDINTS),
+ INT_IRQ1 = 16,
+ INT_IRQ1_MASK = (1 << INT_IRQ1),
+ INT_IRQ2 = 17,
+ INT_IRQ2_MASK = (1 << INT_IRQ2),
+ INT_IRQ3 = 18,
+ INT_IRQ3_MASK = (1 << INT_IRQ3),
+ INT_IRQ6 = 19,
+ INT_IRQ6_MASK = (1 << INT_IRQ6),
+ INT_IRQ5 = 20,
+ INT_IRQ5_MASK = (1 << INT_IRQ5),
+ INT_SPIS = 21,
+ INT_SPIS_MASK = (1 << INT_SPIS),
+ INT_TIMER1 = 22,
+ INT_TIMER1_MASK = (1 << INT_TIMER1),
+ INT_IRQ7 = 23,
+ INT_IRQ7_MASK = (1 << INT_IRQ7),
+
+ RTCHMSR_SECONDS = 0x0000003f,
+ RTCHMSR_SECONDS_SHIFT = 0,
+ RTCHMSR_MINUTES = 0x003f0000,
+ RTCHMSR_MINUTES_SHIFT = 16,
+ RTCHMSR_HOURS = 0x1f000000,
+ RTCHMSR_HOURS_SHIFT = 24,
+ };
+
+ void scr_w(u8 data);
+
+ void grpbasea_w(u16 data);
+ void grpbaseb_w(u16 data);
+ void grpbasec_w(u16 data);
+ void grpbased_w(u16 data);
+
+ void pllcr_w(u16 data);
+ void pllfsr_w(u16 data);
+ void pctlr_w(u8 data);
+ void ivr_w(u8 data);
+ void icr_w(u8 data);
+ void imr_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ void imr_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ void isr_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ void isr_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ void ipr_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ void ipr_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+
+ void padir_w(u8 data);
+ void padata_w(u8 data);
+ void pbdir_w(u8 data);
+ void pbdata_w(u8 data);
+ void pbsel_w(u8 data);
+ void pcdir_w(u8 data);
+ void pcdata_w(u8 data);
+ void pcsel_w(u8 data);
+ void pddir_w(u8 data);
+ void pddata_w(u8 data);
+ void pdpuen_w(u8 data);
+ void pdpol_w(u8 data);
+ void pdirqen_w(u8 data);
+ void pdirqedge_w(u8 data);
+ void pedir_w(u8 data);
+ void pedata_w(u8 data);
+ void pepuen_w(u8 data);
+ void pesel_w(u8 data);
+ void pfdir_w(u8 data);
+ void pfdata_w(u8 data);
+ void pfpuen_w(u8 data);
+ void pfsel_w(u8 data);
+ void pgdir_w(u8 data);
+ void pgdata_w(u8 data);
+ void pgpuen_w(u8 data);
+ void pgsel_w(u8 data);
+
+ virtual void pwmc_w(u16 data) = 0;
+
+ template <int Timer> void tctl_w(u16 data);
+ template <int Timer> void tprer_w(u16 data);
+ template <int Timer> void tcmp_w(u16 data);
+ template <int Timer> void tcr_w(u16 data);
+ template <int Timer> void tcn_w(u16 data);
+ template <int Timer> void tstat_w(u16 data);
+
+ void spimdata_w(u16 data);
+ void spimcont_w(u16 data);
+
+ void ustcnt_w(u16 data);
+ void ubaud_w(u16 data);
+ void urx_w(u16 data);
+ void utx_w(u16 data);
+ void umisc_w(u16 data);
+
+ void lssa_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ void lssa_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ void lvpw_w(u8 data);
+ void lxmax_w(u16 data);
+ void lymax_w(u16 data);
+ void lcxp_w(u16 data);
+ void lcyp_w(u16 data);
+ void lcwch_w(u16 data);
+ void lblkc_w(u8 data);
+ virtual void lpicf_w(u8 data) = 0;
+ void lpolcf_w(u8 data);
+ void lacdrc_w(u8 data);
+ void lpxcd_w(u8 data);
+ virtual void lckcon_w(u8 data) = 0;
+ void lposr_w(u8 data);
+ void lfrcm_w(u8 data);
+
+ void hmsr_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ void hmsr_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ void alarm_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ void alarm_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ virtual void rtcctl_w(offs_t offset, u16 data, u16 mem_mask);
+ void rtcisr_w(offs_t offset, u16 data, u16 mem_mask);
+ void rtcienr_w(offs_t offset, u16 data, u16 mem_mask);
+ void stpwtch_w(offs_t offset, u16 data, u16 mem_mask);
+
+ u8 scr_r();
+
+ u16 grpbasea_r();
+ u16 grpbaseb_r();
+ u16 grpbasec_r();
+ u16 grpbased_r();
+
+ u16 pllcr_r();
+ u16 pllfsr_r();
+ u8 pctlr_r();
+
+ u8 ivr_r();
+ u16 icr_r();
+ u16 imr_msw_r();
+ u16 imr_lsw_r();
+ u16 isr_msw_r();
+ u16 isr_lsw_r();
+ u16 ipr_msw_r();
+ u16 ipr_lsw_r();
+
+ u8 padir_r();
+ u8 padata_r();
+ u8 pbdir_r();
+ u8 pbdata_r();
+ u8 pbsel_r();
+ u8 pcdir_r();
+ u8 pcdata_r();
+ u8 pcsel_r();
+ u8 pddir_r();
+ u8 pddata_r();
+ u8 pdpuen_r();
+ u8 pdpol_r();
+ u8 pdirqen_r();
+ u8 pdirqedge_r();
+ u8 pedir_r();
+ u8 pedata_r();
+ u8 pepuen_r();
+ u8 pesel_r();
+ u8 pfdir_r();
+ u8 pfdata_r();
+ u8 pfpuen_r();
+ u8 pfsel_r();
+ u8 pgdir_r();
+ u8 pgdata_r();
+ u8 pgpuen_r();
+ u8 pgsel_r();
+
+ virtual u16 pwmc_r() = 0;
+
+ template <int Timer> u16 tctl_r();
+ template <int Timer> u16 tprer_r();
+ template <int Timer> u16 tcmp_r();
+ template <int Timer> u16 tcr_r();
+ template <int Timer> u16 tcn_r();
+ template <int Timer> u16 tstat_r();
+
+ u16 spimdata_r();
+ u16 spimcont_r();
+
+ u16 ustcnt_r();
+ u16 ubaud_r();
+ u16 urx_r();
+ u16 utx_r();
+ u16 umisc_r();
+
+ u16 lssa_msw_r();
+ u16 lssa_lsw_r();
+ u8 lvpw_r();
+ u16 lxmax_r();
+ u16 lymax_r();
+ u16 lcxp_r();
+ u16 lcyp_r();
+ u16 lcwch_r();
+ u8 lblkc_r();
+ u8 lpicf_r();
+ u8 lpolcf_r();
+ u8 lacdrc_r();
+ u8 lpxcd_r();
+ u8 lckcon_r();
+ u8 lposr_r();
+ u8 lfrcm_r();
+
+ u16 hmsr_msw_r();
+ u16 hmsr_lsw_r();
+ u16 alarm_msw_r();
+ u16 alarm_lsw_r();
+ u16 rtcctl_r();
+ u16 rtcisr_r();
+ u16 rtcienr_r();
+ u16 stpwtch_r();
+
+ // $(FF)FFF000
+ u8 m_scr; // System Control Register
+
+ // $(FF)FFF100
+ u16 m_grpbasea; // Chip Select Group A Base Register
+ u16 m_grpbaseb; // Chip Select Group B Base Register
+ u16 m_grpbasec; // Chip Select Group C Base Register
+ u16 m_grpbased; // Chip Select Group D Base Register
+
+ // $(FF)FFF200
+ u16 m_pllcr; // PLL Control Register
+ u16 m_pllfsr; // PLL Frequency Select Register
+ u8 m_pctlr; // Power Control Register
+
+ // $(FF)FFF300
+ u8 m_ivr; // Interrupt Vector Register
+ u16 m_icr; // Interrupt Control Register
+ u32 m_imr; // Interrupt Mask Register
+ u32 m_gisr; // (global) Interrupt Status Register
+ u32 m_ipr; // Interrupt Pending Register
+
+ // $(FF)FFF400
+ u8 m_padir; // Port A Direction Register
+ u8 m_padata; // Port A Data Register
+ u8 m_pasel; // Port A Select Register
+
+ u8 m_pbdir; // Port B Direction Register
+ u8 m_pbdata; // Port B Data Register
+ u8 m_pbsel; // Port B Select Register
+
+ u8 m_pcdir; // Port C Direction Register
+ u8 m_pcdata; // Port C Data Register
+ u8 m_pcsel; // Port C Select Register
+
+ u8 m_pddir; // Port D Direction Register
+ u8 m_pddata; // Port D Data Register
+ u8 m_pdpuen; // Port D Pullup Enable Register
+ u8 m_pdpol; // Port D Polarity Register
+ u8 m_pdirqen; // Port D IRQ Enable Register
+ u8 m_pdirqedge; // Port D IRQ Edge Register
+ u8 m_pdindata; // Port D direct input data (not memory-mapped)
+
+ u8 m_pedir; // Port E Direction Register
+ u8 m_pedata; // Port E Data Register
+ u8 m_pepuen; // Port E Pullup Enable Register
+ u8 m_pesel; // Port E Select Register
+
+ u8 m_pfdir; // Port F Direction Register
+ u8 m_pfdata; // Port F Data Register
+ u8 m_pfpuen; // Port F Pullup Enable Register
+ u8 m_pfsel; // Port F Select Register
+
+ u8 m_pgdir; // Port G Direction Register
+ u8 m_pgdata; // Port G Data Register
+ u8 m_pgpuen; // Port G Pullup Enable Register
+ u8 m_pgsel; // Port G Select Register
+
+ // $(FF)FFF500
+ u16 m_pwmc; // PWM Control Register
+ bool m_pwmo;
+
+ // $(FF)FFF600
+ struct timer_regs
+ {
+ u16 tctl; // Timer Control Register
+ u16 tprer; // Timer Prescaler Register
+ u16 tcmp; // Timer Compare Register
+ u16 tcr; // Timer Capture Register
+ u16 tcn; // Timer Counter
+ u16 tstat; // Timer Status
+ u16 tclear; // Timer Clearable Status
+ };
+
+ // $(FF)FFF800
+ u16 m_spimdata; // SPIM Data Register
+ u16 m_spimcont; // SPIM Control/Status Register
+ bool m_spmtxd; // SPIM Shift-register output (TODO: multiplex onto Port K)
+ bool m_spmrxd; // SPIM Shift-register input (TODO: multiplex onto Port K)
+ bool m_spmclk; // SPIM Shift-register clock (TODO: multiplex onto Port K)
+ u16 m_spim_bit_read_idx; // Starting bit index for SPI transfers
+
+ // $(FF)FFF900
+ u16 m_ustcnt; // UART Status/Control Register
+ u16 m_ubaud; // UART Baud Control Register
+ u16 m_urx; // UART RX Register
+ u16 m_utx; // UART TX Register
+ u16 m_umisc; // UART Misc Register
+
+ // $(FF)FFFA00
+ u32 m_lssa; // Screen Starting Address Register
+ u32 m_lssa_end; // Screen Starting Address Register, buffer end address (not memory-mapped)
+ u8 m_lvpw; // Virtual Page Width Register
+ u16 m_lxmax; // Screen Width Register
+ u16 m_lymax; // Screen Height Register
+ u16 m_lcxp; // Cursor X Position
+ u16 m_lcyp; // Cursor Y Position
+ u16 m_lcwch; // Cursor Width & Height Register
+ u8 m_lblkc; // Blink Control Register
+ u8 m_lpicf; // Panel Interface Config Register
+ u8 m_lpolcf; // Polarity Config Register
+ u8 m_lacdrc; // ACD (M) Rate Control Register
+ u8 m_lpxcd; // Pixel Clock Divider Register
+ u8 m_lckcon; // Clocking Control Register
+ u8 m_lposr; // Panning Offset Register
+ u8 m_lfrcm; // Frame Rate Control Modulation Register
+ bool m_lcd_update_pending;
+
+ // $(FF)FFFB00
+ u32 m_hmsr; // RTC Hours Minutes Seconds Register
+ u32 m_alarm; // RTC Alarm Register
+ u16 m_rtcctl; // RTC Control Register
+ u16 m_rtcisr; // RTC Interrupt Status Register
+ u16 m_rtcienr; // RTC Interrupt Enable Register
+ u16 m_stpwtch; // Stopwatch Minutes
+
+ void base_internal_map(u32 addr_bits, address_map &map);
+
+ // internal state
+ u8 irq_callback(offs_t offset);
+ virtual void register_state_save();
+
+ void update_ipr_state(u32 changed_mask);
+ void update_imr_state(u32 changed_mask);
+ void set_interrupt_line(u32 line, u32 active);
+ virtual u32 get_irq_mask_for_level(int level) = 0;
+ virtual int get_irq_level_for_mask(u32 level) = 0;
+
+ virtual emu_timer *get_timer(int timer) = 0;
+ virtual timer_regs &get_timer_regs(int timer) = 0;
+ virtual u32 get_timer_int(int timer) = 0;
+ template<int Timer> u32 get_timer_frequency();
+ template<int Timer> void update_gptimer_state();
+ template<int Timer> TIMER_CALLBACK_MEMBER(timer_tick);
+
+ virtual void lcd_update_info() = 0;
+ virtual u16 lcd_get_lxmax_mask() = 0;
+ virtual int lcd_get_width() = 0;
+ virtual u32 lcd_get_line_word_count() = 0;
+ virtual attotime lcd_get_line_rate() = 0;
+ virtual u8 lcd_get_panel_bit_size() = 0;
+ virtual attotime get_pixclk_rate() = 0;
+
+ TIMER_CALLBACK_MEMBER(refclk_tick);
+ virtual TIMER_CALLBACK_MEMBER(pwm_tick) = 0;
+ TIMER_CALLBACK_MEMBER(rtc_tick);
+ TIMER_CALLBACK_MEMBER(spim_tick);
+ TIMER_CALLBACK_MEMBER(lcd_scan_tick);
+ void fill_lcd_dma_buffer();
+
+ virtual bool rtc_int_is_active() = 0;
+ virtual void rtc_advance_seconds();
+ virtual u16 rtc_get_int_mask() = 0;
+ virtual bool rtc_get_alarm_match() = 0;
+
+ emu_timer *m_refclk;
+ emu_timer *m_pwm;
+ emu_timer *m_rtc;
+ emu_timer *m_spim;
+
+ emu_timer *m_lcd_scan;
+ bool m_lcd_first_line;
+ u32 m_lcd_sysmem_ptr;
+ u32 m_lcd_line_bit;
+ u32 m_lcd_line_word;
+ bool m_lsclk;
+ std::unique_ptr<u16[]> m_lcd_line_buffer;
+
+ devcb_write_line::array<8> m_out_port_a_cb;
+ devcb_write_line::array<8> m_out_port_b_cb;
+ devcb_write_line::array<8> m_out_port_c_cb;
+ devcb_write_line::array<8> m_out_port_d_cb;
+ devcb_write_line::array<8> m_out_port_e_cb;
+ devcb_write_line::array<8> m_out_port_f_cb;
+ devcb_write_line::array<8> m_out_port_g_cb;
+
+ devcb_read_line::array<8> m_in_port_a_cb;
+ devcb_read_line::array<8> m_in_port_b_cb;
+ devcb_read_line::array<8> m_in_port_c_cb;
+ devcb_read_line::array<8> m_in_port_d_cb;
+ devcb_read_line::array<8> m_in_port_e_cb;
+ devcb_read_line::array<8> m_in_port_f_cb;
+ devcb_read_line::array<8> m_in_port_g_cb;
+
+ devcb_write_line m_out_pwm_cb;
+
+ devcb_write_line m_out_spim_cb;
+ devcb_read_line m_in_spim_cb;
+
+ devcb_write_line m_out_flm_cb;
+ devcb_write_line m_out_llp_cb;
+ devcb_write_line m_out_lsclk_cb;
+ devcb_write8 m_out_ld_cb;
+ lcd_info_changed_delegate m_lcd_info_changed_cb;
+
+ static const u32 VCO_DIVISORS[8];
+};
+
+class mc68328_device : public mc68328_base_device
+{
+public:
+ mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ template <int Line> auto out_port_j() { return m_out_port_j_cb[Line].bind(); }
+ template <int Line> auto out_port_k() { return m_out_port_k_cb[Line].bind(); }
+ template <int Line> auto out_port_m() { return m_out_port_m_cb[Line].bind(); }
+ template <int Line> auto in_port_j() { return m_in_port_j_cb[Line].bind(); }
+ template <int Line> auto in_port_k() { return m_in_port_k_cb[Line].bind(); }
+ template <int Line> auto in_port_m() { return m_in_port_m_cb[Line].bind(); }
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
private:
- struct mc68328_regs_t
+ enum : u8
{
- // $(FF)FFF000
- uint8_t scr; // System Control Register
- uint8_t unused0[255];
-
- // $(FF)FFF100
- uint16_t grpbasea; // Chip Select Group A Base Register
- uint16_t grpbaseb; // Chip Select Group B Base Register
- uint16_t grpbasec; // Chip Select Group C Base Register
- uint16_t grpbased; // Chip Select Group D Base Register
- uint16_t grpmaska; // Chip Select Group A Mask Register
- uint16_t grpmaskb; // Chip Select Group B Mask Register
- uint16_t grpmaskc; // Chip Select Group C Mask Register
- uint16_t grpmaskd; // Chip Select Group D Mask Register
- uint32_t csa0; // Group A Chip Select 0 Register
- uint32_t csa1; // Group A Chip Select 1 Register
- uint32_t csa2; // Group A Chip Select 2 Register
- uint32_t csa3; // Group A Chip Select 3 Register
- uint32_t csb0; // Group B Chip Select 0 Register
- uint32_t csb1; // Group B Chip Select 1 Register
- uint32_t csb2; // Group B Chip Select 2 Register
- uint32_t csb3; // Group B Chip Select 3 Register
- uint32_t csc0; // Group C Chip Select 0 Register
- uint32_t csc1; // Group C Chip Select 1 Register
- uint32_t csc2; // Group C Chip Select 2 Register
- uint32_t csc3; // Group C Chip Select 3 Register
- uint32_t csd0; // Group D Chip Select 0 Register
- uint32_t csd1; // Group D Chip Select 1 Register
- uint32_t csd2; // Group D Chip Select 2 Register
- uint32_t csd3; // Group D Chip Select 3 Register
- uint8_t unused1[176];
-
- // $(FF)FFF200
- uint16_t pllcr; // PLL Control Register
- uint16_t pllfsr; // PLL Frequency Select Register
- uint8_t pad2[3];
- uint8_t pctlr; // Power Control Register
- uint8_t unused3[248];
-
- // $(FF)FFF300
- uint8_t ivr; // Interrupt Vector Register
- uint8_t unused4[1];
- uint16_t icr; // Interrupt Control Register
- uint32_t imr; // Interrupt Mask Register
- uint32_t iwr; // Interrupt Wakeup Enable Register
- uint32_t isr; // Interrupt Status Register
- uint32_t ipr; // Interrupt Pending Register
- uint8_t unused5[236];
-
- // $(FF)FFF400
- uint8_t padir; // Port A Direction Register
- uint8_t padata; // Port A Data Register
- uint8_t unused6[1];
- uint8_t pasel; // Port A Select Register
- uint8_t unused7[4];
-
- uint8_t pbdir; // Port B Direction Register
- uint8_t pbdata; // Port B Data Register
- uint8_t unused8[1];
- uint8_t pbsel; // Port B Select Register
- uint8_t unused9[4];
-
- uint8_t pcdir; // Port C Direction Register
- uint8_t pcdata; // Port C Data Register
- uint8_t unused10[1];
- uint8_t pcsel; // Port C Select Register
- uint8_t unused11[4];
-
- uint8_t pddir; // Port D Direction Register
- uint8_t pddata; // Port D Data Register
- uint8_t pdpuen; // Port D Pullup Enable Register
- uint8_t unused12[1];
- uint8_t pdpol; // Port D Polarity Register
- uint8_t pdirqen; // Port D IRQ Enable Register
- uint8_t pddataedge; // Port D Data Edge Level
- uint8_t pdirqedge; // Port D IRQ Edge Register
-
- uint8_t pedir; // Port E Direction Register
- uint8_t pedata; // Port E Data Register
- uint8_t pepuen; // Port E Pullup Enable Register
- uint8_t pesel; // Port E Select Register
- uint8_t unused14[4];
-
- uint8_t pfdir; // Port F Direction Register
- uint8_t pfdata; // Port F Data Register
- uint8_t pfpuen; // Port F Pullup Enable Register
- uint8_t pfsel; // Port F Select Register
- uint8_t unused15[4];
-
- uint8_t pgdir; // Port G Direction Register
- uint8_t pgdata; // Port G Data Register
- uint8_t pgpuen; // Port G Pullup Enable Register
- uint8_t pgsel; // Port G Select Register
- uint8_t unused16[4];
-
- uint8_t pjdir; // Port J Direction Register
- uint8_t pjdata; // Port J Data Register
- uint8_t unused17[1];
- uint8_t pjsel; // Port J Select Register
- uint8_t unused18[4];
- uint8_t pkdir; // Port K Direction Register
- uint8_t pkdata; // Port K Data Register
- uint8_t pkpuen; // Port K Pullup Enable Register
- uint8_t pksel; // Port K Select Register
- uint8_t unused19[4];
-
- uint8_t pmdir; // Port M Direction Register
- uint8_t pmdata; // Port M Data Register
- uint8_t pmpuen; // Port M Pullup Enable Register
- uint8_t pmsel; // Port M Select Register
- uint8_t unused20[180];
-
- // $(FF)FFF500
- uint16_t pwmc; // PWM Control Register
- uint16_t pwmp; // PWM Period Register
- uint16_t pwmw; // PWM Width Register
- uint16_t pwmcnt; // PWN Counter
- uint8_t unused21[248];
-
- // $(FF)FFF600
- uint16_t tctl[2]; // Timer Control Register
- uint16_t tprer[2]; // Timer Prescaler Register
- uint16_t tcmp[2]; // Timer Compare Register
- uint16_t tcr[2]; // Timer Capture Register
- uint16_t tcn[2]; // Timer Counter
- uint16_t tstat[2]; // Timer Status
- uint16_t wctlr; // Watchdog Control Register
- uint16_t wcmpr; // Watchdog Compare Register
- uint16_t wcn; // Watchdog Counter
- uint8_t tclear[2]; // Timer Clearable Status
- uint8_t unused22[224];
-
- // $(FF)FFF700
- uint16_t spisr; // SPIS Register
- uint8_t unused23[254];
-
- // $(FF)FFF800
- uint16_t spimdata; // SPIM Data Register
- uint16_t spimcont; // SPIM Control/Status Register
- uint8_t unused24[252];
-
- // $(FF)FFF900
- uint16_t ustcnt; // UART Status/Control Register
- uint16_t ubaud; // UART Baud Control Register
- uint16_t urx; // UART RX Register
- uint16_t utx; // UART TX Register
- uint16_t umisc; // UART Misc Register
- uint8_t unused25[246];
-
- // $(FF)FFFA00
- uint32_t lssa; // Screen Starting Address Register
- uint8_t unused26[1];
- uint8_t lvpw; // Virtual Page Width Register
- uint8_t unused27[2];
- uint16_t lxmax; // Screen Width Register
- uint16_t lymax; // Screen Height Register
- uint8_t unused28[12];
- uint16_t lcxp; // Cursor X Position
- uint16_t lcyp; // Cursor Y Position
- uint16_t lcwch; // Cursor Width & Height Register
- uint8_t unused29[1];
- uint8_t lblkc; // Blink Control Register
- uint8_t lpicf; // Panel Interface Config Register
- uint8_t lpolcf; // Polarity Config Register
- uint8_t unused30[1];
- uint8_t lacdrc; // ACD (M) Rate Control Register
- uint8_t unused31[1];
- uint8_t lpxcd; // Pixel Clock Divider Register
- uint8_t unused32[1];
- uint8_t lckcon; // Clocking Control Register
- uint8_t unused33[1];
- uint8_t llbar; // Last Buffer Address Register
- uint8_t unused34[1];
- uint8_t lotcr; // Octet Terminal Count Register
- uint8_t unused35[1];
- uint8_t lposr; // Panning Offset Register
- uint8_t unused36[3];
- uint8_t lfrcm; // Frame Rate Control Modulation Register
- uint16_t lgpmr; // Gray Palette Mapping Register
- uint8_t unused37[204];
-
- // $(FF)FFFB00
- uint32_t hmsr; // RTC Hours Minutes Seconds Register
- uint32_t alarm; // RTC Alarm Register
- uint8_t unused38[4];
- uint16_t rtcctl; // RTC Control Register
- uint16_t rtcisr; // RTC Interrupt Status Register
- uint16_t rtcienr; // RTC Interrupt Enable Register
- uint16_t stpwtch; // Stopwatch Minutes
- uint8_t unused42[1260];
+ LPICF_GS = 0x01,
+ LPICF_GS_BIT = 0,
+ LPICF_PBSIZ = 0x06,
+ LPICF_PBSIZ_SHIFT = 1,
+ LPICF_PBSIZ_1 = 0x00,
+ LPICF_PBSIZ_2 = 0x02,
+ LPICF_PBSIZ_4 = 0x04,
+
+ LCKCON_PCDS_BIT = 0,
+ LCKCON_DWIDTH = 0x02,
+ LCKCON_DWIDTH_BIT = 1,
+ LCKCON_WS = 0x30,
+ LCKCON_WS_SHIFT = 4,
+ LCKCON_WS_1 = 0x00,
+ LCKCON_WS_2 = 0x10,
+ LCKCON_WS_3 = 0x20,
+ LCKCON_WS_4 = 0x30,
+ LCKCON_DMA16 = 0x40,
+ LCKCON_DMA16_BIT = 6,
+ LCKCON_LCDON_BIT = 7,
};
+ enum : u16
+ {
+ PWMC_CLKSEL = 0x0007,
+ PWMC_PWMEN = 0x0010,
+ PWMC_POL = 0x0040,
+ PWMC_PIN = 0x0080,
+ PWMC_LOAD = 0x0100,
+ PWMC_IRQEN = 0x4000,
+ PWMC_PWMIRQ = 0x8000,
+
+ LGPMR_PAL2 = 0x0007,
+ LGPMR_PAL3 = 0x0070,
+ LGPMR_PAL0 = 0x0700,
+ LGPMR_PAL1 = 0x7000,
+
+ WCTLR_WDRST = 0x0008,
+ WCTLR_LOCK = 0x0004,
+ WCTLR_FI = 0x0002,
+ WCTLR_WDEN = 0x0001,
+
+ RTCIENR_MASK = 0x001f,
+ };
+
+ void grpmaska_w(u16 data);
+ void grpmaskb_w(u16 data);
+ void grpmaskc_w(u16 data);
+ void grpmaskd_w(u16 data);
+ template<int ChipSelect> void csa_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ template<int ChipSelect> void csa_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ template<int ChipSelect> void csb_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ template<int ChipSelect> void csb_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ template<int ChipSelect> void csc_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ template<int ChipSelect> void csc_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+ template<int ChipSelect> void csd_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ template<int ChipSelect> void csd_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+
+ void iwr_msw_w(offs_t offset, u16 data, u16 mem_mask);
+ void iwr_lsw_w(offs_t offset, u16 data, u16 mem_mask);
+
+ void pasel_w(u8 data);
+ void pjdir_w(u8 data);
+ void pjdata_w(u8 data);
+ void pjsel_w(u8 data);
+ void pkdir_w(u8 data);
+ void pkdata_w(u8 data);
+ void pkpuen_w(u8 data);
+ void pksel_w(u8 data);
+ void pmdir_w(u8 data);
+ void pmdata_w(u8 data);
+ void pmpuen_w(u8 data);
+ void pmsel_w(u8 data);
+
+ virtual void pwmc_w(u16 data) override;
+ void pwmp_w(u16 data);
+ void pwmw_w(u16 data);
+ void pwmcnt_w(u16 data);
+
+ void wctlr_w(u16 data);
+ void wcmpr_w(u16 data);
+ void wcn_w(u16 data);
+
+ void spisr_w(u16 data);
+
+ virtual void lpicf_w(u8 data) override;
+ virtual void lckcon_w(u8 data) override;
+ void llbar_w(u8 data);
+ void lotcr_w(u8 data);
+ void lgpmr_w(u8 data);
+
+ u16 grpmaska_r();
+ u16 grpmaskb_r();
+ u16 grpmaskc_r();
+ u16 grpmaskd_r();
+ template<int ChipSelect> u16 csa_msw_r();
+ template<int ChipSelect> u16 csa_lsw_r();
+ template<int ChipSelect> u16 csb_msw_r();
+ template<int ChipSelect> u16 csb_lsw_r();
+ template<int ChipSelect> u16 csc_msw_r();
+ template<int ChipSelect> u16 csc_lsw_r();
+ template<int ChipSelect> u16 csd_msw_r();
+ template<int ChipSelect> u16 csd_lsw_r();
+
+ u16 iwr_msw_r();
+ u16 iwr_lsw_r();
+
+ u8 pasel_r();
+ u8 pjdir_r();
+ u8 pjdata_r();
+ u8 pjsel_r();
+ u8 pkdir_r();
+ u8 pkdata_r();
+ u8 pkpuen_r();
+ u8 pksel_r();
+ u8 pmdata_r();
+ u8 pmdir_r();
+ u8 pmpuen_r();
+ u8 pmsel_r();
+
+ virtual u16 pwmc_r() override;
+ u16 pwmp_r();
+ u16 pwmw_r();
+ u16 pwmcnt_r();
+
+ u16 wctlr_r();
+ u16 wcmpr_r();
+ u16 wcn_r();
+
+ u16 spisr_r();
+
+ u8 llbar_r();
+ u8 lotcr_r();
+ u16 lgpmr_r();
+
+ // $(FF)FFF108
+ u16 m_grpmaska; // Chip Select Group A Mask Register
+ u16 m_grpmaskb; // Chip Select Group B Mask Register
+ u16 m_grpmaskc; // Chip Select Group C Mask Register
+ u16 m_grpmaskd; // Chip Select Group D Mask Register
+ u32 m_csa[4]; // Group A Chip Select Registers
+ u32 m_csb[4]; // Group B Chip Select Registers
+ u32 m_csc[4]; // Group C Chip Select Registers
+ u32 m_csd[4]; // Group D Chip Select Registers
+
+ // $(FF)FFF300
+ u32 m_iwr; // Interrupt Wakeup Enable Register
+
+ // $(FF)FFF438
+ u8 m_pjdir; // Port J Direction Register
+ u8 m_pjdata; // Port J Data Register
+ u8 m_pjsel; // Port J Select Register
+
+ u8 m_pkdir; // Port K Direction Register
+ u8 m_pkdata; // Port K Data Register
+ u8 m_pkpuen; // Port K Pullup Enable Register
+ u8 m_pksel; // Port K Select Register
+
+ u8 m_pmdir; // Port M Direction Register
+ u8 m_pmdata; // Port M Data Register
+ u8 m_pmpuen; // Port M Pullup Enable Register
+ u8 m_pmsel; // Port M Select Register
+
+ // $(FF)FFF502
+ u16 m_pwmp; // PWM Period Register
+ u16 m_pwmw; // PWM Width Register
+ u16 m_pwmcnt; // PWM Counter
+
+ // $(FF)FFF600
+ timer_regs m_timer_regs[2];
+ u16 m_wctlr; // Watchdog Control Register
+ u16 m_wcmpr; // Watchdog Compare Register
+ u16 m_wcn; // Watchdog Counter
+
+ // $(FF)FFF700
+ u16 m_spisr; // SPIS Register
+
+ // $(FF)FFFA00
+ u8 m_llbar; // Last Buffer Address Register
+ u8 m_lotcr; // Octet Terminal Count Register
+ u16 m_lgpmr; // Gray Palette Mapping Register
+
void internal_map(address_map &map);
+ void cpu_space_map(address_map &map);
// internal state
- void set_interrupt_line(uint32_t line, uint32_t active);
- void poll_port_d_interrupts();
- void cpu_space_map(address_map &map);
- uint8_t irq_callback(offs_t offset);
- uint32_t get_timer_frequency(uint32_t index);
- void maybe_start_timer(uint32_t index, uint32_t new_enable);
- void timer_compare_event(uint32_t index);
+ virtual void register_state_save() override;
- void register_state_save();
+ virtual u32 get_irq_mask_for_level(int level) override;
+ virtual int get_irq_level_for_mask(u32 level) override;
- TIMER_CALLBACK_MEMBER(timer1_hit);
- TIMER_CALLBACK_MEMBER(timer2_hit);
- TIMER_CALLBACK_MEMBER(pwm_transition);
- TIMER_CALLBACK_MEMBER(rtc_tick);
+ virtual TIMER_CALLBACK_MEMBER(pwm_tick) override;
- void internal_write(offs_t offset, uint16_t data, uint16_t mem_mask = 0xffff);
- uint16_t internal_read(offs_t offset, uint16_t mem_mask = 0xffff);
+ virtual emu_timer *get_timer(int timer) override;
+ virtual timer_regs &get_timer_regs(int timer) override;
+ virtual u32 get_timer_int(int timer) override;
- mc68328_regs_t m_regs;
+ virtual void lcd_update_info() override;
+ virtual u16 lcd_get_lxmax_mask() override;
+ virtual int lcd_get_width() override;
+ virtual u32 lcd_get_line_word_count() override;
+ virtual attotime lcd_get_line_rate() override;
+ virtual u8 lcd_get_panel_bit_size() override;
+ virtual attotime get_pixclk_rate() override;
- emu_timer *m_gptimer[2];
- emu_timer *m_rtc;
- emu_timer *m_pwm;
+ virtual bool rtc_int_is_active() override;
+ virtual u16 rtc_get_int_mask() override;
+ virtual bool rtc_get_alarm_match() override;
+
+ emu_timer *m_gptimer[2];
- devcb_write8 m_out_port_a_cb; /* 8-bit output */
- devcb_write8 m_out_port_b_cb; /* 8-bit output */
- devcb_write8 m_out_port_c_cb; /* 8-bit output */
- devcb_write8 m_out_port_d_cb; /* 8-bit output */
- devcb_write8 m_out_port_e_cb; /* 8-bit output */
- devcb_write8 m_out_port_f_cb; /* 8-bit output */
- devcb_write8 m_out_port_g_cb; /* 8-bit output */
- devcb_write8 m_out_port_j_cb; /* 8-bit output */
- devcb_write8 m_out_port_k_cb; /* 8-bit output */
- devcb_write8 m_out_port_m_cb; /* 8-bit output */
-
- devcb_read8 m_in_port_a_cb; /* 8-bit input */
- devcb_read8 m_in_port_b_cb; /* 8-bit input */
- devcb_read8 m_in_port_c_cb; /* 8-bit input */
- devcb_read8 m_in_port_d_cb; /* 8-bit input */
- devcb_read8 m_in_port_e_cb; /* 8-bit input */
- devcb_read8 m_in_port_f_cb; /* 8-bit input */
- devcb_read8 m_in_port_g_cb; /* 8-bit input */
- devcb_read8 m_in_port_j_cb; /* 8-bit input */
- devcb_read8 m_in_port_k_cb; /* 8-bit input */
- devcb_read8 m_in_port_m_cb; /* 8-bit input */
-
- devcb_write8 m_out_pwm_cb; /* 1-bit output */
-
- devcb_write16 m_out_spim_cb; /* 16-bit output */
- devcb_read16 m_in_spim_cb; /* 16-bit input */
-
- devcb_write_line m_spim_xch_trigger_cb; /* SPIM exchange trigger */ /*todo: not really a write line, fix*/
+ devcb_write_line::array<8> m_out_port_j_cb;
+ devcb_write_line::array<8> m_out_port_k_cb;
+ devcb_write_line::array<8> m_out_port_m_cb;
+
+ devcb_read_line::array<8> m_in_port_j_cb;
+ devcb_read_line::array<8> m_in_port_k_cb;
+ devcb_read_line::array<8> m_in_port_m_cb;
};
+class mc68ez328_device : public mc68328_base_device
+{
+public:
+ mc68ez328_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ enum : u8
+ {
+ LPICF_GS = 0x03,
+ LPICF_GS_2COL = 0x00,
+ LPICF_GS_4COL = 0x01,
+ LPICF_GS_16COL = 0x02,
+ LPICF_PBSIZ = 0x0c,
+ LPICF_PBSIZ_SHIFT = 2,
+ LPICF_PBSIZ_1 = 0x00,
+ LPICF_PBSIZ_2 = 0x04,
+ LPICF_PBSIZ_4 = 0x08,
+
+ LCKCON_DWS = 0x0f,
+ LCKCON_DWS_SHIFT = 0,
+ LCKCON_DWIDTH = 0x40,
+ LCKCON_DWIDTH_BIT = 6,
+ LCKCON_LCDON_BIT = 7,
+ };
+
+ enum : u16
+ {
+ CSA_MASK = 0x81ff,
+ CSB_MASK = 0xf9ff,
+ CSC_MASK = 0xf9ff,
+ CSD_MASK = 0xffff,
+ EMUCS_MASK = 0x0070,
+ CS_EN_BIT = 0,
+ CS_SIZ_MASK = 0x000e,
+ CS_SIZ_SHIFT = 1,
+ CS_WS_MASK = 0x0070,
+ CS_WS_SHIFT = 4,
+ CS_BSW_BIT = 7,
+ CS_FLASH_BIT = 8,
+ CS_DRAM_BIT = 9,
+ CS_COMB_BIT = 10,
+ CS_UPSIZ_MASK = 0x1800,
+ CS_UPSIZ_SHIFT = 11,
+ CS_ROP_BIT = 13,
+ CS_SOP_BIT = 14,
+ CS_RO_BIT = 15,
+
+ PWMC_CLKSEL = 0x0003,
+ PWMC_REPEAT = 0x000c,
+ PWMC_REPEAT_SHIFT = 2,
+ PWMC_EN = 0x0010,
+ PWMC_FIFO_AV = 0x0020,
+ PWMC_IRQ_EN = 0x0040,
+ PWMC_IRQ = 0x0080,
+ PWMC_IRQ_BIT = 7,
+ PWMC_PRESCALE = 0x7f00,
+ PWMC_PRESCALE_SHIFT = 8,
+ PWMC_CLK_SRC = 0x8000,
+ PWMC_RECALC_MASK = PWMC_CLK_SRC | PWMC_PRESCALE | PWMC_CLKSEL | PWMC_EN,
+
+ WATCHDOG_MASK = 0x0083,
+ WATCHDOG_EN_BIT = 0,
+ WATCHDOG_ISEL_BIT = 1,
+ WATCHDOG_INTF = 0x0080,
+ WATCHDOG_INTF_BIT = 7,
+ WATCHDOG_CNT_MASK = 0x0300,
+ WATCHDOG_CNT_SHIFT = 8,
+
+ RTCINT_HOUR = 0x0020,
+ RTCINT_SAM0 = 0x0100,
+ RTCINT_SAM1 = 0x0200,
+ RTCINT_SAM2 = 0x0400,
+ RTCINT_SAM3 = 0x0800,
+ RTCINT_SAM4 = 0x1000,
+ RTCINT_SAM5 = 0x2000,
+ RTCINT_SAM6 = 0x4000,
+ RTCINT_SAM7 = 0x8000,
+ RTCINT_RTCIRQ_MASK = 0x00ff,
+
+ RTC_DAYS_MASK = 0x01ff,
+ };
+
+ enum : u32
+ {
+ INT_MSAM = 22,
+ INT_MSAM_MASK = (1 << INT_MSAM),
+ INT_MEMIQ = 23,
+ INT_MEMIQ_MASK = (1 << INT_MEMIQ),
+ };
+
+ void csa_w(offs_t offset, u16 data, u16 mem_mask);
+ void csb_w(offs_t offset, u16 data, u16 mem_mask);
+ void csc_w(offs_t offset, u16 data, u16 mem_mask);
+ void csd_w(offs_t offset, u16 data, u16 mem_mask);
+ void emucs_w(offs_t offset, u16 data, u16 mem_mask);
+
+ virtual void pwmc_w(u16 data) override;
+ void pwms_w(offs_t offset, u16 data, u16 mem_mask);
+ void pwmp_w(u8 data);
+ void pwmcnt_w(u8 data);
+
+ virtual void lpicf_w(u8 data) override;
+ virtual void lckcon_w(u8 data) override;
+ void lrra_w(u8 data);
+ void pwmr_w(offs_t offset, u16 data, u16 mem_mask);
+
+ void watchdog_w(offs_t offset, u16 data, u16 mem_mask);
+ virtual void rtcctl_w(offs_t offset, u16 data, u16 mem_mask) override;
+ void dayr_w(offs_t offset, u16 data, u16 mem_mask);
+ void dayalarm_w(offs_t offset, u16 data, u16 mem_mask);
+
+ u8 revision_r(offs_t offset);
+
+ u16 csa_r();
+ u16 csb_r();
+ u16 csc_r();
+ u16 csd_r();
+ u16 emucs_r();
+
+ virtual u16 pwmc_r() override;
+ u16 pwms_r();
+ u8 pwmp_r();
+ u8 pwmcnt_r();
+
+ u8 lrra_r();
+ u16 pwmr_r();
+
+ u16 watchdog_r();
+ u16 dayr_r();
+ u16 dayalarm_r();
+
+ // $(FF)FFF100
+ u16 m_csa; // Group A Chip-Select Register
+ u16 m_csb; // Group B Chip-Select Register
+ u16 m_csc; // Group C Chip-Select Register
+ u16 m_csd; // Group D Chip-Select Register
+ u16 m_emucs; // Emulation Chip-Select Register
+
+ // $(FF)FFF502
+ u8 m_pwmp; // PWM Period Register
+ u8 m_pwmcnt; // PWM Counter
+ u8 m_pwmfifo[5]; // PWM FIFO
+ u8 m_pwmfifo_wr; // PWM FIFO Write Index
+ u8 m_pwmfifo_rd; // PWM FIFO Read Index
+ u8 m_pwmfifo_cnt; // PWM FIFO Count
+ u8 m_pwm_rep_cnt; // PWM Repeat Count
+
+ // $(FF)FFF600
+ timer_regs m_timer_regs;
+
+ // $(FF)FFFA00
+ u8 m_lrra; // LCD Refresh Rate Adjustment Register
+ u16 m_pwmr; // PWM Contrast Control Register
+
+ // $(FF)FFFB00
+ u16 m_watchdog; // Watchdog Timer Register
+ u16 m_dayr; // RTC Day Count Register
+ u16 m_dayalarm; // RTC Day Alarm Register
+ u8 m_sam_cnt; // RTC Sample Timer Counter (internal, not readable)
+
+ void internal_map(address_map &map);
+ void cpu_space_map(address_map &map);
+
+ // internal state
+ virtual void register_state_save() override;
+
+ virtual u32 get_irq_mask_for_level(int level) override;
+ virtual int get_irq_level_for_mask(u32 level) override;
+
+ void update_pwm_period(bool high_cycle);
+ void pwm_fifo_push(u8 data);
+ void pwm_fifo_pop();
+ virtual TIMER_CALLBACK_MEMBER(pwm_tick) override;
+
+ virtual emu_timer *get_timer(int timer) override;
+ virtual timer_regs &get_timer_regs(int timer) override;
+ virtual u32 get_timer_int(int timer) override;
+
+ virtual void lcd_update_info() override;
+ virtual u16 lcd_get_lxmax_mask() override;
+ virtual int lcd_get_width() override;
+ virtual u32 lcd_get_line_word_count() override;
+ virtual attotime lcd_get_line_rate() override;
+ virtual u8 lcd_get_panel_bit_size() override;
+ virtual attotime get_pixclk_rate() override;
+
+ TIMER_CALLBACK_MEMBER(sample_timer_tick);
+ virtual bool rtc_int_is_active() override;
+ virtual void rtc_advance_seconds() override;
+ virtual u16 rtc_get_int_mask() override;
+ virtual bool rtc_get_alarm_match() override;
+
+ emu_timer *m_gptimer;
+ emu_timer *m_rtc_sample_timer;
+};
DECLARE_DEVICE_TYPE(MC68328, mc68328_device)
+DECLARE_DEVICE_TYPE(MC68EZ328, mc68ez328_device)
#endif // MAME_MACHINE_MC68328_H
diff --git a/src/devices/machine/mc6843.cpp b/src/devices/machine/mc6843.cpp
index 74945094b40..d1df8e4d4ee 100644
--- a/src/devices/machine/mc6843.cpp
+++ b/src/devices/machine/mc6843.cpp
@@ -1,835 +1,952 @@
// license:BSD-3-Clause
-// copyright-holders:Antoine Mine
-/**********************************************************************
-
- Copyright (C) Antoine Mine' 2007
-
- Motorola 6843 Floppy Disk Controller emulation.
-
-**********************************************************************/
-
-/*
- Main MC 6843 features are:
- - single density floppies
- - IBM 3740 compatible
- - DMA-able
- - high-level commands (including multi-sector read/write)
-
- CLONES: HD 46503S seems to be a clone of MC 6843
-
- BUGS
- The driver was designed with Thomson computer emulation in mind
- (CD 90-015 5"1/4 floppy controller) and works in this context.
- It might work in other contexts but has currently shortcomings:
- - DMA is not emulated
- - Free-Format Read is not emulated
- - Free-Format Write only supports track formatting, in a specific
- format (FWF=1, Thomson-like sector formats)
- - very rough timing: basically, there is a fixed delay between
- a command request (CMR write) and its response (first byte
- available, seek complete, etc.); there is no delay between
- read / write
- */
+// copyright-holders:Olivier Galibert
+// Not implemented for lack of test cases: FFR
#include "emu.h"
#include "mc6843.h"
-//#define VERBOSE 1
-#include "logmacro.h"
-
-
-/******************* parameters ******************/
-
-/* 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 */
-#define DELAY_CRC attotime::from_usec( 64 ) /* read crc time */
-
+DEFINE_DEVICE_TYPE(MC6843, mc6843_device, "mc6843", "Motorola MC6843 FDC")
+mc6843_device::mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MC6843, tag, owner, clock),
+ m_irq(*this),
+ m_force_ready(false)
+{
+}
-static const char *const mc6843_cmd[16] =
+void mc6843_device::device_start()
{
- "---", "---", "STZ", "SEK", "SSR", "SSW", "RCR", "SWD",
- "---", "---", "FFR", "FFW", "MSR", "MSW", "---", "---",
-};
+ m_timer = timer_alloc(FUNC(mc6843_device::update_tick), this);
+ m_floppy = nullptr;
+
+ m_dir = 0x00;
+ m_dor = 0x00;
+ m_ctar = 0x00;
+ m_sur = 0x00;
+ m_cmr = 0x00;
+ m_gcr = 0x00;
+ m_ccr = 0x00;
+ m_ltar = 0x00;
+
+ save_item(NAME(m_dir));
+ save_item(NAME(m_dor));
+ save_item(NAME(m_ctar));
+ save_item(NAME(m_cmr));
+ save_item(NAME(m_isr));
+ save_item(NAME(m_sur));
+ save_item(NAME(m_stra));
+ save_item(NAME(m_sar));
+ save_item(NAME(m_strb));
+ save_item(NAME(m_gcr));
+ save_item(NAME(m_ccr));
+ save_item(NAME(m_ltar));
+ save_item(NAME(m_state));
+ save_item(NAME(m_step_count));
+ save_item(NAME(m_head_loaded));
+ save_item(NAME(m_dir_loaded));
+ save_item(NAME(m_dor_loaded));
+ save_item(NAME(m_dor_needed));
+ save_item(NAME(m_idam_turns));
+}
+void mc6843_device::device_reset()
+{
+ m_state = S_IDLE;
+ m_cur_live.state = L_IDLE;
+ m_cur_live.tm = attotime::never;
+ m_step_count = 0;
+ m_head_loaded = false;
+ m_dir_loaded = false;
+ m_dor_loaded = false;
+ m_dor_needed = false;
-DEFINE_DEVICE_TYPE(MC6843, mc6843_device, "mc6843", "Motorola MC6843 FDC")
+ m_idam_turns = 0;
-mc6843_device::mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MC6843, tag, owner, clock),
- m_floppy(*this, {finder_base::DUMMY_TAG, finder_base::DUMMY_TAG, finder_base::DUMMY_TAG, finder_base::DUMMY_TAG}),
- m_write_irq(*this),
- m_CTAR(0),
- m_CMR(0),
- m_ISR(0),
- m_SUR(0),
- m_STRA(0),
- m_STRB(0),
- m_SAR(0),
- m_GCR(0),
- m_CCR(0),
- m_LTAR(0),
- m_drive(0),
- m_side(0),
- m_data_size(0),
- m_data_idx(0),
- m_data_id(0),
- m_index_pulse(0),
- m_crc_wait(0),
- m_timer_cont(nullptr)
-{
- for (auto & elem : m_data)
- {
- elem = 0;
- }
+ m_cmr &= 0xf0;
+ m_isr = 0x00;
+ m_stra = 0x00;
+ m_sar = 0x00;
+ m_strb = 0x00;
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void mc6843_device::device_start()
+void mc6843_device::map(address_map &map)
{
- m_write_irq.resolve_safe();
-
- m_timer_cont = timer_alloc(TIMER_CONT);
-
- save_item(NAME(m_CTAR));
- save_item(NAME(m_CMR));
- save_item(NAME(m_ISR));
- save_item(NAME(m_SUR));
- save_item(NAME(m_STRA));
- save_item(NAME(m_STRB));
- save_item(NAME(m_SAR));
- save_item(NAME(m_GCR));
- save_item(NAME(m_CCR));
- save_item(NAME(m_LTAR));
- save_item(NAME(m_drive));
- save_item(NAME(m_side));
- save_item(NAME(m_data));
- save_item(NAME(m_data_size));
- save_item(NAME(m_data_idx));
- save_item(NAME(m_data_id));
- save_item(NAME(m_crc_wait));
-}
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
+ map(0, 0).rw(FUNC(mc6843_device::dir_r), FUNC(mc6843_device::dor_w));
+ map(1, 1).rw(FUNC(mc6843_device::ctar_r), FUNC(mc6843_device::ctar_w));
+ map(2, 2).rw(FUNC(mc6843_device::isr_r), FUNC(mc6843_device::cmr_w));
+ map(3, 3).rw(FUNC(mc6843_device::stra_r), FUNC(mc6843_device::sur_w));
+ map(4, 4).rw(FUNC(mc6843_device::strb_r), FUNC(mc6843_device::sar_w));
+ map(5, 5).w (FUNC(mc6843_device::gcr_w));
+ map(6, 6).w (FUNC(mc6843_device::ccr_w));
+ map(7, 7).w (FUNC(mc6843_device::ltar_w));
+}
-void mc6843_device::device_reset()
+void mc6843_device::set_floppy(floppy_image_device *floppy)
{
- LOG (( "mc6843 reset\n" ));
+ if(m_floppy == floppy)
+ return;
- /* setup/reset floppy drive */
- for (auto &img : m_floppy)
- {
- if (img.found())
- {
- img->floppy_mon_w(CLEAR_LINE);
- img->floppy_drive_set_ready_state(FLOPPY_DRIVE_READY, 0 );
- img->floppy_drive_set_rpm( 300. );
- }
+ int prev_ready = m_floppy ? m_floppy->ready_r() : 1;
+
+ if(m_floppy) {
+ m_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
+ m_floppy->setup_ready_cb(floppy_image_device::ready_cb());
}
- /* reset registers */
- m_CMR &= 0xf0; /* zero only command */
- m_ISR = 0;
- m_STRA &= 0x5c;
- m_SAR = 0;
- m_STRB &= 0x20;
- status_update( );
+ m_floppy = floppy;
- m_data_size = 0;
- m_data_idx = 0;
- m_crc_wait = 0;
- m_timer_cont->adjust( attotime::never );
-}
+ logerror("floppy %s\n", m_floppy ? m_floppy->tag() : "-");
-/************************** floppy interface ****************************/
+ int next_ready = m_floppy ? m_floppy->ready_r() : 1;
+ if(m_floppy) {
+ m_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&mc6843_device::index_callback, this));
+ m_floppy->setup_ready_cb(floppy_image_device::ready_cb(&mc6843_device::ready_callback, this));
+ }
+ if(prev_ready != next_ready)
+ ready_callback(m_floppy, next_ready);
+}
-legacy_floppy_image_device* mc6843_device::floppy_image( )
+u8 mc6843_device::dir_r()
{
- assert(m_floppy[m_drive].found());
- return m_floppy[m_drive].target();
+ if(!machine().side_effects_disabled()) {
+ m_dir_loaded = false;
+ logerror("dir_r %02x\n", m_dir);
+ }
+ return m_dir;
}
+void mc6843_device::dor_w(u8 data)
+{
+ m_dor = data;
+ m_dor_loaded = true;
+ logerror("dor_w %02x\n", m_dor);
+
+ m_strb &= ~SB_DTERR;
+ if(m_strb == 0)
+ m_isr &= 0x7;
+}
-void mc6843_device::set_drive( int drive )
+u8 mc6843_device::ctar_r()
{
- m_drive = drive;
+ if(!machine().side_effects_disabled())
+ logerror("ctar_r %02x\n", m_ctar);
+ return m_ctar;
}
+void mc6843_device::ctar_w(u8 data)
+{
+ m_ctar = data;
+ logerror("ctar_w %02x\n", m_ctar);
+}
+void mc6843_device::isr_raise(u8 flag)
+{
+ m_isr |= flag;
+}
-void mc6843_device::set_side( int side )
+u8 mc6843_device::isr_r()
{
- m_side = side;
+ u8 res = m_isr;
+ if(!machine().side_effects_disabled()) {
+ logerror("isr_r %02x\n", m_isr);
+ m_isr &= 0x8;
+ }
+ return res;
}
+void mc6843_device::cmr_w(u8 data)
+{
+ static const char *cmds[0x10] = {
+ "nop", "?1",
+ "stz", "sek", "ssr", "ssw", "rcr", "swd",
+ "?8", "?9",
+ "ffr", "ffw", "msr", "msw",
+ "?e", "?f"
+ };
+
+ if(m_stra & SA_BUSY) {
+ if((data & 0xf) == 0 && (m_cmr & 0xf) == C_FFW) {
+ m_stra &= ~SA_BUSY;
+ live_abort();
+ m_state = S_IDLE;
+ } else {
+ logerror("cmr_w %02x - dropped busy\n", data);
+ return;
+ }
+ }
+ m_cmr = data;
+ logerror("cmr_w %02x - isr=%s isr3=%s %s fwf=%d %s\n", m_cmr,
+ m_cmr & 0x80 ? "off" : "on",
+ m_cmr & 0x40 ? "off" : "on",
+ m_cmr & 0x20 ? "dma" : "pio",
+ m_cmr & 0x10 ? 1 : 0,
+ cmds[m_cmr & 0xf]);
+ command_start();
+}
-/* called after ISR or STRB has changed */
-void mc6843_device::status_update( )
+u8 mc6843_device::stra_r()
{
- int irq = 0;
-
- /* ISR3 */
- if ( (m_CMR & 0x40) || ! m_STRB )
- m_ISR &= ~8;
- else
- m_ISR |= 8;
+ u8 res = m_stra;
+ if(m_floppy) {
+ if(m_floppy->idx_r())
+ res |= SA_IDX;
+ if(m_floppy->wpt_r())
+ res |= SA_WPT;
+ if(!m_floppy->trk00_r())
+ res |= SA_TRK0;
+ }
+ if(is_ready())
+ res |= SA_RDY;
- /* interrupts */
- if ( m_ISR & 4 )
- irq = 1; /* unmaskable */
- if ( ! (m_CMR & 0x80) )
- {
- /* maskable */
- if ( m_ISR & ~4 )
- irq = 1;
+ switch(m_cmr & 0xf) {
+ case C_SSR: case C_MSR: case C_FFR:
+ if(m_dir_loaded)
+ res |= SA_DTR;
+ break;
+ case C_SSW: case C_SWD: case C_MSW: case C_FFW:
+ if(!m_dor_loaded && m_dor_needed)
+ res |= SA_DTR;
+ break;
}
- m_write_irq( irq );
- LOG( "status_update: irq=%i (CMR=%02X, ISR=%02X)\n", irq, m_CMR, m_ISR );
+ if(!machine().side_effects_disabled()) {
+ static int prev = -1;
+ if(prev != res) {
+ logerror("stra_r %02x -%s%s%s%s%s%s%s%s\n", res,
+ res & SA_BUSY ? " busy" : "",
+ res & SA_IDX ? " idx" : "",
+ res & SA_TNEQ ? " tneq" : "",
+ res & SA_WPT ? " wpt" : "",
+ res & SA_TRK0 ? " trk0" : "",
+ res & SA_RDY ? " rdy" : "",
+ res & SA_DDM ? " ddm" : "",
+ res & SA_DTR ? " dtr" : "");
+ prev = res;
+ }
+ }
+ return res;
}
-
-void mc6843_device::set_index_pulse( int index_pulse )
+void mc6843_device::sur_w(u8 data)
{
- m_index_pulse = index_pulse;
+ m_sur = data;
+ logerror("sur_w %02x\n", m_sur);
}
+u8 mc6843_device::strb_r()
+{
+ u8 strb = m_strb;
+ if(!machine().side_effects_disabled()) {
+ logerror("strb_r %02x -%s%s%s%s%s%s%s%s\n", strb,
+ strb & SB_HERR ? " herr" : "",
+ strb & SB_WERR ? " werr" : "",
+ strb & SB_FI ? " fi" : "",
+ strb & SB_SERR ? " serr" : "",
+ strb & SB_SAERR ? " saerr" : "",
+ strb & SB_DMERR ? " dmerr" : "",
+ strb & SB_CRC ? " crc" : "",
+ strb & SB_DTERR ? " dterr" : "");
+ m_strb &= ~(SB_HERR|SB_WERR|SB_SERR|SB_SAERR|SB_DMERR|SB_CRC|SB_DTERR);
+ if(m_strb == 0)
+ m_isr &= 0x7;
+ }
+ return strb;
+}
-/* called at end of command */
-void mc6843_device::cmd_end( )
+void mc6843_device::sar_w(u8 data)
{
- int cmd = m_CMR & 0x0f;
+ m_sar = data & 0x1f;
+ logerror("sar_w %02x\n", m_sar);
+}
- if ( ( cmd == CMD_STZ ) || ( cmd == CMD_SEK ) )
- {
- m_ISR |= 0x02; /* set Settling Time Complete */
- }
- else
- {
- m_ISR |= 0x01; /* set Macro Command Complete */
- }
- m_STRA &= ~0x80; /* clear Busy */
- m_CMR &= 0xf0; /* clear command */
- status_update( );
+void mc6843_device::gcr_w(u8 data)
+{
+ m_gcr = data & 0x7f;
+ logerror("gcr_w %02x\n", m_gcr);
}
+void mc6843_device::ccr_w(u8 data)
+{
+ m_ccr = data & 3;
+ logerror("ccr_w %02x\n", m_ccr);
+}
+void mc6843_device::ltar_w(u8 data)
+{
+ m_ltar = data & 0x7f;
+ logerror("ltar_w %02x\n", m_ltar);
+}
-/* Seek Track Zero bottom half */
-void mc6843_device::finish_STZ( )
+void mc6843_device::index_callback(floppy_image_device *floppy, int state)
{
- legacy_floppy_image_device* img = floppy_image( );
- int i;
+ if(state) {
+ live_sync();
+ logerror("idam %d\n", m_idam_turns);
+ if(m_idam_turns) {
+ m_idam_turns --;
+ if(!m_idam_turns) {
+ live_abort();
+ m_state = S_IDAM_NOT_FOUND;
+ }
+ }
+ run(false, false, true);
+ }
+}
- /* seek to track zero */
- for ( i=0; i<83; i++ )
- {
- if (img->floppy_tk00_r() == CLEAR_LINE)
- break;
- img->floppy_drive_seek( -1 );
+void mc6843_device::ready_callback(floppy_image_device *floppy, int state)
+{
+ if(state) {
+ live_sync();
+ run(false, true, false);
}
+}
- LOG( "%f mc6843_finish_STZ: actual=%i\n", machine().time().as_double(), img->floppy_drive_get_current_track() );
+TIMER_CALLBACK_MEMBER(mc6843_device::update_tick)
+{
+ live_sync();
+ run(true, false, false);
+}
- /* update state */
- m_CTAR = 0;
- m_GCR = 0;
- m_SAR = 0;
- m_STRB |= img->floppy_tk00_r() << 4;
+void mc6843_device::command_start()
+{
+ assert(m_state == S_IDLE);
+ switch(m_cmr & 0xf) {
+
+ case C_STZ:
+ logerror("Seek to track 0\n");
+ if(m_floppy)
+ m_floppy->dir_w(1);
+ m_stra |= SA_BUSY;
+ m_step_count = 82;
+ m_state = S_STZ_STEP;
+ break;
- cmd_end( );
-}
+ case C_SEK:
+ logerror("Seek from track %d to %d\n", m_ctar, m_gcr);
+ if(m_gcr > m_ctar) {
+ if(m_floppy)
+ m_floppy->dir_w(0);
+ m_step_count = m_gcr - m_ctar;
+ } else {
+ if(m_floppy)
+ m_floppy->dir_w(1);
+ m_step_count = m_ctar - m_gcr;
+ }
+ m_stra |= SA_BUSY;
+ if(!m_step_count) {
+ m_state = S_SEEK_HEAD_SETTLING;
+ delay(4096 * (m_sur & 15));
+ } else
+ m_state = S_SEEK_STEP;
+ break;
+ case C_SSR: case C_RCR: case C_SSW: case C_SWD: case C_MSR: case C_MSW:
+ m_stra |= SA_BUSY;
+ m_stra &= ~(SA_DDM|SA_TNEQ);
+ m_strb &= ~SB_DMERR;
+ if(m_strb == 0)
+ m_isr &= 0x7;
+ m_state = S_SRW_WAIT_READY;
+ break;
+ case C_FFW:
+ m_stra |= SA_BUSY;
+ m_state = S_FFW_WAIT_READY;
+ m_dor_needed = true;
+ break;
-/* Seek bottom half */
-void mc6843_device::finish_SEK( )
-{
- legacy_floppy_image_device* img = floppy_image( );
+ case 0x0:
+ case 0x1:
+ case 0x8:
+ case 0x9:
+ case 0xe:
+ case 0xf:
+ break;
- /* seek to track */
- // TODO: not sure how CTAR bit 7 is handled here, but this is the safest approach for now
- img->floppy_drive_seek( m_GCR - (m_CTAR & 0x7F) );
+ default:
+ fatalerror("Unsupported command\n");
+ }
- LOG( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", machine().time().as_double(), (m_CTAR & 0x7F), m_GCR, img->floppy_drive_get_current_track() );
+ run(false, false, false);
+}
- /* update state */
- m_CTAR = m_GCR;
- m_SAR = 0;
- cmd_end( );
+void mc6843_device::delay(int cycles)
+{
+ // A delay of zero freezes the fdc, it's expected
+ if(cycles) {
+ m_timer->adjust(attotime::from_ticks(cycles, clock()));
+ }
}
+bool mc6843_device::is_ready() const
+{
+ return m_force_ready || (m_floppy && !m_floppy->ready_r());
+}
-/* preamble to all sector read / write commands, returns 1 if found */
-int mc6843_device::address_search( chrn_id* id )
+void mc6843_device::run(bool timeout, bool ready, bool index)
{
- legacy_floppy_image_device* img = floppy_image( );
- int r = 0;
-
- while ( 1 )
- {
- if ( ( ! img->floppy_drive_get_next_id( m_side, id ) ) || ( id->flags & ID_FLAG_CRC_ERROR_IN_ID_FIELD ) || ( id->N != 0 ) )
- {
- /* read address error */
- LOG( "%f mc6843_address_search: get_next_id failed\n", machine().time().as_double() );
- m_STRB |= 0x0a; /* set CRC error & Sector Address Undetected */
- cmd_end( );
- return 0;
+ for(;;) {
+ if(m_cur_live.state != L_IDLE) {
+ live_run();
+ if(m_cur_live.state != L_IDLE)
+ return;
}
- if ( id->C != m_LTAR )
- {
- /* track mismatch */
- LOG( "%f mc6843_address_search: track mismatch: logical=%i real=%i\n", machine().time().as_double(), m_LTAR, id->C );
- m_data[0] = id->C; /* make the track number available to the CPU */
- m_STRA |= 0x20; /* set Track Not Equal */
- cmd_end( );
- return 0;
- }
+ switch(m_state) {
+ case S_IDLE:
+ return;
- if ( id->R == m_SAR )
- {
- /* found! */
- LOG( "%f mc6843_address_search: sector %i found on track %i\n", machine().time().as_double(), id->R, id->C );
- if ( ! (m_CMR & 0x20) )
- {
- m_ISR |= 0x04; /* if no DMA, set Status Sense */
+ case S_STZ_STEP:
+ if(m_floppy && !m_floppy->trk00_r()) {
+ m_floppy->stp_w(0);
+ m_floppy->stp_w(1);
}
- return 1;
- }
-
- if ( img->floppy_drive_get_flag_state( FLOPPY_DRIVE_INDEX ) )
- {
- r++;
- if ( r >= 4 )
- {
- /* time-out after 3 full revolutions */
- LOG( "%f mc6843_address_search: no sector %i found after 3 revolutions\n", machine().time().as_double(), m_SAR );
- m_STRB |= 0x08; /* set Sector Address Undetected */
- cmd_end( );
- return 0;
+ m_step_count --;
+ m_state = S_STZ_STEP_WAIT;
+ delay(1024 * (m_sur >> 4));
+ return;
+
+ case S_STZ_STEP_WAIT:
+ if(!timeout)
+ return;
+ if(m_step_count)
+ m_state = S_STZ_STEP;
+ else {
+ m_ctar = m_gcr = 0;
+ m_state = S_STZ_HEAD_SETTLING;
+ delay(4096 * (m_sur & 15));
+ return;
}
- }
- }
+ break;
- //return 0; /* unreachable */
-}
+ case S_STZ_HEAD_SETTLING:
+ if(!timeout)
+ return;
+ m_head_loaded = true;
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_SCE);
+ return;
+
+ case S_SEEK_STEP:
+ if(m_floppy) {
+ m_floppy->stp_w(0);
+ m_floppy->stp_w(1);
+ }
+ m_step_count --;
+ m_state = S_SEEK_STEP_WAIT;
+ delay(1024 * (m_sur >> 4));
+ return;
+
+ case S_SEEK_STEP_WAIT:
+ if(!timeout)
+ return;
+ if(m_step_count)
+ m_state = S_SEEK_STEP;
+ else {
+ m_ctar = m_gcr;
+ m_state = S_SEEK_HEAD_SETTLING;
+ delay(4096 * (m_sur & 15));
+ return;
+ }
+ break;
+ case S_SEEK_HEAD_SETTLING:
+ if(!timeout)
+ return;
+ m_head_loaded = true;
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_SCE);
+ return;
+
+ case S_SRW_WAIT_READY:
+ if(!is_ready())
+ return;
+ if(!m_head_loaded) {
+ m_state = S_SRW_HEAD_SETTLING;
+ delay(4096 * (m_sur & 15));
+ return;
+ } else
+ m_state = S_SRW_START;
+ break;
+ case S_SRW_HEAD_SETTLING:
+ if(timeout) {
+ m_head_loaded = true;
+ m_state = S_SRW_START;
+ }
+ break;
-/* preamble specific to read commands (adds extra checks) */
-int mc6843_device::address_search_read( chrn_id* id )
-{
- if ( ! address_search( id ) )
- return 0;
+ case S_SRW_START:
+ m_idam_turns = 3;
+ live_start(L_IDAM_SEARCH);
+ return;
+
+ case S_FFW_WAIT_READY:
+ if(!is_ready())
+ return;
+ if(!m_head_loaded) {
+ m_state = S_FFW_HEAD_SETTLING;
+ delay(4096 * (m_sur & 15));
+ return;
+ } else
+ m_state = S_FFW_START;
+ break;
- if ( id->flags & ID_FLAG_CRC_ERROR_IN_DATA_FIELD )
- {
- LOG( "%f mc6843_address_search_read: data CRC error\n", machine().time().as_double() );
- m_STRB |= 0x06; /* set CRC error & Data Mark Undetected */
- cmd_end( );
- return 0;
- }
+ case S_FFW_HEAD_SETTLING:
+ if(timeout) {
+ m_head_loaded = true;
+ m_state = S_FFW_START;
+ }
+ break;
- if ( id->flags & ID_FLAG_DELETED_DATA )
- {
- LOG( "%f mc6843_address_search_read: deleted data\n", machine().time().as_double() );
- m_STRA |= 0x02; /* set Delete Data Mark Detected */
+ case S_FFW_START:
+ live_start(L_FFW_BYTE);
+ return;
+
+ case S_IDAM_BAD_TRACK:
+ m_dir = m_cur_live.data_reg;
+ m_stra |= SA_TNEQ;
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_RWCE);
+ return;
+
+ case S_IDAM_BAD_CRC:
+ m_strb |= SB_CRC | SB_SAERR;
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_RWCE | I_STRB);
+ return;
+
+ case S_IDAM_FOUND:
+ if(m_cmr & 0x20)
+ isr_raise(I_SSR);
+ if((m_cmr & 0xf) == C_SSR || (m_cmr & 0xf) == C_MSR || (m_cmr & 0xf) == C_RCR)
+ live_start(L_DAM_SEARCH);
+
+ else {
+ m_dor_needed = true;
+ live_start(L_DAM_WAIT);
+ }
+ return;
+
+ case S_IDAM_NOT_FOUND:
+ m_stra &= ~SA_BUSY;
+ m_strb |= SB_SAERR;
+ m_state = S_IDLE;
+ isr_raise(I_RWCE | I_STRB);
+ logerror("not found\n");
+ return;
+
+ case S_DAM_NOT_FOUND:
+ m_strb |= SB_DMERR;
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_RWCE | I_STRB);
+ return;
+
+ case S_DAM_BAD_CRC:
+ m_strb |= SB_CRC;
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_RWCE | I_STRB);
+ return;
+
+ case S_DAM_DONE:
+ m_dor_needed = false;
+ if((m_cmr & 0xf) == C_MSR || (m_cmr & 0xf) == C_MSW) {
+ m_sar = (m_sar + 1) & 0x1f;
+ m_gcr = (m_gcr - 1) & 0x7f;
+ if(m_gcr != 0x7f) {
+ m_state = S_SRW_START;
+ break;
+ }
+ }
+ m_stra &= ~SA_BUSY;
+ m_state = S_IDLE;
+ isr_raise(I_RWCE);
+ return;
+ }
}
-
- return 1;
}
-
-
-
-/* Read CRC bottom half */
-void mc6843_device::finish_RCR( )
+void mc6843_device::live_start(int state, bool start_writing)
{
- chrn_id id;
- if ( ! address_search_read( &id ) )
- return;
- cmd_end( );
+ m_cur_live.tm = machine().time();
+ m_cur_live.state = state;
+ m_cur_live.next_state = -1;
+ m_cur_live.shift_reg = 0;
+ m_cur_live.crc = 0xffff;
+ m_cur_live.bit_counter = 0;
+ m_cur_live.data_separator_phase = false;
+ m_cur_live.data_reg = 0;
+
+ m_cur_live.pll.reset(m_cur_live.tm);
+ m_cur_live.pll.set_clock(attotime::from_ticks(2, clock()));
+ if(start_writing)
+ m_cur_live.pll.start_writing(machine().time());
+
+ m_checkpoint_live = m_cur_live;
+
+ live_run();
}
-
-
-/* Single / Multiple Sector Read bottom half */
-void mc6843_device::cont_SR( )
+void mc6843_device::checkpoint()
{
- chrn_id id;
- legacy_floppy_image_device* img = floppy_image( );
-
- /* sector seek */
- if ( ! address_search_read( &id ) )
- return;
-
- /* sector read */
- img->floppy_drive_read_sector_data( m_side, id.data_id, m_data, 128 );
- m_data_idx = 0;
- m_data_size = 128;
- m_STRA |= 0x01; /* set Data Transfer Request */
- status_update( );
+ m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
+ m_checkpoint_live = m_cur_live;
}
-void mc6843_device::finish_SR( )
+void mc6843_device::rollback()
{
- m_crc_wait = 0;
- cmd_end( );
+ m_cur_live = m_checkpoint_live;
}
-/* Single / Multiple Sector Write bottom half */
-void mc6843_device::cont_SW( )
+void mc6843_device::live_delay(int state)
{
- chrn_id id;
-
- /* sector seek */
- if ( ! address_search( &id ) )
- return;
-
- /* setup sector write buffer */
- m_data_idx = 0;
- m_data_size = 128;
- m_STRA |= 0x01; /* set Data Transfer Request */
- m_data_id = id.data_id; /* for subsequent write sector command */
- status_update( );
+ m_cur_live.next_state = state;
+ m_timer->adjust(m_cur_live.tm - machine().time());
}
-
-
-/* bottom halves, called to continue / finish a command after some delay */
-void mc6843_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void mc6843_device::live_sync()
{
- switch (id)
- {
- case TIMER_CONT:
- {
- int cmd = m_CMR & 0x0f;
-
- LOG( "%f mc6843_cont: timer called for cmd=%s(%i)\n", machine().time().as_double(), mc6843_cmd[cmd], cmd );
-
- m_timer_cont->adjust( attotime::never );
-
- switch ( cmd )
- {
- case CMD_STZ: finish_STZ( ); break;
- case CMD_SEK: finish_SEK( ); break;
- case CMD_SSR:
- case CMD_MSR:
- if ( m_crc_wait )
- finish_SR( );
- else
- cont_SR( );
- break;
- case CMD_SSW: cont_SW( ); break;
- case CMD_RCR: finish_RCR( ); break;
- case CMD_SWD: cont_SW( ); break;
- case CMD_MSW: cont_SW( ); break;
- }
+ if(m_cur_live.state != L_IDLE && !m_cur_live.tm.is_never()) {
+ if(m_cur_live.tm > machine().time()) {
+ if(0)
+ logerror("%s: Rolling back and replaying (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
+ rollback();
+ live_run(machine().time());
+ m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
+ } else {
+ if(0)
+ logerror("%s: Committing (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
+ m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
+ if(m_cur_live.next_state != -1) {
+ m_cur_live.state = m_cur_live.next_state;
+ m_cur_live.next_state = -1;
}
- break;
-
- default:
- break;
+ if(m_cur_live.state == L_IDLE) {
+ m_cur_live.pll.stop_writing(m_floppy, m_cur_live.tm);
+ m_cur_live.tm = attotime::never;
+ }
+ }
+ m_cur_live.next_state = -1;
+ checkpoint();
}
}
+void mc6843_device::live_abort()
+{
+ if(!m_cur_live.tm.is_never() && m_cur_live.tm > machine().time()) {
+ rollback();
+ live_run(machine().time());
+ }
+ m_cur_live.pll.stop_writing(m_floppy, m_cur_live.tm);
+ m_cur_live.tm = attotime::never;
+ m_cur_live.state = L_IDLE;
+ m_cur_live.next_state = -1;
+}
-/************************** CPU interface ****************************/
-
-
+bool mc6843_device::read_one_bit(const attotime &limit)
+{
+ int bit = m_cur_live.pll.get_next_bit(m_cur_live.tm, m_floppy, limit);
+ if(bit < 0)
+ return true;
+ m_cur_live.shift_reg = (m_cur_live.shift_reg << 1) | bit;
+ m_cur_live.bit_counter++;
+ if(m_cur_live.data_separator_phase) {
+ m_cur_live.data_reg = (m_cur_live.data_reg << 1) | bit;
+ if((m_cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ m_cur_live.crc = (m_cur_live.crc << 1) ^ 0x1021;
+ else
+ m_cur_live.crc = m_cur_live.crc << 1;
+ }
+ m_cur_live.data_separator_phase = !m_cur_live.data_separator_phase;
+ return false;
+}
-uint8_t mc6843_device::read(offs_t offset)
+bool mc6843_device::write_one_bit(const attotime &limit)
{
- uint8_t data = 0;
+ bool bit = m_cur_live.shift_reg & 0x8000;
+ if(m_cur_live.pll.write_next_bit(bit, m_cur_live.tm, m_floppy, limit))
+ return true;
+ if(m_cur_live.bit_counter & 1) {
+ if((m_cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ m_cur_live.crc = (m_cur_live.crc << 1) ^ 0x1021;
+ else
+ m_cur_live.crc = m_cur_live.crc << 1;
+ }
+ m_cur_live.shift_reg = m_cur_live.shift_reg << 1;
+ m_cur_live.bit_counter--;
+ return false;
+}
- switch ( offset ) {
- case 0: /* Data Input Register (DIR) */
- {
- int cmd = m_CMR & 0x0f;
+void mc6843_device::live_run(attotime limit)
+{
+ if(m_cur_live.state == L_IDLE || m_cur_live.next_state != -1)
+ return;
- if (machine().side_effects_disabled())
- {
- data = m_data[0];
- break;
+ if(limit == attotime::never) {
+ if(m_floppy)
+ limit = m_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);
+ m_timer->adjust(attotime::from_msec(1));
}
+ }
- LOG( "%f %s mc6843_r: data input cmd=%s(%i), pos=%i/%i, GCR=%i, ",
- machine().time().as_double(), machine().describe_context(),
- mc6843_cmd[cmd], cmd, m_data_idx,
- m_data_size, m_GCR );
-
- if ( cmd == CMD_SSR || cmd == CMD_MSR )
- {
- /* sector read */
- assert( m_data_size > 0 );
- assert( m_data_idx < m_data_size );
- assert( m_data_idx < sizeof(m_data) );
- data = m_data[ m_data_idx ];
- m_data_idx++;
-
- if ( m_data_idx >= m_data_size )
- {
- /* end of sector read */
-
- m_STRA &= ~0x01; /* clear Data Transfer Request */
-
- if ( cmd == CMD_MSR )
- {
- /* schedule next sector in multiple sector read */
- m_GCR--;
- m_SAR++;
- if ( m_GCR == 0xff )
- {
- m_crc_wait = 1;
- m_timer_cont->adjust( DELAY_CRC );
- }
- else if ( m_SAR > 26 )
-
- {
- m_STRB |= 0x08; /* set Sector Address Undetected */
- m_crc_wait = 1;
- m_timer_cont->adjust( DELAY_CRC );
- }
- else
- {
- m_timer_cont->adjust( DELAY_ADDR );
- }
- }
- else
- {
- m_crc_wait = 1;
- m_timer_cont->adjust( DELAY_CRC );
- }
+ for(;;) {
+ switch(m_cur_live.state) {
+ case L_IDAM_SEARCH:
+ if(read_one_bit(limit))
+ return;
+
+ if(0)
+ logerror("%s: shift = %04x data=%02x c=%d\n", m_cur_live.tm.to_string(), m_cur_live.shift_reg,
+ (m_cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
+ (m_cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
+ (m_cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
+ (m_cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
+ (m_cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
+ (m_cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
+ (m_cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
+ (m_cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ m_cur_live.bit_counter);
+
+ if(m_cur_live.shift_reg == 0xf57e) {
+ m_cur_live.crc = 0xef21;
+ m_cur_live.data_separator_phase = false;
+ m_cur_live.bit_counter = 0;
+ m_cur_live.state = L_IDAM_CHECK_TRACK;
}
- }
- else if ( cmd == 0 )
- {
- data = m_data[0];
- }
- else
- {
- /* XXX TODO: other read modes */
- data = m_data[0];
- logerror( "%s mc6843 read in unsupported command mode %i\n", machine().describe_context(), cmd );
- }
-
- LOG( "data=%02X\n", data );
+ break;
- break;
- }
+ case L_IDAM_CHECK_TRACK:
+ if(read_one_bit(limit))
+ return;
- case 1: /* Current-Track Address Register (CTAR) */
- data = m_CTAR;
- if (machine().side_effects_disabled())
- break;
- LOG( "%f %s mc6843_r: read CTAR %i (actual=%i)\n",
- machine().time().as_double(), machine().describe_context(), data,
- floppy_image()->floppy_drive_get_current_track());
- break;
+ if(m_cur_live.bit_counter == 16) {
+ logerror("%s IDAM track %d\n", m_cur_live.tm.to_string(), m_cur_live.data_reg);
+ if(m_cur_live.data_reg != m_ltar) {
+ m_state = S_IDAM_BAD_TRACK;
+ live_delay(L_IDLE);
+ return;
- case 2: /* Interrupt Status Register (ISR) */
- data = m_ISR;
- if (machine().side_effects_disabled())
+ } else
+ m_cur_live.state = L_IDAM_CHECK_SECTOR;
+ }
break;
- LOG( "%f %s mc6843_r: read ISR %02X: cmd=%scomplete settle=%scomplete sense-rq=%i STRB=%i\n",
- machine().time().as_double(), machine().describe_context(), data,
- (data & 1) ? "" : "not-" , (data & 2) ? "" : "not-",
- (data >> 2) & 1, (data >> 3) & 1 );
-
- /* reset */
- m_ISR &= 8; /* keep STRB */
- status_update( );
- break;
- case 3: /* Status Register A (STRA) */
- {
- /* update */
- legacy_floppy_image_device* img = floppy_image( );
- int flag = img->floppy_drive_get_flag_state( FLOPPY_DRIVE_READY);
- data = m_STRA & 0xa3;
- if ( flag & FLOPPY_DRIVE_READY )
- data |= 0x04;
+ case L_IDAM_CHECK_SECTOR:
+ if(read_one_bit(limit))
+ return;
- data |= !img->floppy_tk00_r() << 3;
- data |= !img->floppy_wpt_r() << 4;
+ if(m_cur_live.bit_counter == 48) {
+ logerror("%s IDAM sector %d\n", m_cur_live.tm.to_string(), m_cur_live.data_reg);
+ if(m_cur_live.data_reg != m_sar)
+ m_cur_live.state = L_IDAM_SEARCH;
+ else
+ m_cur_live.state = L_IDAM_CHECK_CRC;
+ }
+ break;
- if ( m_index_pulse )
- data |= 0x40;
+ case L_IDAM_CHECK_CRC:
+ if(read_one_bit(limit))
+ return;
- if (machine().side_effects_disabled())
+ if(m_cur_live.bit_counter == 96) {
+ logerror("IDAM crc remainder %04x\n", m_cur_live.crc);
+ if(m_cur_live.crc)
+ m_state = S_IDAM_BAD_CRC;
+ else
+ m_state = S_IDAM_FOUND;
+ live_delay(L_IDLE);
+ return;
+ }
break;
- m_STRA = data;
- LOG( "%f %s mc6843_r: read STRA %02X: data-rq=%i del-dta=%i ready=%i t0=%i wp=%i trk-dif=%i idx=%i busy=%i\n",
- machine().time().as_double(), machine().describe_context(), data,
- data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1,
- (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 );
- break;
- }
-
- case 4: /* Status Register B (STRB) */
- data = m_STRB;
- if (machine().side_effects_disabled())
+ case L_DAM_SEARCH:
+ if(read_one_bit(limit))
+ return;
+
+ if(m_cur_live.shift_reg == 0xf56a || m_cur_live.shift_reg == 0xf56f) {
+ m_cur_live.data_separator_phase = false;
+ m_cur_live.bit_counter = 0;
+ logerror("DAM mark %02x\n", m_cur_live.data_reg);
+ if(m_cur_live.shift_reg == 0xf56f) {
+ logerror("DAM found\n");
+ m_cur_live.crc = 0xbf84;
+ m_cur_live.state = L_DAM_READ;
+ } else {
+ logerror("DDAM found\n");
+ m_cur_live.crc = 0x8fe7;
+ live_delay(L_DAM_DELETED);
+ return;
+ }
+ }
break;
- LOG( "%f %s mc6843_r: read STRB %02X: data-err=%i CRC-err=%i dta--mrk-err=%i sect-mrk-err=%i seek-err=%i fi=%i wr-err=%i hard-err=%i\n",
- machine().time().as_double(), machine().describe_context(), data,
- data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1,
- (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 );
-
- /* (partial) reset */
- m_STRB &= ~0xfb;
- status_update( );
- break;
- case 7: /* Logical-Track Address Register (LTAR) */
- data = m_LTAR;
- if (machine().side_effects_disabled())
+ case L_DAM_DELETED:
+ m_stra |= SA_DDM;
+ m_cur_live.state = L_DAM_READ;
break;
- LOG( "%f %s mc6843_r: read LTAR %i (actual=%i)\n",
- machine().time().as_double(), machine().describe_context(), data,
- floppy_image()->floppy_drive_get_current_track());
- break;
- default:
- logerror( "%s mc6843 invalid read offset %i\n", machine().describe_context(), offset );
- }
+ case L_DAM_READ:
+ if(read_one_bit(limit))
+ return;
- return data;
-}
-
-void mc6843_device::write(offs_t offset, uint8_t data)
-{
- switch ( offset ) {
- case 0: /* Data Output Register (DOR) */
- {
- int cmd = m_CMR & 0x0f;
- int FWF = (m_CMR >> 4) & 1;
-
- LOG( "%f %s mc6843_w: data output cmd=%s(%i), pos=%i/%i, GCR=%i, data=%02X\n",
- machine().time().as_double(), machine().describe_context(),
- mc6843_cmd[cmd], cmd, m_data_idx,
- m_data_size, m_GCR, data );
-
- if ( cmd == CMD_SSW || cmd == CMD_MSW || cmd == CMD_SWD )
- {
- /* sector write */
- assert( m_data_size > 0 );
- assert( m_data_idx < m_data_size );
- assert( m_data_idx < sizeof(m_data) );
- m_data[ m_data_idx ] = data;
- m_data_idx++;
- if ( m_data_idx >= m_data_size )
- {
- /* end of sector write */
- legacy_floppy_image_device* img = floppy_image( );
-
- LOG( "%f %s mc6843_w: write sector %i\n", machine().time().as_double(), machine().describe_context(), m_data_id );
-
- img->floppy_drive_write_sector_data(
- m_side, m_data_id,
- m_data, m_data_size,
- (cmd == CMD_SWD) ? ID_FLAG_DELETED_DATA : 0 );
-
- m_STRA &= ~0x01; /* clear Data Transfer Request */
-
- if ( cmd == CMD_MSW )
- {
- m_GCR--;
- m_SAR++;
- if ( m_GCR == 0xff )
- {
- cmd_end( );
- }
- else if ( m_SAR > 26 )
-
- {
- m_STRB |= 0x08; /* set Sector Address Undetected */
- cmd_end( );
- }
- else
- {
- m_timer_cont->adjust( DELAY_ADDR );
- }
- }
- else
- {
- cmd_end( );
- }
+ if(!(m_cur_live.bit_counter & 0xf)) {
+ live_delay(L_DAM_READ_BYTE);
+ return;
}
- }
- else if ( (cmd == CMD_FFW) && FWF )
- {
- /* assume we are formatting */
- uint8_t nibble;
- nibble =
- (data & 0x01) |
- ((data & 0x04) >> 1 )|
- ((data & 0x10) >> 2 )|
- ((data & 0x40) >> 3 );
-
- assert( m_data_idx < sizeof(m_data) );
-
- m_data[m_data_idx / 2] =
- (m_data[m_data_idx / 2] << 4) | nibble;
-
- if ( (m_data_idx == 0) && (m_data[0] == 0xfe ) )
- {
- /* address mark detected */
- m_data_idx = 2;
- }
- else if ( m_data_idx == 9 )
- {
- /* address id field complete */
- if ( (m_data[2] == 0) && (m_data[4] == 0) )
- {
- /* valid address id field */
- legacy_floppy_image_device* img = floppy_image( );
- uint8_t track = m_data[1];
- uint8_t sector = m_data[3];
- uint8_t filler = 0xe5; /* standard Thomson filler */
- LOG( "%f %s mc6843_w: address id detected track=%i sector=%i\n", machine().time().as_double(), machine().describe_context(), track, sector);
- img->floppy_drive_format_sector( m_side, sector, track, 0, sector, 0, filler );
- m_data_idx = 0;
+ break;
+
+ case L_DAM_READ_BYTE: {
+ int byte = m_cur_live.bit_counter >> 4;
+ logerror("byte %02x = %02x crc %04x\n", byte, m_cur_live.data_reg, m_cur_live.crc);
+ if(byte <= 128) {
+ if((m_cmr & 0xf) != C_RCR) {
+ if(m_dir_loaded)
+ m_strb |= SB_DTERR;
+ m_dir_loaded = true;
}
+ m_dir = m_cur_live.data_reg;
+ } else if(byte == 130) {
+ if(m_cur_live.crc)
+ m_state = S_DAM_BAD_CRC;
else
- {
- /* abort */
- m_data_idx = 0;
- }
- }
- else if ( m_data_idx > 0 )
- {
- /* accumulate address id field */
- m_data_idx++;
+ m_state = S_DAM_DONE;
+ m_cur_live.state = L_IDLE;
+ return;
}
- }
- else if ( cmd == 0 )
- {
- /* nothing */
- }
- else
- {
- /* XXX TODO: other write modes */
- logerror( "%s mc6843 write %02X in unsupported command mode %i (FWF=%i)\n", machine().describe_context(), data, cmd, FWF );
- }
- break;
- }
-
- case 1: /* Current-Track Address Register (CTAR) */
- m_CTAR = data;
- LOG( "%f %s mc6843_w: set CTAR to %i %02X (actual=%i) \n",
- machine().time().as_double(), machine().describe_context(), m_CTAR, data,
- floppy_image()->floppy_drive_get_current_track());
- break;
-
- case 2: /* Command Register (CMR) */
- {
- int cmd = data & 15;
-
- LOG( "%f %s mc6843_w: set CMR to $%02X: cmd=%s(%i) FWF=%i DMA=%i ISR3-intr=%i fun-intr=%i\n",
- machine().time().as_double(), machine().describe_context(),
- data, mc6843_cmd[cmd], cmd, (data >> 4) & 1, (data >> 5) & 1,
- (data >> 6) & 1, (data >> 7) & 1 );
-
- /* sanitize state */
- m_STRA &= ~0x81; /* clear Busy & Data Transfer Request */
- m_data_idx = 0;
- m_data_size = 0;
-
- /* commands are initiated by updating some flags and scheduling
- a bottom-half (mc6843_cont) after some delay */
-
- switch (cmd)
- {
- case CMD_SSW:
- case CMD_SSR:
- case CMD_SWD:
- case CMD_RCR:
- case CMD_MSR:
- case CMD_MSW:
- m_STRA |= 0x80; /* set Busy */
- m_STRA &= ~0x22; /* clear Track Not Equal & Delete Data Mark Detected */
- m_STRB &= ~0x04; /* clear Data Mark Undetected */
- m_timer_cont->adjust( DELAY_ADDR );
- break;
- case CMD_STZ:
- case CMD_SEK:
- m_STRA |= 0x80; /* set Busy */
- m_timer_cont->adjust( DELAY_SEEK );
- break;
- case CMD_FFW:
- case CMD_FFR:
- m_data_idx = 0;
- m_STRA |= 0x01; /* set Data Transfer Request */
+ m_cur_live.state = L_DAM_READ;
break;
}
- m_CMR = data;
- status_update( );
- break;
- }
+ case L_DAM_WAIT:
+ if(read_one_bit(limit))
+ return;
- case 3: /* Set-Up Register (SUR) */
- m_SUR = data;
+ if(m_cur_live.bit_counter == 11*16) {
+ m_cur_live.bit_counter = (6+1+128+2)*16;
+ live_delay(L_DAM_WRITE_BYTE);
+ return;
+ }
+ break;
- /* assume CLK freq = 1MHz (IBM 3740 compatibility) */
- LOG( "%f %s mc6843_w: set SUR to $%02X: head settling time=%fms, track-to-track seek time=%f\n",
- machine().time().as_double(), machine().describe_context(),
- data, 4.096 * (data & 15), 1.024 * ((data >> 4) & 15) );
- break;
+ case L_DAM_WRITE:
+ if(write_one_bit(limit))
+ return;
+ if(!(m_cur_live.bit_counter & 0xf)) {
+ live_delay(L_DAM_WRITE_BYTE);
+ return;
+ }
+ break;
- case 4: /* Sector Address Register (SAR) */
- m_SAR = data & 0x1f;
- LOG( "%f %s mc6843_w: set SAR to %i (%02X)\n", machine().time().as_double(), machine().describe_context(), m_SAR, data );
- break;
+ case L_DAM_WRITE_BYTE: {
+ int byte = (6+1+128+2) - (m_cur_live.bit_counter >> 4);
+ if(!byte) {
+ m_cur_live.pll.start_writing(m_cur_live.tm);
+ m_cur_live.shift_reg = 0xaaaa;
- case 5: /* General Count Register (GCR) */
- m_GCR = data & 0x7f;
- LOG( "%f %s mc6843_w: set GCR to %i (%02X)\n", machine().time().as_double(), machine().describe_context(), m_GCR, data );
- break;
+ } else if(byte <= 5) {
+ m_cur_live.shift_reg = 0xaaaa;
- case 6: /* CRC Control Register (CCR) */
- m_CCR = data & 3;
- LOG( "%f %s mc6843_w: set CCR to %02X: CRC=%s shift=%i\n",
- machine().time().as_double(), machine().describe_context(), data,
- (data & 1) ? "enabled" : "disabled", (data >> 1) & 1 );
- break;
+ } else if(byte <= 6) {
+ m_cur_live.crc = 0xffff;
+ if((m_cmr & 0xf) == C_SWD)
+ m_cur_live.shift_reg = 0xf56a;
+ else
+ m_cur_live.shift_reg = 0xf56f;
+
+ } else if(byte <= 134) {
+ if(!m_dor_loaded)
+ m_strb |= SB_DTERR;
+ m_dor_loaded = false;
+ if(byte == 128)
+ m_dor_needed = false;
+ m_cur_live.shift_reg = 0xaaaa |
+ (m_dor & 0x80 ? 1<<14 : 0) |
+ (m_dor & 0x40 ? 1<<12 : 0) |
+ (m_dor & 0x20 ? 1<<10 : 0) |
+ (m_dor & 0x10 ? 1<< 8 : 0) |
+ (m_dor & 0x08 ? 1<< 6 : 0) |
+ (m_dor & 0x04 ? 1<< 4 : 0) |
+ (m_dor & 0x02 ? 1<< 2 : 0) |
+ (m_dor & 0x01 ? 1 : 0);
+
+ } else if(byte <= 136) {
+ m_cur_live.shift_reg = 0xaaaa |
+ (m_cur_live.crc & 0x8000 ? 1<<14 : 0) |
+ (m_cur_live.crc & 0x4000 ? 1<<12 : 0) |
+ (m_cur_live.crc & 0x2000 ? 1<<10 : 0) |
+ (m_cur_live.crc & 0x1000 ? 1<< 8 : 0) |
+ (m_cur_live.crc & 0x0800 ? 1<< 6 : 0) |
+ (m_cur_live.crc & 0x0400 ? 1<< 4 : 0) |
+ (m_cur_live.crc & 0x0200 ? 1<< 2 : 0) |
+ (m_cur_live.crc & 0x0100 ? 1 : 0);
+
+ } else if(byte <= 137) {
+ m_cur_live.shift_reg = 0xffff;
+
+ } else {
+ m_state = S_DAM_DONE;
+ m_cur_live.state = L_IDLE;
+ m_cur_live.pll.stop_writing(m_floppy, m_cur_live.tm);
+ return;
+ }
+ m_cur_live.state = L_DAM_WRITE;
+ break;
+ }
- case 7: /* Logical-Track Address Register (LTAR) */
- m_LTAR = data & 0x7f;
- LOG( "%f %s mc6843_w: set LTAR to %i %02X (actual=%i)\n",
- machine().time().as_double(), machine().describe_context(), m_LTAR, data,
- floppy_image()->floppy_drive_get_current_track());
- break;
+ case L_FFW_BYTE:
+ if(!m_dor_loaded)
+ m_strb |= SB_DTERR;
+ m_dor_loaded = false;
+ logerror("write %02x\n", m_dor);
+ if(m_cmr & 0x10) {
+ m_cur_live.shift_reg = m_dor << 8;
+ m_cur_live.bit_counter = 8;
+
+ } else {
+ m_cur_live.shift_reg = 0xaaaa |
+ (m_dor & 0x80 ? 1<<14 : 0) |
+ (m_dor & 0x40 ? 1<<12 : 0) |
+ (m_dor & 0x20 ? 1<<10 : 0) |
+ (m_dor & 0x10 ? 1<< 8 : 0) |
+ (m_dor & 0x08 ? 1<< 6 : 0) |
+ (m_dor & 0x04 ? 1<< 4 : 0) |
+ (m_dor & 0x02 ? 1<< 2 : 0) |
+ (m_dor & 0x01 ? 1 : 0);
+ m_cur_live.bit_counter = 16;
+ }
+ m_cur_live.state = L_FFW_WRITE;
+ break;
- default:
- logerror( "%s mc6843 invalid write offset %i (data=$%02X)\n", machine().describe_context(), offset, data );
+ case L_FFW_WRITE:
+ if(write_one_bit(limit))
+ return;
+ if(m_cur_live.bit_counter == 0) {
+ live_delay(L_FFW_BYTE);
+ return;
+ }
+ break;
+ }
}
}
diff --git a/src/devices/machine/mc6843.h b/src/devices/machine/mc6843.h
index 488b4671026..86a92757279 100644
--- a/src/devices/machine/mc6843.h
+++ b/src/devices/machine/mc6843.h
@@ -1,97 +1,196 @@
// license:BSD-3-Clause
-// copyright-holders:Antoine Mine
-/**********************************************************************
+// copyright-holders:Olivier Galibert
- Copyright (C) Antoine Mine' 2007
-
- Motorola 6843 Floppy Disk Controller emulation.
-
-**********************************************************************/
+// Motorola 6843 floppy drive controller
+//
+// The Hitachi HD46503S, HD6843 and HD68A43 seem identical
#ifndef MAME_MACHINE_MC6843_H
#define MAME_MACHINE_MC6843_H
#pragma once
-#include "imagedev/flopdrv.h"
-
+#include "imagedev/floppy.h"
+#include "fdc_pll.h"
class mc6843_device : public device_t
{
public:
mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- template<int Id, typename T> void set_floppy_drive(T &&tag) { m_floppy[Id].set_tag(std::forward<T>(tag)); }
- template<typename T, typename U, typename V, typename W> void set_floppy_drives(T &&tag0, U &&tag1, V &&tag2, W &&tag3)
- {
- m_floppy[0].set_tag(std::forward<T>(tag0));
- m_floppy[1].set_tag(std::forward<U>(tag1));
- m_floppy[2].set_tag(std::forward<V>(tag2));
- m_floppy[3].set_tag(std::forward<W>(tag3));
- }
+ void force_ready() { m_force_ready = true; }
- auto irq() { return m_write_irq.bind(); }
+ auto irq() { return m_irq.bind(); }
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
+ void set_floppy(floppy_image_device *floppy);
- void set_drive(int drive);
- void set_side(int side);
- void set_index_pulse(int index_pulse);
+ void map(address_map &map);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_tick);
private:
- enum
- {
- TIMER_CONT
+ // Status flags
+ enum {
+ SA_BUSY = 0x80,
+ SA_IDX = 0x40,
+ SA_TNEQ = 0x20,
+ SA_WPT = 0x10,
+ SA_TRK0 = 0x08,
+ SA_RDY = 0x04,
+ SA_DDM = 0x02,
+ SA_DTR = 0x01,
+
+ SB_HERR = 0x80,
+ SB_WERR = 0x40,
+ SB_FI = 0x20,
+ SB_SERR = 0x10,
+ SB_SAERR = 0x08,
+ SB_DMERR = 0x04,
+ SB_CRC = 0x02,
+ SB_DTERR = 0x01,
+
+ I_STRB = 0x08,
+ I_SSR = 0x04,
+ I_SCE = 0x02,
+ I_RWCE = 0x01,
+
+ C_STZ = 0x2,
+ C_SEK = 0x3,
+ C_SSR = 0x4,
+ C_SSW = 0x5,
+ C_RCR = 0x6,
+ C_SWD = 0x7,
+ C_FFR = 0xa,
+ C_FFW = 0xb,
+ C_MSR = 0xc,
+ C_MSW = 0xd,
};
- optional_device_array<legacy_floppy_image_device, 4> m_floppy;
-
- devcb_write_line m_write_irq;
-
- /* registers */
- uint8_t m_CTAR; /* current track */
- uint8_t m_CMR; /* command */
- uint8_t m_ISR; /* interrupt status */
- uint8_t m_SUR; /* set-up */
- uint8_t m_STRA; /* status */
- uint8_t m_STRB; /* status */
- uint8_t m_SAR; /* sector address */
- uint8_t m_GCR; /* general count */
- uint8_t m_CCR; /* CRC control */
- uint8_t m_LTAR; /* logical address track (=track destination) */
-
- /* internal state */
- uint8_t m_drive;
- uint8_t m_side;
- uint8_t m_data[128]; /* sector buffer */
- uint32_t m_data_size; /* size of data */
- uint32_t m_data_idx; /* current read/write position in data */
- uint32_t m_data_id; /* chrd_id for sector write */
- uint8_t m_index_pulse;
- uint8_t m_crc_wait;
-
- /* trigger delayed actions (bottom halves) */
- emu_timer* m_timer_cont;
-
- legacy_floppy_image_device* floppy_image();
- void status_update();
- void cmd_end();
- void finish_STZ();
- void finish_SEK();
- int address_search(chrn_id* id);
- int address_search_read(chrn_id* id);
- void finish_RCR();
- void cont_SR();
- void finish_SR();
- void cont_SW();
+ enum {
+ S_IDLE,
+
+ S_STZ_STEP,
+ S_STZ_STEP_WAIT,
+ S_STZ_HEAD_SETTLING,
+
+ S_SEEK_STEP,
+ S_SEEK_STEP_WAIT,
+ S_SEEK_HEAD_SETTLING,
+
+ S_SRW_WAIT_READY,
+ S_SRW_HEAD_SETTLING,
+ S_SRW_START,
+
+ S_FFW_WAIT_READY,
+ S_FFW_HEAD_SETTLING,
+ S_FFW_START,
+
+ S_IDAM_BAD_TRACK,
+ S_IDAM_BAD_CRC,
+ S_IDAM_FOUND,
+ S_IDAM_NOT_FOUND,
+
+ S_DAM_NOT_FOUND,
+ S_DAM_BAD_CRC,
+ S_DAM_DONE,
+ };
+
+ enum {
+ L_IDLE,
+
+ L_IDAM_SEARCH,
+ L_IDAM_CHECK_TRACK,
+ L_IDAM_CHECK_SECTOR,
+ L_IDAM_CHECK_CRC,
+
+ L_DAM_SEARCH,
+ L_DAM_DELETED,
+ L_DAM_READ,
+ L_DAM_READ_BYTE,
+
+ L_DAM_WAIT,
+ L_DAM_WRITE,
+ L_DAM_WRITE_BYTE,
+
+ L_FFW_BYTE,
+ L_FFW_WRITE,
+ };
+
+ struct live_info {
+ attotime tm;
+ fdc_pll_t pll;
+ int state, next_state;
+ u16 shift_reg;
+ u16 crc;
+ int bit_counter;
+ bool data_separator_phase, data_bit_context;
+ uint8_t data_reg;
+ };
+ devcb_write_line m_irq;
+ bool m_force_ready;
+
+ emu_timer *m_timer;
+ floppy_image_device *m_floppy;
+
+ live_info m_cur_live, m_checkpoint_live;
+
+ int m_state;
+
+ bool m_head_loaded, m_dir_loaded, m_dor_loaded, m_dor_needed;
+
+ u8 m_dir;
+ u8 m_dor;
+ u8 m_ctar;
+ u8 m_cmr;
+ u8 m_isr;
+ u8 m_sur;
+ u8 m_stra;
+ u8 m_sar;
+ u8 m_strb;
+ u8 m_gcr;
+ u8 m_ccr;
+ u8 m_ltar;
+
+ u8 m_step_count;
+ u8 m_idam_turns;
+
+ u8 dir_r();
+ void dor_w(u8 data);
+ u8 ctar_r();
+ void ctar_w(u8 data);
+ u8 isr_r();
+ void cmr_w(u8 data);
+ u8 stra_r();
+ void sur_w(u8 data);
+ u8 strb_r();
+ void sar_w(u8 data);
+ void gcr_w(u8 data);
+ void ccr_w(u8 data);
+ void ltar_w(u8 data);
+
+ void index_callback(floppy_image_device *floppy, int state);
+ void ready_callback(floppy_image_device *floppy, int state);
+
+ void command_start();
+ void run(bool timeout, bool ready, bool index);
+ void isr_raise(u8 flag);
+ void delay(int);
+ void live_start(int state, bool start_writing = false);
+ void checkpoint();
+ void rollback();
+ void live_delay(int state);
+ void live_sync();
+ void live_abort();
+ bool read_one_bit(const attotime &limit);
+ bool write_one_bit(const attotime &limit);
+ void live_run(attotime limit = attotime::never);
+ bool is_ready() const;
};
DECLARE_DEVICE_TYPE(MC6843, mc6843_device)
diff --git a/src/devices/machine/mc6844.cpp b/src/devices/machine/mc6844.cpp
index a88b497a271..1a3aca8d903 100644
--- a/src/devices/machine/mc6844.cpp
+++ b/src/devices/machine/mc6844.cpp
@@ -84,9 +84,9 @@ mc6844_device::mc6844_device(const machine_config &mconfig, const char *tag, dev
, m_out_txak_cb(*this)
, m_out_drq1_cb(*this)
, m_out_drq2_cb(*this)
- , m_in_memr_cb(*this)
+ , m_in_memr_cb(*this, 0)
, m_out_memw_cb(*this)
- , m_in_ior_cb(*this)
+ , m_in_ior_cb(*this, 0)
, m_out_iow_cb(*this)
, m_state(STATE_S0)
, m_icount(0)
@@ -94,22 +94,6 @@ mc6844_device::mc6844_device(const machine_config &mconfig, const char *tag, dev
}
//-------------------------------------------------
-// device_resolve_objects - device-specific setup
-//-------------------------------------------------
-void mc6844_device::device_resolve_objects()
-{
- m_out_int_cb.resolve_safe();
- m_out_txak_cb.resolve_safe();
- m_out_drq1_cb.resolve_safe();
- m_out_drq2_cb.resolve_safe();
- m_in_memr_cb.resolve_safe(0);
- m_out_memw_cb.resolve_safe();
-
- m_in_ior_cb.resolve_all_safe(0);
- m_out_iow_cb.resolve_all_safe();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
diff --git a/src/devices/machine/mc6844.h b/src/devices/machine/mc6844.h
index 242528454a6..7737d700164 100644
--- a/src/devices/machine/mc6844.h
+++ b/src/devices/machine/mc6844.h
@@ -63,14 +63,12 @@ public:
template <unsigned CH> auto in_ior_callback() { return m_in_ior_cb[CH].bind(); }
template <unsigned CH> auto out_iow_callback() { return m_out_iow_cb[CH].bind(); }
- template <unsigned CH> DECLARE_WRITE_LINE_MEMBER( dreq_w ) { dma_request(CH, state); }
+ template <unsigned CH> void dreq_w(int state) { dma_request(CH, state); }
- DECLARE_WRITE_LINE_MEMBER( dgrnt_w ){ m_dgrnt = state; trigger(1); }
+ void dgrnt_w(int state) { m_dgrnt = state; trigger(1); }
protected:
- // device-level overrides
- //virtual void device_validity_check(validity_checker &valid) const override;
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
virtual void execute_run() override;
diff --git a/src/devices/machine/mc6846.cpp b/src/devices/machine/mc6846.cpp
index 72b3f1added..26c42d8a5ec 100644
--- a/src/devices/machine/mc6846.cpp
+++ b/src/devices/machine/mc6846.cpp
@@ -33,8 +33,7 @@
#define PORT \
((m_pdr & m_ddr) | \
- ((!m_in_port_cb.isnull() ? m_in_port_cb( 0 ) : 0) & \
- ~m_ddr))
+ (m_in_port_cb(0) & ~m_ddr))
#define CTO \
((MODE == 0x30 || (m_tcr & 0x80)) ? m_cto : 0)
@@ -48,11 +47,11 @@ DEFINE_DEVICE_TYPE(MC6846, mc6846_device, "mc6846", "MC6846 Programmable Timer")
mc6846_device::mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, MC6846, tag, owner, clock),
- m_out_port_cb(*this),
- m_out_cp2_cb(*this),
- m_in_port_cb(*this),
- m_out_cto_cb(*this),
- m_irq_cb(*this)
+ m_out_port_cb(*this), // 8-bit output
+ m_out_cp2_cb(*this), // 1-bit output
+ m_in_port_cb(*this, 0), // CPU read from the outside through chip (8-bit input)
+ m_out_cto_cb(*this), // asynchronous timer output to output world (1-bit output)
+ m_irq_cb(*this) // timer interrupt
{
}
@@ -62,20 +61,8 @@ mc6846_device::mc6846_device(const machine_config &mconfig, const char *tag, dev
void mc6846_device::device_start()
{
- m_interval = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc6846_device::timer_expire), this));
- m_one_shot = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc6846_device::timer_one_shot), this));
-
- m_out_port_cb.resolve(); /* 8-bit output */
- m_out_cp2_cb.resolve(); /* 1-bit output */
-
- /* CPU read from the outside through chip */
- m_in_port_cb.resolve(); /* 8-bit input */
-
- /* asynchronous timer output to outside world */
- m_out_cto_cb.resolve(); /* 1-bit output */
-
- /* timer interrupt */
- m_irq_cb.resolve();
+ m_interval = timer_alloc(FUNC(mc6846_device::timer_expire), this);
+ m_one_shot = timer_alloc(FUNC(mc6846_device::timer_one_shot), this);
save_item(NAME(m_csr));
save_item(NAME(m_pcr));
@@ -155,14 +142,12 @@ inline void mc6846_device::update_irq()
if ( cif )
{
m_csr |= 0x80;
- if ( !m_irq_cb.isnull() )
- m_irq_cb( 1 );
+ m_irq_cb( 1 );
}
else
{
m_csr &= ~0x80;
- if ( !m_irq_cb.isnull() )
- m_irq_cb( 0 );
+ m_irq_cb( 0 );
}
}
@@ -176,8 +161,7 @@ inline void mc6846_device::update_cto()
LOG( "%f: mc6846 CTO set to %i\n", machine().time().as_double(), cto );
m_old_cto = cto;
}
- if ( !m_out_cto_cb.isnull() )
- m_out_cto_cb( cto );
+ m_out_cto_cb( cto );
}
@@ -395,8 +379,7 @@ void mc6846_device::write(offs_t offset, uint8_t data)
if (data & 0x10)
{
m_cp2_cpu = (data >> 3) & 1;
- if ( !m_out_cp2_cb.isnull() )
- m_out_cp2_cb( m_cp2_cpu );
+ m_out_cp2_cb( m_cp2_cpu );
}
else
logerror( "%s mc6846 acknowledge not implemented\n", machine().describe_context() );
@@ -408,8 +391,7 @@ void mc6846_device::write(offs_t offset, uint8_t data)
if ( ! (m_pcr & 0x80) )
{
m_ddr = data;
- if ( !m_out_port_cb.isnull() )
- m_out_port_cb( (offs_t) 0, m_pdr & m_ddr );
+ m_out_port_cb( (offs_t) 0, m_pdr & m_ddr );
}
break;
@@ -418,8 +400,7 @@ void mc6846_device::write(offs_t offset, uint8_t data)
if ( ! (m_pcr & 0x80) )
{
m_pdr = data;
- if ( !m_out_port_cb.isnull() )
- m_out_port_cb( (offs_t) 0, m_pdr & m_ddr );
+ m_out_port_cb( (offs_t) 0, m_pdr & m_ddr );
if ( m_csr1_to_be_cleared && (m_csr & 2) )
{
m_csr &= ~2;
diff --git a/src/devices/machine/mc6852.cpp b/src/devices/machine/mc6852.cpp
index 714e093aed3..af74f26516c 100644
--- a/src/devices/machine/mc6852.cpp
+++ b/src/devices/machine/mc6852.cpp
@@ -68,12 +68,6 @@ mc6852_device::mc6852_device(const machine_config &mconfig, const char *tag, dev
void mc6852_device::device_start()
{
- // resolve callbacks
- m_write_tx_data.resolve_safe();
- m_write_irq.resolve_safe();
- m_write_sm_dtr.resolve_safe();
- m_write_tuf.resolve_safe();
-
set_rcv_rate(m_rx_clock);
set_tra_rate(m_tx_clock);
diff --git a/src/devices/machine/mc6852.h b/src/devices/machine/mc6852.h
index 27e7ec9f962..6fb6cc512c7 100644
--- a/src/devices/machine/mc6852.h
+++ b/src/devices/machine/mc6852.h
@@ -55,14 +55,14 @@ public:
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( rx_data_w ) { device_serial_interface::rx_w(state); }
- DECLARE_WRITE_LINE_MEMBER( rx_clk_w ) { rx_clock_w(state); }
- DECLARE_WRITE_LINE_MEMBER( tx_clk_w ) { tx_clock_w(state); }
- DECLARE_WRITE_LINE_MEMBER( cts_w ) { m_cts = state; }
- DECLARE_WRITE_LINE_MEMBER( dcd_w ) { m_dcd = state; }
-
- DECLARE_READ_LINE_MEMBER( sm_dtr_r ) { return m_sm_dtr; }
- DECLARE_READ_LINE_MEMBER( tuf_r ) { return m_tuf; }
+ void rx_data_w(int state) { device_serial_interface::rx_w(state); }
+ void rx_clk_w(int state) { rx_clock_w(state); }
+ void tx_clk_w(int state) { tx_clock_w(state); }
+ void cts_w(int state) { m_cts = state; }
+ void dcd_w(int state) { m_dcd = state; }
+
+ int sm_dtr_r() { return m_sm_dtr; }
+ int tuf_r() { return m_tuf; }
// These are to allow integration of this driver with code
// controlling floppy disks.
diff --git a/src/devices/machine/mc6854.cpp b/src/devices/machine/mc6854.cpp
index ed5eb02b8b5..1c26764b2a6 100644
--- a/src/devices/machine/mc6854.cpp
+++ b/src/devices/machine/mc6854.cpp
@@ -33,9 +33,9 @@
#include "emu.h"
#include "mc6854.h"
-#define LOG_SETUP ( 1U << 1 )
-#define LOG_BITS ( 1U << 2 )
-#define LOG_IRQ ( 1U << 3 )
+#define LOG_SETUP (1U << 1)
+#define LOG_BITS (1U << 2)
+#define LOG_IRQ (1U << 3)
//#define VERBOSE (LOG_IRQ | LOG_BITS | LOG_GENERAL | LOG_SETUP)
//#define LOG_OUTPUT_STREAM std::cout
@@ -186,15 +186,9 @@ mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, dev
void mc6854_device::device_start()
{
- m_out_irq_cb.resolve_safe();
- m_out_rdsr_cb.resolve_safe();
- m_out_tdsr_cb.resolve_safe();
- m_out_txd_cb.resolve();
- m_out_frame_cb.resolve();
- m_out_rts_cb.resolve_safe();
- m_out_dtr_cb.resolve_safe();
+ m_out_frame_cb.resolve_safe();
- m_ttimer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc6854_device::tfifo_cb), this));
+ m_ttimer = timer_alloc(FUNC(mc6854_device::tfifo_cb), this);
save_item(NAME(m_cr1));
save_item(NAME(m_cr2));
@@ -273,11 +267,8 @@ void mc6854_device::send_bits( uint32_t data, int len, int zi )
m_tones = 0;
/* send bits */
- if ( !m_out_txd_cb.isnull() )
- {
- for ( i = 0; i < len; i++, data >>= 1 )
- m_out_txd_cb( data & 1 );
- }
+ for ( i = 0; i < len; i++, data >>= 1 )
+ m_out_txd_cb( data & 1 );
/* schedule when to ask the MC6854 for more bits */
expire = m_ttimer ->remaining( );
@@ -434,8 +425,7 @@ TIMER_CALLBACK_MEMBER(mc6854_device::tfifo_cb)
m_tstate = 0;
m_flen = 0;
- if ( !m_out_frame_cb.isnull() )
- m_out_frame_cb( m_frame, len );
+ m_out_frame_cb( m_frame, len );
}
}
@@ -583,7 +573,7 @@ uint8_t mc6854_device::rfifo_pop( )
}
-WRITE_LINE_MEMBER( mc6854_device::set_rx )
+void mc6854_device::set_rx(int state)
{
m_rxd = state;
}
@@ -638,7 +628,7 @@ int mc6854_device::send_frame( uint8_t* data, int len )
-WRITE_LINE_MEMBER( mc6854_device::set_cts )
+void mc6854_device::set_cts(int state)
{
if ( ! m_cts && state )
m_sr1 |= CTS;
@@ -653,7 +643,7 @@ WRITE_LINE_MEMBER( mc6854_device::set_cts )
-WRITE_LINE_MEMBER( mc6854_device::set_dcd )
+void mc6854_device::set_dcd(int state)
{
if ( ! m_dcd && state )
{
@@ -917,7 +907,7 @@ inline bool mc6854_device::receive_allowed() const
}
/* MC6854 makes fields from bits */
-WRITE_LINE_MEMBER( mc6854_device::rxc_w )
+void mc6854_device::rxc_w(int state)
{
if (receive_allowed() && state && !m_rxc)
{
@@ -989,7 +979,7 @@ WRITE_LINE_MEMBER( mc6854_device::rxc_w )
m_rxc = state;
}
-WRITE_LINE_MEMBER( mc6854_device::txc_w )
+void mc6854_device::txc_w(int state)
{
// TODO
}
diff --git a/src/devices/machine/mc6854.h b/src/devices/machine/mc6854.h
index 2e2fe6fa663..81be8766816 100644
--- a/src/devices/machine/mc6854.h
+++ b/src/devices/machine/mc6854.h
@@ -38,18 +38,18 @@ public:
uint8_t dma_r(){ return read(2); }
/* low-level, bit-based interface */
- DECLARE_WRITE_LINE_MEMBER( set_rx );
+ void set_rx(int state);
/* high-level, frame-based interface */
int send_frame( uint8_t* data, int length ); /* ret -1 if busy */
/* control lines */
- DECLARE_WRITE_LINE_MEMBER( set_cts ); /* 1 = clear-to-send, 0 = busy */
- DECLARE_WRITE_LINE_MEMBER( set_dcd ); /* 1 = carrier, 0 = no carrier */
+ void set_cts(int state); /* 1 = clear-to-send, 0 = busy */
+ void set_dcd(int state); /* 1 = carrier, 0 = no carrier */
/* clock */
- DECLARE_WRITE_LINE_MEMBER( rxc_w );
- DECLARE_WRITE_LINE_MEMBER( txc_w );
+ void rxc_w(int state);
+ void txc_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/mc68681.cpp b/src/devices/machine/mc68681.cpp
index 378feed8dcc..3a3fcfcecf7 100644
--- a/src/devices/machine/mc68681.cpp
+++ b/src/devices/machine/mc68681.cpp
@@ -112,8 +112,8 @@ DEFINE_DEVICE_TYPE(DUART_CHANNEL, duart_channel, "duart_channel", "DUART channel
// LIVE DEVICE
//**************************************************************************
-duart_base_device::duart_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
+duart_base_device::duart_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
m_chanA(*this, CHANA_TAG),
m_chanB(*this, CHANB_TAG),
m_chanC(*this, CHANC_TAG),
@@ -123,7 +123,7 @@ duart_base_device::duart_base_device(const machine_config &mconfig, device_type
write_b_tx(*this),
write_c_tx(*this),
write_d_tx(*this),
- read_inport(*this),
+ read_inport(*this, 0),
write_outport(*this),
ip3clk(0),
ip4clk(0),
@@ -200,15 +200,7 @@ void duart_base_device::set_clocks(int clk3, int clk4, int clk5, int clk6)
void duart_base_device::device_start()
{
- write_irq.resolve_safe();
- write_a_tx.resolve_safe();
- write_b_tx.resolve_safe();
- write_c_tx.resolve_safe();
- write_d_tx.resolve_safe();
- read_inport.resolve();
- write_outport.resolve_safe();
-
- duart_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(duart_base_device::duart_timer_callback),this), nullptr);
+ duart_timer = timer_alloc(FUNC(duart_base_device::duart_timer_callback), this);
save_item(NAME(ACR));
save_item(NAME(IMR));
@@ -622,7 +614,7 @@ uint8_t duart_base_device::read(offs_t offset)
break;
case 0x0d: /* IP */
- if (!read_inport.isnull())
+ if (!read_inport.isunset())
{
r = read_inport(); // TODO: go away
}
@@ -889,7 +881,7 @@ void duart_base_device::write(offs_t offset, uint8_t data)
}
}
-WRITE_LINE_MEMBER(duart_base_device::ip0_w)
+void duart_base_device::ip0_w(int state)
{
uint8_t newIP = (IP_last_state & ~0x01) | ((state == ASSERT_LINE) ? 1 : 0);
@@ -906,7 +898,7 @@ WRITE_LINE_MEMBER(duart_base_device::ip0_w)
IP_last_state = newIP;
}
-WRITE_LINE_MEMBER(duart_base_device::ip1_w)
+void duart_base_device::ip1_w(int state)
{
uint8_t newIP = (IP_last_state & ~0x02) | ((state == ASSERT_LINE) ? 2 : 0);
@@ -923,7 +915,7 @@ WRITE_LINE_MEMBER(duart_base_device::ip1_w)
IP_last_state = newIP;
}
-WRITE_LINE_MEMBER(duart_base_device::ip2_w)
+void duart_base_device::ip2_w(int state)
{
uint8_t newIP = (IP_last_state & ~0x04) | ((state == ASSERT_LINE) ? 4 : 0);
@@ -940,7 +932,7 @@ WRITE_LINE_MEMBER(duart_base_device::ip2_w)
IP_last_state = newIP;
}
-WRITE_LINE_MEMBER(duart_base_device::ip3_w)
+void duart_base_device::ip3_w(int state)
{
uint8_t newIP = (IP_last_state & ~0x08) | ((state == ASSERT_LINE) ? 8 : 0);
@@ -957,21 +949,21 @@ WRITE_LINE_MEMBER(duart_base_device::ip3_w)
IP_last_state = newIP;
}
-WRITE_LINE_MEMBER(duart_base_device::ip4_w)
+void duart_base_device::ip4_w(int state)
{
uint8_t newIP = (IP_last_state & ~0x10) | ((state == ASSERT_LINE) ? 0x10 : 0);
// TODO: special mode for ip4 (Ch. A Rx clock)
IP_last_state = newIP;
}
-WRITE_LINE_MEMBER(duart_base_device::ip5_w)
+void duart_base_device::ip5_w(int state)
{
uint8_t newIP = (IP_last_state & ~0x20) | ((state == ASSERT_LINE) ? 0x20 : 0);
// TODO: special mode for ip5 (Ch. B Tx clock)
IP_last_state = newIP;
}
-WRITE_LINE_MEMBER(duart_base_device::ip6_w)
+void duart_base_device::ip6_w(int state)
{
uint8_t newIP = (IP_last_state & ~0x40) | ((state == ASSERT_LINE) ? 0x40 : 0);
// TODO: special mode for ip6 (Ch. B Rx clock)
@@ -1168,8 +1160,9 @@ duart_channel::duart_channel(const machine_config &mconfig, const char *tag, dev
, SR(0)
, rx_enabled(0)
, rx_fifo_num(0)
- , tx_enabled(0)
+ , m_tx_data_in_buffer(false)
, m_tx_break(false)
+ , m_bits_transmitted(255)
{
std::fill_n(&rx_fifo[0], MC68681_RX_FIFO_SIZE + 1, 0);
}
@@ -1192,10 +1185,10 @@ void duart_channel::device_start()
save_item(NAME(rx_fifo_read_ptr));
save_item(NAME(rx_fifo_write_ptr));
save_item(NAME(rx_fifo_num));
- save_item(NAME(tx_enabled));
- save_item(NAME(tx_data));
- save_item(NAME(tx_ready));
+ save_item(NAME(m_tx_data));
+ save_item(NAME(m_tx_data_in_buffer));
save_item(NAME(m_tx_break));
+ save_item(NAME(m_bits_transmitted));
}
void duart_channel::device_reset()
@@ -1267,20 +1260,17 @@ void duart_channel::rx_fifo_push(uint8_t data, uint8_t errors)
void duart_channel::tra_complete()
{
- //printf("%s ch %d Tx complete\n", tag(), m_ch);
- tx_ready = 1;
- SR |= STATUS_TRANSMITTER_READY;
-
- if (m_ch == 0)
- m_uart->set_ISR_bits(INT_TXRDYA);
+ if (!(SR & STATUS_TRANSMITTER_READY))
+ {
+ transmit_register_setup(m_tx_data);
+ m_bits_transmitted = 0;
+ m_tx_data_in_buffer = false;
+ }
else
- m_uart->set_ISR_bits(INT_TXRDYB);
-
- // if local loopback is on, write the transmitted data as if a byte had been received
- if ((MR2 & 0xc0) == 0x80)
- rx_fifo_push(tx_data, 0);
-
- update_interrupts();
+ {
+ SR |= STATUS_TRANSMITTER_EMPTY;
+ update_interrupts();
+ }
}
void duart_channel::tra_callback()
@@ -1307,9 +1297,15 @@ void duart_channel::tra_callback()
m_uart->write_d_tx(bit);
}
}
- else // must call this to advance the transmitter
+ else
+ // loop back transmitted bit
+ rx_w(transmit_register_get_data_bit());
+
+ // TxRDY is not set until the end of start bit time
+ if (++m_bits_transmitted > 1 && !m_tx_data_in_buffer)
{
- transmit_register_get_data_bit();
+ SR |= STATUS_TRANSMITTER_READY;
+ update_interrupts();
}
}
@@ -1319,24 +1315,13 @@ void duart_channel::update_interrupts()
switch (MR2 & 0xc0) // what mode are we in?
{
case 0x00: // normal mode
- if (tx_enabled)
- SR |= STATUS_TRANSMITTER_EMPTY;
- else
- SR &= ~STATUS_TRANSMITTER_EMPTY;
break;
case 0x40: // automatic echo mode
- SR &= ~STATUS_TRANSMITTER_EMPTY;
SR &= ~STATUS_TRANSMITTER_READY;
break;
case 0x80: // local loopback mode
- if (tx_enabled)
- SR |= STATUS_TRANSMITTER_EMPTY;
- else
- SR &= ~STATUS_TRANSMITTER_EMPTY;
break;
case 0xc0: // remote loopback mode
- // write me, what the txrdy/txemt regs do for remote loopback mode is undocumented afaik, for now just clear both
- SR &= ~STATUS_TRANSMITTER_EMPTY;
SR &= ~STATUS_TRANSMITTER_READY;
break;
}
@@ -1570,13 +1555,20 @@ void duart_channel::write_CR(uint8_t data)
receive_register_reset();
break;
case 3: /* Reset channel transmitter */
- tx_enabled = 0;
- SR &= ~STATUS_TRANSMITTER_READY;
+ SR &= ~(STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY);
if (m_ch == 0)
+ {
+ m_uart->write_a_tx(1);
m_uart->clear_ISR_bits(INT_TXRDYA);
+ }
else
+ {
+ m_uart->write_b_tx(1);
m_uart->clear_ISR_bits(INT_TXRDYB);
+ }
transmit_register_reset();
+ m_bits_transmitted = 255;
+ m_tx_data_in_buffer = false;
break;
case 4: /* Reset Error Status */
SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR | STATUS_OVERRUN_ERROR);
@@ -1632,11 +1624,10 @@ void duart_channel::write_CR(uint8_t data)
SR &= ~STATUS_RECEIVER_READY;
}
- if (BIT(data, 2))
+ if (!(SR & STATUS_TRANSMITTER_READY) && BIT(data, 2))
{
- tx_enabled = 1;
- tx_ready = 1;
- SR |= STATUS_TRANSMITTER_READY;
+ SR |= STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY;
+ m_tx_data_in_buffer = false;
if (m_ch == 0)
m_uart->set_ISR_bits(INT_TXRDYA);
else
@@ -1644,9 +1635,8 @@ void duart_channel::write_CR(uint8_t data)
}
if (BIT(data, 3))
{
- tx_enabled = 0;
- tx_ready = 0;
- SR &= ~STATUS_TRANSMITTER_READY;
+ SR &= ~(STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY);
+ m_tx_data_in_buffer = false;
if (m_ch == 0)
m_uart->clear_ISR_bits(INT_TXRDYA);
else
@@ -1658,25 +1648,23 @@ void duart_channel::write_CR(uint8_t data)
void duart_channel::write_TX(uint8_t data)
{
- tx_data = data;
-
-/* if (!tx_ready)
- {
- printf("Write %02x to TX when TX not ready!\n", data);
- }*/
-
- //printf("%s ch %d Tx %c [%02x]\n", tag(), m_ch, isprint(data) ? data : ' ', data);
-
- tx_ready = 0;
- SR &= ~STATUS_TRANSMITTER_READY;
+ if (!(SR & STATUS_TRANSMITTER_READY))
+ {
+ logerror("write_tx transmitter not ready (data 0x%02x discarded)\n", data);
+ return;
+ }
- if (m_ch == 0)
- m_uart->clear_ISR_bits(INT_TXRDYA);
+ SR &= ~(STATUS_TRANSMITTER_READY | STATUS_TRANSMITTER_EMPTY);
+ if (!is_transmit_register_empty())
+ {
+ m_tx_data = data;
+ m_tx_data_in_buffer = true;
+ }
else
- m_uart->clear_ISR_bits(INT_TXRDYB);
-
- // send tx_data
- transmit_register_setup(tx_data);
+ {
+ transmit_register_setup(data);
+ m_bits_transmitted = 0;
+ }
update_interrupts();
}
diff --git a/src/devices/machine/mc68681.h b/src/devices/machine/mc68681.h
index b47e7276cd8..fecd5feb742 100644
--- a/src/devices/machine/mc68681.h
+++ b/src/devices/machine/mc68681.h
@@ -71,10 +71,10 @@ private:
int m_ch;
/* Transmitter */
- uint8_t tx_enabled;
- uint8_t tx_data;
- uint8_t tx_ready;
+ uint8_t m_tx_data;
+ bool m_tx_data_in_buffer;
bool m_tx_break;
+ uint8_t m_bits_transmitted;
/* Rx/Tx clocking */
uint8_t m_rx_prescaler , m_tx_prescaler;
@@ -107,8 +107,8 @@ public:
virtual uint8_t read(offs_t offset);
virtual void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(rx_a_w) { m_chanA->device_serial_interface::rx_w((uint8_t)state); }
- DECLARE_WRITE_LINE_MEMBER(rx_b_w) { m_chanB->device_serial_interface::rx_w((uint8_t)state); }
+ void rx_a_w(int state) { m_chanA->device_serial_interface::rx_w((uint8_t)state); }
+ void rx_b_w(int state) { m_chanB->device_serial_interface::rx_w((uint8_t)state); }
auto irq_cb() { return write_irq.bind(); }
auto a_tx_cb() { return write_a_tx.bind(); }
@@ -117,13 +117,13 @@ public:
auto outport_cb() { return write_outport.bind(); }
// new-style push handlers for input port bits
- DECLARE_WRITE_LINE_MEMBER(ip0_w);
- DECLARE_WRITE_LINE_MEMBER(ip1_w);
- DECLARE_WRITE_LINE_MEMBER(ip2_w);
- DECLARE_WRITE_LINE_MEMBER(ip3_w);
- DECLARE_WRITE_LINE_MEMBER(ip4_w);
- DECLARE_WRITE_LINE_MEMBER(ip5_w);
- DECLARE_WRITE_LINE_MEMBER(ip6_w);
+ void ip0_w(int state);
+ void ip1_w(int state);
+ void ip2_w(int state);
+ void ip3_w(int state);
+ void ip4_w(int state);
+ void ip5_w(int state);
+ void ip6_w(int state);
bool irq_pending() const { return (ISR & IMR) != 0; }
@@ -230,8 +230,8 @@ public:
auto c_tx_cb() { return write_c_tx.bind(); }
auto d_tx_cb() { return write_d_tx.bind(); }
- DECLARE_WRITE_LINE_MEMBER(rx_c_w) { m_chanC->device_serial_interface::rx_w((uint8_t)state); }
- DECLARE_WRITE_LINE_MEMBER(rx_d_w) { m_chanD->device_serial_interface::rx_w((uint8_t)state); }
+ void rx_c_w(int state) { m_chanC->device_serial_interface::rx_w((uint8_t)state); }
+ void rx_d_w(int state) { m_chanD->device_serial_interface::rx_w((uint8_t)state); }
virtual uint8_t read(offs_t offset) override;
virtual void write(offs_t offset, uint8_t data) override;
diff --git a/src/devices/machine/mc68901.cpp b/src/devices/machine/mc68901.cpp
index 082e02985a7..e6e8a1f4695 100644
--- a/src/devices/machine/mc68901.cpp
+++ b/src/devices/machine/mc68901.cpp
@@ -30,7 +30,7 @@
the CPU IPL signals (it is even possible that GLUE make some kind of latching). This would create a window
long enough for the 'precise point' described above.
- "yes, the spurious interrupt occurs when i mask a timer. i did not notice an occurance of the SPI when changing data and control registers.
+ "yes, the spurious interrupt occurs when i mask a timer. i did not notice an occurrence of the SPI when changing data and control registers.
if i kill interrupts with the status reg before masking the timer interrupt, then the SPI occurs as soon as the status register is set to re-enable interrupts."
Well, more experiments show that it's somewhat incorrect, and
@@ -45,9 +45,8 @@
#include "mc68901.h"
#include "cpu/m68000/m68000.h"
-#define LOG_GENERAL (1 << 0U)
-#define LOG_RCV (1 << 1U)
-#define LOG_XMIT (1 << 2U)
+#define LOG_RCV (1U << 1)
+#define LOG_XMIT (1U << 2)
//#define VERBOSE (LOG_GENERAL | LOG_RCV | LOG_XMIT)
#include "logmacro.h"
@@ -152,7 +151,6 @@ enum : u8 {
#define DIVISOR PRESCALER[data & 0x07]
-
const u16 mc68901_device::INT_MASK_GPIO[] =
{
IR_GPIP_0, IR_GPIP_1, IR_GPIP_2, IR_GPIP_3,
@@ -230,34 +228,34 @@ inline void mc68901_device::rx_error()
}
}
-inline void mc68901_device::timer_count(int index)
+TIMER_CALLBACK_MEMBER(mc68901_device::timer_count)
{
- if (m_tmc[index] == 0x01)
+ if (m_tmc[param] == 0x01)
{
/* toggle timer output signal */
- m_to[index] = !m_to[index];
+ m_to[param] = !m_to[param];
- switch (index)
+ switch (param)
{
- case TIMER_A: m_out_tao_cb(m_to[index]); break;
- case TIMER_B: m_out_tbo_cb(m_to[index]); break;
- case TIMER_C: m_out_tco_cb(m_to[index]); break;
- case TIMER_D: m_out_tdo_cb(m_to[index]); break;
+ case TIMER_A: m_out_tao_cb(m_to[param]); break;
+ case TIMER_B: m_out_tbo_cb(m_to[param]); break;
+ case TIMER_C: m_out_tco_cb(m_to[param]); break;
+ case TIMER_D: m_out_tdo_cb(m_to[param]); break;
}
- if (m_ier & INT_MASK_TIMER[index])
+ if (m_ier & INT_MASK_TIMER[param])
{
/* signal timer elapsed interrupt */
- take_interrupt(INT_MASK_TIMER[index]);
+ take_interrupt(INT_MASK_TIMER[param]);
}
/* load main counter */
- m_tmc[index] = m_tdr[index];
+ m_tmc[param] = m_tdr[param];
}
else
{
/* count down */
- m_tmc[index]--;
+ m_tmc[param]--;
}
}
@@ -276,7 +274,6 @@ inline void mc68901_device::timer_input(int index, int value)
timer_count(index);
}
- m_ti[index] = value;
break;
case TCR_TIMER_PULSE_4:
@@ -295,10 +292,10 @@ inline void mc68901_device::timer_input(int index, int value)
take_interrupt(INT_MASK_GPIO[bit]);
}
}
-
- m_ti[index] = value;
break;
}
+
+ m_ti[index] = value;
}
@@ -346,43 +343,43 @@ void mc68901_device::gpio_output()
// mc68901_device - constructor
//-------------------------------------------------
-mc68901_device::mc68901_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, MC68901, tag, owner, clock),
- m_timer_clock(0),
- m_out_irq_cb(*this),
- m_out_gpio_cb(*this),
- m_out_tao_cb(*this),
- m_out_tbo_cb(*this),
- m_out_tco_cb(*this),
- m_out_tdo_cb(*this),
- m_out_so_cb(*this),
- //m_out_rr_cb(*this),
- //m_out_tr_cb(*this),
- m_iack_chain_cb(*this),
- m_aer(0),
- m_ier(0),
- m_scr(0),
- m_scr_parity(false),
- m_transmit_buffer(0),
- m_receive_buffer(0),
- m_gpio_input(0),
- m_gpio_output(0xff),
- m_rframe(0),
- m_rclk(0),
- m_rbits(0),
- m_si_scan(0xff),
- m_next_rsr(0),
- m_rc(true),
- m_si(true),
- m_last_si(true),
- m_rparity(false),
- m_osr(0),
- m_tclk(0),
- m_tbits(0),
- m_tc(true),
- m_so(false),
- m_tparity(false),
- m_underrun(false)
+mc68901_device::mc68901_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, MC68901, tag, owner, clock),
+ m_timer_clock(0),
+ m_out_irq_cb(*this),
+ m_out_gpio_cb(*this),
+ m_out_tao_cb(*this),
+ m_out_tbo_cb(*this),
+ m_out_tco_cb(*this),
+ m_out_tdo_cb(*this),
+ m_out_so_cb(*this),
+ //m_out_rr_cb(*this),
+ //m_out_tr_cb(*this),
+ m_iack_chain_cb(*this, 0x18), // Spurious IRQ
+ m_aer(0),
+ m_ier(0),
+ m_scr(0),
+ m_scr_parity(false),
+ m_transmit_buffer(0),
+ m_receive_buffer(0),
+ m_gpio_input(0),
+ m_gpio_output(0xff),
+ m_rframe(0),
+ m_rclk(0),
+ m_rbits(0),
+ m_si_scan(0xff),
+ m_next_rsr(0),
+ m_rc(true),
+ m_si(true),
+ m_last_si(true),
+ m_rparity(false),
+ m_osr(0),
+ m_tclk(0),
+ m_tbits(0),
+ m_tc(true),
+ m_so(false),
+ m_tparity(false),
+ m_underrun(false)
{
}
@@ -393,23 +390,11 @@ mc68901_device::mc68901_device(const machine_config &mconfig, const char *tag, d
void mc68901_device::device_start()
{
- /* resolve callbacks */
- m_out_irq_cb.resolve_safe();
- m_out_gpio_cb.resolve_safe();
- m_out_tao_cb.resolve_safe();
- m_out_tbo_cb.resolve_safe();
- m_out_tco_cb.resolve_safe();
- m_out_tdo_cb.resolve_safe();
- m_out_so_cb.resolve_safe();
- //m_out_rr_cb.resolve_safe();
- //m_out_tr_cb.resolve_safe();
- m_iack_chain_cb.resolve();
-
/* create the timers */
- m_timer[TIMER_A] = timer_alloc(TIMER_A);
- m_timer[TIMER_B] = timer_alloc(TIMER_B);
- m_timer[TIMER_C] = timer_alloc(TIMER_C);
- m_timer[TIMER_D] = timer_alloc(TIMER_D);
+ m_timer[TIMER_A] = timer_alloc(FUNC(mc68901_device::timer_count), this);
+ m_timer[TIMER_B] = timer_alloc(FUNC(mc68901_device::timer_count), this);
+ m_timer[TIMER_C] = timer_alloc(FUNC(mc68901_device::timer_count), this);
+ m_timer[TIMER_D] = timer_alloc(FUNC(mc68901_device::timer_count), this);
/* register for state saving */
save_item(NAME(m_gpip));
@@ -500,17 +485,6 @@ void mc68901_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void mc68901_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- if(id >= TIMER_A && id <= TIMER_D)
- timer_count(id);
-}
-
-
-//-------------------------------------------------
// read - read from one MFP register
//-------------------------------------------------
@@ -696,7 +670,7 @@ void mc68901_device::write(offs_t offset, u8 data)
{
int divisor = PRESCALER[m_tacr & 0x07];
LOG("MC68901 Timer A Delay Mode : %u Prescale\n", divisor);
- m_timer[TIMER_A]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor));
+ m_timer[TIMER_A]->adjust(attotime::from_hz(m_timer_clock / divisor), TIMER_A, attotime::from_hz(m_timer_clock / divisor));
}
break;
@@ -712,12 +686,8 @@ void mc68901_device::write(offs_t offset, u8 data)
case TCR_TIMER_PULSE_64:
case TCR_TIMER_PULSE_100:
case TCR_TIMER_PULSE_200:
- {
- int divisor = PRESCALER[m_tacr & 0x07];
- LOG("MC68901 Timer A Pulse Width Mode : %u Prescale\n", divisor);
- m_timer[TIMER_A]->adjust(attotime::never, 0, attotime::from_hz(m_timer_clock / divisor));
- m_timer[TIMER_A]->enable(false);
- }
+ LOG("MC68901 Timer A Pulse Width Mode\n");
+ m_timer[TIMER_A]->adjust(attotime::never);
break;
}
@@ -749,9 +719,9 @@ void mc68901_device::write(offs_t offset, u8 data)
case TCR_TIMER_DELAY_100:
case TCR_TIMER_DELAY_200:
{
- int divisor = PRESCALER[m_tbcr & 0x07];
- LOG("MC68901 Timer B Delay Mode : %u Prescale\n", divisor);
- m_timer[TIMER_B]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor));
+ int divisor = PRESCALER[m_tbcr & 0x07];
+ LOG("MC68901 Timer B Delay Mode : %u Prescale\n", divisor);
+ m_timer[TIMER_B]->adjust(attotime::from_hz(m_timer_clock / divisor), TIMER_B, attotime::from_hz(m_timer_clock / divisor));
}
break;
@@ -767,12 +737,8 @@ void mc68901_device::write(offs_t offset, u8 data)
case TCR_TIMER_PULSE_64:
case TCR_TIMER_PULSE_100:
case TCR_TIMER_PULSE_200:
- {
- int divisor = PRESCALER[m_tbcr & 0x07];
- LOG("MC68901 Timer B Pulse Width Mode : %u Prescale\n", DIVISOR);
- m_timer[TIMER_B]->adjust(attotime::never, 0, attotime::from_hz(m_timer_clock / divisor));
- m_timer[TIMER_B]->enable(false);
- }
+ LOG("MC68901 Timer B Pulse Width Mode\n");
+ m_timer[TIMER_B]->adjust(attotime::never);
break;
}
@@ -806,7 +772,7 @@ void mc68901_device::write(offs_t offset, u8 data)
{
int divisor = PRESCALER[m_tcdcr & 0x07];
LOG("MC68901 Timer D Delay Mode : %u Prescale\n", divisor);
- m_timer[TIMER_D]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor));
+ m_timer[TIMER_D]->adjust(attotime::from_hz(m_timer_clock / divisor), TIMER_D, attotime::from_hz(m_timer_clock / divisor));
}
break;
}
@@ -828,7 +794,7 @@ void mc68901_device::write(offs_t offset, u8 data)
{
int divisor = PRESCALER[(m_tcdcr >> 4) & 0x07];
LOG("MC68901 Timer C Delay Mode : %u Prescale\n", divisor);
- m_timer[TIMER_C]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor));
+ m_timer[TIMER_C]->adjust(attotime::from_hz(m_timer_clock / divisor), TIMER_C, attotime::from_hz(m_timer_clock / divisor));
}
break;
}
@@ -1073,29 +1039,26 @@ u8 mc68901_device::get_vector()
}
}
- if (!m_iack_chain_cb.isnull())
- return m_iack_chain_cb();
- else
- return 0x18; // Spurious irq
+ return m_iack_chain_cb();
}
-WRITE_LINE_MEMBER( mc68901_device::i0_w ) { gpio_input(0, state); }
-WRITE_LINE_MEMBER( mc68901_device::i1_w ) { gpio_input(1, state); }
-WRITE_LINE_MEMBER( mc68901_device::i2_w ) { gpio_input(2, state); }
-WRITE_LINE_MEMBER( mc68901_device::i3_w ) { gpio_input(3, state); }
-WRITE_LINE_MEMBER( mc68901_device::i4_w ) { gpio_input(4, state); }
-WRITE_LINE_MEMBER( mc68901_device::i5_w ) { gpio_input(5, state); }
-WRITE_LINE_MEMBER( mc68901_device::i6_w ) { gpio_input(6, state); }
-WRITE_LINE_MEMBER( mc68901_device::i7_w ) { gpio_input(7, state); }
+void mc68901_device::i0_w(int state) { gpio_input(0, state); }
+void mc68901_device::i1_w(int state) { gpio_input(1, state); }
+void mc68901_device::i2_w(int state) { gpio_input(2, state); }
+void mc68901_device::i3_w(int state) { gpio_input(3, state); }
+void mc68901_device::i4_w(int state) { gpio_input(4, state); }
+void mc68901_device::i5_w(int state) { gpio_input(5, state); }
+void mc68901_device::i6_w(int state) { gpio_input(6, state); }
+void mc68901_device::i7_w(int state) { gpio_input(7, state); }
-WRITE_LINE_MEMBER( mc68901_device::tai_w )
+void mc68901_device::tai_w(int state)
{
timer_input(TIMER_A, state);
}
-WRITE_LINE_MEMBER( mc68901_device::tbi_w )
+void mc68901_device::tbi_w(int state)
{
timer_input(TIMER_B, state);
}
@@ -1108,7 +1071,7 @@ WRITE_LINE_MEMBER( mc68901_device::tbi_w )
// si_w - serial data input for receiver
//-------------------------------------------------
-WRITE_LINE_MEMBER(mc68901_device::si_w)
+void mc68901_device::si_w(int state)
{
m_si = state;
}
@@ -1117,7 +1080,7 @@ WRITE_LINE_MEMBER(mc68901_device::si_w)
// rc_w - receiver clock input
//-------------------------------------------------
-WRITE_LINE_MEMBER(mc68901_device::rc_w)
+void mc68901_device::rc_w(int state)
{
if (state != m_rc)
{
@@ -1132,7 +1095,7 @@ WRITE_LINE_MEMBER(mc68901_device::rc_w)
// tc_w - transmitter clock input
//-------------------------------------------------
-WRITE_LINE_MEMBER(mc68901_device::tc_w)
+void mc68901_device::tc_w(int state)
{
if (state != m_tc)
{
diff --git a/src/devices/machine/mc68901.h b/src/devices/machine/mc68901.h
index cc792b34900..35712dbb8a2 100644
--- a/src/devices/machine/mc68901.h
+++ b/src/devices/machine/mc68901.h
@@ -71,27 +71,26 @@ public:
u8 get_vector();
- DECLARE_WRITE_LINE_MEMBER( i0_w );
- DECLARE_WRITE_LINE_MEMBER( i1_w );
- DECLARE_WRITE_LINE_MEMBER( i2_w );
- DECLARE_WRITE_LINE_MEMBER( i3_w );
- DECLARE_WRITE_LINE_MEMBER( i4_w );
- DECLARE_WRITE_LINE_MEMBER( i5_w );
- DECLARE_WRITE_LINE_MEMBER( i6_w );
- DECLARE_WRITE_LINE_MEMBER( i7_w );
-
- DECLARE_WRITE_LINE_MEMBER( tai_w );
- DECLARE_WRITE_LINE_MEMBER( tbi_w );
-
- DECLARE_WRITE_LINE_MEMBER( si_w );
- DECLARE_WRITE_LINE_MEMBER( rc_w );
- DECLARE_WRITE_LINE_MEMBER( tc_w );
+ void i0_w(int state);
+ void i1_w(int state);
+ void i2_w(int state);
+ void i3_w(int state);
+ void i4_w(int state);
+ void i5_w(int state);
+ void i6_w(int state);
+ void i7_w(int state);
+
+ void tai_w(int state);
+ void tbi_w(int state);
+
+ void si_w(int state);
+ void rc_w(int state);
+ void tc_w(int state);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
void check_interrupts();
void take_interrupt(u16 mask);
@@ -99,7 +98,7 @@ protected:
void tx_error();
void rx_buffer_full();
void rx_error();
- void timer_count(int index);
+ TIMER_CALLBACK_MEMBER(timer_count);
void timer_input(int index, int value);
void gpio_input(int bit, int state);
void gpio_output();
diff --git a/src/devices/machine/mc88200.cpp b/src/devices/machine/mc88200.cpp
new file mode 100644
index 00000000000..0419c279588
--- /dev/null
+++ b/src/devices/machine/mc88200.cpp
@@ -0,0 +1,992 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * Motorola MC88200 Cache/Memory Management Unit (CMMU).
+ *
+ * Sources:
+ * - MC88200 Cache/Memory Management User's Manual, Second Edition (MC88200UM/AD, Rev 1)
+ *
+ * TODO:
+ * - probe commands
+ * - mbus snooping
+ * - multiple cmmus per pbus
+ * - cycle counting
+ * - cache inhibited accesses invalidate matching cache tags (no writeback)
+ * - mc88204 64k variant
+ * - find out where patc valid flag is stored
+ */
+
+#include "emu.h"
+
+#include "mc88200.h"
+
+//#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(MC88200, mc88200_device, "mc88200", "Motorola MC88200 Cache/Memory Management Unit")
+
+mc88200_device::mc88200_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, u8 id)
+ : device_t(mconfig, MC88200, tag, owner, clock)
+ , m_mbus(*this, finder_base::DUMMY_TAG, -1, 32)
+ , m_id(u32(id) << 24)
+{
+}
+
+enum idr_mask : u32
+{
+ IDR_VERSION = 0x001f0000,
+ IDR_TYPE = 0x00e00000,
+ IDR_ID = 0xff000000,
+};
+
+enum idr_type_mask : u32
+{
+ TYPE_MC88200 = 0x00a00000, // 16k cache
+ TYPE_MC88204 = 0x00c00000, // 64k cache
+};
+
+enum ssr_mask : u32
+{
+ SSR_V = 0x00000001, // valid
+ SSR_BH = 0x00000002, // batc hit
+ SSR_WP = 0x00000004, // write protection
+ SSR_U = 0x00000008, // used
+ SSR_M = 0x00000010, // modified
+ SSR_CI = 0x00000040, // cache inhibit
+ SSR_G = 0x00000080, // global
+ SSR_SP = 0x00000100, // supervisor privilege
+ SSR_WT = 0x00000200, // writethrough
+ SSR_BE = 0x00004000, // bus error
+ SSR_CE = 0x00008000, // copyback error
+
+ SSR_WM = 0x0000c3df,
+};
+
+enum sctr_mask : u32
+{
+ SCTR_PR = 0x00010000, // priority arbitration
+ SCTR_SE = 0x00020000, // snoop enable
+ SCTR_PE = 0x00040000, // parity enable
+};
+
+enum pfsr_mask : u32
+{
+ PFSR_OK = 0x00000000, // success (no fault)
+ PFSR_BE = 0x00030000, // bus error
+ PFSR_SF = 0x00040000, // segment fault
+ PFSR_PF = 0x00050000, // page fault
+ PFSR_SV = 0x00060000, // supervisor violation
+ PFSR_WV = 0x00070000, // write violation
+
+ PFSR_WM = 0x00070000,
+};
+
+enum apr_mask : u32
+{
+ APR_TE = 0x00000001, // translation enable
+ APR_CI = 0x00000040, // cache inhibit
+ APR_G = 0x00000080, // global
+ APR_WT = 0x00000200, // writethrough
+ APR_STBA = 0xfffff000, // segment table base address
+
+ APR_WM = 0xfffff2c1,
+};
+
+enum batc_mask : u32
+{
+ BATC_V = 0x00000001, // valid
+ BATC_WP = 0x00000002, // write protect
+ BATC_CI = 0x00000004, // cache inhibit
+ BATC_G = 0x00000008, // global
+ BATC_WT = 0x00000010, // writethrough
+ BATC_S = 0x00000020, // supervisor
+ BATC_PBA = 0x0007ffc0, // physical block address
+ BATC_LBA = 0xfff80000, // logical block address
+};
+
+enum cssp_mask : u32
+{
+ CSSP_VV0 = 0x00003000, // line valid 0
+ CSSP_VV1 = 0x0000c000, // line valid 1
+ CSSP_VV2 = 0x00030000, // line valid 2
+ CSSP_VV3 = 0x000c0000, // line valid 3
+ CSSP_D0 = 0x00100000, // line disable 0
+ CSSP_D1 = 0x00200000, // line disable 1
+ CSSP_D2 = 0x00400000, // line disable 2
+ CSSP_D3 = 0x00800000, // line disable 3
+ CSSP_L0 = 0x01000000, // line 1 more recently used than line 0
+ CSSP_L1 = 0x02000000, // line 2 more recently used than line 0
+ CSSP_L2 = 0x04000000, // line 2 more recently used than line 1
+ CSSP_L3 = 0x08000000, // line 3 more recently used than line 0
+ CSSP_L4 = 0x10000000, // line 3 more recently used than line 1
+ CSSP_L5 = 0x20000000, // line 3 more recently used than line 2
+
+ CSSP_WM = 0x3ffff000,
+};
+
+enum valid : unsigned
+{
+ EXU = 0, // exclusive unmodified
+ EXM = 1, // exclusive modified
+ SHU = 2, // shared unmodified
+ INV = 3, // invalid
+};
+
+enum patc_mask : u64
+{
+ PATC_WP = 0x0000'00000001, // write protect
+ PATC_M = 0x0000'00000002, // modified
+ PATC_CI = 0x0000'00000004, // cache inhibit
+ PATC_G = 0x0000'00000008, // global
+ PATC_WT = 0x0000'00000010, // writethrough
+ PATC_S = 0x0000'00000020, // supervisor
+ PATC_PFA = 0x0000'03ffffc0, // page frame address
+ PATC_LPA = 0x3fff'fc000000, // logical page address
+
+ PATC_V = 0x8000'00000000, // valid (??)
+};
+
+enum segment_descriptor_mask : u32
+{
+ SGD_V = 0x00000001, // valid
+ SGD_WP = 0x00000004, // write protect
+ SGD_CI = 0x00000040, // cache inhibit
+ SGD_G = 0x00000080, // global
+ SGD_SP = 0x00000100, // supervisor protection
+ SGD_WT = 0x00000200, // writethrough
+ SGD_PTBA = 0xfffff000, // page table base address
+};
+
+enum page_descriptor_mask : u32
+{
+ PGD_V = 0x00000001, // valid
+ PGD_WP = 0x00000004, // write protect
+ PGD_U = 0x00000008, // used
+ PGD_M = 0x00000010, // modified
+ PGD_CI = 0x00000040, // cache inhibit
+ PGD_G = 0x00000080, // global
+ PGD_SP = 0x00000100, // supervisor protection
+ PGD_WT = 0x00000200, // writethrough
+ PGD_PFA = 0xfffff000, // page frame address
+};
+
+enum logical_address_mask : u32
+{
+ LA_OFS = 0x00000fff,
+ LA_PAG = 0x003ff000,
+ LA_SEG = 0xffc00000,
+};
+
+void mc88200_device::device_start()
+{
+ m_cache = std::make_unique<cache_set[]>(CACHE_SETS);
+
+ save_item(NAME(m_idr));
+ save_item(NAME(m_scr));
+ save_item(NAME(m_ssr));
+ save_item(NAME(m_sar));
+ save_item(NAME(m_sctr));
+ save_item(NAME(m_pfsr));
+ save_item(NAME(m_pfar));
+ save_item(NAME(m_sapr));
+ save_item(NAME(m_uapr));
+
+ save_item(NAME(m_batc));
+ save_item(NAME(m_patc));
+ save_item(NAME(m_patc_ptr));
+
+ save_item(NAME(m_bus_error));
+
+ save_pointer(STRUCT_MEMBER(m_cache, status), CACHE_SETS);
+ // TODO: save state for cache lines
+
+ m_idr = m_id | TYPE_MC88200;
+ m_mbus->install_device(0xfff00000U | ((m_idr & IDR_ID) >> 12), 0xfff00fffU | ((m_idr & IDR_ID) >> 12), *this, &mc88200_device::map);
+}
+
+void mc88200_device::device_reset()
+{
+ m_scr = 0;
+ m_ssr = 0;
+ m_sar = 0; // undefined
+ m_sctr = 0;
+ m_pfsr = 0;
+ m_pfar = 0; // undefined
+ m_sapr = APR_CI;
+ m_uapr = APR_CI;
+
+ std::fill_n(m_batc, std::size(m_batc), 0U);
+
+ // batc contains two hard-wired entries
+ m_batc[8] = 0xfff7ffb5;
+ m_batc[9] = 0xfffffff5;
+
+ std::fill_n(m_patc, std::size(m_patc), 0U);
+ m_patc_ptr = 0;
+
+ m_bus_error = false;
+
+ idr_w(m_id);
+}
+
+void mc88200_device::map(address_map &map)
+{
+ // system interface registers
+ map(0x000, 0x003).rw(FUNC(mc88200_device::idr_r), FUNC(mc88200_device::idr_w));
+ map(0x004, 0x007).rw(FUNC(mc88200_device::scr_r), FUNC(mc88200_device::scr_w));
+ map(0x008, 0x00b).rw(FUNC(mc88200_device::ssr_r), FUNC(mc88200_device::ssr_w));
+ map(0x00c, 0x00f).rw(FUNC(mc88200_device::sar_r), FUNC(mc88200_device::sar_w));
+ map(0x104, 0x107).rw(FUNC(mc88200_device::sctr_r), FUNC(mc88200_device::sctr_w));
+
+ // p bus fault registers
+ map(0x108, 0x10b).rw(FUNC(mc88200_device::pfsr_r), FUNC(mc88200_device::pfsr_w));
+ map(0x10c, 0x10f).rw(FUNC(mc88200_device::pfar_r), FUNC(mc88200_device::pfar_w));
+
+ // area pointers
+ map(0x200, 0x203).rw(FUNC(mc88200_device::sapr_r), FUNC(mc88200_device::sapr_w));
+ map(0x204, 0x207).rw(FUNC(mc88200_device::uapr_r), FUNC(mc88200_device::uapr_w));
+
+ // batc write ports
+ map(0x400, 0x41f).w(FUNC(mc88200_device::bwp_w)).mirror(0x20);
+
+ // cache diagnostic ports
+ map(0x800, 0x80f).rw(FUNC(mc88200_device::cdp_r), FUNC(mc88200_device::cdp_w)).mirror(0x30);
+ map(0x840, 0x84f).rw(FUNC(mc88200_device::ctp_r), FUNC(mc88200_device::ctp_w)).mirror(0x30);
+ map(0x880, 0x883).rw(FUNC(mc88200_device::cssp_r), FUNC(mc88200_device::cssp_w)).mirror(0x30);
+}
+
+void mc88200_device::idr_w(u32 data)
+{
+ if ((data ^ m_idr) & IDR_ID)
+ {
+ LOG("idr_w 0x%08x (%s)\n", data, machine().describe_context());
+
+ m_mbus->unmap_readwrite(0xfff00000U | ((m_idr & IDR_ID) >> 12), 0xfff00fffU | ((m_idr & IDR_ID) >> 12));
+ m_idr = (m_idr & ~IDR_ID) | (data & IDR_ID);
+ m_mbus->install_device(0xfff00000U | ((m_idr & IDR_ID) >> 12), 0xfff00fffU | ((m_idr & IDR_ID) >> 12), *this, &mc88200_device::map);
+ }
+}
+
+void mc88200_device::scr_w(u32 data)
+{
+ LOG("scr_w 0x%08x (%s)\n", data, machine().describe_context());
+
+ char const *const action[] = { nullptr, "invalidate", "copy back", "copy back and invalidate" };
+
+ switch (data & 0x3f)
+ {
+ 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:
+ LOG("no operation\n");
+ break;
+ case 0x14: // invalidate line
+ case 0x18: // copy back line
+ case 0x1c: // copy back and invalidate line
+ LOG("data cache %s line 0x%08x\n", action[BIT(data, 2, 2)], m_sar);
+ cache_flush(BIT(m_sar, 4, 8), BIT(m_sar, 4, 8) + 1, &mc88200_device::cache_set::cache_line::match_page, BIT(data, 3), BIT(data, 2));
+ break;
+ case 0x15: // invalidate page
+ case 0x19: // copy back page
+ case 0x1d: // copy back and invalidate page
+ LOG("data cache %s page 0x%08x\n", action[BIT(data, 2, 2)], m_sar & ~LA_OFS);
+ cache_flush(0, CACHE_SETS, &mc88200_device::cache_set::cache_line::match_page, BIT(data, 3), BIT(data, 2));
+ break;
+ case 0x16: // invalidate segment
+ case 0x1a: // copy back segment
+ case 0x1e: // copy back and invalidate segment
+ LOG("data cache %s segment 0x%08x\n", action[BIT(data, 2, 2)], m_sar & LA_SEG);
+ cache_flush(0, CACHE_SETS, &mc88200_device::cache_set::cache_line::match_segment, BIT(data, 3), BIT(data, 2));
+ break;
+ case 0x17: // invalidate all
+ case 0x1b: // copy back all
+ case 0x1f: // copy back and invalidate all
+ LOG("data cache %s all\n", action[BIT(data, 2, 2)]);
+ cache_flush(0, CACHE_SETS, nullptr, BIT(data, 3), BIT(data, 2));
+ break;
+ case 0x20: case 0x21: case 0x22: case 0x23:
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ logerror("probe user address (unemulated)\n");
+ break;
+ case 0x24: case 0x25: case 0x26: case 0x27:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ logerror("probe supervisor (unemulated)\n");
+ break;
+ case 0x31: case 0x39: // page
+ LOG("invalidate PATC descriptors (user, page 0x%08x)\n", m_sar & ~LA_OFS);
+ for (u64 &patc : m_patc)
+ if (!(patc & PATC_S) && BIT(patc, 26, 20) == BIT(m_sar, 12, 20))
+ patc &= ~PATC_V;
+ break;
+ case 0x32: case 0x3a: // segment
+ LOG("invalidate PATC descriptors (user, segment 0x%08x)\n", m_sar & LA_SEG);
+ for (u64 &patc : m_patc)
+ if (!(patc & PATC_S) && BIT(patc, 36, 10) == BIT(m_sar, 22, 10))
+ patc &= ~PATC_V;
+ break;
+ case 0x33: case 0x3b: // all
+ LOG("invalidate PATC descriptors (user, all)\n");
+ for (u64 &patc : m_patc)
+ if (!(patc & PATC_S))
+ patc &= ~PATC_V;
+ break;
+ case 0x35: case 0x3d: // page
+ LOG("invalidate PATC descriptors (supervisor, page 0x%08x)\n", m_sar & ~LA_OFS);
+ for (u64 &patc : m_patc)
+ if ((patc & PATC_S) && BIT(patc, 26, 20) == BIT(m_sar, 12, 20))
+ patc &= ~PATC_V;
+ break;
+ case 0x36: case 0x3e: // segment
+ LOG("invalidate PATC descriptors (supervisor, segment 0x%08x)\n", m_sar & LA_SEG);
+ for (u64 &patc : m_patc)
+ if ((patc & PATC_S) && BIT(patc, 36, 10) == BIT(m_sar, 22, 10))
+ patc &= ~PATC_V;
+ break;
+ case 0x37: case 0x3f: // all
+ LOG("invalidate PATC cache descriptors (supervisor, all)\n");
+ for (u64 &patc : m_patc)
+ if (patc & PATC_S)
+ patc &= ~PATC_V;
+ break;
+ default:
+ logerror("unknown operation 0x%08x (%s)\n", data, machine().describe_context());
+ break;
+ }
+
+ m_scr = data & 0x3f;
+}
+
+void mc88200_device::ssr_w(u32 data) { LOG("ssr_w 0x%08x (%s)\n", data, machine().describe_context()); m_ssr = data & SSR_WM; }
+void mc88200_device::sar_w(u32 data) { LOG("sar_w 0x%08x (%s)\n", data, machine().describe_context()); m_sar = data; }
+void mc88200_device::sctr_w(u32 data) { LOG("sctr_w 0x%08x (%s)\n", data, machine().describe_context()); m_sctr = data; }
+
+void mc88200_device::pfsr_w(u32 data) { LOG("pfsr_w 0x%08x (%s)\n", data, machine().describe_context()); m_pfsr = data & PFSR_WM; }
+void mc88200_device::pfar_w(u32 data) { LOG("pfar_w 0x%08x (%s)\n", data, machine().describe_context()); m_pfar = data; }
+void mc88200_device::sapr_w(u32 data) { LOG("sapr_w 0x%08x (%s)\n", data, machine().describe_context()); m_sapr = data & APR_WM; }
+void mc88200_device::uapr_w(u32 data) { LOG("uapr_w 0x%08x (%s)\n", data, machine().describe_context()); m_uapr = data & APR_WM; }
+
+void mc88200_device::bwp_w(offs_t offset, u32 data)
+{
+ LOG("bwp_w %x,0x%08x (%s)\n", offset, data, machine().describe_context());
+
+ if (data & BATC_V)
+ {
+ for (unsigned i = 0; i < std::size(m_batc); i++)
+ {
+ if ((i != offset) && (m_batc[i] & BATC_V) && BIT(m_batc[i], 19, 13) == BIT(data, 19, 13))
+ {
+ logerror("duplicate batc entry 0x%08x invalidated (%s)\n", data, machine().describe_context());
+ data &= ~BATC_V;
+ }
+ }
+ }
+
+ m_batc[offset] = data;
+}
+
+void mc88200_device::cdp_w(offs_t offset, u32 data)
+{
+ LOG("cdp_w set %d line %d word %d data 0x%08x (%s)\n",
+ BIT(m_sar, 4, 8), offset, BIT(m_sar, 2, 2), data, machine().describe_context());
+
+ m_cache[BIT(m_sar, 4, 8)].line[offset].data[BIT(m_sar, 2, 2)] = data;
+}
+
+void mc88200_device::ctp_w(offs_t offset, u32 data)
+{
+ LOG("ctp_w set %d line %d data 0x%08x (%s)\n",
+ BIT(m_sar, 4, 8), offset, data, machine().describe_context());
+
+ m_cache[BIT(m_sar, 4, 8)].line[offset].tag = data & ~LA_OFS;
+}
+
+void mc88200_device::cssp_w(u32 data)
+{
+ LOG("cssp_w 0x%08x (%s)\n", data, machine().describe_context());
+
+ m_cache[BIT(m_sar, 4, 8)].status = data & CSSP_WM;
+}
+
+// abbreviated, side-effect free address translation for debugger
+bool mc88200_device::translate(int intention, u32 &address, bool supervisor)
+{
+ // select area descriptor
+ u32 const apr = supervisor ? m_sapr : m_uapr;
+ if (apr & APR_TE)
+ {
+ // search block address translation cache
+ for (u32 const &batc : m_batc)
+ {
+ if ((batc & BATC_V) && bool(batc & BATC_S) == supervisor && BIT(address, 19, 13) == BIT(batc, 19, 13))
+ {
+ address = ((batc & BATC_PBA) << 13) | (address & ~BATC_LBA);
+ return true;
+ }
+ }
+
+ // search page address translation cache
+ for (u64 const &patc : m_patc)
+ {
+ if ((patc & PATC_V) && (bool(patc & PATC_S) == supervisor && BIT(address, 12, 20) == BIT(patc, 26, 20)))
+ {
+ address = ((patc & PATC_PFA) << 6) | (address & LA_OFS);
+ return true;
+ }
+ }
+
+ // load and check segment descriptor
+ std::optional<u32> const sgd = mbus_read<u32>((apr & APR_STBA) | ((address & LA_SEG) >> 20));
+ if (!sgd.has_value() || !(sgd.value() & SGD_V) || ((sgd.value() & SGD_SP) && !supervisor))
+ return false;
+
+ // load and check page descriptor
+ std::optional<u32> pgd = mbus_read<u32>((sgd.value() & SGD_PTBA) | ((address & LA_PAG) >> 10));
+ if (!pgd.has_value() || !(pgd.value() & PGD_V) || ((pgd.value() & PGD_SP) && !supervisor))
+ return false;
+
+ address = (pgd.value() & PGD_PFA) | (address & LA_OFS);
+ }
+ else
+ {
+ // apply hard-wired batc entries
+ if (BIT(address, 19, 13) == BIT(m_batc[8], 19, 13))
+ address = ((m_batc[8] & BATC_PBA) << 13) | (address & ~BATC_LBA);
+ else if (BIT(address, 19, 13) == BIT(m_batc[9], 19, 13))
+ address = ((m_batc[9] & BATC_PBA) << 13) | (address & ~BATC_LBA);
+ }
+
+ return true;
+}
+
+std::optional<mc88200_device::translate_result> mc88200_device::translate(u32 virtual_address, bool supervisor, bool write)
+{
+ // select area descriptor
+ u32 const apr = supervisor ? m_sapr : m_uapr;
+ if (apr & APR_TE)
+ {
+ // search block address translation cache
+ for (u32 const &batc : m_batc)
+ {
+ if ((batc & BATC_V) && bool(batc & BATC_S) == supervisor && BIT(virtual_address, 19, 13) == BIT(batc, 19, 13))
+ {
+ if (!write || !(batc & BATC_WP))
+ return translate_result(((batc & BATC_PBA) << 13) | (virtual_address & ~BATC_LBA), batc & BATC_CI, batc & BATC_G, batc & BATC_WT);
+ else
+ {
+ // write violation
+ m_pfsr = PFSR_WV;
+
+ return std::nullopt;
+ }
+ }
+ }
+
+ // search page address translation cache
+ bool patc_hit = false;
+ for (u64 &patc : m_patc)
+ {
+ if ((patc & PATC_V) && (bool(patc & PATC_S) == supervisor && BIT(virtual_address, 12, 20) == BIT(patc, 26, 20)))
+ {
+ if (!write || !(patc & PATC_WP))
+ {
+ if (!write || (patc & PATC_M))
+ return translate_result(((patc & PATC_PFA) << 6) | (virtual_address & LA_OFS), patc & PATC_CI, patc & PATC_G, patc & PATC_WT);
+
+ patc |= PATC_M;
+ patc_hit = true;
+ break;
+ }
+ else
+ {
+ // write violation
+ m_pfsr = PFSR_WV;
+
+ return std::nullopt;
+ }
+ }
+ }
+
+ // load and check segment descriptor
+ std::optional<u32> const sgd = mbus_read<u32>((apr & APR_STBA) | ((virtual_address & LA_SEG) >> 20));
+ if (!sgd.has_value())
+ return std::nullopt;
+ if (!(sgd.value() & SGD_V))
+ {
+ m_pfsr = PFSR_SF;
+ m_pfar = (apr & APR_STBA) | ((virtual_address & LA_SEG) >> 20);
+
+ return std::nullopt;
+ }
+ if ((sgd.value() & SGD_SP) && !supervisor)
+ {
+ m_pfsr = PFSR_SV;
+ m_pfar = (apr & APR_STBA) | ((virtual_address & LA_SEG) >> 20);
+
+ return std::nullopt;
+ }
+
+ // load and check page descriptor
+ std::optional<u32> pgd = mbus_read<u32>((sgd.value() & SGD_PTBA) | ((virtual_address & LA_PAG) >> 10));
+ if (!pgd.has_value())
+ return std::nullopt;
+ if (!(pgd.value() & PGD_V))
+ {
+ m_pfsr = PFSR_PF;
+ m_pfar = (sgd.value() & SGD_PTBA) | ((virtual_address & LA_PAG) >> 10);
+
+ return std::nullopt;
+ }
+ if ((pgd.value() & PGD_SP) && !supervisor)
+ {
+ m_pfsr = PFSR_SV;
+ m_pfar = (sgd.value() & SGD_PTBA) | ((virtual_address & LA_PAG) >> 10);
+
+ return std::nullopt;
+ }
+
+ // check write protect
+ if (write && ((sgd.value() | pgd.value()) & PGD_WP))
+ {
+ m_pfsr = PFSR_WV;
+ return std::nullopt;
+ }
+
+ // update page descriptor used and modified bits
+ if (!(pgd.value() & PGD_U) || (write && !(pgd.value() & PGD_M)))
+ {
+ pgd.value() |= (write ? PGD_M : 0) | PGD_U;
+
+ if (!mbus_write((sgd.value() & SGD_PTBA) | ((virtual_address & LA_PAG) >> 10), pgd.value()))
+ return std::nullopt;
+ }
+
+ if (!patc_hit)
+ {
+ // create patc entry (lpa,pfa,s,wt,g,ci,m,wp)
+ m_patc[m_patc_ptr++] = PATC_V | (u64(virtual_address & ~LA_OFS) << 14) | ((pgd.value() & PGD_PFA) >> 6) | (supervisor ? PATC_S : 0) | bitswap<u64>(apr | sgd.value() | pgd.value(), 9, 7, 6, 4, 2);
+ if (m_patc_ptr == std::size(m_patc))
+ m_patc_ptr = 0;
+ }
+
+ return translate_result((pgd.value() & PGD_PFA) | (virtual_address & LA_OFS),
+ (apr | sgd.value() | pgd.value()) & PGD_CI,
+ (apr | sgd.value() | pgd.value()) & PGD_G,
+ (apr | sgd.value() | pgd.value()) & PGD_WT);
+ }
+ else
+ {
+ /*
+ * The user manual states that the hardwired BATC entries are used in
+ * supervisor mode even when translation is disabled.
+ *
+ * Despite statements indicating that CMMU control space should be part
+ * of the supervisor address space, the MVME181 firmware "Cache Inhibit
+ * Bits" diagnostic expects that CMMU registers also be accessible from
+ * user mode when translation is disabled.
+ *
+ * The following logic assumes that the hardwired entries are applied
+ * when translation is disabled without regard to the active mode,
+ * ensuring cache inhibit is activated.
+ */
+ for (unsigned i = 8; i < 10; i++)
+ if (BIT(virtual_address, 19, 13) == BIT(m_batc[i], 19, 13))
+ return translate_result(((m_batc[i] & BATC_PBA) << 13) | (virtual_address & ~BATC_LBA), m_batc[i] & BATC_CI, m_batc[i] & BATC_G, m_batc[i] & BATC_WT);
+
+ return translate_result(virtual_address, apr & APR_CI, apr & APR_G, apr & APR_WT);
+ }
+}
+
+void mc88200_device::cache_set::set_mru(unsigned const line)
+{
+ static const struct
+ {
+ u32 clr;
+ u32 set;
+ }
+ flags[] =
+ {
+ { CSSP_L3 | CSSP_L1 | CSSP_L0, 0 },
+ { CSSP_L4 | CSSP_L2, CSSP_L0 },
+ { CSSP_L5, CSSP_L2 | CSSP_L1 },
+ { 0, CSSP_L5 | CSSP_L4 | CSSP_L3 },
+ };
+
+ status = (status & ~flags[line].clr) | flags[line].set;
+}
+
+void mc88200_device::cache_set::set_unmodified(unsigned const line)
+{
+ status &= ~(INV << (12 + line * 2));
+}
+
+void mc88200_device::cache_set::set_modified(unsigned const line)
+{
+ status &= ~(INV << (12 + line * 2));
+ status |= EXM << (12 + line * 2);
+}
+
+void mc88200_device::cache_set::set_shared(unsigned const line)
+{
+ status &= ~(INV << (12 + line * 2));
+ status |= SHU << (12 + line * 2);
+}
+
+void mc88200_device::cache_set::set_invalid(unsigned const line)
+{
+ status |= INV << (12 + line * 2);
+}
+
+bool mc88200_device::cache_set::modified(unsigned const line) const
+{
+ return BIT(status, 12 + line * 2, 2) == EXM;
+}
+
+bool mc88200_device::cache_set::shared(unsigned const line) const
+{
+ return BIT(status, 12 + line * 2, 2) == SHU;
+}
+
+bool mc88200_device::cache_set::invalid(unsigned const line) const
+{
+ return BIT(status, 12 + line * 2, 2) == INV;
+}
+
+bool mc88200_device::cache_set::enabled(unsigned const line) const
+{
+ return !BIT(status, 20 + line);
+}
+
+bool mc88200_device::cache_set::cache_line::match_segment(u32 const address) const
+{
+ return BIT(tag, 22, 10) == BIT(address, 22, 10);
+}
+
+bool mc88200_device::cache_set::cache_line::match_page(u32 const address) const
+{
+ return BIT(tag, 12, 20) == BIT(address, 12, 20);
+}
+
+bool mc88200_device::cache_set::cache_line::load_line(mc88200_device &cmmu, u32 const address)
+{
+ for (unsigned i = 0; i < 4; i++)
+ {
+ std::optional<u32> const read = cmmu.mbus_read<u32>(address | i * 4);
+
+ if (read.has_value())
+ data[i] = read.value();
+ else
+ return false;
+ }
+
+ return true;
+}
+
+bool mc88200_device::cache_set::cache_line::copy_back(mc88200_device &cmmu, u32 const address, bool const flush)
+{
+ for (unsigned i = 0; i < 4; i++)
+ if (!cmmu.mbus_write(address | i * 4, data[i], flush))
+ return false;
+
+ return true;
+}
+
+std::optional<unsigned> mc88200_device::cache_replace(cache_set const &cs)
+{
+ // check for enabled invalid lines
+ for (unsigned l = 0; l < std::size(cs.line); l++)
+ if (cs.enabled(l) && cs.invalid(l))
+ return l;
+
+ /*
+ * This table encodes the cache line usage sequence for each combination of
+ * LRU flags. A zero value indicates an invalid flag combination, otherwise
+ * the two most-significant bits correspond to the most recently-used line
+ * and the two least-significant bits correspond to the least recently-used.
+ */
+ static u8 const usage_table[] =
+ {
+ 0x1b, 0x4b, 0x00, 0x63, 0x27, 0x00, 0x87, 0x93, // 00-07
+ 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x9c, // 08-0f
+ 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x8d, 0x00, // 10-17
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb4, // 18-1f
+ 0x1e, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20-27
+ 0x00, 0x72, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, // 28-2f
+ 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, // 30-37
+ 0xc6, 0xd2, 0x00, 0xd8, 0xc9, 0x00, 0xe1, 0xe4, // 38-3f
+ };
+
+ u8 const usage = usage_table[BIT(cs.status, 24, 6)];
+ if (usage)
+ {
+ // find least-recently used enabled line
+ for (unsigned i = 0; i < 4; i++)
+ {
+ unsigned const l = BIT(usage, i * 2, 2);
+
+ if (cs.enabled(i))
+ return l;
+ }
+ }
+
+ // invalid flags or no enabled lines
+ return std::nullopt;
+}
+
+void mc88200_device::cache_flush(unsigned const start, unsigned const limit, match_function match, bool const copyback, bool const invalidate)
+{
+ for (unsigned s = start; s < limit; s++)
+ {
+ cache_set &cs = m_cache[s];
+
+ for (unsigned l = 0; l < std::size(cs.line); l++)
+ {
+ if (!match || std::invoke(match, cs.line[l], m_sar))
+ {
+ // copy back
+ if (copyback && cs.modified(l))
+ if (!cs.line[l].copy_back(*this, cs.line[l].tag | (s << 4), true))
+ return;
+
+ // invalidate
+ if (invalidate)
+ cs.set_invalid(l);
+ }
+ }
+ }
+}
+
+template <typename T> std::optional<T> mc88200_device::read(u32 virtual_address, bool supervisor)
+{
+ std::optional<mc88200_device::translate_result> result = translate(virtual_address, supervisor, false);
+ if (!result.has_value())
+ return std::nullopt;
+
+ u32 const physical_address = result.value().address;
+ if (!result.value().ci)
+ {
+ unsigned const s = BIT(physical_address, 4, 8);
+ cache_set &cs = m_cache[s];
+
+ for (unsigned l = 0; l < std::size(cs.line); l++)
+ {
+ // cache line hit: tag match, enabled, not invalid
+ if (cs.line[l].match_page(physical_address) && cs.enabled(l) && !cs.invalid(l))
+ {
+ // set most recently used
+ cs.set_mru(l);
+
+ // return data
+ u32 const data = cs.line[l].data[BIT(physical_address, 2, 2)];
+
+ switch (sizeof(T))
+ {
+ case 1: return T(data >> (24 - (physical_address & 3) * 8));
+ case 2: return T(data >> (16 - (physical_address & 3) * 8));
+ case 4: return T(data);
+ }
+ }
+ }
+
+ // select cache line for replacement
+ std::optional<unsigned> const l = cache_replace(cs);
+
+ if (l.has_value())
+ {
+ // copy back modified line
+ if (cs.modified(l.value()))
+ if (!cs.line[l.value()].copy_back(*this, cs.line[l.value()].tag | (s << 4)))
+ return false;
+
+ // mark line invalid
+ cs.set_invalid(l.value());
+
+ // update tag
+ cs.line[l.value()].tag = physical_address & ~LA_OFS;
+
+ // load line from memory
+ if (!cs.line[l.value()].load_line(*this, physical_address & 0xfffffff0U))
+ return false;
+
+ // mark line shared unmodified
+ cs.set_shared(l.value());
+
+ // set most recently used
+ cs.set_mru(l.value());
+
+ // return data
+ u32 const data = cs.line[l.value()].data[BIT(physical_address, 2, 2)];
+
+ switch (sizeof(T))
+ {
+ case 1: return T(data >> (24 - (physical_address & 3) * 8));
+ case 2: return T(data >> (16 - (physical_address & 3) * 8));
+ case 4: return T(data);
+ }
+ }
+ }
+
+ return mbus_read<T>(physical_address);
+}
+
+template <typename T> bool mc88200_device::write(u32 virtual_address, T data, bool supervisor)
+{
+ std::optional<mc88200_device::translate_result> result = translate(virtual_address, supervisor, true);
+ if (!result.has_value())
+ return false;
+
+ u32 const physical_address = result.value().address;
+ if (!result.value().ci)
+ {
+ unsigned const s = BIT(physical_address, 4, 8);
+ cache_set &cs = m_cache[s];
+
+ for (unsigned l = 0; l < std::size(cs.line); l++)
+ {
+ // cache line hit: tag match, enabled, not invalid
+ if (cs.line[l].match_page(physical_address) && cs.enabled(l) && !cs.invalid(l))
+ {
+ // write data to cache
+ u32 &cache_data = cs.line[l].data[BIT(physical_address, 2, 2)];
+ switch (sizeof(T))
+ {
+ case 1: cache_data = (cache_data & ~(0x000000ffU << (24 - (physical_address & 3) * 8))) | (u32(data) << (24 - (physical_address & 3) * 8)); break;
+ case 2: cache_data = (cache_data & ~(0x0000ffffU << (16 - (physical_address & 3) * 8))) | (u32(data) << (16 - (physical_address & 3) * 8)); break;
+ case 4: cache_data = data; break;
+ }
+
+ // set most recently used
+ cs.set_mru(l);
+
+ // write data to memory
+ if (result.value().wt || result.value().g)
+ if (!mbus_write(physical_address, data))
+ return false;
+
+ // update line status
+ if (cs.shared(l))
+ {
+ if (result.value().g)
+ cs.set_unmodified(l);
+ else if (!result.value().wt)
+ cs.set_modified(l);
+ }
+ else
+ cs.set_modified(l);
+
+ return true;
+ }
+ }
+
+ // select cache line for replacement
+ std::optional<unsigned> const l = cache_replace(cs);
+
+ if (l.has_value())
+ {
+ // copy back modified line
+ if (cs.modified(l.value()))
+ if (!cs.line[l.value()].copy_back(*this, cs.line[l.value()].tag | (s << 4)))
+ return false;
+
+ // mark line invalid
+ cs.set_invalid(l.value());
+
+ // load line from memory
+ if (!cs.line[l.value()].load_line(*this, physical_address & 0xfffffff0U))
+ return false;
+ }
+
+ // write data to memory
+ if (!mbus_write(physical_address, data))
+ return false;
+
+ if (l.has_value())
+ {
+ // update tag
+ cs.line[l.value()].tag = physical_address & ~LA_OFS;
+
+ // write data into cache
+ u32 &cache_data = cs.line[l.value()].data[BIT(physical_address, 2, 2)];
+ switch (sizeof(T))
+ {
+ case 1: cache_data = (cache_data & ~(0x000000ffU << (24 - (physical_address & 3) * 8))) | (u32(data) << (24 - (physical_address & 3) * 8)); break;
+ case 2: cache_data = (cache_data & ~(0x0000ffffU << (16 - (physical_address & 3) * 8))) | (u32(data) << (16 - (physical_address & 3) * 8)); break;
+ case 4: cache_data = data; break;
+ }
+
+ // mark line exclusive unmodified
+ cs.set_unmodified(l.value());
+
+ // set most recently used
+ cs.set_mru(l.value());
+ }
+
+ return true;
+ }
+
+ return mbus_write(result.value().address, data);
+}
+
+template std::optional<u8> mc88200_device::read(u32 virtual_address, bool supervisor);
+template std::optional<u16> mc88200_device::read(u32 virtual_address, bool supervisor);
+template std::optional<u32> mc88200_device::read(u32 virtual_address, bool supervisor);
+
+template bool mc88200_device::write(u32 virtual_address, u8 data, bool supervisor);
+template bool mc88200_device::write(u32 virtual_address, u16 data, bool supervisor);
+template bool mc88200_device::write(u32 virtual_address, u32 data, bool supervisor);
+
+template <typename T> std::optional<T> mc88200_device::mbus_read(u32 address)
+{
+ std::optional<T> data;
+
+ switch (sizeof(T))
+ {
+ case 1: data = m_mbus->read_byte(address); break;
+ case 2: data = m_mbus->read_word(address); break;
+ case 4: data = m_mbus->read_dword(address); break;
+ }
+
+ if (m_bus_error)
+ {
+ if (!machine().side_effects_disabled())
+ {
+ m_bus_error = false;
+ m_pfar = address;
+ m_pfsr = PFSR_BE;
+ }
+ data = std::nullopt;
+ }
+
+ return data;
+}
+
+template <typename T> bool mc88200_device::mbus_write(u32 address, T data, bool flush)
+{
+ switch (sizeof(T))
+ {
+ case 1: m_mbus->write_byte(address, data); break;
+ case 2: m_mbus->write_word(address, data); break;
+ case 4: m_mbus->write_dword(address, data); break;
+ }
+
+ if (m_bus_error)
+ {
+ m_bus_error = false;
+ if (!flush)
+ {
+ m_pfar = address;
+ m_pfsr = PFSR_BE;
+ }
+ else
+ {
+ m_sar = address;
+ m_ssr |= SSR_BE;
+ }
+
+ return false;
+ }
+ else
+ return true;
+}
diff --git a/src/devices/machine/mc88200.h b/src/devices/machine/mc88200.h
new file mode 100644
index 00000000000..813bce64e13
--- /dev/null
+++ b/src/devices/machine/mc88200.h
@@ -0,0 +1,141 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_MC88200_H
+#define MAME_MACHINE_MC88200_H
+
+#pragma once
+
+class mc88200_device
+ : public device_t
+{
+public:
+ mc88200_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, u8 id = 0);
+
+ template <typename T> void set_mbus(T &&tag, int spacenum) { m_mbus.set_tag(std::forward<T>(tag), spacenum); }
+
+ bool translate(int intention, u32 &address, bool supervisor);
+
+ template <typename T> std::optional<T> read(u32 virtual_address, bool supervisor);
+ template <typename T> bool write(u32 virtual_address, T data, bool supervisor);
+ void bus_error_w(int state) { if (!machine().side_effects_disabled()) m_bus_error = true; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void map(address_map &map);
+
+ u32 idr_r() { return m_idr; }
+ u32 scr_r() { return m_scr; }
+ u32 ssr_r() { return m_ssr; }
+ u32 sar_r() { return m_sar; }
+ u32 sctr_r() { return m_sctr; }
+
+ u32 pfsr_r() { return m_pfsr; }
+ u32 pfar_r() { return m_pfar; }
+ u32 sapr_r() { return m_sapr; }
+ u32 uapr_r() { return m_uapr; }
+
+ u32 cdp_r(offs_t offset) { return m_cache[BIT(m_sar, 4, 8)].line[offset].data[BIT(m_sar, 2, 2)]; }
+ u32 ctp_r(offs_t offset) { return m_cache[BIT(m_sar, 4, 8)].line[offset].tag; }
+ u32 cssp_r() { return m_cache[BIT(m_sar, 4, 8)].status; }
+
+ void idr_w(u32 data);
+ void scr_w(u32 data);
+ void ssr_w(u32 data);
+ void sar_w(u32 data);
+ void sctr_w(u32 data);
+
+ void pfsr_w(u32 data);
+ void pfar_w(u32 data);
+ void sapr_w(u32 data);
+ void uapr_w(u32 data);
+
+ void bwp_w(offs_t offset, u32 data);
+ void cdp_w(offs_t offset, u32 data);
+ void ctp_w(offs_t offset, u32 data);
+ void cssp_w(u32 data);
+
+ struct translate_result
+ {
+ translate_result(u32 address, bool ci, bool g, bool wt)
+ : address(address)
+ , ci(ci)
+ , g(g)
+ , wt(wt)
+ {}
+
+ u32 const address;
+ bool const ci; // cache inhibit
+ bool const g; // global
+ bool const wt; // writethrough
+ };
+ std::optional<translate_result> translate(u32 virtual_address, bool supervisor, bool write);
+
+ struct cache_set
+ {
+ void set_mru(unsigned const line);
+
+ void set_unmodified(unsigned const line);
+ void set_modified(unsigned const line);
+ void set_shared(unsigned const line);
+ void set_invalid(unsigned const line);
+
+ bool modified(unsigned const line) const;
+ bool shared(unsigned const line) const;
+ bool invalid(unsigned const line) const;
+
+ bool enabled(unsigned const line) const;
+
+ u32 status;
+
+ struct cache_line
+ {
+ bool match_segment(u32 const address) const;
+ bool match_page(u32 const address) const;
+
+ bool load_line(mc88200_device &cmmu, u32 const address);
+ bool copy_back(mc88200_device &cmmu, u32 const address, bool const flush = false);
+
+ u32 tag;
+ u32 data[4];
+ }
+ line[4];
+ };
+ typedef bool (mc88200_device::cache_set::cache_line::* match_function)(u32 const) const;
+
+ std::optional<unsigned> cache_replace(cache_set const &cs);
+ void cache_flush(unsigned const start, unsigned const limit, match_function match, bool const copyback, bool const invalidate);
+
+ template <typename T> std::optional<T> mbus_read(u32 address);
+ template <typename T> bool mbus_write(u32 address, T data, bool flush = false);
+
+private:
+ required_address_space m_mbus;
+
+ u32 m_idr; // identification register
+ u32 m_scr; // system command register
+ u32 m_ssr; // system status register
+ u32 m_sar; // system address register
+ u32 m_sctr; // system control register
+ u32 m_pfsr; // p bus fault status register
+ u32 m_pfar; // p bus fault address register
+ u32 m_sapr; // supervisor area pointer register
+ u32 m_uapr; // user area pointer register
+
+ u32 m_batc[10]; // block address translation cache
+ u64 m_patc[56]; // page address translation cache
+ u32 m_patc_ptr;
+
+ bool m_bus_error;
+
+ static constexpr unsigned CACHE_SETS = 256;
+ std::unique_ptr<cache_set[]> m_cache; // data cache
+
+ u32 const m_id;
+};
+
+DECLARE_DEVICE_TYPE(MC88200, mc88200_device)
+
+#endif // MAME_MACHINE_MC88200_H
diff --git a/src/devices/machine/mccs1850.cpp b/src/devices/machine/mccs1850.cpp
index 7422565b53f..af9edbddecd 100644
--- a/src/devices/machine/mccs1850.cpp
+++ b/src/devices/machine/mccs1850.cpp
@@ -18,6 +18,8 @@
#include "emu.h"
#include "mccs1850.h"
+#include "multibyte.h"
+
//#define VERBOSE 0
#include "logmacro.h"
@@ -105,7 +107,7 @@ DEFINE_DEVICE_TYPE(MCCS1850, mccs1850_device, "mccs1850", "MCCS1850 RTC")
//**************************************************************************
-// INLINE HELPERS
+// DEVICE FUNCTIONS
//**************************************************************************
//-------------------------------------------------
@@ -131,8 +133,7 @@ inline void mccs1850_device::check_interrupt()
m_ram[REGISTER_STATUS] &= ~STATUS_IT;
}
- if(!int_cb.isnull())
- int_cb(interrupt);
+ int_cb(interrupt);
}
@@ -144,8 +145,7 @@ inline void mccs1850_device::set_pse_line(bool state)
{
m_pse = state;
- if(!pse_cb.isnull())
- pse_cb(m_pse);
+ pse_cb(m_pse);
}
@@ -160,10 +160,7 @@ inline uint8_t mccs1850_device::read_register(offs_t offset)
case REGISTER_COUNTER_LATCH:
case REGISTER_COUNTER_LATCH+3: // Required by the NeXT power on test
// load counter value into latch
- m_ram[REGISTER_COUNTER_LATCH] = m_counter >> 24;
- m_ram[REGISTER_COUNTER_LATCH + 1] = m_counter >> 16;
- m_ram[REGISTER_COUNTER_LATCH + 2] = m_counter >> 8;
- m_ram[REGISTER_COUNTER_LATCH + 3] = m_counter;
+ put_u32be(&m_ram[REGISTER_COUNTER_LATCH], m_counter);
break;
case REGISTER_TEST_1:
@@ -247,9 +244,9 @@ inline void mccs1850_device::write_register(offs_t offset, uint8_t data)
// advance_seconds -
//-------------------------------------------------
-inline void mccs1850_device::advance_seconds()
+TIMER_CALLBACK_MEMBER(mccs1850_device::advance_seconds)
{
- uint32_t alarm = (m_ram[REGISTER_ALARM_LATCH] << 24) | (m_ram[REGISTER_ALARM_LATCH + 1] << 16) | (m_ram[REGISTER_ALARM_LATCH + 2] << 8) | m_ram[REGISTER_ALARM_LATCH + 3];
+ uint32_t alarm = get_u32be(&m_ram[REGISTER_ALARM_LATCH]);
m_counter++;
@@ -318,13 +315,8 @@ void mccs1850_device::rtc_clock_updated(int year, int month, int day, int day_of
void mccs1850_device::device_start()
{
- // resolve callbacks
- int_cb.resolve();
- pse_cb.resolve();
- nuc_cb.resolve();
-
// allocate timers
- m_clock_timer = timer_alloc(TIMER_CLOCK);
+ m_clock_timer = timer_alloc(FUNC(mccs1850_device::advance_seconds), this);
m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
// state saving
@@ -356,21 +348,6 @@ void mccs1850_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void mccs1850_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch (id)
- {
- case TIMER_CLOCK:
- advance_seconds();
- break;
- }
-}
-
-
-//-------------------------------------------------
// nvram_default - called to initialize NVRAM to
// its default state
//-------------------------------------------------
@@ -394,9 +371,10 @@ void mccs1850_device::nvram_default()
// .nv file
//-------------------------------------------------
-void mccs1850_device::nvram_read(emu_file &file)
+bool mccs1850_device::nvram_read(util::read_stream &file)
{
- file.read(m_ram, RAM_SIZE);
+ auto const [err, actual] = read(file, m_ram, RAM_SIZE);
+ return !err && (actual == RAM_SIZE);
}
@@ -405,9 +383,10 @@ void mccs1850_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void mccs1850_device::nvram_write(emu_file &file)
+bool mccs1850_device::nvram_write(util::write_stream &file)
{
- file.write(m_ram, RAM_SIZE);
+ auto const [err, actual] = write(file, m_ram, RAM_SIZE);
+ return !err;
}
@@ -415,7 +394,7 @@ void mccs1850_device::nvram_write(emu_file &file)
// ce_w - chip enable write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mccs1850_device::ce_w )
+void mccs1850_device::ce_w(int state)
{
m_ce = state;
@@ -431,7 +410,7 @@ WRITE_LINE_MEMBER( mccs1850_device::ce_w )
// sck_w - serial clock write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mccs1850_device::sck_w )
+void mccs1850_device::sck_w(int state)
{
if (!m_ce) return;
@@ -511,7 +490,7 @@ WRITE_LINE_MEMBER( mccs1850_device::sck_w )
// sdo_r - serial data out read
//-------------------------------------------------
-READ_LINE_MEMBER( mccs1850_device::sdo_r )
+int mccs1850_device::sdo_r()
{
if (!m_ce || BIT(m_address, 7))
{
@@ -529,7 +508,7 @@ READ_LINE_MEMBER( mccs1850_device::sdo_r )
// sdi_w - serial data in write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mccs1850_device::sdi_w )
+void mccs1850_device::sdi_w(int state)
{
m_sdi = state;
}
@@ -539,7 +518,7 @@ WRITE_LINE_MEMBER( mccs1850_device::sdi_w )
// pwrsw_w - power switch write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mccs1850_device::pwrsw_w )
+void mccs1850_device::pwrsw_w(int state)
{
if (!state)
{
@@ -559,7 +538,7 @@ WRITE_LINE_MEMBER( mccs1850_device::pwrsw_w )
// por_w - power on reset write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mccs1850_device::por_w )
+void mccs1850_device::por_w(int state)
{
if (!state)
{
@@ -572,7 +551,7 @@ WRITE_LINE_MEMBER( mccs1850_device::por_w )
// test_w - test mode write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mccs1850_device::test_w )
+void mccs1850_device::test_w(int state)
{
if (state)
{
diff --git a/src/devices/machine/mccs1850.h b/src/devices/machine/mccs1850.h
index 62b7f5d5afc..3dd6b0173e6 100644
--- a/src/devices/machine/mccs1850.h
+++ b/src/devices/machine/mccs1850.h
@@ -43,36 +43,33 @@ public:
auto pse_wr_callback() { return pse_cb.bind(); }
auto nuc_wr_callback() { return nuc_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER( ce_w );
- DECLARE_WRITE_LINE_MEMBER( sck_w );
- DECLARE_READ_LINE_MEMBER( sdo_r );
- DECLARE_WRITE_LINE_MEMBER( sdi_w );
- DECLARE_WRITE_LINE_MEMBER( pwrsw_w );
- DECLARE_WRITE_LINE_MEMBER( por_w );
- DECLARE_WRITE_LINE_MEMBER( test_w );
+ void ce_w(int state);
+ void sck_w(int state);
+ int sdo_r();
+ void sdi_w(int state);
+ void pwrsw_w(int state);
+ void por_w(int state);
+ void test_w(int state);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
// 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) override;
private:
- inline void check_interrupt();
- inline void set_pse_line(bool state);
- inline uint8_t read_register(offs_t offset);
- inline void write_register(offs_t offset, uint8_t data);
- inline void advance_seconds();
-
- static const device_timer_id TIMER_CLOCK = 0;
+ void check_interrupt();
+ void set_pse_line(bool state);
+ uint8_t read_register(offs_t offset);
+ void write_register(offs_t offset, uint8_t data);
+ TIMER_CALLBACK_MEMBER(advance_seconds);
devcb_write_line int_cb, pse_cb, nuc_cb;
diff --git a/src/devices/machine/mcf5206e.cpp b/src/devices/machine/mcf5206e.cpp
index 776223dc530..7d1c9d5f0fd 100644
--- a/src/devices/machine/mcf5206e.cpp
+++ b/src/devices/machine/mcf5206e.cpp
@@ -7,10 +7,10 @@
#include "emu.h"
#include "mcf5206e.h"
-#define LOG_DEBUG (0U << 0)
-#define LOG_INVALID (0U << 1)
-#define LOG_TIMER (0U << 2)
-
+#define LOG_DEBUG (1U << 1)
+#define LOG_INVALID (1U << 2)
+#define LOG_TIMER (1U << 3)
+#define VERBOSE (0)
#include "logmacro.h"
void mcf5206e_peripheral_device::coldfire_regs_map(address_map &map)
@@ -661,7 +661,7 @@ TIMER_CALLBACK_MEMBER(mcf5206e_peripheral_device::timer1_callback)
// technically we should do the vector check in the IRQ callback as well as various checks based on the IRQ masks before asserting the interrupt
if (ICR & 0x80) // AVEC
{
- if (!(m_IMR & 0x0200)) m_cpu->set_input_line((ICR&0x1c)>>2, HOLD_LINE);
+ if (!(m_IMR & 0x0200)) m_maincpu->set_input_line((ICR&0x1c)>>2, HOLD_LINE);
}
LOGMASKED(LOG_TIMER, "timer1_callback\n");
@@ -826,8 +826,8 @@ DEFINE_DEVICE_TYPE(MCF5206E_PERIPHERAL, mcf5206e_peripheral_device, "mcf5206e_pe
mcf5206e_peripheral_device::mcf5206e_peripheral_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, MCF5206E_PERIPHERAL, tag, owner, clock),
device_memory_interface(mconfig, *this),
+ m_maincpu(*this, finder_base::DUMMY_TAG),
m_space_config("coldfire_regs", ENDIANNESS_BIG, 32,10, 0, address_map_constructor(FUNC(mcf5206e_peripheral_device::coldfire_regs_map), this))
-
{
}
@@ -846,7 +846,7 @@ void mcf5206e_peripheral_device::device_start()
{
init_regs(true);
- m_timer1 = machine().scheduler().timer_alloc( timer_expired_delegate( FUNC( mcf5206e_peripheral_device::timer1_callback ), this) );
+ m_timer1 = timer_alloc( FUNC( mcf5206e_peripheral_device::timer1_callback ), this );
save_item(NAME(m_ICR));
save_item(NAME(m_CSAR));
@@ -870,8 +870,6 @@ void mcf5206e_peripheral_device::device_start()
void mcf5206e_peripheral_device::device_reset()
{
- m_cpu = (cpu_device*)machine().device(":maincpu"); // hack. this device should really be attached to a modern CPU core
-
init_regs(false);
m_timer1->adjust(attotime::never);
}
diff --git a/src/devices/machine/mcf5206e.h b/src/devices/machine/mcf5206e.h
index 171620d5f0b..d4ec0dd7980 100644
--- a/src/devices/machine/mcf5206e.h
+++ b/src/devices/machine/mcf5206e.h
@@ -23,6 +23,13 @@ class mcf5206e_peripheral_device : public device_t,
{
public:
// construction/destruction
+ template <typename T>
+ mcf5206e_peripheral_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ : mcf5206e_peripheral_device(mconfig, tag, owner, clock)
+ {
+ m_maincpu.set_tag(std::forward<T>(cpu_tag));
+ }
+
mcf5206e_peripheral_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
uint32_t dev_r(offs_t offset, uint32_t mem_mask = ~0);
@@ -160,7 +167,7 @@ private:
MAX_ICR
};
- cpu_device* m_cpu;
+ required_device<cpu_device> m_maincpu;
address_space_config m_space_config;
diff --git a/src/devices/machine/mdcr.cpp b/src/devices/machine/mdcr.cpp
new file mode 100644
index 00000000000..a4b881a9bd4
--- /dev/null
+++ b/src/devices/machine/mdcr.cpp
@@ -0,0 +1,326 @@
+// license:BSD-3-Clause
+// copyright-holders:Erwin Jansen
+/**********************************************************************
+
+ Philips Mini Digital Cassette Recorder emulation
+
+**********************************************************************/
+
+#include "emu.h"
+#include "mdcr.h"
+#include "formats/p2000t_cas.h"
+
+DEFINE_DEVICE_TYPE(MDCR, mdcr_device, "mdcr", "Philips Mini-DCR")
+
+int mdcr_device::rdc()
+{
+ // According to mdcr spec there is cross talk on the wires when writing,
+ // hence the clock signal is always false when writing.
+ if (m_recording)
+ return false;
+
+ return m_fwd ? m_rdc : m_rda;
+}
+
+int mdcr_device::rda()
+{
+ return m_fwd ? m_rda : m_rdc;
+}
+
+int mdcr_device::bet()
+{
+ return tape_start_or_end();
+}
+
+int mdcr_device::cip()
+{
+ return m_cassette->get_image() != nullptr;
+}
+
+int mdcr_device::wen()
+{
+ return m_cassette->get_image() != nullptr && m_cassette->is_writeable();
+}
+
+void mdcr_device::rev(int state)
+{
+ m_rev = state;
+ if (m_rev)
+ {
+ rewind();
+ }
+
+ if (!m_rev && !m_fwd)
+ {
+ stop();
+ }
+}
+
+void mdcr_device::fwd(int state)
+{
+ m_fwd = state;
+ if (m_fwd)
+ {
+ forward();
+ }
+
+ if (!m_rev && !m_fwd)
+ {
+ stop();
+ }
+}
+
+void mdcr_device::wda(int state)
+{
+ m_wda = state;
+}
+
+void mdcr_device::wdc(int state)
+{
+ if (state)
+ {
+ write_bit(m_wda);
+ };
+}
+
+void mdcr_device::device_add_mconfig(machine_config &config)
+{
+ CASSETTE(config, m_cassette);
+ m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED);
+ m_cassette->set_interface("p2000_cass");
+ m_cassette->set_formats(p2000t_cassette_formats);
+}
+
+mdcr_device::mdcr_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MDCR, tag, owner, clock)
+ , m_rdc_cb(*this)
+ , m_cassette(*this, "cassette")
+ , m_read_timer(nullptr)
+{
+}
+
+void mdcr_device::device_start()
+{
+ m_read_timer = timer_alloc(FUNC(mdcr_device::read_timer_tick), this);
+ m_read_timer->adjust(attotime::from_hz(44100), 0, attotime::from_hz(44100));
+
+ save_item(NAME(m_fwd));
+ save_item(NAME(m_rev));
+ save_item(NAME(m_rdc));
+ save_item(NAME(m_rda));
+ save_item(NAME(m_wda));
+ save_item(NAME(m_recording));
+ save_item(NAME(m_fwd_pulse_time));
+ save_item(NAME(m_last_tape_time));
+ save_item(NAME(m_save_tape_time));
+ // Phase decoder
+ save_item(STRUCT_MEMBER(m_phase_decoder, m_last_signal));
+ save_item(STRUCT_MEMBER(m_phase_decoder, m_needs_sync));
+ save_item(STRUCT_MEMBER(m_phase_decoder, m_bit_queue));
+ save_item(STRUCT_MEMBER(m_phase_decoder, m_bit_place));
+ save_item(STRUCT_MEMBER(m_phase_decoder, m_current_clock));
+ save_item(STRUCT_MEMBER(m_phase_decoder, m_clock_period));
+}
+
+void mdcr_device::device_pre_save()
+{
+ m_save_tape_time = m_cassette->get_position();
+}
+
+void mdcr_device::device_post_load()
+{
+ m_cassette->seek(m_save_tape_time, SEEK_SET);
+}
+
+TIMER_CALLBACK_MEMBER(mdcr_device::read_timer_tick)
+{
+ if (!m_recording && m_cassette->motor_on())
+ {
+ // Account for moving backwards.
+ auto delay = std::abs(m_cassette->get_position() - m_last_tape_time);
+
+ // Decode the signal using the fake phase decode circuit
+ bool newBit = m_phase_decoder.signal((m_cassette->input() > +0.04), delay);
+ if (newBit)
+ {
+ // Flip rdc
+ m_rdc = !m_rdc;
+ m_rda = m_phase_decoder.pull_bit();
+ }
+ }
+ m_rdc_cb(m_rdc);
+ m_last_tape_time = m_cassette->get_position();
+}
+
+void mdcr_device::write_bit(bool bit)
+{
+ m_recording = true;
+ m_cassette->change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE);
+ m_cassette->output(bit ? +1.0 : -1.0);
+ m_phase_decoder.reset();
+}
+
+void mdcr_device::rewind()
+{
+ m_fwd = false;
+ m_recording = false;
+ m_cassette->set_motor(true);
+ m_cassette->change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE);
+ m_cassette->go_reverse();
+}
+
+void mdcr_device::forward()
+{
+ // A pulse of 1us < T < 20 usec should reset the phase decoder.
+ // See mdcr spec for details.
+ constexpr double RESET_PULSE_TIMING = 2.00e-05;
+ auto now = machine().time().as_double();
+ auto pulse_delay = now - m_fwd_pulse_time;
+ m_fwd_pulse_time = now;
+
+ if (pulse_delay < RESET_PULSE_TIMING)
+ {
+ m_phase_decoder.reset();
+ }
+
+ m_fwd = true;
+ m_cassette->set_motor(true);
+ m_cassette->change_state(m_recording ? CASSETTE_RECORD : CASSETTE_PLAY, CASSETTE_MASK_UISTATE);
+ m_cassette->go_forward();
+}
+
+void mdcr_device::stop()
+{
+ m_cassette->change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE);
+ m_cassette->set_motor(false);
+}
+
+bool mdcr_device::tape_start_or_end()
+{
+ auto pos = m_cassette->get_position();
+ auto bet = m_cassette->motor_on() && (pos <= 0 || pos >= m_cassette->get_length());
+
+ // Reset phase decoder at tape start/end.
+ if (bet)
+ m_phase_decoder.reset();
+
+ return bet;
+}
+
+void p2000_mdcr_devices(device_slot_interface &device)
+{
+ device.option_add("mdcr", MDCR);
+}
+
+//
+// phase_decoder
+//
+
+mdcr_device::phase_decoder::phase_decoder(double tolerance)
+: m_tolerance(tolerance)
+{
+ reset();
+}
+
+bool mdcr_device::phase_decoder::pull_bit()
+{
+ if (m_bit_place == 0)
+ return false;
+ auto res = BIT(m_bit_queue, 0);
+ m_bit_place--;
+ m_bit_queue >>= 1;
+ return res;
+}
+
+bool mdcr_device::phase_decoder::signal(bool state, double delay)
+{
+ m_current_clock += delay;
+ if (state == m_last_signal)
+ {
+ if (m_needs_sync == 0 && m_current_clock > m_clock_period &&
+ !within_tolerance(m_current_clock, m_clock_period))
+ {
+ // We might be at the last bit in a sequence, meaning we
+ // are only getting the reference signal for a while.
+ // so we produce one last clock signal.
+ reset();
+ return true;
+ }
+ return false;
+ }
+
+ // A transition happened!
+ m_last_signal = state;
+ if (m_needs_sync > 0)
+ {
+ // We have not yet determined our clock period.
+ return sync_signal(state);
+ }
+
+ // We are within bounds of the current clock
+ if (within_tolerance(m_current_clock, m_clock_period))
+ {
+ add_bit(state);
+ return true;
+ };
+
+ // We went out of sync, our clock is wayyy out of bounds.
+ if (m_current_clock > m_clock_period)
+ reset();
+
+ // We are likely halfway in our clock signal..
+ return false;
+};
+
+void mdcr_device::phase_decoder::reset()
+{
+ m_last_signal = false;
+ m_current_clock = {};
+ m_clock_period = {};
+ m_needs_sync = SYNCBITS;
+}
+
+void mdcr_device::phase_decoder::add_bit(bool bit)
+{
+ if (bit)
+ m_bit_queue |= bit << m_bit_place;
+ else
+ m_bit_queue &= ~(bit << m_bit_place);
+
+ if (m_bit_place <= QUEUE_DELAY)
+ m_bit_place++;
+
+ m_current_clock = {};
+}
+
+bool mdcr_device::phase_decoder::sync_signal(bool state)
+{
+ m_needs_sync--;
+ if (m_needs_sync == SYNCBITS - 1)
+ {
+ // We can only synchronize when we go up
+ // on the first bit.
+ if (state)
+ add_bit(true);
+ return false;
+ }
+ if (m_clock_period != 0 && !within_tolerance(m_current_clock, m_clock_period))
+ {
+ // Clock is way off!
+ reset();
+ return false;
+ }
+
+ // We've derived a clock period, we will use the average.
+ auto div = SYNCBITS - m_needs_sync - 1;
+ m_clock_period = ((div - 1) * m_clock_period + m_current_clock) / div;
+ add_bit(state);
+ return true;
+}
+
+// y * (1 - tolerance) < x < y * (1 + tolerance)
+bool mdcr_device::phase_decoder::within_tolerance(double x, double y)
+{
+ assert(m_tolerance > 0 && m_tolerance < 1);
+ return (y * (1 - m_tolerance)) < x && x < (y * (1 + m_tolerance));
+}
diff --git a/src/devices/machine/mdcr.h b/src/devices/machine/mdcr.h
new file mode 100644
index 00000000000..64053454a34
--- /dev/null
+++ b/src/devices/machine/mdcr.h
@@ -0,0 +1,181 @@
+// license:BSD-3-Clause
+// copyright-holders:Erwin Jansen
+/**********************************************************************
+
+ Philips Mini Digital Cassette Recorder Emulation
+
+**********************************************************************
+
+ +12V 1 8 !WCD
+ OV (signal) 2 9 !REV
+ OV (power) 3 A !FWD
+ GND 4 B RDC
+ !WDA 6 C !RDA
+ !BET 7 D !CIP
+ E !WEN
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_MDCR_H
+#define MAME_MACHINE_MDCR_H
+
+#pragma once
+
+#include "imagedev/cassette.h"
+
+/// \brief Models a MCR220 Micro Cassette Recorder
+///
+/// Detailed documentation on the device can be found in this repository:
+/// https://github.com/p2000t/documentation/tree/master/hardware
+///
+/// This device was built in the P2000t and was used as tape storage.
+/// It used mini-cassettes that were also used in dictation devices.
+/// The P2000t completely controls this device without user intervention.
+class mdcr_device : public device_t
+{
+public:
+ mdcr_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0);
+
+ /// \brief The read clock, switches state when a bit is available.
+ ///
+ /// This is the read clock. The read clock is a flip flop that switches
+ /// whenever a new bit is available on rda. The original flips every 167us
+ /// This system flips at 154 / 176 usec, which is within the tolerance for
+ /// the rom and system diagnostics.
+ ///
+ /// Note that rdc & rda are flipped when the tape is moving in reverse.
+ int rdc();
+
+ /// The current active data bit.
+ int rda();
+
+ /// False indicates we have reached end/beginning of tape
+ int bet();
+
+ /// False if a cassette is in place.
+ int cip();
+
+ /// False when the cassette is write enabled.
+ int wen();
+
+ /// True if we should activate the reverse motor.
+ void rev(int state);
+
+ /// True if we should activate the forward motor.
+ /// Note: A quick pulse (<20usec) will reset the phase decoder.
+ void fwd(int state);
+
+ /// The bit to write to tape. Make sure to set wda after wdc.
+ void wda(int state);
+
+ /// True if the current wda should be written to tape.
+ void wdc(int state);
+
+ auto rdc_cb() { return m_rdc_cb.bind(); }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_pre_save() override;
+ virtual void device_post_load() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ TIMER_CALLBACK_MEMBER(read_timer_tick);
+
+private:
+ devcb_write_line m_rdc_cb;
+
+ /// \brief A Phase Decoder used in a Philips MDCR220 Mini Cassette Recorder
+ ///
+ /// A phase decoder is capable of converting a signal stream into a
+ /// a series of bits that go together with a clock signal. This phase
+ /// decoder is conform to what you would find in an Philips MDCR220
+ ///
+ /// Signals are converted into bits whenever the line signal
+ /// changes from low to high and vice versa on a clock signal.
+ ///
+ /// A transition on a clock boundary from low to high is a 1.
+ /// A transition on a clock boundary from high to low is a 0
+ /// An intermediate transition halfway between the clock boundary
+ /// can occur when there are consecutive 0s or 1s. See the example
+ /// below where the clock is marked by a |
+ ///
+ /// 1 0 1 1 0 0
+ /// RDA: _|----|____|--__|----|__--|__--
+ /// RDC: _|-___|-___|-___|-___|-___|-___
+ /// ^ ^
+ /// |-- clock signal |-- intermediate transition.
+ ///
+ /// This particular phase decoder expects a signal of
+ /// 1010 1010 which is used to derive the clock T.
+ /// after a reset.
+ class phase_decoder
+ {
+ using time_in_seconds = double;
+
+ public:
+ /// Creates a phase decoder with the given tolerance.
+ phase_decoder(double tolerance = 0.15);
+
+ /// Pulls the bit out of the queue.
+ bool pull_bit();
+
+ /// Returns true if a new bit can be read, you can now pull the bit.
+ bool signal(bool state, double delay);
+
+ /// Reset the clock state, the system will now need to resynchronize on 0xAA.
+ void reset();
+
+ private:
+ // add a bit and reset the current clock.
+ void add_bit(bool bit);
+
+ // tries to sync up the signal and calculate the clock period.
+ bool sync_signal(bool state);
+
+ // y * (1 - tolerance) < x < y * (1 + tolerance)
+ bool within_tolerance(double x, double y);
+
+ double m_tolerance;
+
+ static constexpr int SYNCBITS = 7;
+ static constexpr int QUEUE_DELAY = 2;
+
+ public:
+ // Needed for save state.
+ bool m_last_signal{ false };
+ int m_needs_sync{ SYNCBITS };
+ uint8_t m_bit_queue{ 0 };
+ uint8_t m_bit_place{ 0 };
+ time_in_seconds m_current_clock{ 0 };
+ time_in_seconds m_clock_period{ 0 };
+ };
+
+
+ void write_bit(bool bit);
+ void rewind();
+ void forward();
+ void stop();
+ bool tape_start_or_end();
+
+ bool m_fwd{ false };
+ bool m_rev{ false };
+ bool m_rdc{ false };
+ bool m_rda{ false };
+ bool m_wda{ false };
+
+ bool m_recording{ false };
+ double m_fwd_pulse_time{ 0 };
+ double m_last_tape_time{ 0 };
+ double m_save_tape_time{ 0 };
+
+ required_device<cassette_image_device> m_cassette;
+ phase_decoder m_phase_decoder;
+
+ // timers
+ emu_timer *m_read_timer;
+};
+
+
+DECLARE_DEVICE_TYPE(MDCR, mdcr_device)
+
+#endif // MAME_MACHINE_MDCR_H
diff --git a/src/devices/machine/mediagx_cs5530_bridge.cpp b/src/devices/machine/mediagx_cs5530_bridge.cpp
new file mode 100644
index 00000000000..8521d9451fe
--- /dev/null
+++ b/src/devices/machine/mediagx_cs5530_bridge.cpp
@@ -0,0 +1,561 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/**************************************************************************************************
+
+[Cyrix/National Semiconductor/AMD] [MediaGX/Geode] [Cx/CS]5530 bridge implementation (southbridge)
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "mediagx_cs5530_bridge.h"
+
+#include "speaker.h"
+
+#define LOG_MAP (1U << 1) // log full remaps
+
+#define VERBOSE (LOG_GENERAL | LOG_MAP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(MEDIAGX_CS5530_BRIDGE, mediagx_cs5530_bridge_device, "mediagx_cs5530_bridge", "MediaGX CS5530 Bridge")
+
+mediagx_cs5530_bridge_device::mediagx_cs5530_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, MEDIAGX_CS5530_BRIDGE, tag, owner, clock)
+// , m_smi_callback(*this)
+// , m_nmi_callback(*this)
+// , m_stpclk_callback(*this)
+ , m_boot_state_hook(*this)
+ , m_rtcale(*this)
+ , m_rtccs_read(*this, 0xff)
+ , m_rtccs_write(*this)
+ , m_host_cpu(*this, finder_base::DUMMY_TAG)
+ , m_ide(*this, finder_base::DUMMY_TAG)
+ , m_kbdc(*this, finder_base::DUMMY_TAG)
+ , 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_isabus(*this, "isabus")
+ , m_speaker(*this, "speaker")
+{
+}
+
+void mediagx_cs5530_bridge_device::device_add_mconfig(machine_config &config)
+{
+ // 8254-equivalent
+ PIT8254(config, m_pit8254);
+ m_pit8254->set_clk<0>(4772720 / 4); // heartbeat IRQ
+ m_pit8254->out_handler<0>().set(FUNC(mediagx_cs5530_bridge_device::at_pit8254_out0_changed));
+ m_pit8254->set_clk<1>(4772720 / 4); // DRAM refresh
+ m_pit8254->out_handler<1>().set(FUNC(mediagx_cs5530_bridge_device::at_pit8254_out1_changed));
+ m_pit8254->set_clk<2>(4772720 / 4); // PIO port C pin 4, and speaker polling enough
+ m_pit8254->out_handler<2>().set(FUNC(mediagx_cs5530_bridge_device::at_pit8254_out2_changed));
+
+ // 8237-equivalent
+ AM9517A(config, m_dma8237_1, XTAL(14'318'181) / 3);
+ m_dma8237_1->out_hreq_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq0_w));
+ m_dma8237_1->out_eop_callback().set(FUNC(mediagx_cs5530_bridge_device::at_dma8237_out_eop));
+ m_dma8237_1->in_memr_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_dma_read_byte));
+ m_dma8237_1->out_memw_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_dma_write_byte));
+ m_dma8237_1->in_ior_callback<0>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_0_dack_r));
+ m_dma8237_1->in_ior_callback<1>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_1_dack_r));
+ m_dma8237_1->in_ior_callback<2>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_2_dack_r));
+ m_dma8237_1->in_ior_callback<3>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_3_dack_r));
+ m_dma8237_1->out_iow_callback<0>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_0_dack_w));
+ m_dma8237_1->out_iow_callback<1>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_1_dack_w));
+ m_dma8237_1->out_iow_callback<2>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_2_dack_w));
+ m_dma8237_1->out_iow_callback<3>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_3_dack_w));
+ m_dma8237_1->out_dack_callback<0>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack0_w));
+ m_dma8237_1->out_dack_callback<1>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack1_w));
+ m_dma8237_1->out_dack_callback<2>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack2_w));
+ m_dma8237_1->out_dack_callback<3>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack3_w));
+
+ AM9517A(config, m_dma8237_2, XTAL(14'318'181) / 3);
+ m_dma8237_2->out_hreq_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_dma_hrq_changed));
+ m_dma8237_2->in_memr_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_dma_read_word));
+ m_dma8237_2->out_memw_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_dma_write_word));
+ m_dma8237_2->in_ior_callback<1>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_5_dack_r));
+ m_dma8237_2->in_ior_callback<2>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_6_dack_r));
+ m_dma8237_2->in_ior_callback<3>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_7_dack_r));
+ m_dma8237_2->out_iow_callback<1>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_5_dack_w));
+ m_dma8237_2->out_iow_callback<2>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_6_dack_w));
+ m_dma8237_2->out_iow_callback<3>().set(FUNC(mediagx_cs5530_bridge_device::pc_dma8237_7_dack_w));
+ m_dma8237_2->out_dack_callback<0>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack4_w));
+ m_dma8237_2->out_dack_callback<1>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack5_w));
+ m_dma8237_2->out_dack_callback<2>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack6_w));
+ m_dma8237_2->out_dack_callback<3>().set(FUNC(mediagx_cs5530_bridge_device::pc_dack7_w));
+
+ // 8259A-equivalent
+ PIC8259(config, m_pic8259_master);
+ m_pic8259_master->out_int_callback().set_inputline(m_host_cpu, 0);
+ m_pic8259_master->in_sp_callback().set_constant(1);
+ m_pic8259_master->read_slave_ack_callback().set(FUNC(mediagx_cs5530_bridge_device::get_slave_ack));
+
+ PIC8259(config, m_pic8259_slave);
+ m_pic8259_slave->out_int_callback().set(m_pic8259_master, FUNC(pic8259_device::ir2_w));
+ m_pic8259_slave->in_sp_callback().set_constant(0);
+
+ SPEAKER(config, "mono").front_center();
+ SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
+
+ ISA16(config, m_isabus, 0);
+ m_isabus->irq3_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq3_w));
+ m_isabus->irq4_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq4_w));
+ m_isabus->irq5_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq5_w));
+ m_isabus->irq6_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq6_w));
+ m_isabus->irq7_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq7_w));
+ m_isabus->irq2_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq9_w));
+ m_isabus->irq10_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq10_w));
+ m_isabus->irq11_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq11_w));
+ m_isabus->irq12_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq12m_w));
+ m_isabus->irq14_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq14_w));
+ m_isabus->irq15_callback().set(FUNC(mediagx_cs5530_bridge_device::pc_irq15_w));
+ m_isabus->iochck_callback().set(FUNC(mediagx_cs5530_bridge_device::iochck_w));
+}
+
+void mediagx_cs5530_bridge_device::device_config_complete()
+{
+ auto isabus = m_isabus.finder_target();
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_memspace(m_host_cpu, AS_PROGRAM);
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_iospace(m_host_cpu, AS_IO);
+
+ pci_device::device_config_complete();
+}
+
+void mediagx_cs5530_bridge_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ status = 0x0280;
+
+ m_nmi_enabled = false;
+}
+
+void mediagx_cs5530_bridge_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+// map(0x40, 0x42) PCI Function Control
+// map(0x43, 0x43) USB Shadow
+// map(0x44, 0x44) Reset Control
+
+// map(0x50, 0x50) PIT Control/ISA CLK divider
+// map(0x51, 0x51) ISA I/O Recovery Control
+// map(0x52, 0x52) ROM/AT Logic Control
+// map(0x53, 0x53) Alternate CPU Support
+// map(0x5a, 0x5b) Decode Control
+ map(0x5a, 0x5b).lrw8(
+ NAME([this] (offs_t offset) {
+ return m_decode_control[offset];
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_decode_control[offset] = data;
+ remap_cb();
+ })
+ );
+// map(0x5c, 0x5d) PCI Interrupt Steering
+
+// map(0x70, 0x71) GPCS Base Address
+// map(0x72, 0x72) GPCS Control
+
+// map(0x80, 0x83) Power Management Enable
+// map(0x84, 0x87) Second Level Power Management Status Mirror (r/o)
+// map(0x88, 0x89) General Purpose Timer 1 Count/Control
+// map(0x8a, 0x8b) General Purpose Timer 2 Count/Control
+// map(0x8c, 0x8c) IRQ Speedup Timer Count
+// map(0x8d, 0x8d) Video Speedup Timer Count
+// map(0x8e, 0x8e) VGA Timer COunt
+
+// map(0x90, 0x90) GPIO Pin Direction
+// map(0x91, 0x91) GPIO Pin Data
+// map(0x92, 0x92) GPIO Control 1
+// map(0x93, 0x93) Miscellaneous Device Control
+// map(0x94, 0x95) Suspend Modulation OFF/ON Count
+// map(0x96, 0x96) Suspend Configuration
+// map(0x97, 0x97) GPIO Control 2
+
+// map(0x98, 0x99) Primary HDD Idle Timer Count
+// map(0x9a, 0x9b) Floppy Disk Idle Timer Count
+// map(0x9c, 0x9d) Parallel / Serial Idle Timer Count
+// map(0x9e, 0x9f) Keyboard / Mouse Idle Timer Count
+// map(0xa0, 0xa5) User Defined Device # Idle Timer Count
+// map(0xa6, 0xa7) Video Idle Timer Count
+// map(0xa8, 0xa9) Video Overflow Count
+// map(0xac, 0xad) Secondary HDD Idle Timer Count
+// map(0xae, 0xae) CPU Suspend Command (w/o)
+// map(0xaf, 0xaf) Suspend Notebook Command (w/o)
+
+// map(0xb4, 0xb7) Floppy Port Shadows (r/o)
+// map(0xb8, 0xb8) DMA Shadow (r/o)
+// map(0xb9, 0xb9) PIC Shadow (r/o)
+// map(0xba, 0xba) PIT Shadow (r/o)
+// map(0xbb, 0xbb) RTC Index Shadow (r/o)
+// map(0xbc, 0xbc) Clock Stop Control
+
+// map(0xc0, 0xcb) User Defined Device # Base Address
+// map(0xcc, 0xce) User Defined Device # Control
+
+// map(0xd0, 0xd0) Software SMI (w/o)
+// map(0xec, 0xec) Timer Test
+
+// map(0xf4, 0xf7) Second Level Power Management Status
+}
+
+// TODO: keyboard & RTC ports should map thru map_extra subtractive/positive decoding
+void mediagx_cs5530_bridge_device::internal_io_map(address_map &map)
+{
+ map(0x0000, 0x001f).rw("dma8237_1", FUNC(am9517a_device::read), FUNC(am9517a_device::write));
+ map(0x0020, 0x0021).rw("pic8259_master", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ map(0x0040, 0x005f).rw("pit8254", FUNC(pit8254_device::read), FUNC(pit8254_device::write));
+ map(0x0060, 0x0060).rw(m_kbdc, FUNC(kbdc8042_device::port60_r), FUNC(kbdc8042_device::port60_w));
+ map(0x0061, 0x0061).rw(FUNC(mediagx_cs5530_bridge_device::at_portb_r), FUNC(mediagx_cs5530_bridge_device::at_portb_w));
+ map(0x0064, 0x0064).rw(m_kbdc, FUNC(kbdc8042_device::port64_r), FUNC(kbdc8042_device::port64_w));
+ map(0x0070, 0x0070).lw8(
+ NAME([this] (u8 data) {
+ m_nmi_enabled = BIT(data, 7);
+ // TODO: trap write for RTC shadow reg
+ m_rtcale(data);
+ })
+ );
+ map(0x0071, 0x0071).lrw8(
+ NAME([this] () {
+ return m_rtccs_read();
+ }),
+ NAME([this] (u8 data) {
+ m_rtccs_write(data);
+ })
+ );
+ map(0x0080, 0x008f).rw(FUNC(mediagx_cs5530_bridge_device::at_page8_r), FUNC(mediagx_cs5530_bridge_device::at_page8_w));
+ // TODO: port decoding driven by PCI register $52
+ map(0x0092, 0x0092).lrw8(
+ NAME([this] () {
+ //LOG("Fast init $92 read\n");
+ return m_fast_init;
+ }),
+ NAME([this] (u8 data) {
+ LOG("Fast init $92 write %02x\n", data);
+ m_host_cpu->set_input_line(INPUT_LINE_A20, BIT(data, 1));
+ m_fast_init = data;
+ })
+ );
+ map(0x00a0, 0x00a1).rw("pic8259_slave", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ map(0x00c0, 0x00df).rw(FUNC(mediagx_cs5530_bridge_device::at_dma8237_2_r), FUNC(mediagx_cs5530_bridge_device::at_dma8237_2_w));
+// map(0x04d0, 0x04d1).rw(FUNC(mediagx_cs5530_bridge_device::eisa_irq_read), FUNC(mediagx_cs5530_bridge_device::eisa_irq_write));
+ map(0x00e0, 0x00ef).noprw();
+// map(0x121c, 0x121f) ACPI Timer count register (on rev 1.3+)
+}
+
+void mediagx_cs5530_bridge_device::pc_irq1_w(int state) { m_pic8259_master->ir1_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq3_w(int state) { m_pic8259_master->ir3_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq4_w(int state) { m_pic8259_master->ir4_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq5_w(int state) { m_pic8259_master->ir5_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq6_w(int state) { m_pic8259_master->ir6_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq7_w(int state) { m_pic8259_master->ir7_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq8n_w(int state) { m_pic8259_slave->ir0_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq9_w(int state) { m_pic8259_slave->ir1_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq10_w(int state) { m_pic8259_slave->ir2_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq11_w(int state) { m_pic8259_slave->ir3_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq12m_w(int state) { m_pic8259_slave->ir4_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq14_w(int state) { m_pic8259_slave->ir6_w(state); }
+void mediagx_cs5530_bridge_device::pc_irq15_w(int state) { m_pic8259_slave->ir7_w(state); }
+
+uint8_t mediagx_cs5530_bridge_device::get_slave_ack(offs_t offset)
+{
+ if (offset == 2) // IRQ = 2
+ return m_pic8259_slave->acknowledge();
+
+ return 0x00;
+}
+
+void mediagx_cs5530_bridge_device::at_pit8254_out0_changed(int state)
+{
+ if (m_pic8259_master)
+ m_pic8259_master->ir0_w(state);
+}
+
+void mediagx_cs5530_bridge_device::at_pit8254_out1_changed(int state)
+{
+ if (state)
+ m_refresh = !m_refresh;
+}
+
+void mediagx_cs5530_bridge_device::at_pit8254_out2_changed(int state)
+{
+ m_pit_out2 = state ? 1 : 0;
+ m_speaker->level_w(m_at_spkrdata & m_pit_out2);
+}
+
+void mediagx_cs5530_bridge_device::at_speaker_set_spkrdata(uint8_t data)
+{
+ m_at_spkrdata = data ? 1 : 0;
+ m_speaker->level_w(m_at_spkrdata & m_pit_out2);
+}
+
+uint8_t mediagx_cs5530_bridge_device::at_portb_r()
+{
+ uint8_t data = m_at_speaker;
+
+ data &= ~0xd0; /* AT BIOS don't likes this being set */
+ /* 0x10 is the dram refresh line bit on the 5170, just a timer here, 15.085us. */
+ data |= m_refresh ? 0x10 : 0;
+ if (m_pit_out2)
+ data |= 0x20;
+ else
+ data &= ~0x20; /* ps2m30 wants this */
+
+ return data;
+}
+
+void mediagx_cs5530_bridge_device::at_portb_w(uint8_t data)
+{
+ m_at_speaker = data;
+ m_pit8254->write_gate2(BIT(data, 0));
+ at_speaker_set_spkrdata(BIT(data, 1));
+ m_channel_check = BIT(data, 3);
+ if (m_channel_check)
+ m_host_cpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+}
+
+void mediagx_cs5530_bridge_device::iochck_w(int state)
+{
+ if (!state && !m_channel_check && m_nmi_enabled)
+ m_host_cpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
+}
+
+uint8_t mediagx_cs5530_bridge_device::at_page8_r(offs_t offset)
+{
+ uint8_t 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;
+}
+
+void mediagx_cs5530_bridge_device::at_page8_w(offs_t offset, uint8_t data)
+{
+ m_at_pages[offset % 0x10] = data;
+
+ switch (offset % 8)
+ {
+ case 0:
+ m_boot_state_hook((offs_t)0, data);
+ break;
+ 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;
+ }
+}
+
+void mediagx_cs5530_bridge_device::pc_dma_hrq_changed(int state)
+{
+ m_host_cpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ m_dma8237_2->hack_w(state);
+}
+
+uint8_t mediagx_cs5530_bridge_device::pc_dma_read_byte(offs_t offset)
+{
+ address_space &prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
+ return 0xff;
+ uint8_t result;
+ offs_t page_offset = ((offs_t)m_dma_offset[0][m_dma_channel]) << 16;
+
+ result = prog_space.read_byte(page_offset + offset);
+ return result;
+}
+
+void mediagx_cs5530_bridge_device::pc_dma_write_byte(offs_t offset, uint8_t data)
+{
+ address_space &prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
+ return;
+ offs_t page_offset = ((offs_t)m_dma_offset[0][m_dma_channel]) << 16;
+
+ prog_space.write_byte(page_offset + offset, data);
+}
+
+uint8_t mediagx_cs5530_bridge_device::pc_dma_read_word(offs_t offset)
+{
+ address_space &prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
+ return 0xff;
+ uint16_t result;
+ offs_t page_offset = ((offs_t)m_dma_offset[1][m_dma_channel & 3]) << 16;
+
+ result = prog_space.read_word((page_offset & 0xfe0000) | (offset << 1));
+ m_dma_high_byte = result & 0xFF00;
+
+ return result & 0xFF;
+}
+
+void mediagx_cs5530_bridge_device::pc_dma_write_word(offs_t offset, uint8_t data)
+{
+ address_space &prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if (m_dma_channel == -1)
+ return;
+ offs_t page_offset = ((offs_t)m_dma_offset[1][m_dma_channel & 3]) << 16;
+
+ prog_space.write_word((page_offset & 0xfe0000) | (offset << 1), m_dma_high_byte | data);
+}
+
+uint8_t mediagx_cs5530_bridge_device::pc_dma8237_0_dack_r() { return m_isabus->dack_r(0); }
+uint8_t mediagx_cs5530_bridge_device::pc_dma8237_1_dack_r() { return m_isabus->dack_r(1); }
+uint8_t mediagx_cs5530_bridge_device::pc_dma8237_2_dack_r() { return m_isabus->dack_r(2); }
+uint8_t mediagx_cs5530_bridge_device::pc_dma8237_3_dack_r() { return m_isabus->dack_r(3); }
+uint8_t mediagx_cs5530_bridge_device::pc_dma8237_5_dack_r() { return m_isabus->dack_r(5); }
+uint8_t mediagx_cs5530_bridge_device::pc_dma8237_6_dack_r() { return m_isabus->dack_r(6); }
+uint8_t mediagx_cs5530_bridge_device::pc_dma8237_7_dack_r() { return m_isabus->dack_r(7); }
+
+void mediagx_cs5530_bridge_device::pc_dma8237_0_dack_w(uint8_t data) { m_isabus->dack_w(0, data); }
+void mediagx_cs5530_bridge_device::pc_dma8237_1_dack_w(uint8_t data) { m_isabus->dack_w(1, data); }
+void mediagx_cs5530_bridge_device::pc_dma8237_2_dack_w(uint8_t data) { m_isabus->dack_w(2, data); }
+void mediagx_cs5530_bridge_device::pc_dma8237_3_dack_w(uint8_t data) { m_isabus->dack_w(3, data); }
+void mediagx_cs5530_bridge_device::pc_dma8237_5_dack_w(uint8_t data) { m_isabus->dack_w(5, data); }
+void mediagx_cs5530_bridge_device::pc_dma8237_6_dack_w(uint8_t data) { m_isabus->dack_w(6, data); }
+void mediagx_cs5530_bridge_device::pc_dma8237_7_dack_w(uint8_t data) { m_isabus->dack_w(7, data); }
+
+void mediagx_cs5530_bridge_device::at_dma8237_out_eop(int state)
+{
+ m_cur_eop = state == ASSERT_LINE;
+ if (m_dma_channel != -1)
+ m_isabus->eop_w(m_dma_channel, m_cur_eop ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void mediagx_cs5530_bridge_device::pc_select_dma_channel(int channel, bool state)
+{
+ m_isabus->dack_line_w(channel, state);
+
+ if (!state)
+ {
+ m_dma_channel = channel;
+ if (m_cur_eop)
+ m_isabus->eop_w(channel, ASSERT_LINE);
+ }
+ else if (m_dma_channel == channel)
+ {
+ m_dma_channel = -1;
+ if (m_cur_eop)
+ m_isabus->eop_w(channel, CLEAR_LINE);
+ }
+}
+
+void mediagx_cs5530_bridge_device::pc_dack0_w(int state) { pc_select_dma_channel(0, state); }
+void mediagx_cs5530_bridge_device::pc_dack1_w(int state) { pc_select_dma_channel(1, state); }
+void mediagx_cs5530_bridge_device::pc_dack2_w(int state) { pc_select_dma_channel(2, state); }
+void mediagx_cs5530_bridge_device::pc_dack3_w(int state) { pc_select_dma_channel(3, state); }
+void mediagx_cs5530_bridge_device::pc_dack4_w(int state) { m_dma8237_1->hack_w( state ? 0 : 1); } // it's inverted
+void mediagx_cs5530_bridge_device::pc_dack5_w(int state) { pc_select_dma_channel(5, state); }
+void mediagx_cs5530_bridge_device::pc_dack6_w(int state) { pc_select_dma_channel(6, state); }
+void mediagx_cs5530_bridge_device::pc_dack7_w(int state) { pc_select_dma_channel(7, state); }
+
+uint8_t mediagx_cs5530_bridge_device::at_dma8237_2_r(offs_t offset)
+{
+ return m_dma8237_2->read(offset / 2);
+}
+
+void mediagx_cs5530_bridge_device::at_dma8237_2_w(offs_t offset, uint8_t data)
+{
+ m_dma8237_2->write(offset / 2, data);
+}
+
+void mediagx_cs5530_bridge_device::map_bios(address_space *memory_space, uint32_t start, uint32_t end)
+{
+ uint32_t mask = m_region->bytes() - 1;
+ memory_space->install_rom(start, end, m_region->base() + (start & mask));
+}
+
+void mediagx_cs5530_bridge_device::map_extra(
+ uint64_t memory_window_start,
+ uint64_t memory_window_end,
+ uint64_t memory_offset,
+ address_space *memory_space,
+ uint64_t io_window_start,
+ uint64_t io_window_end,
+ uint64_t io_offset,
+ address_space *io_space)
+{
+ m_isabus->remap(AS_PROGRAM, 0, 1 << 24);
+ map_bios(memory_space, 0xffffffff - m_region->bytes() + 1, 0xffffffff);
+ // TODO: BIOS window conditions + BIOS ROM
+ if (BIT(m_decode_control[1], 5))
+ LOGMAP("BIOS ROM positive decode\n");
+ map_bios(memory_space, 0x000e0000, 0x000fffff);
+
+ m_isabus->remap(AS_IO, 0, 0xffff);
+ io_space->install_device(0, 0xffff, *this, &mediagx_cs5530_bridge_device::internal_io_map);
+
+ if (BIT(m_decode_control[0], 0))
+ LOGMAP("RTC positive decode $070 & $071\n");
+
+ if (BIT(m_decode_control[0], 1))
+ {
+ LOGMAP("KBDC positive decode $060 & $064 (mailbox $62 & $66 %s)\n", BIT(m_decode_control[1], 7) ? "enabled" : "disabled");
+ }
+
+ if (BIT(m_decode_control[0], 2))
+ LOGMAP("COM1 positive decode $3f8-$3ff\n");
+
+ if (BIT(m_decode_control[0], 3))
+ LOGMAP("COM2 positive decode $2f8-$2ff\n");
+
+ if (BIT(m_decode_control[0], 4))
+ LOGMAP("COM3 positive decode $3e8-$3ef\n");
+
+ if (BIT(m_decode_control[0], 5))
+ LOGMAP("COM4 positive decode $2e8-$2ef\n");
+
+ if (BIT(m_decode_control[0], 6))
+ LOGMAP("Primary FDC positive decode $3f2-$3f5 & $3f7\n");
+
+ if (BIT(m_decode_control[0], 7))
+ LOGMAP("Secondary FDC positive decode $372-$375 & $377\n");
+
+ if (BIT(m_decode_control[1], 0))
+ LOGMAP("LPT1 positive decode $378-$37f & $778-$77a\n");
+
+ if (BIT(m_decode_control[1], 1))
+ LOGMAP("LPT2 positive decode $278-$27f & $678-$67a\n");
+
+ if (BIT(m_decode_control[1], 2))
+ LOGMAP("LPT3 positive decode $3bc-$3be & $7bc-$7be\n");
+
+ if (BIT(m_decode_control[1], 4))
+ {
+ LOGMAP("Secondary IDE positive decode $170-$177 & $376-$377\n");
+ io_space->install_device(0, 0xffff, *m_ide, &mediagx_cs5530_ide_device::secondary_ide_map);
+ }
+
+ if (BIT(m_decode_control[1], 3))
+ {
+ LOGMAP("Primary IDE positive decode $1f0-$1f7 & $3f6-$3f7\n");
+ io_space->install_device(0, 0xffff, *m_ide, &mediagx_cs5530_ide_device::primary_ide_map);
+ }
+}
diff --git a/src/devices/machine/mediagx_cs5530_bridge.h b/src/devices/machine/mediagx_cs5530_bridge.h
new file mode 100644
index 00000000000..f381e84697e
--- /dev/null
+++ b/src/devices/machine/mediagx_cs5530_bridge.h
@@ -0,0 +1,149 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_MEDIAGX_CS5530_BRIDGE_H
+#define MAME_MACHINE_MEDIAGX_CS5530_BRIDGE_H
+
+#pragma once
+
+#include "pci.h"
+#include "mediagx_cs5530_ide.h"
+
+#include "bus/isa/isa.h"
+#include "cpu/i386/i386.h"
+#include "machine/8042kbdc.h"
+#include "machine/am9517a.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "sound/spkrdev.h"
+
+
+class mediagx_cs5530_bridge_device : public pci_device
+{
+public:
+ template <typename T, typename U>
+ mediagx_cs5530_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&ide_tag)
+ : mediagx_cs5530_bridge_device(mconfig, tag, owner, clock)
+ {
+ set_ids(0x10780100, 0x00, 0x060100, 0x00000000);
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ set_ide_tag(std::forward<U>(ide_tag));
+ }
+
+ mediagx_cs5530_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto boot_state_hook() { return m_boot_state_hook.bind(); }
+ auto rtcale() { return m_rtcale.bind(); }
+ auto rtccs_read() { return m_rtccs_read.bind(); }
+ auto rtccs_write() { return m_rtccs_write.bind(); }
+ void pc_irq1_w(int state);
+ void pc_irq8n_w(int state);
+ void pc_irq14_w(int state);
+ void pc_irq15_w(int state);
+
+ template <typename T> void set_cpu_tag(T &&tag) { m_host_cpu.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_ide_tag(T &&tag) { m_ide.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_kbdc_tag(T &&tag) { m_kbdc.set_tag(std::forward<T>(tag)); }
+
+protected:
+ virtual void device_add_mconfig(machine_config & config) override;
+ virtual void device_config_complete() override;
+ virtual void device_reset() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual bool map_first() const override { return true; }
+
+ virtual void config_map(address_map &map) override;
+private:
+ void at_pit8254_out0_changed(int state);
+ void at_pit8254_out1_changed(int state);
+ void at_pit8254_out2_changed(int state);
+ uint8_t pc_dma8237_0_dack_r();
+ uint8_t pc_dma8237_1_dack_r();
+ uint8_t pc_dma8237_2_dack_r();
+ uint8_t pc_dma8237_3_dack_r();
+ uint8_t pc_dma8237_5_dack_r();
+ uint8_t pc_dma8237_6_dack_r();
+ uint8_t pc_dma8237_7_dack_r();
+ void pc_dma8237_0_dack_w(uint8_t data);
+ void pc_dma8237_1_dack_w(uint8_t data);
+ void pc_dma8237_2_dack_w(uint8_t data);
+ void pc_dma8237_3_dack_w(uint8_t data);
+ void pc_dma8237_5_dack_w(uint8_t data);
+ void pc_dma8237_6_dack_w(uint8_t data);
+ void pc_dma8237_7_dack_w(uint8_t data);
+ void pc_dack0_w(int state);
+ void pc_dack1_w(int state);
+ void pc_dack2_w(int state);
+ void pc_dack3_w(int state);
+ void pc_dack4_w(int state);
+ void pc_dack5_w(int state);
+ void pc_dack6_w(int state);
+ void pc_dack7_w(int state);
+ void at_dma8237_out_eop(int state);
+ void pc_dma_hrq_changed(int state);
+ uint8_t pc_dma_read_byte(offs_t offset);
+ void pc_dma_write_byte(offs_t offset, uint8_t data);
+ uint8_t pc_dma_read_word(offs_t offset);
+ void pc_dma_write_word(offs_t offset, uint8_t data);
+ uint8_t at_portb_r();
+ void at_portb_w(uint8_t data);
+ void at_speaker_set_spkrdata(uint8_t data);
+ uint8_t get_slave_ack(offs_t offset);
+ void pc_irq3_w(int state);
+ void pc_irq4_w(int state);
+ void pc_irq5_w(int state);
+ void pc_irq6_w(int state);
+ void pc_irq7_w(int state);
+ void pc_irq9_w(int state);
+ void pc_irq10_w(int state);
+ void pc_irq11_w(int state);
+ void pc_irq12m_w(int state);
+ void iochck_w(int state);
+ void pc_select_dma_channel(int channel, bool state);
+ uint8_t at_page8_r(offs_t offset);
+ void at_page8_w(offs_t offset, uint8_t data);
+ uint8_t at_dma8237_2_r(offs_t offset);
+ void at_dma8237_2_w(offs_t offset, uint8_t data);
+
+ void map_bios(address_space *memory_space, uint32_t start, uint32_t end);
+ void internal_io_map(address_map &map);
+
+ devcb_write8 m_boot_state_hook;
+ devcb_write8 m_rtcale;
+ devcb_read8 m_rtccs_read;
+ devcb_write8 m_rtccs_write;
+
+ required_device<cpu_device> m_host_cpu;
+ required_device<mediagx_cs5530_ide_device> m_ide;
+ required_device<kbdc8042_device> m_kbdc;
+ // southbridge internals
+ required_device<pic8259_device> m_pic8259_master;
+ required_device<pic8259_device> m_pic8259_slave;
+ required_device<am9517a_device> m_dma8237_1;
+ required_device<am9517a_device> m_dma8237_2;
+ required_device<pit8254_device> m_pit8254;
+ required_device<isa16_device> m_isabus;
+ required_device<speaker_sound_device> m_speaker;
+
+ uint8_t m_at_spkrdata = 0;
+ uint8_t m_pit_out2 = 0;
+ uint8_t m_at_speaker = 0;
+ bool m_refresh = false;
+ int m_dma_channel = 0;
+ bool m_cur_eop = false;
+ uint8_t m_dma_offset[2][4];
+ uint8_t m_at_pages[0x10]{};
+ uint16_t m_dma_high_byte = 0;
+ uint8_t m_channel_check = 0;
+ bool m_nmi_enabled = false;
+
+ u8 m_fast_init;
+ u8 m_decode_control[2]{};
+};
+
+DECLARE_DEVICE_TYPE(MEDIAGX_CS5530_BRIDGE, mediagx_cs5530_bridge_device)
+
+#endif
diff --git a/src/devices/machine/mediagx_cs5530_ide.cpp b/src/devices/machine/mediagx_cs5530_ide.cpp
new file mode 100644
index 00000000000..a48b35821db
--- /dev/null
+++ b/src/devices/machine/mediagx_cs5530_ide.cpp
@@ -0,0 +1,142 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+[Cyrix/National Semiconductor/AMD] [MediaGX/Geode] [Cx/CS]5530 IDE implementation
+
+TODO:
+- Derive from common pci-ide.cpp interface
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "mediagx_cs5530_ide.h"
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(MEDIAGX_CS5530_IDE, mediagx_cs5530_ide_device, "mediagx_cs5530_ide", "MediaGX CS5530 IDE Controller")
+
+mediagx_cs5530_ide_device::mediagx_cs5530_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, MEDIAGX_CS5530_IDE, tag, owner, clock)
+ , m_ide1(*this, "ide1")
+ , m_ide2(*this, "ide2")
+ , m_irq_pri_callback(*this)
+ , m_irq_sec_callback(*this)
+ , m_bus_master_space(*this, finder_base::DUMMY_TAG, AS_PROGRAM)
+{
+}
+
+void mediagx_cs5530_ide_device::device_add_mconfig(machine_config &config)
+{
+ BUS_MASTER_IDE_CONTROLLER(config, m_ide1).options(ata_devices, "hdd", nullptr, false);
+ m_ide1->irq_handler().set([this](int state) { m_irq_pri_callback(state); });
+ m_ide1->set_bus_master_space(m_bus_master_space);
+
+ BUS_MASTER_IDE_CONTROLLER(config, m_ide2).options(ata_devices, "cdrom", nullptr, false);
+ m_ide2->irq_handler().set([this](int state) { m_irq_sec_callback(state); });
+ m_ide2->set_bus_master_space(m_bus_master_space);
+}
+
+void mediagx_cs5530_ide_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+// index 0x24-0xff reserved
+}
+
+//
+void mediagx_cs5530_ide_device::primary_ide_map(address_map &map)
+{
+ map(0x01f0, 0x01f7).rw(FUNC(mediagx_cs5530_ide_device::ide1_read32_cs0_r), FUNC(mediagx_cs5530_ide_device::ide1_write32_cs0_w));
+ map(0x03f6, 0x03f6).rw(FUNC(mediagx_cs5530_ide_device::ide1_read_cs1_r), FUNC(mediagx_cs5530_ide_device::ide1_write_cs1_w));
+}
+
+void mediagx_cs5530_ide_device::secondary_ide_map(address_map &map)
+{
+ map(0x0170, 0x0177).rw(FUNC(mediagx_cs5530_ide_device::ide2_read32_cs0_r), FUNC(mediagx_cs5530_ide_device::ide2_write32_cs0_w));
+ map(0x0376, 0x0376).rw(FUNC(mediagx_cs5530_ide_device::ide2_read_cs1_r), FUNC(mediagx_cs5530_ide_device::ide2_write_cs1_w));
+}
+
+uint32_t mediagx_cs5530_ide_device::ide1_read32_cs0_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return 0xffffffff;
+ return m_ide1->read_cs0(offset, mem_mask);
+}
+
+void mediagx_cs5530_ide_device::ide1_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return;
+ m_ide1->write_cs0(offset, data, mem_mask);
+}
+
+uint32_t mediagx_cs5530_ide_device::ide2_read32_cs0_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return 0xffffffff;
+ return m_ide2->read_cs0(offset, mem_mask);
+}
+
+void mediagx_cs5530_ide_device::ide2_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return;
+ m_ide2->write_cs0(offset, data, mem_mask);
+}
+
+uint8_t mediagx_cs5530_ide_device::ide1_read_cs1_r()
+{
+ if (!(command & 1))
+ return 0xff;
+ return m_ide1->read_cs1(1, 0xff0000) >> 16;
+}
+
+void mediagx_cs5530_ide_device::ide1_write_cs1_w(uint8_t data)
+{
+ if (!(command & 1))
+ return;
+ m_ide1->write_cs1(1, data << 16, 0xff0000);
+}
+
+uint8_t mediagx_cs5530_ide_device::ide2_read_cs1_r()
+{
+ if (!(command & 1))
+ return 0xff;
+ return m_ide2->read_cs1(1, 0xff0000) >> 16;
+}
+
+void mediagx_cs5530_ide_device::ide2_write_cs1_w(uint8_t data)
+{
+ if (!(command & 1))
+ return;
+ m_ide2->write_cs1(1, data << 16, 0xff0000);
+}
+
+
+// F2BAR
+void mediagx_cs5530_ide_device::io_map(address_map &map)
+{
+ map(0x00, 0x07).rw(m_ide1, FUNC(bus_master_ide_controller_device::bmdma_r), FUNC(bus_master_ide_controller_device::bmdma_w));
+ map(0x08, 0x0f).rw(m_ide2, FUNC(bus_master_ide_controller_device::bmdma_r), FUNC(bus_master_ide_controller_device::bmdma_w));
+// map(0x20, 0x23).select(0x18) Channel # (bit 5) Drive # (bit 3) PIO
+// map(0x24, 0x27).select(0x18) Channel # (bit 5) Drive # (bit 3) DMA Control
+}
+
+void mediagx_cs5530_ide_device::device_start()
+{
+ pci_device::device_start();
+
+ skip_map_regs(4);
+ add_map(128, M_IO, FUNC(mediagx_cs5530_ide_device::io_map));
+}
+
+void mediagx_cs5530_ide_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ status = 0x0280;
+}
diff --git a/src/devices/machine/mediagx_cs5530_ide.h b/src/devices/machine/mediagx_cs5530_ide.h
new file mode 100644
index 00000000000..1cb2b00641d
--- /dev/null
+++ b/src/devices/machine/mediagx_cs5530_ide.h
@@ -0,0 +1,66 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_MEDIAGX_CS5530_IDE_H
+#define MAME_MACHINE_MEDIAGX_CS5530_IDE_H
+
+#pragma once
+
+#include "pci.h"
+#include "idectrl.h"
+
+class mediagx_cs5530_ide_device : public pci_device
+{
+public:
+ template <typename T> mediagx_cs5530_ide_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&host_tag, uint32_t bmspace = AS_PROGRAM
+ ) : mediagx_cs5530_ide_device(mconfig, tag, owner, clock)
+ {
+ set_ids(0x10780102, 0x00, 0x010180, 0x00);
+ m_bus_master_space.set_tag(host_tag, bmspace);
+ }
+ mediagx_cs5530_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto irq_pri() { return m_irq_pri_callback.bind(); }
+ auto irq_sec() { return m_irq_sec_callback.bind(); }
+
+ void primary_ide_map(address_map &map);
+ void secondary_ide_map(address_map &map);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+// virtual void reset_all_mappings() override;
+
+// virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+// uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+
+private:
+ void io_map(address_map &map);
+
+ required_device<bus_master_ide_controller_device> m_ide1;
+ required_device<bus_master_ide_controller_device> m_ide2;
+ devcb_write_line m_irq_pri_callback;
+ devcb_write_line m_irq_sec_callback;
+ required_address_space m_bus_master_space;
+
+ uint32_t ide1_read32_cs0_r(offs_t offset, uint32_t mem_mask = ~0);
+ void ide1_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint32_t ide2_read32_cs0_r(offs_t offset, uint32_t mem_mask = ~0);
+ void ide2_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint8_t ide1_read_cs1_r();
+ void ide1_write_cs1_w(uint8_t data);
+ uint8_t ide2_read_cs1_r();
+ void ide2_write_cs1_w(uint8_t data);
+
+};
+
+DECLARE_DEVICE_TYPE(MEDIAGX_CS5530_IDE, mediagx_cs5530_ide_device)
+
+#endif
diff --git a/src/devices/machine/mediagx_cs5530_video.cpp b/src/devices/machine/mediagx_cs5530_video.cpp
new file mode 100644
index 00000000000..1bd46285ed2
--- /dev/null
+++ b/src/devices/machine/mediagx_cs5530_video.cpp
@@ -0,0 +1,55 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+[Cyrix/National Semiconductor/AMD] [MediaGX/Geode] [Cx/CS]5530 VIDEO implementation (XpressGRAPHICS?)
+
+TODO:
+- extensions for host display section (GX_BASE+8300h);
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "mediagx_cs5530_video.h"
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(MEDIAGX_CS5530_VIDEO, mediagx_cs5530_video_device, "mediagx_cs5530_video", "MediaGX CS5530 Video Controller")
+
+mediagx_cs5530_video_device::mediagx_cs5530_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, MEDIAGX_CS5530_VIDEO, tag, owner, clock)
+{
+ set_ids(0x10780104, 0x00, 0x030000, 0x00);
+}
+
+void mediagx_cs5530_video_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+// map(0x14, 0xff).unmaprw(); // <reserved>
+}
+
+void mediagx_cs5530_video_device::io_map(address_map &map)
+{
+
+}
+
+void mediagx_cs5530_video_device::device_start()
+{
+ pci_device::device_start();
+
+ add_map(4*1024, M_MEM, FUNC(mediagx_cs5530_video_device::io_map));
+
+ // no INT pin
+}
+
+void mediagx_cs5530_video_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ command_mask = 0x0003;
+ status = 0x0280;
+}
diff --git a/src/devices/machine/mediagx_cs5530_video.h b/src/devices/machine/mediagx_cs5530_video.h
new file mode 100644
index 00000000000..7a1428faa2a
--- /dev/null
+++ b/src/devices/machine/mediagx_cs5530_video.h
@@ -0,0 +1,29 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS630_VGA_H
+#define MAME_MACHINE_SIS630_VGA_H
+
+#pragma once
+
+#include "pci.h"
+#include "video/pc_vga.h"
+
+class mediagx_cs5530_video_device : public pci_device
+{
+public:
+ mediagx_cs5530_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void config_map(address_map &map) override;
+
+ void io_map(address_map &map);
+};
+
+DECLARE_DEVICE_TYPE(MEDIAGX_CS5530_VIDEO, mediagx_cs5530_video_device)
+
+
+#endif
diff --git a/src/devices/machine/mediagx_host.cpp b/src/devices/machine/mediagx_host.cpp
new file mode 100644
index 00000000000..a3da478af96
--- /dev/null
+++ b/src/devices/machine/mediagx_host.cpp
@@ -0,0 +1,375 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+MediaGX host implementation (northbridge)
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "mediagx_host.h"
+
+#define LOG_MAP (1U << 1) // log full remaps
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(MEDIAGX_HOST, mediagx_host_device, "mediagx_host", "MediaGX X-Bus Host PCI")
+
+mediagx_host_device::mediagx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_host_device(mconfig, MEDIAGX_HOST, tag, owner, clock)
+ , m_host_cpu(*this, finder_base::DUMMY_TAG)
+ , m_vga(*this, "vga")
+{
+ m_superio_space_config = address_space_config("superio_space", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(mediagx_host_device::superio_map), this));
+}
+
+u8 mediagx_host_device::superio_if_r(offs_t offset)
+{
+ if (!offset || m_superio_lock)
+ {
+ LOG("Super I/O: $%02x read while locked %02x\n", offset + 0x22, m_superio_index);
+ return space().unmap();
+ }
+
+ return space(AS_PCI_IO).read_byte(m_superio_index);
+}
+
+void mediagx_host_device::superio_if_w(offs_t offset, u8 data)
+{
+ if (!offset)
+ {
+ m_superio_index = data;
+ m_superio_lock = false;
+ return;
+ }
+
+ if (!m_superio_lock)
+ {
+ m_superio_lock = true;
+ space(AS_PCI_IO).write_byte(m_superio_index, data);
+ }
+ else
+ LOG("Super I/O: $23 write while locked %02x %02x\n", m_superio_index, data);
+}
+
+void mediagx_host_device::superio_map(address_map &map)
+{
+// map(0x20, 0x20) PCR
+// map(0xb0, 0xb0) SMHR0
+// map(0xb1, 0xb1) SMHR1
+// map(0xb2, 0xb2) SMHR2
+// map(0xb3, 0xb3) SMHR3
+ // GCR
+ map(0xb8, 0xb8).lrw8(
+ NAME([this] () {
+ return m_superio.gcr;
+ }),
+ NAME([this] (u8 data) {
+ m_superio.gcr = data;
+ if (data & 0xc)
+ LOG("GCR scratchpad setting %02x\n", data);
+ remap_cb();
+ })
+ );
+// map(0xb9, 0xb9) VGACTL
+// map(0xba, 0xbd) VGAM0
+// map(0xc1, 0xc1) CCR1
+// map(0xc2, 0xc2) CCR2
+// map(0xc3, 0xc3) CCR3
+// map(0xe8, 0xe8) CCR4
+// map(0xeb, 0xeb) CCR7
+ // DIR0
+ map(0xfe, 0xfe).lr8(
+ NAME([] () {
+ // xxxx ---- Device ID
+ // 0100 ---- MediaGX MMX
+ // ---- xxxx Core Multiplier (depends on DIR1)
+ return 0x40 | 0x05;
+ })
+ );
+// map(0xff, 0xff) DIR1
+}
+
+device_memory_interface::space_config_vector mediagx_host_device::memory_space_config() const
+{
+ auto r = pci_host_device::memory_space_config();
+ r.emplace_back(std::make_pair(AS_PCI_IO, &m_superio_space_config));
+ return r;
+}
+
+void mediagx_host_device::device_start()
+{
+ pci_host_device::device_start();
+ set_spaces(&m_host_cpu->space(AS_PROGRAM), &m_host_cpu->space(AS_IO));
+
+ memory_window_start = 0;
+ memory_window_end = 0xffffffff;
+ memory_offset = 0;
+ io_window_start = 0;
+ io_window_end = 0xffff;
+ io_offset = 0;
+
+ m_ram.resize(m_ram_size/4);
+ m_smm_ram.resize(SMM_SIZE/4);
+}
+
+void mediagx_host_device::device_reset()
+{
+ pci_host_device::device_reset();
+
+ command = 0x0007;
+ status = 0x0280;
+
+ m_pci_control[0] = 0x00;
+ m_pci_control[1] = 0x96;
+
+ m_pci_arbitration[0] = 0x80;
+ m_pci_arbitration[1] = 0x00;
+
+ m_superio_lock = true;
+
+ remap_cb();
+}
+
+void mediagx_host_device::device_add_mconfig(machine_config &config)
+{
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_raw(XTAL(25'174'800), 900, 0, 640, 526, 0, 480);
+ screen.set_screen_update(m_vga, FUNC(mediagx_vga_device::screen_update));
+
+ MEDIAGX_VGA(config, m_vga, 0);
+ m_vga->set_screen("screen");
+ m_vga->set_vram_size(4*1024*1024);
+}
+
+void mediagx_host_device::config_map(address_map &map)
+{
+ pci_host_device::config_map(map);
+ map(0x40, 0x41).lrw8(
+ NAME([this] (offs_t offset) {
+ LOG("PCI Control Function %d read\n", offset + 1);
+ return m_pci_control[offset];
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ LOG("PCI Control Function %d write %02x\n", offset + 1, data);
+ m_pci_control[offset] = data;
+ })
+ );
+
+ map(0x43, 0x44).lrw8(
+ NAME([this] (offs_t offset) {
+ LOG("PCI Arbitration Control %d read\n", offset + 1);
+ return m_pci_arbitration[offset];
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ LOG("PCI Arbitration Control %d write %02x\n", offset + 1, data);
+ m_pci_arbitration[offset] = data;
+ })
+ );
+}
+
+void mediagx_host_device::map_shadowram(address_space *memory_space, uint32_t start_offs, uint32_t end_offs, bool read_enable, bool write_enable)
+{
+ LOGMAP("- 0x%08x-0x%08x ", start_offs, end_offs);
+
+ switch(write_enable << 1 | read_enable)
+ {
+ case 0:
+ LOGMAP("shadow RAM off\n");
+ //memory_space->unmap_write(start_offs, end_offs);
+ break;
+ case 1:
+ LOGMAP("shadow RAM r/o\n");
+ memory_space->install_rom(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ case 2:
+ LOGMAP("shadow RAM w/o\n");
+ //memory_space->install_rom(start_offs, end_offs, m_region->base() + bios_rom_offset);
+ memory_space->install_writeonly(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ case 3:
+ LOGMAP("shadow RAM r/w\n");
+ memory_space->install_ram(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ }
+}
+
+void mediagx_host_device::map_extra(
+ uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space
+) {
+ io_space->install_device(0, 0xffff, *static_cast<pci_host_device *>(this), &pci_host_device::io_configuration_access_map);
+
+ regenerate_config_mapping();
+
+ io_space->install_readwrite_handler(0x22, 0x23,
+ read8sm_delegate(*this, FUNC(mediagx_host_device::superio_if_r)),
+ write8sm_delegate(*this, FUNC(mediagx_host_device::superio_if_w))
+ );
+
+ memory_space->install_ram(0x00000000, 0x0009ffff, &m_ram[0x00000000/4]);
+ // TODO: BC_XMAP_1, which is always 0 in both astropc and matrix (???)
+ //memory_space->install_ram(0x000a0000, 0x000bffff, &m_ram[0x000a0000/4]);
+ memory_space->install_device(0x000a0000, 0x000bffff, *this, &mediagx_host_device::legacy_memory_map);
+ io_space->install_device(0x03b0, 0x03df, *this, &mediagx_host_device::legacy_io_map);
+
+ LOGMAP("Host Remapping table (BC_XMAP_1 %08x BC_XMAP_2 %08x BC_XMAP_3):\n", m_bc_xmap[0], m_bc_xmap[1], m_bc_xmap[2]);
+
+ // BC_XMAP_2 & BC_XMAP_3 bits remaps with this arrangement:
+ // x--- PCI accessible
+ // -x-- Cache Enable
+ // --x- Write Enable
+ // ---x Read Enable
+ for (int i = 0; i < 8; i ++)
+ {
+ u32 start_offs = 0x000c0000 + i * 0x4000;
+ u32 end_offs = start_offs + 0x3fff;
+
+ map_shadowram(
+ memory_space,
+ start_offs, end_offs,
+ bool(BIT(m_bc_xmap[1], i * 4)), bool(BIT(m_bc_xmap[1], i * 4 + 1))
+ );
+ }
+ for (int i = 0; i < 8; i ++)
+ {
+ u32 start_offs = 0x000e0000 + i * 0x4000;
+ u32 end_offs = start_offs + 0x3fff;
+
+ map_shadowram(
+ memory_space,
+ start_offs, end_offs,
+ bool(BIT(m_bc_xmap[2], i * 4)), bool(BIT(m_bc_xmap[2], i * 4 + 1))
+ );
+ }
+ memory_space->install_ram (0x00100000, 0x00efffff, &m_ram[0x00100000/4]);
+ // TODO: verify if there's a memory hole 15M-16M like other x86 PCI hosts
+ //if(memory_hole_upper)
+ memory_space->install_ram (0x00f00000, 0x00ffffff, &m_ram[0x00f00000/4]);
+
+ memory_space->install_ram (0x01000000, m_ram_size-1, &m_ram[0x01000000/4]);
+
+ const u32 gx_base = (m_superio.gcr & 3) << 30;
+
+ if (gx_base)
+ {
+ LOGMAP("gxbase mapped at %08x\n", gx_base);
+ memory_space->install_device(gx_base, (gx_base) | 0xffffff, *this, &mediagx_host_device::gxbase_map);
+ }
+}
+
+void mediagx_host_device::gxbase_map(address_map &map)
+{
+// 0x001000 scratchpad
+ map(0x008000, 0x008003).lrw32(
+ NAME([this] (offs_t offset) {
+ return m_bc_dram_top;
+ }),
+ NAME([this] (offs_t offset, u32 data, u32 mem_mask) {
+ LOG("GXBASE+%04x: BC_DRAM_TOP %08x & %08x\n", (offset * 4) + 0x8000, data, mem_mask);
+ COMBINE_DATA(&m_bc_dram_top);
+ remap_cb();
+ })
+ );
+ map(0x008004, 0x00800f).lrw32(
+ NAME([this] (offs_t offset) {
+ return m_bc_xmap[offset];
+ }),
+ NAME([this] (offs_t offset, u32 data, u32 mem_mask) {
+ LOG("GXBASE+%04x: BC_XMAP_%d %08x & %08x\n", (offset * 4) + 0x8004, offset + 1, data, mem_mask);
+ COMBINE_DATA(&m_bc_xmap[offset]);
+ remap_cb();
+ })
+ );
+ map(0x008100, 0x0082ff).m(*this, FUNC(mediagx_host_device::gfx_pipeline_map));
+ map(0x008300, 0x0083ff).m(*this, FUNC(mediagx_host_device::display_ctrl_map));
+// 0x008400 Memory controller
+// 0x008500 Power Management
+ // SMM System Code
+ map(0x400000, 0x41ffff).lrw32(
+ NAME([this] (offs_t offset) { return m_smm_ram[offset]; }),
+ NAME([this] (offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_smm_ram[offset]); })
+ );
+// 0x800000 GFX memory
+}
+
+/****************************
+ *
+ * Graphics Pipeline
+ *
+ ***************************/
+
+// GX_BASE+$8100
+void mediagx_host_device::gfx_pipeline_map(address_map &map)
+{
+// map(0x0000, 0x012f) <GP BitBLT section>
+// map(0x0140, 0x0143) GP_VGA_WRITE
+// map(0x0144, 0x0147) GP_VGA_READ
+// map(0x0200, 0x020f) <more GP BitBLT>
+// map(0x0210, 0x0213) GGP_VGA_BASE (sic?)
+// map(0x0214, 0x0217) GP_VGA_LATCH
+}
+
+/****************************
+ *
+ * Display Controller
+ *
+ ***************************/
+
+// GX_BASE+$8300
+void mediagx_host_device::display_ctrl_map(address_map &map)
+{
+// map(0x0000, 0x0003) DC_UNLOCK
+// map(0x0004, 0x0007) DC_GENERAL_CFG
+// map(0x0008, 0x000b) DC_TIMING_CFG
+// map(0x000c, 0x000f) DC_OUTPUT_CFG
+// map(0x0010, 0x0013) DC_FB_ST_OFFSET
+// map(0x0014, 0x0017) DC_CB_ST_OFFSET
+// map(0x0018, 0x001b) DC_CURS_ST_OFFSET
+// map(0x0020, 0x0023) DC_VID_ST_OFFSET
+// map(0x0024, 0x0027) DC_LINE_DELTA
+// map(0x0028, 0x002b) DC_BUF_SIZE
+// map(0x0030, 0x0033) DC_H_TIMING_1
+// map(0x0033, 0x0037) DC_H_TIMING_2
+// map(0x0038, 0x003b) DC_H_TIMING_3
+// map(0x003c, 0x003f) DC_FP_H_TIMING
+// map(0x0040, 0x0043) DC_V_TIMING_1
+// map(0x0044, 0x0047) DC_V_TIMING_2
+// map(0x0048, 0x004b) DC_V_TIMING_3
+// map(0x004c, 0x004f) DC_FP_V_TIMING
+// map(0x0050, 0x0053) DC_CURSOR_X
+// map(0x0054, 0x0057) DC_V_LINE_CNT
+// map(0x0058, 0x005b) DC_CURSOR_Y
+// map(0x005c, 0x005f) DC_SS_LINE_CMP
+// map(0x0060, 0x0063) DC_CURSOR_COLOR
+// map(0x0068, 0x006b) DC_BORDER_COLOR
+// map(0x0070, 0x0073) DC_PAL_ADDRESS
+// map(0x0074, 0x0077) DC_PAL_DATA
+// map(0x0078, 0x007b) DC_DFIFO_DIAG
+// map(0x007c, 0x007f) DC_CFIFO_DIAG
+}
+
+void mediagx_host_device::legacy_memory_map(address_map &map)
+{
+ map(0x00000, 0x1ffff).rw(FUNC(mediagx_host_device::vram_r), FUNC(mediagx_host_device::vram_w));
+}
+
+void mediagx_host_device::legacy_io_map(address_map &map)
+{
+ map(0x000, 0x02f).m(m_vga, FUNC(mediagx_vga_device::io_map));
+}
+
+uint8_t mediagx_host_device::vram_r(offs_t offset)
+{
+ return downcast<mediagx_vga_device *>(m_vga.target())->mem_r(offset);
+}
+
+void mediagx_host_device::vram_w(offs_t offset, uint8_t data)
+{
+ downcast<mediagx_vga_device *>(m_vga.target())->mem_w(offset, data);
+}
diff --git a/src/devices/machine/mediagx_host.h b/src/devices/machine/mediagx_host.h
new file mode 100644
index 00000000000..d8cb41445f0
--- /dev/null
+++ b/src/devices/machine/mediagx_host.h
@@ -0,0 +1,83 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_MEDIAGX_HOST_H
+#define MAME_MACHINE_MEDIAGX_HOST_H
+
+#pragma once
+
+#include "pci.h"
+#include "video/pc_vga_mediagx.h"
+
+class mediagx_host_device : public pci_host_device
+{
+public:
+ template <typename T> mediagx_host_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&cpu_tag, int ram_size
+ ) : mediagx_host_device(mconfig, tag, owner, clock)
+ {
+ set_ids(0x10780001, 0x00, 0x060000, 0x00);
+ //set_multifunction_device(true);
+ m_host_cpu.set_tag(std::forward<T>(cpu_tag));
+ set_ram_size(ram_size);
+ }
+
+ mediagx_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ void set_ram_size(int ram_size) { m_ram_size = ram_size; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual space_config_vector memory_space_config() const override;
+ virtual void config_map(address_map &map) override;
+private:
+ void map_shadowram(address_space *memory_space, uint32_t start_offs, uint32_t end_offs, bool read_enable, bool write_enable);
+ enum
+ {
+ //AS_PCI_MEM = 1,
+ AS_PCI_IO = 2
+ };
+ required_device<cpu_device> m_host_cpu;
+ required_device<mediagx_vga_device> m_vga;
+ std::vector<uint32_t> m_ram;
+ std::vector<uint32_t> m_smm_ram;
+ address_space_config m_superio_space_config;
+
+ void superio_map(address_map &map);
+ u8 superio_if_r(offs_t offset);
+ void superio_if_w(offs_t offset, u8 data);
+ u8 m_superio_index = 0;
+ bool m_superio_lock = false;
+
+ struct {
+ u8 gcr = 0;
+ }m_superio;
+
+ u32 m_ram_size = 0;
+ // FIXME: check size
+ static constexpr u32 SMM_SIZE = 0x20000;
+ u8 m_pci_control[2]{};
+ u8 m_pci_arbitration[2]{};
+
+ void gxbase_map(address_map &map);
+ void gfx_pipeline_map(address_map &map);
+ void display_ctrl_map(address_map &map);
+
+ u32 m_bc_dram_top = 0;
+ u32 m_bc_xmap[3]{};
+
+ void legacy_memory_map(address_map &map);
+ void legacy_io_map(address_map &map);
+ u8 vram_r(offs_t offset);
+ void vram_w(offs_t offset, uint8_t data);
+};
+
+DECLARE_DEVICE_TYPE(MEDIAGX_HOST, mediagx_host_device)
+
+#endif
diff --git a/src/devices/machine/meters.cpp b/src/devices/machine/meters.cpp
index cf36ff75177..93ab6fd7fdc 100644
--- a/src/devices/machine/meters.cpp
+++ b/src/devices/machine/meters.cpp
@@ -1,11 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:James Wallace
-///////////////////////////////////////////////////////////////////////////
-// //
-// Electro mechanical meters //
-// //
-// //
-///////////////////////////////////////////////////////////////////////////
+/**********************************************************************
+
+ Electromechanical Meter device
+
+**********************************************************************/
#include "emu.h"
#include "meters.h"
@@ -30,19 +29,17 @@ meters_device::meters_device(const machine_config &mconfig, const char *tag, dev
void meters_device::device_start()
{
- if ( m_number_mtr > MAXMECHMETERS )
+ if (m_number_mtr > MAXMECHMETERS)
m_number_mtr = MAXMECHMETERS;
- for ( int i = 0; i < m_number_mtr; i++ )
+ for (int i = 0; i < m_number_mtr; i++)
{
m_meter_info[i].reacttime = METERREACTTIME;
m_meter_info[i].state = 0;
m_meter_info[i].count = 0;
m_meter_info[i].on = 0;
- m_meter_info[i].meter_timer = timer_alloc(i);
- m_meter_info[i].meter_timer->reset();
+ m_meter_info[i].meter_timer = timer_alloc(FUNC(meters_device::count_tick), this);
- //save_item(NAME(m_meter_info[i].reacttime), i); //enable if void ReactTime(int id, int32_t cycles) gets used
save_item(NAME(m_meter_info[i].state), i);
save_item(NAME(m_meter_info[i].count), i);
save_item(NAME(m_meter_info[i].on), i);
@@ -58,89 +55,42 @@ void meters_device::device_reset()
}
//-------------------------------------------------
-// device_timer - device-specific timer events
+// count_tick - advance the meter's counter
//-------------------------------------------------
-void meters_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(meters_device::count_tick)
{
- if (id >= m_number_mtr)
- throw emu_fatalerror("Unknown id in meters_device::device_timer");
-
m_meter_info[param].count++;
}
-///////////////////////////////////////////////////////////////////////////
-
-int meters_device::GetNumberMeters(void) // currently unused
-{
- return m_number_mtr;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-void meters_device::Setcount(int id, int32_t count) // currently unused
-{
- if ( id >= m_number_mtr )
- return;
-
- m_meter_info[id].count = count;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-int32_t meters_device::Getcount(int id) // currently unused
-{
- int32_t result = 0;
-
- if ( id < m_number_mtr )
- result = m_meter_info[id].count;
-
- return result;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-void meters_device::ReactTime(int id, int32_t cycles) // currently unused
-{
- if ( id >= m_number_mtr )
- return;
-
- m_meter_info[id].reacttime = cycles;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-int meters_device::GetActivity(int id)
+int meters_device::get_activity(int id)
{
return m_meter_info[id].on;
}
-///////////////////////////////////////////////////////////////////////////
-
int meters_device::update(int id, int state)
{
- int res = 0;
-
- if ( id >= m_number_mtr )
- return res;
+ if (id >= m_number_mtr)
+ return 0;
- state = state?1:0;
+ state = state ? 1 : 0;
- if ( m_meter_info[id].state != state )
+ if (m_meter_info[id].state != state)
{ // meter state is changing
m_meter_info[id].state = state;
- if ( state )
+ if (state)
{
- m_meter_info[id].on =1;
+ m_meter_info[id].on = true;
m_meter_info[id].meter_timer->adjust(attotime::from_seconds(m_meter_info[id].reacttime), id);
}
else
{
- m_meter_info[id].on =0;
- m_meter_info[id].meter_timer->adjust(attotime::never, id);
+ m_meter_info[id].on = false;
+ m_meter_info[id].meter_timer->adjust(attotime::never);
}
}
+
return m_meter_info[id].on;
}
diff --git a/src/devices/machine/meters.h b/src/devices/machine/meters.h
index c9a11790931..c8dc68a5800 100644
--- a/src/devices/machine/meters.h
+++ b/src/devices/machine/meters.h
@@ -1,13 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:James Wallace
-///////////////////////////////////////////////////////////////////////////
-// //
-// Electro mechanical meters //
-// //
-// 23-07-2004: Re-Animator //
-// //
-// //
-///////////////////////////////////////////////////////////////////////////
+/**********************************************************************
+
+ Electromechanical Meter device
+
+**********************************************************************/
#ifndef MAME_MACHINE_METERS_H
#define MAME_MACHINE_METERS_H
@@ -18,36 +15,31 @@
class meters_device : public device_t
{
public:
- static constexpr unsigned MAXMECHMETERS = 8;
-
- static constexpr double METERREACTTIME = 0.025; // number of seconds meter has to be active to tick
-
meters_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void set_number(int number) { m_number_mtr = number; }
int update(int id, int state);
- int GetActivity(int id);
-
- int GetNumberMeters(void); // currently unused
- void Setcount(int id, int32_t count); // currently unused
- int32_t Getcount(int id); // currently unused
- void ReactTime(int id, int32_t cycles); // currently unused
+ int get_activity(int id);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(count_tick);
private:
+ static constexpr unsigned MAXMECHMETERS = 8;
+ static constexpr double METERREACTTIME = 0.025; // number of seconds meter has to be active to tick
+
// internal state
struct meter_info
{
- bool on; // Activity of reel
+ bool on; // Reel active
int32_t reacttime;
- int32_t count; // mechmeter value
- bool state; // state 0/1
+ int32_t count; // Meter value
+ bool state;
emu_timer *meter_timer;
};
diff --git a/src/devices/machine/micomxe1a.cpp b/src/devices/machine/micomxe1a.cpp
new file mode 100644
index 00000000000..0aa0f42367d
--- /dev/null
+++ b/src/devices/machine/micomxe1a.cpp
@@ -0,0 +1,368 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/**********************************************************************
+
+ Dempa Micom Soft Analog/Digital Controller emulation
+
+ PC pin Name MD pin Name Dir Signal
+ 1 Up 1 Up In D0
+ 2 Down 2 Down In D1
+ 3 Left 3 Left In D2
+ 4 Right 4 Right In D3
+ 6 TRIG1 6 TL In L/H
+ 7 TRIG2 9 TR In ACK
+ 8 STROBE 7 TH Out REQ
+
+ In analog mode, data is shifted out as twelve nybbles:
+
+ _ ________________________________________________________________
+ REQ \_________/
+ ____ __ __ __ __ __ __ __ __ __ __ __ __
+ ACK \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
+ _____ _____ _____ _____ _____ _____
+ L/H _______/ \_____/ \_____/ \_____/ \_____/ \_____/ \__
+ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____
+ D XXXX_____X_____X_____X_____X_____X_____X_____X_____X_____X_____X_____X_____X
+
+ The falling edge on REQ causes data output to start. The host
+ can't control the speed, it just polls the L/H and ACK lines to
+ know when the data is ready to read.
+
+ Nybble D3 D2 D1 D0
+ 1 A/A' B/B' C D
+ 2 E1 E2 Start Select
+ 3 Y7 Y6 Y5 Y4
+ 4 X7 X6 X5 X4
+ 5 Z7 Z6 Z5 Z4
+ 6 RZ7 RZ6 RZ5 RZ4
+ 7 Y3 Y2 Y1 Y0
+ 8 X3 X2 X1 X0
+ 9 Z3 Z2 Z1 Z0
+ 10 RZ3 RZ2 RZ1 RZ0
+ 11 A B A' B'
+ 12 - - - -
+
+ In MD mode, each pair of nybbles is transmitted in reverse
+ order.
+
+ Sharp released assembly language source code for an X68000
+ driver. It uses the following algorithm:
+ 1. Generate falling edge on REQ
+ 2. Wait until L/H is low
+ 3. Wait until ACK is low
+ 4. Read a nybble
+ 5. Wait until L/H is high
+ 6. Wait until ACK is low
+ 7. Read a nybble
+ 8. If eight nybbles have been read, raise REQ.
+ 9. Loop to step 2 until twelve nybbles have been read
+
+ Mega Drive games use a similar approach, but raise REQ after
+ reading two nybbles. PC Engine games only generate a short low
+ pulse on REQ, but use the same algorithm to determine when to
+ read data.
+
+ CSK Research Institute games for FM Towns (including After
+ Burner III and Galaxy Force II) use a different algorithm:
+ 1. Generate falling edge on REQ
+ 2. Wait until L/H is high
+ 3. Wait until ACK is high
+ 4. Read a nybble
+ 5. Wait until L/H is low
+ 6. Wait until ACK is high
+ 7. Read a nybble
+ 8. Wait until L/H is high
+ 9. Wait until ACK is high
+ 10. Read a nybble
+ 11. Loop to step 5 until eleven nybbles have been read
+ 11. Raise REQ
+
+ From this it can be deduced that:
+ * A negative edge on REQ triggers a report.
+ * The exact time REQ is held low isn't important.
+ * Data is valid while ACK is low and for some time after ACK is
+ raised.
+ * L/H is low when idle and changes some time before data is
+ updated.
+
+ In digital mode, REQ is a simple multiplexer input:
+
+ REQ 0 1
+ D0 Up Throttle Up
+ D1 Down Throttle Down
+ D2 Left C
+ D3 Right D
+ L/H A/A' E1
+ ACK B/B' E2
+
+ Start appears as simultaneous Left/Right
+ Select appears as simultaneous Up/Down
+
+ This mode is almost compatible with a 6-button Towns Pad (on a
+ real 6-button Towns Pad, buttons A and B can be read in either
+ state, they bypass the multiplexer).
+
+ Digital MD mode emulates a 3-button Mega Drive pad:
+
+ REQ 0 1
+ D0 Up Up
+ D1 Down Down
+ D2 0 Left
+ D3 0 Right
+ L/H A B
+ ACK Start C
+
+ TODO:
+ * Dump MB88513 microcontroller from original controller.
+ * Measure timings.
+ - Timings currently fudged for CRI games in FM Towns.
+ * Latch data at beginning of packet.
+ * Confirm button mapping in digital mode.
+ * Estimate thresholds in digital modes.
+ * Implement trigger A/B rapid fire switches.
+ * Implement channel shift switch (Y->X, X->Z, Z->X).
+ * Does channel shift affect digital mode?
+ * Implement special modes (holding buttons on power-on):
+ - Double displacement modes:
+ + X/Y (hold SELECT + A')
+ + Z (hold SELECT + B')
+ + X/Y/Z (hold SELECT + A' + B')
+ - Up/down reverse mode (hold C)
+ * Implement desktop (XE-1AJ/CZ-8NJ2) version:
+ - Four analog channels
+ - E1/E2 on a rocker switch (can't press simultaneously)
+ - Hold mode for A and B triggers
+ - Variable rapid fire rate for A and B triggers
+ - Reset button
+ - Different special modes
+ - No Mega Drive mode
+ - Start and Select not reported in digital mode
+
+**********************************************************************/
+
+#include "emu.h"
+#include "micomxe1a.h"
+
+//#define VERBOSE 1
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(MICOM_XE_1A, micom_xe_1a_device, "micom_xe_1a", "Dempa Micom Soft Analog/Digital Intelligent Controller")
+
+
+
+micom_xe_1a_device::micom_xe_1a_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ u32 clock):
+ device_t(mconfig, MICOM_XE_1A, tag, owner, clock),
+ m_buttons_callback(*this, 0xffff),
+ m_analog_callback(*this, 0x00),
+ m_output_timer(nullptr),
+ m_req(1),
+ m_mode(1),
+ m_interface(0),
+ m_out(0x2f)
+{
+}
+
+
+u8 micom_xe_1a_device::out_r()
+{
+ if (m_mode)
+ {
+ LOG("%s: analog mode read data = %02X\n", machine().describe_context(), m_out);
+ return m_out;
+ }
+ else
+ {
+ u16 const buttons = m_buttons_callback();
+ if (m_interface)
+ {
+ u8 const y = m_analog_callback(0);
+ if (m_req)
+ {
+ u8 const x = m_analog_callback(1);
+ u8 const result =
+ ((0x40 <= y) ? 0x01 : 0x00) | // Up
+ ((0xc0 > y) ? 0x02 : 0x00) | // Down
+ ((0x40 <= x) ? 0x04 : 0x00) | // Left
+ ((0xc0 > x) ? 0x08 : 0x00) | // Right
+ ((BIT(buttons, 2) & BIT(buttons, 8)) << 4) | // B/B'
+ (BIT(buttons, 1) << 5); // C
+ LOG(
+ "%s: MD digital mode basic read = 0x%02X\n",
+ machine().describe_context(),
+ result);
+ return result;
+ }
+ else
+ {
+ u8 const result =
+ ((0x40 <= y) ? 0x01 : 0x00) | // Up
+ ((0xc0 > y) ? 0x02 : 0x00) | // Down
+ ((BIT(buttons, 3) & BIT(buttons, 9)) << 4) | // A/A'
+ (BIT(buttons, 5) << 5); // Start
+ LOG(
+ "%s: MD digital mode extended read = 0x%02X\n",
+ machine().describe_context(),
+ result);
+ return result;
+ }
+ }
+ else
+ {
+ if (m_req)
+ {
+ u8 const z = m_analog_callback(2);
+ u8 const result =
+ ((0x40 <= z) ? 0x01 : 0x00) | // Throttle Up
+ ((0xc0 > z) ? 0x02 : 0x00) | // Throttle Down
+ (BIT(buttons, 1) << 2) | // C
+ (BIT(buttons, 0) << 3) | // D
+ (BIT(buttons, 7) << 4) | // E1
+ (BIT(buttons, 6) << 5); // E2
+ LOG(
+ "%s: digital mode extended read = 0x%02X\n",
+ machine().describe_context(),
+ result);
+ return result;
+ }
+ else
+ {
+ u8 const y = m_analog_callback(0);
+ u8 const x = m_analog_callback(1);
+ u8 const result =
+ ((BIT(buttons, 4) && (0x40 <= y)) ? 0x01 : 0x00) | // Select/Up
+ ((BIT(buttons, 4) && (0xc0 > y)) ? 0x02 : 0x00) | // Select/Down
+ ((BIT(buttons, 5) && (0x40 <= x)) ? 0x04 : 0x00) | // Start/Left
+ ((BIT(buttons, 5) && (0xc0 > x)) ? 0x08 : 0x00) | // Start/Right
+ ((BIT(buttons, 3) & BIT(buttons, 9)) << 4) | // A/A'
+ ((BIT(buttons, 2) & BIT(buttons, 8)) << 5); // B/B'
+ LOG(
+ "%s: digital mode basic read = 0x%02X\n",
+ machine().describe_context(),
+ result);
+ return result;
+ }
+ }
+ }
+}
+
+
+void micom_xe_1a_device::req_w(int state)
+{
+ u8 const req = state ? 1 : 0;
+ if (req != m_req)
+ {
+ if (m_mode)
+ {
+ LOG("%s: /REQ = %u\n", machine().describe_context(), req);
+ if (!req)
+ {
+ // acquire data
+ u16 const buttons = m_buttons_callback();
+ u8 analog[4];
+ for (unsigned i = 0; std::size(analog) > i; ++i)
+ analog[i] = m_analog_callback(i);
+
+ // pack data
+ m_data[0] = BIT(buttons, 0, 8) & ((BIT(buttons, 8, 2) << 2) | 0xf3);
+ m_data[1] = BIT(analog[0], 4, 4) | (BIT(analog[1], 4, 4) << 4);
+ m_data[2] = BIT(analog[2], 4, 4) | (BIT(analog[3], 4, 4) << 4);
+ m_data[3] = BIT(analog[0], 0, 4) | (BIT(analog[1], 0, 4) << 4);
+ m_data[4] = BIT(analog[2], 0, 4) | (BIT(analog[3], 0, 4) << 4);
+ m_data[5] = BIT(buttons, 8, 8) & ((BIT(buttons, 2, 2) << 2) | 0xf3);
+
+ // takes a while to respond
+ m_output_timer->adjust(attotime::from_nsec(50'000), 0);
+ }
+ }
+ else
+ {
+ LOG("%s: /REQ = %u ignored in digital mode\n", machine().describe_context(), req);
+ }
+ m_req = req;
+ }
+}
+
+
+void micom_xe_1a_device::mode_w(int state)
+{
+ u8 const mode = state ? 1 : 0;
+ if (mode != m_mode)
+ {
+ if (mode)
+ {
+ LOG("Analog mode selected\n");
+ }
+ else
+ {
+ LOG("Digital mode selected\n");
+ m_output_timer->enable(false);
+ m_out = 0x2f;
+ }
+ m_mode = mode;
+ }
+}
+
+
+void micom_xe_1a_device::interface_w(int state)
+{
+ m_interface = state ? 1 : 0;
+}
+
+
+void micom_xe_1a_device::device_start()
+{
+ m_output_timer = timer_alloc(FUNC(micom_xe_1a_device::step_output), this);
+
+ std::fill(std::begin(m_data), std::end(m_data), 0x00);
+ m_out = 0x2f;
+
+ save_item(NAME(m_req));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_interface));
+ save_item(NAME(m_data));
+ save_item(NAME(m_out));
+}
+
+
+TIMER_CALLBACK_MEMBER(micom_xe_1a_device::step_output)
+{
+ auto const step = param >> 1;
+ if (!BIT(param, 0))
+ {
+ m_out = (m_out & 0x0f) | (BIT(step, 0) ? 0x30 : 0x20);
+ LOG(
+ "Set nybble %u data = 0x%X, L/H = %u, /ACK = %u\n",
+ step,
+ BIT(m_out, 0, 4),
+ BIT(m_out, 4),
+ BIT(m_out, 5));
+ if ((std::size(m_data) * 2) > step)
+ {
+ m_output_timer->adjust(attotime::from_nsec(10'000), param + 1);
+ }
+ }
+ else
+ {
+ if ((std::size(m_data) * 2) > step)
+ {
+ auto const nybble = step ^ m_interface;
+ if ((std::size(m_data) * 2) > step)
+ m_out = BIT(m_data[nybble >> 1], BIT(nybble, 0) ? 4 : 0, 4) | (m_out & 0x10);
+ else
+ m_out = 0x0f | (m_out & 0x10);
+ LOG(
+ "Set nybble %u data = 0x%X, L/H = %u, /ACK = %u\n",
+ step,
+ BIT(m_out, 0, 4),
+ BIT(m_out, 4),
+ BIT(m_out, 5));
+ m_output_timer->adjust(attotime::from_nsec(10'000), param + 1);
+ }
+ }
+}
diff --git a/src/devices/machine/micomxe1a.h b/src/devices/machine/micomxe1a.h
new file mode 100644
index 00000000000..e581f4f7cb4
--- /dev/null
+++ b/src/devices/machine/micomxe1a.h
@@ -0,0 +1,49 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/**********************************************************************
+
+ Dempa Micom Soft Analog/Digital Controller emulation
+
+**********************************************************************/
+#ifndef MAME_MACHINE_MICOMXE1A_H
+#define MAME_MACHINE_MICOMXE1A_H
+
+#pragma once
+
+
+class micom_xe_1a_device : public device_t
+{
+public:
+ micom_xe_1a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0) ATTR_COLD;
+
+ auto buttons_handler() { return m_buttons_callback.bind(); }
+ auto analog_handler() { return m_analog_callback.bind(); }
+
+ u8 out_r();
+
+ void req_w(int state);
+ void mode_w(int state); // 0 = digital, 1 = analog
+ void interface_w(int state); // 0 = PC, 1 = MD
+
+protected:
+ virtual void device_start() override ATTR_COLD;
+
+private:
+ TIMER_CALLBACK_MEMBER(step_output);
+
+ devcb_read16 m_buttons_callback;
+ devcb_read8 m_analog_callback;
+
+ emu_timer *m_output_timer;
+
+ u8 m_req;
+ u8 m_mode;
+ u8 m_interface;
+ u8 m_data[6];
+ u8 m_out;
+};
+
+
+DECLARE_DEVICE_TYPE(MICOM_XE_1A, micom_xe_1a_device)
+
+#endif // MAME_MACHINE_MICOMXE1A_H
diff --git a/src/devices/machine/microtch.cpp b/src/devices/machine/microtch.cpp
index a974202bfab..987da9e53e2 100644
--- a/src/devices/machine/microtch.cpp
+++ b/src/devices/machine/microtch.cpp
@@ -80,10 +80,10 @@ microtouch_device::microtouch_device(const machine_config &mconfig, const char *
int microtouch_device::check_command( const char* commandtocheck, int command_len, uint8_t* command_data )
{
- if ( (command_len == (strlen(commandtocheck) + 2)) &&
+ if ((command_len == (strlen(commandtocheck) + 2)) &&
(command_data[0] == 0x01) &&
(strncmp(commandtocheck, (const char*)command_data + 1, strlen(commandtocheck)) == 0) &&
- (command_data[command_len-1] == 0x0d) )
+ (command_data[command_len-1] == 0x0d))
{
return 1;
}
@@ -111,10 +111,10 @@ void microtouch_device::send_format_decimal_packet(int x, int y)
int decx, decy;
decx = x / 16;
- if ( decx > 999 )
+ if (decx > 999)
decx = 999;
decy = y / 16;
- if ( decy > 999 )
+ if (decy > 999)
decy = 999;
// header byte
@@ -138,12 +138,11 @@ void microtouch_device::send_touch_packet()
int tx = m_touchx->read();
int ty = m_touchy->read();
- if ( m_out_touch_cb.isnull() ||
- m_out_touch_cb( &tx, &ty ) != 0 )
+ if (m_out_touch_cb(&tx, &ty) != 0)
{
ty = 0x4000 - ty;
- switch( m_format )
+ switch (m_format)
{
case FORMAT_TABLET:
send_format_table_packet(0xc8, tx, ty);
@@ -160,54 +159,49 @@ void microtouch_device::send_touch_packet()
}
}
-void microtouch_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(microtouch_device::update_output)
{
- if (!id)
+ if (m_tx_buffer_ptr < m_tx_buffer_num)
{
- if ( m_tx_buffer_ptr < m_tx_buffer_num )
+ if (is_transmit_register_empty())
{
- if(is_transmit_register_empty())
- {
- m_output = m_tx_buffer[m_tx_buffer_ptr++];
- m_output_valid = true;
- tra_complete();
- }
-
- if ( m_tx_buffer_ptr == m_tx_buffer_num )
- {
- m_tx_buffer_ptr = m_tx_buffer_num = 0;
- }
- return;
+ m_output = m_tx_buffer[m_tx_buffer_ptr++];
+ m_output_valid = true;
+ tra_complete();
}
- if ( (m_reset_done == 0) ||
- (m_format == FORMAT_UNKNOWN) ||
- (m_mode != MODE_STREAM))
+ if (m_tx_buffer_ptr == m_tx_buffer_num)
{
- return;
+ m_tx_buffer_ptr = m_tx_buffer_num = 0;
}
+ return;
+ }
- // send format tablet packet
- if (m_touch->read())
- {
- send_touch_packet();
- }
- else
+ if (m_reset_done == 0 || m_format == FORMAT_UNKNOWN || m_mode != MODE_STREAM)
+ {
+ return;
+ }
+
+ // send format tablet packet
+ if (m_touch->read())
+ {
+ send_touch_packet();
+ }
+ else
+ {
+ if (m_last_touch_state == 1)
{
- if ( m_last_touch_state == 1 )
+ m_last_touch_state = 0;
+ switch (m_format)
{
- m_last_touch_state = 0;
- switch( m_format )
- {
- case FORMAT_TABLET:
- send_format_table_packet(0x88, m_last_x, m_last_y);
- break;
- case FORMAT_DECIMAL:
- send_format_decimal_packet(m_last_x, m_last_y);
- break;
- case FORMAT_UNKNOWN:
- break;
- }
+ case FORMAT_TABLET:
+ send_format_table_packet(0x88, m_last_x, m_last_y);
+ break;
+ case FORMAT_DECIMAL:
+ send_format_decimal_packet(m_last_x, m_last_y);
+ break;
+ case FORMAT_UNKNOWN:
+ break;
}
}
}
@@ -227,7 +221,7 @@ void microtouch_device::device_start()
m_last_y = 0;
m_last_touch_state = -1;
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(microtouch_device::update_output), this);
m_timer->adjust(attotime::from_hz(167*5), 0, attotime::from_hz(167*5));
m_format = FORMAT_UNKNOWN;
@@ -247,8 +241,7 @@ void microtouch_device::device_start()
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); //8N1?
set_tra_rate(clock());
set_rcv_rate(clock());
- m_out_touch_cb.resolve();
- m_out_stx_func.resolve_safe();
+ m_out_touch_cb.resolve_safe(1);
m_output_valid = false;
save_item(NAME(m_output_valid));
@@ -261,10 +254,10 @@ void microtouch_device::rcv_complete()
receive_register_extract();
m_rx_buffer[m_rx_buffer_ptr] = get_received_char();
m_rx_buffer_ptr++;
- if(m_rx_buffer_ptr == 16)
+ if (m_rx_buffer_ptr == 16)
return;
- if (m_rx_buffer_ptr > 0 && (m_rx_buffer[m_rx_buffer_ptr-1] == 0x0d))
+ if (m_rx_buffer_ptr > 0 && m_rx_buffer[m_rx_buffer_ptr-1] == 0x0d)
{
if (VERBOSE)
{
@@ -274,32 +267,32 @@ void microtouch_device::rcv_complete()
LOG("Microtouch: received command %s\n", command);
}
// check command
- if ( check_command( "MS", m_rx_buffer_ptr, m_rx_buffer ) )
+ if (check_command("MS", m_rx_buffer_ptr, m_rx_buffer))
{
m_mode = MODE_STREAM;
}
- else if ( check_command( "MI", m_rx_buffer_ptr, m_rx_buffer ) )
+ else if (check_command("MI", m_rx_buffer_ptr, m_rx_buffer))
{
m_mode = MODE_INACTIVE;
}
- else if ( check_command( "MP", m_rx_buffer_ptr, m_rx_buffer ) )
+ else if (check_command("MP", m_rx_buffer_ptr, m_rx_buffer))
{
m_mode = MODE_POINT;
}
- else if ( check_command( "R", m_rx_buffer_ptr, m_rx_buffer ) )
+ else if (check_command("R", m_rx_buffer_ptr, m_rx_buffer))
{
m_tx_buffer_num = 0;
m_reset_done = 1;
}
- else if ( check_command( "FT", m_rx_buffer_ptr, m_rx_buffer ) )
+ else if (check_command("FT", m_rx_buffer_ptr, m_rx_buffer))
{
m_format = FORMAT_TABLET;
}
- else if ( check_command( "FD", m_rx_buffer_ptr, m_rx_buffer ) )
+ else if (check_command("FD", m_rx_buffer_ptr, m_rx_buffer))
{
m_format = FORMAT_DECIMAL;
}
- else if ( check_command("OI", m_rx_buffer_ptr, m_rx_buffer ) )
+ else if (check_command("OI", m_rx_buffer_ptr, m_rx_buffer))
{
// output identity - SMT3, ver 01.00
m_tx_buffer[m_tx_buffer_num++] = 0x01;
@@ -313,7 +306,7 @@ void microtouch_device::rcv_complete()
m_rx_buffer_ptr = 0;
return;
}
- else if ( check_command("OS", m_rx_buffer_ptr, m_rx_buffer ) )
+ else if (check_command("OS", m_rx_buffer_ptr, m_rx_buffer))
{
// output status
m_tx_buffer[m_tx_buffer_num++] = 0x01;
@@ -347,9 +340,9 @@ void microtouch_device::rcv_complete()
}
}
-INPUT_CHANGED_MEMBER( microtouch_device::touch )
+INPUT_CHANGED_MEMBER(microtouch_device::touch)
{
- if ( newval && ( m_mode == MODE_POINT ) )
+ if (newval && (m_mode == MODE_POINT))
{
send_touch_packet();
}
@@ -368,11 +361,11 @@ ROM_END
static INPUT_PORTS_START(microtouch)
PORT_START("TOUCH")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME( "Touch screen" ) PORT_CHANGED_MEMBER( DEVICE_SELF,microtouch_device, touch, 0 )
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Touch screen") PORT_CHANGED_MEMBER(DEVICE_SELF, microtouch_device, touch, 0)
PORT_START("TOUCH_X")
- PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
+ PORT_BIT(0x3fff, 0x2000, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
PORT_START("TOUCH_Y")
- PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
+ PORT_BIT(0x3fff, 0x2000, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15)
INPUT_PORTS_END
ioport_constructor microtouch_device::device_input_ports() const
@@ -387,7 +380,7 @@ void microtouch_device::tra_callback()
void microtouch_device::tra_complete()
{
- if(m_output_valid)
+ if (m_output_valid)
{
transmit_register_setup(m_output);
m_output_valid = false;
diff --git a/src/devices/machine/microtch.h b/src/devices/machine/microtch.h
index 2f955955e03..67656f93b49 100644
--- a/src/devices/machine/microtch.h
+++ b/src/devices/machine/microtch.h
@@ -15,18 +15,17 @@ public:
typedef device_delegate<int (int *, int *)> touch_cb;
microtouch_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
auto stx() { return m_out_stx_func.bind(); }
+ template <typename... T> void set_touch_callback(T &&... args) { m_out_touch_cb.set(std::forward<T>(args)...); }
- DECLARE_WRITE_LINE_MEMBER(rx) { device_serial_interface::rx_w(state); }
+ void rx(int state) { device_serial_interface::rx_w(state); }
DECLARE_INPUT_CHANGED_MEMBER(touch);
- template <typename... T> void set_touch_callback(T &&... args) { m_out_touch_cb.set(std::forward<T>(args)...); }
-
protected:
// device_t implementation
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_serial_interface implementation
virtual void tra_callback() override;
@@ -36,6 +35,8 @@ protected:
// ROM region (unused, as the device is HLE'd)
virtual const tiny_rom_entry *device_rom_region() const override;
+ TIMER_CALLBACK_MEMBER(update_output);
+
private:
int check_command( const char* commandtocheck, int command_len, uint8_t* command_data );
void send_format_table_packet(uint8_t flag, int x, int y);
@@ -56,25 +57,25 @@ private:
MODE_POINT
};
- uint8_t m_rx_buffer[16];
+ uint8_t m_rx_buffer[16];
int m_rx_buffer_ptr;
- uint8_t m_tx_buffer[16];
- uint8_t m_tx_buffer_num;
- uint8_t m_tx_buffer_ptr;
+ uint8_t m_tx_buffer[16];
+ uint8_t m_tx_buffer_num;
+ uint8_t m_tx_buffer_ptr;
int m_reset_done;
int m_format;
int m_mode;
int m_last_touch_state;
int m_last_x;
int m_last_y;
- touch_cb m_out_touch_cb;
+ touch_cb m_out_touch_cb;
devcb_write_line m_out_stx_func;
required_ioport m_touch;
required_ioport m_touchx;
required_ioport m_touchy;
emu_timer* m_timer;
- bool m_output_valid;
- uint8_t m_output;
+ bool m_output_valid;
+ uint8_t m_output;
};
DECLARE_DEVICE_TYPE(MICROTOUCH, microtouch_device)
diff --git a/src/devices/machine/mm5307.cpp b/src/devices/machine/mm5307.cpp
index 312d7cff86b..33699a8fada 100644
--- a/src/devices/machine/mm5307.cpp
+++ b/src/devices/machine/mm5307.cpp
@@ -121,26 +121,13 @@ mm5307ab_device::mm5307ab_device(const machine_config &mconfig, const char *tag,
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void mm5307_device::device_resolve_objects()
-{
- // Resolve callback
- m_output_cb.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void mm5307_device::device_start()
{
// Create timer
- m_periodic_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mm5307_device::periodic_update), this));
+ m_periodic_timer = timer_alloc(FUNC(mm5307_device::periodic_update), this);
// Register for saving
save_item(NAME(m_freq_control));
diff --git a/src/devices/machine/mm5307.h b/src/devices/machine/mm5307.h
index c1e6dad8f89..7ca0789e3c3 100644
--- a/src/devices/machine/mm5307.h
+++ b/src/devices/machine/mm5307.h
@@ -42,8 +42,7 @@ protected:
// base class constructor
mm5307_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const std::array<u16, 16> &divisors_x2);
- // device-specific overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/mm5740.cpp b/src/devices/machine/mm5740.cpp
index ca378caecf9..9559594e2fc 100644
--- a/src/devices/machine/mm5740.cpp
+++ b/src/devices/machine/mm5740.cpp
@@ -43,21 +43,20 @@ const tiny_rom_entry *mm5740_device::device_rom_region() const
// mm5740_device - constructor
//-------------------------------------------------
-mm5740_device::mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+mm5740_device::mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, MM5740, tag, owner, clock),
- m_read_x(*this),
- m_read_shift(*this),
- m_read_control(*this),
+ m_read_x(*this, 0x3ff),
+ m_read_shift(*this, 0),
+ m_read_control(*this, 0),
m_write_data_ready(*this),
m_rom(*this, "internal")
{
- std::fill(std::begin(m_x_mask), std::end(m_x_mask), 0);
}
-uint32_t mm5740_device::calc_effective_clock_key_debounce(uint32_t capacitance)
+u32 mm5740_device::calc_effective_clock_key_debounce(u32 capacitance)
{
// calculate key debounce based on capacitance in pF
- uint32_t key_debounce_msec = capacitance / 125;
+ u32 key_debounce_msec = capacitance / 125;
if (key_debounce_msec == 0)
{
key_debounce_msec = 1;
@@ -72,41 +71,39 @@ uint32_t mm5740_device::calc_effective_clock_key_debounce(uint32_t capacitance)
void mm5740_device::device_start()
{
- // resolve callbacks
- m_read_x.resolve_all_safe(0x3ff);
- m_read_shift.resolve_safe(0);
- m_read_control.resolve_safe(0);
- m_write_data_ready.resolve_safe();
+ std::fill(std::begin(m_x_mask), std::end(m_x_mask), 0);
+ m_b = -1;
+ m_repeat = false;
+ m_last_repeat = false;
// allocate timers
- m_scan_timer = timer_alloc();
+ m_scan_timer = timer_alloc(FUNC(mm5740_device::perform_scan), this);
m_scan_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
// state saving
save_item(NAME(m_b));
+ save_item(NAME(m_offset));
save_item(NAME(m_x_mask));
+ save_item(NAME(m_repeat));
+ save_item(NAME(m_last_repeat));
}
-
//-------------------------------------------------
-// device_start - device-specific reset
+// perform_scan - scan the keyboard matrix
//-------------------------------------------------
-void mm5740_device::device_reset()
+TIMER_CALLBACK_MEMBER(mm5740_device::perform_scan)
{
-}
-
-//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void mm5740_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- int ako = 0;
+ bool ako = false;
for (int x = 0; x < 9; x++)
{
- uint16_t data = m_read_x[x]() ^ 0x3ff;
+ u16 data = m_read_x[x]() ^ 0x3ff;
+
+ if (data)
+ {
+ ako = true;
+ }
if ((data ^ m_x_mask[x]) == 0)
{
@@ -116,42 +113,55 @@ void mm5740_device::device_timer(emu_timer &timer, device_timer_id id, int param
for (int y = 0; y < 10; y++)
{
+ u16 offset = x * 10 + y;
if (BIT(data, y))
{
- uint8_t *rom = m_rom->base();
- uint16_t offset = x*10 + y;
+ u8 *rom = m_rom->base();
// Common portion
- uint16_t common = (uint16_t) rom[offset];
+ u16 common = (u16)rom[offset];
- offset += (((m_read_shift() ? 1: 0) + (m_read_control() ? 2: 0)) + 1) * 90;
+ u16 uniq_offset = offset + ((((m_read_shift() ? 1 : 0) + (m_read_control() ? 2 : 0)) + 1) * 90);
// Unique portion based on shift/ctrl keys.
- uint8_t uniq = rom[offset];
-
- uint16_t b = (((common & 0x10) << 4) | ((uniq & 0x0f) << 4) | (common & 0x0f)) ^ 0x1ff;
+ u8 uniq = rom[uniq_offset];
- ako = 1;
+ u16 b = (((common & 0x10) << 4) | ((uniq & 0x0f) << 4) | (common & 0x0f)) ^ 0x1ff;
+ // Check for a new keypress
if (!BIT(m_x_mask[x], y))
{
m_x_mask[x] |= (1 << y);
if (m_b != b)
{
m_b = b;
+ m_offset = offset;
m_write_data_ready(ASSERT_LINE);
return;
}
}
}
- else // key released, unmark it from the "down" info
+ else
{
+ // key released, unmark it from the "down" info
m_x_mask[x] &= ~(1 << y);
+ if (m_offset == offset)
+ {
+ m_write_data_ready(CLEAR_LINE);
+ m_b = -1;
+ }
}
}
}
+ if ((m_repeat) && (!m_last_repeat) && (m_b != -1))
+ {
+ m_write_data_ready(ASSERT_LINE);
+ }
+
+ m_last_repeat = m_repeat;
+
if (!ako)
{
m_write_data_ready(CLEAR_LINE);
@@ -159,12 +169,16 @@ void mm5740_device::device_timer(emu_timer &timer, device_timer_id id, int param
}
}
+void mm5740_device::repeat_line_w(int state)
+{
+ m_repeat = (state == ASSERT_LINE);
+}
//-------------------------------------------------
// b_r -
//-------------------------------------------------
-uint16_t mm5740_device::b_r()
+u16 mm5740_device::b_r()
{
m_write_data_ready(CLEAR_LINE);
return m_b;
diff --git a/src/devices/machine/mm5740.h b/src/devices/machine/mm5740.h
index a3242711a95..7158009cdf3 100644
--- a/src/devices/machine/mm5740.h
+++ b/src/devices/machine/mm5740.h
@@ -1,10 +1,10 @@
// license:BSD-3-Clause
-// copyright-holders: R. Belmont
+// copyright-holders: R. Belmont, Mark Garlanger
/**********************************************************************
MM5740 Keyboard Encoder emulation
-**********************************************************************
+ **********************************************************************
_____ _____
B3 1 |* \_/ | 40 B4
Vll 2 | | 39 B9
@@ -27,13 +27,14 @@
Control 19 | | 22 Y10
Shift Lock I/O 20 |_____________| 21 Shift
+
Name Pin No. Function
----------------------------------------------------------------------
X1-X9 4-12 Output - Drives the key switch matrix.
Y1-Y10 22-31 Inputs - connect to the X drive lines with
- the key switch matrix.
+ the key switch matrix.
B1-B9 1,33-40 Tri-stated data outputs.
@@ -44,10 +45,10 @@ Data Strobe Control 14 Input to control data strobe output pulse width
Output Enable 15 Input to control the chip's TRI-STATE output
Repeat 16 Each cycle of this signal will issue
- a new data strobe for the pressed key.
+ a new data strobe for the pressed key.
Key-Bounce Mask 17 Use capacitor on this chip to provide
- key debouncing
+ key debouncing
Shift 21 Shift key pressed
@@ -63,12 +64,9 @@ Vll 2 Ground
Vgg 18 -12V
-
**********************************************************************/
/* TODO:
- Support Key-bounce mask
- Support Repeat function
Support shift lock
Support additional internal ROMs
*/
@@ -78,50 +76,48 @@ Vgg 18 -12V
#pragma once
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-// ======================> mm5740_device
-
class mm5740_device : public device_t
{
public:
- // construction/destruction
- mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
// public interface
- uint16_t b_r();
+ u16 b_r();
template <unsigned N> auto x_cb() { return m_read_x[N - 1].bind(); }
auto shift_cb() { return m_read_shift.bind(); }
auto control_cb() { return m_read_control.bind(); }
auto data_ready_cb() { return m_write_data_ready.bind(); }
- static uint32_t calc_effective_clock_key_debounce(uint32_t capacitance);
+ void repeat_line_w(int state);
+
+ static u32 calc_effective_clock_key_debounce(u32 capacitance);
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual const tiny_rom_entry *device_rom_region() const override;
+ TIMER_CALLBACK_MEMBER(perform_scan);
+
private:
devcb_read16::array<9> m_read_x;
- devcb_read_line m_read_shift, m_read_control;
+ devcb_read_line m_read_shift;
+ devcb_read_line m_read_control;
devcb_write_line m_write_data_ready;
- required_memory_region m_rom; // Internal ROM
+ required_memory_region m_rom; // Internal ROM
- int m_b; // output buffer
+ s32 m_b; // output buffer
+ u16 m_offset; // last key pressed (without shift/ctrl modifiers)
- int m_x_mask[9]; // mask of what keys are down
+ u16 m_x_mask[9]; // mask of what keys are down
+ bool m_repeat; // state of the 'repeat' input.
+ bool m_last_repeat; // state of the repeat input on the last scan.
// timers
- emu_timer *m_scan_timer; // keyboard scan timer
+ emu_timer *m_scan_timer; // keyboard scan timer
};
diff --git a/src/devices/machine/mm58167.cpp b/src/devices/machine/mm58167.cpp
index 05aa4377ccb..203b0bf45c4 100644
--- a/src/devices/machine/mm58167.cpp
+++ b/src/devices/machine/mm58167.cpp
@@ -22,14 +22,14 @@ DEFINE_DEVICE_TYPE(MM58167, mm58167_device, "mm58167", "National Semiconductor M
// registers (0-7 are the live data, 8-f are the setting for the compare IRQ)
typedef enum
{
- R_CNT_MILLISECONDS = 0, // 0 = milliseconds
- R_CNT_HUNDTENTHS, // 1 = hundreds and tenths of seconds
- R_CNT_SECONDS, // 2 = seconds
- R_CNT_MINUTES, // 3 = minutes
- R_CNT_HOURS, // 4 = hours
- R_CNT_DAYOFWEEK, // 5 = day of the week
- R_CNT_DAYOFMONTH, // 6 = day of the month
- R_CNT_MONTH, // 7 = month
+ R_CNT_MILLISECONDS = 0, // 0 = milliseconds [0..9]
+ R_CNT_HUNDTENTHS, // 1 = hundreds and tenths of seconds [0..99]
+ R_CNT_SECONDS, // 2 = seconds [0..59]
+ R_CNT_MINUTES, // 3 = minutes [0..59]
+ R_CNT_HOURS, // 4 = hours [0..23]
+ R_CNT_DAYOFWEEK, // 5 = day of the week [1..7, Sunday = 1]
+ R_CNT_DAYOFMONTH, // 6 = day of the month [1..31; but Feb 29 = Mar 0]
+ R_CNT_MONTH, // 7 = month [1..12]
R_RAM_MILLISECONDS, // 8 = milliseconds
R_RAM_HUNDTENTHS, // 9 = hundreds and tenths of seconds
R_RAM_SECONDS, // a = seconds
@@ -67,11 +67,9 @@ mm58167_device::mm58167_device(const machine_config &mconfig, const char *tag, d
void mm58167_device::device_start()
{
// allocate timers
- m_clock_timer = timer_alloc();
+ m_clock_timer = timer_alloc(FUNC(mm58167_device::clock_tick), this);
m_clock_timer->adjust(attotime::from_hz(clock() / 32.768f), 0, attotime::from_hz(clock() / 32.768f));
- m_irq_w.resolve_safe();
-
// state saving
save_item(NAME(m_regs));
save_item(NAME(m_milliseconds));
@@ -94,10 +92,10 @@ void mm58167_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// clock_tick - advance the RTC's registers
//-------------------------------------------------
-void mm58167_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mm58167_device::clock_tick)
{
m_milliseconds++;
@@ -227,10 +225,14 @@ void mm58167_device::write(offs_t offset, uint8_t data)
case R_CTL_RESETCOUNTERS:
if (data == 0xff)
{
- for (int i = R_CNT_MILLISECONDS; i <= R_CNT_MONTH; i++)
- {
- m_regs[i] = 0;
- }
+ m_regs[R_CNT_MILLISECONDS] = 0;
+ m_regs[R_CNT_HUNDTENTHS] = 0;
+ m_regs[R_CNT_SECONDS] = 0;
+ m_regs[R_CNT_MINUTES] = 0;
+ m_regs[R_CNT_HOURS] = 0;
+ m_regs[R_CNT_DAYOFWEEK] = 1;
+ m_regs[R_CNT_DAYOFMONTH] = 1;
+ m_regs[R_CNT_MONTH] = 1;
update_rtc();
}
diff --git a/src/devices/machine/mm58167.h b/src/devices/machine/mm58167.h
index c12b151b676..82cf173ca95 100644
--- a/src/devices/machine/mm58167.h
+++ b/src/devices/machine/mm58167.h
@@ -38,12 +38,13 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
virtual bool rtc_feature_leap_year() const override { return true; }
+ TIMER_CALLBACK_MEMBER(clock_tick);
+
void set_irq(int bit);
void update_rtc();
diff --git a/src/devices/machine/mm58174.cpp b/src/devices/machine/mm58174.cpp
index fe24c8091b5..0223a70accf 100644
--- a/src/devices/machine/mm58174.cpp
+++ b/src/devices/machine/mm58174.cpp
@@ -18,7 +18,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/mm58174.h"
+#include "mm58174.h"
enum
{
@@ -35,8 +35,11 @@ DEFINE_DEVICE_TYPE(MM58174, mm58174_device, "mm58174", "National Semiconductor M
mm58174_device::mm58174_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MM58174, tag, owner, clock),
- device_rtc_interface(mconfig, *this)
+ : device_t(mconfig, MM58174, tag, owner, clock)
+ , device_rtc_interface(mconfig, *this)
+ , m_control(0)
+ , m_int_ctl(0)
+ , m_tenths(0)
{
}
@@ -47,9 +50,9 @@ mm58174_device::mm58174_device(const machine_config &mconfig, const char *tag, d
void mm58174_device::device_start()
{
- m_increment_rtc = timer_alloc();
- m_increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100));
- m_interrupt_timer = timer_alloc();
+ m_rtc_timer = timer_alloc(FUNC(mm58174_device::clock_tick), this);
+ m_rtc_timer->adjust(attotime::zero, 0, attotime::from_msec(100));
+ m_interrupt_timer = timer_alloc(FUNC(mm58174_device::scheduler_sync), this);
// register for state saving
save_item(NAME(m_control));
@@ -69,16 +72,6 @@ void mm58174_device::device_start()
}
//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void mm58174_device::device_reset()
-{
- m_tenths = 0;
- m_control = 0;
-}
-
-//-------------------------------------------------
// rtc_clock_updated -
//-------------------------------------------------
@@ -103,7 +96,7 @@ attotime mm58174_device::interrupt_period_table(int val)
{
switch(val)
{
- case 0: return attotime::from_msec(0);
+ case 0: return attotime::never;
case 1: return attotime::from_msec(500);
case 2: return attotime::from_seconds(5);
case 4: return attotime::from_seconds(60);
@@ -289,10 +282,8 @@ void mm58174_device::write(offs_t offset, uint8_t data)
// Increment RTC clock (timed interrupt every 1/10s)
-void mm58174_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mm58174_device::clock_tick)
{
- if (id > 0) return;
-
if (m_control & ctl_clkrun)
{
if ((++m_tenths) == 10)
@@ -302,3 +293,12 @@ void mm58174_device::device_timer(emu_timer &timer, device_timer_id id, int para
}
}
}
+
+// TODO: Investigate if this is necessary, or if there's missing functionality from the device.
+// Prior to the device_timer removal, m_interrupt_timer was being allocated with the same default ID as m_rtc_timer.
+// As there was no interrupt-related logic in the existing device_timer implementation, the only possible thing that
+// m_interrupt_timer could possibly do, functionally, is force a scheduler sync by elapsing, and also cause the
+// RTC to tick at an erroneous rate.
+TIMER_CALLBACK_MEMBER(mm58174_device::scheduler_sync)
+{
+}
diff --git a/src/devices/machine/mm58174.h b/src/devices/machine/mm58174.h
index 5d755627084..72fbfc85502 100644
--- a/src/devices/machine/mm58174.h
+++ b/src/devices/machine/mm58174.h
@@ -23,13 +23,14 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
virtual bool rtc_feature_leap_year() const override { return true; }
+ TIMER_CALLBACK_MEMBER(clock_tick);
+ TIMER_CALLBACK_MEMBER(scheduler_sync);
+
void update_rtc();
private:
@@ -55,7 +56,7 @@ private:
int m_seconds2;
int m_tenths; /* tenths of second (BCD : 0-9) */
- emu_timer *m_increment_rtc;
+ emu_timer *m_rtc_timer;
emu_timer *m_interrupt_timer;
};
diff --git a/src/devices/machine/mm58274c.cpp b/src/devices/machine/mm58274c.cpp
index c7e7f49a78e..214e6b2ea08 100644
--- a/src/devices/machine/mm58274c.cpp
+++ b/src/devices/machine/mm58274c.cpp
@@ -21,7 +21,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/mm58274c.h"
+#include "mm58274c.h"
enum
{
@@ -49,6 +49,7 @@ DEFINE_DEVICE_TYPE(MM58274C, mm58274c_device, "mm58274c", "National Semiconducto
mm58274c_device::mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, MM58274C, tag, owner, clock)
+ , device_rtc_interface(mconfig, *this)
, m_mode24(0)
, m_day1(0)
{
@@ -61,9 +62,12 @@ mm58274c_device::mm58274c_device(const machine_config &mconfig, const char *tag,
void mm58274c_device::device_start()
{
- m_increment_rtc = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mm58274c_device::rtc_increment_cb),this));
+ m_increment_rtc = timer_alloc(FUNC(mm58274c_device::rtc_increment_cb), this);
m_increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100));
- m_interrupt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mm58274c_device::rtc_interrupt_cb),this));
+ m_interrupt_timer = timer_alloc(FUNC(mm58274c_device::rtc_interrupt_cb), this);
+
+ m_status = 0;
+ m_control = 0;
// register for state saving
save_item(NAME(m_mode24));
@@ -90,48 +94,41 @@ void mm58274c_device::device_start()
}
//-------------------------------------------------
-// device_reset - device-specific reset
+// rtc_clock_updated - update clock with real time
//-------------------------------------------------
-void mm58274c_device::device_reset()
+void mm58274c_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
{
- system_time systime;
-
- /* get the current date/time from the core */
- machine().current_datetime(systime);
-
- m_clk_set = systime.local_time.year & 3 << 2;
+ m_clk_set = (year & 3) << 2;
if (m_mode24)
m_clk_set |= clk_set_24;
/* The clock count starts on 1st January 1900 */
- m_wday = 1 + ((systime.local_time.weekday - m_day1) % 7);
- m_years1 = (systime.local_time.year / 10) % 10;
- m_years2 = systime.local_time.year % 10;
- m_months1 = (systime.local_time.month + 1) / 10;
- m_months2 = (systime.local_time.month + 1) % 10;
- m_days1 = systime.local_time.mday / 10;
- m_days2 = systime.local_time.mday % 10;
+ m_wday = 1 + ((day_of_week - 1 - m_day1 + 7) % 7);
+ m_years1 = (year / 10) % 10;
+ m_years2 = year % 10;
+ m_months1 = month / 10;
+ m_months2 = month % 10;
+ m_days1 = day / 10;
+ m_days2 = day % 10;
if (!m_mode24)
{
/* 12-hour mode */
- if (systime.local_time.hour > 12)
+ if (hour > 12)
{
- systime.local_time.hour -= 12;
+ hour -= 12;
m_clk_set |= clk_set_pm;
}
- if (systime.local_time.hour == 0)
- systime.local_time.hour = 12;
+ if (hour == 0)
+ hour = 12;
}
- m_hours1 = systime.local_time.hour / 10;
- m_hours2 = systime.local_time.hour % 10;
- m_minutes1 = systime.local_time.minute / 10;
- m_minutes2 = systime.local_time.minute % 10;
- m_seconds1 = systime.local_time.second / 10;
- m_seconds2 = systime.local_time.second % 10;
+ m_hours1 = hour / 10;
+ m_hours2 = hour % 10;
+ m_minutes1 = minute / 10;
+ m_minutes2 = minute % 10;
+ m_seconds1 = second / 10;
+ m_seconds2 = second % 10;
m_tenths = 0;
- m_status = 0;
- m_control = 0;
}
@@ -162,7 +159,8 @@ uint8_t mm58274c_device::read(offs_t offset)
{
case 0x00: /* Control Register */
reply = m_status;
- m_status = 0;
+ if (!machine().side_effects_disabled())
+ m_status = 0;
break;
case 0x01: /* Tenths of Seconds */
diff --git a/src/devices/machine/mm58274c.h b/src/devices/machine/mm58274c.h
index c6fcbee3c46..4f2d302a204 100644
--- a/src/devices/machine/mm58274c.h
+++ b/src/devices/machine/mm58274c.h
@@ -3,11 +3,13 @@
#ifndef MAME_MACHINE_MM58274C_H
#define MAME_MACHINE_MM58274C_H
+#include "dirtc.h"
+
/***************************************************************************
MACROS
***************************************************************************/
-class mm58274c_device : public device_t
+class mm58274c_device : public device_t, public device_rtc_interface
{
public:
mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -25,7 +27,11 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_reset() override;
+
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return false; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
private:
// internal state
diff --git a/src/devices/machine/mm74c922.cpp b/src/devices/machine/mm74c922.cpp
index e9f3c9704ac..edcf4093e20 100644
--- a/src/devices/machine/mm74c922.cpp
+++ b/src/devices/machine/mm74c922.cpp
@@ -34,7 +34,7 @@ DEFINE_DEVICE_TYPE(MM74C923, mm74c923_device, "mm74c923", "MM74C923 20-Key Encod
mm74c922_device::mm74c922_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int max_y) :
device_t(mconfig, type, tag, owner, clock),
- m_write_da(*this), m_read_x(*this), m_tristate_data(*this),
+ m_write_da(*this), m_read_x(*this, (1 << max_y) - 1), m_tristate_data(*this, (1 << max_y) - 1),
m_cap_osc(0), m_cap_debounce(0),
m_max_y(max_y),
m_inhibit(false),
@@ -63,16 +63,11 @@ mm74c923_device::mm74c923_device(const machine_config &mconfig, const char *tag,
void mm74c922_device::device_start()
{
- // resolve callbacks
- m_write_da.resolve_safe();
- m_read_x.resolve_all_safe((1 << m_max_y) - 1);
- m_tristate_data.resolve_safe((1 << m_max_y) - 1);
-
// set initial values
change_output_lines();
// allocate timers
- m_scan_timer = timer_alloc();
+ m_scan_timer = timer_alloc(FUNC(mm74c922_device::perform_scan), this);
m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(500)); // approximate rate from a 100n capacitor
// register for state saving
@@ -87,10 +82,10 @@ void mm74c922_device::device_start()
//-------------------------------------------------
-// device_timer - handler timer events
+// perform_scan - scan the keyboard matrix
//-------------------------------------------------
-void mm74c922_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mm74c922_device::perform_scan)
{
change_output_lines();
clock_scan_counters();
diff --git a/src/devices/machine/mm74c922.h b/src/devices/machine/mm74c922.h
index fd70c7871ae..c3547c792fe 100644
--- a/src/devices/machine/mm74c922.h
+++ b/src/devices/machine/mm74c922.h
@@ -60,14 +60,15 @@ public:
uint8_t read();
- DECLARE_READ_LINE_MEMBER(da_r) { return m_da; }
+ int da_r() { return m_da; }
protected:
mm74c922_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int max_y);
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(perform_scan);
private:
void change_output_lines();
diff --git a/src/devices/machine/mos6526.cpp b/src/devices/machine/mos6526.cpp
index e1f40b109c1..fae0b8618bc 100644
--- a/src/devices/machine/mos6526.cpp
+++ b/src/devices/machine/mos6526.cpp
@@ -19,6 +19,9 @@
- 8520 read/write
- 5710 read/write
- optimize
+ - off by one errors in vAmigaTS/showcia1 TODLO (reproducible particularly with -nothrottle)
+ - flag_w & amigafdc both auto-inverts index pulses, it also fails ICR vAmigaTS/showcia1 test
+ (expected: 0x00, actual: 0x10)
*/
@@ -120,14 +123,14 @@ DEFINE_DEVICE_TYPE(MOS5710, mos5710_device, "mos5710", "MOS 5710 CIA")
//**************************************************************************
-// INLINE HELPERS
+// DEVICE FUNCTIONS
//**************************************************************************
//-------------------------------------------------
// update_pa - update port A
//-------------------------------------------------
-inline void mos6526_device::update_pa()
+void mos6526_device::update_pa()
{
uint8_t pa = m_pra | (m_pa_in & ~m_ddra);
@@ -143,7 +146,7 @@ inline void mos6526_device::update_pa()
// update_pb - update port B
//-------------------------------------------------
-inline void mos6526_device::update_pb()
+void mos6526_device::update_pb()
{
uint8_t pb = m_prb | (m_pb_in & ~m_ddrb);
@@ -175,7 +178,7 @@ inline void mos6526_device::update_pb()
// set_cra - control register A write
//-------------------------------------------------
-inline void mos6526_device::set_cra(uint8_t data)
+void mos6526_device::set_cra(uint8_t data)
{
if (!CRA_STARTED && (data & CRA_START))
{
@@ -205,7 +208,7 @@ inline void mos6526_device::set_cra(uint8_t data)
// set_crb - control register B write
//-------------------------------------------------
-inline void mos6526_device::set_crb(uint8_t data)
+void mos6526_device::set_crb(uint8_t data)
{
if (!CRB_STARTED && (data & CRB_START))
{
@@ -221,7 +224,7 @@ inline void mos6526_device::set_crb(uint8_t data)
// bcd_increment -
//-------------------------------------------------
-inline uint8_t mos6526_device::bcd_increment(uint8_t value)
+uint8_t mos6526_device::bcd_increment(uint8_t value)
{
value++;
@@ -236,7 +239,7 @@ inline uint8_t mos6526_device::bcd_increment(uint8_t value)
// clock_tod - time-of-day clock pulse
//-------------------------------------------------
-inline void mos6526_device::clock_tod()
+void mos6526_device::clock_tod()
{
uint8_t subsecond = (uint8_t) (m_tod >> 0);
uint8_t second = (uint8_t) (m_tod >> 8);
@@ -290,10 +293,10 @@ inline void mos6526_device::clock_tod()
// clock_tod - time-of-day clock pulse
//-------------------------------------------------
-inline void mos8520_device::clock_tod()
+void mos8520_device::clock_tod()
{
m_tod++;
- m_tod &= 0xffffff;
+ m_tod &= 0x00ffffff;
}
@@ -301,7 +304,7 @@ inline void mos8520_device::clock_tod()
// read_tod - time-of-day read
//-------------------------------------------------
-inline uint8_t mos6526_device::read_tod(int offset)
+uint8_t mos6526_device::read_tod(int offset)
{
int shift = 8 * offset;
@@ -320,7 +323,7 @@ inline uint8_t mos6526_device::read_tod(int offset)
// write_tod - time-of-day write
//-------------------------------------------------
-inline void mos6526_device::write_tod(int offset, uint8_t data)
+void mos6526_device::write_tod(int offset, uint8_t data)
{
int shift = 8 * offset;
@@ -339,7 +342,7 @@ inline void mos6526_device::write_tod(int offset, uint8_t data)
// serial_input -
//-------------------------------------------------
-inline void mos6526_device::serial_input()
+void mos6526_device::serial_input()
{
m_shift <<= 1;
m_bits++;
@@ -360,7 +363,7 @@ inline void mos6526_device::serial_input()
// clock_ta - clock timer A
//-------------------------------------------------
-inline void mos6526_device::clock_ta()
+void mos6526_device::clock_ta()
{
if (m_count_a3)
{
@@ -394,7 +397,7 @@ inline void mos6526_device::clock_ta()
// serial_output -
//-------------------------------------------------
-inline void mos6526_device::serial_output()
+void mos6526_device::serial_output()
{
if (m_ta_out && CRA_SPMODE)
{
@@ -438,7 +441,7 @@ inline void mos6526_device::serial_output()
// clock_tb - clock timer B
//-------------------------------------------------
-inline void mos6526_device::clock_tb()
+void mos6526_device::clock_tb()
{
if (m_count_b3)
{
@@ -472,7 +475,7 @@ inline void mos6526_device::clock_tb()
// update_interrupt -
//-------------------------------------------------
-inline void mos6526_device::update_interrupt()
+void mos6526_device::update_interrupt()
{
if (!m_irq && m_ir1)
{
@@ -498,7 +501,7 @@ inline void mos6526_device::update_interrupt()
// clock_pipeline - clock pipeline
//-------------------------------------------------
-inline void mos6526_device::clock_pipeline()
+void mos6526_device::clock_pipeline()
{
// timer A pipeline
m_count_a3 = m_count_a2;
@@ -556,7 +559,7 @@ inline void mos6526_device::clock_pipeline()
// synchronize -
//-------------------------------------------------
-inline void mos6526_device::synchronize()
+void mos6526_device::synchronize()
{
if (!m_pc)
{
@@ -587,20 +590,20 @@ inline void mos6526_device::synchronize()
// mos6526_device - constructor
//-------------------------------------------------
-mos6526_device::mos6526_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant)
- : device_t(mconfig, type, tag, owner, clock),
- device_execute_interface(mconfig, *this),
- m_icount(0),
- m_variant(variant),
- m_tod_clock(0),
- m_write_irq(*this),
- m_write_pc(*this),
- m_write_cnt(*this),
- m_write_sp(*this),
- m_read_pa(*this),
- m_write_pa(*this),
- m_read_pb(*this),
- m_write_pb(*this)
+mos6526_device::mos6526_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_variant(variant),
+ m_tod_clock(0),
+ m_write_irq(*this),
+ m_write_pc(*this),
+ m_write_cnt(*this),
+ m_write_sp(*this),
+ m_read_pa(*this, 0xff),
+ m_write_pa(*this),
+ m_read_pb(*this, 0xff),
+ m_write_pb(*this)
{
}
@@ -631,20 +634,10 @@ void mos6526_device::device_start()
m_cnt = 1;
m_cra = 0;
- // resolve callbacks
- m_write_irq.resolve_safe();
- m_write_pc.resolve_safe();
- m_write_cnt.resolve_safe();
- m_write_sp.resolve_safe();
- m_read_pa.resolve_safe(0xff);
- m_write_pa.resolve_safe();
- m_read_pb.resolve_safe(0xff);
- m_write_pb.resolve_safe();
-
// allocate timer
- if (m_tod_clock > 0)
+ if (m_tod_clock != 0)
{
- m_tod_timer = timer_alloc();
+ m_tod_timer = timer_alloc(FUNC(mos6526_device::advance_tod_clock), this);
m_tod_timer->adjust(attotime::from_hz(m_tod_clock), 0, attotime::from_hz(m_tod_clock));
}
@@ -737,8 +730,9 @@ void mos6526_device::device_reset()
m_load_b1 = 0;
m_load_b2 = 0;
m_oneshot_b0 = 0;
- m_ta = 0;
- m_tb = 0;
+ // initial state is confirmed floating high as per vAmigaTS/showcia1
+ m_ta = 0xffff;
+ m_tb = 0xffff;
m_ta_latch = 0xffff;
m_tb_latch = 0xffff;
m_cra = 0;
@@ -758,11 +752,7 @@ void mos6526_device::device_reset()
}
-//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void mos6526_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mos6526_device::advance_tod_clock)
{
tod_w(1);
tod_w(0);
@@ -902,7 +892,10 @@ uint8_t mos6526_device::read(offs_t offset)
case ICR:
data = (m_ir1 << 7) | m_icr;
- if (machine().side_effects_disabled())
+ // Do not reset irqs unless one is effectively issued.
+ // cfr. amigaocs_flop.xml barb2paln4 that polls for Timer B status
+ // until it expires at PC=7821c and other places.
+ if (machine().side_effects_disabled() || !m_icr)
return data;
m_icr_read = true;
@@ -942,8 +935,9 @@ uint8_t mos8520_device::read(offs_t offset)
data = read_tod(2);
break;
+ // unused register returns floating high as per vAmigaTS/showcia1
case TOD_HR:
- data = read_tod(3);
+ data = 0xff;
break;
default:
@@ -1113,7 +1107,7 @@ void mos8520_device::write(offs_t offset, uint8_t data)
break;
case TOD_HR:
- write_tod(3, data);
+ // ignored in mos8520
break;
}
}
@@ -1123,7 +1117,7 @@ void mos8520_device::write(offs_t offset, uint8_t data)
// sp_w - serial port write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mos6526_device::sp_w )
+void mos6526_device::sp_w(int state)
{
m_sp = state;
}
@@ -1133,7 +1127,7 @@ WRITE_LINE_MEMBER( mos6526_device::sp_w )
// cnt_w - serial counter write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mos6526_device::cnt_w )
+void mos6526_device::cnt_w(int state)
{
if (CRA_SPMODE) return;
@@ -1156,7 +1150,7 @@ WRITE_LINE_MEMBER( mos6526_device::cnt_w )
// flag_w - flag write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mos6526_device::flag_w )
+void mos6526_device::flag_w(int state)
{
if (m_flag && !state)
{
@@ -1171,7 +1165,7 @@ WRITE_LINE_MEMBER( mos6526_device::flag_w )
// tod_w - time-of-day clock write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mos6526_device::tod_w )
+void mos6526_device::tod_w(int state)
{
if (state && !m_tod_stopped)
{
diff --git a/src/devices/machine/mos6526.h b/src/devices/machine/mos6526.h
index 33ccc6dd26d..637124cc733 100644
--- a/src/devices/machine/mos6526.h
+++ b/src/devices/machine/mos6526.h
@@ -91,13 +91,13 @@ public:
uint8_t pa_r() { return m_pa; }
uint8_t pb_r() { return m_pb; }
- DECLARE_READ_LINE_MEMBER( sp_r ) { return m_sp; }
- DECLARE_WRITE_LINE_MEMBER( sp_w );
- DECLARE_READ_LINE_MEMBER( cnt_r ) { return m_cnt; }
- DECLARE_WRITE_LINE_MEMBER( cnt_w );
- DECLARE_WRITE_LINE_MEMBER( flag_w );
- DECLARE_READ_LINE_MEMBER( irq_r ) { return m_irq; }
- DECLARE_WRITE_LINE_MEMBER( tod_w );
+ int sp_r() { return m_sp; }
+ void sp_w(int state);
+ int cnt_r() { return m_cnt; }
+ void cnt_w(int state);
+ void flag_w(int state);
+ int irq_r() { return m_irq; }
+ void tod_w(int state);
protected:
enum
@@ -113,28 +113,29 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void execute_run() override;
+ TIMER_CALLBACK_MEMBER(advance_tod_clock);
+
int m_icount;
const int m_variant;
int m_tod_clock;
- inline void update_interrupt();
- inline void update_pa();
- inline void update_pb();
- inline void set_cra(uint8_t data);
- inline void set_crb(uint8_t data);
- inline void serial_input();
- inline void serial_output();
- inline void clock_ta();
- inline void clock_tb();
- inline void clock_pipeline();
- inline uint8_t bcd_increment(uint8_t value);
- virtual inline void clock_tod();
- inline uint8_t read_tod(int offset);
- inline void write_tod(int offset, uint8_t data);
- inline void synchronize();
+ void update_interrupt();
+ void update_pa();
+ void update_pb();
+ void set_cra(uint8_t data);
+ void set_crb(uint8_t data);
+ void serial_input();
+ void serial_output();
+ void clock_ta();
+ void clock_tb();
+ void clock_pipeline();
+ uint8_t bcd_increment(uint8_t value);
+ virtual void clock_tod();
+ uint8_t read_tod(int offset);
+ void write_tod(int offset, uint8_t data);
+ void synchronize();
devcb_write_line m_write_irq;
devcb_write_line m_write_pc;
@@ -232,7 +233,7 @@ public:
void write(offs_t offset, uint8_t data);
protected:
- virtual inline void clock_tod() override;
+ virtual void clock_tod() override;
};
diff --git a/src/devices/machine/mos6529.cpp b/src/devices/machine/mos6529.cpp
index 46bbf3bc0b8..fbfe7f067ac 100644
--- a/src/devices/machine/mos6529.cpp
+++ b/src/devices/machine/mos6529.cpp
@@ -45,8 +45,6 @@ mos6529_device::mos6529_device(const machine_config &mconfig, const char *tag, d
void mos6529_device::device_start()
{
- // resolve callbacks
- m_p_handler.resolve_all_safe();
}
diff --git a/src/devices/machine/mos6530.cpp b/src/devices/machine/mos6530.cpp
index 8cc7198b3e5..599e3962bc8 100644
--- a/src/devices/machine/mos6530.cpp
+++ b/src/devices/machine/mos6530.cpp
@@ -1,383 +1,594 @@
// license:BSD-3-Clause
// copyright-holders:Curt Coder
-/***************************************************************************
+/**********************************************************************
- MOS 6530 MIOT emulation
- Memory, I/O, Timer Array (Rockwell calls it RRIOT: ROM, RAM, I/O, Timer)
+ MOS Technology 6530 MIOT (Memory, I/O, Timer Array)
+ Rockwell calls it RRIOT: ROM, RAM, I/O, Timer
-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.
+ MOS Technology 6532 RIOT (RAM, I/O, Timer Array)
-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"
+#define LOG_TIMER (1U << 1)
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
+//#define VERBOSE (LOG_GENERAL | LOG_TIMER)
+#include "logmacro.h"
-enum
-{
- TIMER_IDLE,
- TIMER_COUNTING,
- TIMER_FINISHING
-};
+#define LOGTIMER(...) LOGMASKED(LOG_TIMER, __VA_ARGS__)
-#define TIMER_FLAG 0x80
-/***************************************************************************
- DEVICE INTERFACE
-***************************************************************************/
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
DEFINE_DEVICE_TYPE(MOS6530, mos6530_device, "mos6530", "MOS 6530 MIOT")
+DEFINE_DEVICE_TYPE(MOS6532, mos6532_device, "mos6532", "MOS 6532 RIOT")
+
+
+void mos6530_device::rom_map(address_map &map)
+{
+ map.global_mask(0x3ff);
+ map(0x000, 0x3ff).r(FUNC(mos6530_device::rom_r));
+}
+
+void mos6530_device::ram_map(address_map &map)
+{
+ map.global_mask(0x3f);
+ map(0x00, 0x3f).rw(FUNC(mos6530_device::ram_r), FUNC(mos6530_device::ram_w));
+}
+
+void mos6530_device::io_map(address_map &map)
+{
+ map.global_mask(0xf);
+ map(0x00, 0x00).mirror(0x8).rw(FUNC(mos6530_device::pa_data_r), FUNC(mos6530_device::pa_data_w));
+ map(0x01, 0x01).mirror(0x8).rw(FUNC(mos6530_device::pa_ddr_r), FUNC(mos6530_device::pa_ddr_w));
+ map(0x02, 0x02).mirror(0x8).rw(FUNC(mos6530_device::pb_data_r), FUNC(mos6530_device::pb_data_w));
+ map(0x03, 0x03).mirror(0x8).rw(FUNC(mos6530_device::pb_ddr_r), FUNC(mos6530_device::pb_ddr_w));
+ map(0x04, 0x07).w(FUNC(mos6530_device::timer_off_w));
+ map(0x0c, 0x0f).w(FUNC(mos6530_device::timer_on_w));
+ map(0x04, 0x04).mirror(0x2).r(FUNC(mos6530_device::timer_off_r));
+ map(0x0c, 0x0c).mirror(0x2).r(FUNC(mos6530_device::timer_on_r));
+ map(0x05, 0x05).mirror(0xa).r(FUNC(mos6530_device::irq_r));
+}
-mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MOS6530, tag, owner, clock),
- m_in_pa_cb(*this),
- m_out_pa_cb(*this),
- m_in_pb_cb(*this),
- m_out_pb_cb(*this)
+void mos6532_device::ram_map(address_map &map)
{
+ map.global_mask(0x7f);
+ map(0x00, 0x7f).rw(FUNC(mos6532_device::ram_r), FUNC(mos6532_device::ram_w));
}
+void mos6532_device::io_map(address_map &map)
+{
+ map.global_mask(0x1f);
+ map(0x00, 0x00).mirror(0x18).rw(FUNC(mos6532_device::pa_data_r), FUNC(mos6532_device::pa_data_w));
+ map(0x01, 0x01).mirror(0x18).rw(FUNC(mos6532_device::pa_ddr_r), FUNC(mos6532_device::pa_ddr_w));
+ map(0x02, 0x02).mirror(0x18).rw(FUNC(mos6532_device::pb_data_r), FUNC(mos6532_device::pb_data_w));
+ map(0x03, 0x03).mirror(0x18).rw(FUNC(mos6532_device::pb_ddr_r), FUNC(mos6532_device::pb_ddr_w));
+ map(0x14, 0x17).w(FUNC(mos6532_device::timer_off_w));
+ map(0x1c, 0x1f).w(FUNC(mos6532_device::timer_on_w));
+ map(0x04, 0x04).mirror(0x12).r(FUNC(mos6532_device::timer_off_r));
+ map(0x0c, 0x0c).mirror(0x12).r(FUNC(mos6532_device::timer_on_r));
+ map(0x05, 0x05).mirror(0x1a).r(FUNC(mos6532_device::irq_r));
+ map(0x04, 0x07).mirror(0x8).w(FUNC(mos6532_device::edge_w));
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
//-------------------------------------------------
-// device_start - device-specific startup
+// mos6530_device_base - constructor
//-------------------------------------------------
-void mos6530_device::device_start()
-{
- /* set static values */
- m_clock = clock();
+mos6530_device_base::mos6530_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 rsize) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_ram(*this, finder_base::DUMMY_TAG, rsize, ENDIANNESS_LITTLE),
+ m_rom(*this, DEVICE_SELF),
+ m_irq_cb(*this),
+ m_in8_pa_cb(*this, 0),
+ m_out8_pa_cb(*this),
+ m_in8_pb_cb(*this, 0),
+ m_out8_pb_cb(*this),
+ m_in_pa_cb(*this, 0),
+ m_out_pa_cb(*this),
+ m_in_pb_cb(*this, 0),
+ m_out_pb_cb(*this),
+ m_pa_in(0xff),
+ m_pa_out(0),
+ m_pa_ddr(0),
+ m_pa7(1),
+ m_pa7_dir(0),
+ m_pb_in(0xff),
+ m_pb_out(0),
+ m_pb_ddr(0),
+ m_ie_timer(false),
+ m_irq_timer(false),
+ m_ie_edge(false),
+ m_irq_edge(false)
+{ }
+
+
+//-------------------------------------------------
+// mos6530_device - constructor
+//-------------------------------------------------
+
+mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ mos6530_device_base(mconfig, MOS6530, tag, owner, clock, 0x40)
+{ }
- /* resolve callbacks */
- m_in_pa_cb.resolve_safe(0);
- m_out_pa_cb.resolve_safe();
- m_in_pb_cb.resolve_safe(0);
- m_out_pb_cb.resolve_safe();
- /* allocate timers */
- m_timer = timer_alloc(TIMER_END_CALLBACK);
+//-------------------------------------------------
+// mos6532_device - constructor
+//-------------------------------------------------
- /* register for save states */
- save_item(NAME(m_port[0].m_in));
- save_item(NAME(m_port[0].m_out));
- save_item(NAME(m_port[0].m_ddr));
- save_item(NAME(m_port[1].m_in));
- save_item(NAME(m_port[1].m_out));
- save_item(NAME(m_port[1].m_ddr));
+mos6532_device::mos6532_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ mos6530_device_base(mconfig, MOS6532, tag, owner, clock, 0x80)
+{ }
- save_item(NAME(m_irqstate));
- save_item(NAME(m_irqenable));
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mos6530_device_base::device_start()
+{
+ // allocate timer
+ m_timer = timer_alloc(FUNC(mos6530_device_base::timer_end), this);
+ m_timershift = 10;
+ m_timerstate = TIMER_COUNTING;
+ m_timer->adjust(attotime::from_ticks(256 << m_timershift, clock()));
+
+ // state saving
+ save_item(NAME(m_pa_in));
+ save_item(NAME(m_pa_out));
+ save_item(NAME(m_pa_ddr));
+ save_item(NAME(m_pa7));
+ save_item(NAME(m_pa7_dir));
+
+ save_item(NAME(m_pb_in));
+ save_item(NAME(m_pb_out));
+ save_item(NAME(m_pb_ddr));
+
+ save_item(NAME(m_ie_timer));
+ save_item(NAME(m_irq_timer));
+ save_item(NAME(m_ie_edge));
+ save_item(NAME(m_irq_edge));
save_item(NAME(m_timershift));
save_item(NAME(m_timerstate));
+ save_item(NAME(m_timeout));
}
+
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
-void mos6530_device::device_reset()
+void mos6530_device_base::device_reset()
{
- /* reset I/O states */
- m_port[0].m_out = 0;
- m_port[0].m_ddr = 0;
- m_port[1].m_out = 0;
- m_port[1].m_ddr = 0;
+ m_pa_out = 0;
+ m_pa_ddr = 0;
+ m_pb_out = 0;
+ m_pb_ddr = 0;
+
+ m_ie_timer = false;
+ m_ie_edge = false;
+ m_irq_edge = false;
+ m_pa7_dir = 0;
+
+ update_pa();
+ update_pb();
+ update_irq();
+ edge_detect();
+}
- /* reset IRQ states */
- m_irqenable = 0;
- m_irqstate = TIMER_FLAG;
- update_irqstate();
- /* reset timer states */
- m_timershift = 0;
- m_timerstate = TIMER_IDLE;
- m_timer->adjust(attotime::never);
+//-------------------------------------------------
+// update_pa -
+//-------------------------------------------------
+
+void mos6530_device_base::update_pa()
+{
+ uint8_t data = (m_pa_out & m_pa_ddr) | (m_pa_ddr ^ 0xff);
+
+ if (m_out8_pa_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ m_out_pa_cb[i](BIT(data, i));
+ }
+ else
+ m_out8_pa_cb(data);
}
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
+//-------------------------------------------------
+// update_pb -
+//-------------------------------------------------
+void mos6530_device_base::update_pb()
+{
+ uint8_t data = (m_pb_out & m_pb_ddr) | (m_pb_ddr ^ 0xff);
-/*-------------------------------------------------
- update_irqstate - update the IRQ state
- based on interrupt enables
--------------------------------------------------*/
+ if (m_out8_pb_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ m_out_pb_cb[i](BIT(data, i));
+ }
+ else
+ m_out8_pb_cb(data);
+}
-void mos6530_device::update_irqstate()
+void mos6530_device::update_pb()
{
- uint8_t out = m_port[1].m_out;
+ uint8_t data = (m_pb_out & m_pb_ddr) | (m_pb_ddr ^ 0xff);
- if (m_irqenable)
- out = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (out & 0x7F);
+ if (!BIT(m_pb_ddr, 7))
+ {
+ // active low!
+ if (m_ie_timer && m_irq_timer)
+ data &= ~IRQ_TIMER;
+ else
+ data |= IRQ_TIMER;
+ }
+
+ if (m_out8_pb_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ m_out_pb_cb[i](BIT(data, i));
+ }
+ else
+ m_out8_pb_cb(data);
- m_out_pb_cb((offs_t)0, out);
+ m_irq_cb(BIT(data, 7) ? CLEAR_LINE: ASSERT_LINE);
}
-/*-------------------------------------------------
- get_timer - return the current timer value
--------------------------------------------------*/
+//-------------------------------------------------
+// update_irq -
+//-------------------------------------------------
-uint8_t mos6530_device::get_timer()
+void mos6530_device_base::update_irq()
{
- /* if idle, return 0 */
- if (m_timerstate == TIMER_IDLE)
- return 0;
+ int state = CLEAR_LINE;
- /* if counting, return the number of ticks remaining */
- else if (m_timerstate == TIMER_COUNTING)
- return m_timer->remaining().as_ticks(m_clock) >> m_timershift;
+ if (m_ie_timer && m_irq_timer) state = ASSERT_LINE;
+ if (m_ie_edge && m_irq_edge) state = ASSERT_LINE;
- /* if finishing, return the number of ticks without the shift */
- else
- return m_timer->remaining().as_ticks(m_clock);
+ m_irq_cb(state);
}
+void mos6530_device::update_irq()
+{
+ update_pb();
+}
-/***************************************************************************
- INTERNAL FUNCTIONS
-***************************************************************************/
-/*-------------------------------------------------
- timer_end_callback - callback to process the
- timer
--------------------------------------------------*/
+//-------------------------------------------------
+// get_irq_flags -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::get_irq_flags()
+{
+ uint8_t data = 0;
+
+ if (m_irq_timer) data |= IRQ_TIMER;
+ if (m_irq_edge) data |= IRQ_EDGE;
+
+ return data;
+}
-void mos6530_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+uint8_t mos6530_device::get_irq_flags()
{
- switch (id)
+ uint8_t data = 0;
+
+ if (m_irq_timer) data |= IRQ_TIMER;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// get_timer - return the current timer value
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::get_timer()
+{
+ // determine the number of ticks remaining
+ uint8_t shift = (m_timerstate == TIMER_COUNTING) ? m_timershift : 0;
+ int64_t remain = m_timer->remaining().as_ticks(clock());
+ uint8_t val = remain >> shift;
+
+ // timeout is at 255, so round it down
+ return (remain & ((1 << shift) - 1)) ? val : (val - 1);
+}
+
+
+//-------------------------------------------------
+// timer_start - restart timer counter
+//-------------------------------------------------
+
+void mos6530_device_base::timer_start(uint8_t data)
+{
+ m_timerstate = TIMER_COUNTING;
+ attotime curtime = machine().time();
+ int64_t target = curtime.as_ticks(clock()) + 1 + (data << m_timershift);
+ m_timer->adjust(attotime::from_ticks(target, clock()) - curtime);
+}
+
+
+//-------------------------------------------------
+// timer_end -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(mos6530_device_base::timer_end)
+{
+ // if we finished counting, signal timer IRQ
+ if (m_timerstate == TIMER_COUNTING)
{
- // deferred reset
- case TIMER_END_CALLBACK:
- assert(m_timerstate != TIMER_IDLE);
-
- /* if we finished counting, switch to the finishing state */
- if (m_timerstate == TIMER_COUNTING)
- {
- m_timerstate = TIMER_FINISHING;
- m_timer->adjust(attotime::from_ticks(256, m_clock));
-
- /* signal timer IRQ as well */
- m_irqstate |= TIMER_FLAG;
- update_irqstate();
- }
-
- /* if we finished finishing, switch to the idle state */
- else if (m_timerstate == TIMER_FINISHING)
- {
- m_timerstate = TIMER_IDLE;
- m_timer->adjust(attotime::never);
- }
- break;
+ m_timeout = machine().time();
+ m_irq_timer = true;
+ update_irq();
}
+
+ // if we finished, keep spinning without the prescaler
+ m_timerstate = TIMER_SPINNING;
+ m_timer->adjust(attotime::from_ticks(256, clock()));
}
-/***************************************************************************
- I/O ACCESS
-***************************************************************************/
-/*-------------------------------------------------
- mos6530_w - master I/O write access
--------------------------------------------------*/
+//-------------------------------------------------
+// edge_detect -
+//-------------------------------------------------
-void mos6530_device::write(offs_t offset, uint8_t data)
+void mos6530_device_base::edge_detect()
{
- /* if A2 == 1, we are writing to the timer */
- if (offset & 0x04)
+ uint8_t data = (m_pa_out & m_pa_ddr) | (m_pa_in & ~m_pa_ddr);
+ int state = BIT(data, 7);
+
+ if ((m_pa7 ^ state) && !(m_pa7_dir ^ state) && !m_irq_edge)
{
- static const uint8_t timershift[4] = { 0, 3, 6, 10 };
- attotime curtime = machine().time();
- int64_t target;
+ LOG("%s %s edge-detect IRQ\n", machine().time().as_string(), name());
- /* A0-A1 contain the timer divisor */
- m_timershift = timershift[offset & 3];
+ m_irq_edge = true;
+ update_irq();
+ }
- /* A3 contains the timer IRQ enable */
- if (offset & 8)
- m_irqenable |= TIMER_FLAG;
- else
- m_irqenable &= ~TIMER_FLAG;
+ m_pa7 = state;
+}
- /* writes here clear the timer flag */
- if (m_timerstate != TIMER_FINISHING || get_timer() != 0xff)
- m_irqstate &= ~TIMER_FLAG;
- update_irqstate();
- /* update the timer */
- m_timerstate = TIMER_COUNTING;
- target = curtime.as_ticks(m_clock) + 1 + (data << m_timershift);
- m_timer->adjust(attotime::from_ticks(target, m_clock) - curtime);
- }
+//-------------------------------------------------
+// pa_w -
+//-------------------------------------------------
- /* if A2 == 0, we are writing to the I/O section */
- else
- {
- /* A1 selects the port */
- mos6530_port *port = &m_port[BIT(offset, 1)];
+void mos6530_device_base::pa_w(offs_t offset, uint8_t data, uint8_t mem_mask)
+{
+ LOG("%s %s %s Port A Data Write %02X Mask %02X\n", machine().time().as_string(), machine().describe_context(), name(), data, mem_mask);
- /* if A0 == 1, we are writing to the port's DDR */
- if (offset & 1)
- port->m_ddr = data;
+ m_pa_in = (m_pa_in & ~mem_mask) | (data & mem_mask);
+ edge_detect();
+}
- /* if A0 == 0, we are writing to the port's output */
- else
- {
- uint8_t olddata = port->m_out;
- port->m_out = data;
-
- if ((offset & 2) && m_irqenable)
- {
- olddata = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (olddata & 0x7F);
- data = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (data & 0x7F);
- }
-
- if (!BIT(offset, 1))
- m_out_pa_cb((offs_t)0, data);
- else
- m_out_pb_cb((offs_t)0, data);
- }
- }
+
+//-------------------------------------------------
+// pb_w -
+//-------------------------------------------------
+
+void mos6530_device_base::pb_w(offs_t offset, uint8_t data, uint8_t mem_mask)
+{
+ LOG("%s %s %s Port B Data Write %02X Mask %02X\n", machine().time().as_string(), machine().describe_context(), name(), data, mem_mask);
+
+ m_pb_in = (m_pb_in & ~mem_mask) | (data & mem_mask);
}
-/*-------------------------------------------------
- mos6530_r - master I/O read access
--------------------------------------------------*/
+//-------------------------------------------------
+// pa_data_r -
+//-------------------------------------------------
-uint8_t mos6530_device::read(offs_t offset)
+uint8_t mos6530_device_base::pa_data_r()
{
- uint8_t val;
+ uint8_t in = 0;
- /* if A2 == 1 and A0 == 1, we are reading interrupt flags */
- if ((offset & 0x05) == 0x05)
+ if (m_in8_pa_cb.isunset())
{
- val = m_irqstate;
+ for (int i = 0; i < 8; i++)
+ in |= (m_in_pa_cb[i].isunset() ? BIT(m_pa_in, i) : m_in_pa_cb[i]()) << i;
}
+ else
+ in = m_in8_pa_cb();
- /* if A2 == 1 and A0 == 0, we are reading the timer */
- else if ((offset & 0x05) == 0x04)
- {
- val = get_timer();
+ uint8_t data = (m_pa_out & m_pa_ddr) | (in & ~m_pa_ddr);
- /* A3 contains the timer IRQ enable */
- if (offset & 8)
- m_irqenable |= TIMER_FLAG;
- else
- m_irqenable &= ~TIMER_FLAG;
+ LOG("%s %s %s Port A Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
- /* implicitly clears the timer flag */
- if (m_timerstate != TIMER_FINISHING || val != 0xff)
- m_irqstate &= ~TIMER_FLAG;
- update_irqstate();
- }
+ return data;
+}
- /* if A2 == 0 and A0 == anything, we are reading from ports */
- else
- {
- /* A1 selects the port */
- mos6530_port *port = &m_port[BIT(offset, 1)];
- /* if A0 == 1, we are reading the port's DDR */
- if (offset & 1)
- val = port->m_ddr;
+//-------------------------------------------------
+// pa_data_w -
+//-------------------------------------------------
- /* if A0 == 0, we are reading the port as an input */
- else
- {
- uint8_t out = port->m_out;
+void mos6530_device_base::pa_data_w(uint8_t data)
+{
+ m_pa_out = data;
- if ((offset & 2) && m_irqenable)
- out = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (out & 0x7F);
+ LOG("%s %s %s Port A Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
- /* call the input callback if it exists */
- if (!BIT(offset, 1))
- port->m_in = m_in_pa_cb(0);
- else
- port->m_in = m_in_pb_cb(0);
+ update_pa();
+ edge_detect();
+}
- /* apply the DDR to the result */
- val = (out & port->m_ddr) | (port->m_in & ~port->m_ddr);
- }
+
+//-------------------------------------------------
+// pa_ddr_w -
+//-------------------------------------------------
+
+void mos6530_device_base::pa_ddr_w(uint8_t data)
+{
+ m_pa_ddr = data;
+
+ LOG("%s %s %s Port A DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ update_pa();
+ edge_detect();
+}
+
+
+//-------------------------------------------------
+// pb_data_r -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::pb_data_r()
+{
+ uint8_t in = 0;
+
+ if (m_in8_pb_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ in |= (m_in_pb_cb[i].isunset() ? BIT(m_pb_in, i) : m_in_pb_cb[i]()) << i;
}
- return val;
+ else
+ in = m_in8_pb_cb();
+
+ uint8_t data = (m_pb_out & m_pb_ddr) | (in & ~m_pb_ddr);
+
+ LOG("%s %s %s Port B Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ return data;
}
-/*-------------------------------------------------
- mos6530_porta_in_set - set port A input
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// pb_data_w -
+//-------------------------------------------------
-void mos6530_device::porta_in_set(uint8_t data, uint8_t mask)
+void mos6530_device_base::pb_data_w(uint8_t data)
{
- m_port[0].m_in = (m_port[0].m_in & ~mask) | (data & mask);
+ m_pb_out = data;
+
+ LOG("%s %s %s Port B Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ update_pb();
}
-/*-------------------------------------------------
- mos6530_portb_in_set - set port B input
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// pb_ddr_w -
+//-------------------------------------------------
-void mos6530_device::portb_in_set(uint8_t data, uint8_t mask)
+void mos6530_device_base::pb_ddr_w(uint8_t data)
{
- m_port[1].m_in = (m_port[1].m_in & ~mask) | (data & mask);
+ m_pb_ddr = data;
+
+ LOG("%s %s %s Port B DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ update_pb();
}
-/*-------------------------------------------------
- mos6530_porta_in_get - return port A input
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// timer_r -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::timer_off_r()
+{
+ return timer_r(false);
+}
-uint8_t mos6530_device::porta_in_get()
+uint8_t mos6530_device_base::timer_on_r()
{
- return m_port[0].m_in;
+ return timer_r(true);
}
+uint8_t mos6530_device_base::timer_r(bool ie)
+{
+ uint8_t data = get_timer();
+
+ if (!machine().side_effects_disabled())
+ {
+ // IRQ is not cleared when reading at the same time IRQ is raised
+ if (m_timeout < machine().time() - attotime::from_hz(2 * clock()))
+ {
+ m_irq_timer = false;
+
+ // timer goes back to count mode
+ if (m_timerstate == TIMER_SPINNING)
+ timer_start(data);
+ }
-/*-------------------------------------------------
- mos6530_portb_in_get - return port B input
- value
--------------------------------------------------*/
+ m_ie_timer = ie;
+ update_irq();
-uint8_t mos6530_device::portb_in_get()
+ LOGTIMER("%s %s %s Timer read %02x IE %u\n", machine().time().as_string(), machine().describe_context(), name(), data, m_ie_timer ? 1 : 0);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// irq_r -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::irq_r()
{
- return m_port[1].m_in;
+ uint8_t data = get_irq_flags();
+
+ if (!machine().side_effects_disabled() && m_irq_edge)
+ {
+ m_irq_edge = false;
+ update_irq();
+ }
+
+ return data;
}
-/*-------------------------------------------------
- mos6530_porta_in_get - return port A output
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// timer_w -
+//-------------------------------------------------
+
+void mos6530_device_base::timer_off_w(offs_t offset, uint8_t data)
+{
+ timer_w(offset, data, false);
+}
+
+void mos6530_device_base::timer_on_w(offs_t offset, uint8_t data)
+{
+ timer_w(offset, data, true);
+}
-uint8_t mos6530_device::porta_out_get()
+void mos6530_device_base::timer_w(offs_t offset, uint8_t data, bool ie)
{
- return m_port[0].m_out;
+ // A0-A1 contain the prescaler
+ static const uint8_t timershift[4] = { 0, 3, 6, 10 };
+ m_timershift = timershift[offset & 3];
+ timer_start(data);
+
+ m_irq_timer = false;
+ m_ie_timer = ie;
+ update_irq();
+
+ LOGTIMER("%s %s %s Timer value %02x prescale %u IE %u\n", machine().time().as_string(), machine().describe_context(), name(), data, 1 << m_timershift, m_ie_timer ? 1 : 0);
}
-/*-------------------------------------------------
- mos6530_portb_in_get - return port B output
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// edge_w -
+//-------------------------------------------------
-uint8_t mos6530_device::portb_out_get()
+void mos6530_device_base::edge_w(offs_t offset, uint8_t data)
{
- return m_port[1].m_out;
+ m_pa7_dir = BIT(offset, 0);
+ m_ie_edge = bool(BIT(offset, 1));
+ update_irq();
+
+ LOG("%s %s %s %s edge-detect, %s interrupt\n", machine().time().as_string(), machine().describe_context(), name(), m_pa7_dir ? "positive" : "negative", m_ie_edge ? "enable" : "disable");
}
diff --git a/src/devices/machine/mos6530.h b/src/devices/machine/mos6530.h
index 0639544d8e0..1e814623b2c 100644
--- a/src/devices/machine/mos6530.h
+++ b/src/devices/machine/mos6530.h
@@ -2,7 +2,7 @@
// copyright-holders:Curt Coder
/**********************************************************************
- MOS Technology 6530 Memory, I/O, Timer Array emulation
+ MOS Technology 6530 MIOT, 6532 RIOT
**********************************************************************
_____ _____
@@ -27,6 +27,28 @@
CS2/PB5 19 | | 22 PB3
Vcc 20 |_____________| 21 PB4
+ _____ _____
+ Vss 1 |* \_/ | 40 A6
+ A5 2 | | 39 phi2
+ A4 3 | | 38 CS1
+ A3 4 | | 37 _CS2
+ A2 5 | | 36 _RS
+ A1 6 | | 35 R/W
+ A0 7 | | 34 _RES
+ PA0 8 | | 33 D0
+ PA1 9 | | 32 D1
+ PA2 10 | MCS6532 | 31 D2
+ PA3 11 | | 30 D3
+ PA4 12 | | 29 D4
+ PA5 13 | | 28 D5
+ PA6 14 | | 27 D6
+ PA7 15 | | 26 D7
+ PB7 16 | | 25 _IRQ
+ PB6 17 | | 24 PB0
+ PB5 18 | | 23 PB1
+ PB4 19 | | 22 PB2
+ Vcc 20 |_____________| 21 PB3
+
**********************************************************************/
#ifndef MAME_MACHINE_MOS6530_H
@@ -34,78 +56,152 @@
#pragma once
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/***************************************************************************
- MACROS / CONSTANTS
-***************************************************************************/
+// ======================> mos6530_device_base
-class mos6530_device : public device_t
+class mos6530_device_base : public device_t
{
public:
- mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto in_pa_callback() { return m_in_pa_cb.bind(); }
- auto out_pa_callback() { return m_out_pa_cb.bind(); }
- auto in_pb_callback() { return m_in_pb_cb.bind(); }
- auto out_pb_callback() { return m_out_pb_cb.bind(); }
-
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
-
- uint8_t porta_in_get();
- uint8_t portb_in_get();
-
- uint8_t porta_out_get();
- uint8_t portb_out_get();
+ // port byte callbacks
+ auto pa_rd_callback() { return m_in8_pa_cb.bind(); }
+ auto pa_wr_callback() { return m_out8_pa_cb.bind(); }
+ auto pb_rd_callback() { return m_in8_pb_cb.bind(); }
+ auto pb_wr_callback() { return m_out8_pb_cb.bind(); }
+
+ // port bit callbacks
+ template <unsigned N> auto pa_rd_callback() { return m_in_pa_cb[N].bind(); }
+ template <unsigned N> auto pa_wr_callback() { return m_out_pa_cb[N].bind(); }
+ template <unsigned N> auto pb_rd_callback() { return m_in_pb_cb[N].bind(); }
+ template <unsigned N> auto pb_wr_callback() { return m_out_pb_cb[N].bind(); }
+
+ // _IRQ pin (on 6530 it's shared with PB7)
+ auto irq_wr_callback() { return m_irq_cb.bind(); }
+
+ // write to port inputs (PA7 can trigger an IRQ, the others are normal inputs)
+ void pa_w(offs_t offset, uint8_t data, uint8_t mem_mask = 0xff);
+ void pb_w(offs_t offset, uint8_t data, uint8_t mem_mask = 0xff);
+ template <unsigned N> void pa_bit_w(int state) { pa_w(0, (state & 1) << N, 1 << N); }
+ template <unsigned N> void pb_bit_w(int state) { pb_w(0, (state & 1) << N, 1 << N); }
protected:
+ // construction/destruction
+ mos6530_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 rsize);
+
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-private:
enum
{
- TIMER_END_CALLBACK
+ IRQ_EDGE = 0x40,
+ IRQ_TIMER = 0x80
};
- struct mos6530_port
+ enum
{
- uint8_t m_in;
- uint8_t m_out;
- uint8_t m_ddr;
+ TIMER_COUNTING,
+ TIMER_SPINNING
};
- // internal state
- devcb_read8 m_in_pa_cb;
- devcb_write8 m_out_pa_cb;
+ void update_pa();
+ virtual void update_pb();
+ virtual void update_irq();
+ virtual uint8_t get_irq_flags();
+ uint8_t get_timer();
+ void timer_start(uint8_t data);
+ TIMER_CALLBACK_MEMBER(timer_end);
+ void edge_detect();
+
+ void timer_w(offs_t offset, uint8_t data, bool ie);
+ uint8_t timer_r(bool ie);
+
+ uint8_t rom_r(offs_t offset) { return m_rom[offset]; }
+ uint8_t ram_r(offs_t offset) { return m_ram[offset]; }
+ void ram_w(offs_t offset, uint8_t data) { m_ram[offset] = data; }
+ uint8_t pa_data_r();
+ void pa_data_w(uint8_t data);
+ uint8_t pb_data_r();
+ void pb_data_w(uint8_t data);
+ uint8_t pa_ddr_r() { return m_pa_ddr; }
+ void pa_ddr_w(uint8_t data);
+ uint8_t pb_ddr_r() { return m_pb_ddr; }
+ void pb_ddr_w(uint8_t data);
+ uint8_t timer_off_r();
+ uint8_t timer_on_r();
+ uint8_t irq_r();
+ void timer_off_w(offs_t offset, uint8_t data);
+ void timer_on_w(offs_t offset, uint8_t data);
+ void edge_w(offs_t offset, uint8_t data);
+
+ memory_share_creator<uint8_t> m_ram;
+ optional_region_ptr<uint8_t> m_rom;
+
+ devcb_write_line m_irq_cb;
+ devcb_read8 m_in8_pa_cb;
+ devcb_write8 m_out8_pa_cb;
+ devcb_read8 m_in8_pb_cb;
+ devcb_write8 m_out8_pb_cb;
+ devcb_read_line::array<8> m_in_pa_cb;
+ devcb_write_line::array<8> m_out_pa_cb;
+ devcb_read_line::array<8> m_in_pb_cb;
+ devcb_write_line::array<8> m_out_pb_cb;
+
+ uint8_t m_pa_in;
+ uint8_t m_pa_out;
+ uint8_t m_pa_ddr;
+ int m_pa7;
+ int m_pa7_dir;
+
+ uint8_t m_pb_in;
+ uint8_t m_pb_out;
+ uint8_t m_pb_ddr;
+
+ bool m_ie_timer;
+ bool m_irq_timer;
+ bool m_ie_edge;
+ bool m_irq_edge;
+
+ uint8_t m_timershift;
+ uint8_t m_timerstate;
+ emu_timer *m_timer;
+ attotime m_timeout;
+};
- devcb_read8 m_in_pb_cb;
- devcb_write8 m_out_pb_cb;
- mos6530_port m_port[2];
+class mos6530_device : public mos6530_device_base
+{
+public:
+ // construction/destruction
+ mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- uint8_t m_irqstate;
- uint8_t m_irqenable;
+ virtual void rom_map(address_map &map);
+ virtual void ram_map(address_map &map);
+ virtual void io_map(address_map &map);
- uint8_t m_timershift;
- uint8_t m_timerstate;
- emu_timer * m_timer;
+protected:
+ // device-level overrides
+ void update_pb() override;
+ void update_irq() override;
+ uint8_t get_irq_flags() override;
+};
- uint32_t m_clock;
- void update_irqstate();
- uint8_t get_timer();
+class mos6532_device : public mos6530_device_base
+{
+public:
+ // construction/destruction
+ mos6532_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- void porta_in_set(uint8_t data, uint8_t mask);
- void portb_in_set(uint8_t data, uint8_t mask);
+ virtual void ram_map(address_map &map);
+ virtual void io_map(address_map &map);
};
+
+// device type definition
DECLARE_DEVICE_TYPE(MOS6530, mos6530_device)
+DECLARE_DEVICE_TYPE(MOS6532, mos6532_device)
#endif // MAME_MACHINE_MOS6530_H
diff --git a/src/devices/machine/mos6530n.cpp b/src/devices/machine/mos6530n.cpp
deleted file mode 100644
index e6ad3c9dc86..00000000000
--- a/src/devices/machine/mos6530n.cpp
+++ /dev/null
@@ -1,811 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Curt Coder
-/**********************************************************************
-
- MOS Technology 6530 Memory, I/O, Timer Array emulation
- MOS Technology 6532 RAM, I/O, Timer Array emulation
-
-**********************************************************************/
-
-#include "emu.h"
-#include "mos6530n.h"
-
-#define LOG_GENERAL (1U << 0)
-#define LOG_TIMER (1U << 1)
-
-//#define VERBOSE (LOG_GENERAL | LOG_TIMER)
-#include "logmacro.h"
-
-#define LOGTIMER(...) LOGMASKED(LOG_TIMER, __VA_ARGS__)
-
-
-
-//**************************************************************************
-// DEVICE DEFINITIONS
-//**************************************************************************
-
-DEFINE_DEVICE_TYPE(MOS6530_NEW, mos6530_new_device, "mos6530_new", "MOS 6530 (new)")
-DEFINE_DEVICE_TYPE(MOS6532_NEW, mos6532_new_device, "mos6532_new", "MOS 6532 (new)")
-
-
-void mos6530_new_device::rom_map(address_map &map)
-{
- map.global_mask(0x3ff);
- map(0x000, 0x3ff).r(FUNC(mos6530_new_device::rom_r));
-}
-
-void mos6530_new_device::ram_map(address_map &map)
-{
- map.global_mask(0x3f);
- map(0x00, 0x3f).rw(FUNC(mos6530_new_device::ram_r), FUNC(mos6530_new_device::ram_w));
-}
-
-void mos6530_new_device::io_map(address_map &map)
-{
- map.global_mask(0xf);
- map(0x00, 0x00).mirror(0x8).rw(FUNC(mos6530_new_device::pa_data_r), FUNC(mos6530_new_device::pa_data_w));
- map(0x01, 0x01).mirror(0x8).rw(FUNC(mos6530_new_device::pa_ddr_r), FUNC(mos6530_new_device::pa_ddr_w));
- map(0x02, 0x02).mirror(0x8).rw(FUNC(mos6530_new_device::pb_data_r), FUNC(mos6530_new_device::pb_data_w));
- map(0x03, 0x03).mirror(0x8).rw(FUNC(mos6530_new_device::pb_ddr_r), FUNC(mos6530_new_device::pb_ddr_w));
- map(0x04, 0x07).w(FUNC(mos6530_new_device::timer_off_w));
- map(0x0c, 0x0f).w(FUNC(mos6530_new_device::timer_on_w));
- map(0x04, 0x04).mirror(0x2).r(FUNC(mos6530_new_device::timer_off_r));
- map(0x0c, 0x0c).mirror(0x2).r(FUNC(mos6530_new_device::timer_on_r));
- map(0x05, 0x05).mirror(0xa).r(FUNC(mos6530_new_device::irq_r));
-}
-
-void mos6532_new_device::ram_map(address_map &map)
-{
- map.global_mask(0x7f);
- map(0x00, 0x7f).rw(FUNC(mos6532_new_device::ram_r), FUNC(mos6532_new_device::ram_w));
-}
-
-void mos6532_new_device::io_map(address_map &map)
-{
- map.global_mask(0x1f);
- map(0x00, 0x00).mirror(0x18).rw(FUNC(mos6532_new_device::pa_data_r), FUNC(mos6532_new_device::pa_data_w)); // SWCHA
- map(0x01, 0x01).mirror(0x18).rw(FUNC(mos6532_new_device::pa_ddr_r), FUNC(mos6532_new_device::pa_ddr_w)); // SWACNT
- map(0x02, 0x02).mirror(0x18).rw(FUNC(mos6532_new_device::pb_data_r), FUNC(mos6532_new_device::pb_data_w)); // SWCHB
- map(0x03, 0x03).mirror(0x18).rw(FUNC(mos6532_new_device::pb_ddr_r), FUNC(mos6532_new_device::pb_ddr_w)); // SWBCNT
- map(0x14, 0x17).w(FUNC(mos6532_new_device::timer_off_w));
- map(0x1c, 0x1f).w(FUNC(mos6532_new_device::timer_on_w));
- map(0x04, 0x04).mirror(0x12).r(FUNC(mos6532_new_device::timer_off_r));
- map(0x0c, 0x0c).mirror(0x12).r(FUNC(mos6532_new_device::timer_on_r));
- map(0x05, 0x05).mirror(0x1a).r(FUNC(mos6532_new_device::irq_r));
- map(0x04, 0x07).mirror(0x8).w(FUNC(mos6532_new_device::edge_w));
-}
-
-uint8_t mos6532_new_device::io_r(offs_t offset)
-{
- offset &= 0x1f;
- uint8_t ret = 0;
-
- if (offset == 0x00 || offset == 0x08 || offset == 0x10 || offset == 0x18) ret = pa_data_r();
- if (offset == 0x01 || offset == 0x09 || offset == 0x11 || offset == 0x19) ret = pa_ddr_r();
- if (offset == 0x02 || offset == 0x0a || offset == 0x12 || offset == 0x1a) ret = pb_data_r();
- if (offset == 0x03 || offset == 0x0b || offset == 0x13 || offset == 0x1b) ret = pb_ddr_r();
-
- if (offset == 0x04 || offset == 0x06 || offset == 0x14 || offset == 0x16) ret = timer_off_r();
- if (offset == 0x0c || offset == 0x0e || offset == 0x1c || offset == 0x1e) ret = timer_on_r();
-
- if (offset == 0x05 || offset == 0x07 || offset == 0x0d || offset == 0x0f) ret = irq_r();
- if (offset == 0x15 || offset == 0x17 || offset == 0x1d || offset == 0x1f) ret = irq_r();
-
- return ret;
-}
-
-void mos6532_new_device::io_w(offs_t offset, uint8_t data)
-{
- offset &= 0x1f;
-
- if (offset == 0x00 || offset == 0x08 || offset == 0x10 || offset == 0x18) pa_data_w(data);
- if (offset == 0x01 || offset == 0x09 || offset == 0x11 || offset == 0x19) pa_ddr_w(data);
- if (offset == 0x02 || offset == 0x0a || offset == 0x12 || offset == 0x1a) pb_data_w(data);
- if (offset == 0x03 || offset == 0x0b || offset == 0x13 || offset == 0x1b) pb_ddr_w(data);
- if (offset == 0x14 || offset == 0x15 || offset == 0x16 || offset == 0x17) timer_off_w(offset&3, data);
- if (offset == 0x1c || offset == 0x1d || offset == 0x1e || offset == 0x1f) timer_on_w(offset&3, data);
-
- if (offset == 0x04 || offset == 0x05 || offset == 0x06 || offset == 0x07) edge_w(data);
- if (offset == 0x0c || offset == 0x0d || offset == 0xea || offset == 0x0f) edge_w(data);
-}
-
-
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
-
-//-------------------------------------------------
-// mos6530_device_base - constructor
-//-------------------------------------------------
-
-mos6530_device_base::mos6530_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 rsize) :
- device_t(mconfig, type, tag, owner, clock),
- m_ram(*this, finder_base::DUMMY_TAG, rsize, ENDIANNESS_LITTLE),
- m_rom(*this, DEVICE_SELF),
- m_irq_cb(*this),
- m_in8_pa_cb(*this),
- m_out8_pa_cb(*this),
- m_in8_pb_cb(*this),
- m_out8_pb_cb(*this),
- m_in_pa_cb(*this),
- m_out_pa_cb(*this),
- m_in_pb_cb(*this),
- m_out_pb_cb(*this),
- m_pa_in(0xff),
- m_pa_out(0),
- m_pa_ddr(0),
- m_pa7(0),
- m_pa7_dir(0),
- m_pb_in(0xff),
- m_pb_out(0),
- m_pb_ddr(0),
- m_ie_timer(false),
- m_irq_timer(true),
- m_ie_edge(false),
- m_irq_edge(false)
-{
- cur_live.tm = attotime::never;
- cur_live.state = IDLE;
- cur_live.next_state = -1;
-}
-
-
-//-------------------------------------------------
-// mos6530_new_device - constructor
-//-------------------------------------------------
-
-mos6530_new_device::mos6530_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : mos6530_device_base(mconfig, MOS6530_NEW, tag, owner, clock, 0x40) { }
-
-
-//-------------------------------------------------
-// mos6532_new_device - constructor
-//-------------------------------------------------
-
-mos6532_new_device::mos6532_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : mos6530_device_base(mconfig, MOS6532_NEW, tag, owner, clock, 0x80) { }
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void mos6530_device_base::device_start()
-{
- // resolve callbacks
- m_irq_cb.resolve_safe();
- m_in8_pa_cb.resolve();
- m_out8_pa_cb.resolve();
- m_in8_pb_cb.resolve();
- m_out8_pb_cb.resolve();
- m_in_pa_cb.resolve_all();
- m_out_pa_cb.resolve_all_safe();
- m_in_pb_cb.resolve_all();
- m_out_pb_cb.resolve_all_safe();
-
- // allocate timer
- t_gen = timer_alloc(0);
-
- // state saving
- save_item(NAME(m_pa_in));
- save_item(NAME(m_pa_out));
- save_item(NAME(m_pa_ddr));
- save_item(NAME(m_pa7));
- save_item(NAME(m_pa7_dir));
- save_item(NAME(m_pb_in));
- save_item(NAME(m_pb_out));
- save_item(NAME(m_pb_ddr));
- save_item(NAME(m_ie_timer));
- save_item(NAME(m_irq_timer));
- save_item(NAME(m_ie_edge));
- save_item(NAME(m_irq_edge));
- save_item(NAME(m_prescale));
- save_item(NAME(m_timer));
-}
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void mos6530_device_base::device_reset()
-{
- m_pa_out = 0xff;
- m_pa_ddr = 0;
- m_pb_out = 0xff; // a7800 One-On-One Basketball (1on1u) needs this or you can't start a game, it doesn't initialize it. (see MT6060)
- m_pb_ddr = 0;
-
- m_ie_timer = false;
- m_irq_timer = false;
- m_ie_edge = false;
- m_irq_edge = false;
- m_pa7_dir = 0;
-
- update_pa();
- update_pb();
- update_irq();
- edge_detect();
-
- m_timer = 0xff;
- m_prescale = 1024;
-
- if (cur_live.state != IDLE) {
- live_abort();
- }
-
- live_start();
- live_run();
-}
-
-
-//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void mos6530_device_base::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- live_sync();
- live_run();
-}
-
-
-//-------------------------------------------------
-// update_pa -
-//-------------------------------------------------
-
-void mos6530_device_base::update_pa()
-{
- uint8_t out = m_pa_out;
- uint8_t ddr = m_pa_ddr;
- uint8_t data = (out & ddr) | (ddr ^ 0xff);
-
- if (m_out8_pa_cb.isnull())
- {
- m_out_pa_cb[0](BIT(data, 0));
- m_out_pa_cb[1](BIT(data, 1));
- m_out_pa_cb[2](BIT(data, 2));
- m_out_pa_cb[3](BIT(data, 3));
- m_out_pa_cb[4](BIT(data, 4));
- m_out_pa_cb[5](BIT(data, 5));
- m_out_pa_cb[6](BIT(data, 6));
- m_out_pa_cb[7](BIT(data, 7));
- }
- else
- {
- m_out8_pa_cb(data);
- }
-}
-
-
-//-------------------------------------------------
-// update_pb -
-//-------------------------------------------------
-
-void mos6530_device_base::update_pb()
-{
- uint8_t out = m_pb_out;
- uint8_t ddr = m_pb_ddr;
- uint8_t data = (out & ddr) | (ddr ^ 0xff);
-
- if (m_out8_pb_cb.isnull())
- {
- m_out_pb_cb[0](BIT(data, 0));
- m_out_pb_cb[1](BIT(data, 1));
- m_out_pb_cb[2](BIT(data, 2));
- m_out_pb_cb[3](BIT(data, 3));
- m_out_pb_cb[4](BIT(data, 4));
- m_out_pb_cb[5](BIT(data, 5));
- m_out_pb_cb[6](BIT(data, 6));
- m_out_pb_cb[7](BIT(data, 7));
- }
- else
- {
- m_out8_pb_cb(data);
- }
-}
-
-void mos6530_new_device::update_pb()
-{
- uint8_t out = m_pb_out;
- uint8_t ddr = m_pb_ddr;
- uint8_t data = (out & ddr) | (ddr ^ 0xff);
-
- if (m_ie_timer)
- {
- if (m_irq_timer) {
- data |= IRQ_TIMER;
- } else {
- data &= ~IRQ_TIMER;
- }
- }
-
- if (m_out8_pb_cb.isnull())
- {
- m_out_pb_cb[0](BIT(data, 0));
- m_out_pb_cb[1](BIT(data, 1));
- m_out_pb_cb[2](BIT(data, 2));
- m_out_pb_cb[3](BIT(data, 3));
- m_out_pb_cb[4](BIT(data, 4));
- m_out_pb_cb[5](BIT(data, 5));
- m_out_pb_cb[6](BIT(data, 6));
- m_out_pb_cb[7](BIT(data, 7));
- }
- else
- {
- m_out8_pb_cb(data);
- }
-}
-
-
-//-------------------------------------------------
-// update_irq -
-//-------------------------------------------------
-
-void mos6530_device_base::update_irq()
-{
- int state = CLEAR_LINE;
-
- if (m_ie_timer && m_irq_timer) state = ASSERT_LINE;
- if (m_ie_edge && m_irq_edge) state = ASSERT_LINE;
-
- m_irq_cb(state);
-}
-
-void mos6530_new_device::update_irq()
-{
- update_pb();
-}
-
-
-//-------------------------------------------------
-// get_irq_flags -
-//-------------------------------------------------
-
-uint8_t mos6530_device_base::get_irq_flags()
-{
- uint8_t data = 0;
-
- if (m_irq_timer) data |= IRQ_TIMER;
- if (m_irq_edge) data |= IRQ_EDGE;
-
- return data;
-}
-
-uint8_t mos6530_new_device::get_irq_flags()
-{
- uint8_t data = 0;
-
- if (m_irq_timer) data |= IRQ_TIMER;
-
- return data;
-}
-
-
-//-------------------------------------------------
-// edge_detect -
-//-------------------------------------------------
-
-void mos6530_device_base::edge_detect()
-{
- uint8_t ddr_out = m_pa_ddr;
- uint8_t ddr_in = m_pa_ddr ^ 0xff;
- uint8_t data = (m_pa_out & ddr_out) | (m_pa_in & ddr_in);
- int state = BIT(data, 7);
-
- if ((m_pa7 ^ state) && (m_pa7_dir ^ state) == 0 && !m_irq_edge)
- {
- LOG("%s %s edge-detect IRQ\n", machine().time().as_string(), name());
-
- m_irq_edge = true;
- update_irq();
- }
-
- m_pa7 = state;
-}
-
-
-//-------------------------------------------------
-// pa_w -
-//-------------------------------------------------
-
-void mos6530_device_base::pa_w(int bit, int state)
-{
- LOG("%s %s %s Port A Data Bit %u State %u\n", machine().time().as_string(), machine().describe_context(), name(), bit, state);
-
- m_pa_in &= ~(1 << bit);
- m_pa_in |= (state << bit);
-
- edge_detect();
-}
-
-
-//-------------------------------------------------
-// pb_w -
-//-------------------------------------------------
-
-void mos6530_device_base::pb_w(int bit, int state)
-{
- LOG("%s %s %s Port B Data Bit %u State %u\n", machine().time().as_string(), machine().describe_context(), name(), bit, state);
-
- m_pb_in &= ~(1 << bit);
- m_pb_in |= (state << bit);
-}
-
-
-//-------------------------------------------------
-// pa_data_r -
-//-------------------------------------------------
-
-uint8_t mos6530_device_base::pa_data_r()
-{
- uint8_t in = 0;
-
- if (m_in8_pa_cb.isnull())
- {
- in |= (m_in_pa_cb[0].isnull() ? BIT(m_pa_in, 0) : m_in_pa_cb[0]());
- in |= (m_in_pa_cb[1].isnull() ? BIT(m_pa_in, 1) : m_in_pa_cb[1]()) << 1;
- in |= (m_in_pa_cb[2].isnull() ? BIT(m_pa_in, 2) : m_in_pa_cb[2]()) << 2;
- in |= (m_in_pa_cb[3].isnull() ? BIT(m_pa_in, 3) : m_in_pa_cb[3]()) << 3;
- in |= (m_in_pa_cb[4].isnull() ? BIT(m_pa_in, 4) : m_in_pa_cb[4]()) << 4;
- in |= (m_in_pa_cb[5].isnull() ? BIT(m_pa_in, 5) : m_in_pa_cb[5]()) << 5;
- in |= (m_in_pa_cb[6].isnull() ? BIT(m_pa_in, 6) : m_in_pa_cb[6]()) << 6;
- in |= (m_in_pa_cb[7].isnull() ? BIT(m_pa_in, 7) : m_in_pa_cb[7]()) << 7;
- }
- else
- {
- in = m_in8_pa_cb();
- }
-
- uint8_t out = m_pa_out;
- uint8_t ddr_out = m_pa_ddr;
- uint8_t ddr_in = m_pa_ddr ^ 0xff;
- uint8_t data = (out & ddr_out) | (in & ddr_in);
-
- LOG("%s %s %s Port A Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
-
- return data;
-}
-
-
-//-------------------------------------------------
-// pa_data_w -
-//-------------------------------------------------
-
-void mos6530_device_base::pa_data_w(uint8_t data)
-{
- m_pa_out = data;
-
- LOG("%s %s %s Port A Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
-
- update_pa();
- edge_detect();
-}
-
-
-//-------------------------------------------------
-// pa_ddr_w -
-//-------------------------------------------------
-
-void mos6530_device_base::pa_ddr_w(uint8_t data)
-{
- m_pa_ddr = data;
-
- LOG("%s %s %s Port A DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
-
- update_pa();
- edge_detect();
-}
-
-
-//-------------------------------------------------
-// pb_data_r -
-//-------------------------------------------------
-
-uint8_t mos6530_device_base::pb_data_r()
-{
- uint8_t in = 0;
-
- if (m_in8_pb_cb.isnull())
- {
- in |= (m_in_pb_cb[0].isnull() ? BIT(m_pb_in, 0) : m_in_pb_cb[0]());
- in |= (m_in_pb_cb[1].isnull() ? BIT(m_pb_in, 1) : m_in_pb_cb[1]()) << 1;
- in |= (m_in_pb_cb[2].isnull() ? BIT(m_pb_in, 2) : m_in_pb_cb[2]()) << 2;
- in |= (m_in_pb_cb[3].isnull() ? BIT(m_pb_in, 3) : m_in_pb_cb[3]()) << 3;
- in |= (m_in_pb_cb[4].isnull() ? BIT(m_pb_in, 4) : m_in_pb_cb[4]()) << 4;
- in |= (m_in_pb_cb[5].isnull() ? BIT(m_pb_in, 5) : m_in_pb_cb[5]()) << 5;
- in |= (m_in_pb_cb[6].isnull() ? BIT(m_pb_in, 6) : m_in_pb_cb[6]()) << 6;
- in |= (m_in_pb_cb[7].isnull() ? BIT(m_pb_in, 7) : m_in_pb_cb[7]()) << 7;
- }
- else
- {
- in = m_in8_pb_cb();
- }
-
- uint8_t out = m_pb_out;
- uint8_t ddr_out = m_pb_ddr;
- uint8_t ddr_in = m_pb_ddr ^ 0xff;
- uint8_t data = (out & ddr_out) | (in & ddr_in);
-
- LOG("%s %s %s Port B Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
-
- return data;
-}
-
-
-//-------------------------------------------------
-// pb_data_w -
-//-------------------------------------------------
-
-void mos6530_device_base::pb_data_w(uint8_t data)
-{
- m_pb_out = data;
-
- LOG("%s %s %s Port B Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
-
- update_pb();
-}
-
-
-//-------------------------------------------------
-// pb_ddr_w -
-//-------------------------------------------------
-
-void mos6530_device_base::pb_ddr_w(uint8_t data)
-{
- m_pb_ddr = data;
-
- LOG("%s %s %s Port B DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
-
- update_pb();
-}
-
-
-//-------------------------------------------------
-// timer_r -
-//-------------------------------------------------
-
-uint8_t mos6530_device_base::timer_off_r()
-{
- if (machine().side_effects_disabled())
- return 0;
-
- return timer_r(false);
-}
-
-uint8_t mos6530_device_base::timer_on_r()
-{
- if (machine().side_effects_disabled())
- return 0;
-
- return timer_r(true);
-}
-
-uint8_t mos6530_device_base::timer_r(bool ie)
-{
- uint8_t data;
-
- live_sync();
-
- m_ie_timer = ie;
- if (cur_live.tm_irq != machine().time()) {
- m_irq_timer = false;
- }
- update_irq();
-
- data = cur_live.value;
-
- LOGTIMER("%s %s %s Timer read %02x IE %u\n", machine().time().as_string(), machine().describe_context(), name(), data, m_ie_timer ? 1 : 0);
-
- checkpoint();
- live_run();
-
- return data;
-}
-
-
-//-------------------------------------------------
-// irq_r -
-//-------------------------------------------------
-
-uint8_t mos6530_device_base::irq_r()
-{
- uint8_t data = get_irq_flags();
-
- if (!machine().side_effects_disabled()) {
- if (m_irq_edge) {
- m_irq_edge = false;
- update_irq();
- }
- }
-
- return data;
-}
-
-
-//-------------------------------------------------
-// timer_w -
-//-------------------------------------------------
-
-void mos6530_device_base::timer_off_w(offs_t offset, uint8_t data)
-{
- timer_w(offset, data, false);
-}
-
-void mos6530_device_base::timer_on_w(offs_t offset, uint8_t data)
-{
- timer_w(offset, data, true);
-}
-
-void mos6530_device_base::timer_w(offs_t offset, uint8_t data, bool ie)
-{
- live_sync();
-
- m_timer = data;
-
- switch (offset & 0x03) {
- case 0: m_prescale = 1; break;
- case 1: m_prescale = 8; break;
- case 2: m_prescale = 64; break;
- case 3: m_prescale = 1024; break;
- }
-
- m_ie_timer = ie;
- if (cur_live.tm_irq != machine().time()) {
- m_irq_timer = false;
- }
- update_irq();
-
- LOGTIMER("%s %s %s Timer value %02x prescale %u IE %u\n", machine().time().as_string(), machine().describe_context(), name(), data, m_prescale, m_ie_timer ? 1 : 0);
-
- checkpoint();
-
- if (cur_live.state != IDLE) {
- live_abort();
- }
-
- live_start();
- live_run();
-}
-
-
-//-------------------------------------------------
-// edge_w -
-//-------------------------------------------------
-
-void mos6530_device_base::edge_w(uint8_t data)
-{
- m_pa7_dir = BIT(data, 0);
- m_ie_edge = BIT(data, 1) ? false : true;
-
- LOG("%s %s %s %s edge-detect, %s interrupt\n", machine().time().as_string(), machine().describe_context(), name(), m_pa7_dir ? "positive" : "negative", m_ie_edge ? "enable" : "disable");
-}
-
-
-//-------------------------------------------------
-// live_start -
-//-------------------------------------------------
-
-void mos6530_device_base::live_start()
-{
- cur_live.period = attotime::from_ticks(m_prescale, clock());
- cur_live.tm = machine().time() + attotime::from_hz(clock());
- cur_live.state = RUNNING;
- cur_live.next_state = -1;
-
- cur_live.value = m_timer;
-
- checkpoint();
-
- live_run();
-}
-
-void mos6530_device_base::checkpoint()
-{
- checkpoint_live = cur_live;
-}
-
-void mos6530_device_base::rollback()
-{
- cur_live = checkpoint_live;
-}
-
-void mos6530_device_base::live_delay(int state)
-{
- cur_live.next_state = state;
- if(cur_live.tm != machine().time())
- t_gen->adjust(cur_live.tm - machine().time());
- else
- live_sync();
-}
-
-void mos6530_device_base::live_sync()
-{
- if(!cur_live.tm.is_never()) {
- if(cur_live.tm > machine().time()) {
- rollback();
- live_run(machine().time());
- } else {
- if(cur_live.next_state != -1) {
- cur_live.state = cur_live.next_state;
- cur_live.next_state = -1;
- }
- if(cur_live.state == IDLE) {
- cur_live.tm = attotime::never;
- }
- }
- cur_live.next_state = -1;
- checkpoint();
- }
-}
-
-void mos6530_device_base::live_abort()
-{
- if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) {
- rollback();
- live_run(machine().time());
- }
-
- cur_live.tm = attotime::never;
- cur_live.state = IDLE;
- cur_live.next_state = -1;
- cur_live.tm_irq = attotime::never;
-}
-
-void mos6530_device_base::live_run(const attotime &limit)
-{
- if(cur_live.state == IDLE || cur_live.next_state != -1)
- return;
-
- for(;;) {
- switch(cur_live.state) {
- case RUNNING: {
- if (cur_live.tm > limit)
- return;
-
- cur_live.value--;
-
- if (cur_live.value == 0xff) {
- live_delay(RUNNING_SYNCPOINT);
- return;
- } else {
- LOGTIMER("%s %s timer %02x\n", cur_live.tm.as_string(), name(), cur_live.value);
-
- cur_live.tm += cur_live.period;
- }
- break;
- }
-
- case RUNNING_SYNCPOINT: {
- LOGTIMER("%s %s timer %02x interrupt\n", cur_live.tm.as_string(), name(), cur_live.value);
-
- cur_live.tm_irq = cur_live.tm;
- m_irq_timer = true;
- update_irq();
-
- checkpoint();
-
- cur_live.state = RUNNING_AFTER_INTERRUPT;
- cur_live.period = attotime::from_hz(clock());
- cur_live.tm += cur_live.period;
- break;
- }
-
- case RUNNING_AFTER_INTERRUPT: {
- if (cur_live.tm > limit)
- return;
-
- cur_live.value--;
-
- LOGTIMER("%s %s timer %02x\n", cur_live.tm.as_string(), name(), cur_live.value);
-
- if (!cur_live.value) {
- cur_live.state = IDLE;
- return;
- }
-
- cur_live.tm += cur_live.period;
- break;
- }
- }
- }
-}
diff --git a/src/devices/machine/mos6530n.h b/src/devices/machine/mos6530n.h
deleted file mode 100644
index 2822d18d6bf..00000000000
--- a/src/devices/machine/mos6530n.h
+++ /dev/null
@@ -1,235 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Curt Coder
-/**********************************************************************
-
- MOS Technology 6530 Memory, I/O, Timer Array emulation
- MOS Technology 6532 RAM, I/O, Timer Array emulation
-
-**********************************************************************
- _____ _____
- Vss 1 |* \_/ | 40 PA1
- PA0 2 | | 39 PA2
- phi2 3 | | 38 PA3
- RS0 4 | | 37 PA4
- A9 5 | | 36 PA5
- A8 6 | | 35 PA6
- A7 7 | | 34 PA7
- A6 8 | | 33 DB0
- R/W 9 | | 32 DB1
- A5 10 | MCS6530 | 31 DB2
- A4 11 | | 30 DB3
- A3 12 | | 29 DB4
- A2 13 | | 28 DB5
- A1 14 | | 27 DB6
- A0 15 | | 26 DB7
- _RES 16 | | 25 PB0
- IRQ/PB7 17 | | 24 PB1
- CS1/PB6 18 | | 23 PB2
- CS2/PB5 19 | | 22 PB3
- Vcc 20 |_____________| 21 PB4
-
- _____ _____
- Vss 1 |* \_/ | 40 A6
- A5 2 | | 39 phi2
- A4 3 | | 38 CS1
- A3 4 | | 37 _CS2
- A2 5 | | 36 _RS
- A1 6 | | 35 R/W
- A0 7 | | 34 _RES
- PA0 8 | | 33 D0
- PA1 9 | | 32 D1
- PA2 10 | MCS6532 | 31 D2
- PA3 11 | | 30 D3
- PA4 12 | | 29 D4
- PA5 13 | | 28 D5
- PA6 14 | | 27 D6
- PA7 15 | | 26 D7
- PB7 16 | | 25 _IRQ
- PB6 17 | | 24 PB0
- PB5 18 | | 23 PB1
- PB4 19 | | 22 PB2
- Vcc 20 |_____________| 21 PB3
-
-**********************************************************************/
-
-#ifndef MAME_MACHINE_MOS6530N_H
-#define MAME_MACHINE_MOS6530N_H
-
-#pragma once
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-// ======================> mos6530_device_base
-
-class mos6530_device_base : public device_t
-{
-public:
- auto irq_wr_callback() { return m_irq_cb.bind(); }
- auto pa_rd_callback() { return m_in8_pa_cb.bind(); }
- auto pa_wr_callback() { return m_out8_pa_cb.bind(); }
- auto pb_rd_callback() { return m_in8_pb_cb.bind(); }
- auto pb_wr_callback() { return m_out8_pb_cb.bind(); }
- template <unsigned N> auto pa_rd_callback() { return m_in_pa_cb[N].bind(); }
- template <unsigned N> auto pa_wr_callback() { return m_out_pa_cb[N].bind(); }
- template <unsigned N> auto pb_rd_callback() { return m_in_pb_cb[N].bind(); }
- template <unsigned N> auto pb_wr_callback() { return m_out_pb_cb[N].bind(); }
-
- DECLARE_WRITE_LINE_MEMBER( pa0_w ) { pa_w(0, state); }
- DECLARE_WRITE_LINE_MEMBER( pa1_w ) { pa_w(1, state); }
- DECLARE_WRITE_LINE_MEMBER( pa2_w ) { pa_w(2, state); }
- DECLARE_WRITE_LINE_MEMBER( pa3_w ) { pa_w(3, state); }
- DECLARE_WRITE_LINE_MEMBER( pa4_w ) { pa_w(4, state); }
- DECLARE_WRITE_LINE_MEMBER( pa5_w ) { pa_w(5, state); }
- DECLARE_WRITE_LINE_MEMBER( pa6_w ) { pa_w(6, state); }
- DECLARE_WRITE_LINE_MEMBER( pa7_w ) { pa_w(7, state); }
-
- DECLARE_WRITE_LINE_MEMBER( pb0_w ) { pb_w(0, state); }
- DECLARE_WRITE_LINE_MEMBER( pb1_w ) { pb_w(1, state); }
- DECLARE_WRITE_LINE_MEMBER( pb2_w ) { pb_w(2, state); }
- DECLARE_WRITE_LINE_MEMBER( pb3_w ) { pb_w(3, state); }
- DECLARE_WRITE_LINE_MEMBER( pb4_w ) { pb_w(4, state); }
- DECLARE_WRITE_LINE_MEMBER( pb5_w ) { pb_w(5, state); }
- DECLARE_WRITE_LINE_MEMBER( pb6_w ) { pb_w(6, state); }
- DECLARE_WRITE_LINE_MEMBER( pb7_w ) { pb_w(7, state); }
-
-protected:
- // construction/destruction
- mos6530_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 rsize);
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
- enum
- {
- IRQ_EDGE = 0x40,
- IRQ_TIMER = 0x80
- };
-
- void update_pa();
- virtual void update_pb();
- virtual void update_irq();
- virtual uint8_t get_irq_flags();
- void edge_detect();
- void pa_w(int bit, int state);
- void pb_w(int bit, int state);
- void timer_w(offs_t offset, uint8_t data, bool ie);
- uint8_t timer_r(bool ie);
-
- uint8_t rom_r(offs_t offset) { return m_rom[offset]; }
- uint8_t ram_r(offs_t offset) { return m_ram[offset]; }
- void ram_w(offs_t offset, uint8_t data) { m_ram[offset] = data; }
- uint8_t pa_data_r();
- void pa_data_w(uint8_t data);
- uint8_t pb_data_r();
- void pb_data_w(uint8_t data);
- uint8_t pa_ddr_r() { return m_pa_ddr; }
- void pa_ddr_w(uint8_t data);
- uint8_t pb_ddr_r() { return m_pb_ddr; }
- void pb_ddr_w(uint8_t data);
- uint8_t timer_off_r();
- uint8_t timer_on_r();
- uint8_t irq_r();
- void timer_off_w(offs_t offset, uint8_t data);
- void timer_on_w(offs_t offset, uint8_t data);
- void edge_w(uint8_t data);
-
- memory_share_creator<uint8_t> m_ram;
- optional_region_ptr<uint8_t> m_rom;
-
- devcb_write_line m_irq_cb;
- devcb_read8 m_in8_pa_cb;
- devcb_write8 m_out8_pa_cb;
- devcb_read8 m_in8_pb_cb;
- devcb_write8 m_out8_pb_cb;
- devcb_read_line::array<8> m_in_pa_cb;
- devcb_write_line::array<8> m_out_pa_cb;
- devcb_read_line::array<8> m_in_pb_cb;
- devcb_write_line::array<8> m_out_pb_cb;
-
- uint8_t m_pa_in;
- uint8_t m_pa_out;
- uint8_t m_pa_ddr;
- int m_pa7;
- int m_pa7_dir;
-
- uint8_t m_pb_in;
- uint8_t m_pb_out;
- uint8_t m_pb_ddr;
-
- bool m_ie_timer;
- bool m_irq_timer;
- bool m_ie_edge;
- bool m_irq_edge;
-
- int m_prescale;
- uint8_t m_timer;
-
- enum {
- IDLE,
- RUNNING,
- RUNNING_SYNCPOINT,
- RUNNING_AFTER_INTERRUPT
- };
-
- struct live_info {
- attotime tm, tm_irq;
- attotime period;
- int state, next_state;
- uint8_t value;
- };
-
- live_info cur_live, checkpoint_live;
- emu_timer *t_gen;
-
- void live_start();
- void checkpoint();
- void rollback();
- void live_delay(int state);
- void live_sync();
- void live_abort();
- void live_run(const attotime &limit = attotime::never);
-};
-
-
-class mos6530_new_device : public mos6530_device_base
-{
-public:
- // construction/destruction
- mos6530_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- virtual void rom_map(address_map &map);
- virtual void ram_map(address_map &map);
- virtual void io_map(address_map &map);
-
-protected:
- // device-level overrides
- void update_pb() override;
- void update_irq() override;
- uint8_t get_irq_flags() override;
-};
-
-
-class mos6532_new_device : public mos6530_device_base
-{
-public:
- // construction/destruction
- mos6532_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- virtual void ram_map(address_map &map);
- virtual void io_map(address_map &map);
-
- // is there a better way to access the memory map when not using m()?
- uint8_t io_r(offs_t offset);
- void io_w(offs_t offset, uint8_t data);
-};
-
-
-// device type definition
-DECLARE_DEVICE_TYPE(MOS6530_NEW, mos6530_new_device)
-DECLARE_DEVICE_TYPE(MOS6532_NEW, mos6532_new_device)
-
-#endif // MAME_MACHINE_MOS6530N_H
diff --git a/src/devices/machine/mos6551.cpp b/src/devices/machine/mos6551.cpp
index 56302c75050..c570a746806 100644
--- a/src/devices/machine/mos6551.cpp
+++ b/src/devices/machine/mos6551.cpp
@@ -72,13 +72,6 @@ void mos6551_device::device_add_mconfig(machine_config &config)
void mos6551_device::device_start()
{
- // resolve callbacks
- m_irq_handler.resolve_safe();
- m_txd_handler.resolve_safe();
- m_rxc_handler.resolve_safe();
- m_rts_handler.resolve_safe();
- m_dtr_handler.resolve_safe();
-
// state saving
save_item(NAME(m_control));
save_item(NAME(m_command));
@@ -449,7 +442,7 @@ void mos6551_device::set_xtal(uint32_t xtal)
}
}
-WRITE_LINE_MEMBER( mos6551_device::internal_clock )
+void mos6551_device::internal_clock(int state)
{
if (m_tx_internal_clock)
{
@@ -457,7 +450,7 @@ WRITE_LINE_MEMBER( mos6551_device::internal_clock )
}
}
-WRITE_LINE_MEMBER(mos6551_device::write_xtal1)
+void mos6551_device::write_xtal1(int state)
{
if (!m_tx_internal_clock)
{
@@ -465,12 +458,12 @@ WRITE_LINE_MEMBER(mos6551_device::write_xtal1)
}
}
-WRITE_LINE_MEMBER( mos6551_device::write_rxd )
+void mos6551_device::write_rxd(int state)
{
m_rxd = state;
}
-WRITE_LINE_MEMBER( mos6551_device::write_rxc )
+void mos6551_device::write_rxc(int state)
{
if (!m_rx_internal_clock)
{
@@ -478,7 +471,7 @@ WRITE_LINE_MEMBER( mos6551_device::write_rxc )
}
}
-WRITE_LINE_MEMBER( mos6551_device::write_cts )
+void mos6551_device::write_cts(int state)
{
if (m_cts != state)
{
@@ -495,7 +488,7 @@ WRITE_LINE_MEMBER( mos6551_device::write_cts )
}
}
-WRITE_LINE_MEMBER( mos6551_device::write_dsr )
+void mos6551_device::write_dsr(int state)
{
if (m_dsr != state)
{
@@ -503,7 +496,7 @@ WRITE_LINE_MEMBER( mos6551_device::write_dsr )
}
}
-WRITE_LINE_MEMBER( mos6551_device::write_dcd )
+void mos6551_device::write_dcd(int state)
{
if (m_dcd != state)
{
@@ -511,7 +504,7 @@ WRITE_LINE_MEMBER( mos6551_device::write_dcd )
}
}
-WRITE_LINE_MEMBER(mos6551_device::receiver_clock)
+void mos6551_device::receiver_clock(int state)
{
if (m_rx_clock != state)
{
@@ -663,7 +656,7 @@ WRITE_LINE_MEMBER(mos6551_device::receiver_clock)
}
}
-WRITE_LINE_MEMBER(mos6551_device::transmitter_clock)
+void mos6551_device::transmitter_clock(int state)
{
if (m_rx_internal_clock)
{
diff --git a/src/devices/machine/mos6551.h b/src/devices/machine/mos6551.h
index b7afabfa603..5e40ea6f2c9 100644
--- a/src/devices/machine/mos6551.h
+++ b/src/devices/machine/mos6551.h
@@ -44,12 +44,12 @@ public:
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(write_xtal1); // txc
- DECLARE_WRITE_LINE_MEMBER(write_rxd);
- DECLARE_WRITE_LINE_MEMBER(write_rxc);
- DECLARE_WRITE_LINE_MEMBER(write_cts);
- DECLARE_WRITE_LINE_MEMBER(write_dsr);
- DECLARE_WRITE_LINE_MEMBER(write_dcd);
+ void write_xtal1(int state); // txc
+ void write_rxd(int state);
+ void write_rxc(int state);
+ void write_cts(int state);
+ void write_dsr(int state);
+ void write_dcd(int state);
void set_xtal(uint32_t clock);
void set_xtal(const XTAL &clock) { set_xtal(clock.value()); }
@@ -125,9 +125,9 @@ private:
int stoplength();
- DECLARE_WRITE_LINE_MEMBER(internal_clock);
- DECLARE_WRITE_LINE_MEMBER(receiver_clock);
- DECLARE_WRITE_LINE_MEMBER(transmitter_clock);
+ void internal_clock(int state);
+ void receiver_clock(int state);
+ void transmitter_clock(int state);
static const int internal_divider[16];
static const int transmitter_controls[4][3];
diff --git a/src/devices/machine/mos8722.cpp b/src/devices/machine/mos8722.cpp
index 0364460b63e..9683b18ab93 100644
--- a/src/devices/machine/mos8722.cpp
+++ b/src/devices/machine/mos8722.cpp
@@ -73,9 +73,9 @@ mos8722_device::mos8722_device(const machine_config &mconfig, const char *tag, d
device_t(mconfig, MOS8722, tag, owner, clock),
m_write_z80en(*this),
m_write_fsdir(*this),
- m_read_game(*this),
- m_read_exrom(*this),
- m_read_sense40(*this)
+ m_read_game(*this, 1),
+ m_read_exrom(*this, 1),
+ m_read_sense40(*this, 1)
{
}
@@ -86,12 +86,6 @@ mos8722_device::mos8722_device(const machine_config &mconfig, const char *tag, d
void mos8722_device::device_start()
{
- // resolve callbacks
- m_write_z80en.resolve_safe();
- m_write_fsdir.resolve_safe();
- m_read_game.resolve_safe(1);
- m_read_exrom.resolve_safe(1);
- m_read_sense40.resolve_safe(1);
}
@@ -252,7 +246,7 @@ void mos8722_device::write(offs_t offset, uint8_t data)
// fsdir_r - fast serial direction read
//-------------------------------------------------
-READ_LINE_MEMBER( mos8722_device::fsdir_r )
+int mos8722_device::fsdir_r()
{
return MCR_FSDIR;
}
diff --git a/src/devices/machine/mos8722.h b/src/devices/machine/mos8722.h
index 2b80aa846c2..5c86facc49b 100644
--- a/src/devices/machine/mos8722.h
+++ b/src/devices/machine/mos8722.h
@@ -59,7 +59,7 @@ public:
uint8_t read(offs_t offset, uint8_t data);
void write(offs_t offset, uint8_t data);
- DECLARE_READ_LINE_MEMBER( fsdir_r );
+ int fsdir_r();
offs_t ta_r(offs_t offset, int aec, int *ms0, int *ms1, int *ms2, int *ms3, int *cas0, int *cas1);
diff --git a/src/devices/machine/mos8726.cpp b/src/devices/machine/mos8726.cpp
index e1f167d70d3..c701239f6df 100644
--- a/src/devices/machine/mos8726.cpp
+++ b/src/devices/machine/mos8726.cpp
@@ -111,7 +111,7 @@ void mos8726_device::write(offs_t offset, uint8_t data)
// bs_w - bank select write
//-------------------------------------------------
-WRITE_LINE_MEMBER( mos8726_device::bs_w )
+void mos8726_device::bs_w(int state)
{
m_bs = state;
}
diff --git a/src/devices/machine/mos8726.h b/src/devices/machine/mos8726.h
index 90b78ec8412..720f348c728 100644
--- a/src/devices/machine/mos8726.h
+++ b/src/devices/machine/mos8726.h
@@ -63,7 +63,7 @@ public:
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( bs_w );
+ void bs_w(int state);
int romsel_r(int roml, int romh);
diff --git a/src/devices/machine/mpc106.cpp b/src/devices/machine/mpc106.cpp
new file mode 100644
index 00000000000..3bc89e6174d
--- /dev/null
+++ b/src/devices/machine/mpc106.cpp
@@ -0,0 +1,384 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/**********************************************************************
+
+ mpc106.cpp - Motorola MPC106 PCI host bridge, aka "Grackle".
+
+ Can support up to 4 PowerPC CPUs, up to 1 GiB of RAM, and 16 MiB of ROM
+
+**********************************************************************/
+#include "emu.h"
+#include "mpc106.h"
+
+#define LOG_RAM (1U << 1)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+enum
+{
+ AS_PCI_MEM = 1,
+ AS_PCI_IO = 2
+};
+
+constexpr u32 PICR1_LE_MODE = 0x00000020; // Host CPU is little-endian if set, big-endian if clear
+
+DEFINE_DEVICE_TYPE(MPC106, mpc106_host_device, "mpc106", "Motorola MPC106 PCI Bridge/Memory Controller")
+
+void mpc106_host_device::config_map(address_map &map)
+{
+ pci_host_device::config_map(map);
+ map(0x70, 0x71).rw(FUNC(mpc106_host_device::pwrconfig1_r), FUNC(mpc106_host_device::pwrconfig1_w));
+ map(0x72, 0x72).rw(FUNC(mpc106_host_device::pwrconfig2_r), FUNC(mpc106_host_device::pwrconfig2_w));
+ map(0x80, 0x8f).rw(FUNC(mpc106_host_device::memory_start_r), FUNC(mpc106_host_device::memory_start_w));
+ map(0x90, 0x9f).rw(FUNC(mpc106_host_device::memory_end_r), FUNC(mpc106_host_device::memory_end_w));
+ map(0xa0, 0xa0).rw(FUNC(mpc106_host_device::memory_enable_r), FUNC(mpc106_host_device::memory_enable_w));
+ map(0xa8, 0xab).rw(FUNC(mpc106_host_device::picr1_r), FUNC(mpc106_host_device::picr1_w));
+}
+
+mpc106_host_device::mpc106_host_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : pci_host_device(mconfig, MPC106, tag, owner, clock)
+ , m_mem_config("memory_space", ENDIANNESS_LITTLE, 32, 32)
+ , m_io_config("io_space", ENDIANNESS_LITTLE, 32, 32)
+ , m_cpu(*this, finder_base::DUMMY_TAG)
+{
+ set_ids_host(0x10570002, 0x40, 0x000006);
+ m_memory_bank_enable = 0;
+ m_picr1 = 0;
+}
+
+void mpc106_host_device::set_ram_info(u8 *ram_ptr, int ram_size)
+{
+ m_ram = ram_ptr;
+ m_ram_size = ram_size;
+}
+
+void mpc106_host_device::set_rom_tag(const char *tag)
+{
+ m_rom_tag = tag;
+}
+
+void mpc106_host_device::set_map_type(map_type maptype)
+{
+ m_map_type = maptype;
+}
+
+void mpc106_host_device::device_start()
+{
+ pci_host_device::device_start();
+ m_cpu_space = &m_cpu->space(AS_PCI_CONFIG);
+ set_spaces(&space(AS_PCI_MEM), &space(AS_PCI_IO));
+
+ memory_window_start = 0;
+ memory_window_end = 0xffffffff;
+ memory_offset = 0;
+ io_window_start = 0;
+ io_window_end = 0xffffffff;
+ io_offset = 0;
+ command = 0x0006;
+ status = 0x0080;
+ revision = 0x40;
+
+ m_rom = device().machine().root_device().memregion(m_rom_tag)->base();
+ m_rom_size = device().machine().root_device().memregion(m_rom_tag)->bytes();
+
+ m_pwrconfig1 = m_pwrconfig2 = 0;
+
+ u64 rom_base = 0x100000000ULL - m_rom_size;
+ m_cpu_space->install_rom(rom_base, 0xffffffff, m_rom);
+
+ if (m_map_type == MAP_TYPE_A)
+ { // type A is PReP
+ m_cpu_space->install_read_handler (0x80000000, 0x807fffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_io_r<0>)));
+ m_cpu_space->install_write_handler(0x80000000, 0x807fffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_io_w<0>)));
+
+ m_cpu_space->install_device(0x80000000, 0x80000cff, *static_cast<pci_host_device *>(this), &pci_host_device::io_configuration_access_map);
+
+ m_cpu_space->install_read_handler (0x81000000, 0xbf7fffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_io_r<0x01000000>)));
+ m_cpu_space->install_write_handler(0x81000000, 0xbf7fffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_io_w<0x01000000>)));
+ m_cpu_space->install_read_handler (0xc0000000, 0xfeffffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_memory_r<0>)));
+ m_cpu_space->install_write_handler(0xc0000000, 0xfeffffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_memory_w<0>)));
+ }
+ else if (m_map_type == MAP_TYPE_B)
+ { // type B is CHRP
+ m_cpu_space->install_read_handler (0x80000000, 0xfcffffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_memory_r<0x80000000>)));
+ m_cpu_space->install_write_handler(0x80000000, 0xfcffffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_memory_w<0x80000000>)));
+ m_cpu_space->install_read_handler (0xfd000000, 0xfdffffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_memory_r<0>)));
+ m_cpu_space->install_write_handler(0xfd000000, 0xfdffffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_memory_w<0>)));
+ m_cpu_space->install_read_handler (0xfe000000, 0xfe00ffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_io_r<0>)));
+ m_cpu_space->install_write_handler(0xfe000000, 0xfe00ffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_io_w<0>)));
+ m_cpu_space->install_read_handler (0xfe800000, 0xfebfffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_io_r<0x00800000>)));
+ m_cpu_space->install_write_handler(0xfe800000, 0xfebfffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_io_w<0x00800000>)));
+
+ if (m_picr1 & PICR1_LE_MODE)
+ {
+ m_cpu_space->install_device(0xfec00000, 0xfeefffff, *static_cast<mpc106_host_device *>(this), &mpc106_host_device::access_map_le);
+ }
+ else
+ {
+ m_cpu_space->install_device(0xfec00000, 0xfeefffff, *static_cast<mpc106_host_device *>(this), &mpc106_host_device::access_map_be);
+ }
+ }
+
+ save_item(NAME(m_pwrconfig1));
+ save_item(NAME(m_pwrconfig2));
+ save_item(NAME(m_memory_starts));
+ save_item(NAME(m_memory_ends));
+ save_item(NAME(m_memory_bank_enable));
+ save_item(NAME(m_picr1));
+}
+
+device_memory_interface::space_config_vector mpc106_host_device::memory_space_config() const
+{
+ auto r = pci_bridge_device::memory_space_config();
+ r.emplace_back(std::make_pair(AS_PCI_MEM, &m_mem_config));
+ r.emplace_back(std::make_pair(AS_PCI_IO, &m_io_config));
+ return r;
+}
+
+void mpc106_host_device::reset_all_mappings()
+{
+ pci_host_device::reset_all_mappings();
+}
+
+void mpc106_host_device::device_reset()
+{
+ pci_host_device::device_reset();
+}
+
+void mpc106_host_device::access_map_le(address_map &map)
+{
+ map(0x00000000, 0x001fffff).rw(FUNC(mpc106_host_device::config_address_r), FUNC(mpc106_host_device::config_address_w));
+ map(0x00200000, 0x002fffff).rw(FUNC(mpc106_host_device::config_data_r), FUNC(mpc106_host_device::config_data_w));
+}
+
+void mpc106_host_device::access_map_be(address_map &map)
+{
+ map(0x00000000, 0x001fffff).rw(FUNC(mpc106_host_device::be_config_address_r), FUNC(mpc106_host_device::be_config_address_w));
+ map(0x00200000, 0x002fffff).rw(FUNC(mpc106_host_device::be_config_data_r), FUNC(mpc106_host_device::be_config_data_w));
+}
+
+u32 mpc106_host_device::be_config_address_r()
+{
+ return swapendian_int32(pci_host_device::config_address_r());
+}
+
+void mpc106_host_device::be_config_address_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ pci_host_device::config_address_w(offset, swapendian_int32(data), swapendian_int32(mem_mask));
+}
+
+u32 mpc106_host_device::be_config_data_r(offs_t offset, u32 mem_mask)
+{
+ return swapendian_int32(pci_host_device::config_data_r(offset, swapendian_int32(mem_mask)));
+}
+
+void mpc106_host_device::be_config_data_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ pci_host_device::config_data_w(offset, swapendian_int32(data), swapendian_int32(mem_mask));
+}
+
+template <u32 Base>
+u32 mpc106_host_device::cpu_memory_r(offs_t offset, u32 mem_mask)
+{
+ if (m_picr1 & PICR1_LE_MODE)
+ {
+ return m_cpu_space->read_dword(Base + (offset * 4), mem_mask);
+ }
+ else
+ {
+ return swapendian_int32(m_cpu_space->read_dword(Base + (offset * 4), swapendian_int32(mem_mask)));
+ }
+}
+
+template <u32 Base>
+void mpc106_host_device::cpu_memory_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ if (m_picr1 & PICR1_LE_MODE)
+ {
+ m_cpu_space->write_dword(Base + (offset * 4), data, mem_mask);
+ }
+ else
+ {
+ m_cpu_space->write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32(mem_mask));
+ }
+}
+
+template u32 mpc106_host_device::cpu_memory_r<0>(offs_t offset, u32 mem_mask);
+template u32 mpc106_host_device::cpu_memory_r<0xff800000>(offs_t offset, u32 mem_mask);
+
+template void mpc106_host_device::cpu_memory_w<0>(offs_t offset, u32 data, u32 mem_mask);
+template void mpc106_host_device::cpu_memory_w<0xff800000>(offs_t offset, u32 data, u32 mem_mask);
+
+template <u32 Base>
+u32 mpc106_host_device::pci_memory_r(offs_t offset, u32 mem_mask)
+{
+ if (m_picr1 & PICR1_LE_MODE)
+ {
+ return this->space(AS_PCI_MEM).read_dword(Base + (offset * 4), mem_mask);
+ }
+ else
+ {
+ return swapendian_int32(this->space(AS_PCI_MEM).read_dword(Base + (offset * 4), swapendian_int32(mem_mask)));
+ }
+}
+
+template <u32 Base>
+void mpc106_host_device::pci_memory_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ if (m_picr1 & PICR1_LE_MODE)
+ {
+ this->space(AS_PCI_MEM).write_dword(Base + (offset * 4), data, mem_mask);
+ }
+ else
+ {
+ this->space(AS_PCI_MEM).write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32((mem_mask)));
+ }
+}
+
+template u32 mpc106_host_device::pci_memory_r<0>(offs_t offset, u32 mem_mask);
+template u32 mpc106_host_device::pci_memory_r<0x80000000>(offs_t offset, u32 mem_mask);
+
+template void mpc106_host_device::pci_memory_w<0>(offs_t offset, u32 data, u32 mem_mask);
+template void mpc106_host_device::pci_memory_w<0x80000000>(offs_t offset, u32 data, u32 mem_mask);
+
+template <u32 Base>
+u32 mpc106_host_device::pci_io_r(offs_t offset, u32 mem_mask)
+{
+ if (m_picr1 & PICR1_LE_MODE)
+ {
+ return this->space(AS_PCI_IO).read_dword(Base + (offset * 4), mem_mask);
+ }
+ else
+ {
+ return swapendian_int32(this->space(AS_PCI_IO).read_dword(Base + (offset * 4), swapendian_int32(mem_mask)));
+ }
+}
+
+template <u32 Base>
+void mpc106_host_device::pci_io_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ if (m_picr1 & PICR1_LE_MODE)
+ {
+ this->space(AS_PCI_IO).write_dword(Base + (offset * 4), data, mem_mask);
+ }
+ else
+ {
+ this->space(AS_PCI_IO).write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32((mem_mask)));
+ }
+}
+
+template u32 mpc106_host_device::pci_io_r<0>(offs_t offset, u32 mem_mask);
+template u32 mpc106_host_device::pci_io_r<0x01000000>(offs_t offset, u32 mem_mask);
+template u32 mpc106_host_device::pci_io_r<0x00800000>(offs_t offset, u32 mem_mask);
+
+template void mpc106_host_device::pci_io_w<0>(offs_t offset, u32 data, u32 mem_mask);
+template void mpc106_host_device::pci_io_w<0x01000000>(offs_t offset, u32 data, u32 mem_mask);
+template void mpc106_host_device::pci_io_w<0x00800000>(offs_t offset, u32 data, u32 mem_mask);
+
+// map PCI memory and I/O space stuff here
+void mpc106_host_device::map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space,
+ u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space)
+{
+ // map RAM and ROM into the PCI memory space (because the PPC bus is 64 bits wide, and weirdness happens on DMA otherwise)
+ memory_space->install_read_handler(0xff800000, 0xffffffff, read32s_delegate(*this, FUNC(mpc106_host_device::cpu_memory_r<0xff800000>)));
+
+ memory_space->install_read_handler(0, m_ram_size - 1, read32s_delegate(*this, FUNC(mpc106_host_device::cpu_memory_r<0>)));
+ memory_space->install_write_handler(0, m_ram_size - 1, write32s_delegate(*this, FUNC(mpc106_host_device::cpu_memory_w<0>)));
+}
+
+u16 mpc106_host_device::pwrconfig1_r()
+{
+ return m_pwrconfig1;
+}
+
+void mpc106_host_device::pwrconfig1_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ COMBINE_DATA(&m_pwrconfig1);
+}
+
+u8 mpc106_host_device::pwrconfig2_r()
+{
+ return m_pwrconfig2;
+}
+
+void mpc106_host_device::pwrconfig2_w(offs_t offset, u8 data)
+{
+ m_pwrconfig2 = data;
+}
+
+u32 mpc106_host_device::memory_start_r(offs_t offset)
+{
+ return m_memory_starts[offset];
+}
+
+void mpc106_host_device::memory_start_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_memory_starts[offset]);
+ LOGMASKED(LOG_RAM, "%s: %08x to memory start @ %x\n", tag(), data, offset);
+}
+
+u32 mpc106_host_device::memory_end_r(offs_t offset)
+{
+ return m_memory_ends[offset];
+}
+
+void mpc106_host_device::memory_end_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_memory_ends[offset]);
+ LOGMASKED(LOG_RAM, "%s: %08x to memory end @ %x\n", tag(), data, offset);
+}
+
+u8 mpc106_host_device::memory_enable_r()
+{
+ return m_memory_bank_enable;
+}
+
+void mpc106_host_device::memory_enable_w(offs_t offset, u8 data)
+{
+ LOGMASKED(LOG_RAM, "%s: %02x to memory_enable\n", tag(), data);
+ m_memory_bank_enable = data;
+
+ // unmap all RAM
+ m_cpu_space->unmap_readwrite(0x00000000, 0x0fffffff);
+
+ u64 base = m_memory_starts[0] | ((u64)m_memory_starts[1] << 32);
+ u64 base2 = m_memory_starts[2] | ((u64)m_memory_starts[3] << 32);
+ u64 end = m_memory_ends[0] | ((u64)m_memory_ends[0] << 32);
+ u64 end2 = m_memory_ends[2] | ((u64)m_memory_ends[3] << 32);
+ u32 bank_start = 0;
+ u32 bank_end = 0;
+ u64 install_ptr = 0;
+
+ for (int bank = 0; bank < 8; bank++)
+ {
+ if (((base & 0xff) != 0xff) && (BIT(m_memory_bank_enable, bank)))
+ {
+ bank_start = (base & 0xff) << 20;
+ bank_start |= (base2 & 0xff) << 28;
+ bank_end = (end & 0xff) << 20;
+ bank_end |= (end2 & 0xff) << 28;
+ bank_end |= 0xfffff;
+
+ LOGMASKED(LOG_RAM, "bank %d: start %08x end %08x, install_ptr = %llx\n", bank, bank_start, bank_end, install_ptr);
+
+ m_cpu_space->install_ram(bank_start, bank_end, &m_ram[install_ptr]);
+ install_ptr += (bank_end + 1);
+ }
+
+ base >>= 8;
+ base2 >>= 8;
+ end >>= 8;
+ end2 >>= 8;
+ }
+}
+
+u32 mpc106_host_device::picr1_r()
+{
+ return m_picr1;
+}
+
+void mpc106_host_device::picr1_w(u32 data)
+{
+ m_picr1 = data;
+}
diff --git a/src/devices/machine/mpc106.h b/src/devices/machine/mpc106.h
new file mode 100644
index 00000000000..da4ecca061f
--- /dev/null
+++ b/src/devices/machine/mpc106.h
@@ -0,0 +1,99 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/**********************************************************************
+
+ mpc106.h - Motorola MPC-106 PCI host bridge, aka "Grackle".
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_MPC106_H
+#define MAME_MACHINE_MPC106_H
+
+#pragma once
+
+#include "pci.h"
+
+class mpc106_host_device : public pci_host_device {
+public:
+ typedef enum
+ {
+ MAP_TYPE_A, // Type A is PowerPC Reference Platform (PReP)
+ MAP_TYPE_B // Type B is Common Hardware Reference Platform (CHRP)
+ } map_type;
+
+ template <typename T>
+ mpc106_host_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, map_type map, T &&cpu_tag, const char *rom_tag)
+ : mpc106_host_device(mconfig, tag, owner, clock)
+ {
+ set_ids_host(0x10570002, 0x00, 0x00000000);
+ set_map_type(map);
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ set_rom_tag(rom_tag);
+ }
+ mpc106_host_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ template <typename T> void set_cpu_tag(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
+ void set_ram_info(u8 *ram_ptr, int ram_size);
+ void set_rom_tag(const char *tag);
+ void set_map_type(map_type maptype);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void reset_all_mappings() override;
+
+ virtual void map_extra(u64 memory_window_start, u64 memory_window_end, u64 memory_offset, address_space *memory_space,
+ u64 io_window_start, u64 io_window_end, u64 io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ void access_map_le(address_map &map);
+ void access_map_be(address_map &map);
+ u32 be_config_address_r();
+ void be_config_address_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+ u32 be_config_data_r(offs_t offset, u32 mem_mask = ~0);
+ void be_config_data_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+ template <u32 Base> u32 cpu_memory_r(offs_t offset, u32 mem_mask);
+ template <u32 Base> void cpu_memory_w(offs_t offset, u32 data, u32 mem_mask);
+ template <u32 Base> u32 pci_memory_r(offs_t offset, u32 mem_mask);
+ template <u32 Base> void pci_memory_w(offs_t offset, u32 data, u32 mem_mask);
+ template <u32 Base> u32 pci_io_r(offs_t offset, u32 mem_mask);
+ template <u32 Base> void pci_io_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u16 pwrconfig1_r();
+ void pwrconfig1_w(offs_t offset, u16 data, u16 mem_mask);
+ u8 pwrconfig2_r();
+ void pwrconfig2_w(offs_t offset, u8 data);
+ u32 memory_start_r(offs_t offset);
+ void memory_start_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 memory_end_r(offs_t offset);
+ void memory_end_w(offs_t offset, u32 data, u32 mem_mask);
+ u8 memory_enable_r();
+ void memory_enable_w(offs_t offset, u8 data);
+ u32 picr1_r();
+ void picr1_w(u32 data);
+
+ address_space_config m_mem_config, m_io_config;
+ const char *m_rom_tag;
+ u8 *m_ram;
+ int m_ram_size;
+ map_type m_map_type;
+ required_device<device_memory_interface> m_cpu;
+ u8 *m_rom;
+ u32 m_rom_size;
+ address_space *m_cpu_space;
+ u16 m_pwrconfig1;
+ u8 m_pwrconfig2;
+ u32 m_memory_starts[4];
+ u32 m_memory_ends[4];
+ u32 m_picr1;
+ u8 m_memory_bank_enable;
+};
+
+DECLARE_DEVICE_TYPE(MPC106, mpc106_host_device)
+
+#endif // MAME_MACHINE_MPC106_H
diff --git a/src/devices/machine/mpu401.cpp b/src/devices/machine/mpu401.cpp
index 0103e51ceca..2bf71c51fbf 100644
--- a/src/devices/machine/mpu401.cpp
+++ b/src/devices/machine/mpu401.cpp
@@ -39,11 +39,11 @@
***************************************************************************/
#include "emu.h"
-#include "machine/mpu401.h"
+#include "mpu401.h"
+
#include "bus/midi/midi.h"
#define M6801_TAG "mpu6801"
-#define ROM_TAG "mpurom"
#define MIDIIN_TAG "mdin"
#define MIDIOUT_TAG "mdout"
@@ -59,15 +59,12 @@
void mpu401_device::mpu401_map(address_map &map)
{
- map(0x0000, 0x001f).m(m_ourcpu, FUNC(m6801_cpu_device::m6801_io));
map(0x0020, 0x0021).rw(FUNC(mpu401_device::asic_r), FUNC(mpu401_device::asic_w));
- map(0x0080, 0x00ff).ram(); // on-chip RAM
map(0x0800, 0x0fff).ram(); // external RAM
- map(0xf000, 0xffff).rom().region(ROM_TAG, 0);
}
ROM_START( mpu401 )
- ROM_REGION(0x1000, ROM_TAG, 0)
+ ROM_REGION(0x1000, M6801_TAG, 0)
ROM_LOAD( "roland__6801v0b55p__15179222.bin", 0x000000, 0x001000, CRC(65d3a151) SHA1(00efbfb96aeb997b69bb16981c6751d3c784bb87) ) /* Mask MCU; Label: "Roland // 6801V0B55P // 5A1 JAPAN // 15179222"; This is the final version (1.5A) of the mpu401 firmware; version is located at offsets 0x649 (0x15) and 0x64f (0x01) */
ROM_END
@@ -83,7 +80,7 @@ DEFINE_DEVICE_TYPE(MPU401, mpu401_device, "mpu401", "Roland MPU-401 I/O box")
void mpu401_device::device_add_mconfig(machine_config &config)
{
- M6801(config, m_ourcpu, 4000000); /* 4 MHz as per schematics */
+ HD6801V0(config, m_ourcpu, 4000000); /* 4 MHz as per schematics */
m_ourcpu->set_addrmap(AS_PROGRAM, &mpu401_device::mpu401_map);
m_ourcpu->in_p1_cb().set(FUNC(mpu401_device::port1_r));
m_ourcpu->out_p1_cb().set(FUNC(mpu401_device::port1_w));
@@ -126,8 +123,7 @@ mpu401_device::mpu401_device(const machine_config &mconfig, const char *tag, dev
void mpu401_device::device_start()
{
- write_irq.resolve_safe();
- m_timer = timer_alloc(0, nullptr);
+ m_timer = timer_alloc(FUNC(mpu401_device::serial_tick), this);
}
//-------------------------------------------------
@@ -145,12 +141,12 @@ void mpu401_device::device_reset()
}
//-------------------------------------------------
-// device_timer - called when our device timer expires
+// serial_tick - update the 6801's serial clock
//-------------------------------------------------
-void mpu401_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(mpu401_device::serial_tick)
{
- m_ourcpu->m6801_clock_serial();
+ m_ourcpu->clock_serial();
}
uint8_t mpu401_device::port1_r()
diff --git a/src/devices/machine/mpu401.h b/src/devices/machine/mpu401.h
index 6a51a8f3e91..a76cc53dcdd 100644
--- a/src/devices/machine/mpu401.h
+++ b/src/devices/machine/mpu401.h
@@ -28,9 +28,10 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual const tiny_rom_entry *device_rom_region() const override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_add_mconfig(machine_config &config) override;
+ TIMER_CALLBACK_MEMBER(serial_tick);
+
private:
void midi_rx_w(int state);
diff --git a/src/devices/machine/msm5001n.cpp b/src/devices/machine/msm5001n.cpp
new file mode 100644
index 00000000000..4fd30735314
--- /dev/null
+++ b/src/devices/machine/msm5001n.cpp
@@ -0,0 +1,199 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+OKI MSM5001N CMOS LCD Watch IC
+
+Decap shows it's not an MCU. No known documentation exists, but there are datasheets
+available for equivalent Samsung chips: KS5198, KS5199A, KS5114.
+
+These kind of chips were used a lot for cheap 2-button digital wristwatches.
+
+TODO:
+- add D/S inputs (other display modes, setup mode)
+- datasheets mention a 4-year calendar, does it mean it supports leap years somehow?
+- one of the Samsung datasheets mention 24hr mode, does the MSM5001N support that?
+
+*/
+
+#include "emu.h"
+#include "msm5001n.h"
+
+
+DEFINE_DEVICE_TYPE(MSM5001N, msm5001n_device, "msm5001n", "OKI MSM5001N LCD Watch")
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+msm5001n_device::msm5001n_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, MSM5001N, tag, owner, clock),
+ device_rtc_interface(mconfig, *this),
+ device_nvram_interface(mconfig, *this),
+ m_write_segs(*this)
+{ }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+// allow save_item on a non-fundamental type
+ALLOW_SAVE_TYPE(msm5001n_device::mode);
+
+void msm5001n_device::device_start()
+{
+ m_timer = timer_alloc(FUNC(msm5001n_device::clock_tick), this);
+
+ m_power = true;
+ initialize();
+
+ // register for savestates
+ save_item(NAME(m_power));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_counter));
+}
+
+void msm5001n_device::initialize()
+{
+ m_mode = MODE_NORMAL_HRMIN;
+ m_counter = 0;
+
+ // 1 January, 1AM
+ set_time(true, 0, 1, 1, 1, 1, 0, 0);
+}
+
+
+//-------------------------------------------------
+// input pins
+//-------------------------------------------------
+
+void msm5001n_device::d_w(int state)
+{
+}
+
+void msm5001n_device::s_w(int state)
+{
+}
+
+void msm5001n_device::power_w(int state)
+{
+ if (m_power && !state)
+ {
+ // reset chip when power goes off
+ initialize();
+ write_lcd(nullptr, false);
+ }
+
+ m_power = bool(state);
+}
+
+void msm5001n_device::device_clock_changed()
+{
+ // smallest interval (at default frequency of 32768Hz) is LCD refresh at 32Hz
+ attotime period = attotime::from_ticks(1024, clock());
+ m_timer->adjust(period, 0, period);
+
+ // clear LCD if clock stopped
+ if (clock() == 0)
+ write_lcd(nullptr, false);
+}
+
+
+//-------------------------------------------------
+// process
+//-------------------------------------------------
+
+void msm5001n_device::write_lcd(u8 *digits, bool colon)
+{
+ u32 segs = 0;
+
+ if (digits)
+ {
+ // 0-9, A, P, none
+ static const u8 lut_segs[0x10] =
+ { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x73,0x00,0x00,0x00,0x00 };
+
+ for (int i = 0; i < 4; i++)
+ segs |= lut_segs[digits[i]] << (8 * i);
+ }
+ segs |= colon ? 0x80 : 0;
+
+ // COM1: BC1,F2,A2,B2,COLON,F3,AD3,B3,F4,A4,B4
+ m_write_segs(0, bitswap<11>(segs,25,21,16,17,7,13,8,9,5,0,1));
+
+ // COM2: D2,E2,G2,C2,D4,E3,G3,C3,E4,G4,C4
+ m_write_segs(1, bitswap<11>(segs,19,20,22,18,3,12,14,10,4,6,2));
+}
+
+TIMER_CALLBACK_MEMBER(msm5001n_device::clock_tick)
+{
+ if (!m_power)
+ return;
+
+ m_counter++;
+ if ((m_counter & 0x1f) == 0)
+ advance_seconds();
+
+ u8 digits[4];
+ for (int i = 0; i < 4; i++)
+ digits[i] = 0xf;
+ bool colon = false;
+
+ // convert current time to BCD
+ u8 minute = convert_to_bcd(get_clock_register(RTC_MINUTE));
+ u8 hour = get_clock_register(RTC_HOUR) % 12;
+ hour = convert_to_bcd((hour == 0) ? 12 : hour);
+
+ switch (m_mode)
+ {
+ case MODE_NORMAL_HRMIN:
+ digits[0] = minute & 0xf;
+ digits[1] = minute >> 4;
+ digits[2] = hour & 0xf;
+ if (hour & 0xf0)
+ digits[3] = hour >> 4;
+
+ colon = !BIT(m_counter, 4);
+ break;
+
+ default:
+ break;
+ }
+
+ write_lcd(digits, colon);
+}
+
+
+//-------------------------------------------------
+// nvram
+//-------------------------------------------------
+
+bool msm5001n_device::nvram_write(util::write_stream &file)
+{
+ u8 buf[5];
+
+ // current time
+ for (int i = 0; i < 5; i++)
+ buf[i] = get_clock_register(i);
+
+ auto const [err, actual] = write(file, &buf, sizeof(buf));
+ if (err)
+ return false;
+
+ return true;
+}
+
+bool msm5001n_device::nvram_read(util::read_stream &file)
+{
+ u8 buf[5];
+ auto const [err, actual] = read(file, &buf, sizeof(buf));
+ if (err || (sizeof(buf) != actual))
+ return false;
+
+ // current time
+ for (int i = 0; i < 5; i++)
+ set_clock_register(i, buf[i]);
+
+ return true;
+}
diff --git a/src/devices/machine/msm5001n.h b/src/devices/machine/msm5001n.h
new file mode 100644
index 00000000000..d7e16998e34
--- /dev/null
+++ b/src/devices/machine/msm5001n.h
@@ -0,0 +1,65 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ OKI MSM5001N CMOS LCD Watch IC
+
+*/
+
+#ifndef MAME_MACHINE_MSM5001N_H
+#define MAME_MACHINE_MSM5001N_H
+
+#pragma once
+
+#include "dirtc.h"
+
+class msm5001n_device : public device_t, public device_rtc_interface, public device_nvram_interface
+{
+public:
+ msm5001n_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // configuration helpers
+ auto write_segs() { return m_write_segs.bind(); } // COM in offset, SEG pins in data
+
+ void d_w(int state); // D button
+ void s_w(int state); // S button
+ void power_w(int state);
+
+ // set_current_time is unused here (only using dirtc for the counters)
+ virtual void set_current_time(const system_time &systime) override { ; }
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_clock_changed() override;
+
+ // device_nvram_interface implementation
+ virtual void nvram_default() override { ; }
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override { ; } // unused
+
+private:
+ enum mode : u8
+ {
+ MODE_NORMAL_HRMIN = 0
+ };
+
+ emu_timer *m_timer;
+
+ bool m_power;
+ mode m_mode;
+ u8 m_counter;
+
+ devcb_write16 m_write_segs;
+
+ TIMER_CALLBACK_MEMBER(clock_tick);
+ void write_lcd(u8 *digits, bool colon);
+ void initialize();
+};
+
+
+DECLARE_DEVICE_TYPE(MSM5001N, msm5001n_device)
+
+#endif // MAME_MACHINE_MSM5001N_H
diff --git a/src/devices/machine/msm5832.cpp b/src/devices/machine/msm5832.cpp
index 9d4ef6e088a..0d1310f8d91 100644
--- a/src/devices/machine/msm5832.cpp
+++ b/src/devices/machine/msm5832.cpp
@@ -110,7 +110,7 @@ msm5832_device::msm5832_device(const machine_config &mconfig, const char *tag, d
void msm5832_device::device_start()
{
// allocate timers
- m_clock_timer = timer_alloc(TIMER_CLOCK);
+ m_clock_timer = timer_alloc(FUNC(msm5832_device::clock_tick), this);
m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
// state saving
@@ -125,19 +125,14 @@ void msm5832_device::device_start()
//-------------------------------------------------
-// device_timer - handler timer events
+// clock_tick - advance the RTC if enabled
//-------------------------------------------------
-void msm5832_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(msm5832_device::clock_tick)
{
- switch (id)
+ if (!m_hold)
{
- case TIMER_CLOCK:
- if (!m_hold)
- {
- advance_seconds();
- }
- break;
+ advance_seconds();
}
}
@@ -217,7 +212,7 @@ void msm5832_device::address_w(uint8_t data)
// adj_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm5832_device::adj_w )
+void msm5832_device::adj_w(int state)
{
LOG("MSM5832 30 ADJ: %u\n", state);
@@ -232,7 +227,7 @@ WRITE_LINE_MEMBER( msm5832_device::adj_w )
// test_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm5832_device::test_w )
+void msm5832_device::test_w(int state)
{
LOG("MSM5832 TEST: %u\n", state);
}
@@ -242,7 +237,7 @@ WRITE_LINE_MEMBER( msm5832_device::test_w )
// hold_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm5832_device::hold_w )
+void msm5832_device::hold_w(int state)
{
LOG("MSM5832 HOLD: %u\n", state);
@@ -254,7 +249,7 @@ WRITE_LINE_MEMBER( msm5832_device::hold_w )
// read_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm5832_device::read_w )
+void msm5832_device::read_w(int state)
{
LOG("MSM5832 READ: %u\n", state);
@@ -266,7 +261,7 @@ WRITE_LINE_MEMBER( msm5832_device::read_w )
// write_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm5832_device::write_w )
+void msm5832_device::write_w(int state)
{
if (m_write == state)
return;
@@ -296,7 +291,7 @@ WRITE_LINE_MEMBER( msm5832_device::write_w )
// cs_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm5832_device::cs_w )
+void msm5832_device::cs_w(int state)
{
LOG("MSM5832 CS: %u\n", state);
diff --git a/src/devices/machine/msm5832.h b/src/devices/machine/msm5832.h
index 5ba34a537da..9e0d98bdaee 100644
--- a/src/devices/machine/msm5832.h
+++ b/src/devices/machine/msm5832.h
@@ -45,25 +45,24 @@ public:
void address_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( adj_w );
- DECLARE_WRITE_LINE_MEMBER( test_w );
- DECLARE_WRITE_LINE_MEMBER( hold_w );
+ void adj_w(int state);
+ void test_w(int state);
+ void hold_w(int state);
- DECLARE_WRITE_LINE_MEMBER( read_w );
- DECLARE_WRITE_LINE_MEMBER( write_w );
- DECLARE_WRITE_LINE_MEMBER( cs_w );
+ void read_w(int state);
+ void write_w(int state);
+ void cs_w(int state);
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
-private:
- static constexpr device_timer_id TIMER_CLOCK = 0;
+ TIMER_CALLBACK_MEMBER(clock_tick);
+private:
inline int read_counter(int counter);
inline void write_counter(int counter, int value);
diff --git a/src/devices/machine/msm58321.cpp b/src/devices/machine/msm58321.cpp
index 4f74ef3f888..aa0c30987f6 100644
--- a/src/devices/machine/msm58321.cpp
+++ b/src/devices/machine/msm58321.cpp
@@ -201,23 +201,16 @@ msm58321_device::msm58321_device(const machine_config &mconfig, const char *tag,
void msm58321_device::device_start()
{
- // resolve callbacks
- m_d0_handler.resolve_safe();
- m_d1_handler.resolve_safe();
- m_d2_handler.resolve_safe();
- m_d3_handler.resolve_safe();
- m_busy_handler.resolve_safe();
-
// allocate timers
- m_clock_timer = timer_alloc(TIMER_CLOCK);
+ m_clock_timer = timer_alloc(FUNC(msm58321_device::clock_tick), this);
m_clock_timer->adjust(clocks_to_attotime(32768/1024), 0, clocks_to_attotime(32768/1024));
// busy signal active period is approximately 427 µs
- m_busy_timer = timer_alloc(TIMER_BUSY);
+ m_busy_timer = timer_alloc(FUNC(msm58321_device::release_busy), this);
m_busy_timer->adjust(clocks_to_attotime(32768 - 14), 0, clocks_to_attotime(32768));
// standard signal active period is approximately 122 µs
- m_standard_timer = timer_alloc(TIMER_STANDARD);
+ m_standard_timer = timer_alloc(FUNC(msm58321_device::assert_standard), this);
m_standard_timer->adjust(clocks_to_attotime(32768-4), 0, clocks_to_attotime(32768));
// state saving
@@ -244,56 +237,59 @@ void msm58321_device::device_start()
//-------------------------------------------------
-// device_timer - handler timer events
+// clock_tick - advance the RTC
//-------------------------------------------------
-void msm58321_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(msm58321_device::clock_tick)
{
- switch (id)
+ if (m_khz_ctr & 1)
+ {
+ m_reg[REGISTER_REF0] |= 1;
+ m_reg[REGISTER_REF1] |= 1;
+ }
+ else
{
- case TIMER_CLOCK:
+ m_reg[REGISTER_REF0] &= ~1;
+ m_reg[REGISTER_REF1] &= ~1;
+ }
- if (m_khz_ctr & 1)
+ if (++m_khz_ctr >= 1024)
+ {
+ m_khz_ctr = 0;
+ if (!m_stop)
{
- m_reg[REGISTER_REF0] |= 1;
- m_reg[REGISTER_REF1] |= 1;
+ advance_seconds();
}
- else
+
+ if (!m_busy)
{
- m_reg[REGISTER_REF0] &= ~1;
- m_reg[REGISTER_REF1] &= ~1;
+ m_busy = 1;
+ m_busy_handler(m_busy);
}
+ }
+}
- if (++m_khz_ctr >= 1024)
- {
- m_khz_ctr = 0;
- if (!m_stop)
- {
- advance_seconds();
- }
- if (!m_busy)
- {
- m_busy = 1;
- m_busy_handler(m_busy);
- }
- }
- break;
+//-------------------------------------------------
+// release_busy - release the 'busy' line after
+// an appropriate amount of time
+//-------------------------------------------------
- case TIMER_BUSY:
- if (!m_cs1 || !m_cs2 || !m_write || m_address != REGISTER_RESET)
- {
- m_busy = 0;
- m_busy_handler(m_busy);
- }
- break;
- case TIMER_STANDARD:
- m_reg[REGISTER_REF0] = 0x0e;
- m_reg[REGISTER_REF1] = 0x0e;
- break;
+TIMER_CALLBACK_MEMBER(msm58321_device::release_busy)
+{
+ if (!m_cs1 || !m_cs2 || !m_write || m_address != REGISTER_RESET)
+ {
+ m_busy = 0;
+ m_busy_handler(m_busy);
}
}
+TIMER_CALLBACK_MEMBER(msm58321_device::assert_standard)
+{
+ m_reg[REGISTER_REF0] = 0x0e;
+ m_reg[REGISTER_REF1] = 0x0e;
+}
+
void msm58321_device::update_standard()
{
uint8_t reg = 0;
@@ -350,11 +346,14 @@ void msm58321_device::nvram_default()
// .nv file
//-------------------------------------------------
-void msm58321_device::nvram_read(emu_file &file)
+bool msm58321_device::nvram_read(util::read_stream &file)
{
- file.read(m_reg.data(), m_reg.size());
+ auto const [err, actual] = read(file, m_reg.data(), m_reg.size());
+ if (err || (actual != m_reg.size()))
+ return false;
clock_updated();
+ return true;
}
@@ -363,9 +362,10 @@ void msm58321_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void msm58321_device::nvram_write(emu_file &file)
+bool msm58321_device::nvram_write(util::write_stream &file)
{
- file.write(m_reg.data(), m_reg.size());
+ auto const [err, actual] = write(file, m_reg.data(), m_reg.size());
+ return !err;
}
//-------------------------------------------------
@@ -508,7 +508,7 @@ void msm58321_device::update_input()
// cs2_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::cs2_w )
+void msm58321_device::cs2_w(int state)
{
if (m_cs2 != state)
{
@@ -525,7 +525,7 @@ WRITE_LINE_MEMBER( msm58321_device::cs2_w )
// write_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::write_w )
+void msm58321_device::write_w(int state)
{
if (m_write != state)
{
@@ -542,7 +542,7 @@ WRITE_LINE_MEMBER( msm58321_device::write_w )
// read_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::read_w )
+void msm58321_device::read_w(int state)
{
if (m_read != state)
{
@@ -560,7 +560,7 @@ WRITE_LINE_MEMBER( msm58321_device::read_w )
// d0_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::d0_w )
+void msm58321_device::d0_w(int state)
{
if (m_d0_in != state)
{
@@ -575,7 +575,7 @@ WRITE_LINE_MEMBER( msm58321_device::d0_w )
// d1_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::d1_w )
+void msm58321_device::d1_w(int state)
{
if (m_d1_in != state)
{
@@ -590,7 +590,7 @@ WRITE_LINE_MEMBER( msm58321_device::d1_w )
// d2_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::d2_w )
+void msm58321_device::d2_w(int state)
{
if (m_d2_in != state)
{
@@ -605,7 +605,7 @@ WRITE_LINE_MEMBER( msm58321_device::d2_w )
// d3_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::d3_w )
+void msm58321_device::d3_w(int state)
{
if (m_d3_in != state)
{
@@ -620,7 +620,7 @@ WRITE_LINE_MEMBER( msm58321_device::d3_w )
// address_write_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::address_write_w )
+void msm58321_device::address_write_w(int state)
{
if (m_address_write != state)
{
@@ -637,7 +637,7 @@ WRITE_LINE_MEMBER( msm58321_device::address_write_w )
// stop_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::stop_w )
+void msm58321_device::stop_w(int state)
{
if (m_stop != state)
{
@@ -652,7 +652,7 @@ WRITE_LINE_MEMBER( msm58321_device::stop_w )
// test_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::test_w )
+void msm58321_device::test_w(int state)
{
if (m_test != state)
{
@@ -668,7 +668,7 @@ WRITE_LINE_MEMBER( msm58321_device::test_w )
// cs1_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( msm58321_device::cs1_w )
+void msm58321_device::cs1_w(int state)
{
if (m_cs1 != state)
{
diff --git a/src/devices/machine/msm58321.h b/src/devices/machine/msm58321.h
index d5b7a5d78c3..e04e3136854 100644
--- a/src/devices/machine/msm58321.h
+++ b/src/devices/machine/msm58321.h
@@ -58,22 +58,21 @@ public:
void set_year0(int year0) { m_year0 = year0; }
void set_default_24h(bool default_24h) { m_default_24h = default_24h; }
- DECLARE_WRITE_LINE_MEMBER( cs2_w );
- DECLARE_WRITE_LINE_MEMBER( write_w );
- DECLARE_WRITE_LINE_MEMBER( read_w );
- DECLARE_WRITE_LINE_MEMBER( d0_w );
- DECLARE_WRITE_LINE_MEMBER( d1_w );
- DECLARE_WRITE_LINE_MEMBER( d2_w );
- DECLARE_WRITE_LINE_MEMBER( d3_w );
- DECLARE_WRITE_LINE_MEMBER( address_write_w );
- DECLARE_WRITE_LINE_MEMBER( stop_w );
- DECLARE_WRITE_LINE_MEMBER( test_w );
- DECLARE_WRITE_LINE_MEMBER( cs1_w );
+ void cs2_w(int state);
+ void write_w(int state);
+ void read_w(int state);
+ void d0_w(int state);
+ void d1_w(int state);
+ void d2_w(int state);
+ void d3_w(int state);
+ void address_write_w(int state);
+ void stop_w(int state);
+ void test_w(int state);
+ void cs1_w(int state);
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
@@ -81,15 +80,15 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
virtual bool rtc_feature_leap_year() const override { return true; }
-private:
- static constexpr device_timer_id TIMER_CLOCK = 0;
- static constexpr device_timer_id TIMER_BUSY = 1;
- static constexpr device_timer_id TIMER_STANDARD = 2;
+ TIMER_CALLBACK_MEMBER(clock_tick);
+ TIMER_CALLBACK_MEMBER(release_busy);
+ TIMER_CALLBACK_MEMBER(assert_standard);
+private:
void update_input();
void update_output();
void update_standard();
diff --git a/src/devices/machine/msm6200.cpp b/src/devices/machine/msm6200.cpp
new file mode 100644
index 00000000000..70e05aa1ddf
--- /dev/null
+++ b/src/devices/machine/msm6200.cpp
@@ -0,0 +1,99 @@
+// license:BSD-3-Clause
+// copyright-holders:Devin Acker
+/***************************************************************************
+ OKI MSM6200 keyboard controller (HLE)
+***************************************************************************/
+
+#include "emu.h"
+#include "msm6200.h"
+
+DEFINE_DEVICE_TYPE(MSM6200, msm6200_device, "msm6200", "OKI MSM6200 keyboard controller")
+
+/**************************************************************************/
+msm6200_device::msm6200_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MSM6200, tag, owner, clock),
+ m_keys(*this, "KI%u", 1u),
+ m_velocity(*this, "VELOCITY"),
+ m_irq_cb(*this)
+{
+}
+
+/**************************************************************************/
+void msm6200_device::device_start()
+{
+ m_cmd = 0xf;
+
+ save_item(NAME(m_cmd));
+ save_item(NAME(m_row));
+ save_item(NAME(m_key_data));
+ save_item(NAME(m_key_state));
+ save_item(NAME(m_last_state));
+}
+
+/**************************************************************************/
+void msm6200_device::device_reset()
+{
+ m_row = 0;
+ m_key_data = 0;
+ m_key_state = 0;
+ std::fill(std::begin(m_last_state), std::end(m_last_state), 0);
+}
+
+/**************************************************************************/
+void msm6200_device::write(offs_t offset, u8 data)
+{
+ // 8-bit multiplexed address/data bus, upper 4 bits are output only
+ // on write, the lower 4 bits of the address are latched and the data is ignored
+ m_cmd = offset & 0xf;
+ m_key_data = 0xff;
+
+ switch (m_cmd)
+ {
+ case 0: // read key number
+ for (int i = 0; i < 2; i++)
+ {
+ if (BIT(m_key_state ^ m_last_state[m_row], i))
+ {
+ m_last_state[m_row] ^= (1 << i);
+ m_key_data = (BIT(m_key_state, i) << 7) | ((m_row + 1) << 1) | i;
+ break;
+ }
+ }
+ if (m_key_state == m_last_state[m_row])
+ m_irq_cb(0);
+ break;
+
+ case 1: // read velocity
+ m_key_data = m_velocity.read_safe(0x3f);
+ break;
+
+ case 2: // next row?
+ (++m_row) %= m_keys.size();
+ // TODO: what should this one actually be?
+ // the cz1/ht6000 key MCU code outputs the result to port 1 for debugging
+ m_key_data = m_row;
+ break;
+
+ case 7: // capture current row?
+ m_key_state = m_keys[m_row].read_safe(0);
+ if (m_key_state != m_last_state[m_row])
+ m_irq_cb(1);
+ break;
+
+ case 8: // init all rows
+ for (int i = 0; i < m_keys.size(); i++)
+ m_last_state[i] = m_keys[i].read_safe(0);
+ m_irq_cb(0);
+ break;
+
+ default:
+ logerror("%s: unknown cmd 0x%x\n", machine().describe_context(), m_cmd);
+ break;
+ }
+}
+
+/**************************************************************************/
+u8 msm6200_device::read()
+{
+ return m_key_data;
+}
diff --git a/src/devices/machine/msm6200.h b/src/devices/machine/msm6200.h
new file mode 100644
index 00000000000..034950d10e7
--- /dev/null
+++ b/src/devices/machine/msm6200.h
@@ -0,0 +1,40 @@
+// license:BSD-3-Clause
+// copyright-holders: Devin Acker
+/***************************************************************************
+ OKI MSM6200 keyboard controller (HLE)
+***************************************************************************/
+
+#ifndef MAME_MACHINE_MSM6200_H
+#define MAME_MACHINE_MSM6200_H
+
+#pragma once
+
+class msm6200_device : public device_t
+{
+public:
+ msm6200_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ auto irq_cb() { return m_irq_cb.bind(); }
+
+ void write(offs_t offset, u8 data);
+ u8 read();
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ optional_ioport_array<38> m_keys;
+ optional_ioport m_velocity;
+
+ devcb_write_line m_irq_cb;
+
+ u8 m_cmd, m_row, m_key_data;
+ u8 m_key_state;
+ u8 m_last_state[38];
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(MSM6200, msm6200_device)
+
+#endif // MAME_MACHINE_MSM6200_H
diff --git a/src/devices/machine/msm6242.cpp b/src/devices/machine/msm6242.cpp
index f6dd7c6dca7..59abd5313bc 100644
--- a/src/devices/machine/msm6242.cpp
+++ b/src/devices/machine/msm6242.cpp
@@ -14,9 +14,8 @@
***************************************************************************/
#include "emu.h"
-#include "machine/msm6242.h"
+#include "msm6242.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_UNMAPPED (1U << 1)
#define LOG_IRQ (1U << 2)
#define LOG_IRQ_ENABLE (1U << 3)
@@ -53,7 +52,6 @@ enum
MSM6242_REG_CF
};
-#define TIMER_RTC_CALLBACK 1
@@ -97,11 +95,11 @@ msm6242_device::msm6242_device(const machine_config &mconfig, device_type type,
void msm6242_device::device_start()
{
- m_out_int_handler.resolve();
-
// let's call the timer callback every tick
- m_timer = timer_alloc(TIMER_RTC_CALLBACK);
+ m_timer = timer_alloc(FUNC(msm6242_device::rtc_timer_callback), this);
m_timer->adjust(attotime::zero);
+ m_timer_irq_clear = timer_alloc(FUNC(msm6242_device::rtc_irq_pulse_timer_callback), this);
+ m_timer_irq_clear->adjust(attotime::zero);
// set up registers
m_tick = 0;
@@ -164,22 +162,6 @@ void msm6242_device::device_post_load()
//-------------------------------------------------
-// device_timer - called whenever a device timer
-// fires
-//-------------------------------------------------
-
-void msm6242_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch(id)
- {
- case TIMER_RTC_CALLBACK:
- rtc_timer_callback();
- break;
- }
-}
-
-
-//-------------------------------------------------
// set_irq - set the IRQ flag and output
//-------------------------------------------------
@@ -190,8 +172,16 @@ void msm6242_device::set_irq(bool active)
else
m_reg[0] &= 0x0b;
- if (!m_out_int_handler.isnull())
+ if (!m_out_int_handler.isunset())
m_out_int_handler(active ? ASSERT_LINE : CLEAR_LINE);
+
+ if (active)
+ {
+ if (!BIT(m_reg[1], 1)) // irq is pulsed
+ {
+ m_timer_irq_clear->adjust(attotime::from_nsec(7812500));
+ }
+ }
}
@@ -278,7 +268,7 @@ void msm6242_device::update_rtc_registers()
return;
// ticks
- if ((m_tick % 200) != int((delta + m_tick) % 0x200))
+ if ((m_tick / 0x200) != int((delta + m_tick) / 0x200))
irq(IRQ_64THSECOND);
delta = bump(RTC_TICKS, delta, 0, 0x8000);
if (delta == 0)
@@ -319,7 +309,7 @@ void msm6242_device::update_timer()
attotime callback_time = attotime::never;
// we only need to call back if the IRQ flag is on, and we have a handler
- if (!m_out_int_handler.isnull() && m_irq_flag == 1)
+ if (!m_out_int_handler.isunset() && m_irq_flag == 1)
{
switch(m_irq_type)
{
@@ -377,7 +367,7 @@ void msm6242_device::rtc_clock_updated(int year, int month, int day, int day_of_
// rtc_timer_callback
//-------------------------------------------------
-void msm6242_device::rtc_timer_callback()
+TIMER_CALLBACK_MEMBER(msm6242_device::rtc_timer_callback)
{
update_rtc_registers();
update_timer();
@@ -386,6 +376,17 @@ void msm6242_device::rtc_timer_callback()
//-------------------------------------------------
+// rtc_irq_pulse_timer_callback
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(msm6242_device::rtc_irq_pulse_timer_callback)
+{
+ set_irq(false);
+}
+
+
+
+//-------------------------------------------------
// get_clock_nibble
//-------------------------------------------------
@@ -535,6 +536,7 @@ void msm6242_device::write(offs_t offset, u8 data)
{
LOGIRQENABLE("%s: MSM6242 acknowledging irq\n", machine().describe_context());
set_irq(false);
+ m_timer_irq_clear->adjust(attotime::zero);
}
m_reg[0] = (data & 0x09) | (m_reg[0] & 0x06);
break;
@@ -544,7 +546,7 @@ void msm6242_device::write(offs_t offset, u8 data)
// --x- STD
// ---x MASK
m_reg[1] = data & 0x0f;
- if((data & 3) == 0) // MASK & STD = 0
+ if((data & 1) == 0) // MASK = 0
{
m_irq_flag = 1;
m_irq_type = (data & 0xc) >> 2;
diff --git a/src/devices/machine/msm6242.h b/src/devices/machine/msm6242.h
index 6ee5929a641..216c66fc5b5 100644
--- a/src/devices/machine/msm6242.h
+++ b/src/devices/machine/msm6242.h
@@ -62,7 +62,6 @@ protected:
virtual void device_reset() override;
virtual void device_pre_save() override;
virtual void device_post_load() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// rtc overrides
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
@@ -84,10 +83,12 @@ private:
// incidentals
devcb_write_line m_out_int_handler;
emu_timer * m_timer;
+ emu_timer * m_timer_irq_clear;
u64 m_last_update_time; // last update time, in clock cycles
// methods
- void rtc_timer_callback();
+ TIMER_CALLBACK_MEMBER(rtc_timer_callback);
+ TIMER_CALLBACK_MEMBER(rtc_irq_pulse_timer_callback);
u64 current_time();
void set_irq(bool active);
void irq(u8 irq_type);
diff --git a/src/devices/machine/msm6253.cpp b/src/devices/machine/msm6253.cpp
index 53a47b2152e..5f6bd1a8a12 100644
--- a/src/devices/machine/msm6253.cpp
+++ b/src/devices/machine/msm6253.cpp
@@ -7,7 +7,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/msm6253.h"
+#include "msm6253.h"
//**************************************************************************
// GLOBAL VARIABLES
diff --git a/src/devices/machine/mv6436x.cpp b/src/devices/machine/mv6436x.cpp
new file mode 100644
index 00000000000..9db05547393
--- /dev/null
+++ b/src/devices/machine/mv6436x.cpp
@@ -0,0 +1,1230 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Marvell MV64360/1/2
+
+ System controller for PowerPC processors
+
+***************************************************************************/
+
+#include "emu.h"
+#include "mv6436x.h"
+
+#define LOG_PCI_CONFIG (1U << 1)
+#define LOG_PCI_MEM (1U << 2)
+#define LOG_PCI_IO (1U << 3)
+#define LOG_REG_READ (1U << 4)
+#define LOG_REG_WRITE (1U << 5)
+
+#define VERBOSE (LOG_GENERAL | LOG_REG_WRITE | LOG_PCI_CONFIG | LOG_PCI_MEM)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(MV64361, mv64361_device, "mv64361", "Marvell MV64361 System Controller")
+DEFINE_DEVICE_TYPE(MV64361_PCI_HOST, mv64361_pci_host_device, "mv64361_pci_host", "Marvell MV64361 PCI Host")
+
+
+//**************************************************************************
+// MV64361 SYSTEM CONTROLLER
+//**************************************************************************
+
+mv64361_device::mv64361_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MV64361, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_pcihost(*this, finder_base::DUMMY_TAG, 0)
+{
+}
+
+void mv64361_device::device_start()
+{
+ m_cpu_space = &m_cpu->space(AS_PROGRAM);
+
+ // 2 MB internal SRAM
+ m_sram = std::make_unique<uint8_t[]>(0x200000);
+
+ // TODO savestates
+}
+
+void mv64361_device::device_reset()
+{
+ // initialize internal registers
+ m_regs[REG_CPU_CONFIG] = 0x028000ff;
+ m_regs[REG_INTERNAL_BASE] = 0x01001400;
+ m_regs[REG_BOOTCS_BASE] = 0x0000ff80;
+ m_regs[REG_BOOTCS_SIZE] = 0x0000007f;
+ m_regs[REG_PCI0_IO_BASE] = 0x01001000;
+ m_regs[REG_PCI0_IO_SIZE] = 0x000001ff;
+ m_regs[REG_PCI0_IO_REMAP] = 0x00001000;
+ m_regs[REG_PCI0_MEM0_BASE] = 0x01001200;
+ m_regs[REG_PCI0_MEM0_SIZE] = 0x000001ff;
+ m_regs[REG_PCI0_MEM0_REMAP_LOW] = 0x00001200;
+ m_regs[REG_PCI0_MEM0_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_PCI0_MEM1_BASE] = 0x0100f200;
+ m_regs[REG_PCI0_MEM1_SIZE] = 0x000001ff;
+ m_regs[REG_PCI0_MEM1_REMAP_LOW] = 0x0000f200;
+ m_regs[REG_PCI0_MEM1_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_PCI0_MEM2_BASE] = 0x0100f400;
+ m_regs[REG_PCI0_MEM2_SIZE] = 0x000001ff;
+ m_regs[REG_PCI0_MEM2_REMAP_LOW] = 0x0000f400;
+ m_regs[REG_PCI0_MEM2_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_PCI0_MEM3_BASE] = 0x0100f600;
+ m_regs[REG_PCI0_MEM3_SIZE] = 0x000001ff;
+ m_regs[REG_PCI0_MEM3_REMAP_LOW] = 0x0000f600;
+ m_regs[REG_PCI0_MEM3_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_PCI1_IO_BASE] = 0x01002000;
+ m_regs[REG_PCI1_IO_SIZE] = 0x000001ff;
+ m_regs[REG_PCI1_IO_REMAP] = 0x00002000;
+ m_regs[REG_PCI1_MEM0_BASE] = 0x00002200;
+ m_regs[REG_PCI1_MEM0_SIZE] = 0x000001ff;
+ m_regs[REG_PCI1_MEM0_REMAP_LOW] = 0x00002200;
+ m_regs[REG_PCI1_MEM0_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_PCI1_MEM1_BASE] = 0x01002400;
+ m_regs[REG_PCI1_MEM1_SIZE] = 0x000001ff;
+ m_regs[REG_PCI1_MEM1_REMAP_LOW] = 0x00002400;
+ m_regs[REG_PCI1_MEM1_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_PCI1_MEM2_BASE] = 0x01002600;
+ m_regs[REG_PCI1_MEM2_SIZE] = 0x000001ff;
+ m_regs[REG_PCI1_MEM2_REMAP_LOW] = 0x00002600;
+ m_regs[REG_PCI1_MEM2_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_PCI1_MEM3_BASE] = 0x01002800;
+ m_regs[REG_PCI1_MEM3_SIZE] = 0x000001ff;
+ m_regs[REG_PCI1_MEM3_REMAP_LOW] = 0x00002800;
+ m_regs[REG_PCI1_MEM3_REMAP_HIGH] = 0x00000000;
+ m_regs[REG_BASE_ADDRESS_ENABLE] = 0x00000000;
+
+ // pegasos2 specific override (TODO: make generic)
+ m_regs[REG_INTERNAL_BASE] = 0x0100f100;
+ m_regs[REG_PCI1_IO_BASE] = 0x0100fe00;
+ m_regs[REG_PCI1_IO_SIZE] = 0x000000ff;
+ m_regs[REG_PCI1_IO_REMAP] = 0x00000000;
+ m_regs[REG_BASE_ADDRESS_ENABLE] = 0x00efbfff;
+
+ for (int i = 0; i < 21; i++)
+ m_ranges[i].enabled = false;
+
+ map_windows();
+}
+
+void mv64361_device::register_map(address_map &map)
+{
+ map(0x0000, 0x0003).rw(FUNC(mv64361_device::cpu_config_r), FUNC(mv64361_device::cpu_config_w));
+ map(0x0048, 0x004b).rw(FUNC(mv64361_device::pci0_io_base_r), FUNC(mv64361_device::pci0_io_base_w));
+ map(0x0050, 0x0053).rw(FUNC(mv64361_device::pci0_io_size_r), FUNC(mv64361_device::pci0_io_size_w));
+ map(0x0058, 0x005b).rw(FUNC(mv64361_device::pci0_mem0_base_r), FUNC(mv64361_device::pci0_mem0_base_w));
+ map(0x0060, 0x0063).rw(FUNC(mv64361_device::pci0_mem0_size_r), FUNC(mv64361_device::pci0_mem0_size_w));
+ map(0x0068, 0x006b).rw(FUNC(mv64361_device::internal_base_r), FUNC(mv64361_device::internal_base_w));
+ map(0x0080, 0x0083).rw(FUNC(mv64361_device::pci0_mem1_base_r), FUNC(mv64361_device::pci0_mem1_base_w));
+ map(0x0088, 0x008b).rw(FUNC(mv64361_device::pci0_mem1_size_r), FUNC(mv64361_device::pci0_mem1_size_w));
+ map(0x0090, 0x0093).rw(FUNC(mv64361_device::pci1_io_base_r), FUNC(mv64361_device::pci1_io_base_w));
+ map(0x0098, 0x009b).rw(FUNC(mv64361_device::pci1_io_size_r), FUNC(mv64361_device::pci1_io_size_w));
+ map(0x00a0, 0x00a3).rw(FUNC(mv64361_device::pci1_mem0_base_r), FUNC(mv64361_device::pci1_mem0_base_w));
+ map(0x00a8, 0x00ab).rw(FUNC(mv64361_device::pci1_mem0_size_r), FUNC(mv64361_device::pci1_mem0_size_w));
+ map(0x00b0, 0x00b3).rw(FUNC(mv64361_device::pci1_mem1_base_r), FUNC(mv64361_device::pci1_mem1_base_w));
+ map(0x00b8, 0x00bb).rw(FUNC(mv64361_device::pci1_mem1_size_r), FUNC(mv64361_device::pci1_mem1_size_w));
+ map(0x00f0, 0x00f3).rw(FUNC(mv64361_device::pci0_io_remap_r), FUNC(mv64361_device::pci0_io_remap_w));
+ map(0x00f8, 0x00fb).rw(FUNC(mv64361_device::pci0_mem0_remap_low_r), FUNC(mv64361_device::pci0_mem0_remap_low_w));
+ map(0x0100, 0x0103).rw(FUNC(mv64361_device::pci0_mem1_remap_low_r), FUNC(mv64361_device::pci0_mem1_remap_low_w));
+ map(0x0108, 0x010b).rw(FUNC(mv64361_device::pci1_io_remap_r), FUNC(mv64361_device::pci1_io_remap_w));
+ map(0x0110, 0x0113).rw(FUNC(mv64361_device::pci1_mem0_remap_low_r), FUNC(mv64361_device::pci1_mem0_remap_low_w));
+ map(0x0118, 0x011b).rw(FUNC(mv64361_device::pci1_mem1_remap_low_r), FUNC(mv64361_device::pci1_mem1_remap_low_w));
+ map(0x0238, 0x023b).rw(FUNC(mv64361_device::bootcs_base_r), FUNC(mv64361_device::bootcs_base_w));
+ map(0x0240, 0x0243).rw(FUNC(mv64361_device::bootcs_size_r), FUNC(mv64361_device::bootcs_size_w));
+ map(0x0258, 0x025b).rw(FUNC(mv64361_device::pci0_mem2_base_r), FUNC(mv64361_device::pci0_mem2_base_w));
+ map(0x0260, 0x0263).rw(FUNC(mv64361_device::pci0_mem2_size_r), FUNC(mv64361_device::pci0_mem2_size_w));
+ map(0x0268, 0x026b).rw(FUNC(mv64361_device::sram_base_r), FUNC(mv64361_device::sram_base_w));
+ map(0x0278, 0x027b).rw(FUNC(mv64361_device::base_address_enable_r), FUNC(mv64361_device::base_address_enable_w));
+ map(0x0280, 0x0283).rw(FUNC(mv64361_device::pci0_mem3_base_r), FUNC(mv64361_device::pci0_mem3_base_w));
+ map(0x0288, 0x028b).rw(FUNC(mv64361_device::pci0_mem3_size_r), FUNC(mv64361_device::pci0_mem3_size_w));
+ map(0x02a0, 0x02a3).rw(FUNC(mv64361_device::pci1_mem2_base_r), FUNC(mv64361_device::pci1_mem2_base_w));
+ map(0x02a8, 0x02ab).rw(FUNC(mv64361_device::pci1_mem2_size_r), FUNC(mv64361_device::pci1_mem2_size_w));
+ map(0x02b0, 0x02b3).rw(FUNC(mv64361_device::pci1_mem3_base_r), FUNC(mv64361_device::pci1_mem3_base_w));
+ map(0x02b8, 0x02bb).rw(FUNC(mv64361_device::pci1_mem3_size_r), FUNC(mv64361_device::pci1_mem3_size_w));
+ map(0x02f8, 0x02fb).rw(FUNC(mv64361_device::pci0_mem2_remap_low_r), FUNC(mv64361_device::pci0_mem2_remap_low_w));
+ map(0x0300, 0x0303).rw(FUNC(mv64361_device::pci0_mem3_remap_low_r), FUNC(mv64361_device::pci0_mem3_remap_low_w));
+ map(0x0310, 0x0313).rw(FUNC(mv64361_device::pci1_mem2_remap_low_r), FUNC(mv64361_device::pci1_mem2_remap_low_w));
+ map(0x0318, 0x031b).rw(FUNC(mv64361_device::pci1_mem3_remap_low_r), FUNC(mv64361_device::pci1_mem3_remap_low_w));
+ map(0x0320, 0x0323).rw(FUNC(mv64361_device::pci0_mem0_remap_high_r), FUNC(mv64361_device::pci0_mem0_remap_high_w));
+ map(0x0328, 0x032b).rw(FUNC(mv64361_device::pci0_mem1_remap_high_r), FUNC(mv64361_device::pci0_mem1_remap_high_w));
+ map(0x0330, 0x0333).rw(FUNC(mv64361_device::pci0_mem2_remap_high_r), FUNC(mv64361_device::pci0_mem2_remap_high_w));
+ map(0x0338, 0x033b).rw(FUNC(mv64361_device::pci0_mem3_remap_high_r), FUNC(mv64361_device::pci0_mem3_remap_high_w));
+ map(0x0340, 0x0343).rw(FUNC(mv64361_device::pci1_mem0_remap_high_r), FUNC(mv64361_device::pci1_mem0_remap_high_w));
+ map(0x0348, 0x034b).rw(FUNC(mv64361_device::pci1_mem1_remap_high_r), FUNC(mv64361_device::pci1_mem1_remap_high_w));
+ map(0x0350, 0x0353).rw(FUNC(mv64361_device::pci1_mem2_remap_high_r), FUNC(mv64361_device::pci1_mem2_remap_high_w));
+ map(0x0358, 0x035b).rw(FUNC(mv64361_device::pci1_mem3_remap_high_r), FUNC(mv64361_device::pci1_mem3_remap_high_w));
+
+ map(0x0c78, 0x0c7b).rw(m_pcihost[0], FUNC(mv64361_pci_host_device::config_address_r), FUNC(mv64361_pci_host_device::config_address_w));
+ map(0x0c7c, 0x0c7f).rw(m_pcihost[0], FUNC(mv64361_pci_host_device::config_data_r), FUNC(mv64361_pci_host_device::config_data_w));
+ map(0x0cf8, 0x0cfb).rw(m_pcihost[1], FUNC(mv64361_pci_host_device::config_address_r), FUNC(mv64361_pci_host_device::config_address_w));
+ map(0x0cfc, 0x0cff).rw(m_pcihost[1], FUNC(mv64361_pci_host_device::config_data_r), FUNC(mv64361_pci_host_device::config_data_w));
+}
+
+uint32_t mv64361_device::cpu_config_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "cpu_config_r\n");
+
+ return swapendian_int32(m_regs[REG_CPU_CONFIG]);
+}
+
+void mv64361_device::cpu_config_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "cpu_config_w: %08x\n", data);
+ m_regs[REG_CPU_CONFIG] = (data & 0xe4e3bff) | (1 << 23); // handle reserved bits
+}
+
+uint32_t mv64361_device::pci0_io_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_io_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_IO_BASE]);
+}
+
+void mv64361_device::pci0_io_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_io_base_w: %08x\n", data);
+ m_regs[REG_PCI0_IO_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI0_IO_REMAP] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci0_io_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_io_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_IO_SIZE]);
+}
+
+void mv64361_device::pci0_io_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_io_size_w: %08x\n", data);
+ m_regs[REG_PCI0_IO_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_mem0_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem0_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM0_BASE]);
+}
+
+void mv64361_device::pci0_mem0_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem0_base_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM0_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI0_MEM0_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci0_mem0_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem0_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM0_SIZE]);
+}
+
+void mv64361_device::pci0_mem0_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem0_size_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM0_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::internal_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "internal_base_r\n");
+
+ return swapendian_int32(m_regs[REG_INTERNAL_BASE]);
+}
+
+void mv64361_device::internal_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "internal_base_w: %08x\n", data);
+ m_regs[REG_INTERNAL_BASE] = data & 0x000fffff;
+}
+
+uint32_t mv64361_device::pci0_mem1_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem1_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM1_BASE]);
+}
+
+void mv64361_device::pci0_mem1_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem1_base_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM1_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI0_MEM1_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci0_mem1_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem1_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM1_SIZE]);
+}
+
+void mv64361_device::pci0_mem1_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem1_size_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM1_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_io_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_io_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_IO_BASE]);
+}
+
+void mv64361_device::pci1_io_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_io_base_w: %08x\n", data);
+ m_regs[REG_PCI1_IO_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI1_IO_REMAP] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci1_io_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_io_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_IO_SIZE]);
+}
+
+void mv64361_device::pci1_io_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_io_size_w: %08x\n", data);
+ m_regs[REG_PCI1_IO_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem0_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem0_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM0_BASE]);
+}
+
+void mv64361_device::pci1_mem0_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem0_base_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM0_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI1_MEM0_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci1_mem0_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem0_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM0_SIZE]);
+}
+
+void mv64361_device::pci1_mem0_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem0_size_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM0_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem1_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem1_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM1_BASE]);
+}
+
+void mv64361_device::pci1_mem1_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem1_base_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM1_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI1_MEM1_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci1_mem1_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem1_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM1_SIZE]);
+}
+
+void mv64361_device::pci1_mem1_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem1_size_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM1_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_io_remap_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_io_remap_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_IO_REMAP]);
+}
+
+void mv64361_device::pci0_io_remap_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_io_remap_w: %08x\n", data);
+ m_regs[REG_PCI0_IO_REMAP] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_mem0_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem0_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM0_REMAP_LOW]);
+}
+
+void mv64361_device::pci0_mem0_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem0_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM0_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_mem1_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem1_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM1_REMAP_LOW]);
+}
+
+void mv64361_device::pci0_mem1_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem1_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM1_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_io_remap_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_io_remap_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_IO_REMAP]);
+}
+
+void mv64361_device::pci1_io_remap_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_io_remap_w: %08x\n", data);
+ m_regs[REG_PCI1_IO_REMAP] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem0_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem0_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM0_REMAP_LOW]);
+}
+
+void mv64361_device::pci1_mem0_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem0_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM0_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem1_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem1_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM1_REMAP_LOW]);
+}
+
+void mv64361_device::pci1_mem1_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem1_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM1_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::bootcs_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "bootcs_base_r\n");
+
+ return swapendian_int32(m_regs[REG_BOOTCS_BASE]);
+}
+
+void mv64361_device::bootcs_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "bootcs_base_w: %08x\n", data);
+ m_regs[REG_BOOTCS_BASE] = data & 0x000fffff;
+}
+
+uint32_t mv64361_device::bootcs_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "bootcs_size_r\n");
+
+ return swapendian_int32(m_regs[REG_BOOTCS_SIZE]);
+}
+
+void mv64361_device::bootcs_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "bootcs_size_w: %08x\n", data);
+ m_regs[REG_BOOTCS_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_mem2_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem2_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM2_BASE]);
+}
+
+void mv64361_device::pci0_mem2_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem2_base_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM2_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI0_MEM2_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci0_mem2_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem2_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM2_SIZE]);
+}
+
+void mv64361_device::pci0_mem2_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem2_size_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM2_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::sram_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "sram_base_r\n");
+
+ return swapendian_int32(m_regs[REG_SRAM_BASE]);
+}
+
+void mv64361_device::sram_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "sram_base_w: %08x\n", data);
+ m_regs[REG_SRAM_BASE] = data & 0x000fffff;
+}
+
+uint32_t mv64361_device::base_address_enable_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "base_address_enable_r\n");
+
+ return swapendian_int32(m_regs[REG_BASE_ADDRESS_ENABLE]);
+}
+
+void mv64361_device::base_address_enable_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "base_address_enable_w: %08x\n", data);
+ m_regs[REG_BASE_ADDRESS_ENABLE] = data & 0x001fffff;
+
+ map_windows();
+}
+
+uint32_t mv64361_device::pci0_mem3_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem3_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM3_BASE]);
+}
+
+void mv64361_device::pci0_mem3_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem3_base_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM3_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI0_MEM3_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci0_mem3_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem3_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM3_SIZE]);
+}
+
+void mv64361_device::pci0_mem3_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem3_size_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM3_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem2_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem2_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM2_BASE]);
+}
+
+void mv64361_device::pci1_mem2_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem2_base_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM2_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI1_MEM2_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci1_mem2_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem2_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM2_SIZE]);
+}
+
+void mv64361_device::pci1_mem2_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem2_size_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM2_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem3_base_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem3_base_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM3_BASE]);
+}
+
+void mv64361_device::pci1_mem3_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem3_base_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM3_BASE] = data & 0x030fffff;
+
+ if (BIT(m_regs[REG_CPU_CONFIG], 27) == 0)
+ m_regs[REG_PCI1_MEM3_REMAP_LOW] = data & 0x0000fffff;
+}
+
+uint32_t mv64361_device::pci1_mem3_size_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem3_size_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM3_SIZE]);
+}
+
+void mv64361_device::pci1_mem3_size_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem3_size_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM3_SIZE] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_mem2_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem2_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM2_REMAP_LOW]);
+}
+
+void mv64361_device::pci0_mem2_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem2_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM2_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_mem3_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem3_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM3_REMAP_LOW]);
+}
+
+void mv64361_device::pci0_mem3_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem3_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM3_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem2_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem2_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM2_REMAP_LOW]);
+}
+
+void mv64361_device::pci1_mem2_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem2_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM2_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci1_mem3_remap_low_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem3_remap_low_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM3_REMAP_LOW]);
+}
+
+void mv64361_device::pci1_mem3_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem3_remap_low_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM3_REMAP_LOW] = data & 0x0000ffff;
+}
+
+uint32_t mv64361_device::pci0_mem0_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem0_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM0_REMAP_HIGH]);
+}
+
+void mv64361_device::pci0_mem0_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem0_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM0_REMAP_HIGH] = data;
+}
+
+uint32_t mv64361_device::pci0_mem1_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem1_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM1_REMAP_HIGH]);
+}
+
+void mv64361_device::pci0_mem1_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem1_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM1_REMAP_HIGH] = data;
+}
+
+uint32_t mv64361_device::pci0_mem2_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem2_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM2_REMAP_HIGH]);
+}
+
+void mv64361_device::pci0_mem2_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem2_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM2_REMAP_HIGH] = data;
+}
+
+uint32_t mv64361_device::pci0_mem3_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci0_mem3_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI0_MEM3_REMAP_HIGH]);
+}
+
+void mv64361_device::pci0_mem3_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci0_mem3_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI0_MEM3_REMAP_HIGH] = data;
+}
+
+uint32_t mv64361_device::pci1_mem0_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem0_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM0_REMAP_HIGH]);
+}
+
+void mv64361_device::pci1_mem0_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem0_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM0_REMAP_HIGH] = data;
+}
+
+uint32_t mv64361_device::pci1_mem1_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem1_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM1_REMAP_HIGH]);
+}
+
+void mv64361_device::pci1_mem1_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem1_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM1_REMAP_HIGH] = data;
+}
+
+uint32_t mv64361_device::pci1_mem2_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem2_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM2_REMAP_HIGH]);
+}
+
+void mv64361_device::pci1_mem2_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem2_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM2_REMAP_HIGH] = data;
+}
+
+uint32_t mv64361_device::pci1_mem3_remap_high_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_REG_READ, "pci1_mem3_remap_high_r\n");
+
+ return swapendian_int32(m_regs[REG_PCI1_MEM3_REMAP_HIGH]);
+}
+
+void mv64361_device::pci1_mem3_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ data = swapendian_int32(data);
+ LOGMASKED(LOG_REG_WRITE, "pci1_mem3_remap_high_w: %08x\n", data);
+ m_regs[REG_PCI1_MEM3_REMAP_HIGH] = data;
+}
+
+void mv64361_device::map_windows()
+{
+ for (int i = 0; i < 21; i++)
+ {
+ // unmap currently mapped ranges
+ if (m_ranges[i].enabled)
+ {
+ m_cpu_space->unmap_readwrite(m_ranges[i].start, m_ranges[i].end);
+ m_ranges[i].enabled = false;
+ }
+
+ if (BIT(m_regs[REG_BASE_ADDRESS_ENABLE], i) == 0)
+ {
+ m_ranges[i].enabled = true;
+
+ switch (i)
+ {
+ case 0: // CS0
+ m_ranges[0].enabled = false;
+ logerror("Mapping CS0\n");
+ break;
+
+ case 1: // CS1
+ m_ranges[1].enabled = false;
+ logerror("Mapping CS1\n");
+ break;
+
+ case 2: // CS2
+ m_ranges[2].enabled = false;
+ logerror("Mapping CS2\n");
+ break;
+
+ case 3: // CS3
+ m_ranges[3].enabled = false;
+ logerror("Mapping CS3\n");
+ break;
+
+ case 4: // DEVCS0
+ m_ranges[4].enabled = false;
+ logerror("Mapping DEVCS0\n");
+ break;
+
+ case 5: // DEVCS1
+ m_ranges[5].enabled = false;
+ logerror("Mapping DEVCS1\n");
+ break;
+
+ case 6: // DEVCS2
+ m_ranges[6].enabled = false;
+ logerror("Mapping DEVCS2\n");
+ break;
+
+ case 7: // DEVCS3
+ m_ranges[7].enabled = false;
+ logerror("Mapping DEVCS3\n");
+ break;
+
+ case 8: // BOOTCS
+ m_ranges[8].start = m_regs[REG_BOOTCS_BASE] << 16;
+ m_ranges[8].end = (m_regs[REG_BOOTCS_BASE] << 16) + ((m_regs[REG_BOOTCS_SIZE] << 16) | 0xffff);
+ m_ranges[8].enabled = false;
+ logerror("MAP %08x-%08x BOOTCS (not supported)\n", m_ranges[8].start , m_ranges[8].end);
+ break;
+
+ case 9: // PCI0 I/O
+ m_ranges[9].start = m_regs[REG_PCI0_IO_BASE] << 16;
+ m_ranges[9].end = (m_regs[REG_PCI0_IO_BASE] << 16) + ((m_regs[REG_PCI0_IO_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI0 I/O (remap: %04x)\n", m_ranges[9].start, m_ranges[9].end, m_regs[REG_PCI0_IO_REMAP]);
+ m_cpu_space->install_read_handler (m_ranges[9].start, m_ranges[9].end, read32s_delegate(*this, FUNC(mv64361_device::pci0_io_r)));
+ m_cpu_space->install_write_handler(m_ranges[9].start, m_ranges[9].end, write32s_delegate(*this, FUNC(mv64361_device::pci0_io_w)));
+ break;
+
+ case 10: // PCI0 MEM0
+ m_ranges[10].start = m_regs[REG_PCI0_MEM0_BASE] << 16;
+ m_ranges[10].end = (m_regs[REG_PCI0_MEM0_BASE] << 16) + ((m_regs[REG_PCI0_MEM0_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI0 MEM0 (remap: %08x %04x)\n", m_ranges[10].start, m_ranges[10].end, m_regs[REG_PCI0_MEM0_REMAP_HIGH], m_regs[REG_PCI0_MEM0_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[10].start, m_ranges[10].end, read32s_delegate(*this, FUNC(mv64361_device::pci0_mem0_r)));
+ m_cpu_space->install_write_handler(m_ranges[10].start, m_ranges[10].end, write32s_delegate(*this, FUNC(mv64361_device::pci0_mem0_w)));
+ break;
+
+ case 11: // PCI0 MEM1
+ m_ranges[11].start = m_regs[REG_PCI0_MEM1_BASE] << 16;
+ m_ranges[11].end = (m_regs[REG_PCI0_MEM1_BASE] << 16) + ((m_regs[REG_PCI0_MEM1_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI0 MEM1 (remap: %08x %04x)\n", m_ranges[11].start, m_ranges[11].end, m_regs[REG_PCI0_MEM1_REMAP_HIGH], m_regs[REG_PCI0_MEM1_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[11].start, m_ranges[11].end, read32s_delegate(*this, FUNC(mv64361_device::pci0_mem1_r)));
+ m_cpu_space->install_write_handler(m_ranges[11].start, m_ranges[11].end, write32s_delegate(*this, FUNC(mv64361_device::pci0_mem1_w)));
+ break;
+
+ case 12: // PCI0 MEM2
+ m_ranges[12].start = m_regs[REG_PCI0_MEM2_BASE] << 16;
+ m_ranges[12].end = (m_regs[REG_PCI0_MEM2_BASE] << 16) + ((m_regs[REG_PCI0_MEM2_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI0 MEM2 (remap: %08x %04x)\n", m_ranges[12].start, m_ranges[12].end, m_regs[REG_PCI0_MEM2_REMAP_HIGH], m_regs[REG_PCI0_MEM2_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[12].start, m_ranges[12].end, read32s_delegate(*this, FUNC(mv64361_device::pci0_mem2_r)));
+ m_cpu_space->install_write_handler(m_ranges[12].start, m_ranges[12].end, write32s_delegate(*this, FUNC(mv64361_device::pci0_mem2_w)));
+ break;
+
+ case 13: // PCI0 MEM3
+ m_ranges[13].start = m_regs[REG_PCI0_MEM3_BASE] << 16;
+ m_ranges[13].end = (m_regs[REG_PCI0_MEM3_BASE] << 16) + ((m_regs[REG_PCI0_MEM3_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI0 MEM3 (remap: %08x %04x)\n", m_ranges[13].start, m_ranges[13].end, m_regs[REG_PCI0_MEM3_REMAP_HIGH], m_regs[REG_PCI0_MEM3_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[13].start, m_ranges[13].end, read32s_delegate(*this, FUNC(mv64361_device::pci0_mem3_r)));
+ m_cpu_space->install_write_handler(m_ranges[13].start, m_ranges[13].end, write32s_delegate(*this, FUNC(mv64361_device::pci0_mem3_w)));
+ break;
+
+ case 14: // PCI1 I/O
+ m_ranges[14].start = m_regs[REG_PCI1_IO_BASE] << 16;
+ m_ranges[14].end = (m_regs[REG_PCI1_IO_BASE] << 16) + ((m_regs[REG_PCI1_IO_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI1 I/O (remap: %04x)\n", m_ranges[14].start, m_ranges[14].end, m_regs[REG_PCI1_IO_REMAP]);
+ m_cpu_space->install_read_handler (m_ranges[14].start, m_ranges[14].end, read32s_delegate(*this, FUNC(mv64361_device::pci1_io_r)));
+ m_cpu_space->install_write_handler(m_ranges[14].start, m_ranges[14].end, write32s_delegate(*this, FUNC(mv64361_device::pci1_io_w)));
+ break;
+
+ case 15: // PCI1 MEM0
+ m_ranges[15].start = m_regs[REG_PCI1_MEM0_BASE] << 16;
+ m_ranges[15].end = (m_regs[REG_PCI1_MEM0_BASE] << 16) + ((m_regs[REG_PCI1_MEM0_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI1 MEM0 (remap: %08x %04x)\n", m_ranges[15].start, m_ranges[15].end, m_regs[REG_PCI1_MEM0_REMAP_HIGH], m_regs[REG_PCI1_MEM0_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[15].start, m_ranges[15].end, read32s_delegate(*this, FUNC(mv64361_device::pci1_mem0_r)));
+ m_cpu_space->install_write_handler(m_ranges[15].start, m_ranges[15].end, write32s_delegate(*this, FUNC(mv64361_device::pci1_mem0_w)));
+ break;
+
+ case 16: // PCI1 MEM1
+ m_ranges[16].start = m_regs[REG_PCI1_MEM1_BASE] << 16;
+ m_ranges[16].end = (m_regs[REG_PCI1_MEM1_BASE] << 16) + ((m_regs[REG_PCI1_MEM1_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI1 MEM1 (remap: %08x %04x)\n", m_ranges[16].start, m_ranges[16].end, m_regs[REG_PCI1_MEM1_REMAP_HIGH], m_regs[REG_PCI1_MEM1_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[16].start, m_ranges[16].end, read32s_delegate(*this, FUNC(mv64361_device::pci1_mem1_r)));
+ m_cpu_space->install_write_handler(m_ranges[16].start, m_ranges[16].end, write32s_delegate(*this, FUNC(mv64361_device::pci1_mem1_w)));
+
+ break;
+
+ case 17: // PCI1 MEM2
+ m_ranges[17].start = m_regs[REG_PCI1_MEM2_BASE] << 16;
+ m_ranges[17].end = (m_regs[REG_PCI1_MEM2_BASE] << 16) + ((m_regs[REG_PCI1_MEM2_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI1 MEM2 (remap: %08x %04x)\n", m_ranges[17].start, m_ranges[17].end, m_regs[REG_PCI1_MEM2_REMAP_HIGH], m_regs[REG_PCI1_MEM2_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[17].start, m_ranges[17].end, read32s_delegate(*this, FUNC(mv64361_device::pci1_mem2_r)));
+ m_cpu_space->install_write_handler(m_ranges[17].start, m_ranges[17].end, write32s_delegate(*this, FUNC(mv64361_device::pci1_mem2_w)));
+ break;
+
+ case 18: // PCI1 MEM3
+ m_ranges[18].start = m_regs[REG_PCI1_MEM3_BASE] << 16;
+ m_ranges[18].end = (m_regs[REG_PCI1_MEM3_BASE] << 16) + ((m_regs[REG_PCI1_MEM3_SIZE] << 16) | 0xffff);
+ logerror("MAP %08x-%08x PCI1 MEM3 (remap: %08x %04x)\n", m_ranges[18].start, m_ranges[18].end, m_regs[REG_PCI1_MEM3_REMAP_HIGH], m_regs[REG_PCI1_MEM3_REMAP_LOW]);
+ m_cpu_space->install_read_handler (m_ranges[18].start, m_ranges[18].end, read32s_delegate(*this, FUNC(mv64361_device::pci1_mem3_r)));
+ m_cpu_space->install_write_handler(m_ranges[18].start, m_ranges[18].end, write32s_delegate(*this, FUNC(mv64361_device::pci1_mem3_w)));
+ break;
+
+ case 19: // SRAM
+ m_ranges[19].start = m_regs[REG_SRAM_BASE] << 16;
+ m_ranges[19].end = (m_regs[REG_SRAM_BASE] << 16) + 0x1fffff;
+ logerror("MAP %08x-%08x SRAM\n", m_ranges[19].start, m_ranges[19].end);
+ m_cpu_space->install_ram(m_ranges[19].start, m_ranges[19].end, m_sram.get());
+ break;
+
+ case 20: // INTERNAL
+ m_ranges[20].start = m_regs[REG_INTERNAL_BASE] << 16;
+ m_ranges[20].end = (m_regs[REG_INTERNAL_BASE] << 16) + 0xffff;
+ logerror("MAP %08x-%08x INTERNAL\n", m_ranges[20].start, m_ranges[20].end);
+ m_cpu_space->install_device(m_ranges[20].start, m_ranges[20].end, *static_cast<mv64361_device *>(this), &mv64361_device::register_map);
+ break;
+ }
+ }
+ }
+}
+
+uint32_t mv64361_device::remap_offset(offs_t offset, uint16_t size, uint16_t remap)
+{
+ uint32_t size_mask = (size << 16) | 0xffff;
+ return (offset & size_mask) | ((remap << 16) & ~size_mask);
+}
+
+uint32_t mv64361_device::pci0_io_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[0]->io_r(remap_offset(offset, m_regs[REG_PCI0_IO_SIZE], m_regs[REG_PCI0_IO_REMAP]), mem_mask);
+}
+
+void mv64361_device::pci0_io_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[0]->io_w(remap_offset(offset, m_regs[REG_PCI0_IO_SIZE], m_regs[REG_PCI0_IO_REMAP]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci0_mem0_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[0]->mem_r(remap_offset(offset, m_regs[REG_PCI0_MEM0_SIZE], m_regs[REG_PCI0_MEM0_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci0_mem0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[0]->mem_w(remap_offset(offset, m_regs[REG_PCI0_MEM0_SIZE], m_regs[REG_PCI0_MEM0_REMAP_LOW]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci0_mem1_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[0]->mem_r(remap_offset(offset, m_regs[REG_PCI0_MEM1_SIZE], m_regs[REG_PCI0_MEM1_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci0_mem1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[0]->mem_w(remap_offset(offset, m_regs[REG_PCI0_MEM0_SIZE], m_regs[REG_PCI0_MEM1_REMAP_LOW]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci0_mem2_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[0]->mem_r(remap_offset(offset, m_regs[REG_PCI0_MEM2_SIZE], m_regs[REG_PCI0_MEM2_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci0_mem2_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[0]->mem_w(remap_offset(offset, m_regs[REG_PCI0_MEM2_SIZE], m_regs[REG_PCI0_MEM2_REMAP_LOW]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci0_mem3_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[0]->mem_r(remap_offset(offset, m_regs[REG_PCI0_MEM3_SIZE], m_regs[REG_PCI0_MEM3_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci0_mem3_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[0]->mem_w(remap_offset(offset, m_regs[REG_PCI0_MEM3_SIZE], m_regs[REG_PCI0_MEM3_REMAP_LOW]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci1_io_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[1]->io_r(remap_offset(offset, m_regs[REG_PCI1_IO_SIZE], m_regs[REG_PCI1_IO_REMAP]), mem_mask);
+}
+
+void mv64361_device::pci1_io_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[1]->io_w(remap_offset(offset, m_regs[REG_PCI1_IO_SIZE], m_regs[REG_PCI1_IO_REMAP]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci1_mem0_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[1]->mem_r(remap_offset(offset, m_regs[REG_PCI1_MEM0_SIZE], m_regs[REG_PCI1_MEM0_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci1_mem0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[1]->mem_w(remap_offset(offset, m_regs[REG_PCI1_MEM0_SIZE], m_regs[REG_PCI1_MEM0_REMAP_LOW]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci1_mem1_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[1]->mem_r(remap_offset(offset, m_regs[REG_PCI1_MEM1_SIZE], m_regs[REG_PCI1_MEM1_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci1_mem1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[1]->mem_w(remap_offset(offset, m_regs[REG_PCI1_MEM0_SIZE], m_regs[REG_PCI1_MEM1_REMAP_LOW]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci1_mem2_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[1]->mem_r(remap_offset(offset, m_regs[REG_PCI1_MEM2_SIZE], m_regs[REG_PCI1_MEM2_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci1_mem2_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[1]->mem_w(remap_offset(offset, m_regs[REG_PCI1_MEM2_SIZE], m_regs[REG_PCI1_MEM2_REMAP_LOW]), data, mem_mask);
+}
+
+uint32_t mv64361_device::pci1_mem3_r(offs_t offset, uint32_t mem_mask)
+{
+ return m_pcihost[1]->mem_r(remap_offset(offset, m_regs[REG_PCI1_MEM3_SIZE], m_regs[REG_PCI1_MEM3_REMAP_LOW]), mem_mask);
+}
+
+void mv64361_device::pci1_mem3_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ m_pcihost[1]->mem_w(remap_offset(offset, m_regs[REG_PCI1_MEM3_SIZE], m_regs[REG_PCI1_MEM3_REMAP_LOW]), data, mem_mask);
+}
+
+
+//**************************************************************************
+// MV64361 PCI HOST
+//**************************************************************************
+
+mv64361_pci_host_device::mv64361_pci_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ pci_host_device(mconfig, MV64361_PCI_HOST, tag, owner, clock),
+ m_mem_config("memory_space", ENDIANNESS_LITTLE, 32, 32),
+ m_io_config("io_space", ENDIANNESS_LITTLE, 32, 32)
+{
+ set_ids_host(0x11ab6460, 0x01, 0x00000000);
+}
+
+void mv64361_pci_host_device::device_start()
+{
+ pci_host_device::device_start();
+
+ set_spaces(&space(AS_PCI_MEM), &space(AS_PCI_IO));
+
+ memory_window_start = 0;
+ memory_window_end = 0xffffffff;
+ memory_offset = 0;
+ io_window_start = 0;
+ io_window_end = 0xffffffff;
+ io_offset = 0;
+}
+
+void mv64361_pci_host_device::device_reset()
+{
+ pci_host_device::device_reset();
+}
+
+void mv64361_pci_host_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+}
+
+device_memory_interface::space_config_vector mv64361_pci_host_device::memory_space_config() const
+{
+ auto r = pci_bridge_device::memory_space_config();
+ r.emplace_back(std::make_pair(AS_PCI_MEM, &m_mem_config));
+ r.emplace_back(std::make_pair(AS_PCI_IO, &m_io_config));
+ return r;
+}
+
+uint32_t mv64361_pci_host_device::config_address_r(offs_t offset, uint32_t mem_mask)
+{
+ uint32_t data = pci_host_device::config_address_r();
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PCI_CONFIG, "config_address_r: %08x & %08x\n", swapendian_int32(data), swapendian_int32(mem_mask));
+
+ return swapendian_int32(data);
+}
+
+void mv64361_pci_host_device::config_address_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_PCI_CONFIG, "config_address_w: %08x & %08x\n", swapendian_int32(data), swapendian_int32(mem_mask));
+ pci_host_device::config_address_w(0, swapendian_int32(data), swapendian_int32(mem_mask));
+}
+
+uint32_t mv64361_pci_host_device::config_data_r(offs_t offset, uint32_t mem_mask)
+{
+ uint32_t data = pci_host_device::config_data_r(0, swapendian_int32(mem_mask));
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PCI_CONFIG, "config_data_r: %08x & %08x\n", swapendian_int32(data), swapendian_int32(mem_mask));
+
+ return swapendian_int32(data);
+}
+
+void mv64361_pci_host_device::config_data_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_PCI_CONFIG, "config_data_w: %08x & %08x\n", swapendian_int32(data), swapendian_int32(mem_mask));
+ pci_host_device::config_data_w(0, swapendian_int32(data), swapendian_int32(mem_mask));
+}
+
+uint32_t mv64361_pci_host_device::io_r(offs_t offset, uint32_t mem_mask)
+{
+ uint32_t data = space(AS_PCI_IO).read_dword(offset * 4, swapendian_int32(mem_mask));
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PCI_IO, "io_r[%08x]: %08x & %08x\n", offset * 4, swapendian_int32(data), swapendian_int32(mem_mask));
+
+ return swapendian_int32(data);
+}
+
+void mv64361_pci_host_device::io_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_PCI_IO, "io_w[%08x]: %08x & %08x\n", offset * 4, swapendian_int32(data), swapendian_int32(mem_mask));
+ space(AS_PCI_IO).write_dword(offset * 4, swapendian_int32(data), swapendian_int32(mem_mask));
+}
+
+uint32_t mv64361_pci_host_device::mem_r(offs_t offset, uint32_t mem_mask)
+{
+ uint32_t data = space(AS_PCI_MEM).read_dword(offset * 4, swapendian_int32(mem_mask));
+
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PCI_MEM, "mem_r[%08x]: %08x & %08x\n", offset * 4, swapendian_int32(data), swapendian_int32(mem_mask));
+
+ return swapendian_int32(data);
+}
+
+void mv64361_pci_host_device::mem_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_PCI_MEM, "mem_w[%08x]: %08x & %08x\n", offset * 4, swapendian_int32(data), swapendian_int32(mem_mask));
+ space(AS_PCI_MEM).write_dword(offset * 4, swapendian_int32(data), swapendian_int32(mem_mask));
+}
diff --git a/src/devices/machine/mv6436x.h b/src/devices/machine/mv6436x.h
new file mode 100644
index 00000000000..4d85912ecfe
--- /dev/null
+++ b/src/devices/machine/mv6436x.h
@@ -0,0 +1,282 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Marvell MV64360/1/2
+
+ System controller for PowerPC processors
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_MV6436X_H
+#define MAME_MACHINE_MV6436X_H
+
+#pragma once
+
+#include "cpu/powerpc/ppc.h"
+#include "pci.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// forward declaration
+class mv64361_pci_host_device;
+
+// ======================> mv64361_device
+
+class mv64361_device : public device_t
+{
+public:
+ // construction/destruction
+ template <typename T, typename U, typename V>
+ mv64361_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&pcihost0_tag, V &&pcihost1_tag):
+ mv64361_device(mconfig, tag, owner, clock)
+ {
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ set_pcihost_tag(0, std::forward<U>(pcihost0_tag));
+ set_pcihost_tag(1, std::forward<V>(pcihost1_tag));
+ }
+
+ mv64361_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T> void set_cpu_tag(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_pcihost_tag(int idx, T &&tag) { m_pcihost[idx].set_tag(std::forward<T>(tag)); }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ void register_map(address_map &map);
+
+ // internal register cpu interface
+ uint32_t cpu_config_r(offs_t offset, uint32_t mem_mask);
+ void cpu_config_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_io_base_r(offs_t offset, uint32_t mem_mask);
+ void pci0_io_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_io_size_r(offs_t offset, uint32_t mem_mask);
+ void pci0_io_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem0_base_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem0_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem0_size_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem0_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t internal_base_r(offs_t offset, uint32_t mem_mask);
+ void internal_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem1_base_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem1_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem1_size_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem1_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_io_base_r(offs_t offset, uint32_t mem_mask);
+ void pci1_io_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_io_size_r(offs_t offset, uint32_t mem_mask);
+ void pci1_io_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem0_base_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem0_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem0_size_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem0_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem1_base_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem1_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem1_size_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem1_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_io_remap_r(offs_t offset, uint32_t mem_mask);
+ void pci0_io_remap_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem0_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem0_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem1_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem1_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_io_remap_r(offs_t offset, uint32_t mem_mask);
+ void pci1_io_remap_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem0_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem0_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem1_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem1_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t bootcs_base_r(offs_t offset, uint32_t mem_mask);
+ void bootcs_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t bootcs_size_r(offs_t offset, uint32_t mem_mask);
+ void bootcs_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem2_base_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem2_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem2_size_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem2_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t sram_base_r(offs_t offset, uint32_t mem_mask);
+ void sram_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t base_address_enable_r(offs_t offset, uint32_t mem_mask);
+ void base_address_enable_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem3_base_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem3_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem3_size_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem3_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem2_base_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem2_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem2_size_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem2_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem3_base_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem3_base_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem3_size_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem3_size_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem2_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem2_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem3_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem3_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem2_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem2_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem3_remap_low_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem3_remap_low_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem0_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem0_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem1_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem1_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem2_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem2_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem3_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem3_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem0_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem0_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem1_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem1_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem2_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem2_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem3_remap_high_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem3_remap_high_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ void map_windows();
+
+ uint32_t remap_offset(offs_t offset, uint16_t size, uint16_t remap);
+
+ // pci windows installed into cpu memory space
+ uint32_t pci0_io_r(offs_t offset, uint32_t mem_mask);
+ void pci0_io_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem0_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem0_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem1_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem1_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem2_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem2_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci0_mem3_r(offs_t offset, uint32_t mem_mask);
+ void pci0_mem3_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_io_r(offs_t offset, uint32_t mem_mask);
+ void pci1_io_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem0_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem0_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem1_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem1_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem2_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem2_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ uint32_t pci1_mem3_r(offs_t offset, uint32_t mem_mask);
+ void pci1_mem3_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ required_device<ppc_device> m_cpu;
+ required_device_array<mv64361_pci_host_device, 2> m_pcihost;
+
+ address_space *m_cpu_space;
+
+ // internal registers
+ enum
+ {
+ REG_CPU_CONFIG = 0,
+ REG_PCI0_IO_BASE,
+ REG_PCI0_IO_SIZE,
+ REG_PCI0_IO_REMAP,
+ REG_PCI0_MEM0_BASE,
+ REG_PCI0_MEM0_SIZE,
+ REG_PCI0_MEM0_REMAP_LOW,
+ REG_PCI0_MEM0_REMAP_HIGH,
+ REG_PCI0_MEM1_BASE,
+ REG_PCI0_MEM1_SIZE,
+ REG_PCI0_MEM1_REMAP_LOW,
+ REG_PCI0_MEM1_REMAP_HIGH,
+ REG_PCI0_MEM2_BASE,
+ REG_PCI0_MEM2_SIZE,
+ REG_PCI0_MEM2_REMAP_LOW,
+ REG_PCI0_MEM2_REMAP_HIGH,
+ REG_PCI0_MEM3_BASE,
+ REG_PCI0_MEM3_SIZE,
+ REG_PCI0_MEM3_REMAP_LOW,
+ REG_PCI0_MEM3_REMAP_HIGH,
+ REG_PCI1_IO_BASE,
+ REG_PCI1_IO_SIZE,
+ REG_PCI1_IO_REMAP,
+ REG_PCI1_MEM0_BASE,
+ REG_PCI1_MEM0_SIZE,
+ REG_PCI1_MEM0_REMAP_LOW,
+ REG_PCI1_MEM0_REMAP_HIGH,
+ REG_PCI1_MEM1_BASE,
+ REG_PCI1_MEM1_SIZE,
+ REG_PCI1_MEM1_REMAP_LOW,
+ REG_PCI1_MEM1_REMAP_HIGH,
+ REG_PCI1_MEM2_BASE,
+ REG_PCI1_MEM2_SIZE,
+ REG_PCI1_MEM2_REMAP_LOW,
+ REG_PCI1_MEM2_REMAP_HIGH,
+ REG_PCI1_MEM3_BASE,
+ REG_PCI1_MEM3_SIZE,
+ REG_PCI1_MEM3_REMAP_LOW,
+ REG_PCI1_MEM3_REMAP_HIGH,
+ REG_INTERNAL_BASE,
+ REG_BOOTCS_BASE,
+ REG_BOOTCS_SIZE,
+ REG_SRAM_BASE,
+ REG_BASE_ADDRESS_ENABLE
+ };
+
+ uint32_t m_regs[REG_BASE_ADDRESS_ENABLE + 1];
+
+ std::unique_ptr<uint8_t[]> m_sram;
+
+ // helper to keep track of what we installed into cpu space
+ struct decode_range
+ {
+ uint32_t start;
+ uint32_t end;
+ bool enabled;
+ };
+
+ decode_range m_ranges[21];
+};
+
+// ======================> mv64361_pci_host_device
+
+class mv64361_pci_host_device : public pci_host_device
+{
+public:
+ // construction/destruction
+ mv64361_pci_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ uint32_t config_address_r(offs_t offset, uint32_t mem_mask = ~0);
+ void config_address_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint32_t config_data_r(offs_t offset, uint32_t mem_mask = ~0);
+ void config_data_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+
+ uint32_t io_r(offs_t offset, uint32_t mem_mask);
+ void io_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t mem_r(offs_t offset, uint32_t mem_mask);
+ void mem_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ enum
+ {
+ AS_PCI_MEM = 1,
+ AS_PCI_IO = 2
+ };
+
+ address_space_config m_mem_config;
+ address_space_config m_io_config;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(MV64361, mv64361_device)
+DECLARE_DEVICE_TYPE(MV64361_PCI_HOST, mv64361_pci_host_device)
+
+#endif // MAME_MACHINE_MV6436X_H
diff --git a/src/devices/machine/mv_sonora.cpp b/src/devices/machine/mv_sonora.cpp
new file mode 100644
index 00000000000..f51007d9e64
--- /dev/null
+++ b/src/devices/machine/mv_sonora.cpp
@@ -0,0 +1,343 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Mac video support, "Sonora" edition
+ Supports 5 different modelines at up to 16bpp
+
+*********************************************************************/
+
+#include "emu.h"
+#include "mv_sonora.h"
+
+DEFINE_DEVICE_TYPE(MAC_VIDEO_SONORA, mac_video_sonora_device, "mv_sonora", "Mac Sonora video support")
+
+const mac_video_sonora_device::modeline mac_video_sonora_device::modelines[5] = {
+ { 0x02, "512x384 12\" RGB", 15667200, 640, 16, 32, 80, 407, 1, 3, 19, true },
+ { 0x06, "640x480 13\" RGB", 31334400, 896, 80, 64, 112, 525, 3, 3, 39, true },
+ { 0x01, "640x870 15\" Portrait", 57283200, 832, 32, 80, 80, 918, 3, 3, 42, false },
+ { 0x09, "832x624 16\" RGB", 57283200, 1152, 32, 64, 224, 667, 1, 3, 39, false },
+ { 0x0b, "640x480 VGA", 25175000, 800, 16, 96, 48, 525, 10, 2, 33, false },
+};
+
+mac_video_sonora_device::mac_video_sonora_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MAC_VIDEO_SONORA, tag, owner, clock),
+ m_screen(*this, "screen"),
+ m_palette(*this, "palette"),
+ m_monitor_config(*this, "monitor"),
+ m_screen_vblank(*this),
+ m_is32bit(false)
+{
+}
+
+void mac_video_sonora_device::device_start()
+{
+ m_vram = nullptr;
+
+ save_item(NAME(m_vram_offset));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_depth));
+ save_item(NAME(m_monitor_id));
+ save_item(NAME(m_vtest));
+ save_item(NAME(m_modeline_id));
+}
+
+void mac_video_sonora_device::device_reset()
+{
+ m_modeline_id = -1;
+ m_mode = 0x9f;
+ m_depth = 0;
+ m_monitor_id = 8;
+ m_vtest = 0;
+ m_vram_offset = 0;
+}
+
+void mac_video_sonora_device::device_add_mconfig(machine_config &config)
+{
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ // dot clock, htotal, hstart, hend, vtotal, vstart, vend
+ m_screen->set_raw(31334400, 896, 0, 640, 525, 0, 480);
+ m_screen->set_screen_update(FUNC(mac_video_sonora_device::screen_update));
+ m_screen->screen_vblank().set([this](int state) { m_screen_vblank(state && (m_modeline_id != -1)); });
+
+ PALETTE(config, m_palette).set_entries(256);
+}
+
+// The monitor detection goes through 3 sense lines which are
+// pulled-up but can be set to 0 or 1 by the system.
+
+// The monitor itself either connects some lines to ground (old
+// method) or connects some lines together, sometimes with a diode
+// (extended monitor sense).
+
+// The system starts by leaving everything undriven and reading the
+// result. If it's not 7, it's the monitor type. If it's 7, then it
+// needs the extended monitor sense. It then drives a 0 on each of
+// the 3 pins in sequence and records the result on the other two, and
+// that gives the signature.
+
+static constexpr uint8_t ext(uint8_t bc, uint8_t ac, uint8_t ab)
+{
+ return 0x40 | (bc << 4) | (ac << 2) | ab;
+}
+
+static INPUT_PORTS_START(monitor_config)
+ PORT_START("monitor")
+ PORT_CONFNAME(0x7f, 6, "Monitor type")
+ PORT_CONFSETTING(2, "512x384 12\" RGB")
+ PORT_CONFSETTING(6, "640x480 13\" RGB") // Biggest resolution with 16bpp support, hence default
+ PORT_CONFSETTING(1, "620x870 15\" Portrait")
+ PORT_CONFSETTING(ext(2, 3, 1), "832x624 16\" RGB")
+ PORT_CONFSETTING(ext(1, 1, 3), "640x480 VGA")
+INPUT_PORTS_END
+
+
+ioport_constructor mac_video_sonora_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(monitor_config);
+}
+
+uint32_t mac_video_sonora_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ if((m_mode & 0x80) || m_modeline_id == -1 || m_depth > 4 || (m_depth == 4 && !modelines[m_modeline_id].supports_16bpp) || !m_vram) {
+ bitmap.fill(0);
+ return 0;
+ }
+
+ const auto &m = modelines[m_modeline_id];
+ uint32_t hres = m.htot - m.hfp - m.hs - m.hbp;
+ uint32_t vres = m.vtot - m.vfp - m.vs - m.vbp;
+
+ const pen_t *pens = m_palette->pens();
+
+ if (m_is32bit) {
+ const uint32_t *vram = (uint32_t *)(m_vram + (m_vram_offset / 8));
+ switch (m_depth)
+ {
+ case 0: // 1bpp
+ for (uint32_t y = 0; y != vres; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (uint32_t x = 0; x != hres; x += 32)
+ {
+ uint32_t pixels = *vram++;
+ for (int32_t bit = 31; bit >= 0; bit--)
+ *scanline++ = pens[(((pixels >> bit) & 1) << 7) | 0x7f];
+ }
+ }
+ break;
+
+ case 1: // 2bpp
+ for (uint32_t y = 0; y != vres; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (uint32_t x = 0; x != hres; x += 16)
+ {
+ uint32_t pixels = *vram++;
+ for (int32_t bit = 30; bit >= 0; bit -= 2)
+ *scanline++ = pens[(((pixels >> bit) & 0x3)<<6) | 0x3f];
+ }
+ }
+ break;
+
+ case 2: // 4bpp
+ for (uint32_t y = 0; y != vres; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (uint32_t x = 0; x != hres; x += 8)
+ {
+ uint32_t pixels = *vram++;
+ for (int32_t bit = 28; bit >= 0; bit -= 4)
+ *scanline++ = pens[(((pixels >> bit) & 0x0f)<<4) | 0x0f];
+ }
+ }
+ break;
+
+ case 3: // 8bpp
+ for (uint32_t y = 0; y != vres; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (uint32_t x = 0; x != hres; x += 4)
+ {
+ uint32_t pixels = *vram++;
+ for (int32_t bit = 24; bit >= 0; bit -= 8)
+ *scanline++ = pens[((pixels >> bit) & 0xff)];
+ }
+ }
+ break;
+
+ case 4: // 16bpp
+ for (uint32_t y = 0; y != vres; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (uint32_t x = 0; x != hres; x += 2)
+ {
+ const uint32_t pixels = *vram++;
+ *scanline++ = rgb_t(((pixels >> 26) & 0x1f) << 3, ((pixels >> 21) & 0x1f) << 3, ((pixels >> 16) & 0x1f) << 3);
+ *scanline++ = rgb_t(((pixels >> 10) & 0x1f) << 3, ((pixels >> 5) & 0x1f) << 3, (pixels & 0x1f) << 3);
+ }
+ }
+ break;
+
+ default:
+ bitmap.fill(0xff0000);
+ break;
+ }
+ } else {
+ const uint64_t *vram = m_vram + (m_vram_offset / 8);
+ switch(m_depth) {
+ case 0: // 1bpp
+ for(uint32_t y = 0; y != vres; y++) {
+ uint32_t *scanline = &bitmap.pix(y);
+ for(uint32_t x = 0; x != hres; x += 64) {
+ uint64_t pixels = *vram ++;
+ for(int32_t bit = 63; bit >= 0; bit --)
+ *scanline ++ = pens[(((pixels >> bit) & 1) << 7) | 0x7f];
+ }
+ }
+ break;
+
+ case 3: // 8bpp
+ for(uint32_t y = 0; y != vres; y++) {
+ uint32_t *scanline = &bitmap.pix(y);
+ for(uint32_t x = 0; x != hres; x += 8) {
+ uint64_t pixels = *vram ++;
+ for(int32_t bit = 56; bit >= 0; bit -= 8)
+ *scanline ++ = pens[((pixels >> bit) & 0xff)];
+ }
+ }
+ break;
+
+ default:
+ bitmap.fill(0xff0000);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+uint8_t mac_video_sonora_device::vctrl_r(offs_t offset)
+{
+ switch(offset) {
+ case 0: return m_mode;
+ case 1: return m_depth;
+
+ case 2: {
+ uint8_t mon = m_monitor_config->read();
+ uint8_t res;
+ if(mon & 0x40) {
+ res = 7;
+ if(!(m_monitor_id & 0xc))
+ res &= 4 | (BIT(mon, 5) << 1) | BIT(mon, 4);
+ if(!(m_monitor_id & 0xa))
+ res &= (BIT(mon, 3) << 2) | 2 | BIT(mon, 2);
+ if(!(m_monitor_id & 0x9))
+ res &= (BIT(mon, 1) << 2) | (BIT(mon, 0) << 1) | 1;
+
+ } else {
+ res = mon;
+ if(!(m_monitor_id & 8))
+ res &= m_monitor_id & 7;
+ }
+
+ return m_monitor_id | (res << 4);
+ }
+
+ case 3: return m_vtest;
+ case 4: return (m_screen->hpos() >> 8) & 7;
+ case 5: return m_screen->hpos() & 0xff;
+ case 6: return (m_screen->vpos() >> 8) & 3;
+ case 7: return m_screen->vpos() & 0xff;
+ }
+
+ return 0;
+}
+
+void mac_video_sonora_device::vctrl_w(offs_t offset, uint8_t data)
+{
+ switch(offset) {
+ case 0: {
+ int prev_modeline = m_modeline_id;
+ m_mode = data & 0x9f;
+ m_modeline_id = -1;
+ for(unsigned i=0; i != std::size(modelines) && m_modeline_id == -1; i++)
+ if((m_mode & 0x1f) == modelines[i].mode_id)
+ m_modeline_id = i;
+
+ logerror("Mode switch %02x %s%s\n", data,
+ m_mode & 0x80 ? "blanked " : "",
+ m_modeline_id == -1 ? "disabled" : modelines[m_modeline_id].name);
+
+ if(m_modeline_id != -1 && m_modeline_id != prev_modeline) {
+ const modeline &m = modelines[m_modeline_id];
+ rectangle visarea(0, m.htot - m.hfp - m.hs - m.hbp - 1, 0, m.vtot - m.vfp - m.vs - m.vbp - 1);
+ m_screen->configure(m.htot, m.vtot, visarea, attotime::from_ticks(m.htot*m.vtot, m.dotclock).as_attoseconds());
+ }
+ break;
+ }
+
+ case 1:
+ m_depth = data & 7;
+ if(m_depth <= 4)
+ logerror("Pixel depth %dbpp\n", 1 << m_depth);
+ else
+ logerror("Pixel depth invalid (%d)\n", m_depth);
+ break;
+
+ case 2:
+ m_monitor_id = data & 0xf;
+ break;
+
+ case 3:
+ m_vtest = data & 1;
+ break;
+
+ default:
+ logerror("vctrl_w %x, %02x\n", offset, data);
+ }
+}
+
+uint8_t mac_video_sonora_device::dac_r(offs_t offset)
+{
+ switch(offset) {
+ case 2:
+ return m_pal_control;
+
+ default:
+ logerror("dac_r %x\n", offset);
+ return 0;
+ }
+}
+
+void mac_video_sonora_device::dac_w(offs_t offset, uint8_t data)
+{
+ switch(offset) {
+ case 0:
+ m_pal_address = data;
+ m_pal_idx = 0;
+ break;
+
+ case 1:
+ switch(m_pal_idx) {
+ case 0: m_palette->set_pen_red_level(m_pal_address, data); break;
+ case 1: m_palette->set_pen_green_level(m_pal_address, data); break;
+ case 2: m_palette->set_pen_blue_level(m_pal_address, data); break;
+ }
+ m_pal_idx ++;
+ if(m_pal_idx == 3) {
+ m_pal_idx = 0;
+ m_pal_address ++;
+ }
+ break;
+
+ case 2:
+ logerror("control = %02x\n", data);
+ m_pal_control = data;
+ break;
+
+ case 3:
+ m_pal_colkey = data;
+ break;
+ }
+}
diff --git a/src/devices/machine/mv_sonora.h b/src/devices/machine/mv_sonora.h
new file mode 100644
index 00000000000..127cd921edc
--- /dev/null
+++ b/src/devices/machine/mv_sonora.h
@@ -0,0 +1,72 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/*********************************************************************
+
+ Mac video support, "Sonora" edition
+ Supports 5 different modelines at up to 16bpp
+
+*********************************************************************/
+#ifndef MAME_MACHINE_MAC_VIDEO_SONORA_H
+#define MAME_MACHINE_MAC_VIDEO_SONORA_H
+
+#pragma once
+
+#include "emupal.h"
+#include "screen.h"
+
+class mac_video_sonora_device : public device_t
+{
+public:
+ mac_video_sonora_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ virtual ~mac_video_sonora_device() = default;
+
+ uint8_t vctrl_r(offs_t offset);
+ void vctrl_w(offs_t offset, uint8_t data);
+ uint8_t dac_r(offs_t offset);
+ void dac_w(offs_t offset, uint8_t data);
+
+ int vblank() const { return m_screen->vblank(); }
+ int hblank() const { return m_screen->hblank(); }
+
+ auto screen_vblank() { return m_screen_vblank.bind(); }
+
+ void set_vram_base(const uint64_t *vram) { m_vram = vram; }
+ void set_vram_offset(uint32_t offset) { m_vram_offset = offset; }
+ void set_32bit() { m_is32bit = true; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+
+private:
+ struct modeline {
+ uint8_t mode_id;
+ const char *name;
+ uint32_t dotclock;
+ uint32_t htot, hfp, hs, hbp;
+ uint32_t vtot, vfp, vs, vbp;
+ bool supports_16bpp;
+ };
+
+ static const modeline modelines[5];
+
+ required_device<screen_device> m_screen;
+ required_device<palette_device> m_palette;
+ required_ioport m_monitor_config;
+ devcb_write_line m_screen_vblank;
+
+ const uint64_t *m_vram;
+ uint32_t m_vram_offset;
+ uint8_t m_mode, m_depth, m_monitor_id, m_vtest;
+ uint8_t m_pal_address, m_pal_idx, m_pal_control, m_pal_colkey;
+ int m_modeline_id;
+ bool m_is32bit;
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+};
+
+DECLARE_DEVICE_TYPE(MAC_VIDEO_SONORA, mac_video_sonora_device)
+
+#endif /* MAME_MACHINE_MAC_VIDEO_SONORA_H */
diff --git a/src/devices/machine/myb3k_kbd.cpp b/src/devices/machine/myb3k_kbd.cpp
index 83ee8553373..0eb63868aff 100644
--- a/src/devices/machine/myb3k_kbd.cpp
+++ b/src/devices/machine/myb3k_kbd.cpp
@@ -124,7 +124,6 @@
#include "emu.h"
#include "myb3k_kbd.h"
-//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already
#define LOG_MOD (1U << 1)
#define LOG_BYTES (1U << 2)
@@ -355,20 +354,22 @@ ioport_constructor myb3k_keyboard_device::device_input_ports() const
void myb3k_keyboard_device::device_start()
{
- m_keyboard_cb.resolve();
+ m_keyboard_cb.resolve_safe();
+ m_scan_timer = timer_alloc(FUNC(myb3k_keyboard_device::scan_keys), this);
+ m_first_byte_timer = timer_alloc(FUNC(myb3k_keyboard_device::send_first_byte), this);
+ m_second_byte_timer = timer_alloc(FUNC(myb3k_keyboard_device::send_second_byte), this);
}
void myb3k_keyboard_device::device_reset()
{
m_modifier_keys = 0;
memset(m_io_kbd_state, 0, sizeof(m_io_kbd_state));
- timer_set(attotime::from_msec(100), TIMER_ID_SCAN_KEYS);
+ m_scan_timer->adjust(attotime::from_msec(100));
m_modifier_keys = 0;
}
void myb3k_keyboard_device::send_byte(u8 code)
{
- assert(!m_keyboard_cb.isnull());
m_keyboard_cb(code);
}
@@ -391,7 +392,7 @@ void myb3k_keyboard_device::key_changed(int x, int y, bool pressed)
(y & 0x7);
}
-void myb3k_keyboard_device::scan_keys()
+TIMER_CALLBACK_MEMBER(myb3k_keyboard_device::scan_keys)
{
// Iterate over all columns (m_x)
// and for each column iterate over all rows (m_y)
@@ -408,7 +409,7 @@ void myb3k_keyboard_device::scan_keys()
update_modifiers(m_y, bit);
}
- timer_set(attotime::from_msec(3), TIMER_ID_FIRST_BYTE);
+ m_first_byte_timer->adjust(attotime::from_msec(3));
wait_for_timer = true;
}
@@ -420,7 +421,7 @@ void myb3k_keyboard_device::scan_keys()
m_y = 0;
// Done scanning the matrix. Now sleep for a while,
// then start scanning again. Scan ~50 times per second.
- timer_set(attotime::from_msec(20), TIMER_ID_SCAN_KEYS);
+ m_scan_timer->adjust(attotime::from_msec(20));
wait_for_timer = true;
// (The final switch x=11 y=7 is not electrically connected.
// Thus if we get here, then there can be no key changed
@@ -456,31 +457,24 @@ void myb3k_keyboard_device::update_modifiers(int y, bool down)
m_modifier_keys = (m_modifier_keys & mask) | (down?bit:0);
}
-void myb3k_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(myb3k_keyboard_device::send_first_byte)
{
- switch (id)
- {
- case TIMER_ID_SCAN_KEYS:
- scan_keys();
- break;
+ LOGBYTES("FIRST_BYTE %02x %s (with modifiers %s%s%s%s%s)\n", m_first_byte,
+ (m_first_byte&MYB3K_KEY_ON)?"Pressed":"Released",
+ (m_first_byte&MYB3K_KEY_CTRL)?"CTRL ":"",
+ (m_first_byte&MYB3K_KEY_GRAPH)?"GRAPH ":"",
+ (m_first_byte&MYB3K_KEY_LSHIFT)?"LSHIFT ":"",
+ (m_first_byte&MYB3K_KEY_RSHIFT)?"RSHIFT ":"",
+ (m_first_byte&MYB3K_KEY_CAP)?"CAP ":"");
+ send_byte(m_first_byte);
+ m_second_byte_timer->adjust(attotime::from_msec(3));
+}
- case TIMER_ID_FIRST_BYTE:
- LOGBYTES("FIRST_BYTE %02x %s (with modifiers %s%s%s%s%s)\n", m_first_byte,
- (m_first_byte&MYB3K_KEY_ON)?"Pressed":"Released",
- (m_first_byte&MYB3K_KEY_CTRL)?"CTRL ":"",
- (m_first_byte&MYB3K_KEY_GRAPH)?"GRAPH ":"",
- (m_first_byte&MYB3K_KEY_LSHIFT)?"LSHIFT ":"",
- (m_first_byte&MYB3K_KEY_RSHIFT)?"RSHIFT ":"",
- (m_first_byte&MYB3K_KEY_CAP)?"CAP ":"");
- send_byte(m_first_byte);
- timer_set(attotime::from_msec(3), TIMER_ID_SECOND_BYTE);
- break;
- case TIMER_ID_SECOND_BYTE:
- LOGBYTES("SECOND_BYTE %02x x=%d y=%d \n\n\n", m_second_byte, (m_second_byte >> 3)&0xf, (m_second_byte)&0x7);
- send_byte(m_second_byte);
- timer_set(attotime::from_msec(10), TIMER_ID_SCAN_KEYS);
- break;
- }
+TIMER_CALLBACK_MEMBER(myb3k_keyboard_device::send_second_byte)
+{
+ LOGBYTES("SECOND_BYTE %02x x=%d y=%d \n\n\n", m_second_byte, (m_second_byte >> 3)&0xf, (m_second_byte)&0x7);
+ send_byte(m_second_byte);
+ m_scan_timer->adjust(attotime::from_msec(10));
}
stepone_keyboard_device::stepone_keyboard_device(
diff --git a/src/devices/machine/myb3k_kbd.h b/src/devices/machine/myb3k_kbd.h
index 384d837bf20..fa8f6570640 100644
--- a/src/devices/machine/myb3k_kbd.h
+++ b/src/devices/machine/myb3k_kbd.h
@@ -36,13 +36,6 @@ public:
device_t *owner,
u32 clock);
- enum
- {
- TIMER_ID_SCAN_KEYS,
- TIMER_ID_FIRST_BYTE,
- TIMER_ID_SECOND_BYTE
- };
-
template <typename... T>
void set_keyboard_callback(T &&... args)
{
@@ -61,15 +54,21 @@ protected:
virtual void device_reset() override;
virtual void send_byte(u8 code);
void key_changed(int x, int y, bool down);
- void scan_keys();
void update_modifiers(int y, bool down);
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(scan_keys);
+ TIMER_CALLBACK_MEMBER(send_first_byte);
+ TIMER_CALLBACK_MEMBER(send_second_byte);
output_delegate m_keyboard_cb;
required_ioport_array<12> m_io_kbd_t;
u8 m_io_kbd_state[12][8];
- int m_x, m_y;
+ emu_timer *m_scan_timer;
+ emu_timer *m_first_byte_timer;
+ emu_timer *m_second_byte_timer;
+ int m_x;
+ int m_y;
u8 m_first_byte;
u8 m_second_byte;
u8 m_modifier_keys;
diff --git a/src/devices/machine/nandflash.cpp b/src/devices/machine/nandflash.cpp
new file mode 100644
index 00000000000..fa7060d01c2
--- /dev/null
+++ b/src/devices/machine/nandflash.cpp
@@ -0,0 +1,637 @@
+// license:BSD-3-Clause
+// copyright-holders:Raphael Nabet
+/*
+ NAND flash emulation
+
+ 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)
+
+ Raphael Nabet 2004
+*/
+
+#include "emu.h"
+#include "nandflash.h"
+
+#include "formats/imageutl.h"
+
+ALLOW_SAVE_TYPE(nand_device::sm_mode_t)
+ALLOW_SAVE_TYPE(nand_device::pointer_sm_mode_t)
+
+DEFINE_DEVICE_TYPE(NAND, nand_device, "nand", "NAND Flash Memory")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9F5608U0D, samsung_k9f5608u0d_device, "samsung_k9f5608u0d", "Samsung K9F5608U0D")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9F5608U0DJ, samsung_k9f5608u0dj_device, "samsung_k9f5608u0dj", "Samsung K9F5608U0D-J")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9F5608U0B, samsung_k9f5608u0b_device, "samsung_k9f5608u0b", "Samsung K9F5608U0B")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9F2808U0B, samsung_k9f2808u0b_device, "samsung_k9f2808u0b", "Samsung K9F2808U0B")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9F1G08U0B, samsung_k9f1g08u0b_device, "samsung_k9f1g08u0b", "Samsung K9F1G08U0B")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9F1G08U0M, samsung_k9f1g08u0m_device, "samsung_k9f1g08u0m", "Samsung K9F1G08U0M")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9LAG08U0M, samsung_k9lag08u0m_device, "samsung_k9lag08u0m", "Samsung K9LAG08U0M")
+DEFINE_DEVICE_TYPE(SAMSUNG_K9F2G08U0M, samsung_k9f2g08u0m_device, "samsung_k9f2g08u0m", "Samsung K9F2G08U0M")
+
+nand_device::nand_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, NAND, tag, owner, clock)
+{
+}
+
+nand_device::nand_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock),
+ device_nvram_interface(mconfig, *this),
+ m_region(*this, DEVICE_SELF),
+ m_page_data_size(0),
+ m_page_total_size(0),
+ m_num_pages(0),
+ m_log2_pages_per_block(0),
+ m_pagereg(nullptr),
+ m_id_len(0),
+ m_col_address_cycles(0),
+ m_row_address_cycles(0),
+ m_sequential_row_read(0),
+ m_write_rnb(*this)
+{
+ memset(m_id, 0, sizeof(m_id));
+}
+
+samsung_k9f5608u0d_device::samsung_k9f5608u0d_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9F5608U0D, tag, owner, clock)
+{
+ m_id_len = 2;
+ m_id[0] = 0xec;
+ m_id[1] = 0x75;
+ m_page_data_size = 512;
+ m_page_total_size = 512 + 16;
+ m_log2_pages_per_block = compute_log2(32);
+ m_num_pages = 32 * 2048;
+ m_col_address_cycles = 1;
+ m_row_address_cycles = 2;
+ m_sequential_row_read = 1;
+}
+
+samsung_k9f5608u0dj_device::samsung_k9f5608u0dj_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9F5608U0DJ, tag, owner, clock)
+{
+ m_id_len = 2;
+ m_id[0] = 0xec;
+ m_id[1] = 0x75;
+ m_page_data_size = 512;
+ m_page_total_size = 512 + 16;
+ m_log2_pages_per_block = compute_log2(32);
+ m_num_pages = 32 * 2048;
+ m_col_address_cycles = 1;
+ m_row_address_cycles = 2;
+ m_sequential_row_read = 0;
+}
+
+samsung_k9f5608u0b_device::samsung_k9f5608u0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9F5608U0B, tag, owner, clock)
+{
+ m_id_len = 2;
+ m_id[0] = 0xec;
+ m_id[1] = 0x75;
+ m_page_data_size = 512;
+ m_page_total_size = 512 + 16;
+ m_log2_pages_per_block = compute_log2(32);
+ m_num_pages = 32 * 2048;
+ m_col_address_cycles = 1;
+ m_row_address_cycles = 2;
+ m_sequential_row_read = 0;
+}
+
+samsung_k9f2808u0b_device::samsung_k9f2808u0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9F2808U0B, tag, owner, clock)
+{
+ m_id_len = 2;
+ m_id[0] = 0xec;
+ m_id[1] = 0x73;
+ m_page_data_size = 512;
+ m_page_total_size = 512 + 16;
+ m_log2_pages_per_block = compute_log2(32);
+ m_num_pages = 32 * 1024;
+ m_col_address_cycles = 1;
+ m_row_address_cycles = 2;
+ m_sequential_row_read = 0;
+}
+
+samsung_k9f1g08u0b_device::samsung_k9f1g08u0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9F1G08U0B, tag, owner, clock)
+{
+ m_id_len = 5;
+ m_id[0] = 0xec;
+ m_id[1] = 0xf1;
+ m_id[2] = 0x00;
+ m_id[3] = 0x95;
+ m_id[4] = 0x40;
+ m_page_data_size = 2048;
+ m_page_total_size = 2048 + 64;
+ m_log2_pages_per_block = compute_log2(64);
+ m_num_pages = 64 * 1024;
+ m_col_address_cycles = 2;
+ m_row_address_cycles = 2;
+ m_sequential_row_read = 0;
+}
+
+samsung_k9f1g08u0m_device::samsung_k9f1g08u0m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9F1G08U0M, tag, owner, clock)
+{
+ m_id_len = 4;
+ m_id[0] = 0xec;
+ m_id[1] = 0xf1;
+ m_id[2] = 0x00;
+ m_id[3] = 0x15;
+ m_page_data_size = 2048;
+ m_page_total_size = 2048 + 64;
+ m_log2_pages_per_block = compute_log2(64);
+ m_num_pages = 64 * 1024;
+ m_col_address_cycles = 2;
+ m_row_address_cycles = 2;
+ m_sequential_row_read = 0;
+}
+
+samsung_k9lag08u0m_device::samsung_k9lag08u0m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9LAG08U0M, tag, owner, clock)
+{
+ m_id_len = 5;
+ m_id[0] = 0xec;
+ m_id[1] = 0xd5;
+ m_id[2] = 0x55;
+ m_id[3] = 0x25;
+ m_id[4] = 0x68;
+ m_page_data_size = 2048;
+ m_page_total_size = 2048 + 64;
+ m_log2_pages_per_block = compute_log2(128);
+ m_num_pages = 128 * 8192;
+ m_col_address_cycles = 2;
+ m_row_address_cycles = 3;
+ m_sequential_row_read = 0;
+}
+
+samsung_k9f2g08u0m_device::samsung_k9f2g08u0m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nand_device(mconfig, SAMSUNG_K9F2G08U0M, tag, owner, clock)
+{
+ m_id_len = 4;
+ m_id[0] = 0xec;
+ m_id[1] = 0xda;
+ m_id[2] = 0x00;
+ m_id[3] = 0x15;
+ m_page_data_size = 2048;
+ m_page_total_size = 2048 + 64;
+ m_log2_pages_per_block = compute_log2(64);
+ m_num_pages = 128 * 1024;
+ m_col_address_cycles = 2;
+ m_row_address_cycles = 3;
+ m_sequential_row_read = 0;
+}
+
+void nand_device::device_start()
+{
+ m_data_uid_ptr = nullptr; // smartmed cruft
+ m_feeprom_data = std::make_unique<uint8_t[]>(m_page_total_size * m_num_pages);
+ m_pagereg = std::make_unique<uint8_t[]>(m_page_total_size);
+
+ save_item(NAME(m_mode));
+ save_item(NAME(m_pointer_mode));
+ save_item(NAME(m_page_addr));
+ save_item(NAME(m_byte_addr));
+ save_item(NAME(m_status));
+ save_item(NAME(m_accumulated_status));
+ save_item(NAME(m_mode_3065));
+}
+
+void nand_device::device_reset()
+{
+ m_mode = SM_M_INIT;
+ m_pointer_mode = SM_PM_A;
+ m_page_addr = 0;
+ m_byte_addr = 0;
+ m_accumulated_status = 0;
+ m_mode_3065 = false;
+ m_status = 0xc0;
+
+ std::fill_n(m_pagereg.get(), m_page_total_size, 0);
+}
+
+void nand_device::nvram_default()
+{
+ if (m_region.found())
+ {
+ // Copy from region if it exists
+ uint32_t bytes = m_region->bytes();
+
+ if (bytes > m_page_total_size * m_num_pages)
+ bytes = m_page_total_size * m_num_pages;
+
+ for (offs_t offs = 0; offs < bytes; offs++)
+ m_feeprom_data[offs] = m_region->as_u8(offs);
+
+ return;
+ }
+
+ memset(&m_feeprom_data[0], 0xff, m_page_total_size * m_num_pages);
+}
+
+bool nand_device::nvram_read(util::read_stream &file)
+{
+ uint32_t const size = m_page_total_size * m_num_pages;
+ auto const [err, actual] = read(file, &m_feeprom_data[0], size);
+ return !err && (actual == size);
+}
+
+bool nand_device::nvram_write(util::write_stream &file)
+{
+ uint32_t const size = m_page_total_size * m_num_pages;
+ auto const [err, actual] = write(file, &m_feeprom_data[0], size);
+ return !err;
+}
+
+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::command_w(uint8_t 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 = false;
+
+ m_write_rnb(0);
+ m_write_rnb(1);
+ break;
+ case 0x00: // Read (1st cycle)
+ m_mode = SM_M_READ;
+ m_pointer_mode = SM_PM_A;
+ m_addr_load_ptr = 0;
+ break;
+ case 0x01:
+ if (m_page_data_size != 512)
+ {
+ logerror("nandflash: 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_addr_load_ptr = 0;
+ }
+ break;
+ case 0x50:
+ if (m_page_data_size > 512)
+ {
+ logerror("nandflash: unsupported spare area select\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_mode = SM_M_READ;
+ m_pointer_mode = SM_PM_C;
+ m_addr_load_ptr = 0;
+ }
+ break;
+ case 0x80: // Page Program (1st cycle)
+ m_mode = SM_M_PROGRAM;
+ m_addr_load_ptr = 0;
+ m_program_byte_count = 0;
+ memset(m_pagereg.get(), 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("nandflash: illegal page program confirm command\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_status = (m_status & 0x80) | m_accumulated_status;
+ // logerror( "nandflash: program, page_addr %08X\n", m_page_addr);
+ for (int i = 0; i < m_page_total_size; i++)
+ m_feeprom_data[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;
+
+ m_write_rnb(0);
+ m_write_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("nandflash: illegal block erase confirm command\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_status &= 0x80;
+ memset(m_feeprom_data.get() + ((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( "nandflash: 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;
+
+ m_write_rnb(0);
+ m_write_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("nandflash: 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("nandflash: 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
+ {
+ m_write_rnb(0);
+ m_write_rnb(1);
+ }
+ }
+ break;
+ case 0x65:
+ if (m_mode != SM_M_30)
+ {
+ logerror("nandflash: unexpected address port write\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_mode_3065 = true;
+ }
+ break;
+ case 0x05: // Random Data Output (1st cycle)
+ if ((m_mode != SM_M_READ) && (m_mode != SM_M_RANDOM_DATA_OUTPUT))
+ {
+ logerror("nandflash: 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("nandflash: 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("nandflash: 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("nandflash: unsupported command 0x%02x\n", data);
+ m_mode = SM_M_INIT;
+ break;
+ }
+}
+
+void nand_device::address_w(uint8_t data)
+{
+ if (!is_present())
+ return;
+
+ switch (m_mode)
+ {
+ case SM_M_INIT:
+ logerror("nandflash: unexpected address port write\n");
+ break;
+ case SM_M_READ:
+ case SM_M_PROGRAM:
+ if (m_addr_load_ptr == 0)
+ {
+ m_page_addr = 0;
+ }
+ 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("nandflash: 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;
+ }
+}
+
+uint8_t nand_device::data_r()
+{
+ uint8_t reply = 0;
+ if (!is_present())
+ return 0;
+
+ switch (m_mode)
+ {
+ case SM_M_INIT:
+ case SM_M_30:
+ logerror("nandflash: 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)
+ {
+ if (m_page_addr < m_num_pages)
+ reply = m_feeprom_data[m_page_addr * m_page_total_size + m_byte_addr];
+ else
+ reply = 0xff;
+ }
+ else
+ {
+ reply = 0xFF;
+ }
+ }
+ else
+ {
+ if (m_data_uid_ptr != nullptr)
+ {
+ // FIXME: this appears to be incorrect, m_data_uid_ptr is a smaller structure of 256*16
+ // this code would always result in reading past the buffer
+ uint32_t addr = m_page_addr * m_page_total_size + m_byte_addr;
+ if (addr < 256 + 16)
+ reply = m_data_uid_ptr[addr];
+ }
+ else
+ {
+ reply = 0xff;
+ }
+ }
+ m_byte_addr++;
+
+ // "Sequential Row Read is available only on K9F5608U0D_Y,P,V,F or K9F5608D0D_Y,P"
+ 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("nandflash: 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;
+}
+
+void nand_device::data_w(uint8_t 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("nandflash: 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("nandflash: unexpected data port write\n");
+ break;
+ }
+}
diff --git a/src/devices/machine/nandflash.h b/src/devices/machine/nandflash.h
new file mode 100644
index 00000000000..dc1b3f0d134
--- /dev/null
+++ b/src/devices/machine/nandflash.h
@@ -0,0 +1,162 @@
+// license:BSD-3-Clause
+// copyright-holders:Raphael Nabet
+
+#ifndef MAME_MACHINE_NANDFLASH_H
+#define MAME_MACHINE_NANDFLASH_H
+
+#pragma once
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> nand_device
+class nand_device : public device_t, public device_nvram_interface
+{
+public:
+ // construction/destruction
+ nand_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_nvram_interface implementation
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ auto rnb_wr_callback() { return m_write_rnb.bind(); }
+
+ int is_present();
+ int is_protected();
+ int is_busy();
+
+ uint8_t data_r();
+ void command_w(uint8_t data);
+ void address_w(uint8_t data);
+ void data_w(uint8_t data);
+
+protected:
+ enum sm_mode_t : uint8_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 : uint8_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
+ };
+
+ nand_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ optional_memory_region m_region;
+
+ uint32_t m_page_data_size; // 256 for a 2MB card, 512 otherwise
+ uint32_t m_page_total_size; // 264 for a 2MB card, 528 otherwise
+ uint32_t 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
+ int32_t m_log2_pages_per_block; // log2 of number of pages per erase block (usually 4 or 5)
+
+ std::unique_ptr<uint8_t[]> m_feeprom_data; // FEEPROM data area
+ std::unique_ptr<uint8_t[]> m_data_uid_ptr; // TODO: this probably should be contained to smartmed
+
+ sm_mode_t m_mode; // current operation mode
+ pointer_sm_mode_t m_pointer_mode; // pointer mode
+
+ uint32_t m_page_addr; // page address pointer
+ uint32_t m_byte_addr; // byte address pointer
+ uint32_t m_addr_load_ptr; // address load pointer
+
+ uint8_t m_status; // current status
+ uint8_t m_accumulated_status; // accumulated status
+
+ std::unique_ptr<uint8_t[]> m_pagereg; // page register used by program command
+ uint8_t m_id[5]; // chip ID
+
+ bool 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
+ uint32_t m_program_byte_count;
+
+ uint32_t m_id_len;
+ uint32_t m_col_address_cycles;
+ uint32_t m_row_address_cycles;
+ uint32_t m_sequential_row_read;
+
+ devcb_write_line m_write_rnb;
+};
+
+class samsung_k9f5608u0d_device : public nand_device
+{
+public:
+ samsung_k9f5608u0d_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class samsung_k9f5608u0dj_device : public nand_device
+{
+public:
+ samsung_k9f5608u0dj_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class samsung_k9f5608u0b_device : public nand_device
+{
+public:
+ samsung_k9f5608u0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class samsung_k9f2808u0b_device : public nand_device
+{
+public:
+ samsung_k9f2808u0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class samsung_k9f1g08u0b_device : public nand_device
+{
+public:
+ samsung_k9f1g08u0b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class samsung_k9f1g08u0m_device : public nand_device
+{
+public:
+ samsung_k9f1g08u0m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class samsung_k9lag08u0m_device : public nand_device
+{
+public:
+ samsung_k9lag08u0m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+class samsung_k9f2g08u0m_device : public nand_device
+{
+public:
+ samsung_k9f2g08u0m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(NAND, nand_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9F5608U0D, samsung_k9f5608u0d_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9F5608U0DJ, samsung_k9f5608u0dj_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9F5608U0B, samsung_k9f5608u0b_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9F2808U0B, samsung_k9f2808u0b_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9F1G08U0B, samsung_k9f1g08u0b_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9F1G08U0M, samsung_k9f1g08u0m_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9LAG08U0M, samsung_k9lag08u0m_device)
+DECLARE_DEVICE_TYPE(SAMSUNG_K9F2G08U0M, samsung_k9f2g08u0m_device)
+
+#endif // MAME_MACHINE_NANDFLASH_H
diff --git a/src/devices/machine/ncr5380.cpp b/src/devices/machine/ncr5380.cpp
index adc309f6b60..5259bf3bb4f 100644
--- a/src/devices/machine/ncr5380.cpp
+++ b/src/devices/machine/ncr5380.cpp
@@ -1,420 +1,670 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont
+// copyright-holders:Patrick Mackinlay
+
/*
- * 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.
+ * NCR 5380 and 53C80, aka Zilog Z5380, AMD Am5380, Sony CXD1180 and others.
*
- * 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.
+ * Sources:
+ * - http://bitsavers.org/components/ncr/scsi/SP-1051_NCR_5380-53C80_SCSI_Interface_Chip_Design_Manual_Mar86.pdf
*
+ * TODO:
+ * - target mode
+ * - cxd1180 enhancements
*/
#include "emu.h"
#include "ncr5380.h"
-//#define VERBOSE 1
+#define LOG_REGW (1U << 1)
+#define LOG_REGR (1U << 2)
+#define LOG_SCSI (1U << 3)
+#define LOG_ARB (1U << 4)
+#define LOG_DMA (1U << 5)
+
+//#define VERBOSE (LOG_GENERAL|LOG_REGW|LOG_REGR|LOG_SCSI|LOG_ARB|LOG_DMA)
#include "logmacro.h"
+DEFINE_DEVICE_TYPE(NCR5380, ncr5380_device, "ncr5380", "NCR 5380 SCSI")
+DEFINE_DEVICE_TYPE(NCR53C80, ncr53c80_device, "ncr53c80", "NCR 53C80 SCSI")
+DEFINE_DEVICE_TYPE(CXD1180, cxd1180_device, "cxd1180", "Sony CXD1180")
+
+ALLOW_SAVE_TYPE(ncr5380_device::state);
+
+ncr5380_device::ncr5380_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, bool has_lbs)
+ : nscsi_device(mconfig, type, tag, owner, clock)
+ , nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF)
+ , m_irq_handler(*this)
+ , m_drq_handler(*this)
+ , m_has_lbs(has_lbs)
+{
+}
+
+ncr5380_device::ncr5380_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : ncr5380_device(mconfig, NCR5380, tag, owner, clock)
+{
+}
+
+ncr53c80_device::ncr53c80_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : ncr5380_device(mconfig, NCR53C80, tag, owner, clock, true)
+{
+}
-static const char *const rnames[] =
+cxd1180_device::cxd1180_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : ncr5380_device(mconfig, CXD1180, tag, owner, clock, true)
{
- "Current data",
- "Initiator cmd",
- "Mode",
- "Target cmd",
- "Bus status",
- "Bus and status",
- "Input data",
- "Reset parity"
-};
+}
-static const char *const wnames[] =
+void ncr5380_device::map(address_map &map)
{
- "Output data",
- "Initiator cmd",
- "Mode",
- "Target cmd",
- "Select enable",
- "Start DMA",
- "DMA target",
- "DMA initiator rec"
-};
+ map(0x0, 0x0).rw(FUNC(ncr5380_device::csdata_r), FUNC(ncr5380_device::odata_w));
+ map(0x1, 0x1).rw(FUNC(ncr5380_device::icmd_r), FUNC(ncr5380_device::icmd_w));
+ map(0x2, 0x2).rw(FUNC(ncr5380_device::mode_r), FUNC(ncr5380_device::mode_w));
+ map(0x3, 0x3).rw(FUNC(ncr5380_device::tcmd_r), FUNC(ncr5380_device::tcmd_w));
+ map(0x4, 0x4).rw(FUNC(ncr5380_device::csstat_r), FUNC(ncr5380_device::selen_w));
+ map(0x5, 0x5).rw(FUNC(ncr5380_device::bas_r), FUNC(ncr5380_device::sds_w));
+ map(0x6, 0x6).rw(FUNC(ncr5380_device::idata_r), FUNC(ncr5380_device::sdtr_w));
+ map(0x7, 0x7).rw(FUNC(ncr5380_device::rpi_r), FUNC(ncr5380_device::sdir_w));
+}
-// get the length of a SCSI command based on it's command byte type
-static int get_cmd_len(int cbyte)
+void ncr5380_device::device_start()
{
- int group;
+ // Need to be cleared here so that set_irq/drq called from reset
+ // does not compare with uninitialized
+ m_irq_state = false;
+ m_drq_state = false;
- group = (cbyte>>5) & 7;
+ m_state_timer = timer_alloc(FUNC(ncr5380_device::state_timer), this);
- if (group == 0) return 6;
- if (group == 1 || group == 2) return 10;
- if (group == 5) return 12;
+ save_item(NAME(m_state));
- fatalerror("NCR5380: Unknown SCSI command group %d\n", group);
+ save_item(NAME(m_odata));
+ save_item(NAME(m_icmd));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_tcmd));
+ save_item(NAME(m_bas));
+ save_item(NAME(m_idata));
- // never executed
- //return 6;
+ save_item(NAME(m_scsi_ctrl));
+ save_item(NAME(m_irq_state));
+ save_item(NAME(m_drq_state));
}
+void ncr5380_device::device_reset()
+{
+ m_state = IDLE;
+
+ // clear registers
+ m_odata = 0;
+ m_icmd = 0;
+ m_mode = 0;
+ m_tcmd = 0;
+ m_bas = 0;
+ m_idata = 0;
+
+ // clear scsi bus
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
+
+ // monitor all control lines
+ m_scsi_ctrl = 0;
+ scsi_bus->ctrl_wait(scsi_refid, S_ALL, S_ALL);
+
+ // clear output lines
+ set_irq(false);
+ set_drq(false);
+}
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
+void ncr5380_device::scsi_ctrl_changed()
+{
+ u32 const ctrl = scsi_bus->ctrl_r();
-DEFINE_DEVICE_TYPE(NCR5380, ncr5380_device, "ncr5380", "NCR 5380 SCSI")
+ if (VERBOSE & LOG_SCSI)
+ {
+ static char const *const nscsi_phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "*", "*", "MESSAGE OUT", "MESSAGE IN" };
+
+ if (ctrl & S_RST)
+ LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x BUS RESET\n", ctrl);
+ else if ((ctrl & S_BSY) && !(ctrl & S_SEL))
+ LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x phase %s%s%s\n", ctrl, nscsi_phase[ctrl & S_PHASE_MASK],
+ ctrl & S_REQ ? " REQ" : "", ctrl & S_ACK ? " ACK" : "");
+ else if (ctrl & S_BSY)
+ LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x arbitration/selection\n", ctrl);
+ else
+ LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x BUS FREE\n", ctrl);
+ }
+
+ m_bas &= ~BAS_BUSYERROR;
+
+ if (ctrl & S_RST)
+ {
+ LOG("scsi reset received\n");
+ device_reset();
+
+ set_irq(true);
+ }
+ else if (!(m_mode & MODE_TARGET) && (m_scsi_ctrl & S_BSY) && !(ctrl & S_BSY))
+ {
+ LOG("target disconnected\n");
+ m_icmd &= (IC_RST | IC_AIP);
+
+ if (m_mode & MODE_DMA)
+ {
+ // stop dma
+ m_mode &= ~MODE_DMA;
+ m_bas &= ~BAS_ENDOFDMA;
+
+ set_drq(false);
+ }
+
+ if (m_mode & MODE_BSYIRQ)
+ {
+ m_bas |= BAS_BUSYERROR;
-//-------------------------------------------------
-// ncr5380_device - constructor/destructor
-//-------------------------------------------------
+ set_irq(true);
+ }
-ncr5380_device::ncr5380_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- legacy_scsi_host_adapter(mconfig, NCR5380, tag, owner, clock),
- m_irq_cb(*this)
+ m_state = IDLE;
+ m_state_timer->enable(false);
+
+ // clear scsi bus
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
+ }
+ else if (!(m_scsi_ctrl & S_REQ) && (ctrl & S_REQ))
+ {
+ // target asserted REQ
+ if (m_mode & MODE_DMA)
+ {
+ if ((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE))
+ {
+ // transfer cycle
+ if (m_state != IDLE && !m_state_timer->enabled())
+ m_state_timer->adjust(attotime::zero);
+ }
+ else
+ {
+ LOG("phase mismatch %d != %d\n", (ctrl & S_PHASE_MASK), (m_tcmd & TC_PHASE));
+
+ m_state = IDLE;
+ m_state_timer->enable(false);
+
+ set_drq(true);
+ set_irq(true);
+ }
+ }
+ }
+
+ m_scsi_ctrl = ctrl;
+}
+
+u8 ncr5380_device::csdata_r()
{
+ u8 const data = scsi_bus->data_r();
+ LOGMASKED(LOG_REGR, "csdata_r 0x%02x (%s)\n", data, machine().describe_context());
+
+ return data;
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
+void ncr5380_device::odata_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "odata_w 0x%02x (%s)\n", data, machine().describe_context());
-void ncr5380_device::device_start()
+ // drive scsi data
+ if (m_icmd & IC_DBUS)
+ scsi_data_w(data);
+
+ m_odata = data;
+}
+
+u8 ncr5380_device::icmd_r()
{
- legacy_scsi_host_adapter::device_start();
+ LOGMASKED(LOG_REGR, "icmd_r 0x%02x (%s)\n", m_icmd, machine().describe_context());
- memset(m_5380_Registers, 0, sizeof(m_5380_Registers));
- memset(m_5380_Data, 0, sizeof(m_5380_Data));
+ return m_icmd;
+}
- m_next_req_flag = 0;
- m_irq_cb.resolve_safe();
+void ncr5380_device::icmd_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "icmd_w 0x%02x (%s)\n", data, machine().describe_context());
- 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));
+ if (!(data & IC_RST))
+ {
+ // drive scsi data
+ if ((data ^ m_icmd) & IC_DBUS)
+ scsi_data_w((data & IC_DBUS) ? m_odata : 0);
+
+ // check for control line changes
+ if ((data & IC_PHASE) ^ (m_icmd & IC_PHASE))
+ {
+ u32 const mask = (m_mode & MODE_TARGET) ?
+ (S_RST | S_BSY | S_SEL) :
+ (S_RST | S_ACK | S_BSY | S_SEL | S_ATN);
+
+ // translate to nscsi
+ u32 const ctrl =
+ (data & IC_RST ? S_RST : 0) |
+ (data & IC_ACK ? S_ACK : 0) |
+ (data & IC_BSY ? S_BSY : 0) |
+ (data & IC_SEL ? S_SEL : 0) |
+ (data & IC_ATN ? S_ATN : 0);
+
+ LOGMASKED(LOG_SCSI, "changing control lines 0x%04x\n", ctrl);
+ scsi_bus->ctrl_w(scsi_refid, ctrl, mask);
+ }
+ }
+ else
+ {
+ LOG("scsi reset issued\n");
+ device_reset();
+ scsi_bus->ctrl_w(scsi_refid, S_RST, S_RST);
+
+ set_irq(true);
+ }
+
+ m_icmd = (m_icmd & ~IC_WRITE) | (data & IC_WRITE);
}
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
+u8 ncr5380_device::mode_r()
+{
+ LOGMASKED(LOG_REGR, "mode_r 0x%02x (%s)\n", m_mode, machine().describe_context());
-void ncr5380_device::device_reset()
+ return m_mode;
+}
+
+void ncr5380_device::mode_w(u8 data)
{
- memset(m_5380_Registers, 0, sizeof(m_5380_Registers));
- memset(m_5380_Data, 0, sizeof(m_5380_Data));
+ LOGMASKED(LOG_REGW, "mode_w 0x%02x (%s)\n", data, machine().describe_context());
- m_next_req_flag = 0;
- m_cmd_ptr = 0;
- m_d_ptr = 0;
- m_d_limit = 0;
- m_last_id = 0;
+ if (!(data & MODE_BSYIRQ))
+ m_bas &= ~BAS_BUSYERROR;
+
+ // disable dma
+ if ((m_mode & MODE_DMA) && !(data & MODE_DMA))
+ {
+ m_state = IDLE;
+ m_state_timer->enable(false);
+
+ m_bas &= ~BAS_ENDOFDMA;
+
+ if (m_has_lbs)
+ m_tcmd &= ~TC_LBS;
+
+ set_drq(false);
+
+ // clear ACK
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ }
+
+ // start/stop arbitration
+ if ((m_mode ^ data) & MODE_ARBITRATE)
+ {
+ if (data & MODE_ARBITRATE)
+ {
+ // start arbitration
+ m_icmd &= ~IC_LA;
+ m_state = ARB_BUS_FREE;
+ m_state_timer->adjust(attotime::zero);
+ }
+ else
+ {
+ // stop arbitration
+ m_state = IDLE;
+ m_icmd &= ~(IC_AIP | IC_LA);
+ }
+ }
+
+ m_mode = data;
}
-//-------------------------------------------------
-// device_stop - device-specific stop/shutdown
-//-------------------------------------------------
-void ncr5380_device::device_stop()
+u8 ncr5380_device::tcmd_r()
{
+ LOGMASKED(LOG_REGR, "tcmd_r 0x%02x (%s)\n", m_tcmd, machine().describe_context());
+
+ return m_tcmd;
}
-//-------------------------------------------------
-// Public API
-//-------------------------------------------------
-uint8_t ncr5380_device::ncr5380_read_reg(uint32_t offset)
+void ncr5380_device::tcmd_w(u8 data)
{
- int reg = offset & 7;
- uint8_t rv;
+ LOGMASKED(LOG_REGW, "tcmd_w 0x%02x (%s)\n", data, machine().describe_context());
- switch( reg )
- {
- case R5380_CURDATA:
- case R5380_INPUTDATA:
- rv = m_5380_Registers[reg];
+ if (m_has_lbs)
+ m_tcmd = (m_tcmd & TC_LBS) | (data & ~TC_LBS);
+ else
+ m_tcmd = data;
+}
- // if we're in the data transfer phase or DMA, readback device data instead
- if (((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x04) || (m_5380_Registers[R5380_BUSSTATUS] & 0x40))
- {
- rv = m_5380_Data[m_d_ptr];
-
- // if the limit's less than 512, only read "limit" bytes
- if (m_d_limit < 512)
- {
- if (m_d_ptr < (m_d_limit-1))
- {
- m_d_ptr++;
- }
- else
- {
- m_next_req_flag = 1;
- }
- }
- else
- {
- if (m_d_ptr < 511)
- {
- m_d_ptr++;
- }
- else
- {
- m_d_limit -= 512;
- m_d_ptr = 0;
-
- m_next_req_flag = 1;
-
- // don't issue a "false" read
- if (m_d_limit > 0)
- {
- read_data(m_5380_Data, (m_d_limit < 512) ? m_d_limit : 512);
- }
- else
- {
- // if this is DMA, signal DMA end
- if (m_5380_Registers[R5380_BUSSTATUS] & 0x40)
- {
- m_5380_Registers[R5380_BUSSTATUS] |= 0x80;
- }
-
- // drop /REQ
- m_5380_Registers[R5380_BUSSTATUS] &= ~0x20;
-
- // clear phase match
- m_5380_Registers[R5380_BUSANDSTAT] &= ~0x08;
- }
- }
- }
+u8 ncr5380_device::csstat_r()
+{
+ u32 const ctrl = scsi_bus->ctrl_r();
+ u8 const data =
+ (ctrl & S_RST ? ST_RST : 0) |
+ (ctrl & S_BSY ? ST_BSY : 0) |
+ (ctrl & S_REQ ? ST_REQ : 0) |
+ (ctrl & S_MSG ? ST_MSG : 0) |
+ (ctrl & S_CTL ? ST_CD : 0) |
+ (ctrl & S_INP ? ST_IO : 0) |
+ (ctrl & S_SEL ? ST_SEL : 0);
+
+ LOGMASKED(LOG_REGR, "csstat_r 0x%02x (%s)\n", data, machine().describe_context());
+ return data;
+}
- }
- break;
+void ncr5380_device::selen_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "selen_w 0x%02x (%s)\n", data, machine().describe_context());
+}
- default:
- rv = m_5380_Registers[reg];
+u8 ncr5380_device::bas_r()
+{
+ u32 const ctrl = scsi_bus->ctrl_r();
+ u8 const data = m_bas |
+ (((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE)) ? BAS_PHASEMATCH : 0) |
+ (ctrl & S_ATN ? BAS_ATN : 0) |
+ (ctrl & S_ACK ? BAS_ACK : 0);
- // temporarily drop /REQ
- if ((reg == R5380_BUSSTATUS) && (m_next_req_flag))
- {
- rv &= ~0x20;
- m_next_req_flag = 0;
- }
- break;
+ LOGMASKED(LOG_REGR, "bas_r 0x%02x (%s)\n", data, machine().describe_context());
+
+ return data;
+}
+
+void ncr5380_device::sds_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "sds_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ if (m_mode & MODE_DMA)
+ {
+ m_state = DMA_OUT_DRQ;
+ m_state_timer->adjust(attotime::zero);
}
+}
- LOG("%s NCR5380: read %s (reg %d) = %02x\n", machine().describe_context(), rnames[reg], reg, rv);
+u8 ncr5380_device::idata_r()
+{
+ LOGMASKED(LOG_REGR, "idata_r 0x%02x (%s)\n", m_idata, machine().describe_context());
- return rv;
+ return m_idata;
}
-void ncr5380_device::ncr5380_write_reg(uint32_t offset, uint8_t data)
+void ncr5380_device::sdtr_w(u8 data)
{
- int reg = offset & 7;
+ LOGMASKED(LOG_REGW, "sdtr_w 0x%02x (%s)\n", data, machine().describe_context());
+}
- LOG("%s NCR5380: %02x to %s (reg %d)\n", machine().describe_context(), data, wnames[reg], reg);
+u8 ncr5380_device::rpi_r()
+{
+ LOGMASKED(LOG_REGR, "rpi_r (%s)\n", machine().describe_context());
+
+ m_bas &= ~(BAS_PARITYERROR | BAS_BUSYERROR);
+ set_irq(false);
+
+ return 0;
+}
+
+void ncr5380_device::sdir_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "sdir_w 0x%02x (%s)\n", data, machine().describe_context());
- switch( reg )
+ if ((m_mode & MODE_DMA) && !(m_mode & MODE_TARGET))
{
- 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;
- }
+ m_state = DMA_IN_REQ;
+ m_state_timer->adjust(attotime::zero);
+ }
+}
- // 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;
- }
- }
+void ncr5380_device::state_timer(s32 param)
+{
+ // step state machine
+ int const delay = state_step();
- // if this is a write, accumulate accordingly
- if (((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x00) && (m_5380_Registers[R5380_INICOMMAND] == 1))
- {
- m_5380_Data[m_d_ptr] = data;
-
- // if we've hit a sector, flush
- if (m_d_ptr == 511)
- {
- write_data(&m_5380_Data[0], 512);
-
- m_d_limit -= 512;
- m_d_ptr = 0;
-
- // no more data? set DMA END flag
- if (m_d_limit <= 0)
- {
- m_5380_Registers[R5380_BUSANDSTAT] = 0xc8;
- }
- }
- else
- {
- m_d_ptr++;
- }
-
- // make sure we don't upset the status readback
- data = 0;
- }
- break;
+ // check for data stall
+ if (delay < 0)
+ return;
- 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)
- {
- LOG("%s NCR5380: Command (to ID %d): %x %x %x %x %x %x %x %x %x %x\n", machine().describe_context(), m_last_id, m_5380_Command[0], m_5380_Command[1], m_5380_Command[2], m_5380_Command[3], m_5380_Command[4], m_5380_Command[5], m_5380_Command[6], m_5380_Command[7], m_5380_Command[8], m_5380_Command[9]);
-
- send_command(&m_5380_Command[0], 16);
- m_d_limit = get_length();
-
- LOG("NCR5380: Command returned %d bytes\n", m_d_limit);
-
- m_d_ptr = 0;
-
- // is data available?
- if (m_d_limit > 0)
- {
- // make sure for transfers under 512 bytes that we always pad with a zero
- if (m_d_limit < 512)
- {
- m_5380_Data[m_d_limit] = 0;
- }
-
- // read back the amount available, or 512 bytes, whichever is smaller
- read_data(m_5380_Data, (m_d_limit < 512) ? m_d_limit : 512);
-
- // raise REQ to indicate data is available
- m_5380_Registers[R5380_BUSSTATUS] |= 0x20;
- }
- }
- }
+ // repeat until idle
+ if (m_state != IDLE)
+ m_state_timer->adjust(attotime::from_nsec(delay));
+}
- }
+int ncr5380_device::state_step()
+{
+ u32 const ctrl = scsi_bus->ctrl_r();
+ int delay = 0;
- if (data == 5) // want the bus?
+ switch (m_state)
+ {
+ case IDLE:
+ break;
+
+ case ARB_BUS_FREE:
+ if (!(ctrl & (S_SEL | S_BSY | S_RST)))
+ {
+ LOGMASKED(LOG_ARB, "arbitration: bus free\n");
+ // FIXME: AIP should only be set when arbitration begins
+ m_icmd |= IC_AIP;
+ m_state = ARB_START;
+ delay = 1700;
+ }
+ else
+ {
+ LOGMASKED(LOG_ARB, "arbitration: bus not free\n");
+ m_state = IDLE;
+ }
+ break;
+ case ARB_START:
+ LOGMASKED(LOG_ARB, "arbitration: started\n");
+ m_icmd |= IC_BSY;
+ m_state = ARB_EVALUATE;
+ delay = 2200;
+
+ // assert own ID and BSY
+ scsi_bus->data_w(scsi_refid, m_odata);
+ scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY);
+ break;
+ case ARB_EVALUATE:
+ // check if SEL asserted, or if there's a higher ID on the bus
+ if ((ctrl & S_SEL) || (scsi_bus->data_r() & ~((m_odata - 1) | m_odata)))
+ {
+ LOGMASKED(LOG_ARB, "arbitration: lost\n");
+ m_icmd &= ~IC_BSY;
+ m_icmd |= IC_LA;
+
+ m_state = IDLE;
+
+ // clear data and BSY
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
+ }
+ else
+ {
+ LOGMASKED(LOG_ARB, "arbitration: won\n");
+ m_state = IDLE;
+ }
+ break;
+
+ case DMA_IN_REQ:
+ if (ctrl & S_REQ)
+ {
+ if ((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE))
{
- // if the device exists, make the bus busy.
- // otherwise don't.
-
- if (select(m_last_id))
- {
- LOG("NCR5380: Giving the bus for ID %d\n", m_last_id);
- m_5380_Registers[R5380_BUSSTATUS] |= 0x40;
- }
- else
- {
- LOG("NCR5380: Rejecting the bus for ID %d\n", m_last_id);
- m_5380_Registers[R5380_BUSSTATUS] &= ~0x40;
- }
- }
+ m_idata = scsi_bus->data_r();
+ LOGMASKED(LOG_DMA, "dma in: 0x%02x\n", m_idata);
- if (data == 1) // data bus (prelude to command?)
- {
- // raise REQ
- m_5380_Registers[R5380_BUSSTATUS] |= 0x20;
- }
+ m_state = DMA_IN_ACK;
+ set_drq(true);
- if (data & 0x10) // ACK drops REQ
- {
- // drop REQ
- m_5380_Registers[R5380_BUSSTATUS] &= ~0x20;
+ // assert ACK
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
}
- break;
- case R5380_MODE:
- if (data == 2) // DMA
+ delay = -1;
+ }
+ break;
+ case DMA_IN_ACK:
+ if (!(ctrl & S_REQ))
+ {
+ m_state = (m_bas & BAS_ENDOFDMA) ? IDLE : DMA_IN_REQ;
+
+ // clear ACK
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ }
+ break;
+
+ case DMA_OUT_DRQ:
+ m_state = DMA_OUT_REQ;
+ set_drq(true);
+
+ delay = -1;
+ break;
+ case DMA_OUT_REQ:
+ if (ctrl & S_REQ)
+ {
+ if ((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE))
{
- // put us in DMA mode
- m_5380_Registers[R5380_BUSANDSTAT] |= 0x40;
- }
+ LOGMASKED(LOG_DMA, "dma out: 0x%02x\n", m_odata);
- if (data == 1) // arbitrate?
- {
- m_5380_Registers[R5380_INICOMMAND] |= 0x40; // set arbitration in progress
- m_5380_Registers[R5380_INICOMMAND] &= ~0x20; // clear "lost arbitration"
- }
+ m_state = DMA_OUT_ACK;
- if (data == 0)
+ // assert data and ACK
+ scsi_bus->data_w(scsi_refid, m_odata);
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
+ }
+ }
+ break;
+ case DMA_OUT_ACK:
+ if (!(ctrl & S_REQ))
+ {
+ if (m_bas & BAS_ENDOFDMA)
{
- // drop DMA mode
- m_5380_Registers[R5380_BUSANDSTAT] &= ~0x40;
+ m_state = IDLE;
+
+ if (m_has_lbs)
+ m_tcmd |= TC_LBS;
}
- break;
+ else
+ m_state = DMA_OUT_DRQ;
+
+ // clear data and ACK
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ }
+ break;
+ }
+
+ return delay;
+}
- 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;
+void ncr5380_device::eop_w(int state)
+{
+ LOGMASKED(LOG_DMA, "eop_w %d\n", state);
+ if (state && (m_mode & MODE_DMA))
+ {
+ m_bas |= BAS_ENDOFDMA;
- // and set the "phase match" flag
- m_5380_Registers[R5380_BUSANDSTAT] |= 0x08;
+ if (m_mode & MODE_EOPIRQ)
+ {
+ // FIXME: should only trigger when combined with dma_r/dma_w
+ LOG("eop irq asserted\n");
- // and set /REQ
- m_5380_Registers[R5380_BUSSTATUS] |= 0x20;
+ set_irq(true);
+ }
+ }
+}
- // if we're entering the command phase, start accumulating the data
- if ((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x08)
- {
- m_cmd_ptr = 0;
- }
- break;
+void ncr5380_device::dma_w(u8 data)
+{
+ set_drq(false);
+
+ if (m_mode & MODE_DMA)
+ {
+ m_odata = data;
+
+ m_state_timer->adjust(attotime::zero);
+ }
+}
+
+u8 ncr5380_device::dma_r()
+{
+ set_drq(false);
+
+ if (m_mode & MODE_DMA)
+ m_state_timer->adjust(attotime::zero);
+
+ return m_idata;
+}
+
+void ncr5380_device::scsi_data_w(u8 data)
+{
+ // TODO: release data bus when any of the prerequisite conditions expire
+ u32 const ctrl = scsi_bus->ctrl_r();
+
+ if ((m_mode & MODE_TARGET) || (!(ctrl & S_INP) && (ctrl & S_PHASE_MASK) == (m_tcmd & S_PHASE_MASK)))
+ {
+ LOGMASKED(LOG_SCSI, "scsi data 0x%02x\n", data);
+ scsi_bus->data_w(scsi_refid, data);
+ }
+}
+
+void ncr5380_device::set_irq(bool irq_state)
+{
+ if (irq_state != m_irq_state)
+ {
+ LOG("set_irq %d\n", irq_state);
- default:
- break;
+ if (irq_state)
+ m_bas |= BAS_IRQACTIVE;
+ else
+ m_bas &= ~BAS_IRQACTIVE;
+
+ m_irq_state = irq_state;
+ m_irq_handler(m_irq_state);
}
+}
+
+void ncr5380_device::set_drq(bool drq_state)
+{
+ if (drq_state != m_drq_state)
+ {
+ LOGMASKED(LOG_DMA, "set_drq %d\n", drq_state);
- m_5380_Registers[reg] = data;
+ if (drq_state)
+ m_bas |= BAS_DMAREQUEST;
+ else
+ m_bas &= ~BAS_DMAREQUEST;
- // note: busandstat overlaps startdma, so we need to do this here!
- if (reg == R5380_STARTDMA)
+ m_drq_state = drq_state;
+ m_drq_handler(m_drq_state);
+ }
+}
+
+u8 ncr5380_device::read(offs_t offset)
+{
+ switch (offset & 7)
+ {
+ case 0: return csdata_r();
+ case 1: return icmd_r();
+ case 2: return mode_r();
+ case 3: return tcmd_r();
+ case 4: return csstat_r();
+ case 5: return bas_r();
+ case 6: return idata_r();
+ case 7: return rpi_r();
+ }
+
+ // can't happen
+ return 0;
+}
+
+void ncr5380_device::write(offs_t offset, u8 data)
+{
+ switch (offset & 7)
{
- m_5380_Registers[R5380_BUSANDSTAT] = 0x48;
+ case 0: odata_w(data); break;
+ case 1: icmd_w(data); break;
+ case 2: mode_w(data); break;
+ case 3: tcmd_w(data); break;
+ case 4: selen_w(data); break;
+ case 5: sds_w(data); break;
+ case 6: sdtr_w(data); break;
+ case 7: sdir_w(data); break;
}
}
diff --git a/src/devices/machine/ncr5380.h b/src/devices/machine/ncr5380.h
index 9d9d7b96617..e7107ae285e 100644
--- a/src/devices/machine/ncr5380.h
+++ b/src/devices/machine/ncr5380.h
@@ -1,70 +1,186 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-/*
- * ncr5380.h SCSI controller
- *
- */
+// copyright-holders:Patrick Mackinlay
#ifndef MAME_MACHINE_NCR5380_H
#define MAME_MACHINE_NCR5380_H
#pragma once
-#include "legscsi.h"
+#include "machine/nscsi_bus.h"
-// 5380 registers
-enum
-{
- R5380_CURDATA = 0, // current SCSI data (read only)
- R5380_OUTDATA = 0, // output data (write only)
- R5380_INICOMMAND, // initiator command
- R5380_MODE, // mode
- R5380_TARGETCMD, // target command
- R5380_SELENABLE, // select enable (write only)
- R5380_BUSSTATUS = R5380_SELENABLE, // bus status (read only)
- R5380_STARTDMA, // start DMA send (write only)
- R5380_BUSANDSTAT = R5380_STARTDMA, // bus and status (read only)
- R5380_DMATARGET, // DMA target (write only)
- R5380_INPUTDATA = R5380_DMATARGET, // input data (read only)
- R5380_DMAINIRECV, // DMA initiator receive (write only)
- R5380_RESETPARITY = R5380_DMAINIRECV // reset parity/interrupt (read only)
-};
-
-// special Mac Plus registers - they implemented it weird
-#define R5380_OUTDATA_DTACK (R5380_OUTDATA | 0x10)
-#define R5380_CURDATA_DTACK (R5380_CURDATA | 0x10)
-
-// device stuff
-
-
-class ncr5380_device : public legacy_scsi_host_adapter
+class ncr5380_device
+ : public nscsi_device
+ , public nscsi_slot_card_interface
{
public:
- // construction/destruction
- ncr5380_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ncr5380_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
- auto irq_callback() { return m_irq_cb.bind(); }
+ // device configuration
+ auto irq_handler() { return m_irq_handler.bind(); }
+ auto drq_handler() { return m_drq_handler.bind(); }
- // our API
- uint8_t ncr5380_read_reg(uint32_t offset);
- void ncr5380_write_reg(uint32_t offset, uint8_t data);
+ // register access
+ void map(address_map &map);
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+ // dma access
+ void eop_w(int state);
+ u8 dma_r();
+ void dma_w(u8 val);
protected:
- // device-level overrides
+ ncr5380_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, bool has_lbs = false);
+
+ // device_t overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_stop() override;
+
+ // ncsci_device overrides
+ virtual void scsi_ctrl_changed() override;
+
+ // register read handlers
+ u8 csdata_r();
+ u8 icmd_r();
+ u8 mode_r();
+ u8 tcmd_r();
+ u8 csstat_r();
+ u8 bas_r();
+ u8 idata_r();
+ u8 rpi_r();
+
+ // register write handlers
+ void odata_w(u8 data);
+ void icmd_w(u8 data);
+ void mode_w(u8 data);
+ void tcmd_w(u8 data);
+ void selen_w(u8 data);
+ void sds_w(u8 data);
+ void sdtr_w(u8 data);
+ void sdir_w(u8 data);
+
+ // state machine
+ void state_timer(s32 param);
+ int state_step();
+
+ // other helpers
+ void scsi_data_w(u8 data);
+ void set_irq(bool irq_state);
+ void set_drq(bool drq_state);
private:
- uint8_t m_5380_Registers[8];
- uint8_t m_last_id;
- uint8_t m_5380_Command[32];
- int32_t m_cmd_ptr, m_d_ptr, m_d_limit, m_next_req_flag;
- uint8_t m_5380_Data[512];
- devcb_write_line m_irq_cb; /* irq callback */
+ enum icmd_mask : u8
+ {
+ IC_RST = 0x80, // assert R̅S̅T̅
+ IC_TEST = 0x40, // test mode (wo)
+ IC_AIP = 0x40, // arbitration in progress (ro)
+ IC_LA = 0x20, // lost arbitration (ro)
+ IC_ACK = 0x10, // assert A̅C̅K̅
+ IC_BSY = 0x08, // assert B̅S̅Y̅
+ IC_SEL = 0x04, // assert S̅E̅L̅
+ IC_ATN = 0x02, // assert A̅T̅N̅
+ IC_DBUS = 0x01, // assert data bus
+
+ IC_PHASE = 0x9e,
+ IC_WRITE = 0x9f,
+ };
+ enum mode_mask : u8
+ {
+ MODE_BLOCKDMA = 0x80,
+ MODE_TARGET = 0x40,
+ MODE_PARITYCHK = 0x20,
+ MODE_PARITYIRQ = 0x10,
+ MODE_EOPIRQ = 0x08,
+ MODE_BSYIRQ = 0x04,
+ MODE_DMA = 0x02,
+ MODE_ARBITRATE = 0x01,
+ };
+ enum tcmd_mask : u8
+ {
+ TC_LBS = 0x80, // last byte sent
+ TC_REQ = 0x08, // assert R̅E̅Q̅
+ TC_MSG = 0x04, // assert M̅S̅G̅
+ TC_CD = 0x02, // assert C̅/D
+ TC_IO = 0x01, // assert I̅/O
+
+ TC_PHASE = 0x07,
+ };
+ enum csstat_mask : u8
+ {
+ ST_RST = 0x80,
+ ST_BSY = 0x40,
+ ST_REQ = 0x20,
+ ST_MSG = 0x10,
+ ST_CD = 0x08,
+ ST_IO = 0x04,
+ ST_SEL = 0x02,
+ ST_DBP = 0x01,
+ };
+ enum bas_mask : u8
+ {
+ BAS_ENDOFDMA = 0x80,
+ BAS_DMAREQUEST = 0x40,
+ BAS_PARITYERROR = 0x20,
+ BAS_IRQACTIVE = 0x10,
+ BAS_PHASEMATCH = 0x08,
+ BAS_BUSYERROR = 0x04,
+ BAS_ATN = 0x02,
+ BAS_ACK = 0x01,
+ };
+
+ devcb_write_line m_irq_handler;
+ devcb_write_line m_drq_handler;
+
+ // state machine
+ emu_timer *m_state_timer;
+ enum state : uint32_t
+ {
+ IDLE,
+
+ // arbitration
+ ARB_BUS_FREE,
+ ARB_START,
+ ARB_EVALUATE,
+
+ // dma transfer
+ DMA_IN_REQ,
+ DMA_IN_ACK,
+ DMA_OUT_REQ,
+ DMA_OUT_DRQ,
+ DMA_OUT_ACK,
+ }
+ m_state;
+
+ // registers
+ u8 m_odata;
+ u8 m_icmd;
+ u8 m_mode;
+ u8 m_tcmd;
+ u8 m_bas;
+ u8 m_idata;
+
+ // line state
+ u32 m_scsi_ctrl;
+ bool m_irq_state;
+ bool m_drq_state;
+
+ bool const m_has_lbs;
+};
+
+class ncr53c80_device : public ncr5380_device
+{
+public:
+ ncr53c80_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
+};
+
+class cxd1180_device : public ncr5380_device
+{
+public:
+ cxd1180_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
};
-// device type definition
DECLARE_DEVICE_TYPE(NCR5380, ncr5380_device)
+DECLARE_DEVICE_TYPE(NCR53C80, ncr53c80_device)
+DECLARE_DEVICE_TYPE(CXD1180, cxd1180_device)
#endif // MAME_MACHINE_NCR5380_H
diff --git a/src/devices/machine/ncr5380n.cpp b/src/devices/machine/ncr5380n.cpp
deleted file mode 100644
index 3f107db84cd..00000000000
--- a/src/devices/machine/ncr5380n.cpp
+++ /dev/null
@@ -1,666 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Patrick Mackinlay
-
-/*
- * NCR 5380 and 53C80, aka Zilog Z5380, AMD Am5380, Sony CXD1180 and others.
- *
- * Sources:
- * - http://bitsavers.org/components/ncr/scsi/SP-1051_NCR_5380-53C80_SCSI_Interface_Chip_Design_Manual_Mar86.pdf
- *
- * TODO:
- * - target mode
- * - cxd1180 enhancements
- */
-
-#include "emu.h"
-#include "ncr5380n.h"
-
-#define LOG_GENERAL (1U << 0)
-#define LOG_REGW (1U << 1)
-#define LOG_REGR (1U << 2)
-#define LOG_SCSI (1U << 3)
-#define LOG_ARB (1U << 4)
-#define LOG_DMA (1U << 5)
-
-//#define VERBOSE (LOG_GENERAL|LOG_REGW|LOG_REGR|LOG_SCSI|LOG_ARB|LOG_DMA)
-#include "logmacro.h"
-
-DEFINE_DEVICE_TYPE(NCR5380N, ncr5380n_device, "ncr5380_new", "NCR 5380 SCSI (new)")
-DEFINE_DEVICE_TYPE(NCR53C80, ncr53c80_device, "ncr53c80", "NCR 53C80 SCSI")
-DEFINE_DEVICE_TYPE(CXD1180, cxd1180_device, "cxd1180", "Sony CXD1180")
-
-ALLOW_SAVE_TYPE(ncr5380n_device::state);
-
-ncr5380n_device::ncr5380n_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, bool has_lbs)
- : nscsi_device(mconfig, type, tag, owner, clock)
- , nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF)
- , m_irq_handler(*this)
- , m_drq_handler(*this)
- , m_has_lbs(has_lbs)
-{
-}
-
-ncr5380n_device::ncr5380n_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
- : ncr5380n_device(mconfig, NCR5380N, tag, owner, clock)
-{
-}
-
-ncr53c80_device::ncr53c80_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
- : ncr5380n_device(mconfig, NCR53C80, tag, owner, clock, true)
-{
-}
-
-cxd1180_device::cxd1180_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
- : ncr5380n_device(mconfig, CXD1180, tag, owner, clock, true)
-{
-}
-
-void ncr5380n_device::map(address_map &map)
-{
- map(0x0, 0x0).rw(FUNC(ncr5380n_device::csdata_r), FUNC(ncr5380n_device::odata_w));
- map(0x1, 0x1).rw(FUNC(ncr5380n_device::icmd_r), FUNC(ncr5380n_device::icmd_w));
- map(0x2, 0x2).rw(FUNC(ncr5380n_device::mode_r), FUNC(ncr5380n_device::mode_w));
- map(0x3, 0x3).rw(FUNC(ncr5380n_device::tcmd_r), FUNC(ncr5380n_device::tcmd_w));
- map(0x4, 0x4).rw(FUNC(ncr5380n_device::csstat_r), FUNC(ncr5380n_device::selen_w));
- map(0x5, 0x5).rw(FUNC(ncr5380n_device::bas_r), FUNC(ncr5380n_device::sds_w));
- map(0x6, 0x6).rw(FUNC(ncr5380n_device::idata_r), FUNC(ncr5380n_device::sdtr_w));
- map(0x7, 0x7).rw(FUNC(ncr5380n_device::rpi_r), FUNC(ncr5380n_device::sdir_w));
-}
-
-void ncr5380n_device::device_start()
-{
- m_irq_handler.resolve_safe();
- m_drq_handler.resolve_safe();
-
- m_state_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ncr5380n_device::state_timer), this));
-
- save_item(NAME(m_state));
-
- save_item(NAME(m_odata));
- save_item(NAME(m_icmd));
- save_item(NAME(m_mode));
- save_item(NAME(m_tcmd));
- save_item(NAME(m_bas));
- save_item(NAME(m_idata));
-
- save_item(NAME(m_scsi_ctrl));
- save_item(NAME(m_irq_state));
- save_item(NAME(m_drq_state));
-}
-
-void ncr5380n_device::device_reset()
-{
- m_state = IDLE;
-
- // clear registers
- m_odata = 0;
- m_icmd = 0;
- m_mode = 0;
- m_tcmd = 0;
- m_bas = 0;
- m_idata = 0;
-
- // clear scsi bus
- scsi_bus->data_w(scsi_refid, 0);
- scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
-
- // monitor all control lines
- m_scsi_ctrl = 0;
- scsi_bus->ctrl_wait(scsi_refid, S_ALL, S_ALL);
-
- // clear output lines
- set_irq(false);
- set_drq(false);
-}
-
-void ncr5380n_device::scsi_ctrl_changed()
-{
- u32 const ctrl = scsi_bus->ctrl_r();
-
- if (VERBOSE & LOG_SCSI)
- {
- static char const *const nscsi_phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "*", "*", "MESSAGE OUT", "MESSAGE IN" };
-
- if (ctrl & S_RST)
- LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x BUS RESET\n", ctrl);
- else if ((ctrl & S_BSY) && !(ctrl & S_SEL))
- LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x phase %s%s%s\n", ctrl, nscsi_phase[ctrl & S_PHASE_MASK],
- ctrl & S_REQ ? " REQ" : "", ctrl & S_ACK ? " ACK" : "");
- else if (ctrl & S_BSY)
- LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x arbitration/selection\n", ctrl);
- else
- LOGMASKED(LOG_SCSI, "scsi_ctrl_changed 0x%x BUS FREE\n", ctrl);
- }
-
- m_bas &= ~BAS_BUSYERROR;
-
- if (ctrl & S_RST)
- {
- LOG("scsi reset received\n");
- device_reset();
-
- set_irq(true);
- }
- else if (!(m_mode & MODE_TARGET) && (m_scsi_ctrl & S_BSY) && !(ctrl & S_BSY))
- {
- LOG("target disconnected\n");
- m_icmd &= (IC_RST | IC_AIP);
-
- if (m_mode & MODE_DMA)
- {
- // stop dma
- m_mode &= ~MODE_DMA;
- m_bas &= ~BAS_ENDOFDMA;
-
- set_drq(false);
- }
-
- if (m_mode & MODE_BSYIRQ)
- {
- m_bas |= BAS_BUSYERROR;
-
- set_irq(true);
- }
-
- m_state = IDLE;
- m_state_timer->enable(false);
-
- // clear scsi bus
- scsi_bus->data_w(scsi_refid, 0);
- scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
- }
- else if (!(m_scsi_ctrl & S_REQ) && (ctrl & S_REQ))
- {
- // target asserted REQ
- if (m_mode & MODE_DMA)
- {
- if ((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE))
- {
- // transfer cycle
- if (m_state != IDLE && !m_state_timer->enabled())
- m_state_timer->adjust(attotime::zero);
- }
- else
- {
- LOG("phase mismatch %d != %d\n", (ctrl & S_PHASE_MASK), (m_tcmd & TC_PHASE));
- m_state_timer->enable(false);
-
- set_irq(true);
- }
- }
- }
-
- m_scsi_ctrl = ctrl;
-}
-
-u8 ncr5380n_device::csdata_r()
-{
- u8 const data = scsi_bus->data_r();
- LOGMASKED(LOG_REGR, "csdata_r 0x%02x (%s)\n", data, machine().describe_context());
-
- return data;
-}
-
-void ncr5380n_device::odata_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "odata_w 0x%02x (%s)\n", data, machine().describe_context());
-
- // drive scsi data
- if (m_icmd & IC_DBUS)
- scsi_data_w(data);
-
- m_odata = data;
-}
-
-u8 ncr5380n_device::icmd_r()
-{
- LOGMASKED(LOG_REGR, "icmd_r 0x%02x (%s)\n", m_icmd, machine().describe_context());
-
- return m_icmd;
-}
-
-void ncr5380n_device::icmd_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "icmd_w 0x%02x (%s)\n", data, machine().describe_context());
-
- if (!(data & IC_RST))
- {
- // drive scsi data
- if ((data ^ m_icmd) & IC_DBUS)
- scsi_data_w((data & IC_DBUS) ? m_odata : 0);
-
- // check for control line changes
- if ((data & IC_PHASE) ^ (m_icmd & IC_PHASE))
- {
- u32 const mask = (m_mode & MODE_TARGET) ?
- (S_RST | S_BSY | S_SEL) :
- (S_RST | S_ACK | S_BSY | S_SEL | S_ATN);
-
- // translate to nscsi
- u32 const ctrl =
- (data & IC_RST ? S_RST : 0) |
- (data & IC_ACK ? S_ACK : 0) |
- (data & IC_BSY ? S_BSY : 0) |
- (data & IC_SEL ? S_SEL : 0) |
- (data & IC_ATN ? S_ATN : 0);
-
- LOGMASKED(LOG_SCSI, "changing control lines 0x%04x\n", ctrl);
- scsi_bus->ctrl_w(scsi_refid, ctrl, mask);
- }
- }
- else
- {
- LOG("scsi reset issued\n");
- device_reset();
- scsi_bus->ctrl_w(scsi_refid, S_RST, S_RST);
-
- set_irq(true);
- }
-
- m_icmd = (m_icmd & ~IC_WRITE) | (data & IC_WRITE);
-}
-
-u8 ncr5380n_device::mode_r()
-{
- LOGMASKED(LOG_REGR, "mode_r 0x%02x (%s)\n", m_mode, machine().describe_context());
-
- return m_mode;
-}
-
-void ncr5380n_device::mode_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "mode_w 0x%02x (%s)\n", data, machine().describe_context());
-
- if (!(data & MODE_BSYIRQ))
- m_bas &= ~BAS_BUSYERROR;
-
- // disable dma
- if ((m_mode & MODE_DMA) && !(data & MODE_DMA))
- {
- m_state = IDLE;
- m_state_timer->enable(false);
-
- m_bas &= ~BAS_ENDOFDMA;
-
- if (m_has_lbs)
- m_tcmd &= ~TC_LBS;
-
- set_drq(false);
-
- // clear ACK
- scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
- }
-
- // start/stop arbitration
- if ((m_mode ^ data) & MODE_ARBITRATE)
- {
- if (data & MODE_ARBITRATE)
- {
- // start arbitration
- m_icmd &= ~IC_LA;
- m_state = ARB_BUS_FREE;
- m_state_timer->adjust(attotime::zero);
- }
- else
- {
- // stop arbitration
- m_state = IDLE;
- m_icmd &= ~(IC_AIP | IC_LA);
- }
- }
-
- m_mode = data;
-}
-
-u8 ncr5380n_device::tcmd_r()
-{
- LOGMASKED(LOG_REGR, "tcmd_r 0x%02x (%s)\n", m_tcmd, machine().describe_context());
-
- return m_tcmd;
-}
-
-void ncr5380n_device::tcmd_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "tcmd_w 0x%02x (%s)\n", data, machine().describe_context());
-
- if (m_has_lbs)
- m_tcmd = (m_tcmd & TC_LBS) | (data & ~TC_LBS);
- else
- m_tcmd = data;
-}
-
-u8 ncr5380n_device::csstat_r()
-{
- u32 const ctrl = scsi_bus->ctrl_r();
- u8 const data =
- (ctrl & S_RST ? ST_RST : 0) |
- (ctrl & S_BSY ? ST_BSY : 0) |
- (ctrl & S_REQ ? ST_REQ : 0) |
- (ctrl & S_MSG ? ST_MSG : 0) |
- (ctrl & S_CTL ? ST_CD : 0) |
- (ctrl & S_INP ? ST_IO : 0) |
- (ctrl & S_SEL ? ST_SEL : 0);
-
- LOGMASKED(LOG_REGR, "csstat_r 0x%02x (%s)\n", data, machine().describe_context());
- return data;
-}
-
-void ncr5380n_device::selen_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "selen_w 0x%02x (%s)\n", data, machine().describe_context());
-}
-
-u8 ncr5380n_device::bas_r()
-{
- u32 const ctrl = scsi_bus->ctrl_r();
- u8 const data = m_bas |
- (((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE)) ? BAS_PHASEMATCH : 0) |
- (ctrl & S_ATN ? BAS_ATN : 0) |
- (ctrl & S_ACK ? BAS_ACK : 0);
-
- LOGMASKED(LOG_REGR, "bas_r 0x%02x (%s)\n", data, machine().describe_context());
-
- return data;
-}
-
-void ncr5380n_device::sds_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "sds_w 0x%02x (%s)\n", data, machine().describe_context());
-
- if (m_mode & MODE_DMA)
- {
- m_state = DMA_OUT_DRQ;
- m_state_timer->adjust(attotime::zero);
- }
-}
-
-u8 ncr5380n_device::idata_r()
-{
- LOGMASKED(LOG_REGR, "idata_r 0x%02x (%s)\n", m_idata, machine().describe_context());
-
- return m_idata;
-}
-
-void ncr5380n_device::sdtr_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "sdtr_w 0x%02x (%s)\n", data, machine().describe_context());
-}
-
-u8 ncr5380n_device::rpi_r()
-{
- LOGMASKED(LOG_REGR, "rpi_r (%s)\n", machine().describe_context());
-
- m_bas &= ~(BAS_PARITYERROR | BAS_BUSYERROR);
- set_irq(false);
-
- return 0;
-}
-
-void ncr5380n_device::sdir_w(u8 data)
-{
- LOGMASKED(LOG_REGW, "sdir_w 0x%02x (%s)\n", data, machine().describe_context());
-
- if ((m_mode & MODE_DMA) && !(m_mode & MODE_TARGET))
- {
- m_state = DMA_IN_REQ;
- m_state_timer->adjust(attotime::zero);
- }
-}
-
-void ncr5380n_device::state_timer(void *ptr, s32 param)
-{
- // step state machine
- int const delay = state_step();
-
- // check for data stall
- if (delay < 0)
- return;
-
- // repeat until idle
- if (m_state != IDLE)
- m_state_timer->adjust(attotime::from_nsec(delay));
-}
-
-int ncr5380n_device::state_step()
-{
- u32 const ctrl = scsi_bus->ctrl_r();
- int delay = 0;
-
- switch (m_state)
- {
- case IDLE:
- break;
-
- case ARB_BUS_FREE:
- if (!(ctrl & (S_SEL | S_BSY | S_RST)))
- {
- LOGMASKED(LOG_ARB, "arbitration: bus free\n");
- // FIXME: AIP should only be set when arbitration begins
- m_icmd |= IC_AIP;
- m_state = ARB_START;
- delay = 1700;
- }
- else
- {
- LOGMASKED(LOG_ARB, "arbitration: bus not free\n");
- m_state = IDLE;
- }
- break;
- case ARB_START:
- LOGMASKED(LOG_ARB, "arbitration: started\n");
- m_icmd |= IC_BSY;
- m_state = ARB_EVALUATE;
- delay = 2200;
-
- // assert own ID and BSY
- scsi_bus->data_w(scsi_refid, m_odata);
- scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY);
- break;
- case ARB_EVALUATE:
- // check if SEL asserted, or if there's a higher ID on the bus
- if ((ctrl & S_SEL) || (scsi_bus->data_r() & ~((m_odata - 1) | m_odata)))
- {
- LOGMASKED(LOG_ARB, "arbitration: lost\n");
- m_icmd &= ~IC_BSY;
- m_icmd |= IC_LA;
-
- m_state = IDLE;
-
- // clear data and BSY
- scsi_bus->data_w(scsi_refid, 0);
- scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
- }
- else
- {
- LOGMASKED(LOG_ARB, "arbitration: won\n");
- m_state = IDLE;
- }
- break;
-
- case DMA_IN_REQ:
- if (ctrl & S_REQ)
- {
- if ((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE))
- {
- m_idata = scsi_bus->data_r();
- LOGMASKED(LOG_DMA, "dma in: 0x%02x\n", m_idata);
-
- m_state = DMA_IN_ACK;
- set_drq(true);
-
- // assert ACK
- scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
- }
-
- delay = -1;
- }
- break;
- case DMA_IN_ACK:
- if (!(ctrl & S_REQ))
- {
- m_state = (m_bas & BAS_ENDOFDMA) ? IDLE : DMA_IN_REQ;
-
- // clear ACK
- scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
- }
- break;
-
- case DMA_OUT_DRQ:
- m_state = DMA_OUT_REQ;
- set_drq(true);
-
- delay = -1;
- break;
- case DMA_OUT_REQ:
- if (ctrl & S_REQ)
- {
- if ((ctrl & S_PHASE_MASK) == (m_tcmd & TC_PHASE))
- {
- LOGMASKED(LOG_DMA, "dma out: 0x%02x\n", m_odata);
-
- m_state = DMA_OUT_ACK;
-
- // assert data and ACK
- scsi_bus->data_w(scsi_refid, m_odata);
- scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
- }
- }
- break;
- case DMA_OUT_ACK:
- if (!(ctrl & S_REQ))
- {
- if (m_bas & BAS_ENDOFDMA)
- {
- m_state = IDLE;
-
- if (m_has_lbs)
- m_tcmd |= TC_LBS;
- }
- else
- m_state = DMA_OUT_DRQ;
-
- // clear data and ACK
- scsi_bus->data_w(scsi_refid, 0);
- scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
- }
- break;
- }
-
- return delay;
-}
-
-void ncr5380n_device::eop_w(int state)
-{
- LOGMASKED(LOG_DMA, "eop_w %d\n", state);
- if (state && (m_mode & MODE_DMA))
- {
- m_bas |= BAS_ENDOFDMA;
-
- if (m_mode & MODE_EOPIRQ)
- {
- // FIXME: should only trigger when combined with dma_r/dma_w
- LOG("eop irq asserted\n");
-
- set_irq(true);
- }
- }
-}
-
-void ncr5380n_device::dma_w(u8 data)
-{
- set_drq(false);
-
- if (m_mode & MODE_DMA)
- {
- m_odata = data;
-
- m_state_timer->adjust(attotime::zero);
- }
-}
-
-u8 ncr5380n_device::dma_r()
-{
- set_drq(false);
-
- if (m_mode & MODE_DMA)
- m_state_timer->adjust(attotime::zero);
-
- return m_idata;
-}
-
-void ncr5380n_device::scsi_data_w(u8 data)
-{
- // TODO: release data bus when any of the prerequisite conditions expire
- u32 const ctrl = scsi_bus->ctrl_r();
-
- if ((m_mode & MODE_TARGET) || (!(ctrl & S_INP) && (ctrl & S_PHASE_MASK) == (m_tcmd & S_PHASE_MASK)))
- {
- LOGMASKED(LOG_SCSI, "scsi data 0x%02x\n", data);
- scsi_bus->data_w(scsi_refid, data);
- }
-}
-
-void ncr5380n_device::set_irq(bool irq_state)
-{
- if (irq_state != m_irq_state)
- {
- LOG("set_irq %d\n", irq_state);
-
- if (irq_state)
- m_bas |= BAS_IRQACTIVE;
- else
- m_bas &= ~BAS_IRQACTIVE;
-
- m_irq_state = irq_state;
- m_irq_handler(m_irq_state);
- }
-}
-
-void ncr5380n_device::set_drq(bool drq_state)
-{
- if (drq_state != m_drq_state)
- {
- LOGMASKED(LOG_DMA, "set_drq %d\n", drq_state);
-
- if (drq_state)
- m_bas |= BAS_DMAREQUEST;
- else
- m_bas &= ~BAS_DMAREQUEST;
-
- m_drq_state = drq_state;
- m_drq_handler(m_drq_state);
- }
-}
-
-u8 ncr5380n_device::read(offs_t offset)
-{
- switch (offset & 7)
- {
- case 0: return csdata_r();
- case 1: return icmd_r();
- case 2: return mode_r();
- case 3: return tcmd_r();
- case 4: return csstat_r();
- case 5: return bas_r();
- case 6: return idata_r();
- case 7: return rpi_r();
- }
-
- // can't happen
- return 0;
-}
-
-void ncr5380n_device::write(offs_t offset, u8 data)
-{
- switch (offset & 7)
- {
- case 0: odata_w(data); break;
- case 1: icmd_w(data); break;
- case 2: mode_w(data); break;
- case 3: tcmd_w(data); break;
- case 4: selen_w(data); break;
- case 5: sds_w(data); break;
- case 6: sdtr_w(data); break;
- case 7: sdir_w(data); break;
- }
-}
diff --git a/src/devices/machine/ncr5380n.h b/src/devices/machine/ncr5380n.h
deleted file mode 100644
index fbbf9cba616..00000000000
--- a/src/devices/machine/ncr5380n.h
+++ /dev/null
@@ -1,186 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Patrick Mackinlay
-
-#ifndef MAME_MACHINE_NCR5380N_H
-#define MAME_MACHINE_NCR5380N_H
-
-#pragma once
-
-#include "machine/nscsi_bus.h"
-
-class ncr5380n_device
- : public nscsi_device
- , public nscsi_slot_card_interface
-{
-public:
- ncr5380n_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
-
- // device configuration
- auto irq_handler() { return m_irq_handler.bind(); }
- auto drq_handler() { return m_drq_handler.bind(); }
-
- // register access
- void map(address_map &map);
- u8 read(offs_t offset);
- void write(offs_t offset, u8 data);
-
- // dma access
- void eop_w(int state);
- u8 dma_r();
- void dma_w(u8 val);
-
-protected:
- ncr5380n_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, bool has_lbs = false);
-
- // device_t overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
- // ncsci_device overrides
- virtual void scsi_ctrl_changed() override;
-
- // register read handlers
- u8 csdata_r();
- u8 icmd_r();
- u8 mode_r();
- u8 tcmd_r();
- u8 csstat_r();
- u8 bas_r();
- u8 idata_r();
- u8 rpi_r();
-
- // register write handlers
- void odata_w(u8 data);
- void icmd_w(u8 data);
- void mode_w(u8 data);
- void tcmd_w(u8 data);
- void selen_w(u8 data);
- void sds_w(u8 data);
- void sdtr_w(u8 data);
- void sdir_w(u8 data);
-
- // state machine
- void state_timer(void *ptr, s32 param);
- int state_step();
-
- // other helpers
- void scsi_data_w(u8 data);
- void set_irq(bool irq_state);
- void set_drq(bool drq_state);
-
-private:
- enum icmd_mask : u8
- {
- IC_RST = 0x80, // assert R̅S̅T̅
- IC_TEST = 0x40, // test mode (wo)
- IC_AIP = 0x40, // arbitration in progress (ro)
- IC_LA = 0x20, // lost arbitration (ro)
- IC_ACK = 0x10, // assert A̅C̅K̅
- IC_BSY = 0x08, // assert B̅S̅Y̅
- IC_SEL = 0x04, // assert S̅E̅L̅
- IC_ATN = 0x02, // assert A̅T̅N̅
- IC_DBUS = 0x01, // assert data bus
-
- IC_PHASE = 0x9e,
- IC_WRITE = 0x9f,
- };
- enum mode_mask : u8
- {
- MODE_BLOCKDMA = 0x80,
- MODE_TARGET = 0x40,
- MODE_PARITYCHK = 0x20,
- MODE_PARITYIRQ = 0x10,
- MODE_EOPIRQ = 0x08,
- MODE_BSYIRQ = 0x04,
- MODE_DMA = 0x02,
- MODE_ARBITRATE = 0x01,
- };
- enum tcmd_mask : u8
- {
- TC_LBS = 0x80, // last byte sent
- TC_REQ = 0x08, // assert R̅E̅Q̅
- TC_MSG = 0x04, // assert M̅S̅G̅
- TC_CD = 0x02, // assert C̅/D
- TC_IO = 0x01, // assert I̅/O
-
- TC_PHASE = 0x07,
- };
- enum csstat_mask : u8
- {
- ST_RST = 0x80,
- ST_BSY = 0x40,
- ST_REQ = 0x20,
- ST_MSG = 0x10,
- ST_CD = 0x08,
- ST_IO = 0x04,
- ST_SEL = 0x02,
- ST_DBP = 0x01,
- };
- enum bas_mask : u8
- {
- BAS_ENDOFDMA = 0x80,
- BAS_DMAREQUEST = 0x40,
- BAS_PARITYERROR = 0x20,
- BAS_IRQACTIVE = 0x10,
- BAS_PHASEMATCH = 0x08,
- BAS_BUSYERROR = 0x04,
- BAS_ATN = 0x02,
- BAS_ACK = 0x01,
- };
-
- devcb_write_line m_irq_handler;
- devcb_write_line m_drq_handler;
-
- // state machine
- emu_timer *m_state_timer;
- enum state : uint32_t
- {
- IDLE,
-
- // arbitration
- ARB_BUS_FREE,
- ARB_START,
- ARB_EVALUATE,
-
- // dma transfer
- DMA_IN_REQ,
- DMA_IN_ACK,
- DMA_OUT_REQ,
- DMA_OUT_DRQ,
- DMA_OUT_ACK,
- }
- m_state;
-
- // registers
- u8 m_odata;
- u8 m_icmd;
- u8 m_mode;
- u8 m_tcmd;
- u8 m_bas;
- u8 m_idata;
-
- // line state
- u32 m_scsi_ctrl;
- bool m_irq_state;
- bool m_drq_state;
-
- bool const m_has_lbs;
-};
-
-class ncr53c80_device : public ncr5380n_device
-{
-public:
- ncr53c80_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
-};
-
-class cxd1180_device : public ncr5380n_device
-{
-public:
- cxd1180_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
-};
-
-DECLARE_DEVICE_TYPE(NCR5380N, ncr5380n_device)
-DECLARE_DEVICE_TYPE(NCR53C80, ncr53c80_device)
-DECLARE_DEVICE_TYPE(CXD1180, cxd1180_device)
-
-#endif // MAME_MACHINE_NCR5380N_H
diff --git a/src/devices/machine/ncr5385.cpp b/src/devices/machine/ncr5385.cpp
index 6c1f4a3bb4e..fe76078fa95 100644
--- a/src/devices/machine/ncr5385.cpp
+++ b/src/devices/machine/ncr5385.cpp
@@ -1,120 +1,841 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
-/***********************************************************************
- NCR 5385E SCSI Controller
-
- TOOD:
- - Everything.
-
-***********************************************************************/
+/*
+ * NCR 5385 SCSI Protocol Controller
+ *
+ * Sources:
+ * - NCR 5385 SCSI Protocol Controller, 1983, NCR Corporation, Dayton, Ohio, USA
+ * - NCR SCSI Engineering Notebook, 1984, NCR Microelectronics
+ *
+ * TODO:
+ * - target mode send/receive
+ * - disconnect/reselection
+ */
#include "emu.h"
#include "ncr5385.h"
-DEFINE_DEVICE_TYPE(NCR5385, ncr5385_device, "ncr5385", "NCR 5385E SCSI Controller")
+#define LOG_GENERAL (1U << 0)
+#define LOG_REGW (1U << 1)
+#define LOG_REGR (1U << 2)
+#define LOG_STATE (1U << 3)
+#define LOG_DMA (1U << 4)
+#define LOG_COMMAND (1U << 5)
+
+//#define VERBOSE (LOG_GENERAL|LOG_REGW|LOG_REGR|LOG_STATE|LOG_DMA|LOG_COMMAND)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(NCR5385, ncr5385_device, "ncr5385", "NCR 5385 SCSI Protocol Controller")
-ncr5385_device::ncr5385_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, NCR5385, tag, owner, clock)
+// FIXME: would be better to reuse from nscsi_full_device
+unsigned constexpr SCSI_ARB_DELAY = 2'400;
+unsigned constexpr SCSI_BUS_CLEAR = 800;
+unsigned constexpr SCSI_BUS_FREE = 800;
+unsigned constexpr SCSI_BUS_SETTLE = 400;
+unsigned constexpr SCSI_BUS_SKEW = 10;
+unsigned constexpr SCSI_RST_HOLD = 25'000;
+unsigned constexpr SCSI_SEL_TIMEOUT = 250'000'000;
+
+ncr5385_device::ncr5385_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : nscsi_device(mconfig, NCR5385, tag, owner, clock)
+ , nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF)
, m_int(*this)
+ , m_dreq(*this)
+ , m_int_state(false)
+ , m_dreq_state(false)
{
}
+enum state : u32
+{
+ IDLE,
+ DIAGNOSTIC,
+
+ ARB_BUS_FREE,
+ ARB_START,
+ ARB_EVALUATE,
+ SEL_START,
+ SEL_DELAY,
+ SEL_WAIT_BSY,
+ SEL_COMPLETE,
+ SEL_WAIT_REQ,
+
+ XFI_START,
+ XFI_IN_REQ,
+ XFI_IN_DRQ,
+ XFI_IN_ACK,
+ XFI_OUT_REQ,
+ XFI_OUT_DRQ,
+ XFI_OUT_ACK,
+ XFI_OUT_PAD,
+};
+
+enum mode : u8
+{
+ DISCONNECTED,
+ INITIATOR,
+ TARGET,
+};
+
+enum diag_mask : u8
+{
+ DIAG_SELF = 0x07, // self-diagnostic status
+ DIAG_CMD = 0x38, // diagnostic command status
+ DIAG_DONE = 0x80, // self-diagnostic complete
+
+ DIAG_CMD_GP = 0x18, // diagnostic good parity
+ DIAG_CMD_BP = 0x20, // diagnostic bad parity
+};
+
+enum int_mask : u8
+{
+ INT_FUNC_COMPLETE = 0x01,
+ INT_BUS_SERVICE = 0x02,
+ INT_DISCONNECTED = 0x04,
+ INT_SELECTED = 0x08,
+ INT_RESELECTED = 0x10,
+ INT_INVALID_CMD = 0x40,
+};
+
+enum aux_status_mask : u8
+{
+ AUX_STATUS_TC_ZERO = 0x02,
+ AUX_STATUS_PAUSED = 0x04,
+ AUX_STATUS_IO = 0x08,
+ AUX_STATUS_CD = 0x10,
+ AUX_STATUS_MSG = 0x20,
+ AUX_STATUS_PARITY_ERR = 0x40,
+ AUX_STATUS_DATA_FULL = 0x80,
+};
+
+enum cmd_mask : u8
+{
+ CMD_INT = 0x08, // interrupting
+ CMD_SBX = 0x40, // single byte transfer
+ CMD_DMA = 0x80, // DMA mode
+};
+
void ncr5385_device::device_start()
{
- m_int.resolve_safe();
+ save_item(NAME(m_dat));
+ save_item(NAME(m_cmd));
+ save_item(NAME(m_ctl));
+ save_item(NAME(m_dst_id));
+ save_item(NAME(m_aux_status));
+ save_item(NAME(m_own_id));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_src_id));
+ save_item(NAME(m_dia_status));
+ save_item(NAME(m_cnt));
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_phase));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_sbx));
+
+ save_item(NAME(m_int_state));
+ save_item(NAME(m_dreq_state));
+
+ m_state_timer = timer_alloc(timer_expired_delegate(FUNC(ncr5385_device::state_timer), this));
+
+ m_dia_status = DIAG_DONE;
}
void ncr5385_device::device_reset()
{
- m_state = STATE_IDLE;
- m_int_reg = 0;
- m_ctrl_reg = 0;
- m_aux_status_reg = AUX_STATUS_TC_ZERO;
- m_diag_status_reg = DIAG_COMPLETE;
+ m_cmd = 0;
+ m_ctl = 0;
+ m_dst_id = 0;
+ m_aux_status = AUX_STATUS_TC_ZERO;
+ m_int_status = 0;
+ m_src_id = 0;
+ m_dia_status &= (DIAG_DONE | DIAG_SELF);
+ m_cnt = 0;
+
+ m_state = IDLE;
+ m_mode = DISCONNECTED;
+ m_sbx = false;
+
+ // monitor all control lines (device has no RST line)
+ scsi_bus->ctrl_wait(scsi_refid, S_ALL & ~S_RST, S_ALL & ~S_RST);
+
+ update_int();
}
-void ncr5385_device::write(offs_t offset, uint8_t data)
+void ncr5385_device::scsi_ctrl_changed()
{
- switch (offset)
+ u32 const ctrl = scsi_bus->ctrl_r();
+
+ static char const *const nscsi_phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "*", "*", "MESSAGE OUT", "MESSAGE IN" };
+
+ if ((ctrl & S_BSY) && !(ctrl & S_SEL))
{
- case 0x0: // Data Register
- switch (m_state)
- {
- case STATE_DIAGNOSTIC_GOOD_PARITY:
- m_aux_status_reg &= ~AUX_STATUS_PARITY_ERR;
- m_aux_status_reg |= AUX_STATUS_DATA_FULL;
- m_int_reg = INT_FUNC_COMPLETE;
- m_diag_status_reg = DIAG_COMPLETE | DIAG_TURN_GOOD_PARITY;
- m_state = STATE_IDLE;
- m_int(1);
- logerror("%s: ncr5385_w: data=%02x (diagnostic w/ good parity)\n", machine().describe_context(), data);
- break;
- case STATE_DIAGNOSTIC_BAD_PARITY:
- m_aux_status_reg |= AUX_STATUS_PARITY_ERR | AUX_STATUS_DATA_FULL;
- m_int_reg = INT_FUNC_COMPLETE;
- m_diag_status_reg = DIAG_COMPLETE | DIAG_TURN_BAD_PARITY;
- m_state = STATE_IDLE;
- m_int(1);
- logerror("%s: ncr5385_w: data=%02x (diagnostic w/ bad parity)\n", machine().describe_context(), data);
- break;
- default:
- logerror("%s: ncr5385_w: data=%02x\n", machine().describe_context(), data);
- break;
- }
+ LOGMASKED(LOG_STATE, "scsi_ctrl_changed 0x%03x phase %s%s%s\n", ctrl, nscsi_phase[ctrl & S_PHASE_MASK],
+ ctrl & S_REQ ? " REQ" : "", ctrl & S_ACK ? " ACK" : "");
+
+ if (m_state != IDLE)
+ m_state_timer->adjust(attotime::zero);
+ }
+ else if (ctrl & S_BSY)
+ LOGMASKED(LOG_STATE, "scsi_ctrl_changed 0x%03x arbitration/selection\n", ctrl);
+ else
+ {
+ LOGMASKED(LOG_STATE, "scsi_ctrl_changed 0x%03x BUS FREE\n", ctrl);
+
+ if (m_mode == INITIATOR)
+ {
+ m_mode = DISCONNECTED;
+ m_int_status |= INT_DISCONNECTED;
+ update_int();
+ }
+ }
+}
+
+void ncr5385_device::map(address_map &map)
+{
+ map(0x0, 0x0).rw(FUNC(ncr5385_device::dat_r), FUNC(ncr5385_device::dat_w));
+ map(0x1, 0x1).rw(FUNC(ncr5385_device::cmd_r), FUNC(ncr5385_device::cmd_w));
+ map(0x2, 0x2).rw(FUNC(ncr5385_device::ctl_r), FUNC(ncr5385_device::ctl_w));
+ map(0x3, 0x3).rw(FUNC(ncr5385_device::dst_id_r), FUNC(ncr5385_device::dst_id_w));
+ map(0x4, 0x4).r(FUNC(ncr5385_device::aux_status_r));
+ map(0x5, 0x5).r(FUNC(ncr5385_device::own_id_r));
+ map(0x6, 0x6).r(FUNC(ncr5385_device::int_status_r));
+ map(0x7, 0x7).r(FUNC(ncr5385_device::src_id_r));
+ map(0x9, 0x9).r(FUNC(ncr5385_device::dia_status_r));
+ map(0xc, 0xc).rw(FUNC(ncr5385_device::cnt_r<2>), FUNC(ncr5385_device::cnt_w<2>));
+ map(0xd, 0xd).rw(FUNC(ncr5385_device::cnt_r<1>), FUNC(ncr5385_device::cnt_w<1>));
+ map(0xe, 0xe).rw(FUNC(ncr5385_device::cnt_r<0>), FUNC(ncr5385_device::cnt_w<0>));
+ map(0xf, 0xf).rw(FUNC(ncr5385_device::tst_r), FUNC(ncr5385_device::tst_w));
+}
+
+u8 ncr5385_device::dat_r()
+{
+ if (m_aux_status & AUX_STATUS_DATA_FULL)
+ {
+ m_aux_status &= ~AUX_STATUS_DATA_FULL;
+
+ if (m_state != IDLE)
+ m_state_timer->adjust(attotime::zero);
+ }
+ else
+ logerror("data register empty (%s)\n", machine().describe_context());
+
+ return m_dat;
+}
+
+u8 ncr5385_device::cmd_r()
+{
+ return m_cmd;
+}
+
+u8 ncr5385_device::ctl_r()
+{
+ return m_ctl;
+}
+
+u8 ncr5385_device::dst_id_r()
+{
+ return m_dst_id;
+}
+
+u8 ncr5385_device::aux_status_r()
+{
+ u8 data = m_aux_status;
+
+ if (!m_int_status)
+ {
+ // return current phase
+ u32 const ctrl = scsi_bus->ctrl_r();
+ if (ctrl & S_MSG)
+ data |= AUX_STATUS_MSG;
+ if (ctrl & S_CTL)
+ data |= AUX_STATUS_CD;
+ if (ctrl & S_INP)
+ data |= AUX_STATUS_IO;
+ }
+ LOGMASKED(LOG_REGR, "aux_status_r 0x%02x (%s)\n", data, machine().describe_context());
+
+ return data;
+}
+
+u8 ncr5385_device::own_id_r()
+{
+ return m_own_id;
+}
+
+u8 ncr5385_device::int_status_r()
+{
+ u8 const data = m_int_status;
+ LOGMASKED(LOG_REGR, "int_status_r 0x%02x (%s)\n", data, machine().describe_context());
+ m_aux_status &= ~AUX_STATUS_PARITY_ERR;
+ m_int_status = 0;
+ update_int();
+
+ if (m_state != IDLE)
+ m_state_timer->adjust(attotime::zero);
+
+ return data;
+}
+
+u8 ncr5385_device::src_id_r()
+{
+ return m_src_id;
+}
+
+u8 ncr5385_device::dia_status_r()
+{
+ return m_dia_status;
+}
+
+template <unsigned N> u8 ncr5385_device::cnt_r()
+{
+ return u8(m_cnt >> (N * 8));
+}
+
+u8 ncr5385_device::tst_r()
+{
+ return 0;
+}
+
+void ncr5385_device::dat_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "dat_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ if (!(m_aux_status & AUX_STATUS_DATA_FULL))
+ {
+ m_dat = data;
+ m_aux_status |= AUX_STATUS_DATA_FULL;
+
+ if (m_state != IDLE)
+ m_state_timer->adjust(attotime::zero);
+ }
+ else
+ logerror("data register full\n");
+}
+
+void ncr5385_device::cmd_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "cmd_w 0x%02x (%s)\n", data, machine().describe_context());
+ if (!(data & 0x18))
+ {
+ // immediate commands
+
+ switch (data & 0x1f)
+ {
+ case 0x00:
+ LOGMASKED(LOG_COMMAND, "reset\n");
+ reset();
break;
- case 0x1: // Command Register
- switch (data & 0x3f)
- {
- case 0x00: // Chip Reset
- logerror("%s: ncr5385_w: command: reset\n", machine().describe_context());
- m_state = STATE_IDLE;
- m_int_reg = 0;
- m_aux_status_reg = AUX_STATUS_TC_ZERO;
- m_diag_status_reg = DIAG_COMPLETE;
- m_int(0);
- break;
- case 0x0b: // Diagnostic
- logerror("%s: ncr5385_w: command: diagnostic (%s parity)\n", machine().describe_context(), BIT(data, 6) ? "bad" : "good");
- if (BIT(data, 6))
- m_state = STATE_DIAGNOSTIC_BAD_PARITY;
- else
- m_state = STATE_DIAGNOSTIC_GOOD_PARITY;
- break;
- default:
- logerror("%s: ncr5385_w: command: %02x\n", machine().describe_context(), data);
- break;
- }
+ case 0x01: // disconnect
+ LOGMASKED(LOG_COMMAND, "disconnect\n");
+ m_mode = DISCONNECTED;
+ break;
+ case 0x02: // pause
+ LOGMASKED(LOG_COMMAND, "pause\n");
+ break;
+ case 0x03: // set atn
+ LOGMASKED(LOG_COMMAND, "set atn\n");
+ scsi_bus->ctrl_w(scsi_refid, S_ATN, S_ATN);
+ break;
+ case 0x04: // message accepted
+ LOGMASKED(LOG_COMMAND, "message accepted\n");
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ break;
+ case 0x05: // chip disabled
+ LOGMASKED(LOG_COMMAND, "chip disabled\n");
+ break;
+ case 0x06: case 0x07:
+ // reserved
+ break;
+ }
+ }
+ else
+ {
+ // interrupting commands
+ m_aux_status &= ~AUX_STATUS_DATA_FULL;
+ m_cmd = data;
+
+ switch (data & 0x1f)
+ {
+ case 0x08: // select w/atn
+ LOGMASKED(LOG_COMMAND, "select %d w/atn (timeout %d)\n", m_dst_id, attotime::from_ticks(m_cnt * 1024, clock()).to_string());
+ m_state = ARB_BUS_FREE;
+ m_state_timer->adjust(attotime::zero);
+ break;
+ case 0x09: // select w/o atn
+ LOGMASKED(LOG_COMMAND, "select %d w/o atn (timeout %d)\n", m_dst_id, attotime::from_ticks(m_cnt * 1024, clock()).to_string());
+ m_state = ARB_BUS_FREE;
+ m_state_timer->adjust(attotime::zero);
+ break;
+ case 0x0a: // reselect
+ LOGMASKED(LOG_COMMAND, "reselect\n");
+ break;
+ case 0x0b: // diagnostic
+ LOGMASKED(LOG_COMMAND, "diagnostic (%s parity)\n", BIT(data, 6) ? "bad" : "good");
+ m_state = DIAGNOSTIC;
+ break;
+ case 0x0c: // receive command
+ LOGMASKED(LOG_COMMAND, "receive command\n");
+ break;
+ case 0x0d: // receive data
+ LOGMASKED(LOG_COMMAND, "receive data\n");
break;
- case 0x2: // Control Register
- m_ctrl_reg = data & 0x07;
- logerror("%s: ncr5385_w: control: parity_en=%d, reselect_en=%d, select_en=%d\n", machine().describe_context(), BIT(data, CTRL_PARITY_BIT), BIT(data, CTRL_RESELECT_BIT), BIT(data, CTRL_SELECT_BIT));
+ case 0x0e: // receive message out
+ LOGMASKED(LOG_COMMAND, "receive message out\n");
break;
- default:
- logerror("%s: ncr5385_w: %x=%02x\n", machine().describe_context(), offset, data);
+ case 0x0f: // receive unspecified info out
+ LOGMASKED(LOG_COMMAND, "receive unspecified info out\n");
break;
+ case 0x10: // send status
+ LOGMASKED(LOG_COMMAND, "send status\n");
+ break;
+ case 0x11: // send data
+ LOGMASKED(LOG_COMMAND, "send data\n");
+ break;
+ case 0x12: // send message in
+ LOGMASKED(LOG_COMMAND, "send message in\n");
+ break;
+ case 0x13: // send unspecified info in
+ LOGMASKED(LOG_COMMAND, "send unspecified info in\n");
+ break;
+ case 0x14: // transfer info
+ if (data & CMD_SBX)
+ LOGMASKED(LOG_COMMAND, "transfer info (%s, single byte)\n", (data & CMD_DMA) ? "dma" : "pio");
+ else
+ LOGMASKED(LOG_COMMAND, "transfer info (%s, count=%d)\n", (data & CMD_DMA) ? "dma" : "pio", m_cnt);
+ m_state = XFI_START;
+ m_sbx = data & CMD_SBX;
+ m_state_timer->adjust(attotime::zero);
+ break;
+ case 0x15: // transfer pad
+ if (data & CMD_SBX)
+ LOGMASKED(LOG_COMMAND, "transfer pad (%s, single byte)\n", (data & CMD_DMA) ? "dma" : "pio");
+ else
+ LOGMASKED(LOG_COMMAND, "transfer pad (%s, count=%d)\n", (data & CMD_DMA) ? "dma" : "pio", m_cnt);
+ m_state = XFI_START;
+ m_sbx = data & CMD_SBX;
+ m_state_timer->adjust(attotime::zero);
+ break;
+ case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ // reserved
+ break;
+ }
+ }
+}
+
+void ncr5385_device::ctl_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "ctl_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ m_ctl = data & 7;
+}
+
+void ncr5385_device::dst_id_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "dst_id_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_dst_id = (data & 7);
+}
+
+template <unsigned N> void ncr5385_device::cnt_w(u8 data)
+{
+ m_cnt = (m_cnt & ~(u32(0xff) << (N * 8))) | (u32(data) << (N * 8));
+
+ if (m_cnt)
+ m_aux_status &= ~AUX_STATUS_TC_ZERO;
+ else
+ m_aux_status |= AUX_STATUS_TC_ZERO;
+}
+
+void ncr5385_device::tst_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "tst_w 0x%02x (%s)\n", data, machine().describe_context());
+}
+
+u8 ncr5385_device::dma_r()
+{
+ u8 const data = m_dat;
+ m_aux_status &= ~AUX_STATUS_DATA_FULL;
+
+ set_dreq(false);
+ m_state_timer->adjust(attotime::zero);
+
+ return data;
+}
+
+void ncr5385_device::dma_w(u8 data)
+{
+ m_dat = data;
+ m_aux_status |= AUX_STATUS_DATA_FULL;
+
+ set_dreq(false);
+ m_state_timer->adjust(attotime::zero);
+}
+
+void ncr5385_device::state_timer(s32 param)
+{
+ // step state machine
+ int const delay = state_step();
+
+ // check for data stall
+ if (delay < 0)
+ return;
+
+ // repeat until idle
+ if (m_state != IDLE)
+ m_state_timer->adjust(attotime::from_nsec(delay));
+}
+
+int ncr5385_device::state_step()
+{
+ u32 const ctrl = scsi_bus->ctrl_r();
+ int delay = 0;
+
+ u8 const oid = 1 << m_own_id;
+ u8 const tid = 1 << m_dst_id;
+
+ switch (m_state)
+ {
+ case DIAGNOSTIC:
+ m_dia_status &= DIAG_DONE | DIAG_SELF;
+ if (BIT(m_cmd, 6))
+ {
+ m_aux_status |= AUX_STATUS_PARITY_ERR;
+ m_dia_status |= DIAG_CMD_BP;
+ }
+ else
+ {
+ m_aux_status &= ~AUX_STATUS_PARITY_ERR;
+ m_dia_status |= DIAG_CMD_GP;
+ }
+
+ m_int_status |= INT_FUNC_COMPLETE;
+ m_state = IDLE;
+
+ update_int();
+ break;
+
+ case ARB_BUS_FREE:
+ LOGMASKED(LOG_STATE, "arbitration: waiting for bus free\n");
+ if (!(ctrl & (S_SEL | S_BSY | S_RST)))
+ {
+ m_state = ARB_START;
+ delay = SCSI_BUS_FREE;
+ }
+ break;
+ case ARB_START:
+ LOGMASKED(LOG_STATE, "arbitration: started\n");
+ m_state = ARB_EVALUATE;
+ delay = SCSI_ARB_DELAY;
+
+ // assert own ID and BSY
+ scsi_bus->data_w(scsi_refid, oid);
+ scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY);
+ break;
+ case ARB_EVALUATE:
+ // check if SEL asserted, or if there's a higher ID on the bus
+ if ((ctrl & S_SEL) || (scsi_bus->data_r() & ~((oid - 1) | oid)))
+ {
+ LOGMASKED(LOG_STATE, "arbitration: lost\n");
+ m_state = ARB_BUS_FREE;
+
+ // clear data and BSY
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
+ }
+ else
+ {
+ LOGMASKED(LOG_STATE, "arbitration: won\n");
+ m_state = SEL_START;
+ delay = SCSI_BUS_CLEAR + SCSI_BUS_SETTLE;
+ }
+ break;
+
+ case SEL_START:
+ LOGMASKED(LOG_STATE, "selection: SEL asserted\n");
+ m_state = SEL_DELAY;
+ delay = SCSI_BUS_SKEW * 2;
+
+ // assert own and target ID and SEL
+ scsi_bus->data_w(scsi_refid, oid | tid);
+ scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL);
+ break;
+ case SEL_DELAY:
+ LOGMASKED(LOG_STATE, "selection: BSY cleared\n");
+ m_state = SEL_WAIT_BSY;
+ delay = SCSI_SEL_TIMEOUT;
+
+ // clear BSY, optionally assert ATN
+ if (!BIT(m_cmd, 0))
+ scsi_bus->ctrl_w(scsi_refid, S_ATN, S_BSY | S_ATN);
+ else
+ scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
+ break;
+ case SEL_WAIT_BSY:
+ if (ctrl & S_BSY)
+ {
+ LOGMASKED(LOG_STATE, "selection: BSY asserted by target\n");
+ m_state = SEL_COMPLETE;
+ delay = SCSI_BUS_SKEW * 2;
+ }
+ else
+ {
+ LOGMASKED(LOG_STATE, "selection: timed out\n");
+ m_int_status |= INT_DISCONNECTED;
+ m_state = IDLE;
+
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ATN | S_SEL);
+
+ update_int();
+ }
+ break;
+ case SEL_COMPLETE:
+ LOGMASKED(LOG_STATE, "selection: complete\n");
+ m_int_status |= INT_FUNC_COMPLETE;
+ m_mode = INITIATOR;
+ m_state = SEL_WAIT_REQ;
+ delay = -1;
+
+ update_int();
+
+ // clear data and SEL
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_SEL);
+ break;
+ case SEL_WAIT_REQ:
+ // don't generate bus service interrupt until the function complete is cleared
+ if ((ctrl & S_REQ) && !m_int_state)
+ {
+ LOGMASKED(LOG_STATE, "selection: REQ asserted by target\n");
+ m_int_status |= INT_BUS_SERVICE;
+ m_state = IDLE;
+
+ update_int();
+ }
+ else
+ delay = -1;
+ break;
+
+ case XFI_START:
+ m_phase = ctrl & S_PHASE_MASK;
+ m_state = (ctrl & S_INP) ? XFI_IN_REQ : XFI_OUT_REQ;
+ break;
+
+ case XFI_IN_REQ:
+ // TODO: disconnect
+ if (ctrl & S_REQ)
+ {
+ if (remaining() && (ctrl & S_PHASE_MASK) == m_phase)
+ {
+ m_state = XFI_IN_DRQ;
+
+ // transfer pad in doesn't transfer any data
+ if (!BIT(m_cmd, 0))
+ {
+ m_aux_status |= AUX_STATUS_DATA_FULL;
+ m_dat = scsi_bus->data_r();
+
+ if (m_cmd & CMD_DMA)
+ set_dreq(true);
+
+ delay = -1;
+ }
+ }
+ else
+ {
+ LOGMASKED(LOG_STATE, "xfi_in: %s\n", remaining() ? "phase change" : "transfer complete");
+
+ m_int_status |= INT_BUS_SERVICE;
+ m_state = IDLE;
+
+ update_int();
+ }
+ }
+ else
+ delay = -1;
+ break;
+ case XFI_IN_DRQ:
+ m_state = XFI_IN_ACK;
+
+ LOGMASKED(LOG_STATE, "xfi_in: data 0x%02x\n", m_dat);
+
+ // assert ACK
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
+ break;
+ case XFI_IN_ACK:
+ if (!(ctrl & S_REQ))
+ {
+ m_state = XFI_IN_REQ;
+
+ if (!(m_cmd & CMD_SBX))
+ {
+ m_cnt--;
+
+ LOGMASKED(LOG_STATE, "xfi_in: %d remaining\n", m_cnt);
+
+ if (!m_cnt)
+ m_aux_status |= AUX_STATUS_TC_ZERO;
+ }
+ else
+ m_sbx = false;
+
+ // clear ACK except after last byte of message input phase
+ if (!remaining() && (ctrl & S_PHASE_MASK) == S_PHASE_MSG_IN)
+ {
+ m_int_status |= INT_FUNC_COMPLETE;
+ m_state = IDLE;
+
+ update_int();
+ }
+ else
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ }
+ else
+ delay = -1;
+ break;
+
+ case XFI_OUT_REQ:
+ if (ctrl & S_REQ)
+ {
+ // TODO: disconnect
+ if (remaining() && (ctrl & S_PHASE_MASK) == m_phase)
+ {
+ m_state = XFI_OUT_DRQ;
+
+ // FIXME: only one byte dma for transfer pad
+ if (m_cmd & CMD_DMA)
+ set_dreq(true);
+
+ if (!(m_aux_status & AUX_STATUS_DATA_FULL))
+ delay = -1;
+ }
+ else
+ {
+ LOGMASKED(LOG_STATE, "xfi_out: %s\n", remaining() ? "phase change" : "transfer complete");
+ m_int_status |= INT_BUS_SERVICE;
+ m_state = IDLE;
+
+ update_int();
+ }
+ }
+ else
+ delay = -1;
+ break;
+ case XFI_OUT_DRQ:
+ m_state = XFI_OUT_ACK;
+ m_aux_status &= ~AUX_STATUS_DATA_FULL;
+
+ LOGMASKED(LOG_STATE, "xfi_out: data 0x%02x\n", m_dat);
+
+ // assert data and ACK
+ scsi_bus->data_w(scsi_refid, m_dat);
+ if (remaining(1) && (ctrl & S_PHASE_MASK) == S_PHASE_MSG_OUT)
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK | S_ATN);
+ else
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
+ break;
+ case XFI_OUT_ACK:
+ if (!(ctrl & S_REQ))
+ {
+ if (BIT(m_cmd, 0))
+ m_state = XFI_OUT_PAD;
+ else
+ m_state = XFI_OUT_REQ;
+
+ if (!(m_cmd & CMD_SBX))
+ {
+ m_cnt--;
+
+ LOGMASKED(LOG_STATE, "xfi_out: %d remaining\n", m_cnt);
+
+ if (!m_cnt)
+ m_aux_status |= AUX_STATUS_TC_ZERO;
+ }
+ else
+ m_sbx = false;
+
+ // clear data and ACK
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ }
+ else
+ delay = -1;
+ break;
+ case XFI_OUT_PAD:
+ if (ctrl & S_REQ)
+ {
+ // TODO: disconnect
+ if (remaining() && (ctrl & S_PHASE_MASK) == m_phase)
+ m_state = XFI_OUT_DRQ;
+ else
+ {
+ LOGMASKED(LOG_STATE, "xfi_out: %s\n", remaining() ? "phase change" : "transfer complete");
+ m_int_status |= INT_BUS_SERVICE;
+ m_state = IDLE;
+
+ update_int();
+ }
+ }
+ break;
}
+
+ return delay;
}
-uint8_t ncr5385_device::read(offs_t offset)
+/*
+ * Returns a boolean indicating whether any data remains to be transferred:
+ *
+ * - for single byte transfer commands, m_sbx indicates data remaining
+ * - alternatively, return if there's a specific amount of data to transfer
+ * - otherwise, check if there's any data to transfer
+ */
+bool ncr5385_device::remaining(u32 const count) const
{
- switch (offset)
+ if (m_cmd & CMD_SBX)
+ return m_sbx;
+ else if (count)
+ return m_cnt == count;
+ else
+ return m_cnt;
+}
+
+void ncr5385_device::set_dreq(bool dreq)
+{
+ if (m_dreq_state != dreq)
{
- case 0x2:
- logerror("%s: ncr5385_r: control (%02x)\n", machine().describe_context(), m_ctrl_reg);
- return m_ctrl_reg;
- case 0x4:
- logerror("%s: ncr5385_r: aux status (%02x)\n", machine().describe_context(), m_aux_status_reg);
- return m_aux_status_reg;
- case 0x6:
- logerror("%s: ncr5385_r: interrupt (%02x)\n", machine().describe_context(), m_int_reg);
- m_int(1);
- return m_int_reg;
- case 0x9:
- logerror("%s: ncr5385_r: diagnostic status (%02x)\n", machine().describe_context(), m_diag_status_reg);
- return m_diag_status_reg;
- default:
- logerror("%s: ncr5385_r: %x (%02x)\n", machine().describe_context(), offset, 0);
- return 0;
+ LOGMASKED(LOG_DMA, "set_dreq %d\n", dreq);
+
+ m_dreq_state = dreq;
+ m_dreq(m_dreq_state);
+ }
+}
+
+void ncr5385_device::update_int()
+{
+ bool const int_state = m_int_status & 0x5f;
+
+ if (m_int_state != int_state)
+ {
+ LOG("update_int %d\n", int_state);
+
+ m_aux_status &= ~(AUX_STATUS_MSG | AUX_STATUS_CD | AUX_STATUS_IO);
+ if (int_state)
+ {
+ m_cmd = 0;
+
+ // latch current phase
+ u32 const ctrl = scsi_bus->ctrl_r();
+ if (ctrl & S_MSG)
+ m_aux_status |= AUX_STATUS_MSG;
+ if (ctrl & S_CTL)
+ m_aux_status |= AUX_STATUS_CD;
+ if (ctrl & S_INP)
+ m_aux_status |= AUX_STATUS_IO;
+ }
+
+ m_int_state = int_state;
+ m_int(m_int_state);
}
}
diff --git a/src/devices/machine/ncr5385.h b/src/devices/machine/ncr5385.h
index a1dec052045..a1e8deef207 100644
--- a/src/devices/machine/ncr5385.h
+++ b/src/devices/machine/ncr5385.h
@@ -4,11 +4,6 @@
NCR 5385 SCSI Controller emulation
- TODO:
- - Everything. Currently, just enough is implemented to make the
- Philips VP415 CPU / Datagrabber board satisfied that the
- controller has passed its internal diagnostics.
-
************************************************************************
_____ _____
D2 1 |* \_/ | 48 VCC
@@ -43,91 +38,89 @@
#pragma once
+#include "machine/nscsi_bus.h"
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-// ======================> ncr5385_device
-
-class ncr5385_device : public device_t
+class ncr5385_device
+ : public nscsi_device
+ , public nscsi_slot_card_interface
{
public:
- // construction/destruction
- ncr5385_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
auto irq() { return m_int.bind(); }
+ auto dreq() { return m_dreq.bind(); }
+
+ void set_own_id(unsigned id) { m_own_id = id; }
- void write(offs_t offset, uint8_t data);
- uint8_t read(offs_t offset);
+ ncr5385_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ void map(address_map &map);
+
+ u8 dma_r();
+ void dma_w(u8 data);
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
-private:
- enum
- {
- STATE_IDLE,
- STATE_DIAGNOSTIC_GOOD_PARITY,
- STATE_DIAGNOSTIC_BAD_PARITY,
- };
-
- enum
- {
- DIAG_TURN_MISCOMPARE_INITIAL = 0x08,
- DIAG_TURN_MISCOMPARE_FINAL = 0x10,
- DIAG_TURN_GOOD_PARITY = 0x18,
- DIAG_TURN_BAD_PARITY = 0x20,
- DIAG_COMPLETE = 0x80,
-
- DIAG_COMPLETE_BIT = 7,
- };
-
- enum
- {
- INT_FUNC_COMPLETE = 0x01,
- INT_INVALID_CMD = 0x40,
-
- INT_FUNC_COMPLETE_BIT = 0,
- INT_INVALID_CMD_BIT = 6,
- };
-
- enum
- {
- AUX_STATUS_TC_ZERO = 0x02,
- AUX_STATUS_PAUSED = 0x04,
- AUX_STATUS_PARITY_ERR = 0x40,
- AUX_STATUS_DATA_FULL = 0x80,
-
- AUX_STATUS_TC_ZERO_BIT = 1,
- AUX_STATUS_PAUSED_BIT = 2,
- AUX_STATUS_PARITY_ERR_BIT = 6,
- AUX_STATUS_DATA_FULL_BIT = 7,
- };
-
- enum
- {
- CTRL_SELECT = 0x01,
- CTRL_RESELECT = 0x02,
- CTRL_PARITY = 0x04,
-
- CTRL_SELECT_BIT = 0,
- CTRL_RESELECT_BIT = 1,
- CTRL_PARITY_BIT = 2,
- };
+ // ncsci_device implementation
+ virtual void scsi_ctrl_changed() override;
+
+ // read handlers
+ u8 dat_r();
+ u8 cmd_r();
+ u8 ctl_r();
+ u8 dst_id_r();
+ u8 aux_status_r();
+ u8 own_id_r();
+ u8 int_status_r();
+ u8 src_id_r();
+ u8 dia_status_r();
+ template <unsigned N> u8 cnt_r();
+ u8 tst_r();
+
+ // write handlers
+ void dat_w(u8 data);
+ void cmd_w(u8 data);
+ void ctl_w(u8 data);
+ void dst_id_w(u8 data);
+ template <unsigned N> void cnt_w(u8 data);
+ void tst_w(u8 data);
+
+ // state machine, interrupts and dma
+ void state_timer(s32 param);
+ int state_step();
+ bool remaining(u32 const count = 0) const;
+ void update_int();
+ void set_dreq(bool dreq);
+private:
devcb_write_line m_int;
-
- uint32_t m_state;
- uint8_t m_ctrl_reg;
- uint8_t m_int_reg;
- uint8_t m_aux_status_reg;
- uint8_t m_diag_status_reg;
+ devcb_write_line m_dreq;
+
+ emu_timer *m_state_timer;
+
+ // registers
+ u8 m_dat;
+ u8 m_cmd;
+ u8 m_ctl;
+ u8 m_dst_id;
+ u8 m_aux_status;
+ u8 m_own_id;
+ u8 m_int_status;
+ u8 m_src_id;
+ u8 m_dia_status;
+ u32 m_cnt;
+
+ // other state
+ u32 m_state;
+ u8 m_phase;
+ u8 m_mode;
+ bool m_sbx;
+
+ bool m_int_state;
+ bool m_dreq_state;
};
-// device type definition
DECLARE_DEVICE_TYPE(NCR5385, ncr5385_device)
#endif // MAME_MACHINE_NCR5385_H
diff --git a/src/devices/machine/ncr539x.cpp b/src/devices/machine/ncr539x.cpp
deleted file mode 100644
index 1ddd46b2c18..00000000000
--- a/src/devices/machine/ncr539x.cpp
+++ /dev/null
@@ -1,776 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-/*
- * ncr539x.c
- *
- * NCR 53(CF)94/53(CF)96 SCSI controller
- * Includes enhanced features of the AMD 53CF94/96 and compatibles
- *
- * All new emulation in 2011 by R. Belmont.
- *
- */
-
-#include "emu.h"
-#include "ncr539x.h"
-
-#define LOG_GENERAL (1U << 0)
-#define LOG_READS (1U << 1)
-
-//#define VERBOSE (LOG_GENERAL | LOG_READS)
-//#define LOG_OUTPUT_FUNC printf
-#include "logmacro.h"
-
-#define LOGREADS(...) LOGMASKED(LOG_READS, __VA_ARGS__)
-
-enum
-{
- TIMER_539X_COMMAND,
-
- TIMER_539X_END
-};
-
-#define MAIN_STATUS_INTERRUPT 0x80
-#define MAIN_STATUS_ILLEGAL_OPER 0x40
-#define MAIN_STATUS_PARITY_ERROR 0x20
-#define MAIN_STATUS_COUNT_TO_ZERO 0x10
-#define MAIN_STATUS_GROUP_VALID 0x08
-#define MAIN_STATUS_MESSAGE 0x04
-#define MAIN_STATUS_CMD_DATA 0x02
-#define MAIN_STATUS_IO 0x01
-
-#define IRQ_STATUS_RESET 0x80
-#define IRQ_STATUS_INVALID_COMMAND 0x40
-#define IRQ_STATUS_DISCONNECTED 0x20
-#define IRQ_STATUS_SERVICE_REQUEST 0x10
-#define IRQ_STATUS_SUCCESS 0x08
-#define IRQ_STATUS_RESELECTED 0x04 // we were reselected as a target
-#define IRQ_STATUS_SELECTED_WITH_ATN 0x02 // we were selected as a target with ATN steps
-#define IRQ_STATUS_SELECTED 0x01 // we were selected as a target
-
-#define CR2_ALIGN_ENABLE 0x80
-#define CR2_FEATURES_ENABLE 0x40
-#define CR2_BYTE_ORDER 0x20
-#define CR2_TRISTATE_DMA 0x10
-#define CR2_SCSI2_ENABLE 0x08
-#define CR2_ABORT_ON_PARITY_ERROR 0x04
-#define CR2_GENERATE_REGISTER_PARITY 0x02
-#define CR2_GENERATE_DATA_PARITY 0x01
-
-static char const *const rdregs[16] = {
- "Transfer count LSB", // 0
- "Transfer count MSB", // 1
- "FIFO", // 2
- "Command", // 3
- "Status", // 4
- "Interrupt Status", // 5
- "Internal State", // 6
- "Current FIFO/Internal State", // 7
- "Control Register 1", // 8
- "0x9",
- "0xA",
- "Control Register 2",
- "Control Register 3",
- "Control Register 4",
- "Transfer count HSB/Chip ID",
- "0xF"
-};
-
-static char const *const wrregs[16] = {
- "Start Transfer count LSB",
- "Start Transfer count MSB",
- "FIFO",
- "Command",
- "SCSI Destination ID",
- "SCSI Timeout",
- "Synchronous Transfer Period",
- "Synchronous Offset",
- "Control Register 1",
- "Clock Factor",
- "Forced Test Mode",
- "Control Register 2",
- "Control Register 3",
- "Control Register 4",
- "Start Transfer count HSB",
- "Data Alignment"
-};
-
-// get the length of a SCSI command based on its command byte type
-static int get_cmd_len(int cbyte)
-{
- int group;
-
- group = (cbyte>>5) & 7;
-
- if (group == 0) return 6;
- if (group == 1 || group == 2) return 10;
- if (group == 5) return 12;
-
- return 6;
-}
-
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
-
-DEFINE_DEVICE_TYPE(NCR539X, ncr539x_device, "ncr539x", "NCR/AMD 5394/5396 SCSI")
-
-//-------------------------------------------------
-// ncr539x_device - constructor/destructor
-//-------------------------------------------------
-
-ncr539x_device::ncr539x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- legacy_scsi_host_adapter(mconfig, NCR539X, tag, owner, clock),
- m_out_irq_cb(*this),
- m_out_drq_cb(*this)
-{
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void ncr539x_device::device_start()
-{
- legacy_scsi_host_adapter::device_start();
-
- // resolve line callbacks
- m_out_irq_cb.resolve_safe();
- m_out_drq_cb.resolve_safe();
-
- m_operation_timer = timer_alloc(0, nullptr);
-}
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void ncr539x_device::device_reset()
-{
- m_fifo_ptr = 0;
- m_fifo_read_ptr = 0;
- m_irq_status = 0;
- m_status = SCSI_PHASE_STATUS;
- m_internal_state = 0;
- m_buffer_offset = 512;
- m_buffer_remaining = 0;
- m_dma_size = 0;
- m_xfer_count = 0;
- m_total_data = 0;
- m_selected = false;
- m_control1 = m_control2 = m_control3 = m_control4 = 0;
- m_chipid_available = false;
- m_chipid_lock = false;
- m_fifo_internal_state = 0;
-
- m_out_irq_cb(CLEAR_LINE);
- m_out_drq_cb(CLEAR_LINE);
-}
-
-void ncr539x_device::dma_read_data(int bytes, uint8_t *pData)
-{
- read_data(pData, bytes);
-}
-
-
-void ncr539x_device::dma_write_data(int bytes, uint8_t *pData)
-{
- write_data(pData, bytes);
-}
-
-void ncr539x_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
-{
- //printf("539X: device_timer expired, param = %d, m_command = %02x\n", param, m_command);
-
- switch (param)
- {
- case TIMER_539X_COMMAND:
- // if this is a DMA command, raise DRQ now
- if (m_command & 0x80)
- {
- m_out_drq_cb(ASSERT_LINE);
- }
-
- switch (m_command & 0x7f)
- {
- case 0x41: // select without ATN steps
- if (select(m_last_id))
- {
- m_irq_status |= IRQ_STATUS_SERVICE_REQUEST | IRQ_STATUS_SUCCESS;
- // we should now be in the command phase
- m_status &= ~7; // clear bus phases
- m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_COMMAND;
- m_fifo_ptr = 0;
- m_selected = true;
-
- LOG("Selecting w/o ATN, irq_status = %02x, status = %02x!\n", m_irq_status, m_status);
-
- // if DMA is not enabled, there should already be a command loaded into the FIFO
- if (!(m_command & 0x80))
- {
- exec_fifo();
- }
- update_fifo_internal_state(0);
- }
- else
- {
- LOG("Select failed, no device @ ID %d!\n", m_last_id);
- m_status |= MAIN_STATUS_INTERRUPT;
- m_irq_status |= IRQ_STATUS_DISCONNECTED;
- }
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x42: // Select with ATN steps
- if (select(m_last_id))
- {
- m_irq_status |= IRQ_STATUS_SERVICE_REQUEST | IRQ_STATUS_SUCCESS;
- // we should now be in the command phase
- m_status &= ~7; // clear bus phases
- m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_COMMAND;
- m_fifo_ptr = 0;
- m_selected = true;
- LOG("Selecting with ATN, irq_status = %02x, status = %02x!\n", m_irq_status, m_status);
-
- // if DMA is not enabled, there should already be a command loaded into the FIFO
- if (!(m_command & 0x80))
- {
- exec_fifo();
- }
- update_fifo_internal_state(0);
- }
- else
- {
- LOG("Select failed, no device @ ID %d!\n", m_last_id);
- m_status |= MAIN_STATUS_INTERRUPT;
- m_irq_status |= IRQ_STATUS_DISCONNECTED;
- }
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x11: // initiator command complete
- LOG("Initiator command complete\n");
- m_irq_status = IRQ_STATUS_SERVICE_REQUEST;
- m_status &= ~7; // clear phase bits
- m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_DATAIN; // go to data in phase (?)
- m_out_irq_cb(ASSERT_LINE);
-
- // this puts status and message bytes into the FIFO (todo: what are these?)
- m_fifo_ptr = 0;
- m_xfer_count = 2;
- m_buffer_remaining = m_total_data = 0;
- m_fifo[0] = 0; // status byte
- m_fifo[1] = 0; // message byte
- m_selected = false;
- update_fifo_internal_state(2);
- break;
-
- case 0x12: // message accepted
- LOG("Message accepted\n");
- m_irq_status = IRQ_STATUS_SERVICE_REQUEST;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- default:
- fatalerror("539x: Unhandled command %02x\n", m_command);
- }
- break;
-
- default:
- break;
- }
-}
-
-uint8_t ncr539x_device::read(offs_t offset)
-{
- uint8_t rv = 0;
-
- LOGREADS("539x: Read @ %s (%02x) (%s) (status %02x irq_status %02x)\n", rdregs[offset], offset, machine().describe_context(), m_status, m_irq_status);
-
- switch (offset)
- {
- case 0:
- rv = m_xfer_count & 0xff;
- break;
-
- case 1:
- rv = (m_xfer_count>>8) & 0xff;
- break;
-
- case 2: // FIFO
- {
- uint8_t fifo_bytes = m_fifo_internal_state & 0x1f;
-
- if (!fifo_bytes)
- {
- rv = 0;
- }
- else
- {
- rv = m_fifo[m_fifo_read_ptr++];
- m_fifo_read_ptr &= (m_fifo_size-1);
-
- fifo_bytes--;
- m_xfer_count--;
- update_fifo_internal_state(fifo_bytes);
-
- LOG("Read %02x from FIFO[%d], FIFO now contains %d bytes (%s) (m_buffer_remaining %x)\n", rv, m_fifo_read_ptr-1, fifo_bytes, machine().describe_context(), m_buffer_remaining);
-
- if (fifo_bytes == 0)
- {
- // the last transfer command has more data for us
- if (m_xfer_count > 0)
- {
- int fifo_fill_size = m_fifo_size;
- if (m_xfer_count < fifo_fill_size)
- {
- fifo_fill_size = m_xfer_count;
- }
- assert(m_buffer_offset < m_buffer_size);
- assert((m_buffer_offset + fifo_fill_size) <= m_buffer_size);
- memcpy(m_fifo, &m_buffer[m_buffer_offset], fifo_fill_size);
- m_buffer_offset += fifo_fill_size;
- m_buffer_remaining -= fifo_fill_size;
- m_fifo_ptr = 0;
- update_fifo_internal_state(fifo_fill_size);
- LOG("Refreshing FIFO (%x remaining from transfer, %x in buffer, %x in total)\n", m_xfer_count, m_buffer_remaining, m_total_data);
- }
- else
- {
- LOG("FIFO empty, asserting service request (buffer_remaining %x)\n", m_buffer_remaining);
- m_irq_status = IRQ_STATUS_SERVICE_REQUEST;
- m_status &= 0x7; // clear everything but the phase bits
- m_status |= MAIN_STATUS_INTERRUPT | MAIN_STATUS_COUNT_TO_ZERO;
- m_out_irq_cb(ASSERT_LINE);
-
- // if no data at all, drop the phase
- if ((m_buffer_remaining + m_total_data) == 0)
- {
- LOG("Out of data, setting phase STATUS\n");
- m_status &= ~0x7;
- m_status |= SCSI_PHASE_STATUS;
- }
- }
- }
- }
- }
- break;
-
- case 3:
- rv = m_command;
- break;
-
- case 4:
- rv = m_status;
- break;
-
- case 5:
- rv = m_irq_status;
- // clear the interrupt state
- m_status &= ~MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(CLEAR_LINE);
- break;
-
- case 6:
- rv = m_internal_state;
- break;
-
- case 7:
- rv = m_fifo_internal_state;
- break;
-
- case 8:
- rv = m_control1;
- break;
-
- case 0xb:
- rv = m_control2;
- break;
-
- case 0xc:
- rv = m_control3;
- break;
-
- case 0xd:
- rv = m_control4;
- break;
-
- case 0xe:
- if (m_control2 & CR2_FEATURES_ENABLE)
- {
- if (m_chipid_available)
- {
- rv = 0xa2; // 0x12 for CF94, 0xa2 for CF96
- }
- else
- {
- rv = (m_xfer_count>>16) & 0xff;
- }
- }
- break;
-
- }
- return rv;
-}
-
-void ncr539x_device::write(offs_t offset, uint8_t data)
-{
- //if (offset != 2)
- LOG("539x: Write %02x @ %s (%02x) (%s)\n", data, wrregs[offset], offset, machine().describe_context());
-
- switch (offset)
- {
- case 0:
- m_dma_size &= 0xff00;
- m_dma_size |= data;
- break;
-
- case 1:
- m_dma_size &= 0x00ff;
- m_dma_size |= (data<<8);
- break;
-
- case 2: // FIFO
- fifo_write(data);
- break;
-
- case 3:
- m_command = data;
-
- // clear status bits (OK to do here?)
- m_status &= ~MAIN_STATUS_INTERRUPT;
- m_irq_status = 0;
-
- switch (data & 0x7f)
- {
- case 0x00: // NOP
- m_irq_status = IRQ_STATUS_SUCCESS;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
-
- // DMA NOP? allow chip ID
- if ((m_command == 0x80) && (!m_chipid_lock))
- {
- m_chipid_available = true;
- }
- break;
-
- case 0x01: // Clear FIFO (must not change buffer state)
- m_fifo_ptr = 0;
- update_fifo_internal_state(0);
- m_irq_status = IRQ_STATUS_SUCCESS;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x02: // Reset device
- device_reset();
-
- m_irq_status = IRQ_STATUS_SUCCESS;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x03: // Reset SCSI bus
- m_status = 0;
- m_irq_status = IRQ_STATUS_SUCCESS;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x10: // information transfer (must happen immediately)
- m_status &= 0x7; // clear everything but the phase bits
- m_status |= MAIN_STATUS_INTERRUPT;
- m_irq_status = IRQ_STATUS_SUCCESS;
-
- int phase;
- phase = get_phase();
-
- LOG("Information transfer: phase %d buffer remaining %x\n", phase, m_buffer_remaining);
-
- if (phase == SCSI_PHASE_DATAIN) // target -> initiator transfer
- {
- int amtToGet = m_buffer_size;
-
- // fill the internal sector buffer
- if (m_buffer_remaining <= 0)
- {
- if (m_total_data < m_buffer_size)
- {
- amtToGet = m_total_data;
- }
-
- LOG("amtToGet = %x\n", amtToGet);
-
- if (amtToGet > 0)
- {
- read_data(m_buffer, amtToGet);
-
- m_total_data -= amtToGet;
- m_buffer_offset = 0;
- m_buffer_remaining = amtToGet;
- }
- }
-
- // copy the requested amount into the FIFO
- if (amtToGet > 0)
- {
- if (m_buffer_remaining < m_dma_size)
- {
- m_dma_size = m_buffer_remaining;
- }
-
- int fifo_fill_size = m_fifo_size;
-
- if (m_dma_size < fifo_fill_size)
- {
- fifo_fill_size = m_dma_size;
- }
-
- LOG("filling FIFO from buffer[%x] for %x bytes\n", m_buffer_offset, fifo_fill_size);
-
- memcpy(m_fifo, &m_buffer[m_buffer_offset], fifo_fill_size);
- m_buffer_offset += fifo_fill_size;
- m_buffer_remaining -= fifo_fill_size;
-
- m_xfer_count = m_dma_size;
- m_fifo_ptr = 0;
- update_fifo_internal_state(fifo_fill_size);
- m_out_drq_cb(ASSERT_LINE);
- }
-
- m_status |= MAIN_STATUS_COUNT_TO_ZERO;
-
- LOG("Information transfer: put %02x bytes into FIFO (dma size %x) (buffer remaining %x)\n", m_fifo_internal_state & 0x1f, m_dma_size, m_buffer_remaining);
- }
- else if (phase == SCSI_PHASE_DATAOUT)
- {
- m_xfer_count = m_dma_size;
- if (m_xfer_count == 0)
- {
- m_xfer_count = 0x10000;
- }
- LOG("dma_size %x, xfer_count %x\n", m_dma_size, m_xfer_count);
- m_status &= ~MAIN_STATUS_COUNT_TO_ZERO;
- m_fifo_ptr = 0;
- m_buffer_offset = 0;
- m_buffer_remaining = 0;
- }
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x24: // Terminate steps
- LOG("Terminate steps\n");
- m_irq_status = IRQ_STATUS_SUCCESS | IRQ_STATUS_DISCONNECTED;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- m_fifo_ptr = 0;
- update_fifo_internal_state(0);
- break;
-
- case 0x27: // Disconnect
- LOG("Disconnect\n");
- m_irq_status = IRQ_STATUS_SUCCESS;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x44: // Enable selection/reselection
- LOG("Enable selection/reselection\n");
- m_irq_status = IRQ_STATUS_SUCCESS;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- case 0x47: // Reselect with ATN3 steps
- if (select(m_last_id))
- {
- m_irq_status |= IRQ_STATUS_SERVICE_REQUEST | IRQ_STATUS_SUCCESS;
- // we should now be in the command phase
- m_status &= ~7; // clear bus phases
- m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_COMMAND;
- m_fifo_ptr = 0;
- m_selected = true;
- LOG("Reselecting with ATN3, irq_status = %02x, status = %02x!\n", m_irq_status, m_status);
-
- // if DMA is not enabled, there should already be a command loaded into the FIFO
- if (!(m_command & 0x80))
- {
- exec_fifo();
- }
- update_fifo_internal_state(0);
- }
- else
- {
- LOG("Reselect with ATN3 failed, no device @ ID %d!\n", m_last_id);
- m_status |= MAIN_STATUS_INTERRUPT;
- m_irq_status |= IRQ_STATUS_DISCONNECTED;
- }
- m_out_irq_cb(ASSERT_LINE);
- break;
-
- default: // other commands are not instantaneous
- LOG("Setting timer for command %02x\n", data);
- // 1x commands happen much faster
- if ((m_command & 0x70) == 0x10)
- {
- m_operation_timer->adjust(attotime::from_hz(65536), TIMER_539X_COMMAND);
- }
- else
- {
- m_operation_timer->adjust(attotime::from_hz(16384), TIMER_539X_COMMAND);
- }
- break;
- }
- break;
-
- case 4:
- m_last_id = data;
- break;
-
- case 5:
- m_timeout = data;
- break;
-
- case 6:
- m_sync_xfer_period = data;
- break;
-
- case 7:
- m_sync_offset = data;
- break;
-
- case 8:
- m_control1 = data;
- break;
-
- case 9:
- m_clock_factor = data;
- break;
-
- case 0xa:
- m_forced_test = data;
- break;
-
- case 0xb:
- m_control2 = data;
- break;
-
- case 0xc:
- m_control3 = data;
- break;
-
- case 0xd:
- m_control4 = data;
- break;
-
- case 0xe:
- if (m_control2 & CR2_FEATURES_ENABLE)
- {
- m_dma_size &= 0xffff;
- m_dma_size |= (data<<16);
- m_chipid_available = false;
- m_chipid_lock = true;
- }
- break;
-
- case 0xf:
- m_data_alignment = data;
- break;
- }
-}
-
-void ncr539x_device::exec_fifo()
-{
- int length, phase;
-
- send_command(&m_fifo[0], 12);
- length = get_length();
- phase = get_phase();
-
- LOG("Command executed (id %d), new phase %d, length %x\n", m_last_id, phase, length);
-
- m_buffer_offset = m_buffer_size;
- m_buffer_remaining = 0;
- m_total_data = length;
-
- m_status &= ~7; // clear bus phases
- m_status |= (phase & 7); // set the phase reported by the device
-}
-
-void ncr539x_device::check_fifo_executable()
-{
- if (get_cmd_len(m_fifo[0]) == m_fifo_ptr)
- {
- exec_fifo();
- }
-}
-
-void ncr539x_device::fifo_write(uint8_t data)
-{
- int phase = (m_status & 7);
-
- if (phase != SCSI_PHASE_DATAOUT)
- {
- LOG("539x: Write %02x @ FIFO[%x]\n", data, m_fifo_ptr);
- m_fifo[m_fifo_ptr++] = data;
- update_fifo_internal_state(m_fifo_ptr);
-
- if (m_selected)
- {
- check_fifo_executable();
- }
- }
- else // phase is DATAOUT
- {
- m_buffer[m_buffer_offset++] = data;
- m_xfer_count--;
- m_total_data--;
- LOG("539x: Write %02x @ buffer[%x], xfer_count %x, total %x\n", data, m_buffer_offset-1, m_xfer_count, m_total_data);
-
- // default to flushing our entire buffer
- int flush_size = m_buffer_size;
-
- // if the actual size is less than the buffer size, flush that instead
- if (m_dma_size < m_buffer_size)
- {
- flush_size = m_dma_size;
- }
-
- if ((m_buffer_offset == flush_size) || (m_xfer_count == 0))
- {
- LOG("Flushing buffer to device, %x bytes left in buffer (%x total)\n", m_xfer_count, m_total_data);
- write_data(m_buffer, flush_size);
- m_buffer_offset = 0;
-
- // need a service request here too
- m_irq_status = IRQ_STATUS_SERVICE_REQUEST;
- m_status &= 7;
- m_status |= MAIN_STATUS_INTERRUPT;
- m_out_irq_cb(ASSERT_LINE);
- }
-
- if ((m_xfer_count == 0) && (m_total_data == 0))
- {
- LOG("End of write, asserting service request\n");
-
- m_buffer_offset = 0;
- m_irq_status = IRQ_STATUS_SERVICE_REQUEST;
- m_status = MAIN_STATUS_INTERRUPT | SCSI_PHASE_STATUS;
- m_out_irq_cb(ASSERT_LINE);
- }
- }
-}
-
-void ncr539x_device::update_fifo_internal_state(int bytes)
-{
- if (bytes >= 0x1f)
- {
- m_fifo_internal_state |= 0x1f;
- }
- else
- {
- m_fifo_internal_state &= ~0x1f;
- m_fifo_internal_state |= (bytes & 0x1f);
- }
-}
diff --git a/src/devices/machine/ncr539x.h b/src/devices/machine/ncr539x.h
deleted file mode 100644
index 8172f4ea5f2..00000000000
--- a/src/devices/machine/ncr539x.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont
-/*
- * ncr5394/5396.h SCSI controller
- *
- */
-
-#ifndef MAME_MACHINE_NCR539X_H
-#define MAME_MACHINE_NCR539X_H
-
-#pragma once
-
-#include "legscsi.h"
-
-// device stuff
-
-
-class ncr539x_device : public legacy_scsi_host_adapter
-{
-public:
- // construction/destruction
- ncr539x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto irq_callback() { return m_out_irq_cb.bind(); }
- auto drq_callback() { return m_out_drq_cb.bind(); }
-
- // our API
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
-
- void dma_read_data(int bytes, uint8_t *pData);
- void dma_write_data(int bytes, uint8_t *pData);
-
-protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
-private:
- void fifo_write(uint8_t data);
- void check_fifo_executable();
- void exec_fifo();
- void update_fifo_internal_state(int bytes);
-
- uint32_t m_xfer_count;
- uint32_t m_dma_size;
- uint8_t m_command;
- uint8_t m_last_id;
- uint8_t m_timeout;
- uint8_t m_sync_xfer_period;
- uint8_t m_sync_offset;
- uint8_t m_control1, m_control2, m_control3, m_control4;
- uint8_t m_clock_factor;
- uint8_t m_forced_test;
- uint8_t m_data_alignment;
-
- bool m_selected;
- bool m_chipid_available, m_chipid_lock;
-
- static const int m_fifo_size = 16;
- uint8_t m_fifo_ptr, m_fifo_read_ptr, m_fifo[m_fifo_size];
-
- //int m_xfer_remaining; // amount in the FIFO when we're in data in phase
-
- // read-only registers
- uint8_t m_status, m_irq_status, m_internal_state, m_fifo_internal_state;
-
- static const int m_buffer_size = 2048;
-
- uint8_t m_buffer[m_buffer_size];
- int m_buffer_offset, m_buffer_remaining, m_total_data;
-
- emu_timer *m_operation_timer;
-
- devcb_write_line m_out_irq_cb; /* IRQ line */
- devcb_write_line m_out_drq_cb; /* DRQ line */
-};
-
-// device type definition
-DECLARE_DEVICE_TYPE(NCR539X, ncr539x_device)
-
-#endif // MAME_MACHINE_NCR539X_H
diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr53c90.cpp
index 2c516a37ddb..73ebf10ab27 100644
--- a/src/devices/machine/ncr5390.cpp
+++ b/src/devices/machine/ncr53c90.cpp
@@ -3,14 +3,13 @@
/*
* TODO
- * - 16 bit dma order, alignment and last byte handling
+ * - 16 bit dma alignment and last byte handling
* - clean up variable naming and protection
*/
#include "emu.h"
-#include "ncr5390.h"
+#include "ncr53c90.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_STATE (1U << 1)
#define LOG_FIFO (1U << 2)
#define LOG_COMMAND (1U << 3)
@@ -20,27 +19,29 @@
#define DELAY_HACK
-DEFINE_DEVICE_TYPE(NCR5390, ncr5390_device, "ncr5390", "NCR 5390 SCSI Controller")
+DEFINE_DEVICE_TYPE(NCR53C90, ncr53c90_device, "ncr53c90", "NCR 53C90 SCSI Controller")
DEFINE_DEVICE_TYPE(NCR53C90A, ncr53c90a_device, "ncr53c90a", "NCR 53C90A Advanced SCSI Controller")
DEFINE_DEVICE_TYPE(NCR53C94, ncr53c94_device, "ncr53c94", "NCR 53C94 Advanced SCSI Controller")
+DEFINE_DEVICE_TYPE(NCR53C96, ncr53c96_device, "ncr53c96", "NCR 53C96 Advanced SCSI Controller")
DEFINE_DEVICE_TYPE(NCR53CF94, ncr53cf94_device, "ncr53cf94", "NCR 53CF94-2 Fast SCSI Controller") // TODO: differences not emulated
+DEFINE_DEVICE_TYPE(NCR53CF96, ncr53cf96_device, "ncr53cf96", "NCR 53CF96-2 Fast SCSI Controller") // TODO: differences not emulated
-void ncr5390_device::map(address_map &map)
+void ncr53c90_device::map(address_map &map)
{
- map(0x0, 0x0).rw(FUNC(ncr5390_device::tcounter_lo_r), FUNC(ncr5390_device::tcount_lo_w));
- map(0x1, 0x1).rw(FUNC(ncr5390_device::tcounter_hi_r), FUNC(ncr5390_device::tcount_hi_w));
- map(0x2, 0x2).rw(FUNC(ncr5390_device::fifo_r), FUNC(ncr5390_device::fifo_w));
- map(0x3, 0x3).rw(FUNC(ncr5390_device::command_r), FUNC(ncr5390_device::command_w));
- map(0x4, 0x4).rw(FUNC(ncr5390_device::status_r), FUNC(ncr5390_device::bus_id_w));
- map(0x5, 0x5).rw(FUNC(ncr5390_device::istatus_r), FUNC(ncr5390_device::timeout_w));
- map(0x6, 0x6).rw(FUNC(ncr5390_device::seq_step_r), FUNC(ncr5390_device::sync_period_w));
- map(0x7, 0x7).rw(FUNC(ncr5390_device::fifo_flags_r), FUNC(ncr5390_device::sync_offset_w));
- map(0x8, 0x8).rw(FUNC(ncr5390_device::conf_r), FUNC(ncr5390_device::conf_w));
- map(0xa, 0xa).w(FUNC(ncr5390_device::test_w));
- map(0x9, 0x9).w(FUNC(ncr5390_device::clock_w));
+ map(0x0, 0x0).rw(FUNC(ncr53c90_device::tcounter_lo_r), FUNC(ncr53c90_device::tcount_lo_w));
+ map(0x1, 0x1).rw(FUNC(ncr53c90_device::tcounter_hi_r), FUNC(ncr53c90_device::tcount_hi_w));
+ map(0x2, 0x2).rw(FUNC(ncr53c90_device::fifo_r), FUNC(ncr53c90_device::fifo_w));
+ map(0x3, 0x3).rw(FUNC(ncr53c90_device::command_r), FUNC(ncr53c90_device::command_w));
+ map(0x4, 0x4).rw(FUNC(ncr53c90_device::status_r), FUNC(ncr53c90_device::bus_id_w));
+ map(0x5, 0x5).rw(FUNC(ncr53c90_device::istatus_r), FUNC(ncr53c90_device::timeout_w));
+ map(0x6, 0x6).rw(FUNC(ncr53c90_device::seq_step_r), FUNC(ncr53c90_device::sync_period_w));
+ map(0x7, 0x7).rw(FUNC(ncr53c90_device::fifo_flags_r), FUNC(ncr53c90_device::sync_offset_w));
+ map(0x8, 0x8).rw(FUNC(ncr53c90_device::conf_r), FUNC(ncr53c90_device::conf_w));
+ map(0xa, 0xa).w(FUNC(ncr53c90_device::test_w));
+ map(0x9, 0x9).w(FUNC(ncr53c90_device::clock_w));
}
-uint8_t ncr5390_device::read(offs_t offset)
+uint8_t ncr53c90_device::read(offs_t offset)
{
switch (offset)
{
@@ -57,7 +58,7 @@ uint8_t ncr5390_device::read(offs_t offset)
}
}
-void ncr5390_device::write(offs_t offset, uint8_t data)
+void ncr53c90_device::write(offs_t offset, uint8_t data)
{
switch (offset)
{
@@ -78,7 +79,7 @@ void ncr5390_device::write(offs_t offset, uint8_t data)
void ncr53c90a_device::map(address_map &map)
{
- ncr5390_device::map(map);
+ ncr53c90_device::map(map);
map(0xb, 0xb).rw(FUNC(ncr53c90a_device::conf2_r), FUNC(ncr53c90a_device::conf2_w));
}
@@ -87,14 +88,14 @@ uint8_t ncr53c90a_device::read(offs_t offset)
{
if (offset == 11)
return conf2_r();
- return ncr5390_device::read(offset);
+ return ncr53c90_device::read(offset);
}
void ncr53c90a_device::write(offs_t offset, uint8_t data)
{
if (offset == 11)
return conf2_w(data);
- ncr5390_device::write(offset, data);
+ ncr53c90_device::write(offset, data);
}
void ncr53c94_device::map(address_map &map)
@@ -114,7 +115,7 @@ uint8_t ncr53c94_device::read(offs_t offset)
void ncr53c94_device::write(offs_t offset, uint8_t data)
{
- if (offset == 11)
+ if (offset == 12)
conf3_w(data);
else if (offset == 15)
fifo_align_w(data);
@@ -122,24 +123,51 @@ void ncr53c94_device::write(offs_t offset, uint8_t data)
ncr53c90a_device::write(offset, data);
}
-ncr5390_device::ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+void ncr53cf94_device::map(address_map &map)
+{
+ ncr53c94_device::map(map);
+
+ map(0xd, 0xd).rw(FUNC(ncr53cf94_device::conf4_r), FUNC(ncr53cf94_device::conf4_w));
+ map(0xe, 0xe).rw(FUNC(ncr53cf94_device::tcounter_hi2_r), FUNC(ncr53cf94_device::tcount_hi2_w));
+}
+
+uint8_t ncr53cf94_device::read(offs_t offset)
+{
+ if (offset == 13)
+ return conf4_r();
+ else if (offset == 14)
+ return tcounter_hi2_r();
+ return ncr53c94_device::read(offset);
+}
+
+void ncr53cf94_device::write(offs_t offset, uint8_t data)
+{
+ if (offset == 13)
+ conf4_w(data);
+ else if (offset == 14)
+ tcount_hi2_w(data);
+ else
+ ncr53c94_device::write(offset, data);
+}
+
+ncr53c90_device::ncr53c90_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: nscsi_device(mconfig, type, tag, owner, clock)
, nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF)
, tm(nullptr), config(0), status(0), istatus(0), clock_conv(0), sync_offset(0), sync_period(0), bus_id(0)
- , select_timeout(0), seq(0), tcount(0), tcounter(0), mode(0), fifo_pos(0), command_pos(0), state(0), xfr_phase(0), command_length(0), dma_dir(0), irq(false), drq(false), test_mode(false)
+ , select_timeout(0), seq(0), tcount(0), tcounter(0), tcounter_mask(0xffff), mode(0), fifo_pos(0), command_pos(0), state(0), xfr_phase(0), dma_dir(0), irq(false), drq(false), test_mode(false), stepping(0)
, m_irq_handler(*this)
, m_drq_handler(*this)
{
}
ncr53c90a_device::ncr53c90a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : ncr5390_device(mconfig, type, tag, owner, clock)
+ : ncr53c90_device(mconfig, type, tag, owner, clock)
, config2(0)
{
}
-ncr5390_device::ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : ncr5390_device(mconfig, NCR5390, tag, owner, clock)
+ncr53c90_device::ncr53c90_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ncr53c90_device(mconfig, NCR53C90, tag, owner, clock)
{
}
@@ -160,12 +188,30 @@ ncr53c94_device::ncr53c94_device(const machine_config &mconfig, device_type type
{
}
+ncr53c96_device::ncr53c96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ncr53c94_device(mconfig, NCR53C96, tag, owner, clock)
+{
+}
+
+ncr53cf94_device::ncr53cf94_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : ncr53c94_device(mconfig, type, tag, owner, clock)
+ , config4(0)
+ , family_id(0x02)
+ , revision_level(0x02)
+{
+}
+
ncr53cf94_device::ncr53cf94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : ncr53c94_device(mconfig, NCR53CF94, tag, owner, clock)
+ : ncr53cf94_device(mconfig, NCR53CF94, tag, owner, clock)
+{
+}
+
+ncr53cf96_device::ncr53cf96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : ncr53cf94_device(mconfig, NCR53CF96, tag, owner, clock)
{
}
-void ncr5390_device::device_start()
+void ncr53c90_device::device_start()
{
nscsi_device::device_start();
@@ -182,27 +228,24 @@ void ncr5390_device::device_start()
save_item(NAME(fifo));
save_item(NAME(tcount));
save_item(NAME(tcounter));
+ save_item(NAME(tcounter_mask));
save_item(NAME(mode));
save_item(NAME(fifo_pos));
save_item(NAME(command_pos));
save_item(NAME(state));
save_item(NAME(xfr_phase));
- save_item(NAME(command_length));
save_item(NAME(dma_dir));
save_item(NAME(irq));
save_item(NAME(drq));
save_item(NAME(test_mode));
- m_irq_handler.resolve_safe();
- m_drq_handler.resolve_safe();
-
config = 0;
bus_id = 0;
select_timeout = 0;
- tm = timer_alloc(0);
+ tm = timer_alloc(FUNC(ncr53c90_device::update_tick), this);
}
-void ncr5390_device::device_reset()
+void ncr53c90_device::device_reset()
{
fifo_pos = 0;
memset(fifo, 0, sizeof(fifo));
@@ -226,21 +269,21 @@ void ncr5390_device::device_reset()
scsi_bus->ctrl_w(scsi_refid, 0, S_RST);
tcount = 0;
tcounter = 0;
+ tcounter_mask = 0xffff;
reset_disconnect();
}
-void ncr5390_device::reset_disconnect()
+void ncr53c90_device::reset_disconnect()
{
scsi_bus->ctrl_w(scsi_refid, 0, ~S_RST);
command_pos = 0;
- command_length = 0;
memset(command, 0, sizeof(command));
mode = MODE_D;
}
-void ncr5390_device::scsi_ctrl_changed()
+void ncr53c90_device::scsi_ctrl_changed()
{
uint32_t ctrl = scsi_bus->ctrl_r();
if(ctrl & S_RST) {
@@ -248,23 +291,27 @@ void ncr5390_device::scsi_ctrl_changed()
return;
}
- step(false);
+ // disallow further recursion from here
+ if(!stepping)
+ step(false);
}
-void ncr5390_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ncr53c90_device::update_tick)
{
step(true);
}
-void ncr5390_device::step(bool timeout)
+void ncr53c90_device::step(bool timeout)
{
uint32_t ctrl = scsi_bus->ctrl_r();
uint32_t data = scsi_bus->data_r();
uint8_t c = command[0] & 0x7f;
- LOGMASKED(LOG_STATE, "state=%d.%d %s\n",
+ LOGMASKED(LOG_STATE, "state=%d.%d %s @ %s\n",
state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT,
- timeout ? "timeout" : "change");
+ timeout ? "timeout" : "change", machine().time().to_string());
+
+ stepping++;
if(mode == MODE_I && !(ctrl & S_BSY)) {
state = IDLE;
@@ -296,7 +343,7 @@ void ncr5390_device::step(bool timeout)
if(win != scsi_id) {
scsi_bus->data_w(scsi_refid, 0);
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
- fatalerror("ncr5390_device::step need to wait for bus free\n");
+ fatalerror("ncr53c90_device::step need to wait for bus free\n");
}
state = (state & STATE_MASK) | (ARB_ASSERT_SEL << SUB_SHIFT);
scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL);
@@ -421,7 +468,16 @@ void ncr5390_device::step(bool timeout)
break;
if((state & STATE_MASK) != INIT_XFR_RECV_PAD)
+ {
fifo_push(scsi_bus->data_r());
+ // in async mode data in phase in initiator mode, tcount is decremented on ACKO, not DACK
+ if ((mode == MODE_I) && (sync_offset == 0) && ((ctrl & S_PHASE_MASK) == S_PHASE_DATA_IN))
+ {
+ LOGMASKED(LOG_FIFO, "decrement_tcounter data in async, phase %02x (tcounter=%d)\n", (ctrl & S_PHASE_MASK), tcounter);
+ decrement_tcounter();
+ check_drq();
+ }
+ }
scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
state = (state & STATE_MASK) | (RECV_WAIT_REQ_0 << SUB_SHIFT);
step(false);
@@ -435,27 +491,32 @@ void ncr5390_device::step(bool timeout)
break;
case DISC_SEL_ARBITRATION_INIT:
- // wait until a command is in the fifo
- if (!fifo_pos) {
- // dma starts after bus arbitration/selection is complete
- check_drq();
+ if(!timeout)
break;
- }
- command_length = fifo_pos + tcounter;
state = DISC_SEL_ARBITRATION;
step(false);
break;
case DISC_SEL_ARBITRATION:
+ // wait until a command is in the fifo
+ if (!fifo_pos) {
+ // this sequence isn't documented for initiator selection, but
+ // it makes macqd700 happy and may be consistent with target
+ // selection sequences
+ seq = 1;
+ // dma starts after bus arbitration/selection is complete
+ check_drq();
+ break;
+ }
+
if(c == CD_SELECT) {
state = DISC_SEL_WAIT_REQ;
} else
state = DISC_SEL_ATN_WAIT_REQ;
scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
- if(ctrl & S_REQ)
- step(false);
+ step(false);
break;
case DISC_SEL_ATN_WAIT_REQ:
@@ -472,12 +533,12 @@ void ncr5390_device::step(bool timeout)
break;
case DISC_SEL_ATN_SEND_BYTE:
- command_length--;
if(c == CD_SELECT_ATN_STOP) {
- seq = 1;
+ seq = 2;
function_bus_complete();
} else {
state = DISC_SEL_WAIT_REQ;
+ step(false);
}
break;
@@ -485,7 +546,7 @@ void ncr5390_device::step(bool timeout)
if(!(ctrl & S_REQ))
break;
if((ctrl & S_PHASE_MASK) != S_PHASE_COMMAND) {
- if(!command_length)
+ if((!dma_command || (status & S_TC0)) && !fifo_pos)
seq = 4;
else
seq = 2;
@@ -493,6 +554,8 @@ void ncr5390_device::step(bool timeout)
function_bus_complete();
break;
}
+ if(!fifo_pos)
+ break;
if(seq < 3)
seq = 3;
state = DISC_SEL_SEND_BYTE;
@@ -500,18 +563,17 @@ void ncr5390_device::step(bool timeout)
break;
case DISC_SEL_SEND_BYTE:
- if(command_length) {
- command_length--;
- if(!command_length)
- seq = 4;
- }
+ if((!dma_command || (status & S_TC0)) && !fifo_pos)
+ seq = 4;
state = DISC_SEL_WAIT_REQ;
+ step(false);
break;
case INIT_CPT_RECV_BYTE_ACK:
state = INIT_CPT_RECV_WAIT_REQ;
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ step(false);
break;
case INIT_CPT_RECV_WAIT_REQ:
@@ -541,19 +603,23 @@ void ncr5390_device::step(bool timeout)
switch(xfr_phase) {
case S_PHASE_DATA_OUT:
case S_PHASE_COMMAND:
- case S_PHASE_MSG_OUT:
+ case S_PHASE_MSG_OUT: {
state = INIT_XFR_SEND_BYTE;
// can't send if the fifo is empty
if (fifo_pos == 0)
break;
+ // determine remaining bytes to transfer, accounting for fifo level plus potential incoming DMA bytes
+ int remaining_bytes = fifo_pos + (dma_command ? tcounter : 0);
+
// if it's the last message byte, deassert ATN before sending
- if (xfr_phase == S_PHASE_MSG_OUT && ((!dma_command && fifo_pos == 1) || (dma_command && tcounter == 1)))
+ if (xfr_phase == S_PHASE_MSG_OUT && remaining_bytes == 1)
scsi_bus->ctrl_w(scsi_refid, 0, S_ATN);
send_byte();
break;
+ }
case S_PHASE_DATA_IN:
case S_PHASE_STATUS:
@@ -603,6 +669,7 @@ void ncr5390_device::step(bool timeout)
case INIT_XFR_RECV_BYTE_ACK:
state = INIT_XFR_WAIT_REQ;
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ step(false);
break;
case INIT_XFR_RECV_BYTE_NACK:
@@ -611,18 +678,17 @@ void ncr5390_device::step(bool timeout)
break;
case INIT_XFR_FUNCTION_COMPLETE:
- // wait for dma transfer to complete or fifo to drain
- if (dma_command && !(status & S_TC0) && fifo_pos)
+ // wait for dma transfer to complete and fifo to drain
+ if (dma_command && (!(status & S_TC0) || fifo_pos))
break;
-
function_complete();
break;
case INIT_XFR_BUS_COMPLETE:
- // wait for dma transfer to complete or fifo to drain
- if (dma_command && !(status & S_TC0) && fifo_pos)
+ // wait for dma transfer to complete and fifo to drain
+ // (FIFO may still contain one residual byte if enabled for 16-bit DMA)
+ if (dma_command && drq)
break;
-
bus_complete();
break;
@@ -676,18 +742,19 @@ void ncr5390_device::step(bool timeout)
state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT);
exit(0);
}
+
+ assert(stepping > 0);
+ stepping--;
}
-void ncr5390_device::send_byte()
+void ncr53c90_device::send_byte()
{
- if(!fifo_pos)
- fatalerror("ncr5390_device::send_byte - !fifo_pos\n");
-
state = (state & STATE_MASK) | (SEND_WAIT_SETTLE << SUB_SHIFT);
- if((state & STATE_MASK) != INIT_XFR_SEND_PAD &&
- ((state & STATE_MASK) != DISC_SEL_SEND_BYTE ||
- command_length))
+ if((state & STATE_MASK) != INIT_XFR_SEND_PAD) {
+ if(!fifo_pos)
+ fatalerror("ncr53c90_device::send_byte - !fifo_pos\n");
scsi_bus->data_w(scsi_refid, fifo_pop());
+ }
else
scsi_bus->data_w(scsi_refid, 0);
@@ -696,14 +763,14 @@ void ncr5390_device::send_byte()
delay_cycles(sync_period);
}
-void ncr5390_device::recv_byte()
+void ncr53c90_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()
+void ncr53c90_device::function_bus_complete()
{
LOG("function_bus_complete\n");
state = IDLE;
@@ -713,7 +780,7 @@ void ncr5390_device::function_bus_complete()
check_irq();
}
-void ncr5390_device::function_complete()
+void ncr53c90_device::function_complete()
{
LOG("function_complete\n");
state = IDLE;
@@ -723,7 +790,7 @@ void ncr5390_device::function_complete()
check_irq();
}
-void ncr5390_device::bus_complete()
+void ncr53c90_device::bus_complete()
{
LOG("bus_complete\n");
state = IDLE;
@@ -733,7 +800,7 @@ void ncr5390_device::bus_complete()
check_irq();
}
-void ncr5390_device::delay(int cycles)
+void ncr53c90_device::delay(int cycles)
{
if(!clock_conv)
return;
@@ -741,51 +808,55 @@ void ncr5390_device::delay(int cycles)
tm->adjust(clocks_to_attotime(cycles));
}
-void ncr5390_device::delay_cycles(int cycles)
+void ncr53c90_device::delay_cycles(int cycles)
{
tm->adjust(clocks_to_attotime(cycles));
}
-uint8_t ncr5390_device::tcounter_lo_r()
+uint8_t ncr53c90_device::tcounter_lo_r()
{
LOG("tcounter_lo_r %02x (%s)\n", tcounter & 0xff, machine().describe_context());
return tcounter;
}
-void ncr5390_device::tcount_lo_w(uint8_t data)
+void ncr53c90_device::tcount_lo_w(uint8_t data)
{
- tcount = (tcount & 0xff00) | data;
+ tcount = (tcount & ~uint32_t(0xff)) | data;
LOG("tcount_lo_w %02x (%s)\n", data, machine().describe_context());
}
-uint8_t ncr5390_device::tcounter_hi_r()
+uint8_t ncr53c90_device::tcounter_hi_r()
{
- LOG("tcounter_hi_r %02x (%s)\n", tcounter >> 8, machine().describe_context());
+ LOG("tcounter_hi_r %02x (%s)\n", (tcounter >> 8) & 0xff, machine().describe_context());
return tcounter >> 8;
}
-void ncr5390_device::tcount_hi_w(uint8_t data)
+void ncr53c90_device::tcount_hi_w(uint8_t data)
{
- tcount = (tcount & 0x00ff) | (data << 8);
+ tcount = (tcount & ~uint32_t(0xff00)) | (uint32_t(data) << 8);
LOG("tcount_hi_w %02x (%s)\n", data, machine().describe_context());
}
-uint8_t ncr5390_device::fifo_pop()
+uint8_t ncr53c90_device::fifo_pop()
{
uint8_t r = fifo[0];
- fifo_pos--;
- memmove(fifo, fifo+1, fifo_pos);
+ if(fifo_pos) {
+ fifo_pos--;
+ memmove(fifo, fifo+1, fifo_pos);
+ }
check_drq();
return r;
}
-void ncr5390_device::fifo_push(uint8_t val)
+void ncr53c90_device::fifo_push(uint8_t val)
{
- fifo[fifo_pos++] = val;
+ LOGMASKED(LOG_FIFO, "Push %02x to FIFO at position %d\n", val, fifo_pos);
+ if(fifo_pos != 16)
+ fifo[fifo_pos++] = val;
check_drq();
}
-uint8_t ncr5390_device::fifo_r()
+uint8_t ncr53c90_device::fifo_r()
{
uint8_t r;
if(fifo_pos) {
@@ -794,24 +865,29 @@ uint8_t ncr5390_device::fifo_r()
memmove(fifo, fifo+1, fifo_pos);
} else
r = 0;
+
+ check_drq();
LOGMASKED(LOG_FIFO, "fifo_r 0x%02x fifo_pos %d (%s)\n", r, fifo_pos, machine().describe_context());
return r;
}
-void ncr5390_device::fifo_w(uint8_t data)
+void ncr53c90_device::fifo_w(uint8_t data)
{
LOGMASKED(LOG_FIFO, "fifo_w 0x%02x fifo_pos %d (%s)\n", data, fifo_pos, machine().describe_context());
if(fifo_pos != 16)
fifo[fifo_pos++] = data;
+
+ check_drq();
+ step(false);
}
-uint8_t ncr5390_device::command_r()
+uint8_t ncr53c90_device::command_r()
{
LOG("command_r (%s)\n", machine().describe_context());
return command[0];
}
-void ncr5390_device::command_w(uint8_t data)
+void ncr53c90_device::command_w(uint8_t data)
{
LOG("command_w %02x command_pos %d (%s)\n", data, command_pos, machine().describe_context());
if(command_pos == 2) {
@@ -831,7 +907,7 @@ void ncr5390_device::command_w(uint8_t data)
start_command();
}
-void ncr5390_device::command_pop_and_chain()
+void ncr53c90_device::command_pop_and_chain()
{
if(command_pos) {
command_pos--;
@@ -842,7 +918,7 @@ void ncr5390_device::command_pop_and_chain()
}
}
-void ncr5390_device::start_command()
+void ncr53c90_device::start_command()
{
uint8_t c = command[0] & 0x7f;
if(!check_valid_command(c)) {
@@ -856,13 +932,16 @@ void ncr5390_device::start_command()
dma_command = command[0] & 0x80;
if (dma_command)
{
+ LOGMASKED(LOG_COMMAND, "DMA command: tcounter reloaded to %d\n", tcount);
tcounter = tcount;
// clear transfer count zero flag when counter is reloaded
status &= ~S_TC0;
}
else
+ {
tcounter = 0;
+ }
switch(c) {
case CM_NOP:
@@ -914,6 +993,7 @@ void ncr5390_device::start_command()
case CD_DISABLE_SEL:
LOGMASKED(LOG_COMMAND, "Disable selection/reselection\n");
+ function_complete();
command_pop_and_chain();
break;
@@ -941,7 +1021,7 @@ void ncr5390_device::start_command()
// arbirary 1 here makes InterPro happy. Also in the InterPro case (perhaps typical),
// after ACK is asserted the device disconnects and the INIT_MSG_WAIT_REQ state is never
// entered, meaning we end up with I_DISCONNECT instead of I_BUS interrupt status.
- seq = 1;
+ seq = 2;
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
step(false);
break;
@@ -970,11 +1050,11 @@ void ncr5390_device::start_command()
break;
default:
- fatalerror("ncr5390_device::start_command unimplemented command %02x\n", c);
+ fatalerror("ncr53c90_device::start_command unimplemented command %02x\n", c);
}
}
-bool ncr5390_device::check_valid_command(uint8_t cmd)
+bool ncr53c90_device::check_valid_command(uint8_t cmd)
{
int subcmd = cmd & 15;
switch((cmd >> 4) & 7) {
@@ -986,7 +1066,7 @@ bool ncr5390_device::check_valid_command(uint8_t cmd)
return false;
}
-void ncr5390_device::arbitrate()
+void ncr53c90_device::arbitrate()
{
state = (state & STATE_MASK) | (ARB_COMPLETE << SUB_SHIFT);
scsi_bus->data_w(scsi_refid, 1 << scsi_id);
@@ -994,7 +1074,7 @@ void ncr5390_device::arbitrate()
delay(11);
}
-void ncr5390_device::check_irq()
+void ncr53c90_device::check_irq()
{
bool oldirq = irq;
irq = istatus != 0;
@@ -1003,72 +1083,75 @@ void ncr5390_device::check_irq()
}
-uint8_t ncr5390_device::status_r()
+uint8_t ncr53c90_device::status_r()
{
uint32_t ctrl = scsi_bus->ctrl_r();
uint8_t res = status | (ctrl & S_MSG ? 4 : 0) | (ctrl & S_CTL ? 2 : 0) | (ctrl & S_INP ? 1 : 0);
- LOG("status_r %02x (%s)\n", res, machine().describe_context());
+ //LOG("status_r %02x (%s)\n", res, machine().describe_context());
return res;
}
-void ncr5390_device::bus_id_w(uint8_t data)
+void ncr53c90_device::bus_id_w(uint8_t data)
{
bus_id = data & 7;
LOG("bus_id=%d\n", bus_id);
}
-uint8_t ncr5390_device::istatus_r()
+uint8_t ncr53c90_device::istatus_r()
{
uint8_t res = istatus;
- if (irq)
+ if (!machine().side_effects_disabled())
{
- status &= ~(S_GROSS_ERROR | S_PARITY | S_TCC);
- istatus = 0;
- seq = 0;
- }
- check_irq();
- if(res)
- command_pop_and_chain();
+ if (irq)
+ {
+ status &= ~(S_GROSS_ERROR | S_PARITY | S_TCC);
+ istatus = 0;
+ seq = 0;
+ }
+ check_irq();
+ if(res)
+ command_pop_and_chain();
- LOG("istatus_r %02x (%s)\n", res, machine().describe_context());
+ LOG("istatus_r %02x (%s)\n", res, machine().describe_context());
+ }
return res;
}
-void ncr5390_device::timeout_w(uint8_t data)
+void ncr53c90_device::timeout_w(uint8_t data)
{
LOG("timeout_w 0x%02x\n", data);
select_timeout = data;
}
-uint8_t ncr5390_device::seq_step_r()
+uint8_t ncr53c90_device::seq_step_r()
{
LOG("seq_step_r %d (%s)\n", seq, machine().describe_context());
return seq;
}
-void ncr5390_device::sync_period_w(uint8_t data)
+void ncr53c90_device::sync_period_w(uint8_t data)
{
sync_period = data & 0x1f;
}
-uint8_t ncr5390_device::fifo_flags_r()
+uint8_t ncr53c90_device::fifo_flags_r()
{
return fifo_pos;
}
-void ncr5390_device::sync_offset_w(uint8_t data)
+void ncr53c90_device::sync_offset_w(uint8_t data)
{
sync_offset = data & 0x0f;
}
-uint8_t ncr5390_device::conf_r()
+uint8_t ncr53c90_device::conf_r()
{
return config;
}
-void ncr5390_device::conf_w(uint8_t data)
+void ncr53c90_device::conf_w(uint8_t data)
{
config = data;
scsi_id = data & 7;
@@ -1078,44 +1161,48 @@ void ncr5390_device::conf_w(uint8_t data)
test_mode = true;
}
-void ncr5390_device::test_w(uint8_t data)
+void ncr53c90_device::test_w(uint8_t data)
{
if (test_mode)
logerror("test_w %d (%s) - test mode not implemented\n", data, machine().describe_context());
}
-void ncr5390_device::clock_w(uint8_t data)
+void ncr53c90_device::clock_w(uint8_t data)
{
clock_conv = data & 0x07;
}
-void ncr5390_device::dma_set(int dir)
+void ncr53c90_device::dma_set(int dir)
{
dma_dir = dir;
-
- // account for data already in the fifo
- if (dir == DMA_OUT && fifo_pos)
- decrement_tcounter(fifo_pos);
}
-void ncr5390_device::dma_w(uint8_t val)
+void ncr53c90_device::dma_w(uint8_t val)
{
+ LOGMASKED(LOG_FIFO, "dma_w 0x%02x fifo_pos %d tcounter %d (%s)\n", val, fifo_pos, tcounter, machine().describe_context());
fifo_push(val);
decrement_tcounter();
check_drq();
step(false);
}
-uint8_t ncr5390_device::dma_r()
+uint8_t ncr53c90_device::dma_r()
{
+ if (machine().side_effects_disabled())
+ return fifo[0];
+
uint8_t r = fifo_pop();
- decrement_tcounter();
+
+ if ((sync_offset != 0) || ((scsi_bus->ctrl_r() & S_PHASE_MASK) != S_PHASE_DATA_IN))
+ {
+ decrement_tcounter();
+ }
check_drq();
step(false);
return r;
}
-void ncr5390_device::check_drq()
+void ncr53c90_device::check_drq()
{
bool drq_state = drq;
@@ -1125,7 +1212,10 @@ void ncr5390_device::check_drq()
break;
case DMA_IN: // device to memory
- drq_state = !(status & S_TC0) && fifo_pos;
+ if (sync_offset == 0)
+ drq_state = (fifo_pos > 0);
+ else
+ drq_state = !(status & S_TC0) && fifo_pos;
break;
case DMA_OUT: // memory to device
@@ -1139,14 +1229,23 @@ void ncr5390_device::check_drq()
}
}
-void ncr5390_device::decrement_tcounter(int count)
+void ncr53c90_device::decrement_tcounter(int count)
{
if (!dma_command)
return;
- tcounter -= count;
+ // If tcounter is 0 but TC0 is not set yet then it should mean tcount is also 0.
+ // A tcount of 0 specifies the maximum length count (65536) so this should wrap
+ // from 0 to 65535 only once.
+ if (!(status & S_TC0))
+ tcounter = (tcounter - count) & tcounter_mask;
+ else
+ tcounter = 0;
+
if (tcounter == 0)
status |= S_TC0;
+
+ check_drq();
}
/*
@@ -1174,22 +1273,22 @@ void ncr53c90a_device::device_start()
config2 = 0;
- ncr5390_device::device_start();
+ ncr53c90_device::device_start();
}
void ncr53c90a_device::device_reset()
{
config2 = 0;
- ncr5390_device::device_reset();
+ ncr53c90_device::device_reset();
}
uint8_t ncr53c90a_device::status_r()
{
uint32_t ctrl = scsi_bus->ctrl_r();
uint8_t res = (irq ? S_INTERRUPT : 0) | status | (ctrl & S_MSG ? 4 : 0) | (ctrl & S_CTL ? 2 : 0) | (ctrl & S_INP ? 1 : 0);
- LOG("status_r %02x (%s)\n", res, machine().describe_context());
- if (irq)
+ //LOG("status_r %02x (%s)\n", res, machine().describe_context());
+ if (irq && !machine().side_effects_disabled())
status &= ~(S_GROSS_ERROR | S_PARITY | S_TCC);
return res;
}
@@ -1226,18 +1325,24 @@ u16 ncr53c94_device::dma16_r()
{
// check fifo underflow
if (fifo_pos < 2)
- fatalerror("ncr53c94_device::dma16_r fifo_pos %d\n", fifo_pos);
+ return dma_r() | 0xff00;
// pop two bytes from fifo
- u16 const data = (fifo[0] << 8) | fifo[1];
- fifo_pos -= 2;
- memmove(fifo, fifo + 2, fifo_pos);
+ u16 const data = fifo[0] | (fifo[1] << 8);
+ if (!machine().side_effects_disabled())
+ {
+ fifo_pos -= 2;
+ memmove(fifo, fifo + 2, fifo_pos);
- // update drq
- decrement_tcounter(2);
- check_drq();
+ // update drq
+ if ((sync_offset != 0) || ((scsi_bus->ctrl_r() & S_PHASE_MASK) != S_PHASE_DATA_IN))
+ {
+ decrement_tcounter(2);
+ }
+ check_drq();
- step(false);
+ step(false);
+ }
return data;
}
@@ -1245,12 +1350,17 @@ u16 ncr53c94_device::dma16_r()
void ncr53c94_device::dma16_w(u16 data)
{
// check fifo overflow
- if (fifo_pos > 14)
- fatalerror("ncr53c94_device::dma16_w fifo_pos %d\n", fifo_pos);
+ if (fifo_pos > 14 || tcounter == 1)
+ {
+ dma_w(data & 0x00ff);
+ return;
+ }
+
+ LOGMASKED(LOG_FIFO, "dma16_w 0x%04x fifo_pos %d tcounter %d (%s)\n", data, fifo_pos, tcounter, machine().describe_context());
// push two bytes into fifo
- fifo[fifo_pos++] = data >> 8;
fifo[fifo_pos++] = data;
+ fifo[fifo_pos++] = data >> 8;
// update drq
decrement_tcounter(2);
@@ -1270,8 +1380,11 @@ void ncr53c94_device::check_drq()
drq_state = false;
break;
- case DMA_IN: // device to memory
- drq_state = !(status & S_TC0) && fifo_pos > 1;
+ case DMA_IN: // device to memory (optionally save last remaining byte for processor)
+ if (sync_offset == 0)
+ drq_state = fifo_pos > (BIT(config3, 2) || !(status & S_TC0) ? 1 : 0);
+ else
+ drq_state = !(status & S_TC0) && fifo_pos > 1;
break;
case DMA_OUT: // memory to device
@@ -1285,5 +1398,43 @@ void ncr53c94_device::check_drq()
}
}
else
- ncr5390_device::check_drq();
+ ncr53c90_device::check_drq();
+}
+
+void ncr53cf94_device::device_start()
+{
+ save_item(NAME(config4));
+
+ config4 = 0;
+
+ ncr53c94_device::device_start();
+}
+
+void ncr53cf94_device::device_reset()
+{
+ config4 = 0;
+
+ ncr53c94_device::device_reset();
+}
+
+void ncr53cf94_device::conf2_w(uint8_t data)
+{
+ tcounter_mask = (data & S2FE) ? 0xffffff : 0xffff;
+ config2 = data;
+}
+
+uint8_t ncr53cf94_device::tcounter_hi2_r()
+{
+ // tcounter is 24-bit when the features bit is set, otherwise it returns the ID
+ if ((config2 & S2FE) == 0)
+ return (1 << 7) | (family_id << 3) | revision_level;
+
+ LOG("tcounter_hi2_r %02x (%s)\n", (tcounter >> 16) & 0xff, machine().describe_context());
+ return tcounter >> 16;
+}
+
+void ncr53cf94_device::tcount_hi2_w(uint8_t data)
+{
+ tcount = (tcount & ~uint32_t(0xff0000)) | (uint32_t(data) << 16);
+ LOG("tcount_hi2_w %02x (%s)\n", data, machine().describe_context());
}
diff --git a/src/devices/machine/ncr5390.h b/src/devices/machine/ncr53c90.h
index 76952fe0f7b..e1c82d5e831 100644
--- a/src/devices/machine/ncr5390.h
+++ b/src/devices/machine/ncr53c90.h
@@ -1,16 +1,16 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
-#ifndef MAME_MACHINE_NCR5390_H
-#define MAME_MACHINE_NCR5390_H
+#ifndef MAME_MACHINE_NCR53C90_H
+#define MAME_MACHINE_NCR53C90_H
#pragma once
#include "machine/nscsi_bus.h"
-class ncr5390_device : public nscsi_device, public nscsi_slot_card_interface
+class ncr53c90_device : public nscsi_device, public nscsi_slot_card_interface
{
public:
- ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ncr53c90_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// configuration helpers
auto irq_handler_cb() { return m_irq_handler.bind(); }
@@ -48,11 +48,12 @@ public:
void dma_w(uint8_t val);
protected:
- ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+ ncr53c90_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_tick);
enum { MODE_D, MODE_T, MODE_I };
enum { IDLE };
@@ -194,17 +195,17 @@ protected:
uint8_t command[2], config, status, istatus;
uint8_t clock_conv, sync_offset, sync_period, bus_id, select_timeout, seq;
uint8_t fifo[16];
- uint16_t tcount;
- uint16_t tcounter;
+ uint32_t tcount;
+ uint32_t tcounter, tcounter_mask;
int mode, fifo_pos, command_pos;
int state, xfr_phase;
- int command_length;
int dma_dir;
bool irq, drq;
bool dma_command;
bool test_mode;
+ int stepping;
void dma_set(int dir);
virtual void check_drq();
@@ -236,7 +237,7 @@ protected:
devcb_write_line m_drq_handler;
};
-class ncr53c90a_device : public ncr5390_device
+class ncr53c90a_device : public ncr53c90_device
{
public:
ncr53c90a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -245,8 +246,8 @@ public:
virtual uint8_t status_r() override;
- uint8_t conf2_r() { return config2; };
- void conf2_w(uint8_t data) { config2 = data; };
+ uint8_t conf2_r() { return config2; }
+ virtual void conf2_w(uint8_t data) { config2 = data; }
virtual uint8_t read(offs_t offset) override;
virtual void write(offs_t offset, uint8_t data) override;
@@ -276,7 +277,7 @@ protected:
DAE = 0x80, // data alignment enable
};
-private:
+protected:
u8 config2;
};
@@ -296,9 +297,10 @@ public:
virtual void map(address_map &map) override;
- uint8_t conf3_r() { return config3; };
- void conf3_w(uint8_t data) { config3 = data; };
- void fifo_align_w(uint8_t data) { fifo_align = data; };
+ uint8_t conf3_r() { return config3; }
+ void conf3_w(uint8_t data) { config3 = data; }
+
+ void fifo_align_w(uint8_t data) { fifo_align = data; }
virtual uint8_t read(offs_t offset) override;
virtual void write(offs_t offset, uint8_t data) override;
@@ -306,6 +308,9 @@ public:
u16 dma16_r();
void dma16_w(u16 data);
+ u16 dma16_swap_r() { return swapendian_int16(dma16_r()); }
+ void dma16_swap_w(u16 data) { return dma16_w(swapendian_int16(data)); }
+
protected:
ncr53c94_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -326,15 +331,53 @@ private:
busmd_t m_busmd;
};
+class ncr53c96_device : public ncr53c94_device
+{
+public:
+ ncr53c96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
class ncr53cf94_device : public ncr53c94_device
{
public:
ncr53cf94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+
+ virtual void conf2_w(uint8_t data) override;
+
+ uint8_t conf4_r() { return config4; }
+ void conf4_w(uint8_t data) { config4 = data; }
+
+ uint8_t tcounter_hi2_r();
+ void tcount_hi2_w(uint8_t data);
+
+ virtual uint8_t read(offs_t offset) override;
+ virtual void write(offs_t offset, uint8_t data) override;
+
+protected:
+ ncr53cf94_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ u8 config4;
+ u8 family_id;
+ u8 revision_level;
+};
+
+class ncr53cf96_device : public ncr53cf94_device
+{
+public:
+ ncr53cf96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
-DECLARE_DEVICE_TYPE(NCR5390, ncr5390_device)
+DECLARE_DEVICE_TYPE(NCR53C90, ncr53c90_device)
DECLARE_DEVICE_TYPE(NCR53C90A, ncr53c90a_device)
DECLARE_DEVICE_TYPE(NCR53C94, ncr53c94_device)
+DECLARE_DEVICE_TYPE(NCR53C96, ncr53c96_device)
DECLARE_DEVICE_TYPE(NCR53CF94, ncr53cf94_device)
+DECLARE_DEVICE_TYPE(NCR53CF96, ncr53cf96_device)
-#endif // MAME_MACHINE_NCR5390_H
+#endif // MAME_MACHINE_NCR53C90_H
diff --git a/src/devices/machine/netlist.cpp b/src/devices/machine/netlist.cpp
index 76149986551..bba035194f3 100644
--- a/src/devices/machine/netlist.cpp
+++ b/src/devices/machine/netlist.cpp
@@ -1,4 +1,4 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
/***************************************************************************
@@ -11,14 +11,11 @@
#include "emu.h"
#include "netlist.h"
-#include "netlist/nl_base.h"
#include "netlist/nl_setup.h"
#include "netlist/nl_factory.h"
#include "netlist/nl_parser.h"
#include "netlist/nl_interface.h"
-#include "netlist/plib/palloc.h"
-#include "netlist/plib/pmempool.h"
#include "netlist/plib/pdynlib.h"
#include "netlist/plib/pstonum.h"
@@ -31,7 +28,6 @@
#include <string>
#include <utility>
-#define LOG_GENERAL (1U << 0)
#define LOG_DEV_CALLS (1U << 1)
#define LOG_DEBUG (1U << 2)
#define LOG_TIMING (1U << 3)
@@ -68,7 +64,7 @@ DEFINE_DEVICE_TYPE(NETLIST_STREAM_OUTPUT, netlist_mame_stream_output_device, "nl
// Special netlist extension devices ....
// ----------------------------------------------------------------------------------------
-extern const plib::dynlib_static_sym nl_static_solver_syms[];
+extern const plib::static_library::symbol nl_static_solver_syms[];
static netlist::netlist_time_ext nltime_from_attotime(attotime t)
{
@@ -77,13 +73,70 @@ static netlist::netlist_time_ext nltime_from_attotime(attotime t)
return nlmtime;
}
-#if 0
-static attotime attotime_from_nltime(netlist::netlist_time_ext t)
+void netlist_log_csv<1>::open(running_machine &machine, const std::string &name)
{
- return attotime(t.as_raw() / netlist::netlist_time_ext::resolution(),
- (t.as_raw() % netlist::netlist_time_ext::resolution()) * (ATTOSECONDS_PER_SECOND / netlist::netlist_time_ext::resolution()));
+ m_csv_file = fopen(name.c_str(), "wb");
+ m_machine = &machine;
}
-#endif
+
+void netlist_log_csv<1>::close()
+{
+ if (m_csv_file != nullptr)
+ {
+ log_flush();
+ fclose(m_csv_file);
+ }
+}
+
+void netlist_log_csv<1>::log_add(char const* param, double value, bool isfloat)
+{
+ // skip if no file
+ if (m_csv_file == nullptr)
+ return;
+
+ // make a new entry
+ buffer_entry entry = { (*m_machine).scheduler().time(), isfloat, value, param };
+
+ // flush out half of the old entries if we hit the buffer limit
+ if (m_buffer.size() >= MAX_BUFFER_ENTRIES)
+ log_flush(MAX_BUFFER_ENTRIES / 2);
+
+ // fast common case: if we go at the end, just push_back
+ if (m_buffer.size() == 0 || entry.time >= m_buffer.back().time)
+ {
+ m_buffer.push_back(entry);
+ return;
+ }
+
+ // find our place in the queue
+ for (auto cur = m_buffer.rbegin(); cur != m_buffer.rend(); cur++)
+ if (entry.time >= cur->time)
+ {
+ m_buffer.insert(cur.base(), entry);
+ return;
+ }
+
+ // if we're too early, drop this entry rather than risk putting an out-of-order
+ // entry after the last one we flushed
+}
+
+void netlist_log_csv<1>::log_flush(int count)
+{
+ if (m_csv_file == nullptr)
+ return;
+ if (count > m_buffer.size())
+ count = m_buffer.size();
+ while (count--)
+ {
+ auto &entry = m_buffer.front();
+ if (entry.isfloat)
+ fprintf(m_csv_file, "%s,%s,%f\n", entry.time.as_string(), entry.string, entry.value);
+ else
+ fprintf(m_csv_file, "%s,%s,%d\n", entry.time.as_string(), entry.string, int(entry.value));
+ m_buffer.pop_front();
+ }
+}
+
class netlist_mame_device::netlist_mame_t : public netlist::netlist_state_t
{
@@ -286,20 +339,18 @@ void netlist_mame_device::register_memregion_source(netlist::nlparse_t &parser,
void netlist_mame_analog_input_device::write(const double val)
{
- m_value_for_device_timer = val * m_mult + m_offset;
- if (m_value_for_device_timer != (*m_param)())
+ m_value_to_sync = val * m_mult + m_offset;
+ if (m_value_to_sync != (*m_param)())
{
- synchronize(0, 0, &m_value_for_device_timer);
-}
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(netlist_mame_analog_input_device::sync_callback), this));
+ }
}
-void netlist_mame_analog_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_analog_input_device::sync_callback)
{
update_to_current_time();
-#if NETLIST_CREATE_CSV
- nl_owner().log_add(m_param_name, *((double *) ptr), true);
-#endif
- m_param->set(*((double *) ptr));
+ nl_owner().log_csv().log_add(m_param_name, m_value_to_sync, true);
+ m_param->set(m_value_to_sync);
}
void netlist_mame_int_input_device::write(const uint32_t val)
@@ -308,7 +359,7 @@ void netlist_mame_int_input_device::write(const uint32_t val)
if (v != (*m_param)())
{
LOGDEBUG("write %s\n", this->tag());
- synchronize(0, v);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(netlist_mame_int_input_device::sync_callback), this), v);
}
}
@@ -318,29 +369,25 @@ void netlist_mame_logic_input_device::write(const uint32_t val)
if (v != (*m_param)())
{
LOGDEBUG("write %s\n", this->tag());
- synchronize(0, v);
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(netlist_mame_logic_input_device::sync_callback), this), v);
}
}
-void netlist_mame_int_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_int_input_device::sync_callback)
{
update_to_current_time();
-#if NETLIST_CREATE_CSV
- nl_owner().log_add(m_param_name, param, false);
-#endif
+ nl_owner().log_csv().log_add(m_param_name, param, false);
m_param->set(param);
}
-void netlist_mame_logic_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_logic_input_device::sync_callback)
{
update_to_current_time();
-#if NETLIST_CREATE_CSV
- nl_owner().log_add(m_param_name, param, false);
-#endif
+ nl_owner().log_csv().log_add(m_param_name, param, false);
m_param->set(param);
}
-void netlist_mame_ram_pointer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_ram_pointer_device::sync_callback)
{
m_data = (*m_param)();
}
@@ -374,56 +421,6 @@ void netlist_mame_sub_interface::set_mult_offset(const double mult, const double
m_offset = offset;
}
-#if NETLIST_CREATE_CSV
-void netlist_mame_device::log_add(char const* param, double value, bool isfloat)
-{
- // skip if no file
- if (m_csv_file == nullptr)
- return;
-
- // make a new entry
- buffer_entry entry = { machine().scheduler().time(), isfloat, value, param };
-
- // flush out half of the old entries if we hit the buffer limit
- if (m_buffer.size() >= MAX_BUFFER_ENTRIES)
- log_flush(MAX_BUFFER_ENTRIES / 2);
-
- // fast common case: if we go at the end, just push_back
- if (m_buffer.size() == 0 || entry.time >= m_buffer.back().time)
- {
- m_buffer.push_back(entry);
- return;
- }
-
- // find our place in the queue
- for (auto cur = m_buffer.rbegin(); cur != m_buffer.rend(); cur++)
- if (entry.time >= cur->time)
- {
- m_buffer.insert(cur.base(), entry);
- return;
- }
-
- // if we're too early, drop this entry rather than risk putting an out-of-order
- // entry after the last one we flushed
-}
-
-void netlist_mame_device::log_flush(int count)
-{
- if (m_csv_file == nullptr)
- return;
- if (count > m_buffer.size())
- count = m_buffer.size();
- while (count--)
- {
- auto &entry = m_buffer.front();
- if (entry.isfloat)
- fprintf(m_csv_file, "%s,%s,%f\n", entry.time.as_string(), entry.string, entry.value);
- else
- fprintf(m_csv_file, "%s,%s,%d\n", entry.time.as_string(), entry.string, int(entry.value));
- m_buffer.pop_front();
- }
-}
-#endif
netlist_mame_analog_input_device::netlist_mame_analog_input_device(const machine_config &mconfig, const char *tag, device_t *owner, const char *param_name)
: device_t(mconfig, NETLIST_ANALOG_INPUT, tag, owner, 0)
@@ -431,7 +428,7 @@ netlist_mame_analog_input_device::netlist_mame_analog_input_device(const machine
, m_param(nullptr)
, m_auto_port(true)
, m_param_name(param_name)
- , m_value_for_device_timer(0)
+ , m_value_to_sync(0)
{
}
@@ -441,7 +438,7 @@ netlist_mame_analog_input_device::netlist_mame_analog_input_device(const machine
, m_param(nullptr)
, m_auto_port(true)
, m_param_name("")
- , m_value_for_device_timer(0)
+ , m_value_to_sync(0)
{
}
@@ -497,7 +494,7 @@ void netlist_mame_analog_output_device::custom_netlist_additions(netlist::nlpars
pstring dname = pstring("OUT_") + pin;
parser.register_dev(dname, dname);
- parser.register_link(dname + ".IN", pin);
+ parser.register_connection(dname + ".IN", pin);
}
void netlist_mame_analog_output_device::pre_parse_action(netlist::nlparse_t &parser)
@@ -547,7 +544,7 @@ void netlist_mame_logic_output_device::custom_netlist_additions(netlist::nlparse
pstring dname = pstring("OUT_") + pin;
parser.register_dev(dname, dname);
- parser.register_link(dname + ".IN", pin);
+ parser.register_connection(dname + ".IN", pin);
}
void netlist_mame_logic_output_device::pre_parse_action(netlist::nlparse_t &parser)
@@ -814,10 +811,6 @@ void netlist_mame_stream_output_device::device_start()
void netlist_mame_stream_output_device::device_reset()
{
LOGDEVCALLS("reset %s\n", name());
-#if 0
- m_cur = 0.0;
- m_last_buffer_time = netlist::netlist_time_ext::zero();
-#endif
}
void netlist_mame_stream_output_device::sound_update_fill(write_stream_view &target)
@@ -828,7 +821,8 @@ void netlist_mame_stream_output_device::sound_update_fill(write_stream_view &tar
int sampindex;
for (sampindex = 0; sampindex < m_buffer.size(); sampindex++)
target.put(sampindex, m_buffer[sampindex]);
- target.fill(m_cur, sampindex);
+ if (sampindex < target.samples())
+ target.fill(m_cur, sampindex);
}
@@ -854,7 +848,7 @@ void netlist_mame_stream_output_device::custom_netlist_additions(netlist::nlpars
pstring dname = plib::pfmt("STREAM_OUT_{1}")(m_channel);
parser.register_dev(dname, dname);
- parser.register_link(dname + ".IN", pstring(m_out_name));
+ parser.register_connection(dname + ".IN", pstring(m_out_name));
}
void netlist_mame_stream_output_device::process(netlist::netlist_time_ext tim, netlist::nl_fptype val)
@@ -988,7 +982,7 @@ std::unique_ptr<netlist::netlist_state_t> netlist_mame_device::base_validity_che
plib::plog_delegate(&validity_logger::log, &logger));
// enable validation mode
- lnetlist->set_static_solver_lib(std::make_unique<plib::dynlib_static>(nullptr));
+ lnetlist->set_static_solver_lib(std::make_unique<plib::static_library>(nullptr));
common_dev_start(lnetlist.get());
lnetlist->setup().prepare_to_run();
@@ -1036,7 +1030,7 @@ void netlist_mame_device::device_start_common()
{
m_netlist = std::make_unique<netlist_mame_t>(*this, "netlist");
- m_netlist->set_static_solver_lib(std::make_unique<plib::dynlib_static>(nl_static_solver_syms));
+ m_netlist->set_static_solver_lib(std::make_unique<plib::static_library>(nl_static_solver_syms));
if (!machine().options().verbose())
{
@@ -1050,15 +1044,13 @@ void netlist_mame_device::device_start_common()
m_device_reset_called = false;
-#if NETLIST_CREATE_CSV
std::string name = machine().system().name;
name += tag();
for (int index = 0; index < name.size(); index++)
if (name[index] == ':')
name[index] = '_';
name += ".csv";
- m_csv_file = fopen(name.c_str(), "wb");
-#endif
+ log_csv().open(machine(), name);
LOGDEVCALLS("device_start exit\n");
}
@@ -1096,13 +1088,7 @@ void netlist_mame_device::device_stop()
LOGDEVCALLS("device_stop\n");
if (m_netlist)
netlist().exec().stop();
-#if NETLIST_CREATE_CSV
- if (m_csv_file != nullptr)
- {
- log_flush();
- fclose(m_csv_file);
- }
-#endif
+ log_csv().close();
}
void netlist_mame_device::device_post_load()
@@ -1262,6 +1248,16 @@ uint64_t netlist_mame_cpu_device::execute_cycles_to_clocks(uint64_t cycles) cons
return cycles;
}
+netlist::netlist_time_ext netlist_mame_cpu_device::nltime_ext_from_clocks(unsigned c) const noexcept
+{
+ return (m_div * c).shr(MDIV_SHIFT);
+}
+
+netlist::netlist_time netlist_mame_cpu_device::nltime_from_clocks(unsigned c) const noexcept
+{
+ return static_cast<netlist::netlist_time>((m_div * c).shr(MDIV_SHIFT));
+}
+
void netlist_mame_cpu_device::execute_run()
{
//m_ppc = m_pc; // copy PC to previous PC
diff --git a/src/devices/machine/netlist.h b/src/devices/machine/netlist.h
index 8b9e156adba..d9153f96cd2 100644
--- a/src/devices/machine/netlist.h
+++ b/src/devices/machine/netlist.h
@@ -1,4 +1,4 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
/***************************************************************************
@@ -57,6 +57,47 @@ namespace netlist {
void _name(const int data, const attotime &time)
+// ----------------------------------------------------------------------------------------
+// netlist_log_csv
+// ----------------------------------------------------------------------------------------
+
+template <int USE>
+struct netlist_log_csv
+{
+private:
+ static constexpr int MAX_BUFFER_ENTRIES = 1000;
+public:
+ void open(running_machine &machine, const std::string &name) { }
+ void close() { }
+ void log_add(char const* param, double value, bool isfloat) { }
+ void log_flush(int count = MAX_BUFFER_ENTRIES) { }
+
+private:
+};
+
+template <>
+struct netlist_log_csv<1>
+{
+private:
+ static constexpr int MAX_BUFFER_ENTRIES = 1000;
+public:
+ void open(running_machine &machine, const std::string &name);
+ void close();
+
+ void log_add(char const* param, double value, bool isfloat);
+ void log_flush(int count = MAX_BUFFER_ENTRIES);
+private:
+ struct buffer_entry
+ {
+ attotime time;
+ bool isfloat;
+ double value;
+ char const *string;
+ };
+ std::deque<buffer_entry> m_buffer;
+ FILE* m_csv_file = nullptr;
+ running_machine * m_machine;
+};
// ----------------------------------------------------------------------------------------
// netlist_mame_device
@@ -82,6 +123,7 @@ public:
static void register_memregion_source(netlist::nlparse_t &parser, device_t &dev, const char *name);
+ auto &log_csv() { return m_log_csv; }
protected:
netlist_mame_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -113,24 +155,7 @@ private:
func_type m_setup_func;
bool m_device_reset_called;
-#if NETLIST_CREATE_CSV
- static constexpr int MAX_BUFFER_ENTRIES = 1000;
-
-public:
- void log_add(char const* param, double value, bool isfloat);
- void log_flush(int count = MAX_BUFFER_ENTRIES);
-
-private:
- struct buffer_entry
- {
- attotime time;
- bool isfloat;
- double value;
- char const *string;
- };
- std::deque<buffer_entry> m_buffer;
- FILE* m_csv_file = nullptr;
-#endif
+ netlist_log_csv<NETLIST_CREATE_CSV> m_log_csv;
};
class netlist_mame_cpu_device : public netlist_mame_device,
@@ -168,16 +193,6 @@ public:
void update_icount(netlist::netlist_time_ext time) noexcept;
void check_mame_abort_slice() noexcept;
- netlist::netlist_time_ext nltime_ext_from_clocks(unsigned c) const noexcept
- {
- return (m_div * c).shr(MDIV_SHIFT);
- }
-
- netlist::netlist_time nltime_from_clocks(unsigned c) const noexcept
- {
- return static_cast<netlist::netlist_time>((m_div * c).shr(MDIV_SHIFT));
- }
-
protected:
// netlist_mame_device
virtual void nl_register_devices(netlist::nlparse_t &parser) const override;
@@ -204,6 +219,9 @@ protected:
address_space_config m_program_config;
private:
+ netlist::netlist_time_ext nltime_ext_from_clocks(unsigned c) const noexcept;
+ netlist::netlist_time nltime_from_clocks(unsigned c) const noexcept;
+
int m_icount;
netlist::netlist_time_ext m_div;
netlist::netlist_time_ext m_rem;
@@ -230,6 +248,8 @@ private:
// ----------------------------------------------------------------------------------------
// netlist_mame_sound_input_buffer
+//
+// This is a wrapper device to provide operator[] on read_stream_view.
// ----------------------------------------------------------------------------------------
class netlist_mame_sound_input_buffer : public read_stream_view
@@ -371,7 +391,7 @@ public:
else
write(newval);
}
- inline DECLARE_WRITE_LINE_MEMBER(write_line) { write(state); }
+ inline void write_line(int state) { write(state); }
inline void write8(uint8_t data) { write(data); }
inline void write16(uint16_t data) { write(data); }
inline void write32(uint32_t data) { write(data); }
@@ -382,13 +402,14 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(sync_callback);
private:
netlist::param_num_t<netlist::nl_fptype> *m_param;
bool m_auto_port;
const char *m_param_name;
- double m_value_for_device_timer;
+ double m_value_to_sync;
};
// ----------------------------------------------------------------------------------------
@@ -471,7 +492,7 @@ public:
void write(const uint32_t val);
inline DECLARE_INPUT_CHANGED_MEMBER(input_changed) { write(newval); }
- DECLARE_WRITE_LINE_MEMBER(write_line) { write(state); }
+ void write_line(int state) { write(state); }
void write8(uint8_t data) { write(data); }
void write16(uint16_t data) { write(data); }
void write32(uint32_t data) { write(data); }
@@ -482,7 +503,8 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(sync_callback);
private:
netlist::param_num_t<int> *m_param;
@@ -512,7 +534,7 @@ public:
void write(const uint32_t val);
inline DECLARE_INPUT_CHANGED_MEMBER(input_changed) { write(newval); }
- DECLARE_WRITE_LINE_MEMBER(write_line) { write(state); }
+ void write_line(int state) { write(state); }
void write8(uint8_t data) { write(data); }
void write16(uint16_t data) { write(data); }
void write32(uint32_t data) { write(data); }
@@ -523,7 +545,8 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(sync_callback);
private:
netlist::param_num_t<bool> *m_param;
@@ -551,7 +574,8 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(sync_callback);
private:
netlist::param_ptr_t *m_param;
diff --git a/src/devices/machine/nmc9306.cpp b/src/devices/machine/nmc9306.cpp
index d20e77a398b..2001f58e78d 100644
--- a/src/devices/machine/nmc9306.cpp
+++ b/src/devices/machine/nmc9306.cpp
@@ -43,11 +43,14 @@ enum
enum
{
STATE_IDLE = 0,
+ STATE_START,
STATE_COMMAND,
STATE_ADDRESS,
STATE_DATA_IN,
+ STATE_DUMMY_OUT,
STATE_DATA_OUT,
- STATE_ERASE
+ STATE_ERASE,
+ STATE_WRITE
};
@@ -73,11 +76,11 @@ inline uint16_t nmc9306_device::read(offs_t offset)
// nmc9306_device - constructor
//-------------------------------------------------
-inline void nmc9306_device::write(offs_t offset, uint16_t data)
+inline void nmc9306_device::write(offs_t offset, u16 data)
{
if (m_ewen)
{
- m_register[offset] &= data;
+ m_register[offset] = data;
}
}
@@ -104,11 +107,19 @@ inline void nmc9306_device::erase(offs_t offset)
// nmc9306_device - constructor
//-------------------------------------------------
-nmc9306_device::nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, NMC9306, tag, owner, clock),
- device_nvram_interface(mconfig, *this),
- m_state(STATE_IDLE),
- m_ewen(false)
+nmc9306_device::nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, NMC9306, tag, owner, clock),
+ device_nvram_interface(mconfig, *this),
+ m_bits(0),
+ m_state(STATE_IDLE),
+ m_command(0),
+ m_address(0),
+ m_data(0),
+ m_ewen(false),
+ m_cs(0),
+ m_sk(0),
+ m_do(0),
+ m_di(0)
{
}
@@ -142,6 +153,8 @@ void nmc9306_device::device_start()
void nmc9306_device::nvram_default()
{
+ for (auto & elem : m_register)
+ elem = 0xffff;
}
@@ -150,9 +163,10 @@ void nmc9306_device::nvram_default()
// .nv file
//-------------------------------------------------
-void nmc9306_device::nvram_read(emu_file &file)
+bool nmc9306_device::nvram_read(util::read_stream &file)
{
- file.read(m_register, RAM_SIZE);
+ auto const [err, actual] = util::read(file, m_register, RAM_SIZE);
+ return !err && (actual == RAM_SIZE);
}
@@ -161,9 +175,10 @@ void nmc9306_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void nmc9306_device::nvram_write(emu_file &file)
+bool nmc9306_device::nvram_write(util::write_stream &file)
{
- file.write(m_register, RAM_SIZE);
+ auto const [err, actual] = util::write(file, m_register, RAM_SIZE);
+ return !err;
}
@@ -171,8 +186,66 @@ void nmc9306_device::nvram_write(emu_file &file)
// cs_w - chip select input
//-------------------------------------------------
-WRITE_LINE_MEMBER( nmc9306_device::cs_w )
+void nmc9306_device::cs_w(int state)
{
+ if (m_cs != state)
+ {
+ LOG("NMC9306 CS %u\n", state);
+
+ if (m_cs && !state)
+ {
+ switch ((m_command >> 2) & 0x03)
+ {
+ case OTHER:
+ switch (m_command & 0x03)
+ {
+ case WRAL:
+ if (m_state == STATE_WRITE)
+ {
+ LOG("NMC9306 WRAL\n");
+ for (int address = 0; address < 16; address++)
+ {
+ write(address, m_data);
+ }
+ }
+ break;
+
+ case ERAL:
+ if (m_state == STATE_ERASE)
+ {
+ LOG("NMC9306 ERAL\n");
+ for (int address = 0; address < 16; address++)
+ {
+ erase(address);
+ }
+ }
+ break;
+ }
+ break;
+
+ case WRITE:
+ if (m_state == STATE_WRITE)
+ {
+ LOG("NMC9306 WRITE %u:%04x\n", m_address, m_data);
+ write(m_address, m_data);
+ }
+ break;
+
+ case ERASE:
+ if (m_state == STATE_ERASE)
+ {
+ LOG("NMC9306 ERASE %u\n", m_address);
+ erase(m_address);
+ }
+ break;
+ }
+
+ m_state = STATE_IDLE;
+ m_bits = 0;
+ m_do = 0;
+ }
+ }
+
m_cs = state;
}
@@ -181,20 +254,35 @@ WRITE_LINE_MEMBER( nmc9306_device::cs_w )
// ck_w - serial clock input
//-------------------------------------------------
-WRITE_LINE_MEMBER( nmc9306_device::sk_w )
+void nmc9306_device::sk_w(int state)
{
+ if (!m_cs) return;
+ if (m_sk == state) return;
+
+ LOG("NMC9306 SK %u\n", state);
+
m_sk = state;
- if (!m_cs || !m_sk) return;
+ if (m_sk && ((m_state == STATE_DUMMY_OUT) || (m_state == STATE_DATA_OUT))) return;
+ if (!m_sk && (m_state != STATE_DUMMY_OUT) && (m_state != STATE_DATA_OUT)) return;
switch (m_state)
{
case STATE_IDLE:
LOG("NMC9306 Idle %u\n", m_di);
- if (m_di)
+ if (!m_di)
{
// start bit received
+ m_state = STATE_START;
+ }
+ break;
+
+ case STATE_START:
+ LOG("NMC9306 Start %u\n", m_di);
+
+ if (m_di)
+ {
m_state = STATE_COMMAND;
m_bits = 0;
}
@@ -205,6 +293,8 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w )
m_command <<= 1;
m_command |= m_di;
+ m_command &= 0xf;
+
m_bits++;
if (m_bits == 4)
@@ -219,6 +309,8 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w )
m_address <<= 1;
m_address |= m_di;
+ m_address &= 0xf;
+
m_bits++;
if (m_bits == 4)
@@ -235,11 +327,13 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w )
break;
case WRAL:
- LOG("NMC9306 WRAL\n");
+ LOG("NMC9306 Command WRAL\n");
+ m_state = STATE_DATA_IN;
break;
case ERAL:
- LOG("NMC9306 ERAL\n");
+ LOG("NMC9306 Command ERAL\n");
+ m_state = ERASE;
break;
case EWEN:
@@ -251,20 +345,19 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w )
break;
case WRITE:
- LOG("NMC9306 WRITE %u\n", m_address & 0x0f);
+ LOG("NMC9306 Command WRITE %u\n", m_address);
m_state = STATE_DATA_IN;
break;
case READ:
- LOG("NMC9306 READ %u\n", m_address & 0x0f);
- m_data = read(m_address & 0x0f);
- m_state = STATE_DATA_OUT;
+ m_data = read(m_address);
+ LOG("NMC9306 READ %u:%04x\n", m_address, m_data);
+ m_state = STATE_DUMMY_OUT;
break;
case ERASE:
- LOG("NMC9306 ERASE %u\n", m_address & 0x0f);
- erase(m_address & 0x0f);
- m_state = STATE_ERASE;
+ LOG("NMC9306 Command ERASE %u\n", m_address);
+ m_state = ERASE;
break;
}
@@ -277,21 +370,29 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w )
m_data <<= 1;
m_data |= m_di;
+
m_bits++;
if (m_bits == 16)
{
- write(m_address & 0x0f, m_data);
-
- m_state = STATE_IDLE;
+ m_state = STATE_WRITE;
}
break;
- case STATE_DATA_OUT:
- LOG("NMC9306 Data Bit OUT %u\n", m_di);
+ case STATE_DUMMY_OUT:
+ m_do = 0;
+ LOG("NMC9306 Dummy Bit OUT %u\n", m_do);
+
+ m_state = STATE_DATA_OUT;
+ break;
+
+ case STATE_DATA_OUT:
m_do = BIT(m_data, 15);
m_data <<= 1;
+
+ LOG("NMC9306 Data Bit OUT %u\n", m_do);
+
m_bits++;
if (m_bits == 16)
@@ -307,7 +408,7 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w )
// di_w - serial data input
//-------------------------------------------------
-WRITE_LINE_MEMBER( nmc9306_device::di_w )
+void nmc9306_device::di_w(int state)
{
m_di = state;
}
@@ -317,7 +418,7 @@ WRITE_LINE_MEMBER( nmc9306_device::di_w )
// do_r - serial data output
//-------------------------------------------------
-READ_LINE_MEMBER( nmc9306_device::do_r )
+int nmc9306_device::do_r()
{
return m_do;
}
diff --git a/src/devices/machine/nmc9306.h b/src/devices/machine/nmc9306.h
index 07aa6b36db0..141a7bb62b0 100644
--- a/src/devices/machine/nmc9306.h
+++ b/src/devices/machine/nmc9306.h
@@ -33,10 +33,10 @@ public:
// construction/destruction
nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER( cs_w );
- DECLARE_WRITE_LINE_MEMBER( sk_w );
- DECLARE_WRITE_LINE_MEMBER( di_w );
- DECLARE_READ_LINE_MEMBER( do_r );
+ void cs_w(int state);
+ void sk_w(int state);
+ void di_w(int state);
+ int do_r();
protected:
// device-level overrides
@@ -44,26 +44,26 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
inline uint16_t read(offs_t offset);
- inline void write(offs_t offset, uint16_t data);
+ inline void write(offs_t offset, u16 data);
inline void erase(offs_t offset);
uint16_t m_register[16];
int m_bits;
int m_state;
- uint8_t m_command;
- uint8_t m_address;
- uint16_t m_data;
+ u8 m_command;
+ u8 m_address;
+ u16 m_data;
bool m_ewen;
- int m_cs;
- int m_sk;
- int m_do;
- int m_di;
+ bool m_cs;
+ bool m_sk;
+ bool m_do;
+ bool m_di;
};
diff --git a/src/devices/machine/nmk112.cpp b/src/devices/machine/nmk112.cpp
new file mode 100644
index 00000000000..4de5062ac14
--- /dev/null
+++ b/src/devices/machine/nmk112.cpp
@@ -0,0 +1,103 @@
+// license:BSD-3-Clause
+// copyright-holders:Alex W. Jackson
+/* NMK112 - NMK custom IC for bankswitching the sample ROMs of a pair of
+ OKI6295 ADPCM chips
+
+ The address space of each OKI6295 is divided into four banks, each one
+ independently controlled. The sample table at the beginning of the
+ address space may be divided in four pages as well, banked together
+ with the sample data. This allows each of the four voices on the chip
+ to play a sample from a different bank at the same time. */
+
+#include "emu.h"
+#include "nmk112.h"
+
+#define TABLESIZE 0x100
+#define BANKSIZE 0x10000
+
+
+
+DEFINE_DEVICE_TYPE(NMK112, nmk112_device, "nmk112", "NMK112")
+
+nmk112_device::nmk112_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, NMK112, tag, owner, clock)
+ , m_page_mask(0xff)
+ , m_rom0(*this, finder_base::DUMMY_TAG)
+ , m_rom1(*this, finder_base::DUMMY_TAG)
+ , m_size0(0)
+ , m_size1(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nmk112_device::device_start()
+{
+ save_item(NAME(m_current_bank));
+
+ if (m_rom0)
+ m_size0 = m_rom0.bytes() - 0x40000;
+
+ if (m_rom1)
+ m_size1 = m_rom1.bytes() - 0x40000;
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void nmk112_device::device_reset()
+{
+ for (int i = 0; i < 8; i++)
+ {
+ m_current_bank[i] = 0;
+ do_bankswitch(i, m_current_bank[i]);
+ }
+}
+
+void nmk112_device::do_bankswitch( int offset, int data )
+{
+ int chip = (offset & 4) >> 2;
+ int banknum = offset & 3;
+ int paged = (m_page_mask & (1 << chip));
+
+ uint8_t *rom = chip ? m_rom1 : m_rom0;
+ int size = chip ? m_size1 : m_size0;
+
+ m_current_bank[offset] = data;
+
+ if (size == 0) return;
+
+ int bankaddr = (data * BANKSIZE) % size;
+
+ /* copy the samples */
+ if ((paged) && (banknum == 0))
+ memcpy(rom + 0x400, rom + 0x40000 + bankaddr + 0x400, BANKSIZE - 0x400);
+ else
+ memcpy(rom + banknum * BANKSIZE, rom + 0x40000 + bankaddr, BANKSIZE);
+
+ /* also copy the sample address table, if it is paged on this chip */
+ if (paged)
+ {
+ rom += banknum * TABLESIZE;
+ memcpy(rom, rom + 0x40000 + bankaddr, TABLESIZE);
+ }
+}
+
+/*****************************************************************************
+ DEVICE HANDLERS
+*****************************************************************************/
+
+void nmk112_device::okibank_w(offs_t offset, u8 data)
+{
+ if (m_current_bank[offset] != data)
+ do_bankswitch(offset, data);
+}
+
+void nmk112_device::device_post_load()
+{
+ for (int i = 0; i < 8; i++)
+ do_bankswitch(i, m_current_bank[i]);
+}
diff --git a/src/devices/machine/nmk112.h b/src/devices/machine/nmk112.h
new file mode 100644
index 00000000000..5535d94899b
--- /dev/null
+++ b/src/devices/machine/nmk112.h
@@ -0,0 +1,53 @@
+// license:BSD-3-Clause
+// copyright-holders:Alex W. Jackson
+/*************************************************************************
+
+ nmk112.h
+
+**************************************************************************/
+
+#ifndef MAME_MACHINE_NMK112_H
+#define MAME_MACHINE_NMK112_H
+
+#pragma once
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+class nmk112_device : public device_t
+{
+public:
+ nmk112_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // configuration
+ template <typename T> nmk112_device &set_rom0_tag(T &&tag) { m_rom0.set_tag(std::forward<T>(tag)); return *this; }
+ template <typename T> nmk112_device &set_rom1_tag(T &&tag) { m_rom1.set_tag(std::forward<T>(tag)); return *this; }
+ nmk112_device &set_page_mask(uint8_t mask) { m_page_mask = ~mask; return *this; }
+
+ void okibank_w(offs_t offset, u8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_post_load() override;
+
+private:
+ void do_bankswitch( int offset, int data );
+
+ // internal state
+
+ /* which chips have their sample address table divided into pages */
+ uint8_t m_page_mask;
+
+ uint8_t m_current_bank[8];
+
+ optional_region_ptr<uint8_t> m_rom0, m_rom1;
+ int m_size0, m_size1;
+};
+
+DECLARE_DEVICE_TYPE(NMK112, nmk112_device)
+
+
+#endif // MAME_MACHINE_NMK112_H
diff --git a/src/devices/machine/ns32081.cpp b/src/devices/machine/ns32081.cpp
index 73941a85f2c..ab406a84d04 100644
--- a/src/devices/machine/ns32081.cpp
+++ b/src/devices/machine/ns32081.cpp
@@ -2,13 +2,15 @@
// copyright-holders:Patrick Mackinlay
/*
- * National Semiconductor 32081 Floating-Point Unit.
+ * National Semiconductor NS32081 Floating-Point Unit.
*
* Sources:
- * - http://bitsavers.org/components/national/_dataBooks/1989_National_Microprocessor_Databook_32000_NSC800.pdf
+ * - Microprocessor Databook, Series 32000, NSC800, 1989 Edition, National Semiconductor
*
* TODO:
- * - testing
+ * - poly/scalb/logb/dot
+ * - ns32381 timing
+ * - no-result operations
*/
#include "emu.h"
@@ -16,12 +18,12 @@
#include "softfloat3/source/include/softfloat.h"
-#define LOG_GENERAL (1U << 0)
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
-DEFINE_DEVICE_TYPE(NS32081, ns32081_device, "ns32081", "National Semiconductor 32081 Floating-Point Unit")
+DEFINE_DEVICE_TYPE(NS32081, ns32081_device, "ns32081", "National Semiconductor NS32081 Floating-Point Unit")
+DEFINE_DEVICE_TYPE(NS32381, ns32381_device, "ns32381", "National Semiconductor NS32381 Floating-Point Unit")
enum fsr_mask : u32
{
@@ -32,6 +34,7 @@ enum fsr_mask : u32
FSR_IF = 0x00000040, // inexact result flag
FSR_RM = 0x00000180, // rounding mode
FSR_SWF = 0x0000fe00, // software field
+ FSR_RMB = 0x00010000, // (32381 only) register modify bit
};
enum rm_mask : u32
@@ -62,148 +65,159 @@ enum state : unsigned
RESULT = 5, // result word available
};
-enum idbyte : u8
-{
- FORMAT_9 = 0x3e,
- FORMAT_11 = 0xbe,
-};
-
enum operand_length : unsigned
{
LENGTH_F = 4, // single precision
LENGTH_L = 8, // double precision
};
-enum size_code : unsigned
-{
- SIZE_B = 0,
- SIZE_W = 1,
- SIZE_D = 3,
-};
-
-ns32081_device::ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
- : device_t(mconfig, NS32081, tag, owner, clock)
- , ns32000_slave_interface(mconfig, *this)
+ns32081_device_base::ns32081_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , ns32000_fpu_interface(mconfig, *this)
{
}
-void ns32081_device::device_start()
+void ns32081_device_base::device_start()
{
save_item(NAME(m_fsr));
- save_item(NAME(m_f));
+ save_item(NAME(m_state));
save_item(NAME(m_idbyte));
save_item(NAME(m_opword));
+
save_item(STRUCT_MEMBER(m_op, expected));
save_item(STRUCT_MEMBER(m_op, issued));
save_item(STRUCT_MEMBER(m_op, value));
- save_item(NAME(m_status));
- save_item(NAME(m_state));
+ save_item(NAME(m_status));
save_item(NAME(m_tcy));
- m_complete = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32081_device::complete), this));
+ m_complete = timer_alloc(FUNC(ns32081_device::complete), this);
}
-void ns32081_device::device_reset()
+void ns32081_device_base::device_reset()
{
m_fsr = 0;
- std::fill_n(&m_f[0], ARRAY_LENGTH(m_f), 0);
-
m_state = IDLE;
+ m_idbyte = 0;
+ m_opword = 0;
+ m_status = 0;
+ m_tcy = 0;
}
-void ns32081_device::state_add(device_state_interface &parent, int &index)
+void ns32081_device_base::state_add(device_state_interface &parent, int &index)
{
parent.state_add(index++, "FSR", m_fsr).formatstr("%04X");
-
- for (unsigned i = 0; i < 8; i++)
- parent.state_add(index++, util::string_format("F%d", i).c_str(), m_f[i]).formatstr("%08X");
}
-u16 ns32081_device::read_st(int *icount)
+template <typename T> T ns32081_device_base::read()
{
- if (m_state == STATUS)
+ if (m_state == RESULT && m_op[2].issued < m_op[2].expected)
{
- m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT;
+ T const data = m_op[2].value >> (m_op[2].issued * 8);
- if (icount)
- *icount -= m_tcy;
+ m_op[2].issued += sizeof(T);
- LOG("read_st status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy,
- (m_state == RESULT ? "results pending" : "complete"), machine().describe_context());
+ LOG("read %d data 0x%0*x (%s)\n",
+ m_op[2].issued / sizeof(T), sizeof(T) * 2, data, machine().describe_context());
- return m_status;
+ if (m_op[2].issued == m_op[2].expected)
+ {
+ LOG("read complete\n");
+ m_state = IDLE;
+ }
+
+ return data;
}
- logerror("protocol error reading status word (%s)\n", machine().describe_context());
+ logerror("read protocol error (%s)\n", machine().describe_context());
return 0;
}
-u16 ns32081_device::read_op()
+template <typename T> void ns32081_device_base::write(T data)
{
- if (m_state == RESULT && m_op[2].issued < m_op[2].expected)
+ switch (m_state)
{
- u16 const data = u16(m_op[2].value >> (m_op[2].issued * 8));
- LOG("read_op word %d data 0x%04x (%s)\n", m_op[2].issued >> 1, data, machine().describe_context());
-
- m_op[2].issued += 2;
+ case IDLE:
+ if (sizeof(T) == 4)
+ {
+ // decode instruction
+ if (!decode(BIT(data, 24, 8), swapendian_int16(BIT(data, 8, 16))))
+ return;
- if (m_op[2].issued == m_op[2].expected)
+ m_state = OPERAND;
+ }
+ else
{
- LOG("read_op last result word issued\n");
- m_state = IDLE;
+ LOG("write idbyte 0x%04x (%s)\n", data, machine().describe_context());
+ if ((data == FORMAT_9) || (data == FORMAT_11) || (type() == NS32381 && data == FORMAT_12))
+ {
+ // record idbyte
+ m_idbyte = data;
+
+ m_state = OPERATION;
+ }
}
+ break;
- return data;
- }
+ case OPERATION:
+ LOG("write opword 0x%0*x (%s)\n", sizeof(T) * 2, data, machine().describe_context());
- logerror("protocol error reading result word (%s)\n", machine().describe_context());
- return 0;
-}
+ // decode instruction
+ decode(m_idbyte, swapendian_int16(data));
-void ns32081_device::write_id(u16 data)
-{
- bool const match = (data == FORMAT_9) || (data == FORMAT_11);
+ m_state = OPERAND;
+ break;
- if (match)
- {
- LOG("write_id match 0x%04x (%s)\n", data, machine().describe_context());
- m_state = OPERATION;
- }
- else
- {
- LOG("write_id ignore 0x%04x (%s)\n", data, machine().describe_context());
- m_state = IDLE;
+ case OPERAND:
+ // check awaiting operand data
+ if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected)
+ {
+ unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1;
+ operand &op = m_op[n];
+
+ LOG("write operand %d data 0x%0*x (%s)\n",
+ n, sizeof(T) * 2, data, machine().describe_context());
+
+ // insert data into operand value
+ op.value |= u64(data) << (op.issued * 8);
+ op.issued += sizeof(T);
+ }
+ else
+ logerror("write protocol error unexpected operand data 0x%0*x (%s)\n",
+ sizeof(T) * 2, data, machine().describe_context());
+ break;
}
- m_idbyte = u8(data);
+ // start execution when all operands are available
+ if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected)
+ execute();
}
-void ns32081_device::write_op(u16 data)
+bool ns32081_device_base::decode(u8 const idbyte, u16 const opword)
{
- switch (m_state)
- {
- case OPERATION:
- m_opword = swapendian_int16(data);
- LOG("write_op opword 0x%04x (%s)\n", m_opword, machine().describe_context());
+ LOG("decode idbyte 0x%02x opword 0x%04x (%s)\n", idbyte, opword, machine().describe_context());
- // initialize operands
- for (operand &op : m_op)
- {
- op.expected = 0;
- op.issued = 0;
- op.value = 0;
- }
+ m_idbyte = idbyte;
+ m_opword = opword;
+
+ // initialize operands
+ for (operand &op : m_op)
+ {
+ op.expected = 0;
+ op.issued = 0;
+ op.value = 0;
+ }
- // decode operands
- if (m_idbyte == FORMAT_9)
+ switch (m_idbyte)
+ {
+ case FORMAT_9:
{
// format 9: 1111 1222 22oo ofii
unsigned const f_length = BIT(m_opword, 2) ? LENGTH_F : LENGTH_L;
unsigned const size = m_opword & 3;
- switch ((m_opword >> 3) & 7)
+ switch (BIT(m_opword, 3, 3))
{
case 0: // movif
m_op[0].expected = size + 1;
@@ -231,10 +245,11 @@ void ns32081_device::write_op(u16 data)
break;
}
}
- else if (m_idbyte == FORMAT_11)
+ break;
+ case FORMAT_11:
{
// format 11: 1111 1222 22oo oo0f
- unsigned const opcode = (m_opword >> 2) & 15;
+ unsigned const opcode = BIT(m_opword, 2, 4);
unsigned const f_length = BIT(m_opword, 0) ? LENGTH_F : LENGTH_L;
m_op[0].expected = f_length;
@@ -247,68 +262,65 @@ void ns32081_device::write_op(u16 data)
if (opcode != 2)
m_op[2].expected = f_length;
}
-
- // operand 1 in register
- if (m_op[0].expected && !(m_opword & 0xc000))
+ break;
+ case FORMAT_12:
{
- // exclude integer operands
- if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) > 1)
- {
- unsigned const reg = (m_opword >> 11) & 7;
- LOG("write_op read f%d\n", reg);
-
- m_op[0].value = m_f[reg ^ 0];
- if (m_op[0].expected == 8)
- m_op[0].value |= u64(m_f[reg ^ 1]) << 32;
+ // format 12: 1111 1222 22oo oo0f
+ unsigned const f_length = BIT(m_opword, 0) ? LENGTH_F : LENGTH_L;
- m_op[0].issued = m_op[0].expected;
+ switch (BIT(m_opword, 2, 4))
+ {
+ case 2: // polyf
+ case 3: // dotf
+ m_op[0].expected = f_length;
+ m_op[1].expected = f_length;
+ break;
+ case 4: // scalbf
+ m_op[0].expected = f_length;
+ m_op[1].expected = f_length;
+ m_op[2].expected = f_length;
+ break;
+ case 5: // logbf
+ m_op[0].expected = f_length;
+ m_op[2].expected = f_length;
+ break;
}
}
+ break;
+ default:
+ LOG("decode idbyte 0x%02x unknown (%s)\n", m_idbyte, machine().describe_context());
+ return false;
+ }
- // operand 2 in register
- if (m_op[1].expected && !(m_opword & 0x0600))
+ // operand 1 in register
+ if (m_op[0].expected && !BIT(m_opword, 14, 2))
+ {
+ // exclude integer operands
+ if (m_idbyte != FORMAT_9 || (BIT(m_opword, 3, 3) > 1))
{
- unsigned const reg = (m_opword >> 6) & 7;
- LOG("write_op read f%d\n", reg);
+ reg_get(m_op[0].expected, m_op[0].value, BIT(m_opword, 11, 3));
- m_op[1].value = m_f[reg ^ 0];
- if (m_op[1].expected == 8)
- m_op[1].value |= u64(m_f[reg ^ 1]) << 32;
-
- m_op[1].issued = m_op[1].expected;
+ m_op[0].issued = m_op[0].expected;
}
+ }
- m_state = OPERAND;
- break;
-
- case OPERAND:
- // check awaiting operand word
- if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected)
- {
- unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1;
- operand &op = m_op[n];
-
- LOG("write_op op%d data 0x%04x (%s)\n", n, data, machine().describe_context());
+ // operand 2 in register
+ if (m_op[1].expected && !BIT(m_opword, 9, 2))
+ {
+ reg_get(m_op[1].expected, m_op[1].value, BIT(m_opword, 6, 3));
- // insert word into operand value
- op.value |= u64(data) << (op.issued * 8);
- op.issued += 2;
- }
- else
- logerror("protocol error unexpected operand word 0x%04x (%s)\n", data, machine().describe_context());
- break;
+ m_op[1].issued = m_op[1].expected;
}
- // start execution when all operands are available
- if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected)
- execute();
+ return true;
}
-void ns32081_device::execute()
+void ns32081_device_base::execute()
{
- softfloat_exceptionFlags = 0;
+ u32 const fsr = m_fsr;
m_fsr &= ~FSR_TT;
+ softfloat_exceptionFlags = 0;
m_status = 0;
m_tcy = 0;
@@ -316,235 +328,247 @@ void ns32081_device::execute()
{
case FORMAT_9:
// format 9: 1111 1222 22oo ofii
+ switch (BIT(m_opword, 3, 3))
{
- bool const single = BIT(m_opword, 2);
- unsigned const f_length = single ? LENGTH_F : LENGTH_L;
- unsigned const size = m_opword & 3;
-
- switch ((m_opword >> 3) & 7)
+ case 0:
+ // MOVif src,dest
+ // gen,gen
+ // read.i,write.f
{
- case 0:
- // MOVif src,dest
- // gen,gen
- // read.i,write.f
- {
- s32 const src =
- (size == SIZE_D) ? s32(m_op[0].value) :
- (size == SIZE_W) ? s16(m_op[0].value) :
- s8(m_op[0].value);
-
- if (single)
- m_op[2].value = i32_to_f32(src).v;
- else
- m_op[2].value = i32_to_f64(src).v;
- m_op[2].expected = f_length;
- m_tcy = 53;
- }
- break;
- case 1:
- // LFSR src
- // gen
- // read.D
- m_fsr = u16(m_op[0].value);
-
- switch (m_fsr & FSR_RM)
- {
- case RM_N: softfloat_roundingMode = softfloat_round_near_even; break;
- case RM_Z: softfloat_roundingMode = softfloat_round_minMag; break;
- case RM_U: softfloat_roundingMode = softfloat_round_max; break;
- case RM_D: softfloat_roundingMode = softfloat_round_min; break;
- }
- m_tcy = 18;
- break;
- case 2:
- // MOVLF src,dest
- // gen,gen
- // read.L,write.F
- m_op[2].value = f64_to_f32(float64_t{ m_op[0].value }).v;
- m_op[2].expected = f_length;
- m_tcy = (m_opword & 0xc000) ? 23 : 27;
- break;
- case 3:
- // MOVFL src,dest
- // gen,gen
- // read.F,write.L
- m_op[2].value = f32_to_f64(float32_t{ u32(m_op[0].value) }).v;
- m_op[2].expected = f_length;
- m_tcy = (m_opword & 0xc000) ? 22 : 26;
- break;
- case 4:
- // ROUNDfi src,dest
- // gen,gen
- // read.f,write.i
- if (single)
- m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_near_even, true);
- else
- m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_near_even, true);
-
- if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
- || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
- || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
- softfloat_exceptionFlags |= softfloat_flag_overflow;
+ s32 const src = util::sext<s32>(m_op[0].value, m_op[0].expected * 8);
- m_op[2].expected = size + 1;
- m_tcy = (m_opword & 0xc000) ? 53 : 66;
- break;
- case 5:
- // TRUNCfi src,dest
- // gen,gen
- // read.f,write.i
- if (single)
- m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_minMag, true);
+ if (m_op[2].expected == LENGTH_F)
+ m_op[2].value = i32_to_f32(src).v;
else
- m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_minMag, true);
+ m_op[2].value = i32_to_f64(src).v;
- if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
- || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
- || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
- softfloat_exceptionFlags |= softfloat_flag_overflow;
-
- m_op[2].expected = size + 1;
- m_tcy = (m_opword & 0xc000) ? 53 : 66;
- break;
- case 6:
- // SFSR dest
- // gen
- // write.D
- m_op[2].value = m_fsr;
- m_op[2].expected = 4;
- m_tcy = 13;
- break;
- case 7:
- // FLOORfi src,dest
- // gen,gen
- // read.f,write.i
- if (single)
- m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_min, true);
- else
- m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_min, true);
-
- if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
- || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
- || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
- softfloat_exceptionFlags |= softfloat_flag_overflow;
-
- m_op[2].expected = size + 1;
- m_tcy = (m_opword & 0xc000) ? 53 : 66;
- break;
+ m_tcy = 53;
+ }
+ break;
+ case 1:
+ // LFSR src
+ // gen
+ // read.D
+ m_fsr = u16(m_op[0].value);
+
+ switch (m_fsr & FSR_RM)
+ {
+ case RM_N: softfloat_roundingMode = softfloat_round_near_even; break;
+ case RM_Z: softfloat_roundingMode = softfloat_round_minMag; break;
+ case RM_U: softfloat_roundingMode = softfloat_round_max; break;
+ case RM_D: softfloat_roundingMode = softfloat_round_min; break;
}
+ m_tcy = 18;
+ break;
+ case 2:
+ // MOVLF src,dest
+ // gen,gen
+ // read.L,write.F
+ m_op[2].value = f64_to_f32(float64_t{ m_op[0].value }).v;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 23 : 27;
+ break;
+ case 3:
+ // MOVFL src,dest
+ // gen,gen
+ // read.F,write.L
+ m_op[2].value = f32_to_f64(float32_t{ u32(m_op[0].value) }).v;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 22 : 26;
+ break;
+ case 4:
+ // ROUNDfi src,dest
+ // gen,gen
+ // read.f,write.i
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_near_even, true);
+ else
+ m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_near_even, true);
+
+ if (s64(m_op[2].value) != util::sext<s64>(m_op[2].value, m_op[2].expected * 8))
+ softfloat_exceptionFlags |= softfloat_flag_overflow;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 53 : 66;
+ break;
+ case 5:
+ // TRUNCfi src,dest
+ // gen,gen
+ // read.f,write.i
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_minMag, true);
+ else
+ m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_minMag, true);
+
+ if (s64(m_op[2].value) != util::sext<s64>(m_op[2].value, m_op[2].expected * 8))
+ softfloat_exceptionFlags |= softfloat_flag_overflow;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 53 : 66;
+ break;
+ case 6:
+ // SFSR dest
+ // gen
+ // write.D
+ m_op[2].value = fsr;
+
+ m_tcy = 13;
+ break;
+ case 7:
+ // FLOORfi src,dest
+ // gen,gen
+ // read.f,write.i
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_min, true);
+ else
+ m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_min, true);
+
+ if (s64(m_op[2].value) != util::sext<s64>(m_op[2].value, m_op[2].expected * 8))
+ softfloat_exceptionFlags |= softfloat_flag_overflow;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 53 : 66;
+ break;
}
break;
case FORMAT_11:
- // format 11: 1111122222oooo0f
+ // format 11: 1111 1222 22oo oo0f
+ switch (BIT(m_opword, 2, 4))
{
- bool const single = BIT(m_opword, 0);
- unsigned const f_length = single ? LENGTH_F : LENGTH_L;
-
- switch ((m_opword >> 2) & 15)
- {
- case 0x0:
- // ADDf src,dest
- // gen,gen
- // read.f,rmw.f
- if (single)
- m_op[2].value = f32_add(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
- else
- m_op[2].value = f64_add(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
- m_op[2].expected = f_length;
- m_tcy = (m_opword & 0xc600) ? 70 : 74;
- break;
- case 0x1:
- // MOVf src,dest
- // gen,gen
- // read.f,write.f
- m_op[2].value = m_op[0].value;
- m_op[2].expected = f_length;
- m_tcy = (m_opword & 0xc000) ? 23 : 27;
- break;
- case 0x2:
- // CMPf src1,src2
- // gen,gen
- // read.f,read.f
- if (m_op[0].value == m_op[1].value)
- m_status |= SLAVE_Z;
- if ((single && f32_le(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }))
- || (!single && f64_le(float64_t{ m_op[1].value }, float64_t{ m_op[0].value })))
- m_status |= SLAVE_N;
- m_tcy = (m_opword & 0xc600) ? 45 : 49;
- break;
- case 0x3:
- // Trap(SLAVE)
- m_fsr |= TT_ILL;
- m_status = SLAVE_Q;
- break;
- case 0x4:
- // SUBf src,dest
- // gen,gen
- // read.f,rmw.f
- if (single)
- m_op[2].value = f32_sub(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
- else
- m_op[2].value = f64_sub(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
- m_op[2].expected = f_length;
- m_tcy = (m_opword & 0xc600) ? 70 : 74;
- break;
- case 0x5:
- // NEGf src,dest
- // gen,gen
- // read.f,write.f
- if (single)
+ case 0x0:
+ // ADDf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_add(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_add(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+
+ m_tcy = (m_opword & 0xc600) ? 70 : 74;
+ break;
+ case 0x1:
+ // MOVf src,dest
+ // gen,gen
+ // read.f,write.f
+ m_op[2].value = m_op[0].value;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 23 : 27;
+ break;
+ case 0x2:
+ // CMPf src1,src2
+ // gen,gen
+ // read.f,read.f
+ if (m_op[0].value == m_op[1].value)
+ m_status |= SLAVE_Z;
+ if ((m_op[0].expected == LENGTH_F && f32_le(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }))
+ || (m_op[0].expected == LENGTH_L && f64_le(float64_t{ m_op[1].value }, float64_t{ m_op[0].value })))
+ m_status |= SLAVE_N;
+
+ m_tcy = (m_opword & 0xc600) ? 45 : 49;
+ break;
+ case 0x3:
+ // Trap(SLAVE)
+ m_fsr |= TT_ILL;
+ m_status = SLAVE_Q;
+ break;
+ case 0x4:
+ // SUBf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_sub(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_sub(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+
+ m_tcy = (m_opword & 0xc600) ? 70 : 74;
+ break;
+ case 0x5:
+ // NEGf src,dest
+ // gen,gen
+ // read.f,write.f
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v;
+ else
+ m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 20 : 24;
+ break;
+ case 0x8:
+ // DIVf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_div(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_div(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+
+ m_tcy = ((m_opword & 0xc600) ? 55 : 59) + (m_op[0].expected == LENGTH_F ? 30 : 60);
+ break;
+ case 0x9:
+ // Trap(SLAVE)
+ m_fsr |= TT_ILL;
+ m_status = SLAVE_Q;
+ break;
+ case 0xc:
+ // MULf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (m_op[0].expected == LENGTH_F)
+ m_op[2].value = f32_mul(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_mul(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+
+ m_tcy = ((m_opword & 0xc600) ? 30 : 34) + (m_op[0].expected == LENGTH_F ? 14 : 28);
+ break;
+ case 0xd:
+ // ABSf src,dest
+ // gen,gen
+ // read.f,write.f
+ if (m_op[0].expected == LENGTH_F)
+ if (f32_lt(float32_t{ u32(m_op[0].value) }, float32_t{ 0 }))
m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v;
else
+ m_op[2].value = float32_t{ u32(m_op[0].value) }.v;
+ else
+ if (f64_lt(float64_t{ m_op[0].value }, float64_t{ 0 }))
m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v;
- m_op[2].expected = f_length;
- m_tcy = (m_opword & 0xc000) ? 20 : 24;
- break;
- case 0x8:
- // DIVf src,dest
- // gen,gen
- // read.f,rmw.f
- if (single)
- m_op[2].value = f32_div(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
- else
- m_op[2].value = f64_div(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
- m_op[2].expected = f_length;
- m_tcy = ((m_opword & 0xc600) ? 55 : 59) + (single ? 30 : 60);
- break;
- case 0x9:
- // Trap(SLAVE)
- m_fsr |= TT_ILL;
- m_status = SLAVE_Q;
- break;
- case 0xc:
- // MULf src,dest
- // gen,gen
- // read.f,rmw.f
- if (single)
- m_op[2].value = f32_mul(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
- else
- m_op[2].value = f64_mul(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
- m_op[2].expected = f_length;
- m_tcy = ((m_opword & 0xc600) ? 30 : 34) + (single ? 14 : 28);
- break;
- case 0xd:
- // ABSf src,dest
- // gen,gen
- // read.f,write.f
- if (single)
- if (f32_lt(float32_t{ u32(m_op[0].value) }, float32_t{ 0 }))
- m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v;
- else
- m_op[2].value = float32_t{ u32(m_op[0].value) }.v;
else
- if (f64_lt(float64_t{ m_op[0].value }, float64_t{ 0 }))
- m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v;
- else
- m_op[2].value = float64_t{ m_op[0].value }.v;
- m_op[2].expected = f_length;
- m_tcy = (m_opword & 0xc000) ? 20 : 24;
- break;
- }
+ m_op[2].value = float64_t{ m_op[0].value }.v;
+
+ m_tcy = BIT(m_opword, 14, 2) ? 20 : 24;
+ break;
+ }
+ break;
+
+ case FORMAT_12:
+ // format 12: 1111 1222 22oo oo0f
+ switch (BIT(m_opword, 2, 4))
+ {
+ case 0x2:
+ // POLYf src1,src2
+ // gen,gen
+ // read.f,read.f
+ m_fsr |= FSR_RMB;
+ break;
+ case 0x3:
+ // DOTf src1,src2
+ // gen,gen
+ // read.f,read.f
+ m_fsr |= FSR_RMB;
+ break;
+ case 0x4:
+ // SCALBf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ break;
+ case 0x5:
+ // LOGBf src,dest
+ // gen,gen
+ // read.f,write.f
+ break;
+ default:
+ // Trap(SLAVE)
+ m_fsr |= TT_ILL;
+ m_status = SLAVE_Q;
+ break;
}
break;
}
@@ -570,7 +594,10 @@ void ns32081_device::execute()
m_status |= SLAVE_Q;
}
else if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ {
m_fsr |= TT_INV;
+ m_status |= SLAVE_Q;
+ }
else if (softfloat_exceptionFlags & softfloat_flag_inexact)
{
m_fsr |= FSR_IF | TT_INX;
@@ -591,47 +618,177 @@ void ns32081_device::execute()
"addf", "movf", "cmpf", nullptr, "subf", "negf", nullptr, nullptr,
"divf", nullptr, nullptr, nullptr, "mulf", "absf", nullptr, nullptr
};
+ static char const *format12[] =
+ {
+ nullptr, nullptr, "polyf", "dotf", "scalbf", "logbf", nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
+ };
+
+ char const *operation = nullptr;
+ switch (m_idbyte)
+ {
+ case FORMAT_9: operation = format9[BIT(m_opword, 3, 3)]; break;
+ case FORMAT_11: operation = format11[BIT(m_opword, 2, 4)]; break;
+ case FORMAT_12: operation = format12[BIT(m_opword, 2, 4)]; break;
+ }
if (m_status & SLAVE_Q)
- LOG("execute %s 0x%x,0x%x exception\n",
- (m_idbyte == FORMAT_9)
- ? format9[(m_opword >> 3) & 7]
- : format11[(m_opword >> 2) & 15],
- m_op[0].value, m_op[1].value);
+ LOG("execute %s 0x%x,0x%x exception\n", operation, m_op[0].value, m_op[1].value);
else
- LOG("execute %s 0x%x,0x%x result 0x%x\n",
- (m_idbyte == FORMAT_9)
- ? format9[(m_opword >> 3) & 7]
- : format11[(m_opword >> 2) & 15],
- m_op[0].value, m_op[1].value, m_op[2].value);
+ LOG("execute %s 0x%x,0x%x result 0x%x\n", operation, m_op[0].value, m_op[1].value, m_op[2].value);
}
// write-back floating point register results
- if (m_op[2].expected && !(m_opword & 0x0600))
+ if (m_op[2].expected && !BIT(m_opword, 9, 2))
{
// exclude integer results (roundfi, truncfi, sfsr, floorfi)
- if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) < 4)
+ if (m_idbyte != FORMAT_9 || (BIT(m_opword, 3, 3) < 4))
{
- unsigned const reg = (m_opword >> 6) & 7;
+ reg_set(BIT(m_opword, 6, 3), m_op[2].expected, m_op[2].value);
- LOG("execute write-back f%d\n", reg);
-
- m_f[reg ^ 0] = u32(m_op[2].value >> 0);
- if (m_op[2].expected == 8)
- m_f[reg ^ 1] = u32(m_op[2].value >> 32);
+ if (type() == NS32381)
+ m_fsr |= FSR_RMB;
m_op[2].issued = m_op[2].expected;
}
}
+ if (!m_out_scb.isunset())
+ m_complete->adjust(attotime::from_ticks(m_tcy, clock()));
+
m_state = STATUS;
+}
- if (m_out_scb)
- m_complete->adjust(attotime::from_ticks(m_tcy, clock()));
+u16 ns32081_device_base::status(int *icount)
+{
+ if (m_state == STATUS)
+ {
+ m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT;
+
+ if (icount)
+ *icount -= m_tcy;
+
+ LOG("status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy,
+ (m_state == RESULT ? "results pending" : "complete"), machine().describe_context());
+
+ return m_status;
+ }
+
+ logerror("status protocol error (%s)\n", machine().describe_context());
+ return 0;
}
-void ns32081_device::complete(void *buf, s32 param)
+void ns32081_device_base::complete(s32 param)
{
m_out_scb(0);
m_out_scb(1);
}
+
+ns32081_device::ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : ns32081_device_base(mconfig, NS32081, tag, owner, clock)
+ , ns32000_slow_slave_interface(mconfig, *this)
+{
+}
+
+void ns32081_device::device_start()
+{
+ ns32081_device_base::device_start();
+
+ save_item(NAME(m_f));
+}
+
+void ns32081_device::device_reset()
+{
+ ns32081_device_base::device_reset();
+
+ std::fill(std::begin(m_f), std::end(m_f), 0);
+}
+
+void ns32081_device::state_add(device_state_interface &parent, int &index)
+{
+ ns32081_device_base::state_add(parent, index);
+
+ for (unsigned i = 0; i < 8; i++)
+ parent.state_add(index++, util::string_format("F%d", i).c_str(), m_f[i]).formatstr("%08X");
+}
+
+void ns32081_device::reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const
+{
+ op_value = m_f[reg ^ 0];
+ if (op_size == LENGTH_L)
+ op_value |= u64(m_f[reg ^ 1]) << 32;
+
+ if (op_size == LENGTH_L)
+ LOG("reg_get f%d:%d data 0x%016x\n", reg ^ 1, reg ^ 0, op_value);
+ else
+ LOG("reg_get f%d data 0x%08x\n", reg, op_value);
+}
+
+void ns32081_device::reg_set(unsigned const reg, unsigned const op_size, u64 const op_value)
+{
+ if (op_size == LENGTH_L)
+ LOG("reg_set f%d:%d data 0x%016x\n", reg ^ 1, reg ^ 0, op_value);
+ else
+ LOG("reg_set f%d data 0x%08x\n", reg, op_value);
+
+ m_f[reg ^ 0] = u32(op_value >> 0);
+ if (op_size == LENGTH_L)
+ m_f[reg ^ 1] = u32(op_value >> 32);
+}
+
+ns32381_device::ns32381_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : ns32081_device_base(mconfig, NS32381, tag, owner, clock)
+ , ns32000_slow_slave_interface(mconfig, *this)
+ , ns32000_fast_slave_interface(mconfig, *this)
+{
+}
+
+void ns32381_device::device_start()
+{
+ ns32081_device_base::device_start();
+
+ save_item(NAME(m_l));
+}
+
+void ns32381_device::device_reset()
+{
+ std::fill(std::begin(m_l), std::end(m_l), 0);
+}
+
+void ns32381_device::state_add(device_state_interface &parent, int &index)
+{
+ ns32081_device_base::state_add(parent, index);
+
+ for (unsigned i = 0; i < 8; i++)
+ parent.state_add(index++, util::string_format("L%d", i).c_str(), m_l[i]).formatstr("%016X");
+}
+
+void ns32381_device::reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const
+{
+ if (op_size == LENGTH_L)
+ op_value = m_l[reg];
+ else if (reg & 1)
+ op_value = m_l[reg & 6] >> 32;
+ else
+ op_value = u32(m_l[reg & 6]);
+
+ if (op_size == LENGTH_L)
+ LOG("reg_get l%d data 0x%016x\n", reg, op_value);
+ else
+ LOG("reg_get f%d data 0x%08x\n", reg, op_value);
+}
+
+void ns32381_device::reg_set(unsigned const reg, unsigned const op_size, u64 const op_value)
+{
+ if (op_size == LENGTH_L)
+ LOG("reg_set l%d data 0x%016x\n", reg, op_value);
+ else
+ LOG("reg_set f%d data 0x%08x\n", reg, op_value);
+
+ if (op_size == LENGTH_L)
+ m_l[reg] = op_value;
+ else if (reg & 1)
+ m_l[reg & 6] = (op_value << 32) | u32(m_l[reg & 6]);
+ else
+ m_l[reg & 6] = (m_l[reg & 6] & 0xffff'ffff'0000'0000ULL) | u32(op_value);
+}
diff --git a/src/devices/machine/ns32081.h b/src/devices/machine/ns32081.h
index 4097494c830..12a50d9434d 100644
--- a/src/devices/machine/ns32081.h
+++ b/src/devices/machine/ns32081.h
@@ -6,55 +6,121 @@
#pragma once
-#include "cpu/ns32000/slave.h"
+#include "cpu/ns32000/common.h"
-class ns32081_device
+class ns32081_device_base
: public device_t
- , public ns32000_slave_interface
+ , public ns32000_fpu_interface
{
-public:
- ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
-
- virtual void state_add(device_state_interface &parent, int &index) override;
-
- virtual u16 read_st(int *icount = nullptr) override;
- virtual u16 read_op() override;
-
- virtual void write_id(u16 data) override;
- virtual void write_op(u16 data) override;
-
protected:
- // device_t overrides
+ ns32081_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
+
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
+ // ns32000_slave_interface implementation
+ virtual void state_add(device_state_interface &parent, int &index) override;
+
+ // slave interface handlers
+ template <typename T> T read();
+ template <typename T> void write(T data);
+
+ // execution helpers
+ bool decode(u8 const idbyte, u16 const opword);
void execute();
- void complete(void *buf, s32 param);
+ u16 status(int *icount);
+ void complete(s32 param);
+
+ // register helpers
+ virtual void reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const = 0;
+ virtual void reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) = 0;
private:
emu_timer *m_complete;
- // registers
- u32 m_fsr;
- u32 m_f[8];
+ u32 m_fsr; // floating-point status register
// operating state
+ u32 m_state;
u8 m_idbyte;
u16 m_opword;
struct operand
{
- unsigned expected;
- unsigned issued;
+ u32 expected;
+ u32 issued;
u64 value;
}
m_op[3];
u16 m_status;
+ u32 m_tcy;
+};
+
+class ns32081_device
+ : public ns32081_device_base
+ , public ns32000_slow_slave_interface
+{
+public:
+ ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // ns32000_slave_interface implementation
+ virtual void state_add(device_state_interface &parent, int &index) override;
+
+ // ns32000_slow_slave_interface implementation
+ virtual u16 slow_status(int *icount = nullptr) override { return status(icount); }
+ virtual u16 slow_read() override { return read<u16>(); }
+ virtual void slow_write(u16 data) override { write<u16>(data); }
- // implementation state
- unsigned m_state;
- unsigned m_tcy;
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // register helpers
+ virtual void reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const override;
+ virtual void reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) override;
+
+private:
+ // registers
+ u32 m_f[8];
+};
+
+class ns32381_device
+ : public ns32081_device_base
+ , public ns32000_slow_slave_interface
+ , public ns32000_fast_slave_interface
+{
+public:
+ ns32381_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // ns32000_slave_interface implementation
+ virtual void state_add(device_state_interface &parent, int &index) override;
+
+ // ns32000_slow_slave_interface implementation
+ virtual u16 slow_status(int *icount = nullptr) override { return status(icount); }
+ virtual u16 slow_read() override { return read<u16>(); }
+ virtual void slow_write(u16 data) override { write<u16>(data); }
+
+ // ns32000_fast_slave_interface implementation
+ virtual u32 fast_status(int *icount = nullptr) override { return status(icount); }
+ virtual u32 fast_read() override { return read<u32>(); }
+ virtual void fast_write(u32 data) override { write<u32>(data); }
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // register helpers
+ virtual void reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const override;
+ virtual void reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) override;
+
+private:
+ // registers
+ u64 m_l[8];
};
DECLARE_DEVICE_TYPE(NS32081, ns32081_device)
+DECLARE_DEVICE_TYPE(NS32381, ns32381_device)
#endif // MAME_MACHINE_NS32081_H
diff --git a/src/devices/machine/ns32082.cpp b/src/devices/machine/ns32082.cpp
new file mode 100644
index 00000000000..ffe2f645274
--- /dev/null
+++ b/src/devices/machine/ns32082.cpp
@@ -0,0 +1,497 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * National Semiconductor NS32082 Memory Management Unit.
+ *
+ * Sources:
+ * - Microprocessor Databook, Series 32000, NSC800, 1989 Edition, National Semiconductor
+ *
+ * TODO:
+ * - tlb
+ * - breakpoints
+ */
+
+#include "emu.h"
+#include "ns32082.h"
+
+#define LOG_TRANSLATE (1U << 1)
+
+//#define VERBOSE (LOG_GENERAL|LOG_TRANSLATE)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(NS32082, ns32082_device, "ns32082", "National Semiconductor NS32082 Memory Management Unit")
+
+enum state : unsigned
+{
+ IDLE = 0,
+ OPERATION = 1, // awaiting operation word
+ OPERAND = 2, // awaiting operands
+ RDVAL = 3, // rdval pending
+ WRVAL = 4, // wrval pending
+ STATUS = 5, // status word available
+ RESULT = 6, // result word available
+};
+
+enum reg_mask : unsigned
+{
+ BPR0 = 0x0, // breakpoint register 0
+ BPR1 = 0x1, // breakpoint register 1
+ PF0 = 0x4, // program flow register 0 (removed at rev L)
+ PF1 = 0x5, // program flow register 1 (removed at rev L)
+ SC = 0x8, // sequential count register (removed at rev L)
+ MSR = 0xa, // memory management status register
+ BCNT = 0xb, // breakpoint counter register
+ PTB0 = 0xc, // page table base register 0
+ PTB1 = 0xd, // page table base register 1
+ EIA = 0xf, // error/invalidate address register
+};
+
+enum msr_mask : u32
+{
+ MSR_TE = 0x00000001, // translation error
+ MSR_R = 0x00000002, // reset
+ MSR_B = 0x00000004, // break
+ MSR_TET = 0x00000038, // translation error type
+ MSR_BN = 0x00000040, // breakpoint number
+ MSR_ED = 0x00000100, // error direction
+ MSR_BD = 0x00000200, // break direction
+ MSR_EST = 0x00001c00, // error status
+ MSR_BST = 0x0000e000, // breakpoint status
+ MSR_TU = 0x00010000, // translate user-mode addresses
+ MSR_TS = 0x00020000, // translate supervisor-mode addresses
+ MSR_DS = 0x00040000, // dual-space translation
+ MSR_AO = 0x00080000, // access level override
+ MSR_BEN = 0x00100000, // breakpoint enable
+ MSR_UB = 0x00200000, // user-only breakpointing
+ MSR_AI = 0x00400000, // abort/interrupt
+ MSR_FT = 0x00800000, // flow trace (removed at rev L)
+ MSR_UT = 0x01000000, // user trace (removed at rev L)
+ MSR_NT = 0x02000000, // nonsequential trace (removed at rev L)
+
+ MSR_ERC = 0x00000007,
+ MSR_WM = 0x03ff0000,
+};
+
+enum msr_tet_mask : u32
+{
+ TET_PL = 0x00000008,
+ TET_IL1 = 0x00000010,
+ TET_IL2 = 0x00000020,
+};
+
+enum ptb_mask : u32
+{
+ PTB_AB = 0x00fffc00, // address bits
+ PTB_MS = 0x80000000, // memory system
+};
+
+enum va_mask : u32
+{
+ VA_INDEX1 = 0x00ff0000,
+ VA_INDEX2 = 0x0000fe00,
+ VA_OFFSET = 0x000001ff,
+};
+
+enum pte_mask : u32
+{
+ PTE_V = 0x00000001, // valid
+ PTE_PL = 0x00000006, // protection level
+ PTE_R = 0x00000008, // referenced
+ PTE_M = 0x00000010, // modified
+ PTE_NSC = 0x00000060, // reserved
+ PTE_USR = 0x00000180, // user bits
+ PTE_PFN = 0x00fffe00, // page frame number
+ PTE_MS = 0x80000000, // memory system
+};
+
+enum pte_pl_mask : u32
+{
+ PL_SRO = 0x00000000, // supervisor read only
+ PL_SRW = 0x00000002, // supervisor read write
+ PL_URO = 0x00000004, // user read only
+ PL_URW = 0x00000006, // user read write
+};
+
+enum eia_mask : u32
+{
+ EIA_VA = 0x00ffffff, // virtual address
+ EIA_AS = 0x80000000, // address space
+};
+
+ns32082_device::ns32082_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, NS32082, tag, owner, clock)
+ , ns32000_mmu_interface(mconfig, *this)
+ , ns32000_slow_slave_interface(mconfig, *this)
+ , m_bpr{}
+ , m_pf{}
+ , m_sc(0)
+ , m_msr(0)
+ , m_bcnt(0)
+ , m_ptb{}
+ , m_eia(0)
+{
+}
+
+void ns32082_device::device_start()
+{
+ save_item(NAME(m_bpr));
+ save_item(NAME(m_pf));
+ save_item(NAME(m_sc));
+ save_item(NAME(m_msr));
+ save_item(NAME(m_bcnt));
+ save_item(NAME(m_ptb));
+ save_item(NAME(m_eia));
+
+ save_item(NAME(m_idbyte));
+ save_item(NAME(m_opword));
+ save_item(STRUCT_MEMBER(m_op, expected));
+ save_item(STRUCT_MEMBER(m_op, issued));
+ save_item(STRUCT_MEMBER(m_op, value));
+ save_item(NAME(m_status));
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_tcy));
+}
+
+void ns32082_device::device_reset()
+{
+ m_msr = 0;
+
+ m_state = IDLE;
+}
+
+void ns32082_device::state_add(device_state_interface &parent, int &index)
+{
+ parent.state_add(index++, "MSR", m_msr).formatstr("%08X");
+ parent.state_add(index++, "PTB0", m_ptb[0]).formatstr("%08X");
+ parent.state_add(index++, "PTB1", m_ptb[1]).formatstr("%08X");
+ parent.state_add(index++, "EIA", m_eia).formatstr("%08X");
+}
+
+u16 ns32082_device::slow_status(int *icount)
+{
+ if (m_state == STATUS)
+ {
+ m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT;
+
+ if (icount)
+ *icount -= m_tcy;
+
+ LOG("status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy,
+ (m_state == RESULT ? "results pending" : "complete"), machine().describe_context());
+
+ return m_status;
+ }
+
+ logerror("status protocol error (%s)\n", machine().describe_context());
+ return 0;
+}
+
+u16 ns32082_device::slow_read()
+{
+ if (m_state == RESULT && m_op[2].issued < m_op[2].expected)
+ {
+ u16 const data = u16(m_op[2].value >> (m_op[2].issued * 8));
+ LOG("read %d data 0x%04x (%s)\n", m_op[2].issued >> 1, data, machine().describe_context());
+
+ m_op[2].issued += 2;
+
+ if (m_op[2].issued == m_op[2].expected)
+ {
+ LOG("read complete\n");
+ m_state = IDLE;
+ }
+
+ return data;
+ }
+
+ logerror("read protocol error (%s)\n", machine().describe_context());
+ return 0;
+}
+
+void ns32082_device::slow_write(u16 data)
+{
+ switch (m_state)
+ {
+ case IDLE:
+ LOG("write idbyte 0x%04x (%s)\n", data, machine().describe_context());
+ if (data == FORMAT_14)
+ {
+ m_idbyte = u8(data);
+ m_state = OPERATION;
+ }
+ break;
+
+ case OPERATION:
+ m_opword = swapendian_int16(data);
+ LOG("write opword 0x%04x (%s)\n", m_opword, machine().describe_context());
+
+ m_tcy = 0;
+
+ // initialize operands
+ for (operand &op : m_op)
+ {
+ op.expected = 0;
+ op.issued = 0;
+ op.value = 0;
+ }
+
+ // decode operands
+ if (m_idbyte == FORMAT_14)
+ {
+ // format 14: xxxx xsss s0oo ooii 0001 1110
+ unsigned const size = m_opword & 3;
+
+ switch ((m_opword >> 2) & 15)
+ {
+ case 0: // rdval
+ m_op[0].expected = size + 1;
+ break;
+ case 1: // wrval
+ m_op[0].expected = size + 1;
+ break;
+ case 2: // lmr
+ m_op[0].expected = size + 1;
+ break;
+ case 3: // smr
+ m_op[2].expected = size + 1;
+ break;
+ }
+
+ m_state = OPERAND;
+ }
+ break;
+
+ case OPERAND:
+ // check awaiting operand word
+ if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected)
+ {
+ unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1;
+ operand &op = m_op[n];
+
+ LOG("write operand %d data 0x%04x (%s)\n",
+ n, data, machine().describe_context());
+
+ // insert word into operand value
+ op.value |= u64(data) << (op.issued * 8);
+ op.issued += 2;
+ }
+ else
+ logerror("write protocol error unexpected operand data 0x%04x (%s)\n",
+ data, machine().describe_context());
+ break;
+ }
+
+ // start execution when all operands are available
+ if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected)
+ execute();
+}
+
+void ns32082_device::execute()
+{
+ m_status = 0;
+
+ switch (m_idbyte)
+ {
+ case FORMAT_14:
+ // format 14: xxxx xsss s0oo ooii 0001 1110
+ {
+ unsigned const quick = BIT(m_opword, 7, 4);
+
+ switch (BIT(m_opword, 2, 4))
+ {
+ case 0: // rdval
+ m_tcy = 21;
+ m_state = RDVAL;
+ break;
+ case 1: // wrval
+ m_tcy = 21;
+ m_state = WRVAL;
+ break;
+ case 2: // lmr
+ switch (quick)
+ {
+ case BPR0: m_bpr[0] = m_op[0].value & u32(0xfcffffff); break;
+ case BPR1: m_bpr[1] = m_op[0].value & u32(0xf8ffffff); break;
+ case PF0: m_pf[0] = m_op[0].value & u32(0x00ffffff); break;
+ case PF1: m_pf[1] = m_op[0].value & u32(0x00ffffff); break;
+ case SC: m_sc = m_op[0].value; break;
+ case MSR: set_msr(m_op[0].value); break;
+ case BCNT: m_bcnt = m_op[0].value & u32(0x00ffffff); break;
+ case PTB0: m_ptb[0] = m_op[0].value & u32(0xfffffc00); break;
+ case PTB1: m_ptb[1] = m_op[0].value & u32(0xfffffc00); break;
+ case EIA: set_eia(m_op[0].value); break;
+ default:
+ logerror("lmr unknown register %d (%s)\n", quick, machine().describe_context());
+ break;
+ }
+ m_tcy = 30;
+ break;
+ case 3: // smr
+ switch (quick)
+ {
+ case BPR0: m_op[2].value = m_bpr[0]; break;
+ case BPR1: m_op[2].value = m_bpr[1]; break;
+ case PF0: m_op[2].value = m_pf[0]; break;
+ case PF1: m_op[2].value = m_pf[1]; break;
+ case SC: m_op[2].value = m_sc; break;
+ case MSR: m_op[2].value = m_msr; break;
+ case BCNT: m_op[2].value = m_bcnt; break;
+ case PTB0: m_op[2].value = m_ptb[0]; break;
+ case PTB1: m_op[2].value = m_ptb[1]; break;
+ case EIA: m_op[2].value = m_eia; break;
+ default:
+ logerror("smr unknown register %d (%s)\n", quick, machine().describe_context());
+ break;
+ }
+ m_tcy = 25;
+ break;
+ }
+ }
+ break;
+ }
+
+ // exceptions suppress result issue
+ if (m_status & SLAVE_Q)
+ m_op[2].expected = 0;
+
+ if (m_state == OPERAND)
+ m_state = STATUS;
+}
+
+void ns32082_device::set_msr(u32 data)
+{
+ if (data & MSR_R)
+ m_msr &= ~(MSR_TE | MSR_B | MSR_TET | MSR_ED | MSR_BD | MSR_EST | MSR_BST);
+
+ if ((m_msr ^ data) & (MSR_TS | MSR_TU))
+ LOG("supervisor translation %s user translation %s (%s)\n",
+ data & MSR_TS ? "enabled" : "disabled",
+ data & MSR_TU ? "enabled" : "disabled", machine().describe_context());
+
+ m_msr = (m_msr & ~MSR_WM) | (data & MSR_WM);
+}
+
+ns32082_device::translate_result ns32082_device::translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool pfs, bool suppress)
+{
+ // update program flow trace state
+ if (pfs && (m_msr & MSR_FT))
+ {
+ if (st == ns32000::ST_NIF)
+ {
+ m_pf[1] = m_pf[0];
+ m_pf[0] = address;
+
+ m_sc = m_sc << 16;
+ }
+
+ m_sc++;
+ }
+
+ // check translation required
+ if ((!(m_msr & MSR_TU) && user) || (!(m_msr & MSR_TS) && !user))
+ return COMPLETE;
+
+ // treat WRVAL as write
+ write |= m_state == WRVAL;
+
+ bool const address_space = (m_msr & MSR_DS) && user;
+ unsigned const access_level = (user && !(m_msr & MSR_AO))
+ ? ((write || st == ns32000::ST_RMW) ? PL_URW : PL_URO) : ((write || st == ns32000::ST_RMW) ? PL_SRW : PL_SRO);
+
+ u32 const ptb = ((m_ptb[address_space] & PTB_MS) >> 7) | (m_ptb[address_space] & PTB_AB);
+
+ LOGMASKED(LOG_TRANSLATE, "translate address_space %d access_level %d page table 0x%08x address 0x%08x\n", address_space, access_level, ptb, address);
+
+ // read level 1 page table entry
+ u32 const pte1_address = ptb | ((address & VA_INDEX1) >> 14);
+ u32 const pte1 = space.read_dword(pte1_address);
+ LOGMASKED(LOG_TRANSLATE, "translate level 1 page table address 0x%06x entry 0x%08x\n", pte1_address, pte1);
+
+ if (access_level > (pte1 & PTE_PL) || !(pte1 & PTE_V))
+ {
+ if (m_state == IDLE && !suppress)
+ {
+ // reset error status
+ m_msr &= ~(MSR_EST | MSR_ED | MSR_TET | MSR_TE);
+
+ m_msr |= (write ? 0 : MSR_ED) | ((st & 7) << 10) | MSR_TE;
+ if (access_level > (pte1 & PTE_PL))
+ m_msr |= TET_PL;
+ if (!(pte1 & PTE_V))
+ m_msr |= TET_IL1;
+
+ m_eia = (address_space ? EIA_AS : 0) | (address & EIA_VA);
+ }
+
+ if (m_state == RDVAL || m_state == WRVAL)
+ {
+ if (pte1 & PTE_V)
+ {
+ m_state = STATUS;
+ m_status |= SLAVE_F;
+
+ return CANCEL;
+ }
+ else
+ m_state = IDLE;
+ }
+
+ LOGMASKED(LOG_TRANSLATE, "translate level 1 abort eia 0x%08x\n", m_eia);
+ return ABORT;
+ }
+
+ // set referenced
+ if (!(pte1 & PTE_R) && !suppress)
+ space.write_word(pte1_address, u16(pte1 | PTE_R));
+
+ // read level 2 page table entry
+ u32 const pte2_address = ((pte1 & PTE_MS) >> 7) | (pte1 & PTE_PFN) | ((address & VA_INDEX2) >> 7);
+ u32 const pte2 = space.read_dword(pte2_address);
+ LOGMASKED(LOG_TRANSLATE, "translate level 2 page table address 0x%06x entry 0x%08x\n", pte2_address, pte2);
+
+ if (access_level > (pte2 & PTE_PL) || !(pte2 & PTE_V))
+ {
+ if (m_state == IDLE && !suppress)
+ {
+ // reset error status
+ m_msr &= ~(MSR_EST | MSR_ED | MSR_TET | MSR_TE);
+
+ m_msr |= (write ? 0 : MSR_ED) | ((st & 7) << 10) | MSR_TE;
+ if (access_level > (pte2 & PTE_PL))
+ m_msr |= TET_PL;
+ if (!(pte2 & PTE_V))
+ m_msr |= TET_IL2;
+
+ m_eia = (address_space ? EIA_AS : 0) | (address & EIA_VA);
+ }
+
+ if (m_state == RDVAL || m_state == WRVAL)
+ {
+ m_state = STATUS;
+ if (pte2 & PTE_V)
+ m_status |= SLAVE_F;
+
+ return CANCEL;
+ }
+ else
+ {
+ LOGMASKED(LOG_TRANSLATE, "translate level 2 abort eia 0x%08x\n", m_eia);
+ return ABORT;
+ }
+ }
+
+ // set modified and referenced
+ if ((!(pte2 & PTE_R) || (write && !(pte2 & PTE_M))) && !suppress)
+ space.write_word(pte2_address, u16(pte2 | (write ? PTE_M : 0) | PTE_R));
+
+ address = ((pte1 & PTE_MS) >> 7) | (pte2 & PTE_PFN) | (address & VA_OFFSET);
+ LOGMASKED(LOG_TRANSLATE, "translate complete 0x%08x\n", address);
+
+ if (m_state == RDVAL || m_state == WRVAL)
+ m_state = STATUS;
+
+ return COMPLETE;
+}
diff --git a/src/devices/machine/ns32082.h b/src/devices/machine/ns32082.h
new file mode 100644
index 00000000000..b8232e25116
--- /dev/null
+++ b/src/devices/machine/ns32082.h
@@ -0,0 +1,69 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_NS32082_H
+#define MAME_MACHINE_NS32082_H
+
+#pragma once
+
+#include "cpu/ns32000/common.h"
+
+class ns32082_device
+ : public device_t
+ , public ns32000_mmu_interface
+ , public ns32000_slow_slave_interface
+{
+public:
+ ns32082_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // ns32000_slave_interface implementation
+ virtual void state_add(device_state_interface &parent, int &index) override;
+
+ // ns32000_slow_slave_interface implementation
+ virtual u16 slow_status(int *icount = nullptr) override;
+ virtual u16 slow_read() override;
+ virtual void slow_write(u16 data) override;
+
+ // ns32000_mmu_interface implementation
+ virtual translate_result translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool pfs = false, bool suppress = false) override;
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void execute();
+
+ void set_msr(u32 data);
+ void set_eia(u32 data) {}
+
+private:
+ // registers
+ u32 m_bpr[2];
+ u32 m_pf[2];
+ u32 m_sc;
+ u32 m_msr;
+ u32 m_bcnt;
+ u32 m_ptb[2];
+ u32 m_eia;
+
+ // operating state
+ u8 m_idbyte;
+ u16 m_opword;
+ struct operand
+ {
+ u32 expected;
+ u32 issued;
+ u64 value;
+ }
+ m_op[3];
+ u16 m_status;
+
+ // implementation state
+ u32 m_state;
+ u32 m_tcy;
+};
+
+DECLARE_DEVICE_TYPE(NS32082, ns32082_device)
+
+#endif // MAME_MACHINE_NS32082_H
diff --git a/src/devices/machine/ns32202.cpp b/src/devices/machine/ns32202.cpp
index 669a2e63e7f..70d6bf080ea 100644
--- a/src/devices/machine/ns32202.cpp
+++ b/src/devices/machine/ns32202.cpp
@@ -5,25 +5,25 @@
* National Semiconductor NS32202 Interrupt Control Unit (ICU).
*
* Sources:
+ * - Microprocessor Databook, Series 32000, NSC800, 1989 Edition, National Semiconductor
*
- * http://bitsavers.org/components/national/_dataBooks/1989_National_Microprocessor_Databook_32000_NSC800.pdf
- *
- * TODO
- * - timer/counter
+ * TODO:
+ * - more testing
*/
#include "emu.h"
#include "ns32202.h"
-#define LOG_GENERAL (1U << 0)
-#define LOG_STATE (1U << 1)
-#define LOG_REGW (1U << 2)
-#define LOG_REGR (1U << 3)
+#define LOG_STATE (1U << 1)
+#define LOG_REGW (1U << 2)
+#define LOG_REGR (1U << 3)
+#define LOG_INTERRUPT (1U << 4)
+#define LOG_COUNTER (1U << 5)
-//#define VERBOSE (LOG_GENERAL|LOG_STATE|LOG_REGW|LOG_REGR)
+//#define VERBOSE (LOG_GENERAL|LOG_STATE|LOG_REGW|LOG_REGR|LOG_INTERRUPT)
#include "logmacro.h"
-DEFINE_DEVICE_TYPE(NS32202, ns32202_device, "ns32202", "NS32202 Interrupt Control Unit")
+DEFINE_DEVICE_TYPE(NS32202, ns32202_device, "ns32202", "National Semiconductor NS32202 Interrupt Control Unit")
enum mctl_mask : u8
{
@@ -64,19 +64,22 @@ ns32202_device::ns32202_device(machine_config const &mconfig, char const *tag, d
: device_t(mconfig, NS32202, tag, owner, clock)
, m_out_int(*this)
, m_out_cout(*this)
- , m_out_port(*this)
+ , m_out_g(*this)
+ , m_hvct(0)
+ , m_pdat(0)
+ , m_cctl(0)
+ , m_csv{}
+ , m_ccv{}
, m_line_state(0xffff)
, m_out_int_state(false)
, m_out_cout_state(false)
+ , m_pdat_in(0)
+ , m_pdat_out(0)
{
}
void ns32202_device::device_start()
{
- m_out_int.resolve_safe();
- m_out_cout.resolve_safe();
- m_out_port.resolve_safe();
-
save_item(NAME(m_hvct));
save_item(NAME(m_eltg));
save_item(NAME(m_tpl));
@@ -102,9 +105,9 @@ void ns32202_device::device_start()
save_item(NAME(m_out_int_state));
save_item(NAME(m_out_cout_state));
- m_interrupt = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::interrupt), this));
- m_counter[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::counter<0>), this));
- m_counter[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::counter<1>), this));
+ m_interrupt = timer_alloc(FUNC(ns32202_device::interrupt), this);
+ m_counter[0] = timer_alloc(FUNC(ns32202_device::counter<0>), this);
+ m_counter[1] = timer_alloc(FUNC(ns32202_device::counter<1>), this);
}
void ns32202_device::device_reset()
@@ -113,6 +116,7 @@ void ns32202_device::device_reset()
m_tpl = 0;
m_ipnd = 0;
m_isrv = 0;
+ std::fill(std::begin(m_isrv_count), std::end(m_isrv_count), 0);
m_imsk = 0xffff;
m_csrc = 0;
m_fprt = 0x0001;
@@ -123,6 +127,11 @@ void ns32202_device::device_reset()
m_ips = 0xff;
m_pdir = 0xff;
m_cictl = 0;
+
+ set_int(false);
+ set_cout(false);
+
+ update_port();
}
void ns32202_device::set_int(bool int_state)
@@ -140,7 +149,7 @@ void ns32202_device::set_cout(bool cout_state)
{
if (cout_state != m_out_cout_state)
{
- LOGMASKED(LOG_STATE, "cout %s\n", cout_state ? "asserted" : "cleared");
+ LOGMASKED(LOG_COUNTER, "cout %s\n", cout_state ? "asserted" : "cleared");
m_out_cout_state = cout_state;
m_out_cout(!m_out_cout_state);
@@ -177,10 +186,10 @@ template <unsigned ST1> void ns32202_device::map(address_map &map)
map(0x19, 0x19).rw(FUNC(ns32202_device::csvh_r<0>), FUNC(ns32202_device::csvh_w<0>));
map(0x1a, 0x1a).rw(FUNC(ns32202_device::csvl_r<1>), FUNC(ns32202_device::csvl_w<1>));
map(0x1b, 0x1b).rw(FUNC(ns32202_device::csvh_r<1>), FUNC(ns32202_device::csvh_w<1>));
- map(0x1c, 0x1c).rw(FUNC(ns32202_device::lccvl_r), FUNC(ns32202_device::lccvl_w));
- map(0x1d, 0x1d).rw(FUNC(ns32202_device::lccvh_r), FUNC(ns32202_device::lccvh_w));
- map(0x1e, 0x1e).rw(FUNC(ns32202_device::hccvl_r), FUNC(ns32202_device::hccvl_w));
- map(0x1f, 0x1f).rw(FUNC(ns32202_device::hccvh_r), FUNC(ns32202_device::hccvh_w));
+ map(0x1c, 0x1c).rw(FUNC(ns32202_device::ccvl_r<0>), FUNC(ns32202_device::ccvl_w<0>));
+ map(0x1d, 0x1d).rw(FUNC(ns32202_device::ccvh_r<0>), FUNC(ns32202_device::ccvh_w<0>));
+ map(0x1e, 0x1e).rw(FUNC(ns32202_device::ccvl_r<1>), FUNC(ns32202_device::ccvl_w<1>));
+ map(0x1f, 0x1f).rw(FUNC(ns32202_device::ccvh_r<1>), FUNC(ns32202_device::ccvh_w<1>));
}
template void ns32202_device::map<0>(address_map &map);
@@ -193,6 +202,8 @@ template void ns32202_device::map<1>(address_map &map);
*/
template <unsigned Number> void ns32202_device::ir_w(int state)
{
+ LOGMASKED(LOG_INTERRUPT, "ir_w%d %d\n", Number, state);
+
// ignore external interrupts assigned to counters
if (((m_cictl & CICTL_CIEL) && (m_ciptr & 15) == Number) ||
((m_cictl & CICTL_CIEH) && (m_ciptr >> 4) == Number))
@@ -204,12 +215,17 @@ template <unsigned Number> void ns32202_device::ir_w(int state)
{
// level triggered
if (state == BIT(m_tpl, Number))
- m_ipnd |= mask;
+ {
+ if (!(m_mctl & MCTL_FRZ))
+ m_ipnd |= mask;
+ }
else
m_ipnd &= ~mask;
}
else
{
+ // TODO: freeze bit MCTL_FRZ causes delayed edge-triggered recognition?
+
// edge triggered
if (bool(state) == BIT(m_tpl, Number) && bool(state) ^ BIT(m_line_state, Number))
m_ipnd |= mask;
@@ -251,59 +267,56 @@ template void ns32202_device::ir_w<15>(int state);
* - unmasked pending interrupt has priority > in-service interrupt; or
* - unmasked pending cascade interrupt has priorty >= in-service interrupt
*/
-void ns32202_device::interrupt(void *ptr, s32 param)
+void ns32202_device::interrupt(s32 param)
{
- // check for unmasked pending interrupts
- if (!(m_ipnd & m_imsk))
- return;
+ bool int_state = false;
- if (m_mctl & MCTL_NTAR)
+ // check for unmasked pending interrupts
+ if (m_ipnd & ~m_imsk)
{
// fixed priority mode
- bool accept = false;
-
- // check any interrupts in-service
- if (m_isrv)
+ if (m_mctl & MCTL_NTAR)
{
- // check interrupts in descending priority order
- u16 mask = m_fprt;
- for (unsigned i = 0; i < 16; i++)
+ // check any interrupts in-service
+ if (m_isrv)
{
- // check interrupt in-service
- if (m_isrv & mask)
+ // check interrupts in descending priority order
+ u16 mask = m_fprt;
+ for (unsigned i = 0; i < 16; i++)
{
- // check equal priority unmasked pending cascade interrupt
- if ((m_csrc & mask) && (m_ipnd & mask) && !(m_imsk & mask))
+ // check interrupt in-service
+ if (m_isrv & mask)
{
- LOGMASKED(LOG_STATE, "unmasked pending cascade in-service interrupt %d\n", 31 - count_leading_zeros(mask));
- accept = true;
+ // check equal priority unmasked pending cascade interrupt
+ if ((m_csrc & mask) && (m_ipnd & mask) && !(m_imsk & mask))
+ {
+ LOGMASKED(LOG_STATE, "unmasked pending cascade in-service interrupt %d\n", 31 - count_leading_zeros_32(mask));
+ int_state = true;
+ }
+
+ break;
}
- break;
- }
+ // check unmasked pending interrupt
+ if ((m_ipnd & mask) && !(m_imsk & mask))
+ {
+ LOGMASKED(LOG_STATE, "unmasked pending interrupt %d\n", 31 - count_leading_zeros_32(mask));
+ int_state = true;
+ break;
+ }
- // check unmasked pending interrupt
- if ((m_ipnd & mask) && !(m_imsk & mask))
- {
- LOGMASKED(LOG_STATE, "unmasked pending interrupt %d\n", 31 - count_leading_zeros(mask));
- accept = true;
- break;
+ // rotate priority mask
+ mask = (mask << 1) | (mask >> 15);
}
-
- // rotate priority mask
- mask = (mask << 1) | (mask >> 15);
}
+ else
+ int_state = true;
}
- else
- accept = true;
-
- if (!accept)
- return;
+ else if (!m_isrv)
+ int_state = true;
}
- else if (m_isrv)
- return;
- set_int(true);
+ set_int(int_state);
}
u8 ns32202_device::interrupt_acknowledge(bool side_effects)
@@ -311,7 +324,7 @@ u8 ns32202_device::interrupt_acknowledge(bool side_effects)
side_effects &= !machine().side_effects_disabled();
u8 vector = m_hvct | 0x0f;
- if ((m_ipnd & m_imsk) && m_fprt)
+ if ((m_ipnd & ~m_imsk) && m_fprt)
{
// find highest priority unmasked pending interrupt
u16 mask = m_fprt;
@@ -324,7 +337,7 @@ u8 ns32202_device::interrupt_acknowledge(bool side_effects)
mask = (mask << 1) | (mask >> 15);
}
- unsigned const number = 31 - count_leading_zeros(mask);
+ unsigned const number = 31 - count_leading_zeros_32(mask);
if (side_effects)
{
LOGMASKED(LOG_STATE, "acknowledge highest priority unmasked interrupt %d\n", number);
@@ -340,8 +353,9 @@ u8 ns32202_device::interrupt_acknowledge(bool side_effects)
// mark interrupt in-service
m_isrv |= mask;
- // clear interrupt pending
- m_ipnd &= ~(mask);
+ // clear interrupt pending (only if edge-triggered or internal)
+ if (!(m_eltg & mask) || ((m_line_state ^ m_tpl) & mask))
+ m_ipnd &= ~mask;
// clear l-counter interrupt pending
if ((m_cictl & CICTL_CIEL) && (m_cictl & CICTL_CIRL) && BIT(mask, m_ciptr & 15))
@@ -350,9 +364,6 @@ u8 ns32202_device::interrupt_acknowledge(bool side_effects)
// clear h-counter interrupt pending
if ((m_cictl & CICTL_CIEH) && (m_cictl & CICTL_CIRH) && BIT(mask, m_ciptr >> 4))
m_cictl &= ~CICTL_CIRH;
-
- // clear interrupt output
- set_int(false);
}
// compute acknowledge vector
@@ -378,7 +389,11 @@ u8 ns32202_device::interrupt_acknowledge(bool side_effects)
}
if (side_effects)
- LOGMASKED(LOG_STATE, "acknowledge vector 0x%02x\n", vector);
+ {
+ // clear interrupt output
+ if (!(m_ipnd & ~m_imsk & ~m_isrv) || !m_fprt)
+ set_int(false);
+ }
return vector;
}
@@ -400,7 +415,7 @@ u8 ns32202_device::interrupt_return(bool side_effects)
// rotate priority mask
mask = (mask << 1) | (mask >> 15);
}
- unsigned const number = 31 - count_leading_zeros(mask);
+ unsigned const number = 31 - count_leading_zeros_32(mask);
if (side_effects)
{
@@ -447,9 +462,6 @@ u8 ns32202_device::interrupt_return(bool side_effects)
m_fprt = (m_fprt << 1) | (m_fprt >> 15);
}
- if (side_effects)
- LOGMASKED(LOG_STATE, "return vector 0x%02x\n", vector);
-
return vector;
}
@@ -459,6 +471,9 @@ u8 ns32202_device::interrupt_return(bool side_effects)
*/
void ns32202_device::interrupt_update()
{
+ if (m_mctl & MCTL_FRZ)
+ return;
+
// compute new pending state
u16 const ipnd = m_ipnd | (m_eltg & ~(m_line_state ^ m_tpl));
@@ -471,7 +486,7 @@ void ns32202_device::interrupt_update()
}
// N=0 -> l-counter
-template <unsigned N> void ns32202_device::counter(void *buf, s32 param)
+template <unsigned N> void ns32202_device::counter(s32 param)
{
u32 const scaled_clock = clock() / ((m_cctl & CCTL_CFNPS) ? 1 : 4);
@@ -526,19 +541,27 @@ template <unsigned N> void ns32202_device::counter(void *buf, s32 param)
{
// TODO: trigger interrupts if IPS != 0
- u8 const mask = (m_ocasn & ~m_pdir) & 15;
if (m_mctl & MCTL_CLKM)
{
- m_pdat &= ~mask;
-
- m_out_port(0, m_ocasn & 15, mask);
- m_out_port(0, 0, mask);
+ for (unsigned i = 0; i < 4; i++)
+ {
+ if (BIT(m_ocasn, i) && !BIT(m_pdir, i))
+ {
+ m_out_g[i](1);
+ m_out_g[i](0);
+ }
+ }
}
else
{
- m_pdat ^= mask;
-
- m_out_port(0, m_pdat, mask);
+ for (unsigned i = 0; i < 4; i++)
+ {
+ if (BIT(m_ocasn, i) && !BIT(m_pdir, i))
+ {
+ m_pdat_out ^= 1U << i;
+ m_out_g[i](BIT(m_pdat_out, i));
+ }
+ }
}
}
@@ -556,20 +579,30 @@ template <unsigned N> void ns32202_device::counter(void *buf, s32 param)
// raise interrupt
m_ipnd |= 1 << ((m_ciptr >> shift) & 15);
m_interrupt->adjust(attotime::zero);
+
+ LOGMASKED(LOG_COUNTER, "counter %d interrupt %d\n", N, (m_ciptr >> shift) & 15);
}
}
}
template <unsigned ST1, bool SideEffects> u8 ns32202_device::hvct_r()
{
- if (!ST1)
- return interrupt_acknowledge(SideEffects);
- else
- return interrupt_return(SideEffects);
+ u8 data = ST1 ? interrupt_return(SideEffects) : interrupt_acknowledge(SideEffects);
+ LOGMASKED(LOG_REGR, "%cvct_r 0x%02x%s (%s)\n",
+ SideEffects ? 'h' : 's', data, SideEffects ? (ST1 ? " interrupt return" : " interrupt acknowledge") : "", machine().describe_context());
+
+ return data;
+}
+
+void ns32202_device::svct_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "svct_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_hvct = data & 0xf0;
}
void ns32202_device::eltgl_w(u8 data)
{
+ LOGMASKED(LOG_REGW, "eltgl_w 0x%02x (%s)\n", data, machine().describe_context());
m_eltg = (m_eltg & 0xff00) | data;
interrupt_update();
@@ -577,6 +610,7 @@ void ns32202_device::eltgl_w(u8 data)
void ns32202_device::eltgh_w(u8 data)
{
+ LOGMASKED(LOG_REGW, "eltgh_w 0x%02x (%s)\n", data, machine().describe_context());
m_eltg = (u16(data) << 8) | u8(m_eltg);
interrupt_update();
@@ -584,6 +618,7 @@ void ns32202_device::eltgh_w(u8 data)
void ns32202_device::tpll_w(u8 data)
{
+ LOGMASKED(LOG_REGW, "tpll_w 0x%02x (%s)\n", data, machine().describe_context());
m_tpl = (m_tpl & 0xff00) | data;
interrupt_update();
@@ -591,6 +626,7 @@ void ns32202_device::tpll_w(u8 data)
void ns32202_device::tplh_w(u8 data)
{
+ LOGMASKED(LOG_REGW, "tplh_w 0x%02x (%s)\n", data, machine().describe_context());
m_tpl = (u16(data) << 8) | u8(m_tpl);
interrupt_update();
@@ -619,35 +655,99 @@ void ns32202_device::csrch_w(u8 data)
void ns32202_device::ipndl_w(u8 data)
{
if (BIT(data, 6))
- // clear all pending interrupts in register
+ {
+ // clear all pending interrupts
+ LOGMASKED(LOG_REGW, "ipndl_w 0x%02x clear all pending interrupts (%s)\n", data, machine().describe_context());
+
m_ipnd &= 0xff00;
- else if (BIT(data, 7))
+ }
+ else if ((data & 0xf8) == 0x80)
{
- // set interrupt
- m_ipnd |= 1 << (data & 7);
+ // set pending interrupt
+ LOGMASKED(LOG_REGW, "ipndl_w 0x%02x set pending interrupt %d (%s)\n", data, data & 15, machine().describe_context());
- m_interrupt->adjust(attotime::zero);
+ m_ipnd |= 1 << (data & 15);
+ }
+ else if ((data & 0xf8) == 0x00)
+ {
+ // clear pending interrupt
+ LOGMASKED(LOG_REGW, "ipndl_w 0x%02x clear pending interrupt %d (%s)\n", data, data & 15, machine().describe_context());
+
+ m_ipnd &= ~(1 << (data & 15));
}
else
- // clear interrupt
- m_ipnd &= ~(1 << (data & 7));
+ LOGMASKED(LOG_REGW, "ipndl_w 0x%02x unknown (%s)\n", data, machine().describe_context());
+
+ m_interrupt->adjust(attotime::zero);
}
void ns32202_device::ipndh_w(u8 data)
{
if (BIT(data, 6))
- // clear all pending interrupts in register
+ {
+ // clear all pending interrupts
+ LOGMASKED(LOG_REGW, "ipndh_w 0x%02x clear all pending interrupts (%s)\n", data, machine().describe_context());
+
m_ipnd &= 0x00ff;
- else if (BIT(data, 7))
+ }
+ else if ((data & 0xf8) == 0x88)
{
- // set interrupt
- m_ipnd |= 256 << (data & 7);
+ // set pending interrupt
+ LOGMASKED(LOG_REGW, "ipndh_w 0x%02x set pending interrupt %d (%s)\n", data, data & 15, machine().describe_context());
- m_interrupt->adjust(attotime::zero);
+ m_ipnd |= 1 << (data & 15);
+ }
+ else if ((data & 0xf8) == 0x08)
+ {
+ // clear pending interrupt
+ LOGMASKED(LOG_REGW, "ipndh_w 0x%02x clear pending interrupt %d (%s)\n", data, data & 15, machine().describe_context());
+
+ m_ipnd &= ~(1 << (data & 15));
}
else
- // clear interrupt
- m_ipnd &= ~(256 << (data & 7));
+ LOGMASKED(LOG_REGW, "ipndh_w 0x%02x unknown (%s)\n", data, machine().describe_context());
+
+ m_interrupt->adjust(attotime::zero);
+}
+
+void ns32202_device::isrvl_w(u8 data)
+{
+ if (u8(m_isrv >> 0) ^ data)
+ {
+ LOGMASKED(LOG_REGW, "isrvl_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_isrv = (m_isrv & 0xff00) | data;
+
+ m_interrupt->adjust(attotime::zero);
+ }
+}
+
+void ns32202_device::isrvh_w(u8 data)
+{
+ if (u8(m_isrv >> 8) ^ data)
+ {
+ LOGMASKED(LOG_REGW, "isrvh_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_isrv = (u16(data) << 8) | u8(m_isrv);
+
+ m_interrupt->adjust(attotime::zero);
+ }
+}
+
+void ns32202_device::imskl_w(u8 data)
+{
+ if (data ^ u8(m_imsk))
+ LOGMASKED(LOG_REGW, "imskl_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_imsk = (m_imsk & 0xff00) | data;
+
+ m_interrupt->adjust(attotime::zero);
+}
+
+void ns32202_device::imskh_w(u8 data)
+{
+ if (data ^ (m_imsk >> 8))
+ LOGMASKED(LOG_REGW, "imskh_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_imsk = (u16(data) << 8) | u8(m_imsk);
+
+ m_interrupt->adjust(attotime::zero);
}
void ns32202_device::fprtl_w(u8 data)
@@ -666,9 +766,16 @@ void ns32202_device::cctl_w(u8 data)
// start/stop h-counter
if (!(m_cctl & CCTL_CRUNH) && (data & CCTL_CRUNH))
+ {
+ LOGMASKED(LOG_COUNTER, "cctl_w start h-counter clock %d\n", scaled_clock);
m_counter[1]->adjust(attotime::from_ticks(1, scaled_clock), 1);
+ }
else if ((m_cctl & CCTL_CRUNH) && !(data & CCTL_CRUNH))
+ {
+ LOGMASKED(LOG_COUNTER, "cctl_w stop h-counter\n");
+ update_ccv();
m_counter[1]->enable(false);
+ }
if (!(data & CCTL_CRUNH) && (data & CCTL_CDCRH))
{} // TODO: decrement h-counter
@@ -676,23 +783,193 @@ void ns32202_device::cctl_w(u8 data)
// start/stop l-counter
if (!(data & CCTL_CCON))
{
- if (!(m_cctl & CCTL_CRUNH) && (data & CCTL_CRUNH))
+ if (!(m_cctl & CCTL_CRUNL) && (data & CCTL_CRUNL))
+ {
+ LOGMASKED(LOG_COUNTER, "cctl_w start l-counter clock %d\n", scaled_clock);
m_counter[0]->adjust(attotime::from_ticks(1, scaled_clock), 1);
- else if ((m_cctl & CCTL_CRUNH) && !(data & CCTL_CRUNH))
+ }
+ else if ((m_cctl & CCTL_CRUNL) && !(data & CCTL_CRUNL))
+ {
+ LOGMASKED(LOG_COUNTER, "cctl_w stop l-counter\n");
+ update_ccv();
m_counter[0]->enable(false);
+ }
if (!(data & CCTL_CRUNL) && (data & CCTL_CDCRL))
{} // TODO: decrement l-counter
}
- m_cctl = data & ~(CCTL_CRUNH | CCTL_CRUNL);
+ m_cctl = data & ~(CCTL_CDCRH | CCTL_CDCRL);
}
void ns32202_device::cictl_w(u8 data)
{
u8 const mask =
- ((data & CICTL_WENL) ? (CICTL_CERL | CICTL_CIRL | CICTL_CIEL) : 0) |
- ((data & CICTL_WENH) ? (CICTL_CERH | CICTL_CIRH | CICTL_CIEH) : 0);
+ ((data & CICTL_WENL) ? (CICTL_CERL | CICTL_CIRL | CICTL_CIEL | CICTL_WENL) : 0) |
+ ((data & CICTL_WENH) ? (CICTL_CERH | CICTL_CIRH | CICTL_CIEH | CICTL_WENH) : 0);
m_cictl = (m_cictl & ~mask) | (data & mask);
}
+
+template <unsigned N> void ns32202_device::csvl_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "csvl%d_w 0x%02x (%s)\n", N, data, machine().describe_context());
+ m_csv[N] = (m_csv[N] & 0xff00) | data;
+}
+
+template <unsigned N> void ns32202_device::csvh_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "csvh%d_w 0x%02x (%s)\n", N, data, machine().describe_context());
+ m_csv[N] = (u16(data) << 8) | u8(m_csv[N]);
+}
+
+template <unsigned N> void ns32202_device::ccvl_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "ccvl%d_w 0x%02x (%s)\n", N, data, machine().describe_context());
+ if ((N == 0 && !(m_cctl & CCTL_CRUNL)) || ((N == 1) && !(m_cctl & CCTL_CRUNH)))
+ m_ccv[N] = (m_ccv[N] & 0xff00) | data;
+}
+
+template <unsigned N> void ns32202_device::ccvh_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "ccvh%d_w 0x%02x (%s)\n", N, data, machine().describe_context());
+ if ((N == 0 && !(m_cctl & CCTL_CRUNL)) || ((N == 1) && !(m_cctl & CCTL_CRUNH)))
+ m_ccv[N] = (u16(data) << 8) | u8(m_ccv[N]);
+}
+
+void ns32202_device::mctl_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "mctl_w 0x%02x (%s)\n", data, machine().describe_context());
+ if (!(m_mctl & MCTL_CFRZ) && (data & MCTL_CFRZ))
+ update_ccv();
+
+ m_mctl = data;
+}
+
+void ns32202_device::ocasn_w(u8 data)
+{
+ if (VERBOSE & LOG_REGW)
+ {
+ std::string outputs;
+ if (data & 0x0f)
+ {
+ for (unsigned i = 0; i < 4; i++)
+ if (BIT(data, i))
+ outputs.append(util::string_format(" g%d/ir%d", i, i * 2));
+ }
+
+ LOGMASKED(LOG_REGW, "ocasn_w 0x%02x%s (%s)\n", data, outputs, machine().describe_context());
+ }
+
+ m_ocasn = data;
+}
+
+void ns32202_device::ciptr_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "ciptr_w 0x%02x h=%d l=%d (%s)\n", data, BIT(data, 4, 4), BIT(data, 0, 4), machine().describe_context());
+ m_ciptr = data;
+}
+
+void ns32202_device::update_ccv()
+{
+ u32 const scaled_clock = clock() / ((m_cctl & CCTL_CFNPS) ? 1 : 4);
+
+ if (m_cctl & CCTL_CCON)
+ {
+ if (m_cctl & CCTL_CRUNH)
+ {
+ u32 const delta = ((u32(m_csv[1]) << 16) | m_csv[0]) - m_counter[1]->elapsed().as_ticks(scaled_clock);
+
+ m_ccv[1] = delta >> 16;
+ m_ccv[0] = u16(delta);
+ }
+ }
+ else
+ {
+ if (m_cctl & CCTL_CRUNH)
+ m_ccv[1] = m_csv[1] - m_counter[1]->elapsed().as_ticks(scaled_clock);
+
+ if (m_cctl & CCTL_CRUNL)
+ m_ccv[0] = m_csv[0] - m_counter[0]->elapsed().as_ticks(scaled_clock);
+ }
+}
+
+template <unsigned Number> void ns32202_device::g_w(int state)
+{
+ if (state)
+ m_pdat_in |= 1U << Number;
+ else
+ m_pdat_in &= ~(1U << Number);
+}
+
+// instantiate all valid general purpose input templates
+template void ns32202_device::g_w<0>(int state);
+template void ns32202_device::g_w<1>(int state);
+template void ns32202_device::g_w<2>(int state);
+template void ns32202_device::g_w<3>(int state);
+template void ns32202_device::g_w<4>(int state);
+template void ns32202_device::g_w<5>(int state);
+template void ns32202_device::g_w<6>(int state);
+template void ns32202_device::g_w<7>(int state);
+
+u8 ns32202_device::pdat_r()
+{
+ u8 const data = ((m_pdat_in & m_pdir) | (m_pdat & ~m_pdir)) & ~m_ips & ~m_ocasn;
+ LOGMASKED(LOG_REGR, "pdat_r 0x%02x (%s)\n", data, machine().describe_context());
+
+ return data;
+}
+
+void ns32202_device::pdat_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "pdat_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_pdat = data;
+
+ update_port();
+}
+
+void ns32202_device::ips_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "ips_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_ips = data;
+
+ update_port();
+}
+
+void ns32202_device::pdir_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "pdir_w 0x%02x (%s)\n", data, machine().describe_context());
+ m_pdir = data;
+
+ update_port();
+}
+
+void ns32202_device::update_port()
+{
+ // find port output bits which need to be updated
+ u8 const output = ~m_ips & ~m_pdir & ~m_ocasn & (m_pdat ^ m_pdat_out);
+
+ // release interrupt/input lines (assume float high)
+ u8 const release = (m_ips | m_pdir) & ~m_ocasn & ~m_pdat_out;
+
+ for (unsigned i = 0; i < 8; i++)
+ {
+ if (BIT(output, i))
+ {
+ // record the output state
+ if (BIT(m_pdat, i))
+ m_pdat_out |= 1U << i;
+ else
+ m_pdat_out &= ~(1U << i);
+
+ // update the line
+ m_out_g[i](BIT(m_pdat, i));
+ }
+ else if (BIT(release, i))
+ {
+ m_pdat_out |= 1U << i;
+
+ m_out_g[i](1);
+ }
+ }
+}
diff --git a/src/devices/machine/ns32202.h b/src/devices/machine/ns32202.h
index c6328e5fa38..1c5e18fdddb 100644
--- a/src/devices/machine/ns32202.h
+++ b/src/devices/machine/ns32202.h
@@ -9,33 +9,37 @@
class ns32202_device : public device_t
{
public:
+ // output lines
auto out_int() { return m_out_int.bind(); }
auto out_cout() { return m_out_cout.bind(); }
- auto out_port() { return m_out_port.bind(); }
+ template <unsigned Number> auto out_g() { return m_out_g[Number].bind(); }
+ ns32202_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // input lines
template <unsigned Number> void ir_w(int state);
- template <unsigned ST1> void map(address_map &map);
+ template <unsigned Number> void g_w(int state);
- ns32202_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+ template <unsigned ST1> void map(address_map &map);
protected:
- // device_t overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
void set_int(bool int_state);
void set_cout(bool cout_state);
- void interrupt(void *buf, s32 param);
+ void interrupt(s32 param);
u8 interrupt_acknowledge(bool side_effects);
u8 interrupt_return(bool side_effects);
void interrupt_update();
- template <unsigned N> void counter(void *buf, s32 param);
+ template <unsigned N> void counter(s32 param);
+ // register read handlers
template <unsigned ST1, bool SideEffects> u8 hvct_r();
-
u8 eltgl_r() { return u8(m_eltg); }
u8 eltgh_r() { return m_eltg >> 8; }
u8 tpll_r() { return u8(m_tpl); }
@@ -53,83 +57,83 @@ protected:
u8 mctl_r() { return m_mctl; }
u8 ocasn_r() { return m_ocasn; }
u8 ciptr_r() { return m_ciptr; }
- u8 pdat_r() { return 0; }
+ u8 pdat_r();
u8 ips_r() { return m_ips; }
u8 pdir_r() { return m_pdir; }
u8 cctl_r() { return m_cctl; }
u8 cictl_r() { return m_cictl; }
template <unsigned N> u8 csvl_r() { return u8(m_csv[N]); }
template <unsigned N> u8 csvh_r() { return m_csv[N] >> 8; }
- u8 lccvl_r() { return 0; }
- u8 lccvh_r() { return 0; }
- u8 hccvl_r() { return 0; }
- u8 hccvh_r() { return 0; }
-
- void svct_w(u8 data) { m_hvct = data & 0xf0; }
+ template <unsigned N> u8 ccvl_r() { return u8(m_ccv[N]); }
+ template <unsigned N> u8 ccvh_r() { return m_ccv[N] >> 8; }
+ // register write handlers
+ void svct_w(u8 data);
void eltgl_w(u8 data);
void eltgh_w(u8 data);
void tpll_w(u8 data);
void tplh_w(u8 data);
void ipndl_w(u8 data);
void ipndh_w(u8 data);
- void isrvl_w(u8 data) { m_isrv = (m_isrv & 0xff00) | data; }
- void isrvh_w(u8 data) { m_isrv = (u16(data) << 8) | u8(m_isrv); }
- void imskl_w(u8 data) { m_imsk = (m_imsk & 0xff00) | data; m_interrupt->adjust(attotime::zero); }
- void imskh_w(u8 data) { m_imsk = (u16(data) << 8) | u8(m_imsk); m_interrupt->adjust(attotime::zero); }
+ void isrvl_w(u8 data);
+ void isrvh_w(u8 data);
+ void imskl_w(u8 data);
+ void imskh_w(u8 data);
void csrcl_w(u8 data);
void csrch_w(u8 data);
void fprtl_w(u8 data);
void fprth_w(u8 data) {}
-
- void mctl_w(u8 data) { m_mctl = data; }
- void ocasn_w(u8 data) { m_ocasn = data; }
- void ciptr_w(u8 data) { m_ciptr = data; }
- void pdat_w(u8 data) {}
- void ips_w(u8 data) { m_ips = data; }
- void pdir_w(u8 data) { m_pdir = data; }
+ void mctl_w(u8 data);
+ void ocasn_w(u8 data);
+ void ciptr_w(u8 data);
+ void pdat_w(u8 data);
+ void ips_w(u8 data);
+ void pdir_w(u8 data);
void cctl_w(u8 data);
void cictl_w(u8 data);
+ template <unsigned N> void csvl_w(u8 data);
+ template <unsigned N> void csvh_w(u8 data);
+ template <unsigned N> void ccvl_w(u8 data);
+ template <unsigned N> void ccvh_w(u8 data);
- template <unsigned N> void csvl_w(u8 data) { m_csv[N] = (m_csv[N] & 0xff00) | data; }
- template <unsigned N> void csvh_w(u8 data) { m_csv[N] = (u16(data) << 8) | u8(m_csv[N]); }
- void lccvl_w(u8 data) {}
- void lccvh_w(u8 data) {}
- void hccvl_w(u8 data) {}
- void hccvh_w(u8 data) {}
+ void update_ccv();
+ void update_port();
private:
devcb_write_line m_out_int;
devcb_write_line m_out_cout;
- devcb_write8 m_out_port;
+ devcb_write_line::array<8> m_out_g;
emu_timer *m_interrupt;
emu_timer *m_counter[2];
u8 m_hvct; // hardware vector
- u16 m_eltg; // edge/level triggering
- u16 m_tpl; // triggering polarity
- u16 m_ipnd; // interrupts pending
- u16 m_isrv; // interrupts in-service
- u16 m_imsk; // interrupt mask
+ u16 m_eltg; // edge/level triggering (1=level)
+ u16 m_tpl; // triggering polarity (1=active high)
+ u16 m_ipnd; // interrupts pending (1=pending)
+ u16 m_isrv; // interrupts in-service (1=in-service)
+ u16 m_imsk; // interrupt mask (1=masked)
u16 m_csrc; // cascaded source
u16 m_fprt; // first priority
u8 m_mctl; // mode control
- u8 m_ocasn; // output clock assignment
+ u8 m_ocasn; // output clock assignment (1=clock output)
u8 m_ciptr; // counter interrupt pointer
u8 m_pdat; // port data
- u8 m_ips; // interrupt/port select
- u8 m_pdir; // port direction
+ u8 m_ips; // interrupt/port select (1=interrupt)
+ u8 m_pdir; // port direction (1=input)
u8 m_cctl; // counter control
u8 m_cictl; // counter interrupt control
u16 m_csv[2]; // counter starting value
u16 m_ccv[2]; // counter current value
- unsigned m_isrv_count[16];
+ u8 m_isrv_count[16];
u16 m_line_state;
bool m_out_int_state;
bool m_out_cout_state;
+
+ u8 m_pdat_in;
+ u8 m_pdat_out;
};
DECLARE_DEVICE_TYPE(NS32202, ns32202_device)
diff --git a/src/devices/machine/ns32382.cpp b/src/devices/machine/ns32382.cpp
new file mode 100644
index 00000000000..d801342a102
--- /dev/null
+++ b/src/devices/machine/ns32382.cpp
@@ -0,0 +1,429 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * National Semiconductor NS32382 Memory Management Unit.
+ *
+ * Sources:
+ * - Microprocessor Databook, Series 32000, NSC800, 1989 Edition, National Semiconductor
+ *
+ * TODO:
+ * - tlb
+ * - breakpoints
+ * - cycles
+ * - fast status protocol
+ */
+
+#include "emu.h"
+#include "ns32382.h"
+
+#define LOG_TRANSLATE (1U << 1)
+
+//#define VERBOSE (LOG_GENERAL|LOG_TRANSLATE)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(NS32382, ns32382_device, "ns32382", "National Semiconductor NS32382 Memory Management Unit")
+
+enum state : unsigned
+{
+ IDLE = 0,
+ OPERAND = 2, // awaiting operands
+ RDVAL = 3, // rdval pending
+ WRVAL = 4, // wrval pending
+ STATUS = 5, // status word available
+ RESULT = 6, // result word available
+};
+
+enum reg_mask : unsigned
+{
+ BAR = 0x0, // breakpoint address register
+ BMR = 0x2, // breakpoint mask register
+ BDR = 0x3, // breakpoint data register
+ BEAR = 0x6, // bus error address register
+ MCR = 0x9, // memory management control register
+ MSR = 0xa, // memory management status register
+ TEAR = 0xb, // translation exception address register
+ PTB0 = 0xc, // page table base register 0
+ PTB1 = 0xd, // page table base register 1
+ IVAR0 = 0xe, // invalidate virtual address register 0
+ IVAR1 = 0xf, // invalidate virtual address register 1
+};
+
+enum mcr_mask : u32
+{
+ MCR_TU = 0x00000001, // translate user-mode
+ MCR_TS = 0x00000002, // translate supervisor-mode
+ MCR_DS = 0x00000004, // dual-space translation
+ MCR_AO = 0x00000008, // access level override
+ MCR_BR = 0x00000010, // break on read
+ MCR_BW = 0x00000020, // break on write
+ MCR_BE = 0x00000040, // break on execution
+ MCR_BAS = 0x00000080, // breakpoint address space
+
+ MCR_WM = 0x000000ff,
+};
+
+enum msr_mask : u32
+{
+ MSR_TEX = 0x00000003, // translation exception
+ MSR_DDT = 0x00000004, // data direction (translate exception)
+ MSR_UST = 0x00000008, // user/supervisor
+ MSR_STT = 0x000000f0, // cpu status
+ MSR_BP = 0x00000200, // break
+ MSR_CE = 0x00000400, // cpu error
+ MSR_ME = 0x00000800, // mmu error
+ MSR_DDE = 0x00001000, // data direction (bus error)
+ MSR_USE = 0x00002000, // user/supervisor
+ MSR_STE = 0x0003c000, // cpu status
+
+ MSR_WM = 0x0003feff,
+};
+
+enum msr_tex_mask : u32
+{
+ TEX_IL1 = 0x00000001, // first level pte invalid
+ TEX_IL2 = 0x00000002, // second level pte invalid
+ TEX_PL = 0x00000003, // protection violation
+};
+
+enum ptb_mask : u32
+{
+ PTB_AB = 0xfffff000, // address bits
+};
+
+enum pte_mask : u32
+{
+ PTE_V = 0x00000001, // valid
+ PTE_PL = 0x00000006, // protection level
+ PTE_CI = 0x00000040, // (level 2 only) cache inhibit
+ PTE_R = 0x00000080, // referenced
+ PTE_M = 0x00000100, // modified
+ PTE_USR = 0x00000e00, // user
+ PTE_PFN = 0xfffff000, // page frame number
+};
+
+enum pte_pl_mask : u32
+{
+ PL_SRO = 0x00000000, // supervisor read only
+ PL_SRW = 0x00000002, // supervisor read write
+ PL_URO = 0x00000004, // user read only
+ PL_URW = 0x00000006, // user read write
+};
+
+enum va_mask : u32
+{
+ VA_INDEX1 = 0xffc00000,
+ VA_INDEX2 = 0x003ff000,
+ VA_OFFSET = 0x00000fff,
+};
+
+ns32382_device::ns32382_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, NS32382, tag, owner, clock)
+ , ns32000_mmu_interface(mconfig, *this)
+ , ns32000_fast_slave_interface(mconfig, *this)
+{
+}
+
+void ns32382_device::device_start()
+{
+ save_item(NAME(m_bar));
+ save_item(NAME(m_bdr));
+ save_item(NAME(m_bear));
+ save_item(NAME(m_bmr));
+ save_item(NAME(m_mcr));
+ save_item(NAME(m_msr));
+ save_item(NAME(m_ptb));
+ save_item(NAME(m_tear));
+
+ save_item(NAME(m_opword));
+ save_item(STRUCT_MEMBER(m_op, expected));
+ save_item(STRUCT_MEMBER(m_op, issued));
+ save_item(STRUCT_MEMBER(m_op, value));
+ save_item(NAME(m_status));
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_tcy));
+}
+
+void ns32382_device::device_reset()
+{
+ m_mcr = 0;
+ m_msr = 0;
+
+ m_state = IDLE;
+}
+
+void ns32382_device::state_add(device_state_interface &parent, int &index)
+{
+ parent.state_add(index++, "MCR", m_mcr).formatstr("%02X");
+ parent.state_add(index++, "MSR", m_msr).formatstr("%08X");
+}
+
+u32 ns32382_device::fast_status(int *icount)
+{
+ if (m_state == STATUS)
+ {
+ m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT;
+
+ if (icount)
+ *icount -= m_tcy;
+
+ LOG("status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy,
+ (m_state == RESULT ? "results pending" : "complete"), machine().describe_context());
+
+ return m_status;
+ }
+
+ logerror("status protocol error (%s)\n", machine().describe_context());
+ return 0;
+}
+
+u32 ns32382_device::fast_read()
+{
+ if (m_state == RESULT && m_op[2].issued < m_op[2].expected)
+ {
+ u32 const data = u32(m_op[2].value >> (m_op[2].issued * 8));
+ LOG("read %d data 0x%08x (%s)\n", m_op[2].issued >> 2, data, machine().describe_context());
+
+ m_op[2].issued += 4;
+
+ if (m_op[2].issued == m_op[2].expected)
+ {
+ LOG("read complete\n");
+ m_state = IDLE;
+ }
+
+ return data;
+ }
+
+ logerror("read protocol error (%s)\n", machine().describe_context());
+ return 0;
+}
+
+void ns32382_device::fast_write(u32 data)
+{
+ switch (m_state)
+ {
+ case IDLE:
+ if (BIT(data, 24, 8) == FORMAT_14)
+ {
+ m_opword = swapendian_int16(data >> 8);
+
+ LOG("write idbyte 0x%02x opword 0x%04x (%s)\n", FORMAT_14, m_opword, machine().describe_context());
+
+ m_tcy = 0;
+
+ // initialize operands
+ for (operand &op : m_op)
+ {
+ op.expected = 0;
+ op.issued = 0;
+ op.value = 0;
+ }
+
+ // format 14: xxxx xsss s0oo ooii 0001 1110
+ unsigned const size = m_opword & 3;
+
+ switch (BIT(m_opword, 2, 4))
+ {
+ case 0: // rdval
+ break;
+ case 1: // wrval
+ break;
+ case 2: // lmr
+ m_op[0].expected = size + 1;
+ break;
+ case 3: // smr
+ m_op[2].expected = size + 1;
+ break;
+ }
+
+ m_state = OPERAND;
+ }
+ break;
+
+ case OPERAND:
+ // check awaiting operand word
+ if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected)
+ {
+ unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1;
+ operand &op = m_op[n];
+
+ LOG("write opword 0x%08x (%s)\n", data, machine().describe_context());
+
+ // insert dword into operand value
+ op.value |= u64(data) << (op.issued * 8);
+ op.issued += 4;
+ }
+ else
+ logerror("write protocol error unexpected operand data 0x%08x (%s)\n",
+ data, machine().describe_context());
+ break;
+ }
+
+ // start execution when all operands are available
+ if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected)
+ execute();
+}
+
+void ns32382_device::execute()
+{
+ m_status = 0;
+
+ // format 14: xxxx xsss s0oo ooii
+ unsigned const quick = BIT(m_opword, 7, 4);
+
+ switch (BIT(m_opword, 2, 4))
+ {
+ case 0: // rdval
+ m_tcy = 21;
+ m_state = RDVAL;
+ break;
+ case 1: // wrval
+ m_tcy = 21;
+ m_state = WRVAL;
+ break;
+ case 2: // lmr
+ switch (quick)
+ {
+ case BAR: m_bar = m_op[0].value; break;
+ case BMR: m_bmr = m_op[0].value; break;
+ case MCR: m_mcr = m_op[0].value; break;
+ case MSR: m_msr = m_op[0].value; break;
+ case TEAR: m_tear = m_op[0].value; break;
+ case PTB0: m_ptb[0] = m_op[0].value & PTB_AB; break;
+ case PTB1: m_ptb[1] = m_op[0].value & PTB_AB; break;
+ case IVAR0: break; // TODO: invalidate tlb entry
+ case IVAR1: break; // TODO: invalidate tlb entry
+ default:
+ logerror("lmr unknown register %d (%s)\n", quick, machine().describe_context());
+ break;
+ }
+ m_tcy = 30;
+ break;
+ case 3: // smr
+ switch (quick)
+ {
+ case BAR: m_op[2].value = m_bar; break;
+ case BMR: m_op[2].value = m_bmr; break;
+ case BDR: m_op[2].value = m_bdr; break;
+ case BEAR: m_op[2].value = m_bear; break;
+ case MCR: m_op[2].value = m_mcr & MCR_WM; break;
+ case MSR: m_op[2].value = m_msr & MSR_WM; break;
+ case TEAR: m_op[2].value = m_tear; break;
+ case PTB0: m_op[2].value = m_ptb[0]; break;
+ case PTB1: m_op[2].value = m_ptb[1]; break;
+ default:
+ logerror("smr unknown register %d (%s)\n", quick, machine().describe_context());
+ break;
+ }
+ m_tcy = 25;
+ break;
+ }
+
+ // exceptions suppress result issue
+ if (m_status & SLAVE_Q)
+ m_op[2].expected = 0;
+
+ if (m_state == OPERAND)
+ m_state = STATUS;
+}
+
+ns32382_device::translate_result ns32382_device::translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool pfs, bool debug)
+{
+ // check translation required
+ if ((!(m_mcr & MCR_TU) && user) || (!(m_mcr & MCR_TS) && !user))
+ return COMPLETE;
+
+ // treat WRVAL as write
+ write |= m_state == WRVAL;
+
+ bool const address_space = (m_mcr & MCR_DS) && user;
+ unsigned const access_level = (user && !(m_mcr & MCR_AO))
+ ? ((write || st == ns32000::ST_RMW) ? PL_URW : PL_URO) : ((write || st == ns32000::ST_RMW) ? PL_SRW : PL_SRO);
+
+ if (m_state == IDLE && !debug)
+ m_msr &= ~(MSR_STT | MSR_UST | MSR_DDT | MSR_TEX);
+
+ // read level 1 page table entry
+ u32 const pte1_address = m_ptb[address_space] | ((address & VA_INDEX1) >> 20);
+ u32 const pte1 = space.read_dword(pte1_address);
+ LOGMASKED(LOG_TRANSLATE, "translate level 1 page table address 0x%06x entry 0x%08x\n", pte1_address, pte1);
+
+ if (access_level > (pte1 & PTE_PL) || !(pte1 & PTE_V))
+ {
+ if (m_state == IDLE && !debug)
+ {
+ m_msr |= ((st & 15) << 4) | (user ? MSR_UST : 0) | (write ? MSR_DDT : 0);
+ if (access_level > (pte1 & PTE_PL))
+ m_msr |= TEX_PL;
+ else if (!(pte1 & PTE_V))
+ m_msr |= TEX_IL1;
+
+ m_tear = address;
+ }
+
+ if (m_state == RDVAL || m_state == WRVAL)
+ {
+ if (pte1 & PTE_V)
+ {
+ m_state = STATUS;
+ m_status |= SLAVE_F;
+
+ return CANCEL;
+ }
+ else
+ m_state = IDLE;
+ }
+
+ LOGMASKED(LOG_TRANSLATE, "translate level 1 abort address 0x%08x\n", address);
+ return ABORT;
+ }
+
+ // set referenced
+ if (!(pte1 & PTE_R) && !debug)
+ space.write_dword(pte1_address, pte1 | PTE_R);
+
+ // read level 2 page table entry
+ u32 const pte2_address = (pte1 & PTE_PFN) | ((address & VA_INDEX2) >> 10);
+ u32 const pte2 = space.read_dword(pte2_address);
+ LOGMASKED(LOG_TRANSLATE, "translate level 2 page table address 0x%06x entry 0x%08x\n", pte2_address, pte2);
+
+ if (access_level > (pte2 & PTE_PL) || !(pte2 & PTE_V))
+ {
+ if (m_state == IDLE && !debug)
+ {
+ m_msr |= ((st & 15) << 4) | (user ? MSR_UST : 0) | (write ? MSR_DDT : 0);
+ if (access_level > (pte2 & PTE_PL))
+ m_msr |= TEX_PL;
+ else if (!(pte2 & PTE_V))
+ m_msr |= TEX_IL2;
+
+ m_tear = address;
+ }
+
+ if (m_state == RDVAL || m_state == WRVAL)
+ {
+ m_state = STATUS;
+ if (pte2 & PTE_V)
+ m_status |= SLAVE_F;
+
+ return CANCEL;
+ }
+ else
+ {
+ LOGMASKED(LOG_TRANSLATE, "translate level 2 abort address 0x%08x\n", address);
+ return ABORT;
+ }
+ }
+
+ // set modified and referenced
+ if ((!(pte2 & PTE_R) || (write && !(pte2 & PTE_M))) && !debug)
+ space.write_dword(pte2_address, pte2 | (write ? PTE_M : 0) | PTE_R);
+
+ address = (pte2 & PTE_PFN) | (address & VA_OFFSET);
+ LOGMASKED(LOG_TRANSLATE, "translate complete 0x%08x\n", address);
+
+ return COMPLETE;
+}
diff --git a/src/devices/machine/ns32382.h b/src/devices/machine/ns32382.h
new file mode 100644
index 00000000000..a60c6d27f5f
--- /dev/null
+++ b/src/devices/machine/ns32382.h
@@ -0,0 +1,66 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_NS32382_H
+#define MAME_MACHINE_NS32382_H
+
+#pragma once
+
+#include "cpu/ns32000/common.h"
+
+class ns32382_device
+ : public device_t
+ , public ns32000_mmu_interface
+ , public ns32000_fast_slave_interface
+{
+public:
+ ns32382_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // ns32000_slave_interface implementation
+ virtual void state_add(device_state_interface &parent, int &index) override;
+
+ // ns32000_fast_slave_interface implementation
+ virtual u32 fast_status(int *icount = nullptr) override;
+ virtual u32 fast_read() override;
+ virtual void fast_write(u32 data) override;
+
+ // ns32000_mmu_interface implementation
+ virtual translate_result translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool pfs = false, bool debug = false) override;
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void execute();
+
+private:
+ // registers
+ u32 m_bar; // breakpoint address register
+ u32 m_bdr; // breakpoint data register
+ u32 m_bear; // bus error address register
+ u32 m_bmr; // breakpoint mask register
+ u32 m_mcr; // memory management control register
+ u32 m_msr; // memory management status register
+ u32 m_ptb[2]; // page table base registers
+ u32 m_tear; // translation exception address register
+
+ // operating state
+ u16 m_opword;
+ struct operand
+ {
+ u32 expected;
+ u32 issued;
+ u64 value;
+ }
+ m_op[3];
+ u16 m_status;
+
+ // implementation state
+ u32 m_state;
+ u32 m_tcy;
+};
+
+DECLARE_DEVICE_TYPE(NS32382, ns32382_device)
+
+#endif // MAME_MACHINE_NS32382_H
diff --git a/src/devices/machine/nsc810.cpp b/src/devices/machine/nsc810.cpp
index 42ddd8db02f..fbf4f060800 100644
--- a/src/devices/machine/nsc810.cpp
+++ b/src/devices/machine/nsc810.cpp
@@ -29,43 +29,33 @@ nsc810_device::nsc810_device(const machine_config &mconfig, const char *tag, dev
m_portA_latch(0), m_portB_latch(0), m_portC_latch(0),
m_ddrA(0), m_ddrB(0), m_ddrC(0),
m_mode(0),
- m_timer0(nullptr), m_timer1(nullptr),
- m_timer0_mode(0), m_timer1_mode(0),
- m_timer0_counter(0), m_timer1_counter(0),
- m_timer0_base(0), m_timer1_base(0),
- m_timer0_running(false), m_timer1_running(false),
- m_timer0_clock(0), m_timer1_clock(0),
m_ramselect(false),
- m_portA_r(*this),
- m_portB_r(*this),
- m_portC_r(*this),
+ m_portA_r(*this, 0),
+ m_portB_r(*this, 0),
+ m_portC_r(*this, 0),
m_portA_w(*this),
m_portB_w(*this),
m_portC_w(*this),
- m_timer0_out(*this),
- m_timer1_out(*this)
+ m_timer_out(*this)
{
+ std::fill(std::begin(m_timer), std::end(m_timer), nullptr);
+ std::fill(std::begin(m_timer_mode), std::end(m_timer_mode), 0);
+ std::fill(std::begin(m_timer_counter), std::end(m_timer_counter), 0);
+ std::fill(std::begin(m_timer_base), std::end(m_timer_base), 0);
+ std::fill(std::begin(m_timer_running), std::end(m_timer_running), false);
+ std::fill(std::begin(m_timer_clock), std::end(m_timer_clock), 0);
}
void nsc810_device::device_start()
{
- m_portA_r.resolve_safe(0);
- m_portB_r.resolve_safe(0);
- m_portC_r.resolve_safe(0);
- m_portA_w.resolve_safe();
- m_portB_w.resolve_safe();
- m_portC_w.resolve_safe();
- m_timer0_out.resolve_safe();
- m_timer1_out.resolve_safe();
-
m_portA_w(0);
m_portB_w(0);
m_portC_w(0);
- m_timer0_out(0);
- m_timer1_out(0);
+ m_timer_out[0](0);
+ m_timer_out[1](0);
- m_timer0 = timer_alloc(TIMER0_CLOCK);
- m_timer1 = timer_alloc(TIMER1_CLOCK);
+ m_timer[0] = timer_alloc(FUNC(nsc810_device::timer_tick<0>), this);
+ m_timer[1] = timer_alloc(FUNC(nsc810_device::timer_tick<1>), this);
}
void nsc810_device::device_reset()
@@ -77,43 +67,27 @@ void nsc810_device::device_reset()
m_ddrB = 0;
m_ddrC = 0;
m_mode = 0;
- m_timer0_mode = 0;
- m_timer1_mode = 0;
- m_timer0_counter = 0;
- m_timer1_counter = 0;
- m_timer0_running = false;
- m_timer1_running = false;
+ m_timer_mode[0] = 0;
+ m_timer_mode[1] = 0;
+ m_timer_counter[0] = 0;
+ m_timer_counter[1] = 0;
+ m_timer_running[0] = false;
+ m_timer_running[1] = false;
m_ramselect = false;
}
-void nsc810_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+template <int Timer>
+TIMER_CALLBACK_MEMBER(nsc810_device::timer_tick)
{
- switch(id)
+ m_timer_counter[Timer]--;
+ if ((m_timer_mode[Timer] & 0x07) == 0x01 || (m_timer_mode[Timer] & 0x07) == 0x02)
{
- case TIMER0_CLOCK:
- m_timer0_counter--;
- if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02)
+ if (m_timer_counter[Timer] == 0)
{
- if(m_timer0_counter == 0)
- {
- m_timer0_out(ASSERT_LINE);
- m_timer0_counter = m_timer0_base;
- LOG("NSC810: Timer 0 output set\n");
- }
- }
- break;
- case TIMER1_CLOCK:
- m_timer1_counter--;
- if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02)
- {
- if(m_timer1_counter == 0)
- {
- m_timer1_out(ASSERT_LINE);
- m_timer1_counter = m_timer1_base;
- LOG("NSC810: Timer 1 output set\n");
- }
+ m_timer_out[Timer](ASSERT_LINE);
+ m_timer_counter[Timer] = m_timer_base[Timer];
+ LOG("NSC810: Timer %d output set\n", Timer);
}
- break;
}
}
@@ -121,70 +95,70 @@ uint8_t nsc810_device::read(offs_t offset)
{
uint8_t res = 0xff;
- if(m_ramselect)
+ if (m_ramselect)
{
// TODO: 128 byte RAM access
}
else
{
// Register access
- switch(offset & 0x1f)
+ switch (offset & 0x1f)
{
case REG_PORTA:
res = m_portA_latch &= m_ddrA;
res |= (m_portA_r() & ~m_ddrA);
- //LOG("NSC810: Port A data read %02x\n",res);
+ //LOG("NSC810: Port A data read %02x\n", res);
break;
case REG_PORTB:
res = m_portB_latch &= m_ddrB;
res |= (m_portB_r() & ~m_ddrB);
- //LOG("NSC810: Port B data read %02x\n",res);
+ //LOG("NSC810: Port B data read %02x\n", res);
break;
case REG_PORTC:
res = m_portC_latch &= m_ddrC;
res |= (m_portC_r() & ~m_ddrC);
- //LOG("NSC810: Port C data read %02x\n",res);
+ //LOG("NSC810: Port C data read %02x\n", res);
break;
case REG_MODE_TIMER0:
- res = m_timer0_mode;
+ res = m_timer_mode[0];
break;
case REG_MODE_TIMER1:
- res = m_timer1_mode;
+ res = m_timer_mode[1];
break;
case REG_TIMER0_LOW:
- res = m_timer0_counter & 0xff;
- if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02)
+ res = m_timer_counter[0] & 0xff;
+ if ((m_timer_mode[0] & 0x07) == 0x01 || (m_timer_mode[0] & 0x07) == 0x02)
{
- m_timer0_out(CLEAR_LINE);
+ m_timer_out[0](CLEAR_LINE);
LOG("NSC810: Timer 0 output reset\n");
}
break;
case REG_TIMER0_HIGH:
- res = m_timer0_counter >> 8;
- if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02)
+ res = m_timer_counter[0] >> 8;
+ if ((m_timer_mode[0] & 0x07) == 0x01 || (m_timer_mode[0] & 0x07) == 0x02)
{
- m_timer0_out(CLEAR_LINE);
+ m_timer_out[0](CLEAR_LINE);
LOG("NSC810: Timer 0 output reset\n");
}
break;
case REG_TIMER1_LOW:
- res = m_timer1_counter & 0xff;
- if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02)
+ res = m_timer_counter[1] & 0xff;
+ if ((m_timer_mode[1] & 0x07) == 0x01 || (m_timer_mode[1] & 0x07) == 0x02)
{
- m_timer1_out(0);
+ m_timer_out[1](0);
LOG("NSC810: Timer 1 output reset\n");
}
break;
case REG_TIMER1_HIGH:
- res = m_timer1_counter >> 8;
- if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02)
+ res = m_timer_counter[1] >> 8;
+ if ((m_timer_mode[1] & 0x07) == 0x01 || (m_timer_mode[1] & 0x07) == 0x02)
{
- m_timer1_out(0);
+ m_timer_out[1](0);
LOG("NSC810: Timer 1 output reset\n");
}
break;
default:
- LOG("NSC810: unused port %02x read\n",offset);
+ LOG("NSC810: unused port %02x read\n", offset);
}
}
return res;
@@ -194,41 +168,41 @@ void nsc810_device::write(offs_t offset, uint8_t data)
{
uint32_t rate;
- if(m_ramselect)
+ if (m_ramselect)
{
// TODO: 128 byte RAM access
}
else
{
// Register access
- switch(offset & 0x1f)
+ switch (offset & 0x1f)
{
case REG_PORTA:
m_portA_latch = data & ~m_ddrA;
m_portA_w((0xff & ~m_ddrA) | (data & m_ddrA));
- LOG("NSC810: Port A data write %02x\n",data);
+ LOG("NSC810: Port A data write %02x\n", data);
break;
case REG_PORTB:
m_portB_latch = data & ~m_ddrB;
m_portB_w((0xff & ~m_ddrB) | (data & m_ddrB));
- LOG("NSC810: Port B data write %02x\n",data);
+ LOG("NSC810: Port B data write %02x\n", data);
break;
case REG_PORTC:
m_portC_latch = data & ~m_ddrC;
m_portC_w((0xff & ~m_ddrC) | (data & m_ddrC));
- LOG("NSC810: Port C data write %02x\n",data);
+ LOG("NSC810: Port C data write %02x\n", data);
break;
case REG_DDRA:
m_ddrA = data;
- LOG("NSC810: Port A direction write %02x\n",data);
+ LOG("NSC810: Port A direction write %02x\n", data);
break;
case REG_DDRB:
m_ddrB = data;
- LOG("NSC810: Port B direction write %02x\n",data);
+ LOG("NSC810: Port B direction write %02x\n", data);
break;
case REG_DDRC:
m_ddrC = data;
- LOG("NSC810: Port C direction write %02x\n",data);
+ LOG("NSC810: Port C direction write %02x\n", data);
break;
case REG_MODE_DEF:
if ((data & 0x01) == 0x00)
@@ -239,106 +213,106 @@ void nsc810_device::write(offs_t offset, uint8_t data)
m_mode = 2;
else if ((data & 0x07) == 0x07)
m_mode = 3;
- LOG("NSC810: Mode Definition write %02x\n",data);
+ LOG("NSC810: Mode Definition write %02x\n", data);
break;
case REG_PORTA_BITCLR:
m_portA_latch &= ~data;
m_portA_w((0xff & ~m_ddrA) | (m_portA_latch & m_ddrA));
- LOG("NSC810: Port A bit-clear write %02x (PA=%02x)\n",data,m_portA_latch);
+ LOG("NSC810: Port A bit-clear write %02x (PA=%02x)\n", data, m_portA_latch);
break;
case REG_PORTB_BITCLR:
m_portB_latch &= ~data;
m_portB_w((0xff & ~m_ddrB) | (m_portB_latch & m_ddrB));
- LOG("NSC810: Port B bit-clear write %02x (PB=%02x)\n",data,m_portB_latch);
+ LOG("NSC810: Port B bit-clear write %02x (PB=%02x)\n", data, m_portB_latch);
break;
case REG_PORTC_BITCLR:
m_portC_latch &= ~data;
m_portC_w((0xff & ~m_ddrC) | (m_portC_latch & m_ddrC));
- LOG("NSC810: Port C bit-clear write %02x (PC=%02x)\n",data,m_portC_latch);
+ LOG("NSC810: Port C bit-clear write %02x (PC=%02x)\n", data, m_portC_latch);
break;
case REG_PORTA_BITSET:
m_portA_latch |= data;
m_portA_w((0xff & ~m_ddrA) | (m_portA_latch & m_ddrA));
- LOG("NSC810: Port A bit-set write %02x (PA=%02x)\n",data,m_portA_latch);
+ LOG("NSC810: Port A bit-set write %02x (PA=%02x)\n", data, m_portA_latch);
break;
case REG_PORTB_BITSET:
m_portB_latch |= data;
m_portB_w((0xff & ~m_ddrB) | (m_portB_latch & m_ddrB));
- LOG("NSC810: Port B bit-set write %02x (PB=%02x)\n",data,m_portB_latch);
+ LOG("NSC810: Port B bit-set write %02x (PB=%02x)\n", data, m_portB_latch);
break;
case REG_PORTC_BITSET:
m_portC_latch |= data;
m_portC_w((0xff & ~m_ddrC) | (m_portC_latch & m_ddrC));
- LOG("NSC810: Port C bit-set write %02x (PC=%02x)\n",data,m_portC_latch);
+ LOG("NSC810: Port C bit-set write %02x (PC=%02x)\n", data, m_portC_latch);
break;
case REG_TIMER0_LOW:
- m_timer0_base = (m_timer0_base & 0xff00) | data;
- m_timer0_counter = (m_timer0_counter & 0xff00) | data;
- LOG("NSC810: Timer 0 low-byte write %02x (base=%04x)\n",data,m_timer0_base);
+ m_timer_base[0] = (m_timer_base[0] & 0xff00) | data;
+ m_timer_counter[0] = (m_timer_counter[0] & 0xff00) | data;
+ LOG("NSC810: Timer 0 low-byte write %02x (base=%04x)\n", data, m_timer_base[0]);
break;
case REG_TIMER0_HIGH:
- m_timer0_base = (m_timer0_base & 0x00ff) | (data << 8);
- m_timer0_counter = (m_timer0_counter & 0x00ff) | (data << 8);
- LOG("NSC810: Timer 0 high-byte write %02x (base=%04x)\n",data,m_timer0_base);
+ m_timer_base[0] = (m_timer_base[0] & 0x00ff) | (data << 8);
+ m_timer_counter[0] = (m_timer_counter[0] & 0x00ff) | (data << 8);
+ LOG("NSC810: Timer 0 high-byte write %02x (base=%04x)\n", data, m_timer_base[0]);
break;
case REG_TIMER1_LOW:
- m_timer1_base = (m_timer1_base & 0xff00) | data;
- m_timer1_counter = (m_timer1_counter & 0xff00) | data;
- LOG("NSC810: Timer 1 low-byte write %02x (base=%04x)\n",data,m_timer1_base);
+ m_timer_base[1] = (m_timer_base[1] & 0xff00) | data;
+ m_timer_counter[1] = (m_timer_counter[1] & 0xff00) | data;
+ LOG("NSC810: Timer 1 low-byte write %02x (base=%04x)\n", data, m_timer_base[1]);
break;
case REG_TIMER1_HIGH:
- m_timer1_base = (m_timer1_base & 0x00ff) | (data << 8);
- m_timer1_counter = (m_timer1_counter & 0x00ff) | (data << 8);
- LOG("NSC810: Timer 1 high-byte write %02x (base=%04x)\n",data,m_timer1_base);
+ m_timer_base[1] = (m_timer_base[1] & 0x00ff) | (data << 8);
+ m_timer_counter[1] = (m_timer_counter[1] & 0x00ff) | (data << 8);
+ LOG("NSC810: Timer 1 high-byte write %02x (base=%04x)\n", data, m_timer_base[1]);
break;
case REG_TIMER0_STOP:
- m_timer0_running = false;
- m_timer0->reset();
- LOG("NSC810: Timer 0 Stop write %02x\n",tag(),data);
+ m_timer_running[0] = false;
+ m_timer[0]->reset();
+ LOG("NSC810: Timer 0 Stop write %02x\n", tag(), data);
break;
case REG_TIMER0_START:
- if((m_timer0_mode & 0x07) != 0x00 && (m_timer0_mode & 0x07) != 0x07)
+ if ((m_timer_mode[0] & 0x07) != 0x00 && (m_timer_mode[0] & 0x07) != 0x07)
{
- m_timer0_running = true;
- if(m_timer0_mode & 0x10)
- rate = m_timer0_clock / 64;
+ m_timer_running[0] = true;
+ if (m_timer_mode[0] & 0x10)
+ rate = m_timer_clock[0] / 64;
else
- if(m_timer0_mode & 0x08)
- rate = m_timer0_clock / 2;
+ if (m_timer_mode[0] & 0x08)
+ rate = m_timer_clock[0] / 2;
else
- rate = m_timer0_clock;
- m_timer0->adjust(attotime::zero,0,attotime::from_hz(rate));
+ rate = m_timer_clock[0];
+ m_timer[0]->adjust(attotime::zero, 0, attotime::from_hz(rate));
}
- LOG("NSC810: Timer 0 Start write %02x\n",data);
+ LOG("NSC810: Timer 0 Start write %02x\n", data);
break;
case REG_TIMER1_STOP:
- m_timer1_running = false;
- m_timer1->reset();
- LOG("NSC810: Timer 1 Stop write %02x\n",data);
+ m_timer_running[1] = false;
+ m_timer[1]->reset();
+ LOG("NSC810: Timer 1 Stop write %02x\n", data);
break;
case REG_TIMER1_START:
- if((m_timer1_mode & 0x07) != 0x00 && (m_timer1_mode & 0x07) != 0x07)
+ if ((m_timer_mode[1] & 0x07) != 0x00 && (m_timer_mode[1] & 0x07) != 0x07)
{
- m_timer1_running = true;
+ m_timer_running[1] = true;
// no /64 prescaler on timer 1
- if(m_timer0_mode & 0x08)
- rate = m_timer0_clock / 2;
+ if (m_timer_mode[0] & 0x08)
+ rate = m_timer_clock[0] / 2;
else
- rate = m_timer0_clock;
- m_timer1->adjust(attotime::zero,0,attotime::from_hz(rate));
+ rate = m_timer_clock[0];
+ m_timer[1]->adjust(attotime::zero, 0, attotime::from_hz(rate));
}
- LOG("NSC810: Timer 1 Start write %02x\n",data);
+ LOG("NSC810: Timer 1 Start write %02x\n", data);
break;
case REG_MODE_TIMER0:
- m_timer0_mode = data;
- LOG("NSC810: Timer 0 Mode write %02x\n",data);
+ m_timer_mode[0] = data;
+ LOG("NSC810: Timer 0 Mode write %02x\n", data);
break;
case REG_MODE_TIMER1:
- m_timer1_mode = data;
- LOG("NSC810: Timer 1 Mode write %02x\n",data);
+ m_timer_mode[1] = data;
+ LOG("NSC810: Timer 1 Mode write %02x\n", data);
break;
default:
- logerror("NSC810: Unused register %02x write %02x\n",offset,data);
+ logerror("NSC810: Unused register %02x write %02x\n", offset, data);
}
}
}
diff --git a/src/devices/machine/nsc810.h b/src/devices/machine/nsc810.h
index 520591208f7..08a35465cc4 100644
--- a/src/devices/machine/nsc810.h
+++ b/src/devices/machine/nsc810.h
@@ -38,12 +38,12 @@ public:
auto portA_write_callback() { return m_portA_w.bind(); }
auto portB_write_callback() { return m_portB_w.bind(); }
auto portC_write_callback() { return m_portC_w.bind(); }
- auto timer0_callback() { return m_timer0_out.bind(); }
- auto timer1_callback() { return m_timer1_out.bind(); }
+ auto timer0_callback() { return m_timer_out[0].bind(); }
+ auto timer1_callback() { return m_timer_out[1].bind(); }
- void set_timer0_clock(uint32_t clk) { m_timer0_clock = clk; }
+ void set_timer0_clock(uint32_t clk) { m_timer_clock[0] = clk; }
void set_timer0_clock(const XTAL &clk) { set_timer0_clock(clk.value()); }
- void set_timer1_clock(uint32_t clk) { m_timer1_clock = clk; }
+ void set_timer1_clock(uint32_t clk) { m_timer_clock[1] = clk; }
void set_timer1_clock(const XTAL &clk) { set_timer1_clock(clk.value()); }
uint8_t read(offs_t offset);
@@ -52,7 +52,8 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ template <int Timer> TIMER_CALLBACK_MEMBER(timer_tick);
private:
uint8_t m_portA_latch;
@@ -62,18 +63,12 @@ private:
uint8_t m_ddrB;
uint8_t m_ddrC;
uint8_t m_mode;
- emu_timer* m_timer0;
- emu_timer* m_timer1;
- uint8_t m_timer0_mode;
- uint8_t m_timer1_mode;
- uint16_t m_timer0_counter;
- uint16_t m_timer1_counter;
- uint16_t m_timer0_base;
- uint16_t m_timer1_base;
- bool m_timer0_running;
- bool m_timer1_running;
- uint32_t m_timer0_clock;
- uint32_t m_timer1_clock;
+ emu_timer* m_timer[2];
+ uint8_t m_timer_mode[2];
+ uint16_t m_timer_counter[2];
+ uint16_t m_timer_base[2];
+ bool m_timer_running[2];
+ uint32_t m_timer_clock[2];
bool m_ramselect;
devcb_read8 m_portA_r;
@@ -82,11 +77,7 @@ private:
devcb_write8 m_portA_w;
devcb_write8 m_portB_w;
devcb_write8 m_portC_w;
- devcb_write_line m_timer0_out;
- devcb_write_line m_timer1_out;
-
- static constexpr device_timer_id TIMER0_CLOCK = 0;
- static constexpr device_timer_id TIMER1_CLOCK = 1;
+ devcb_write_line::array<2> m_timer_out;
enum
{
diff --git a/src/devices/machine/nscsi_bus.cpp b/src/devices/machine/nscsi_bus.cpp
index 60d7e54d2fd..1f95b670c44 100644
--- a/src/devices/machine/nscsi_bus.cpp
+++ b/src/devices/machine/nscsi_bus.cpp
@@ -3,7 +3,11 @@
#include "emu.h"
#include "nscsi_bus.h"
-#define LOG_GENERAL (1U << 0)
+#include "util/multibyte.h"
+
+#include <cassert>
+#include <cstring>
+
#define LOG_UNSUPPORTED (1U << 1)
#define LOG_STATE (1U << 2)
#define LOG_CONTROL (1U << 3)
@@ -128,7 +132,7 @@ void nscsi_bus_device::ctrl_wait(int refid, uint32_t lines, uint32_t mask)
void nscsi_bus_device::device_resolve_objects()
{
for(int i=0; i<16; i++) {
- device_t *subdev = subdevice(string_format("%d", i).c_str());
+ device_t *subdev = subdevice(string_format("%d", i));
nscsi_device *sdev = subdev ? downcast<nscsi_connector &>(*subdev).get_device() : nullptr;
if(sdev) {
int rid = devcnt++;
@@ -199,17 +203,17 @@ nscsi_full_device::nscsi_full_device(const machine_config &mconfig, device_type
}
const char *const nscsi_full_device::command_names[256] = {
- /* 00 */ "TEST_UNIT_READY", "REZERO", "?", "REQUEST_SENSE", "FORMAT_UNIT", "?", "?", "REASSIGN_BLOCKS",
- /* 08 */ "READ_6/RECIEVE", "?", "WRITE_6/SEND", "SEEK", "?", "?", "?", "?",
- /* 10 */ "?", "?", "INQUIRY", "?", "?", "MODE_SELECT_6", "RESERVE_6", "RELEASE_6",
- /* 18 */ "?", "?", "MODE_SENSE_6", "START_STOP_UNIT", "RECIEVE_DIAG_RES", "SEND_DIAGNOSTICS", "PREVENT_ALLOW_MEDIUM_REMOVAL", "?",
- /* 20 */ "?", "?", "?", "READ_FORMAT_CAPACITIES", "?", "READ_CAPACITY", "?", "?",
-
- /* 28 */ "READ_10", "READ_GENERATION", "WRITE_10", "SEEK_10", "ERASE_10", "READ_UPDATED_BLOCK_10", "WRITE_VERIFY", "VERIFY",
- /* 30 */ "SEARCH_DATA_HIGH_10", "SEARCH_DATA_EQUAL_10", "SEARCH_DATA_LOW_10", "SET_LIMITS_10", "PREFETCH", "SYNC_CACHE", "LOCK_UNLOCK_CACHE", "READ_DEFECT_DATA",
- /* 38 */ "MEDIUM_SCAN", "COMPARE", "COPY_AND_VERIFY", "WRITE_BUFFER", "READ_DATA_BUFFER", "UPDATE_BLOCK", "READ_LONG", "WRITE_LONG",
+ /* 00 */ "TEST_UNIT_READY", "REWIND/REZERO_UNIT", "REQUEST_BLOCK_ADDRESS", "REQUEST_SENSE", "FORMAT/FORMAT_UNIT", "READ_BLOCK_LIMITS", "?", "INITIALIZE_ELEMENT_STATUS/REASSIGN_BLOCKS",
+ /* 08 */ "GET_MESSAGE_6/READ_6/RECEIVE", "?", "PRINT/SEND_MESSAGE_6/SEND_6/WRITE_6", "SEEK_6/SLEW_AND_PRINT", "SEEK_BLOCK", "?", "?", "READ_REVERSE",
+ /* 10 */ "SYNCHRONIZE_BUFFER/WRITE_FILEMARKS", "SPACE", "INQUIRY", "VERIFY_6", "RECOVER_BUFFERED_DATA", "MODE_SELECT_6", "RESERVE_6/RESERVE_UNIT", "RELEASE_6/RELEASE_UNIT",
+ /* 18 */ "COPY", "ERASE", "MODE_SENSE_6", "LOAD_UNLOAD/SCAN/STOP_PRINT/START_STOP_UNIT", "RECEIVE_DIAGNOSTIC_RESULTS", "SEND_DIAGNOSTIC", "PREVENT_ALLOW_MEDIUM_REMOVAL", "?",
+ /* 20 */ "?", "?", "?", "READ_FORMAT_CAPACITIES", "SET_WINDOW", "GET_WINDOW/READ_CAPACITY/READ_CD_RECORDED_CAPACITY", "?", "?",
+
+ /* 28 */ "GET_MESSAGE_10/READ_10", "READ_GENERATION", "SEND_MESSAGE_10/SEND_10/WRITE_10", "LOCATE/POSITION_TO_ELEMENT/SEEK_10", "ERASE_10", "READ_UPDATED_BLOCK", "WRITE_AND_VERIFY_10", "VERIFY_10",
+ /* 30 */ "SEARCH_DATA_HIGH_10", "OBJECT_POSITION/SEARCH_DATA_EQUAL_10", "SEARCH_DATA_LOW_10", "SET_LIMITS_10", "PREFETCH/READ_POSITION", "SYNCHRONIZE_CACHE", "LOCK_UNLOCK_CACHE", "READ_DEFECT_DATA_10",
+ /* 38 */ "MEDIUM_SCAN", "COMPARE", "COPY_AND_VERIFY", "WRITE_BUFFER", "READ_BUFFER", "UPDATE_BLOCK", "READ_LONG", "WRITE_LONG",
/* 40 */ "CHANGE_DEFINITION", "WRITE_SAME", "READ_SUB_CHANNEL", "READ_TOC_PMA_ATIP", "READ_HEADER", "PLAY_AUDIO_10", "GET_CONFIGURATION", "PLAY_AUDIO_MSF",
- /* 48 */ "PLAY_AUDIO_TRACK_INDEX", "PLAY_RELATIVE_10", "GET_EVENT_STATUS_NOTIFICATION", "PAUSE_RESUME", "LOG_SELECT", "LOG_SENSE", "STOP_PLAY_SCAN", "?",
+ /* 48 */ "PLAY_AUDIO_TRACK_INDEX", "PLAY_TRACK_RELATIVE_10", "GET_EVENT_STATUS_NOTIFICATION", "PAUSE_RESUME", "LOG_SELECT", "LOG_SENSE", "STOP_PLAY_SCAN", "?",
/* 50 */ "XDWRITE", "READ_DISC_INFORMATION/XPWRITE", "READ_TRACK_INFORMATION/XDREAD", "RESERVE_TRACK", "SEND_OPC_INFORMATION", "MODE_SELECT_10", "RESERVE_10", "RELEASE_10",
/* 58 */ "REPAIR_TRACK", "READ_MASTER_CUE", "MODE_SENSE_10", "CLOSE_TRACK_SESSION", "READ_BUFFER_CAPACITY", "SEND_CUE_SHEET", "PERSISTENT_RESERVE_IN", "PERSISTENT_RESERVE_OUT",
/* 80 */ "XDWRITE_EXTENDED", "REBUILD", "REGENERATE", "EXTENDED_COPY", "RECEIVE_COPY_RESULTS", "?", "?", "?",
@@ -233,7 +237,7 @@ const char *const nscsi_full_device::command_names[256] = {
void nscsi_full_device::device_start()
{
nscsi_device::device_start();
- scsi_timer = timer_alloc(SCSI_TIMER);
+ scsi_timer = timer_alloc(FUNC(nscsi_full_device::update_tick), this);
save_item(NAME(scsi_cmdbuf));
save_item(NAME(scsi_sense_buffer));
save_item(NAME(scsi_cmdsize));
@@ -263,15 +267,12 @@ void nscsi_full_device::device_reset()
scsi_bus->data_w(scsi_refid, 0);
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL);
+ sense(false, SK_NO_SENSE);
}
-void nscsi_full_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(nscsi_full_device::update_tick)
{
- if(id != SCSI_TIMER)
- return;
-
- step(true);
-
+ step(param);
}
void nscsi_full_device::scsi_ctrl_changed()
@@ -307,7 +308,7 @@ void nscsi_full_device::step(bool timeout)
if(scsi_initiator_id == 16)
scsi_initiator_id = -1;
scsi_state = TARGET_SELECT_WAIT_BUS_SETTLE;
- scsi_timer->adjust(scsi_bus_settle_delay());
+ scsi_timer->adjust(scsi_bus_settle_delay(), true);
}
break;
@@ -339,7 +340,12 @@ void nscsi_full_device::step(bool timeout)
if(!(ctrl & S_ACK)) {
scsi_state &= STATE_MASK;
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
- step(false);
+ attotime delay = scsi_data_byte_period();
+ if (delay == attotime::zero) {
+ step(false);
+ } else {
+ scsi_timer->adjust(delay, false);
+ }
}
break;
@@ -355,7 +361,12 @@ void nscsi_full_device::step(bool timeout)
if(!(ctrl & S_ACK)) {
scsi_state &= STATE_MASK;
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
- step(false);
+ attotime delay = scsi_data_byte_period();
+ if (delay == attotime::zero) {
+ step(false);
+ } else {
+ scsi_timer->adjust(delay, false);
+ }
}
break;
@@ -463,7 +474,12 @@ void nscsi_full_device::step(bool timeout)
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
scsi_command();
scsi_state = TARGET_NEXT_CONTROL;
- step(false);
+ attotime delay = scsi_data_command_delay();
+ if (delay == attotime::zero) {
+ step(false);
+ } else {
+ scsi_timer->adjust(delay, false);
+ }
} else
target_recv_byte();
break;
@@ -544,7 +560,7 @@ bool nscsi_full_device::scsi_command_done(uint8_t command, uint8_t length)
nscsi_full_device::control *nscsi_full_device::buf_control_push()
{
- if(buf_control_wpos == int(ARRAY_LENGTH(buf_control)))
+ if(buf_control_wpos == int(std::size(buf_control)))
throw emu_fatalerror("%s: buf_control overflow\n", tag());
control *c = buf_control + buf_control_wpos;
@@ -606,16 +622,171 @@ void nscsi_full_device::scsi_data_out(int buf, int size)
c->param2 = size;
}
+//////////////////////////////////////////////////////////////////////////////
+
+void nscsi_full_device::set_sense_data(const u8 sense_key, const u16 sense_key_code, const sense_data *data)
+{
+ assert(sizeof(scsi_sense_buffer) >= 18);
+ assert(sense_key <= 0x0f);
+ memset(scsi_sense_buffer, 0, 18);
+ if (data) {
+ scsi_sense_buffer[0] = (data->invalid ? 0 : 0x80) // even though SCSI-2 section 8.2.14 implies valid bit should always be set, other sections such as 10.2.12 disagree!
+ | (data->deferred ? 0x71 : 0x70);
+ scsi_sense_buffer[2] = (data->filemark ? 0x80 : 0)
+ | (data->eom ? 0x40 : 0)
+ | (data->bad_len ? 0x20 : 0); // "incorrect length indicator"
+ put_s32be(&scsi_sense_buffer[3], data->info);
+ }
+ else
+ scsi_sense_buffer[0] = 0xf0;
+ scsi_sense_buffer[2] |= sense_key;
+ scsi_sense_buffer[7] = 10; // additional sense length
+ put_u16be(&scsi_sense_buffer[12], sense_key_code);
+}
+
void nscsi_full_device::sense(bool deferred, uint8_t key, uint8_t asc, uint8_t ascq)
{
- memset(scsi_sense_buffer, 0, sizeof(scsi_sense_buffer));
- scsi_sense_buffer[0] = deferred ? 0x71 : 0x70;
- scsi_sense_buffer[2] = key;
- scsi_sense_buffer[7] = sizeof(scsi_sense_buffer) - 8;
- scsi_sense_buffer[12] = asc;
- scsi_sense_buffer[13] = ascq;
+ sense_data s;
+ s.deferred = deferred;
+ set_sense_data(key, (asc << 8) | ascq, &s);
+}
+
+void nscsi_full_device::report_condition(const u8 sense_key, const u16 sense_key_code, const sense_data *data)
+{
+ set_sense_data(sense_key, sense_key_code, data);
+ scsi_status_complete(SS_CHECK_CONDITION);
+}
+
+void nscsi_full_device::report_bad_lun(const u8 cmd, const u8 lun)
+{
+ LOG("%s (0x%02x) lun=%d\n *** BAD LUN\n", command_names[cmd], cmd, lun);
+ report_condition(SK_ILLEGAL_REQUEST, SKC_LOGICAL_UNIT_NOT_SUPPORTED);
+}
+
+void nscsi_full_device::report_bad_cmd(const u8 cmd)
+{
+ LOG("%s (0x%02x)\n *** BAD COMMAND\n", command_names[cmd], cmd);
+ report_condition(SK_ILLEGAL_REQUEST, SKC_INVALID_COMMAND_OPERATION_CODE);
+}
+
+void nscsi_full_device::report_filemark(const s32 info, const bool eom)
+{
+ LOG(" *** FILEMARK info=%d\n", info);
+ sense_data s;
+ s.filemark = true;
+ s.eom = eom;
+ s.info = info;
+ report_condition(SK_NO_SENSE, SKC_FILEMARK_DETECTED, &s);
+}
+
+void nscsi_full_device::report_bom(const s32 info)
+{
+ LOG(" *** BOM info=%d\n", info);
+ sense_data s;
+ s.eom = true;
+ s.info = info;
+ report_condition(SK_NO_SENSE, SKC_BEGINNING_OF_PARTITION_MEDIUM_DETECTED, &s);
+}
+
+void nscsi_full_device::report_ew(const s32 info)
+{
+ LOG(" EW info=%d\n", info);
+ sense_data s;
+ s.eom = true;
+ s.info = info;
+ report_condition(SK_NO_SENSE, SKC_END_OF_PARTITION_MEDIUM_DETECTED, &s);
+}
+
+void nscsi_full_device::report_eod(const s32 info, const bool eom)
+{
+ LOG(" *** EOD info=%d\n", info);
+ sense_data s;
+ s.eom = eom;
+ s.info = info;
+ report_condition(SK_BLANK_CHECK, SKC_END_OF_DATA_DETECTED, &s);
+}
+
+void nscsi_full_device::report_eom(const bool write, const s32 info, const bool invalid)
+{
+ LOG(" *** EOM info=%d invalid=%d\n", info, invalid);
+ sense_data s;
+ s.invalid = invalid;
+ s.eom = true;
+ s.info = info;
+ report_condition(write ? SK_VOLUME_OVERFLOW : SK_MEDIUM_ERROR, SKC_END_OF_PARTITION_MEDIUM_DETECTED, &s);
}
+void nscsi_full_device::report_bad_len(const bool over, const s32 info)
+{
+ LOG(" *** %sLENGTH BLOCK info=%d\n", over ? "OVER" : "UNDER", info);
+ sense_data s;
+ s.bad_len = true;
+ s.info = info;
+ report_condition(SK_ILLEGAL_REQUEST, SKC_NO_ADDITIONAL_SENSE_INFORMATION, &s);
+}
+
+void nscsi_full_device::report_bad_cdb_field()
+{
+ LOG(" *** BAD CDB FIELD\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_INVALID_FIELD_IN_CDB);
+}
+
+void nscsi_full_device::report_bad_pl_field()
+{
+ LOG(" *** BAD PARAMETER LIST FIELD\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_INVALID_FIELD_IN_PARAMETER_LIST);
+}
+
+void nscsi_full_device::report_bad_pl_len()
+{
+ LOG(" *** BAD PARAMETER LIST LENGTH\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_PARAMETER_LIST_LENGTH_ERROR);
+}
+
+void nscsi_full_device::report_no_saving_params()
+{
+ LOG(" *** NO SAVING PARAMETERS\n");
+ report_condition(SK_ILLEGAL_REQUEST, SKC_SAVING_PARAMETERS_NOT_SUPPORTED);
+}
+
+void nscsi_full_device::report_no_medium()
+{
+ LOG(" *** NO MEDIUM\n");
+ report_condition(SK_NOT_READY, SKC_MEDIUM_NOT_PRESENT);
+}
+
+void nscsi_full_device::report_medium_changed()
+{
+ LOG(" MEDIUM CHANGED\n");
+ report_condition(SK_UNIT_ATTENTION, SKC_NOT_READY_TO_READY_TRANSITION_MEDIUM_MAY_HAVE_CHANGED);
+}
+
+void nscsi_full_device::report_read_only()
+{
+ LOG(" *** READ ONLY\n");
+ report_condition(SK_DATA_PROTECT, SKC_WRITE_PROTECTED);
+}
+
+void nscsi_full_device::report_read_failure()
+{
+ LOG(" *** READ FAILURE\n");
+ report_condition(SK_MEDIUM_ERROR, SKC_UNRECOVERED_READ_ERROR);
+}
+
+void nscsi_full_device::report_write_failure()
+{
+ LOG(" *** WRITE FAILURE\n");
+ report_condition(SK_MEDIUM_ERROR, SKC_WRITE_ERROR);
+}
+
+void nscsi_full_device::report_erase_failure()
+{
+ LOG(" *** ERASE FAILURE\n");
+ report_condition(SK_MEDIUM_ERROR, SKC_ERASE_FAILURE);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
void nscsi_full_device::scsi_unknown_command()
{
std::string txt = util::string_format("Unhandled command %s (%d):", command_names[scsi_cmdbuf[0]], scsi_cmdsize);
@@ -629,15 +800,15 @@ void nscsi_full_device::scsi_unknown_command()
void nscsi_full_device::scsi_command()
{
- switch(scsi_cmdbuf[0]) {
- case SC_REZERO:
- LOG("command REZERO\n");
+ const u8 cmd = scsi_cmdbuf[0];
+ const u8 lun = get_lun(scsi_cmdbuf[1] >> 5); // LUN may be overridden by IDENTIFY, per SCSI-2 section 7.2.2
+ switch(cmd) {
+ case SC_REZERO_UNIT:
+ LOG("command REZERO UNIT\n");
scsi_status_complete(SS_GOOD);
break;
case SC_REQUEST_SENSE:
- LOG("command REQUEST SENSE alloc=%d\n", scsi_cmdbuf[4]);
- scsi_data_in(SBUF_SENSE, scsi_cmdbuf[4] ? std::min(scsi_cmdbuf[4], u8(sizeof(scsi_sense_buffer))) : 4);
- scsi_status_complete(SS_GOOD);
+ handle_request_sense(lun);
break;
default:
scsi_unknown_command();
@@ -645,6 +816,18 @@ void nscsi_full_device::scsi_command()
}
}
+void nscsi_full_device::handle_request_sense(const u8 lun) // mandatory; SCSI-2 section 8.2.14
+{
+ const u8 alloc_len = scsi_cmdbuf[4]; // allocation length
+ LOG("command REQUEST SENSE lun=%d alloc_len=%d\n", lun, alloc_len);
+ if ((scsi_cmdbuf[1] & 0x1f) || scsi_cmdbuf[2] || scsi_cmdbuf[3]) // error: reserved bits set
+ return report_bad_cdb_field();
+
+ assert(sizeof(scsi_sense_buffer) >= 18);
+ scsi_data_in(SBUF_SENSE, std::min(18, (const int)alloc_len));
+ scsi_status_complete(SS_GOOD);
+}
+
void nscsi_full_device::scsi_message()
{
if(scsi_cmdbuf[0] & 0x80) {
@@ -791,3 +974,15 @@ attotime nscsi_full_device::scsi_fast_negation_period()
{
return attotime::from_nsec(30);
}
+
+// Byte transfer rate (immediate)
+attotime nscsi_full_device::scsi_data_byte_period()
+{
+ return attotime::zero;
+}
+
+// Command execution delay (immediate)
+attotime nscsi_full_device::scsi_data_command_delay()
+{
+ return attotime::zero;
+}
diff --git a/src/devices/machine/nscsi_bus.h b/src/devices/machine/nscsi_bus.h
index 60c9f02a3b1..f5d7a236d45 100644
--- a/src/devices/machine/nscsi_bus.h
+++ b/src/devices/machine/nscsi_bus.h
@@ -104,27 +104,27 @@ public:
// Here because some controllers interpret messages
enum {
SM_COMMAND_COMPLETE = 0x00,
- SM_EXTENDED_MSG = 0x01,
- SM_SAVE_DATA_PTR = 0x02,
- SM_RESTORE_PTR = 0x03,
+ SM_EXTENDED_MESSAGE = 0x01,
+ SM_SAVE_DATA_POINTER = 0x02,
+ SM_RESTORE_POINTERS = 0x03,
SM_DISCONNECT = 0x04,
- SM_INITIATOR_ERROR = 0x05,
+ SM_INITIATOR_DETECTED_ERROR = 0x05,
SM_ABORT = 0x06,
- SM_MSG_REJECT = 0x07,
- SM_NOP = 0x08,
- SM_MSG_PARITY = 0x09,
- SM_LCMD_COMPLETE = 0x0a,
- SM_LCMD_COMPLETE_F = 0x0b,
+ SM_MESSAGE_REJECT = 0x07,
+ SM_NO_OPERATION = 0x08,
+ SM_MESSAGE_PARITY_ERROR = 0x09,
+ SM_LINKED_COMMAND_COMPLETE = 0x0a,
+ SM_LINKED_COMMAND_COMPLETE_WITH_FLAG = 0x0b,
SM_BUS_DEVICE_RESET = 0x0c,
SM_ABORT_TAG = 0x0d,
SM_CLEAR_QUEUE = 0x0e,
- SM_INIT_RECOVERY = 0x0f,
+ SM_INITIATE_RECOVERY = 0x0f,
SM_RELEASE_RECOVERY = 0x10,
- SM_TERMINATE_IO = 0x11,
- SM_SIMPLE_QUEUE = 0x20,
- SM_HEAD_QUEUE = 0x21,
- SM_ORDERED_QUEUE = 0x22,
- SM_IGNORE_WIDE_RES = 0x23
+ SM_TERMINATE_IO_PROCESS = 0x11,
+ SM_SIMPLE_QUEUE_TAG = 0x20,
+ SM_HEAD_OF_QUEUE_TAG = 0x21,
+ SM_ORDERED_QUEUE_TAG = 0x22,
+ SM_IGNORE_WIDE_RESIDUE = 0x23
};
void connect_to_bus(nscsi_bus_device *bus, int refid, int default_scsi_id);
@@ -144,9 +144,8 @@ class nscsi_full_device : public nscsi_device, public nscsi_slot_card_interface
{
public:
virtual void scsi_ctrl_changed() override;
-protected:
- enum { SCSI_TIMER = 100 };
+protected:
// SCSI status returns
enum {
SS_GOOD = 0x00,
@@ -174,11 +173,310 @@ protected:
SK_VENDOR_SPECIFIC = 0x09,
SK_COPY_ABORTED = 0x0a,
SK_ABORTED_COMMAND = 0x0b,
+ SK_EQUAL = 0x0c,
SK_VOLUME_OVERFLOW = 0x0d,
SK_MISCOMPARE = 0x0e,
SK_COMPLETED = 0x0f
};
+ // SCSI SPACE type codes; SCSI-2 table 189
+ enum {
+ STC_BLOCKS = 0x00,
+ STC_FILEMARKS = 0x01,
+ STC_SEQUENTIAL_FILEMARKS = 0x02,
+ STC_END_OF_DATA = 0x03,
+ STC_SETMARKS = 0x04,
+ STC_SEQUENTIAL_SETMARKS = 0x05
+ };
+
+ // SCSI MODE SENSE page controls; SCSI-2 table 55
+ enum {
+ SPC_CURRENT_VALUES = 0x00,
+ SPC_CHANGEABLE_VALUES = 0x01,
+ SPC_DEFAULT_VALUES = 0x02,
+ SPC_SAVED_VALUES = 0x03
+ };
+
+ // SCSI MODE SELECT/SENSE page codes; SCSI-2 tables 95, 155, 199, 216, 267, 296, 324, 350, 363; extra SCSI-3 codes from "The SCSI Bench Reference"
+ enum {
+ SPC_VENDOR_SPECIFIC = 0x00,
+ SPC_READ_WRITE_ERROR_RECOVERY_PAGE = 0x01,
+ SPC_READ_ERROR_RECOVERY_PAGE = 0x01,
+ SPC_DISCONNECT_RECONNECT_PAGE = 0x02,
+ SPC_FORMAT_DEVICE_PAGE = 0x03,
+ SPC_PARALLEL_PRINTER_INTERFACE_PAGE = 0x03,
+ SPC_MEASUREMENT_UNITS_PAGE = 0x03,
+ SPC_RIGID_DISK_GEOMETRY_PAGE = 0x04,
+ SPC_SERIAL_PRINTER_INTERFACE_PAGE = 0x04,
+ SPC_FLEXIBLE_DISK_PAGE = 0x05,
+ SPC_PRINTER_OPTIONS_PAGE = 0x05,
+ SPC_OPTICAL_MEMORY_PAGE = 0x06,
+ SPC_VERIFY_ERROR_RECOVERY_PAGE = 0x07,
+ SPC_CACHING_PAGE = 0x08,
+ SPC_PERIPHERAL_DEVICE_PAGE = 0x09,
+ SPC_CONTROL_MODE_PAGE = 0x0a,
+ SPC_MEDIUM_TYPES_SUPPORTED_PAGE = 0x0b,
+ SPC_NOTCH_AND_PARTITION_PAGE = 0x0c,
+ SPC_DIRECT_ACCESS_POWER_CONDITION_PAGE = 0x0d, // direct access device only
+ SPC_CD_ROM_PAGE = 0x0d,
+ SPC_CD_ROM_AUDIO_CONTROL_PAGE = 0x0e,
+ SPC_DATA_COMPRESSION_PAGE = 0x0f,
+ SPC_XOR_CONTROL_MODE_PAGE = 0x10,
+ SPC_DEVICE_CONFIGURATION_PAGE = 0x10,
+ SPC_MEDIUM_PARTITION_PAGE_1 = 0x11,
+ SPC_MEDIUM_PARTITION_PAGE_2 = 0x12,
+ SPC_MEDIUM_PARTITION_PAGE_3 = 0x13,
+ SPC_MEDIUM_PARTITION_PAGE_4 = 0x14,
+ SPC_POWER_CONDITION_PAGE = 0x1a, // all other device types
+ SPC_INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE = 0x1c,
+ SPC_ELEMENT_ADDRESS_ASSIGNMENT_PAGE = 0x1d,
+ SPC_TRANSPORT_GEOMETRY_PARAMETERS_PAGE = 0x1e,
+ SPC_DEVICE_CAPABILITIES_PAGE = 0x1f,
+ SPC_RETURN_ALL_MODE_PAGES = 0x3f
+ };
+
+ // SCSI additional sense codes and additional sense code qualifiers, packaged together as additional qualified sense key codes; SCSI-2 table 71; extra SCSI-3 codes from "The SCSI Bench Reference"
+ enum {
+ SKC_NO_ADDITIONAL_SENSE_INFORMATION = 0x0000,
+ SKC_FILEMARK_DETECTED = 0x0001,
+ SKC_END_OF_PARTITION_MEDIUM_DETECTED = 0x0002,
+ SKC_SETMARK_DETECTED = 0x0003,
+ SKC_BEGINNING_OF_PARTITION_MEDIUM_DETECTED = 0x0004,
+ SKC_END_OF_DATA_DETECTED = 0x0005,
+ SKC_IO_PROCESS_TERMINATED = 0x0006,
+ SKC_AUDIO_PLAY_OPERATION_IN_PROGRESS = 0x0011,
+ SKC_AUDIO_PLAY_OPERATION_PAUSED = 0x0012,
+ SKC_AUDIO_PLAY_OPERATION_SUCCESSFULLY_COMPLETED = 0x0013,
+ SKC_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR = 0x0014,
+ SKC_NO_CURRENT_AUDIO_STATUS_TO_RETURN = 0x0015,
+ SKC_OPERATION_IN_PROGRESS = 0x0016,
+ SKC_CLEANING_REQUESTED = 0x0017,
+ SKC_NO_INDEX_SECTOR_SIGNAL = 0x0100,
+ SKC_NO_SEEK_COMPLETE = 0x0200,
+ SKC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x0300,
+ SKC_NO_WRITE_CURRENT = 0x0301,
+ SKC_EXCESSIVE_WRITE_ERRORS = 0x0302,
+ SKC_LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE = 0x0400,
+ SKC_LOGICAL_UNIT_IS_IN_PROCESS_OF_BECOMING_READY = 0x0401,
+ SKC_LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED = 0x0402,
+ SKC_LOGICAL_UNIT_NOT_READY_MANUAL_INTERVENTION_REQUIRED = 0x0403,
+ SKC_LOGICAL_UNIT_NOT_READY_FORMAT_IN_PROGRESS = 0x0404,
+ SKC_LOGICAL_UNIT_NOT_READY_OPERATION_IN_PROGRESS = 0x0407,
+ SKC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION = 0x0500,
+ SKC_NO_REFERENCE_POSITION_FOUND = 0x0600,
+ SKC_MULTIPLE_PERIPHERAL_DEVICES_SELECTED = 0x0700,
+ SKC_LOGICAL_UNIT_COMMUNICATION_FAILURE = 0x0800,
+ SKC_LOGICAL_UNIT_COMMUNICATION_TIME_OUT = 0x0801,
+ SKC_LOGICAL_UNIT_COMMUNICATION_PARITY_ERROR = 0x0802,
+ SKC_TRACK_FOLLOWING_ERROR = 0x0900,
+ SKC_TRACKING_SERVO_FAILURE = 0x0901,
+ SKC_FOCUS_SERVO_FAILURE = 0x0902,
+ SKC_SPINDLE_SERVO_FAILURE = 0x0903,
+ SKC_HEAD_SELECT_FAULT = 0x0904,
+ SKC_ERROR_LOG_OVERFLOW = 0x0a00,
+ SKC_WARNING = 0x0b00,
+ SKC_WARNING_SPECIFIC_TEMPERATURE_EXCEEDED = 0x0b01,
+ SKC_WRITE_ERROR = 0x0c00,
+ SKC_WRITE_ERROR_RECOVERED_WITH_AUTO_REALLOCATION = 0x0c01,
+ SKC_WRITE_ERROR_AUTO_REALLOCATION_FAILED = 0x0c02,
+ SKC_WRITE_ERROR_RECOMMEND_REASSIGNMENT = 0x0c03,
+ SKC_COMPRESSION_CHECK_MISCOMPARE_ERROR = 0x0c04,
+ SKC_DATA_EXPANSION_OCCURRED_DURING_COMPRESSION = 0x0c05,
+ SKC_BLOCK_NOT_COMPRESSABLE = 0x0c06,
+ SKC_ID_CRC_OR_ECC_ERROR = 0x1000,
+ SKC_UNRECOVERED_READ_ERROR = 0x1100,
+ SKC_READ_RETRIES_EXHAUSTED = 0x1101,
+ SKC_ERROR_TOO_LONG_TO_CORRECT = 0x1102,
+ SKC_MULTIPLE_READ_ERRORS = 0x1103,
+ SKC_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAILED = 0x1104,
+ SKC_L_EC_UNCORRECTABLE_ERROR = 0x1105,
+ SKC_CIRC_UNRECOVERED_ERROR = 0x1106,
+ SKC_DATA_RESYNCHRONIZATION_ERROR = 0x1107,
+ SKC_INCOMPLETE_BLOCK_READ = 0x1108,
+ SKC_NO_GAP_FOUND = 0x1109,
+ SKC_MISCORRECTED_ERROR = 0x110a,
+ SKC_UNRECOVERED_READ_ERROR_RECOMMEND_REASSIGNMENT = 0x110b,
+ SKC_UNRECOVERED_READ_ERROR_RECOMMEND_REWRITE = 0x110c,
+ SKC_DECOMPRESSION_CRC_ERROR = 0x110d,
+ SKC_CANNOT_DECOMPRESS_USING_DECLARED_ALGORITHM = 0x100e,
+ SKC_ADDRESS_MARK_NOT_FOUND_FOR_ID_FIELD = 0x1200,
+ SKC_ADDRESS_MARK_NOT_FOUND_FOR_DATA_FIELD = 0x1300,
+ SKC_RECORDED_ENTITY_NOT_FOUND = 0x1400,
+ SKC_RECORD_NOT_FOUND = 0x1401,
+ SKC_FILEMARK_OR_SETMARK_NOT_FOUND = 0x1402,
+ SKC_END_OF_DATA_NOT_FOUND = 0x1403,
+ SKC_BLOCK_SEQUENCE_ERROR = 0x1404,
+ SKC_RECORD_NOT_FOUND_RECOMMEND_REASSIGNMENT = 0x1405,
+ SKC_RECORD_NOT_FOUND_DATA_AUTO_REALLOCATED = 0x1406,
+ SKC_RANDOM_POSITIONING_ERROR = 0x1500,
+ SKC_MECHANICAL_POSITIONING_ERROR = 0x1501,
+ SKC_POSITIONING_ERROR_DETECTED_BY_READ_OF_MEDIUM = 0x1502,
+ SKC_DATA_SYNCHRONIZATION_MARK_ERROR = 0x1600,
+ SKC_DATA_SYNCHRONIZATION_ERROR_DATA_REWRITTEN = 0x1601,
+ SKC_DATA_SYNCHRONIZATION_ERROR_RECOMMEND_REWRITE = 0x1602,
+ SKC_DATA_SYNCHRONIZATION_ERROR_DATA_AUTO_REALLOCATED = 0x1603,
+ SKC_DATA_SYNCHRONIZATION_ERROR_RECOMMEND_REASSIGNMENT = 0x1604,
+ SKC_RECOVERED_DATA_WITH_NO_ERROR_CORRECTION_APPLIED = 0x1700,
+ SKC_RECOVERED_DATA_WITH_RETRIES = 0x1701,
+ SKC_RECOVERED_DATA_WITH_POSITIVE_HEAD_OFFSET = 0x1702,
+ SKC_RECOVERED_DATA_WITH_NEGATIVE_HEAD_OFFSET = 0x1703,
+ SKC_RECOVERED_DATA_WITH_RETRIES_AND_OR_CIRC_APPLIED = 0x1704,
+ SKC_RECOVERED_DATA_USING_PREVIOUS_SECTOR_ID = 0x1705,
+ SKC_RECOVERED_DATA_WITHOUT_ECC_DATA_AUTO_REALLOCATED = 0x1706,
+ SKC_RECOVERED_DATA_WITHOUT_ECC_RECOMMEND_REASSIGNMENT = 0x1707,
+ SKC_RECOVERED_DATA_WITHOUT_ECC_RECOMMEND_REWRITE = 0x1708,
+ SKC_RECOVERED_DATA_WITHOUT_ECC_DATA_REWRITTEN = 0x1809,
+ SKC_RECOVERED_DATA_WITH_ERROR_CORRECTION_APPLIED = 0x1800,
+ SKC_RECOVERED_DATA_WITH_ERROR_CORRECTION_RETRIES_APPLIED = 0x1801,
+ SKC_RECOVERED_DATA_DATA_AUTO_REALLOCATED = 0x1802,
+ SKC_RECOVERED_DATA_WITH_CIRC = 0x1803,
+ SKC_RECOVERED_DATA_WITH_L_EC = 0x1804,
+ SKC_RECOVERED_DATA_RECOMMEND_REASSIGNMENT = 0x1805,
+ SKC_RECOVERED_DATA_RECOMMEND_REWRITE = 0x1806,
+ SKC_RECOVERED_DATA_WITH_ECC_DATA_REWRITTEN = 0x1807,
+ SKC_DEFECT_LIST_ERROR = 0x1900,
+ SKC_DEFECT_LIST_NOT_AVAILABLE = 0x1901,
+ SKC_DEFECT_LIST_ERROR_IN_PRIMARY_LIST = 0x1902,
+ SKC_DEFECT_LIST_ERROR_IN_GROWN_LIST = 0x1903,
+ SKC_PARAMETER_LIST_LENGTH_ERROR = 0x1a00,
+ SKC_SYNCHRONOUS_DATA_TRANSFER_ERROR = 0x1b00,
+ SKC_DEFECT_LIST_NOT_FOUND = 0x1c00,
+ SKC_PRIMARY_DEFECT_LIST_NOT_FOUND = 0x1c01,
+ SKC_GROWN_DEFECT_LIST_NOT_FOUND = 0x1c02,
+ SKC_MISCOMPARE_DURING_VERIFY_OPERATION = 0x1d00,
+ SKC_RECOVERED_ID_WITH_ECC_CORRECTION = 0x1e00,
+ SKC_PARTIAL_DEFECT_LIST_TRANSFER = 0x1f00,
+ SKC_INVALID_COMMAND_OPERATION_CODE = 0x2000,
+ SKC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE = 0x2100,
+ SKC_INVALID_ELEMENT_ADDRESS = 0x2101,
+ SKC_ILLEGAL_FUNCTION = 0x2200, // "should use 0x2000, 0x2400, or 0x2600"
+ SKC_INVALID_FIELD_IN_CDB = 0x2400,
+ SKC_LOGICAL_UNIT_NOT_SUPPORTED = 0x2500,
+ SKC_INVALID_FIELD_IN_PARAMETER_LIST = 0x2600,
+ SKC_PARAMETER_NOT_SUPPORTED = 0x2601,
+ SKC_PARAMETER_VALUE_INVALID = 0x2602,
+ SKC_THRESHOLD_PARAMETERS_NOT_SUPPORTED = 0x2603,
+ SKC_INVALID_RELEASE_OF_ACTIVE_PERSISTENT_RESERVATION = 0x2604,
+ SKC_WRITE_PROTECTED = 0x2700,
+ SKC_NOT_READY_TO_READY_TRANSITION_MEDIUM_MAY_HAVE_CHANGED = 0x2800,
+ SKC_IMPORT_OR_EXPORT_ELEMENT_ACCESSED = 0x2801,
+ SKC_POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURRED = 0x2900,
+ SKC_POWER_ON_OCCURRED = 0x2901,
+ SKC_SCSI_BUS_RESET_OCCURRED = 0x2902,
+ SKC_SCSI_BUS_DEVICE_RESET_FUNCTION_OCCURRED = 0x2903,
+ SKC_PARAMETERS_CHANGED = 0x2a00,
+ SKC_MODE_PARAMETERS_CHANGED = 0x2a01,
+ SKC_LOG_PARAMETERS_CHANGED = 0x2a02,
+ SKC_RESERVATIONS_PREEMPTED = 0x2a03,
+ SKC_COPY_CANNOT_EXECUTE_SINCE_HOST_CANNOT_DISCONNECT = 0x2b00,
+ SKC_COMMAND_SEQUENCE_ERROR = 0x2c00,
+ SKC_TOO_MANY_WINDOWS_SPECIFIED = 0x2c01,
+ SKC_INVALID_COMBINATION_OF_WINDOWS_SPECIFIED = 0x2c02,
+ SKC_OVERWRITE_ERROR_ON_UPDATE_IN_PLACE = 0x2d00,
+ SKC_COMMANDS_CLEARED_BY_ANOTHER_INITIATOR = 0x2f00,
+ SKC_INCOMPATIBLE_MEDIUM_INSTALLED = 0x3000,
+ SKC_CANNOT_READ_MEDIUM_UNKNOWN_FORMAT = 0x3001,
+ SKC_CANNOT_READ_MEDIUM_INCOMPATIBLE_FORMAT = 0x3002,
+ SKC_CLEANING_CARTRIDGE_INSTALLED = 0x3003,
+ SKC_CANNOT_WRITE_MEDIUM_UNKNOWN_FORMAT = 0x3004,
+ SKC_CANNOT_WRITE_MEDIUM_INCOMPATIBLE_FORMAT = 0x3005,
+ SKC_CANNOT_FORMAT_MEDIUM_INCOMPATIBLE_MEDIUM = 0x3006,
+ SKC_CLEANING_FAILURE = 0x3007,
+ SKC_MEDIUM_FORMAT_CORRUPTED = 0x3100,
+ SKC_FORMAT_COMMAND_FAILED = 0x3101,
+ SKC_NO_DEFECT_SPARE_LOCATION_AVAILABLE = 0x3200,
+ SKC_DEFECT_LIST_UPDATE_FAILURE = 0x3201,
+ SKC_TAPE_LENGTH_ERROR = 0x3300,
+ SKC_RIBBON_INK_OR_TONER_FAILURE = 0x3600,
+ SKC_ROUNDED_PARAMETER = 0x3700,
+ SKC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x3900,
+ SKC_MEDIUM_NOT_PRESENT = 0x3a00,
+ SKC_SEQUENTIAL_POSITIONING_ERROR = 0x3b00,
+ SKC_TAPE_POSITION_ERROR_AT_BEGINNING_OF_MEDIUM = 0x3b01,
+ SKC_TAPE_POSITION_ERROR_AT_END_OF_MEDIUM = 0x3b02,
+ SKC_TAPE_OR_ELECTRONIC_VERTICAL_FORMS_UNIT_NOT_READY = 0x3b03,
+ SKC_SLEW_FAILURE = 0x3b04,
+ SKC_PAPER_JAM = 0x3b05,
+ SKC_FAILED_TO_SENSE_TOP_OF_FORM = 0x3b06,
+ SKC_FAILED_TO_SENSE_BOTTOM_OF_FORM = 0x3b07,
+ SKC_REPOSITION_ERROR = 0x3b08,
+ SKC_READ_PAST_END_OF_MEDIUM = 0x3b09,
+ SKC_READ_PAST_BEGINNING_OF_MEDIUM = 0x3b0a,
+ SKC_POSITION_PAST_END_OF_MEDIUM = 0x3b0b,
+ SKC_POSITION_PAST_BEGINNING_OF_MEDIUM = 0x3b0c,
+ SKC_MEDIUM_DESTINATION_ELEMENT_FULL = 0x3b0d,
+ SKC_MEDIUM_SOURCE_ELEMENT_EMPTY = 0x3b0e,
+ SKC_MEDIUM_MAGAZINE_NOT_ACCESSIBLE = 0x3b11,
+ SKC_MEDIUM_MAGAZINE_REMOVED = 0x3b12,
+ SKC_MEDIUM_MAGAZINE_INSERTED = 0x3b13,
+ SKC_MEDIUM_MAGAZINE_LOCKED = 0x3b14,
+ SKC_MEDIUM_MAGAZINE_UNLOCKED = 0x3b15,
+ SKC_INVALID_BITS_IN_IDENTIFY_MESSAGE = 0x3d00,
+ SKC_LOGICAL_UNIT_HAS_NOT_SELF_CONFIGURED_YET = 0x3e00,
+ SKC_TARGET_OPERATING_CONDITIONS_HAVE_CHANGED = 0x3f00,
+ SKC_MICROCODE_HAS_BEEN_CHANGED = 0x3f01,
+ SKC_CHANGED_OPERATING_DEFINITION = 0x3f02,
+ SKC_INQUIRY_DATA_HAS_CHANGED = 0x3f03,
+ SKC_RAM_FAILURE = 0x4000, // "should use 0x40nn"
+ SKC_DIAGNOSTIC_FAILURE_ON_COMPONENT_NN = 0x4000, // LSB is nn (0x80-0xff)
+ SKC_DATA_PATH_FAILURE = 0x4100, // "should use 0x40nn"
+ SKC_POWER_ON_OR_SELF_TEST_FAILURE = 0x4200, // "should use 0x40nn"
+ SKC_MESSAGE_ERROR = 0x4300,
+ SKC_INTERNAL_TARGET_FAILURE = 0x4400,
+ SKC_SELECT_OR_RESELECT_FAILURE = 0x4500,
+ SKC_UNSUCCESSFUL_SOFT_RESET = 0x4600,
+ SKC_SCSI_PARITY_ERROR = 0x4700,
+ SKC_INITIATOR_DETECTED_ERROR_MESSAGE_RECEIVED = 0x4800,
+ SKC_INVALID_MESSAGE_ERROR = 0x4900,
+ SKC_COMMAND_PHASE_ERROR = 0x4a00,
+ SKC_DATA_PHASE_ERROR = 0x4b00,
+ SKC_LOGICAL_UNIT_FAILED_SELF_CONFIGURATION = 0x4c00,
+ SKC_TAGGED_OVERLAPPED_COMMANDS_NN = 0x4d00, // "queue tag"; LSB is nn
+ SKC_OVERLAPPED_COMMANDS_ATTEMPTED = 0x4e00,
+ SKC_WRITE_APPEND_ERROR = 0x5000,
+ SKC_WRITE_APPEND_POSITION_ERROR = 0x5001,
+ SKC_POSITION_ERROR_RELATED_TO_TIMING = 0x5002,
+ SKC_ERASE_FAILURE = 0x5100,
+ SKC_CARTRIDGE_FAULT = 0x5200,
+ SKC_MEDIA_LOAD_OR_EJECT_FAILED = 0x5300,
+ SKC_UNLOAD_TAPE_FAILURE = 0x5301,
+ SKC_MEDIUM_REMOVAL_PREVENTED = 0x5302,
+ SKC_SCSI_TO_HOST_SYSTEM_INTERFACE_FAILURE = 0x5400,
+ SKC_SYSTEM_RESOURCE_FAILURE = 0x5500,
+ SKC_SYSTEM_BUFFER_FULL = 0x5501,
+ SKC_UNABLE_TO_RECOVER_TABLE_OF_CONTENTS = 0x5700,
+ SKC_GENERATION_DOES_NOT_EXIST = 0x5800,
+ SKC_UPDATED_BLOCK_READ = 0x5900,
+ SKC_OPERATOR_REQUEST_OR_STATE_CHANGE_INPUT = 0x5a00, // "unspecified"
+ SKC_OPERATOR_MEDIUM_REMOVAL_REQUEST = 0x5a01,
+ SKC_OPERATOR_SELECTED_WRITE_PROTECT = 0x5a02,
+ SKC_OPERATOR_SELECTED_WRITE_PERMIT = 0x5a03,
+ SKC_LOG_EXCEPTION = 0x5b00,
+ SKC_THRESHOLD_CONDITION_MET = 0x5b01,
+ SKC_LOG_COUNTER_AT_MAXIMUM = 0x5b02,
+ SKC_LOG_LIST_CODES_EXHAUSTED = 0x5b03,
+ SKC_RPL_STATUS_CHANGE = 0x5c00,
+ SKC_SPINDLES_SYNCHRONIZED = 0x5c01,
+ SKC_SPINDLES_NOT_SYNCHRONIZED = 0x5c02,
+ SKC_FAILURE_PREDICTION_THRESHOLD_EXCEEDED = 0x5d00,
+ SKC_FAILURE_PREDICTION_THRESHOLD_EXCEEDED_FALSE = 0x5dff, // what?!
+ SKC_LOW_POWER_CONDITION_ON = 0x5e00,
+ SKC_IDLE_CONDITION_ACTIVATED_BY_TIMER = 0x5e01,
+ SKC_STANDBY_CONDITION_ACTIVATED_BY_TIMER = 0x5e02,
+ SKC_IDLE_CONDITION_ACTIVATED_BY_COMMAND = 0x5e03,
+ SKC_STANDBY_CONDITION_ACTIVATED_BY_COMMAND = 0x5e04,
+ SKC_LAMP_FAILURE = 0x6000,
+ SKC_VIDEO_ACQUISITION_ERROR = 0x6100,
+ SKC_UNABLE_TO_ACQUIRE_VIDEO = 0x6101,
+ SKC_OUT_OF_FOCUS = 0x6102,
+ SKC_SCAN_HEAD_POSITIONING_ERROR = 0x6200,
+ SKC_END_OF_USER_AREA_ENCOUNTERED_ON_THIS_TRACK = 0x6300,
+ SKC_ILLEGAL_MODE_FOR_THIS_TRACK = 0x6400,
+ SKC_VOLTAGE_FAULT = 0x6500,
+ SKC_DECOMPRESSION_EXCEPTION_SHORT_ALGORITHM_ID_OF_NN = 0x7000, // LSB is nn
+ SKC_DECOMPRESSION_EXCEPTION_LONG_ALGORITHM_ID = 0x7100
+ };
+
// SCSI addtional sense code qualifiers
enum {
SK_ASC_INVALID_FIELD_IN_CDB = 0x24,
@@ -190,47 +488,80 @@ protected:
static const char *const command_names[256];
enum {
SC_TEST_UNIT_READY = 0x00,
- SC_REZERO = 0x01,
+ SC_REWIND = 0x01,
+ SC_REZERO_UNIT = 0x01,
+ SC_REQUEST_BLOCK_ADDRESS = 0x02,
SC_REQUEST_SENSE = 0x03,
+ SC_FORMAT = 0x04,
SC_FORMAT_UNIT = 0x04,
+ SC_READ_BLOCK_LIMITS = 0x05,
+ SC_INITIALIZE_ELEMENT_STATUS = 0x07,
SC_REASSIGN_BLOCKS = 0x07,
+ SC_GET_MESSAGE_6 = 0x08,
SC_READ_6 = 0x08,
- SC_RECIEVE = 0x08,
+ SC_RECEIVE = 0x08,
+ SC_PRINT = 0x0a,
+ SC_SEND_MESSAGE_6 = 0x0a,
+ SC_SEND_6 = 0x0a,
SC_WRITE_6 = 0x0a,
- SC_SEND = 0x0a,
- SC_SEEK = 0x0b,
+ SC_SEEK_6 = 0x0b,
+ SC_SLEW_AND_PRINT = 0x0b,
+ SC_SEEK_BLOCK = 0x0c,
+ SC_READ_REVERSE = 0x0f,
+ SC_SYNCHRONIZE_BUFFER = 0x10,
+ SC_WRITE_FILEMARKS = 0x10,
+ SC_SPACE = 0x11,
SC_INQUIRY = 0x12,
+ SC_VERIFY_6 = 0x13,
+ SC_RECOVER_BUFFERED_DATA = 0x14,
SC_MODE_SELECT_6 = 0x15,
SC_RESERVE_6 = 0x16,
+ SC_RESERVE_UNIT = 0x16,
SC_RELEASE_6 = 0x17,
+ SC_RELEASE_UNIT = 0x17,
+ SC_COPY = 0x18,
+ SC_ERASE = 0x19,
SC_MODE_SENSE_6 = 0x1a,
+ SC_LOAD_UNLOAD = 0x1b,
+ SC_SCAN = 0x1b,
+ SC_STOP_PRINT = 0x1b,
SC_START_STOP_UNIT = 0x1b,
- SC_RECIEVE_DIAG_RES = 0x1c,
- SC_SEND_DIAGNOSTICS = 0x1d,
+ SC_RECEIVE_DIAGNOSTIC_RESULTS = 0x1c,
+ SC_SEND_DIAGNOSTIC = 0x1d,
SC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e,
SC_READ_FORMAT_CAPACITIES = 0x23,
+ SC_SET_WINDOW = 0x24,
+ SC_GET_WINDOW = 0x25,
SC_READ_CAPACITY = 0x25,
+ SC_READ_CD_RECORDED_CAPACITY = 0x25,
+ SC_GET_MESSAGE_10 = 0x28,
SC_READ_10 = 0x28,
SC_READ_GENERATION = 0x29,
+ SC_SEND_MESSAGE_10 = 0x2a,
+ SC_SEND_10 = 0x2a,
SC_WRITE_10 = 0x2a,
+ SC_LOCATE = 0x2b,
+ SC_POSITION_TO_ELEMENT = 0x2b,
SC_SEEK_10 = 0x2b,
SC_ERASE_10 = 0x2c,
- SC_READ_UPDATED_BLOCK_10 = 0x2d,
- SC_WRITE_VERIFY = 0x2e,
- SC_VERIFY = 0x2f,
+ SC_READ_UPDATED_BLOCK = 0x2d,
+ SC_WRITE_AND_VERIFY_10 = 0x2e,
+ SC_VERIFY_10 = 0x2f,
SC_SEARCH_DATA_HIGH_10 = 0x30,
+ SC_OBJECT_POSITION = 0x31,
SC_SEARCH_DATA_EQUAL_10 = 0x31,
SC_SEARCH_DATA_LOW_10 = 0x32,
SC_SET_LIMITS_10 = 0x33,
SC_PREFETCH = 0x34,
- SC_SYNC_CACHE = 0x35,
+ SC_READ_POSITION = 0x34,
+ SC_SYNCHRONIZE_CACHE = 0x35,
SC_LOCK_UNLOCK_CACHE = 0x36,
- SC_READ_DEFECT_DATA = 0x37,
+ SC_READ_DEFECT_DATA_10 = 0x37,
SC_MEDIUM_SCAN = 0x38,
SC_COMPARE = 0x39,
SC_COPY_AND_VERIFY = 0x3a,
SC_WRITE_BUFFER = 0x3b,
- SC_READ_DATA_BUFFER = 0x3c,
+ SC_READ_BUFFER = 0x3c,
SC_UPDATE_BLOCK = 0x3d,
SC_READ_LONG = 0x3e,
SC_WRITE_LONG = 0x3f,
@@ -243,7 +574,7 @@ protected:
SC_GET_CONFIGURATION = 0x46,
SC_PLAY_AUDIO_MSF = 0x47,
SC_PLAY_AUDIO_TRACK_INDEX = 0x48,
- SC_PLAY_RELATIVE_10 = 0x49,
+ SC_PLAY_TRACK_RELATIVE_10 = 0x49,
SC_GET_EVENT_STATUS_NOTIFICATION = 0x4a,
SC_PAUSE_RESUME = 0x4b,
SC_LOG_SELECT = 0x4c,
@@ -316,18 +647,63 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void scsi_message();
virtual void scsi_command();
virtual bool scsi_command_done(uint8_t command, uint8_t length);
+ TIMER_CALLBACK_MEMBER(update_tick);
+
+ void handle_request_sense(const u8 lun);
void scsi_unknown_command();
void scsi_status_complete(uint8_t st);
void scsi_data_in(int buf, int size);
void scsi_data_out(int buf, int size);
+ struct sense_data {
+ sense_data()
+ {
+ invalid = false;
+ deferred = false;
+ filemark = false;
+ eom = false;
+ bad_len = false;
+ sense_key = 0;
+ info = 0;
+ sense_key_code = 0;
+ }
+
+ bool invalid;
+ bool deferred;
+ bool filemark;
+ bool eom;
+ bool bad_len;
+ u8 sense_key;
+ s32 info;
+ u16 sense_key_code;
+ };
+ void set_sense_data(const u8 sense_key, const u16 sense_key_code, const sense_data *data = nullptr);
void sense(bool deferred, uint8_t key, uint8_t asc = 0, uint8_t ascq = 0);
+ void report_condition(const u8 sense_key, const u16 sense_key_code, const sense_data *data = nullptr);
+ void report_bad_lun(const u8 cmd, const u8 lun);
+ void report_bad_cmd(const u8 cmd);
+ void report_filemark(const s32 info = 0, const bool eom = false);
+ void report_bom(const s32 info = 0);
+ void report_ew(const s32 info = 0);
+ void report_eod(const s32 info = 0, const bool eom = false);
+ void report_eom(const bool write, const s32 info = 0, const bool invalid = false);
+ void report_bad_len(const bool over, const s32 info = 0);
+ void report_bad_cdb_field();
+ void report_bad_pl_field();
+ void report_bad_pl_len();
+ void report_no_saving_params();
+ void report_no_medium();
+ void report_medium_changed();
+ void report_read_only();
+ void report_read_failure();
+ void report_write_failure();
+ void report_erase_failure();
+
int get_lun(int def = 0);
void bad_lun();
@@ -396,7 +772,14 @@ protected:
// Fast negation period (30ns)
virtual attotime scsi_fast_negation_period();
- uint8_t scsi_cmdbuf[4096], scsi_sense_buffer[18];
+ // Byte transfer rate (immediate)
+ virtual attotime scsi_data_byte_period();
+
+ // Command delay (immediate)
+ virtual attotime scsi_data_command_delay();
+
+ uint8_t scsi_cmdbuf[4096];
+ uint8_t scsi_sense_buffer[18];
int scsi_cmdsize;
uint8_t scsi_identify;
diff --git a/src/devices/machine/nscsi_cb.cpp b/src/devices/machine/nscsi_cb.cpp
index 5d42caf8265..b4d80bed9f6 100644
--- a/src/devices/machine/nscsi_cb.cpp
+++ b/src/devices/machine/nscsi_cb.cpp
@@ -5,34 +5,23 @@
DEFINE_DEVICE_TYPE(NSCSI_CB, nscsi_callback_device, "nscsi_cb", "SCSI callback (new)")
-nscsi_callback_device::nscsi_callback_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nscsi_device(mconfig, NSCSI_CB, tag, owner, clock),
- nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF),
- m_write_rst(*this),
- m_write_atn(*this),
- m_write_ack(*this),
- m_write_req(*this),
- m_write_msg(*this),
- m_write_io(*this),
- m_write_cd(*this),
- m_write_sel(*this),
- m_write_bsy(*this), m_ctrl(0)
+nscsi_callback_device::nscsi_callback_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ nscsi_device(mconfig, NSCSI_CB, tag, owner, clock),
+ nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF),
+ m_write_rst(*this),
+ m_write_atn(*this),
+ m_write_ack(*this),
+ m_write_req(*this),
+ m_write_msg(*this),
+ m_write_io(*this),
+ m_write_cd(*this),
+ m_write_sel(*this),
+ m_write_bsy(*this), m_ctrl(0)
{
}
void nscsi_callback_device::device_start()
{
- // resolve callbacks
- m_write_rst.resolve_safe();
- m_write_atn.resolve_safe();
- m_write_ack.resolve_safe();
- m_write_req.resolve_safe();
- m_write_msg.resolve_safe();
- m_write_io.resolve_safe();
- m_write_cd.resolve_safe();
- m_write_sel.resolve_safe();
- m_write_bsy.resolve_safe();
-
// state saving
save_item(NAME(m_ctrl));
}
diff --git a/src/devices/machine/nvram.cpp b/src/devices/machine/nvram.cpp
index e00d10447a8..3a6f24c593c 100644
--- a/src/devices/machine/nvram.cpp
+++ b/src/devices/machine/nvram.cpp
@@ -2,14 +2,14 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- nvram.c
+ nvram.cpp
Generic non-volatile RAM.
***************************************************************************/
#include "emu.h"
-#include "machine/nvram.h"
+#include "nvram.h"
//**************************************************************************
// LIVE DEVICE
@@ -22,14 +22,14 @@ DEFINE_DEVICE_TYPE(NVRAM, nvram_device, "nvram", "NVRAM")
// nvram_device - constructor
//-------------------------------------------------
-nvram_device::nvram_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, NVRAM, tag, owner, clock),
- device_nvram_interface(mconfig, *this),
- m_region(*this, DEVICE_SELF),
- m_default_value(DEFAULT_ALL_1),
- m_custom_handler(*this),
- m_base(nullptr),
- m_length(0)
+nvram_device::nvram_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, NVRAM, tag, owner, clock),
+ device_nvram_interface(mconfig, *this),
+ m_region(*this, DEVICE_SELF),
+ m_default_value(DEFAULT_ALL_1),
+ m_custom_handler(*this),
+ m_base(nullptr),
+ m_length(0)
{
}
@@ -78,12 +78,12 @@ void nvram_device::nvram_default()
// random values
case DEFAULT_RANDOM:
- {
- uint8_t *nvram = reinterpret_cast<uint8_t *>(m_base);
- for (int index = 0; index < m_length; index++)
- nvram[index] = machine().rand();
+ {
+ uint8_t *nvram = reinterpret_cast<uint8_t *>(m_base);
+ for (int index = 0; index < m_length; index++)
+ nvram[index] = machine().rand();
+ }
break;
- }
// custom handler
case DEFAULT_CUSTOM:
@@ -102,12 +102,14 @@ void nvram_device::nvram_default()
// .nv file
//-------------------------------------------------
-void nvram_device::nvram_read(emu_file &file)
+bool nvram_device::nvram_read(util::read_stream &file)
{
// make sure we have a valid base pointer
determine_final_base();
- file.read(m_base, m_length);
+ // FIXME: consider width/Endianness
+ auto const [err, actual] = read(file, m_base, m_length);
+ return !err && (actual == m_length);
}
@@ -116,9 +118,11 @@ void nvram_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void nvram_device::nvram_write(emu_file &file)
+bool nvram_device::nvram_write(util::write_stream &file)
{
- file.write(m_base, m_length);
+ // FIXME: consider width/Endianness
+ auto const [err, actual] = write(file, m_base, m_length);
+ return !err;
}
@@ -131,10 +135,10 @@ void nvram_device::nvram_write(emu_file &file)
void nvram_device::determine_final_base()
{
// find our shared pointer with the target RAM
- if (m_base == nullptr)
+ if (!m_base)
{
- memory_share *share = owner()->memshare(tag());
- if (share == nullptr)
+ memory_share *const share = owner()->memshare(tag());
+ if (!share)
throw emu_fatalerror("NVRAM device '%s' has no corresponding share() region", tag());
m_base = share->ptr();
m_length = share->bytes();
@@ -142,5 +146,5 @@ void nvram_device::determine_final_base()
// if we are region-backed for the default, find it now and make sure it's the right size
if (m_region.found() && m_region->bytes() != m_length)
- throw emu_fatalerror("%s",string_format("NVRAM device '%s' has a default region, but it should be 0x%X bytes", tag(), m_length).c_str());
+ throw emu_fatalerror("%s",string_format("NVRAM device '%s' has a default region, but it should be 0x%X bytes", tag(), m_length));
}
diff --git a/src/devices/machine/nvram.h b/src/devices/machine/nvram.h
index f497a02976e..92bc81f64bb 100644
--- a/src/devices/machine/nvram.h
+++ b/src/devices/machine/nvram.h
@@ -55,21 +55,20 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
- virtual bool nvram_can_write() override { return m_base && m_length; }
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
// internal helpers
void determine_final_base();
// configuration state
- optional_memory_region m_region;
- default_value m_default_value;
- init_delegate m_custom_handler;
+ optional_memory_region m_region;
+ default_value m_default_value;
+ init_delegate m_custom_handler;
// runtime state
- void * m_base;
- size_t m_length;
+ void * m_base;
+ size_t m_length;
};
DECLARE_DEVICE_TYPE(NVRAM, nvram_device)
diff --git a/src/devices/machine/output_latch.cpp b/src/devices/machine/output_latch.cpp
index 7ed407d68f8..bc8dcb8ea09 100644
--- a/src/devices/machine/output_latch.cpp
+++ b/src/devices/machine/output_latch.cpp
@@ -12,11 +12,6 @@ output_latch_device::output_latch_device(const machine_config &mconfig, const ch
{
}
-void output_latch_device::device_resolve_objects()
-{
- m_bit_handlers.resolve_all_safe();
-}
-
void output_latch_device::device_start()
{
save_item(NAME(m_bits));
@@ -30,8 +25,7 @@ void output_latch_device::write(uint8_t data)
if (bit != m_bits[i])
{
m_bits[i] = bit;
- if (!m_bit_handlers[i].isnull())
- m_bit_handlers[i](bit);
+ m_bit_handlers[i](bit);
}
}
}
diff --git a/src/devices/machine/output_latch.h b/src/devices/machine/output_latch.h
index 0e6a87ff6dc..c807e79f3e4 100644
--- a/src/devices/machine/output_latch.h
+++ b/src/devices/machine/output_latch.h
@@ -16,7 +16,6 @@ public:
void write(uint8_t data);
protected:
- virtual void device_resolve_objects() override;
virtual void device_start() override;
private:
diff --git a/src/devices/machine/pc87306.cpp b/src/devices/machine/pc87306.cpp
new file mode 100644
index 00000000000..8bc2deb00b0
--- /dev/null
+++ b/src/devices/machine/pc87306.cpp
@@ -0,0 +1,491 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+National Semiconductor PC87306 Super I/O
+
+TODO:
+- Barely enough to make it surpass POST test 0x05 in misc/odyssey.cpp;
+- COM1/COM2/LPT1 address and irq select;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "pc87306.h"
+
+//#include "machine/ds128x.h"
+#include "machine/pckeybrd.h"
+
+#define LOG_WARN (1U << 1) // Show warnings
+
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(PC87306, pc87306_device, "pc87306", "National Semiconductor PC87306 Super I/O Enhanced Sidewinder Lite")
+
+pc87306_device::pc87306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PC87306, tag, owner, clock)
+ , device_isa16_card_interface(mconfig, *this)
+ , device_memory_interface(mconfig, *this)
+ , m_space_config("superio_config_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(pc87306_device::config_map), this))
+ , m_kbdc(*this, "pc_kbdc")
+ , m_rtc(*this, "rtc")
+ , m_pc_com(*this, "uart%d", 0U)
+ , m_pc_lpt(*this, "lpta")
+ , m_gp20_reset_callback(*this)
+ , m_gp25_gatea20_callback(*this)
+ , m_irq1_callback(*this)
+ , m_irq8_callback(*this)
+ , m_irq9_callback(*this)
+ , m_txd1_callback(*this)
+ , m_ndtr1_callback(*this)
+ , m_nrts1_callback(*this)
+ , m_txd2_callback(*this)
+ , m_ndtr2_callback(*this)
+ , m_nrts2_callback(*this)
+{ }
+
+
+void pc87306_device::device_start()
+{
+ set_isa_device();
+ //m_isa->set_dma_channel(0, this, true);
+ //m_isa->set_dma_channel(1, this, true);
+ //m_isa->set_dma_channel(2, this, true);
+ //m_isa->set_dma_channel(3, this, true);
+ // TODO: CFG0 (RTC) + MR (KBD)
+ m_krr = 8 | 1;
+ remap(AS_IO, 0, 0x400);
+}
+
+void pc87306_device::device_reset()
+{
+ m_locked_state = 2;
+}
+
+device_memory_interface::space_config_vector pc87306_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+void pc87306_device::device_add_mconfig(machine_config &config)
+{
+ // TODO: can bank thru bit 5 of KRR
+ DS12885(config, m_rtc, 32.768_kHz_XTAL);
+// m_rtc->irq().set(FUNC(pc87306_device::irq_rtc_w));
+ m_rtc->set_century_index(0x32);
+
+ KBDC8042(config, m_kbdc);
+ m_kbdc->set_keyboard_type(kbdc8042_device::KBDC8042_PS2);
+ m_kbdc->set_interrupt_type(kbdc8042_device::KBDC8042_DOUBLE);
+ m_kbdc->input_buffer_full_callback().set(FUNC(pc87306_device::irq_keyboard_w));
+ m_kbdc->input_buffer_full_mouse_callback().set(FUNC(pc87306_device::irq_mouse_w));
+ m_kbdc->system_reset_callback().set(FUNC(pc87306_device::kbdp20_gp20_reset_w));
+ m_kbdc->gate_a20_callback().set(FUNC(pc87306_device::kbdp21_gp25_gatea20_w));
+ m_kbdc->set_keyboard_tag("at_keyboard");
+
+ at_keyboard_device &at_keyb(AT_KEYB(config, "at_keyboard", pc_keyboard_device::KEYBOARD_TYPE::AT, 1));
+ at_keyb.keypress().set(m_kbdc, FUNC(kbdc8042_device::keyboard_w));
+
+ PC_LPT(config, m_pc_lpt);
+ m_pc_lpt->irq_handler().set(FUNC(pc87306_device::irq_parallel_w));
+
+ NS16550(config, m_pc_com[0], XTAL(1'843'200));
+ m_pc_com[0]->out_int_callback().set(FUNC(pc87306_device::irq_serial1_w));
+ m_pc_com[0]->out_tx_callback().set(FUNC(pc87306_device::txd_serial1_w));
+ m_pc_com[0]->out_dtr_callback().set(FUNC(pc87306_device::dtr_serial1_w));
+ m_pc_com[0]->out_rts_callback().set(FUNC(pc87306_device::rts_serial1_w));
+
+ NS16550(config, m_pc_com[1], XTAL(1'843'200));
+ m_pc_com[1]->out_int_callback().set(FUNC(pc87306_device::irq_serial2_w));
+ m_pc_com[1]->out_tx_callback().set(FUNC(pc87306_device::txd_serial2_w));
+ m_pc_com[1]->out_dtr_callback().set(FUNC(pc87306_device::dtr_serial2_w));
+ m_pc_com[1]->out_rts_callback().set(FUNC(pc87306_device::rts_serial2_w));
+}
+
+void pc87306_device::remap(int space_id, offs_t start, offs_t end)
+{
+ if (space_id == AS_IO)
+ {
+ // TODO: BADDR1/0 config pin controlled
+ u16 superio_base = 0x0398;
+ m_isa->install_device(superio_base, superio_base + 1, read8sm_delegate(*this, FUNC(pc87306_device::read)), write8sm_delegate(*this, FUNC(pc87306_device::write)));
+
+ if (BIT(m_krr, 0))
+ {
+ m_isa->install_device(0x60, 0x60, read8sm_delegate(*m_kbdc, FUNC(kbdc8042_device::data_r)), write8sm_delegate(*m_kbdc, FUNC(kbdc8042_device::data_w)));
+ m_isa->install_device(0x64, 0x64, read8sm_delegate(*this, FUNC(pc87306_device::keybc_status_r)), write8sm_delegate(*this, FUNC(pc87306_device::keybc_command_w)));
+ }
+
+ if (BIT(m_krr, 3))
+ m_isa->install_device(0x70, 0x71, read8sm_delegate(*this, FUNC(pc87306_device::rtc_r)), write8sm_delegate(*this, FUNC(pc87306_device::rtc_w)));
+
+ if (BIT(m_fer, 0))
+ m_isa->install_device(0x378, 0x37f, read8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::read)), write8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::write)));
+
+ if (BIT(m_fer, 1))
+ m_isa->install_device(0x3f8, 0x3ff, read8sm_delegate(*m_pc_com[0], FUNC(ns16450_device::ins8250_r)), write8sm_delegate(*m_pc_com[0], FUNC(ns16450_device::ins8250_w)));
+
+ if (BIT(m_fer, 2))
+ m_isa->install_device(0x2f8, 0x2ff, read8sm_delegate(*m_pc_com[1], FUNC(ns16450_device::ins8250_r)), write8sm_delegate(*m_pc_com[1], FUNC(ns16450_device::ins8250_w)));
+
+ }
+}
+
+u8 pc87306_device::read(offs_t offset)
+{
+ if (m_locked_state)
+ {
+ if (!machine().side_effects_disabled())
+ m_locked_state --;
+ return (m_locked_state) ? 0x88 : 0x00;
+ }
+
+ if (offset == 0)
+ return m_index;
+
+ return space().read_byte(m_index);
+}
+
+void pc87306_device::write(offs_t offset, u8 data)
+{
+ if (offset == 0)
+ {
+ m_index = data;
+ }
+ else
+ {
+ // TODO: two writes, first one just unlocks?
+ space().write_byte(m_index, data);
+ }
+}
+
+void pc87306_device::config_map(address_map &map)
+{
+ map(0x00, 0x00).rw(FUNC(pc87306_device::fer_r), FUNC(pc87306_device::fer_w));
+ map(0x01, 0x01).rw(FUNC(pc87306_device::far_r), FUNC(pc87306_device::far_w));
+// map(0x02, 0x02) PTR Power and Test Register
+// map(0x03, 0x03) FCR Function Control Register
+// map(0x04, 0x04) PCR Printer Control Register
+ map(0x05, 0x05).rw(FUNC(pc87306_device::krr_r), FUNC(pc87306_device::krr_w));
+// map(0x06, 0x06) PMC Power Management Control Register
+// map(0x07, 0x07) TUP Tape, UART and Parallel Port Configuration Register
+ // SID Super I/O Identification Register
+ // bits 7-3 -> 01110 TL/C/12379-27
+ // bits 2-0 -> <undefined>
+ map(0x08, 0x08).lr8(
+ NAME([] (offs_t offset) { return 0x70; })
+ );
+// map(0x09, 0x09) ASC Advanced Super I/O Configuration Register
+// map(0x0a, 0x0a) CS0LA Chip Select 0 Low Address
+// map(0x0b, 0x0b) CS0CF Chip Select 0 Configuration Address
+// map(0x0c, 0x0c) CS1LA Chip Select 1 Low Address
+// map(0x0d, 0x0d) CS1CF Chip Select 1 Configuration Address
+// map(0x0e, 0x0e) IRC InfraRed Configuration Register
+// map(0x0f, 0x0f) GPBA General Purpose I/O Port Base Address
+// map(0x10, 0x10) CS0HA Chip Select 0 High Address
+// map(0x11, 0x11) CS1HA Chip Select 1 High Address
+// map(0x12, 0x12) SCF0 Super I/O Configuration Register 0
+// map(0x18, 0x18) SCF1 Super I/O Configuration Register 1
+// map(0x19, 0x19) LPTBA LPT Base Address
+
+// map(0x1b, 0x1b) PNP0 Plug and Play Configuration 0 Register
+// map(0x1c, 0x1c) PNP1 Plug and Play Configuration 1 Register
+}
+
+/*
+ * [0x00] FER Function Enable Register
+ * x--- ---- IDE address select
+ * -x-- ---- IDE i/f enable
+ * --x- ---- FDC address select
+ * ---x ---- (0) x2 floppy drives (1) x4 floppy drives
+ * ---- x--- FDC enable
+ * ---- -x-- UART2 enable
+ * ---- --x- UART1 enable
+ * ---- ---x Parallel Port enable
+ */
+u8 pc87306_device::fer_r(offs_t offset)
+{
+ return m_fer;
+}
+
+void pc87306_device::fer_w(offs_t offset, u8 data)
+{
+ m_fer = data;
+ remap(AS_IO, 0, 0x400);
+}
+
+/*
+ * [0x01] FAR Function Address Register
+ * xxxx ---- UART2 address select
+ * xx-- xx-- UART1 address select
+ * ---- --xx parallel address select
+ */
+u8 pc87306_device::far_r(offs_t offset)
+{
+ return m_far;
+}
+
+void pc87306_device::far_w(offs_t offset, u8 data)
+{
+ m_far = data;
+ remap(AS_IO, 0, 0x400);
+}
+
+
+/*
+ * [0x05] KRR KBC and RTC Control Register
+ *
+ * x--- ---- KBC clock source select (0) X1 clock (1) SYSCLK
+ * --x- ---- RAMSREL RTC bank select
+ * ---- x--- RTC enable bit
+ * ---- -1-- <unknown> must be 1 for KBC to work
+ * ---- --x- KBC speed control (0) X1 / 3 (1) X1 / 2, ignored when SYSCLK selected
+ * ---- ---x KBC Enable bit
+ *
+ */
+u8 pc87306_device::krr_r(offs_t offset)
+{
+ return m_krr;
+}
+
+void pc87306_device::krr_w(offs_t offset, u8 data)
+{
+ m_krr = data;
+ LOG("krr %02x\n", data);
+ if (data & 0x20)
+ LOGWARN("RAMSREL active\n");
+ remap(AS_IO, 0, 0x400);
+}
+
+u8 pc87306_device::keybc_status_r(offs_t offset)
+{
+ return (m_kbdc->data_r(4) & 0xfb) | 0x10; // bios needs bit 2 to be 0 as powerup and bit 4 to be 1
+}
+
+void pc87306_device::keybc_command_w(offs_t offset, u8 data)
+{
+ m_kbdc->data_w(4, data);
+}
+
+u8 pc87306_device::rtc_r(offs_t offset)
+{
+ if (BIT(offset, 0))
+ return m_rtc->data_r(); // TODO: SCF0 bit 0 locks addresses 38 to 3F (FF is returned)
+ else
+ return m_rtc->get_address(); // datasheet doesn't clarify whether or not this is actually readable
+}
+
+void pc87306_device::rtc_w(offs_t offset, u8 data)
+{
+ if (BIT(offset, 0))
+ m_rtc->data_w(data); // TODO: SCF0 bit 0 locks addresses 38 to 3F
+ else
+ m_rtc->address_w(data);
+}
+
+/*
+ * KBC lines
+ */
+// Unlike other Super I/Os this doesn't seem to have irq line relocation
+
+void pc87306_device::kbdp21_gp25_gatea20_w(int state)
+{
+ if (!BIT(m_krr, 0))
+ return;
+ m_gp25_gatea20_callback(state);
+}
+
+void pc87306_device::kbdp20_gp20_reset_w(int state)
+{
+ if (!BIT(m_krr, 0))
+ return;
+ m_gp20_reset_callback(state);
+}
+
+void pc87306_device::irq_keyboard_w(int state)
+{
+ if (!BIT(m_krr, 0))
+ return;
+ request_irq(1, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void pc87306_device::irq_mouse_w(int state)
+{
+ if (!BIT(m_krr, 0))
+ return;
+ request_irq(12, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+/*
+ * Serial
+ */
+
+void pc87306_device::irq_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ request_irq(3, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void pc87306_device::irq_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ request_irq(4, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void pc87306_device::txd_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ m_txd1_callback(state);
+}
+
+void pc87306_device::txd_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ m_txd2_callback(state);
+}
+
+void pc87306_device::dtr_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ m_ndtr1_callback(state);
+}
+
+void pc87306_device::dtr_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ m_ndtr2_callback(state);
+}
+
+void pc87306_device::rts_serial1_w(int state)
+{
+ if (!(BIT(m_fer, 1)))
+ return;
+ m_nrts1_callback(state);
+}
+
+void pc87306_device::rts_serial2_w(int state)
+{
+ if (!(BIT(m_fer, 2)))
+ return;
+ m_nrts2_callback(state);
+}
+
+void pc87306_device::rxd1_w(int state)
+{
+ m_pc_com[0]->rx_w(state);
+}
+
+void pc87306_device::ndcd1_w(int state)
+{
+ m_pc_com[0]->dcd_w(state);
+}
+
+void pc87306_device::ndsr1_w(int state)
+{
+ m_pc_com[0]->dsr_w(state);
+}
+
+void pc87306_device::nri1_w(int state)
+{
+ m_pc_com[0]->ri_w(state);
+}
+
+void pc87306_device::ncts1_w(int state)
+{
+ m_pc_com[0]->cts_w(state);
+}
+
+void pc87306_device::rxd2_w(int state)
+{
+ m_pc_com[1]->rx_w(state);
+}
+
+void pc87306_device::ndcd2_w(int state)
+{
+ m_pc_com[1]->dcd_w(state);
+}
+
+void pc87306_device::ndsr2_w(int state)
+{
+ m_pc_com[1]->dsr_w(state);
+}
+
+void pc87306_device::nri2_w(int state)
+{
+ m_pc_com[1]->ri_w(state);
+}
+
+void pc87306_device::ncts2_w(int state)
+{
+ m_pc_com[1]->cts_w(state);
+}
+
+/*
+ * Parallel
+ */
+
+void pc87306_device::irq_parallel_w(int state)
+{
+ if (!(BIT(m_fer, 0)))
+ return;
+ request_irq(5, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+void pc87306_device::request_irq(int irq, int state)
+{
+ switch (irq)
+ {
+ case 1:
+ m_irq1_callback(state);
+ break;
+ case 3:
+ m_isa->irq3_w(state);
+ break;
+ case 4:
+ m_isa->irq4_w(state);
+ break;
+ case 5:
+ m_isa->irq5_w(state);
+ break;
+ case 6:
+ m_isa->irq6_w(state);
+ break;
+ case 7:
+ m_isa->irq7_w(state);
+ break;
+ case 8:
+ m_irq8_callback(state);
+ break;
+ case 9:
+ m_irq9_callback(state);
+ break;
+ case 10:
+ m_isa->irq10_w(state);
+ break;
+ case 11:
+ m_isa->irq11_w(state);
+ break;
+ case 12:
+ m_isa->irq12_w(state);
+ break;
+ case 14:
+ m_isa->irq14_w(state);
+ break;
+ case 15:
+ m_isa->irq15_w(state);
+ break;
+ }
+}
diff --git a/src/devices/machine/pc87306.h b/src/devices/machine/pc87306.h
new file mode 100644
index 00000000000..4b1256e1e52
--- /dev/null
+++ b/src/devices/machine/pc87306.h
@@ -0,0 +1,123 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_PC87306_H
+#define MAME_MACHINE_PC87306_H
+
+#pragma once
+
+#include "bus/isa/isa.h"
+#include "machine/8042kbdc.h"
+#include "machine/ds128x.h"
+#include "machine/ins8250.h"
+#include "machine/pc_lpt.h"
+
+class pc87306_device : public device_t,
+ public device_isa16_card_interface,
+ public device_memory_interface
+{
+public:
+ pc87306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~pc87306_device() {}
+
+ void remap(int space_id, offs_t start, offs_t end) override;
+
+ auto gp20_reset() { return m_gp20_reset_callback.bind(); }
+ auto gp25_gatea20() { return m_gp25_gatea20_callback.bind(); }
+ auto irq1() { return m_irq1_callback.bind(); }
+ auto irq8() { return m_irq8_callback.bind(); }
+ auto irq9() { return m_irq9_callback.bind(); }
+ auto txd1() { return m_txd1_callback.bind(); }
+ auto ndtr1() { return m_ndtr1_callback.bind(); }
+ auto nrts1() { return m_nrts1_callback.bind(); }
+ auto txd2() { return m_txd2_callback.bind(); }
+ auto ndtr2() { return m_ndtr2_callback.bind(); }
+ auto nrts2() { return m_nrts2_callback.bind(); }
+
+ void rxd1_w(int state);
+ void ndcd1_w(int state);
+ void ndsr1_w(int state);
+ void nri1_w(int state);
+ void ncts1_w(int state);
+ void rxd2_w(int state);
+ void ndcd2_w(int state);
+ void ndsr2_w(int state);
+ void nri2_w(int state);
+ void ncts2_w(int state);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual space_config_vector memory_space_config() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ const address_space_config m_space_config;
+
+ required_device<kbdc8042_device> m_kbdc;
+ required_device<ds12885_device> m_rtc;
+ required_device_array<ns16550_device, 2> m_pc_com;
+ required_device<pc_lpt_device> m_pc_lpt;
+
+ devcb_write_line m_gp20_reset_callback;
+ devcb_write_line m_gp25_gatea20_callback;
+ devcb_write_line m_irq1_callback;
+ devcb_write_line m_irq8_callback;
+ devcb_write_line m_irq9_callback;
+ devcb_write_line m_txd1_callback;
+ devcb_write_line m_ndtr1_callback;
+ devcb_write_line m_nrts1_callback;
+ devcb_write_line m_txd2_callback;
+ devcb_write_line m_ndtr2_callback;
+ devcb_write_line m_nrts2_callback;
+
+ void request_irq(int irq, int state);
+
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+ void config_map(address_map &map);
+
+ u8 far_r(offs_t offset);
+ void far_w(offs_t offset, u8 data);
+
+ u8 fer_r(offs_t offset);
+ void fer_w(offs_t offset, u8 data);
+
+ u8 keybc_status_r(offs_t offset);
+ void keybc_command_w(offs_t offset, u8 data);
+ u8 rtc_r(offs_t offset);
+ void rtc_w(offs_t offset, u8 data);
+
+ void kbdp21_gp25_gatea20_w(int state);
+ void kbdp20_gp20_reset_w(int state);
+
+ void irq_keyboard_w(int state);
+ void irq_mouse_w(int state);
+
+ u8 krr_r(offs_t offset);
+ void krr_w(offs_t offset, u8 data);
+
+ void irq_parallel_w(int state);
+
+ void irq_serial1_w(int state);
+ void txd_serial1_w(int state);
+ void dtr_serial1_w(int state);
+ void rts_serial1_w(int state);
+ void irq_serial2_w(int state);
+ void txd_serial2_w(int state);
+ void dtr_serial2_w(int state);
+ void rts_serial2_w(int state);
+
+ u8 m_index = 0;
+
+ u8 m_locked_state = 2;
+ u8 m_krr = 0;
+ u8 m_fer = 0;
+ u8 m_far = 0;
+};
+
+DECLARE_DEVICE_TYPE(PC87306, pc87306_device);
+
+#endif // MAME_MACHINE_PC87306_H
diff --git a/src/devices/machine/pc_fdc.cpp b/src/devices/machine/pc_fdc.cpp
index d1668f2381d..6c737f03364 100644
--- a/src/devices/machine/pc_fdc.cpp
+++ b/src/devices/machine/pc_fdc.cpp
@@ -14,10 +14,9 @@
**********************************************************************/
#include "emu.h"
-#include "machine/pc_fdc.h"
-#include "imagedev/floppy.h"
+#include "pc_fdc.h"
-//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already
+#include "imagedev/floppy.h"
//#define VERBOSE (LOG_GENERAL)
//#define LOG_OUTPUT_STREAM std::cout
@@ -69,9 +68,6 @@ void pc_fdc_family_device::device_add_mconfig(machine_config &config)
void pc_fdc_family_device::device_start()
{
- intrq_cb.resolve();
- drq_cb.resolve();
-
for(int i=0; i<4; i++) {
char name[2] = {static_cast<char>('0'+i), 0};
floppy_connector *conn = subdevice<floppy_connector>(name);
@@ -152,7 +148,7 @@ void pc_fdc_family_device::check_irq()
{
bool pirq = irq;
irq = fdc_irq && (dor & 4) && (dor & 8);
- if(irq != pirq && !intrq_cb.isnull()) {
+ if(irq != pirq) {
LOG("pc_irq = %d\n", irq);
intrq_cb(irq);
}
@@ -162,7 +158,7 @@ void pc_fdc_family_device::check_drq()
{
bool pdrq = drq;
drq = fdc_drq && (dor & 4) && (dor & 8);
- if(drq != pdrq && !drq_cb.isnull())
+ if(drq != pdrq)
drq_cb(drq);
}
diff --git a/src/devices/machine/pc_lpt.cpp b/src/devices/machine/pc_lpt.cpp
index 26d2357a72b..1c4b0349046 100644
--- a/src/devices/machine/pc_lpt.cpp
+++ b/src/devices/machine/pc_lpt.cpp
@@ -29,8 +29,6 @@ pc_lpt_device::pc_lpt_device(const machine_config &mconfig, const char *tag, dev
void pc_lpt_device::device_start()
{
- m_irq_handler.resolve_safe();
-
save_item(NAME(m_irq));
save_item(NAME(m_data));
save_item(NAME(m_control));
diff --git a/src/devices/machine/pccard.cpp b/src/devices/machine/pccard.cpp
index 83a05b99421..3171e85e68d 100644
--- a/src/devices/machine/pccard.cpp
+++ b/src/devices/machine/pccard.cpp
@@ -7,8 +7,9 @@
#include "logmacro.h"
-device_pccard_interface::device_pccard_interface(const machine_config &mconfig, device_t &device)
- : device_interface(device, "pccard")
+device_pccard_interface::device_pccard_interface(const machine_config &mconfig, device_t &device) :
+ device_interface(device, "pccard"),
+ m_slot(dynamic_cast<pccard_slot_device *>(device.owner()))
{
}
@@ -43,6 +44,10 @@ DEFINE_DEVICE_TYPE(PCCARD_SLOT, pccard_slot_device, "pccard", "PC Card Slot")
pccard_slot_device::pccard_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, PCCARD_SLOT, tag, owner, clock),
device_single_card_slot_interface<device_pccard_interface>(mconfig, *this),
+ m_card_detect_cb(*this),
+ m_battery_voltage_1_cb(*this),
+ m_battery_voltage_2_cb(*this),
+ m_write_protect_cb(*this),
m_pccard(nullptr)
{
}
@@ -52,11 +57,6 @@ void pccard_slot_device::device_start()
m_pccard = get_card_device();
}
-READ_LINE_MEMBER(pccard_slot_device::read_line_inserted)
-{
- return m_pccard ? 1 : 0;
-}
-
uint16_t pccard_slot_device::read_memory(offs_t offset, uint16_t mem_mask)
{
if (m_pccard)
@@ -84,3 +84,55 @@ void pccard_slot_device::write_reg(offs_t offset, uint16_t data, uint16_t mem_ma
if (m_pccard)
m_pccard->write_reg(offset, data, mem_mask);
}
+
+uint8_t pccard_slot_device::read_memory_byte(offs_t offset)
+{
+ uint8_t data = 0xff;
+
+ if (m_pccard)
+ {
+ if (BIT(offset, 0))
+ data = m_pccard->read_memory(offset / 2, 0xff00) >> 8;
+ else
+ data = m_pccard->read_memory(offset / 2, 0x00ff) >> 0;
+ }
+
+ return data;
+}
+
+uint8_t pccard_slot_device::read_reg_byte(offs_t offset)
+{
+ uint8_t data = 0xff;
+
+ if (m_pccard)
+ {
+ if (BIT(offset, 0))
+ data = m_pccard->read_reg(offset / 2, 0xff00) >> 8;
+ else
+ data = m_pccard->read_reg(offset / 2, 0x00ff) >> 0;
+ }
+
+ return data;
+}
+
+void pccard_slot_device::write_memory_byte(offs_t offset, uint8_t data)
+{
+ if (m_pccard)
+ {
+ if (BIT(offset, 0))
+ m_pccard->write_memory(offset / 2, data << 8, 0xff00);
+ else
+ m_pccard->write_memory(offset / 2, data << 0, 0x00ff);
+ }
+}
+
+void pccard_slot_device::write_reg_byte(offs_t offset, uint8_t data)
+{
+ if (m_pccard)
+ {
+ if (BIT(offset, 0))
+ m_pccard->write_reg(offset / 2, data << 8, 0xff00);
+ else
+ m_pccard->write_reg(offset / 2, data << 0, 0x00ff);
+ }
+}
diff --git a/src/devices/machine/pccard.h b/src/devices/machine/pccard.h
index 9e06018f005..be60e8465b6 100644
--- a/src/devices/machine/pccard.h
+++ b/src/devices/machine/pccard.h
@@ -5,6 +5,7 @@
#pragma once
+class pccard_slot_device;
class device_pccard_interface : public device_interface
{
@@ -18,6 +19,8 @@ public:
protected:
device_pccard_interface(const machine_config &mconfig, device_t &device);
+
+ pccard_slot_device *const m_slot;
};
DECLARE_DEVICE_TYPE(PCCARD_SLOT, pccard_slot_device)
@@ -36,16 +39,45 @@ public:
}
pccard_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_READ_LINE_MEMBER(read_line_inserted);
+ // callbacks
+ auto card_detect_cb() { return m_card_detect_cb.bind(); }
+ auto battery_voltage_1_cb() { return m_battery_voltage_1_cb.bind(); }
+ auto battery_voltage_2_cb() { return m_battery_voltage_2_cb.bind(); }
+ auto write_protect_cb() { return m_write_protect_cb.bind(); }
+
+ // called from card device
+ void card_detect_w(int state) { m_card_detect_cb(state); }
+ void battery_voltage_1_w(int state) { m_battery_voltage_1_cb(state); }
+ void battery_voltage_2_w(int state) { m_battery_voltage_2_cb(state); }
+ void write_protect_w(int state) { m_write_protect_cb(state); }
+
+ // 16-bit access
uint16_t read_memory(offs_t offset, uint16_t mem_mask = ~0);
uint16_t read_reg(offs_t offset, uint16_t mem_mask = ~0);
void write_memory(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void write_reg(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ // 16-bit access, even/odd swapped
+ uint16_t read_memory_swap(offs_t offset, uint16_t mem_mask = 0xffff) { return swapendian_int16(read_memory(offset, swapendian_int16(mem_mask))); }
+ uint16_t read_reg_swap(offs_t offset, uint16_t mem_mask = 0xffff) { return swapendian_int16(read_reg(offset, swapendian_int16(mem_mask))); }
+ void write_memory_swap(offs_t offset, uint16_t data, uint16_t mem_mask = 0xffff) { write_memory(offset, swapendian_int16(data), swapendian_int16(mem_mask)); }
+ void write_reg_swap(offs_t offset, uint16_t data, uint16_t mem_mask = 0xffff) { write_reg(offset, swapendian_int16(data), swapendian_int16(mem_mask)); }
+
+ // 8-bit access
+ uint8_t read_memory_byte(offs_t offset);
+ uint8_t read_reg_byte(offs_t offset);
+ void write_memory_byte(offs_t offset, uint8_t data);
+ void write_reg_byte(offs_t offset, uint8_t data);
+
protected:
virtual void device_start() override;
private:
+ devcb_write_line m_card_detect_cb;
+ devcb_write_line m_battery_voltage_1_cb;
+ devcb_write_line m_battery_voltage_2_cb;
+ devcb_write_line m_write_protect_cb;
+
// internal state
device_pccard_interface *m_pccard;
};
diff --git a/src/devices/machine/pccard_sram.cpp b/src/devices/machine/pccard_sram.cpp
new file mode 100644
index 00000000000..5275b4367ce
--- /dev/null
+++ b/src/devices/machine/pccard_sram.cpp
@@ -0,0 +1,390 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ SRAM PC Cards
+
+***************************************************************************/
+
+#include "emu.h"
+#include "pccard_sram.h"
+#include "machine/nvram.h"
+
+#define LOG_ATTRIBUTE (1U << 1)
+
+#define VERBOSE (LOG_GENERAL | LOG_ATTRIBUTE)
+#include "logmacro.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+// devices without attribute memory
+DEFINE_DEVICE_TYPE(PCCARD_SRAM_MITSUBISHI_1M, pccard_mitsubishi_mf31m1_lycat01_device, "mitsubishi_mf31m1_lycat01", "Mitsubishi Melcard 1 MB SRAM")
+
+// devices with attribute memory
+DEFINE_DEVICE_TYPE(PCCARD_SRAM_CENTENNIAL_1M, pccard_centennial_sl01m_15_11194_device, "centennial_sl01m_15_11194", "Centennial 1 MB SRAM")
+DEFINE_DEVICE_TYPE(PCCARD_SRAM_CENTENNIAL_2M, pccard_centennial_sl02m_15_11194_device, "centennial_sl02m_15_11194", "Centennial 2 MB SRAM")
+DEFINE_DEVICE_TYPE(PCCARD_SRAM_CENTENNIAL_4M, pccard_centennial_sl04m_15_11194_device, "centennial_sl04m_15_11194", "Centennial 4 MB SRAM")
+
+//-------------------------------------------------
+// inputs
+//-------------------------------------------------
+
+static INPUT_PORTS_START( card )
+ PORT_START("switches")
+ PORT_CONFNAME(0x01, 0x00, "Battery Failed") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pccard_sram_device, battery_voltage_1_w)
+ PORT_CONFSETTING( 0x01, DEF_STR(Yes))
+ PORT_CONFSETTING( 0x00, DEF_STR(No))
+ PORT_CONFNAME(0x02, 0x00, "Battery Low") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pccard_sram_device, battery_voltage_2_w)
+ PORT_CONFSETTING( 0x02, DEF_STR(Yes))
+ PORT_CONFSETTING( 0x00, DEF_STR(No))
+ PORT_CONFNAME(0x04, 0x04, "Write Protect") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pccard_sram_device, write_protect_w)
+ PORT_CONFSETTING( 0x04, DEF_STR(No))
+ PORT_CONFSETTING( 0x00, DEF_STR(Yes))
+INPUT_PORTS_END
+
+ioport_constructor pccard_sram_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(card);
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// pccard_sram_device - constructor
+//-------------------------------------------------
+
+pccard_sram_device::pccard_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ device_image_interface(mconfig, *this),
+ device_pccard_interface(mconfig, *this),
+ m_card_detect(false),
+ m_switches(*this, "switches")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void pccard_sram_device::device_start()
+{
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void pccard_sram_device::device_reset()
+{
+ // forward initial state of battery/write protect to slot
+ if (m_card_detect)
+ {
+ m_slot->battery_voltage_1_w(BIT(m_switches->read(), 0));
+ m_slot->battery_voltage_2_w(BIT(m_switches->read(), 1));
+ m_slot->write_protect_w(BIT(m_switches->read(), 2));
+ }
+ else
+ {
+ m_slot->battery_voltage_1_w(0);
+ m_slot->battery_voltage_2_w(0);
+ m_slot->write_protect_w(0);
+ }
+}
+
+//-------------------------------------------------
+// memory_space_config - configure memory space
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector pccard_sram_device::memory_space_config() const
+{
+ return space_config_vector
+ {
+ std::make_pair(0, &m_memory_space_config),
+ std::make_pair(1, &m_attribute_space_config)
+ };
+}
+
+//-------------------------------------------------
+// device_pccard_interface
+//-------------------------------------------------
+
+uint16_t pccard_sram_device::read_memory(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t data = 0xffff;
+
+ if (m_card_detect)
+ data = space(0).read_word(offset * 2, mem_mask);
+
+ return data;
+}
+
+void pccard_sram_device::write_memory(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ if (m_card_detect && BIT(m_switches->read(), 2))
+ space(0).write_word(offset * 2, data, mem_mask);
+}
+
+uint16_t pccard_sram_device::read_reg(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t data = 0xffff;
+
+ if (has_configured_map(1) && m_card_detect)
+ data = space(1).read_word(offset * 2, mem_mask);
+
+ LOGMASKED(LOG_ATTRIBUTE, "attribute memory r: %06x = %04x & %04x\n", offset, data, mem_mask);
+
+ return data & 0x00ff;
+}
+
+void pccard_sram_device::write_reg(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_ATTRIBUTE, "attribute memory w: %06x = %04x & %04x\n", offset, data, mem_mask);
+
+ if (has_configured_map(1) && m_card_detect && BIT(m_switches->read(), 2))
+ space(1).write_word(offset * 2, data & 0x00ff, mem_mask);
+}
+
+void pccard_sram_device::card_inserted(bool state)
+{
+ m_card_detect = state;
+ m_slot->card_detect_w(state ? 1 : 0);
+}
+
+
+/***************************************************************************
+
+ Mitsubishi Melcard
+
+ MF31M1-LYCAT01: 8/16-bit Data Bus Static RAM Card
+
+***************************************************************************/
+
+pccard_mitsubishi_sram_device::pccard_mitsubishi_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ pccard_sram_device(mconfig, type, tag, owner, clock),
+ m_sram(*this, "sram")
+{
+}
+
+std::pair<std::error_condition, std::string> pccard_mitsubishi_sram_device::call_load()
+{
+ card_inserted(false);
+
+ if (length() != m_sram.bytes())
+ return std::make_pair(image_error::INVALIDLENGTH, std::string());
+
+ if (fread(&m_sram[0], m_sram.bytes()) != m_sram.bytes())
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+
+ card_inserted(true);
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+std::pair<std::error_condition, std::string> pccard_mitsubishi_sram_device::call_create(int format_type, util::option_resolution *format_options)
+{
+ card_inserted(false);
+
+ // clear ram
+ std::fill_n(&m_sram[0], m_sram.length(), 0);
+
+ if (fwrite(&m_sram[0], m_sram.bytes()) != m_sram.bytes())
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+
+ card_inserted(true);
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+void pccard_mitsubishi_sram_device::call_unload()
+{
+ if (m_card_detect && !is_readonly())
+ {
+ fseek(0, SEEK_SET);
+ fwrite(&m_sram[0], m_sram.bytes());
+ }
+
+ std::fill_n(&m_sram[0], m_sram.length(), 0);
+
+ card_inserted(false);
+}
+
+pccard_mitsubishi_mf31m1_lycat01_device::pccard_mitsubishi_mf31m1_lycat01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ pccard_mitsubishi_sram_device(mconfig, PCCARD_SRAM_MITSUBISHI_1M, tag, owner, clock)
+{
+ m_memory_space_config = address_space_config("memory", ENDIANNESS_LITTLE, 16, 20, 0, address_map_constructor(FUNC(pccard_mitsubishi_mf31m1_lycat01_device::memory_map), this));
+ m_attribute_space_config = address_space_config("attribute", ENDIANNESS_LITTLE, 16, 14, 0);
+}
+
+void pccard_mitsubishi_mf31m1_lycat01_device::memory_map(address_map &map)
+{
+ map(0x000000, 0x0fffff).ram().share("sram");
+}
+
+
+/***************************************************************************
+
+ Centennial SRAM
+
+ SL01M-15-11194: 1 MB SRAM w/ Write Protect - 150 ns Rechargeable Lithium Battery
+ SL02M-15-11194: 2 MB SRAM w/ Write Protect - 150 ns Rechargeable Lithium Battery
+ SL04M-15-11194: 4 MB SRAM w/ Write Protect - 150 ns Rechargeable Lithium Battery
+
+ TODO:
+ - Get a real EEPROM dump from a factory new card and verify attribute
+ memory map
+ - Add more variants
+
+ Notes:
+ - EEPROM type is probably 28C64A, possible variants with 28C16A
+
+***************************************************************************/
+
+pccard_centennial_sram_device::pccard_centennial_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ pccard_sram_device(mconfig, type, tag, owner, clock),
+ m_sram(*this, "sram"),
+ m_eeprom(*this, "eeprom"),
+ m_eeprom_default(*this, "eeprom")
+{
+}
+
+std::pair<std::error_condition, std::string> pccard_centennial_sram_device::call_load()
+{
+ card_inserted(false);
+
+ if (length() != m_sram.bytes() + m_eeprom.bytes())
+ return std::make_pair(image_error::INVALIDLENGTH, std::string());
+
+ if (fread(&m_sram[0], m_sram.bytes()) != m_sram.bytes())
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+
+ if (fread(&m_eeprom[0], m_eeprom.bytes()) != m_eeprom.bytes())
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+
+ card_inserted(true);
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+std::pair<std::error_condition, std::string> pccard_centennial_sram_device::call_create(int format_type, util::option_resolution *format_options)
+{
+ card_inserted(false);
+
+ // clear ram
+ std::fill_n(&m_sram[0], m_sram.length(), 0);
+
+ // initialize EEPROM data from default data
+ std::copy_n(m_eeprom_default->base(), m_eeprom.length(), &m_eeprom[0]);
+
+ if (fwrite(&m_sram[0], m_sram.bytes()) != m_sram.bytes())
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+
+ if (fwrite(&m_eeprom[0], m_eeprom.bytes()) != m_eeprom.bytes())
+ return std::make_pair(image_error::UNSPECIFIED, std::string());
+
+ card_inserted(true);
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+void pccard_centennial_sram_device::call_unload()
+{
+ if (m_card_detect && !is_readonly())
+ {
+ fseek(0, SEEK_SET);
+ fwrite(&m_sram[0], m_sram.bytes());
+ fwrite(&m_eeprom[0], m_eeprom.bytes());
+ }
+
+ std::fill_n(&m_sram[0], m_sram.length(), 0);
+ std::fill_n(&m_eeprom[0], m_eeprom.length(), 0);
+
+ card_inserted(false);
+}
+
+pccard_centennial_sl01m_15_11194_device::pccard_centennial_sl01m_15_11194_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ pccard_centennial_sram_device(mconfig, PCCARD_SRAM_CENTENNIAL_1M, tag, owner, clock)
+{
+ m_memory_space_config = address_space_config("memory", ENDIANNESS_LITTLE, 16, 20, 0, address_map_constructor(FUNC(pccard_centennial_sl01m_15_11194_device::memory_map), this));
+ m_attribute_space_config = address_space_config("attribute", ENDIANNESS_LITTLE, 16, 14, 0, address_map_constructor(FUNC(pccard_centennial_sl01m_15_11194_device::attribute_map), this));
+}
+
+void pccard_centennial_sl01m_15_11194_device::memory_map(address_map &map)
+{
+ map(0x000000, 0x0fffff).ram().share("sram");
+}
+
+void pccard_centennial_sl01m_15_11194_device::attribute_map(address_map &map)
+{
+ map(0x00000, 0x03fff).ram().share("eeprom");
+}
+
+ROM_START( eeprom_01 )
+ ROM_REGION(0x2000, "eeprom", 0)
+ ROM_LOAD("eeprom.bin", 0x0000, 0x2000, BAD_DUMP CRC(2caacff3) SHA1(8141459dccf63a64f4bdf4e2171b0884f2cc390d))
+ROM_END
+
+const tiny_rom_entry *pccard_centennial_sl01m_15_11194_device::device_rom_region() const
+{
+ return ROM_NAME( eeprom_01 );
+}
+
+pccard_centennial_sl02m_15_11194_device::pccard_centennial_sl02m_15_11194_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ pccard_centennial_sram_device(mconfig, PCCARD_SRAM_CENTENNIAL_2M, tag, owner, clock)
+{
+ m_memory_space_config = address_space_config("memory", ENDIANNESS_LITTLE, 16, 21, 0, address_map_constructor(FUNC(pccard_centennial_sl02m_15_11194_device::memory_map), this));
+ m_attribute_space_config = address_space_config("attribute", ENDIANNESS_LITTLE, 16, 14, 0, address_map_constructor(FUNC(pccard_centennial_sl02m_15_11194_device::attribute_map), this));
+}
+
+void pccard_centennial_sl02m_15_11194_device::memory_map(address_map &map)
+{
+ map(0x000000, 0x1fffff).ram().share("sram");
+}
+
+void pccard_centennial_sl02m_15_11194_device::attribute_map(address_map &map)
+{
+ map(0x00000, 0x03fff).ram().share("eeprom");
+}
+
+ROM_START( eeprom_02 )
+ ROM_REGION(0x2000, "eeprom", 0)
+ ROM_LOAD("eeprom.bin", 0x0000, 0x2000, BAD_DUMP CRC(0d094f14) SHA1(a542a7395b306b9e34fd0be42d895b7b30013390))
+ROM_END
+
+const tiny_rom_entry *pccard_centennial_sl02m_15_11194_device::device_rom_region() const
+{
+ return ROM_NAME( eeprom_02 );
+}
+
+pccard_centennial_sl04m_15_11194_device::pccard_centennial_sl04m_15_11194_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ pccard_centennial_sram_device(mconfig, PCCARD_SRAM_CENTENNIAL_4M, tag, owner, clock)
+{
+ m_memory_space_config = address_space_config("memory", ENDIANNESS_LITTLE, 16, 22, 0, address_map_constructor(FUNC(pccard_centennial_sl04m_15_11194_device::memory_map), this));
+ m_attribute_space_config = address_space_config("attribute", ENDIANNESS_LITTLE, 16, 14, 0, address_map_constructor(FUNC(pccard_centennial_sl04m_15_11194_device::attribute_map), this));
+}
+
+void pccard_centennial_sl04m_15_11194_device::memory_map(address_map &map)
+{
+ map(0x000000, 0x3fffff).ram().share("sram");
+}
+
+void pccard_centennial_sl04m_15_11194_device::attribute_map(address_map &map)
+{
+ map(0x00000, 0x03fff).ram().share("eeprom");
+}
+
+ROM_START( eeprom_04 )
+ ROM_REGION(0x2000, "eeprom", 0)
+ ROM_LOAD("eeprom.bin", 0x0000, 0x2000, BAD_DUMP CRC(ce38fc21) SHA1(155edb39e554cb78547d3b9934a049ee46edc424))
+ROM_END
+
+const tiny_rom_entry *pccard_centennial_sl04m_15_11194_device::device_rom_region() const
+{
+ return ROM_NAME( eeprom_04 );
+}
diff --git a/src/devices/machine/pccard_sram.h b/src/devices/machine/pccard_sram.h
new file mode 100644
index 00000000000..f51e21798cb
--- /dev/null
+++ b/src/devices/machine/pccard_sram.h
@@ -0,0 +1,166 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ SRAM PC Cards
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_PCCARD_SRAM_H
+#define MAME_MACHINE_PCCARD_SRAM_H
+
+#pragma once
+
+#include "machine/pccard.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> pccard_sram_device
+
+class pccard_sram_device :
+ public device_t,
+ public device_memory_interface,
+ public device_image_interface,
+ public device_pccard_interface
+{
+public:
+ void battery_voltage_1_w(int state) { m_slot->battery_voltage_1_w(state); }
+ void battery_voltage_2_w(int state) { m_slot->battery_voltage_2_w(state); }
+ void write_protect_w(int state) { m_slot->write_protect_w(state); }
+
+protected:
+ // construction/destruction
+ pccard_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_t overrides
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_image_interface overrides
+ virtual bool is_readable() const noexcept override { return true; }
+ virtual bool is_writeable() const noexcept override { return true; }
+ virtual bool is_creatable() const noexcept override { return true; }
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual bool support_command_line_image_creation() const noexcept override { return true; }
+ virtual char const *file_extensions() const noexcept override { return "bin"; }
+ virtual const char *image_type_name() const noexcept override { return "sramcard"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "sram"; }
+
+ // device_pccard_interface overrides
+ virtual uint16_t read_memory(offs_t offset, uint16_t mem_mask = ~0) override;
+ virtual uint16_t read_reg(offs_t offset, uint16_t mem_mask = ~0) override;
+ virtual void write_memory(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) override;
+ virtual void write_reg(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) override;
+
+ void card_inserted(bool state);
+
+ address_space_config m_memory_space_config;
+ address_space_config m_attribute_space_config;
+
+ bool m_card_detect;
+
+private:
+ required_ioport m_switches;
+};
+
+class pccard_mitsubishi_sram_device : public pccard_sram_device
+{
+protected:
+ pccard_mitsubishi_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // device_image_interface overrides
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
+ virtual void call_unload() override;
+
+private:
+ required_shared_ptr<uint16_t> m_sram;
+};
+
+class pccard_mitsubishi_mf31m1_lycat01_device : public pccard_mitsubishi_sram_device
+{
+public:
+ // construction/destruction
+ pccard_mitsubishi_mf31m1_lycat01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+private:
+ void memory_map(address_map &map);
+};
+
+class pccard_centennial_sram_device : public pccard_sram_device
+{
+protected:
+ pccard_centennial_sram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // device_image_interface overrides
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) override;
+ virtual void call_unload() override;
+
+private:
+ required_shared_ptr<uint16_t> m_sram;
+ required_shared_ptr<uint16_t> m_eeprom;
+ required_memory_region m_eeprom_default;
+};
+
+class pccard_centennial_sl01m_15_11194_device : public pccard_centennial_sram_device
+{
+public:
+ // construction/destruction
+ pccard_centennial_sl01m_15_11194_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+protected:
+ // device_t overrides
+ virtual const tiny_rom_entry *device_rom_region() const override;
+
+private:
+ void memory_map(address_map &map);
+ void attribute_map(address_map &map);
+};
+
+class pccard_centennial_sl02m_15_11194_device : public pccard_centennial_sram_device
+{
+public:
+ // construction/destruction
+ pccard_centennial_sl02m_15_11194_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+protected:
+ // device_t overrides
+ virtual const tiny_rom_entry *device_rom_region() const override;
+
+private:
+ void memory_map(address_map &map);
+ void attribute_map(address_map &map);
+};
+
+class pccard_centennial_sl04m_15_11194_device : public pccard_centennial_sram_device
+{
+public:
+ // construction/destruction
+ pccard_centennial_sl04m_15_11194_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+protected:
+ // device_t overrides
+ virtual const tiny_rom_entry *device_rom_region() const override;
+
+private:
+ void memory_map(address_map &map);
+ void attribute_map(address_map &map);
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(PCCARD_SRAM_MITSUBISHI_1M, pccard_mitsubishi_mf31m1_lycat01_device)
+DECLARE_DEVICE_TYPE(PCCARD_SRAM_CENTENNIAL_1M, pccard_centennial_sl01m_15_11194_device)
+DECLARE_DEVICE_TYPE(PCCARD_SRAM_CENTENNIAL_2M, pccard_centennial_sl02m_15_11194_device)
+DECLARE_DEVICE_TYPE(PCCARD_SRAM_CENTENNIAL_4M, pccard_centennial_sl04m_15_11194_device)
+
+#endif // MAME_MACHINE_PCCARD_SRAM_H
diff --git a/src/devices/machine/pcf8573.cpp b/src/devices/machine/pcf8573.cpp
new file mode 100644
index 00000000000..a0d12344db6
--- /dev/null
+++ b/src/devices/machine/pcf8573.cpp
@@ -0,0 +1,356 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ Philips PCF8573 Clock and Calendar with Power Fail Detector
+
+ TODO:
+ - status bits 3/4 seconds/minutes are not set.
+
+*********************************************************************/
+
+#include "emu.h"
+#include "pcf8573.h"
+
+#define LOG_DATA (1U << 1)
+#define LOG_LINE (1U << 2)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PCF8573, pcf8573_device, "pcf8573", "PCF8573 RTC with Power Fail Detector")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// pcf8573_device - constructor
+//-------------------------------------------------
+
+pcf8573_device::pcf8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PCF8573, tag, owner, clock)
+ , device_rtc_interface(mconfig, *this)
+ , m_comp_cb(*this)
+ , m_min_cb(*this)
+ , m_sec_cb(*this)
+ , m_clock_timer(nullptr)
+ , m_slave_address(PCF8573_SLAVE_ADDRESS)
+ , m_scl(0)
+ , m_sdaw(0)
+ , m_sdar(1)
+ , m_state(STATE_IDLE)
+ , m_bits(0)
+ , m_shift(0)
+ , m_devsel(0)
+ , m_mode_pointer(0)
+ , m_address(0)
+ , m_status(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void pcf8573_device::device_start()
+{
+ // allocate timers
+ m_clock_timer = timer_alloc(FUNC(pcf8573_device::clock_tick), this);
+ m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
+
+ // state saving
+ save_item(NAME(m_scl));
+ save_item(NAME(m_sdaw));
+ save_item(NAME(m_sdar));
+ save_item(NAME(m_state));
+ save_item(NAME(m_bits));
+ save_item(NAME(m_shift));
+ save_item(NAME(m_devsel));
+ save_item(NAME(m_mode_pointer));
+ save_item(NAME(m_address));
+ save_item(NAME(m_status));
+ save_item(NAME(m_data));
+ save_item(NAME(m_slave_address));
+}
+
+//-------------------------------------------------
+// clock_tick - advance the RTC
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(pcf8573_device::clock_tick)
+{
+ advance_seconds();
+
+ // one pulse per second output
+ m_sec_cb(1);
+ m_sec_cb(0);
+}
+
+void pcf8573_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ if (m_data[REG_MINUTES] == convert_to_bcd(minute))
+ return;
+
+ // update registers
+ set_time_minute(minute);
+ set_time_hour(hour);
+ set_date_day(day);
+ set_date_month(month);
+
+ // one pulse per minute output
+ m_min_cb(1);
+ m_min_cb(0);
+
+ // comparator output
+ if (m_data[REG_HOURS] == m_data[REG_ALARM_HOURS] && m_data[REG_MINUTES] == m_data[REG_ALARM_MINUTES])
+ {
+ if (BIT(m_status, 2) || (m_data[REG_DAYS] == m_data[REG_ALARM_DAYS] && m_data[REG_MONTHS] == m_data[REG_ALARM_MONTHS]))
+ {
+ // set COMP flag
+ m_status |= 1 << 1;
+ m_comp_cb(1);
+ }
+ }
+}
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void pcf8573_device::a0_w(int state)
+{
+ state &= 1;
+ if (BIT(m_slave_address, 1) != state)
+ {
+ LOGMASKED(LOG_LINE, "set a0 %d\n", state );
+ m_slave_address = (m_slave_address & 0xfd) | (state << 1);
+ }
+}
+
+void pcf8573_device::a1_w(int state)
+{
+ state &= 1;
+ if (BIT(m_slave_address, 2) != state)
+ {
+ LOGMASKED(LOG_LINE, "set a1 %d\n", state );
+ m_slave_address = (m_slave_address & 0xfb) | (state << 2);
+ }
+}
+
+void pcf8573_device::scl_w(int state)
+{
+ if (m_scl != state)
+ {
+ m_scl = state;
+ LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_scl);
+
+ switch (m_state)
+ {
+ case STATE_ADDRESS:
+ case STATE_MODE:
+ case STATE_DATAIN:
+ if (m_bits < 8)
+ {
+ if (m_scl)
+ {
+ m_shift = ((m_shift << 1) | m_sdaw) & 0xff;
+ m_bits++;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ m_bits++;
+ }
+ else
+ {
+ if (m_bits == 8)
+ {
+ switch (m_state)
+ {
+ case STATE_ADDRESS:
+ m_devsel = m_shift;
+
+ if ((m_devsel & 0xfe) != m_slave_address)
+ {
+ LOGMASKED(LOG_DATA, "address %02x: not this device\n", m_devsel);
+ m_state = STATE_IDLE;
+ }
+ else if ((m_devsel & 1) == 0)
+ {
+ LOGMASKED(LOG_DATA, "address %02x: write\n", m_devsel);
+ m_state = STATE_MODE;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "address %02x: read\n", m_devsel);
+ m_state = STATE_READSELACK;
+ }
+ break;
+
+ case STATE_MODE:
+ m_mode_pointer = m_shift;
+
+ LOGMASKED(LOG_DATA, "mode pointer %02x\n", m_shift);
+
+ switch (m_mode_pointer & 0x70)
+ {
+ case 0x00: // execute address
+ m_address = m_mode_pointer & 0x07;
+ break;
+ case 0x10: // read control/status flags
+ break;
+ case 0x20: // reset prescaler
+ set_clock_register(RTC_SECOND, 0);
+ adjust_seconds();
+ break;
+ case 0x30: // time adjust
+ adjust_seconds();
+ break;
+ case 0x40: // reset NODA flag
+ m_status &= ~(1 << 2);
+ break;
+ case 0x50: // set NODA flag
+ m_status |= 1 << 2;
+ break;
+ case 0x60: // reset COMP flag
+ m_status &= ~(1 << 1);
+ m_comp_cb(0);
+ break;
+ }
+
+ m_state = STATE_DATAIN;
+ break;
+
+ case STATE_DATAIN:
+ switch (m_mode_pointer & 0x70)
+ {
+ case 0x00: // execute address
+ m_data[m_address] = m_shift;
+
+ LOGMASKED(LOG_DATA, "data[ %02x ] <- %02x\n", m_address, m_shift);
+
+ switch (m_address)
+ {
+ case REG_HOURS: set_clock_register(RTC_HOUR, bcd_to_integer(m_data[REG_HOURS])); break;
+ case REG_MINUTES: set_clock_register(RTC_MINUTE, bcd_to_integer(m_data[REG_MINUTES])); break;
+ case REG_DAYS: set_clock_register(RTC_DAY, bcd_to_integer(m_data[REG_DAYS])); break;
+ case REG_MONTHS: set_clock_register(RTC_MONTH, bcd_to_integer(m_data[REG_MONTHS])); break;
+ }
+
+ m_address = (m_address & 0x04) | ((m_address + 1) & 0x03);
+ break;
+ }
+ break;
+ }
+
+ if( m_state != STATE_IDLE )
+ {
+ m_sdar = 0 ;
+ }
+ }
+ else
+ {
+ m_bits = 0;
+ m_sdar = 1;
+ }
+ }
+ }
+ break;
+
+ case STATE_READSELACK:
+ m_bits = 0;
+ m_state = STATE_DATAOUT;
+ break;
+
+ case STATE_DATAOUT:
+ if (m_bits < 8)
+ {
+ if (m_scl)
+ {
+ m_bits++;
+ }
+ else
+ {
+ if (m_bits == 0)
+ {
+ switch (m_mode_pointer & 0x70)
+ {
+ case 0x00: // execute address
+ m_shift = m_data[m_address];
+ LOGMASKED(LOG_DATA, "data[ %02x ] -> %02x\n", m_address, m_shift);
+ m_address = (m_address & 0x04) | ((m_address + 1) & 0x03);
+ break;
+
+ case 0x10: // read control/status flags
+ m_shift = m_status;
+ LOGMASKED(LOG_DATA, "status -> %02x\n", m_address, m_shift);
+ break;
+ }
+ }
+
+ m_sdar = (m_shift >> 7) & 1;
+
+ m_shift = (m_shift << 1) & 0xff;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "nack\n");
+ m_state = STATE_IDLE;
+ }
+
+ m_bits = 0;
+ }
+ else
+ {
+ m_sdar = 1;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void pcf8573_device::sda_w(int state)
+{
+ state &= 1;
+ if (m_sdaw != state)
+ {
+ LOGMASKED(LOG_LINE, "set sda %d\n", state);
+ m_sdaw = state;
+
+ if (m_scl)
+ {
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "stop\n");
+ m_state = STATE_IDLE;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "start\n");
+ m_state = STATE_ADDRESS;
+ m_bits = 0;
+ }
+
+ m_sdar = 1;
+ }
+ }
+}
+
+int pcf8573_device::sda_r()
+{
+ int res = m_sdar & 1;
+
+ LOGMASKED(LOG_LINE, "read sda %d\n", res);
+
+ return res;
+}
diff --git a/src/devices/machine/pcf8573.h b/src/devices/machine/pcf8573.h
new file mode 100644
index 00000000000..91916ebef12
--- /dev/null
+++ b/src/devices/machine/pcf8573.h
@@ -0,0 +1,127 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ Philips PCF8573 Clock and Calendar with Power Fail Detector
+
+**********************************************************************
+
+ The PCF8573 comes in two package configurations:
+
+ PCF8573P - 16-pin dual-inline package (DIP16)
+ PCF8573T - 16-pin small-outline package (SO16)
+
+**********************************************************************
+
+ Pinning: ____ ____
+ | \/ |
+ A0 1 | | 16 Vdd
+ A1 2 | | 15 Vss1
+ COMP 3 | | 14 OSC0
+ SDA 4 | PCF8573P | 13 OSC1
+ SDL 5 | PCF8573T | 12 TEST
+ EXTPF 6 | | 11 FSET
+ PFIN 7 | | 10 SEC
+ Vss2 8 | | 9 MIN
+ |__________|
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_PCF8573_H
+#define MAME_MACHINE_PCF8573_H
+
+#pragma once
+
+#include "dirtc.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> pcf8573_device
+
+class pcf8573_device :
+ public device_t,
+ public device_rtc_interface
+{
+public:
+ pcf8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto comp_cb() { return m_comp_cb.bind(); }
+ auto min_cb() { return m_min_cb.bind(); }
+ auto sec_cb() { return m_sec_cb.bind(); }
+
+ void set_a0(int a0) { m_slave_address = (m_slave_address & 0xfd) | (a0 << 1); }
+ void set_a1(int a1) { m_slave_address = (m_slave_address & 0xfb) | (a1 << 2); }
+
+ void a0_w(int state);
+ void a1_w(int state);
+ void scl_w(int state);
+ void sda_w(int state);
+ int sda_r();
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+ // 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) override;
+
+ TIMER_CALLBACK_MEMBER(clock_tick);
+
+private:
+ static constexpr uint8_t PCF8573_SLAVE_ADDRESS = 0xd0;
+
+ enum
+ {
+ REG_HOURS = 0x00,
+ REG_MINUTES = 0x01,
+ REG_DAYS = 0x02,
+ REG_MONTHS = 0x03,
+ REG_ALARM_HOURS = 0x04,
+ REG_ALARM_MINUTES = 0x05,
+ REG_ALARM_DAYS = 0x06,
+ REG_ALARM_MONTHS = 0x07
+ };
+
+ // get/set time
+ uint8_t get_time_minute() { return bcd_to_integer(m_data[REG_MINUTES]); }
+ void set_time_minute(uint8_t minute){ m_data[REG_MINUTES] = convert_to_bcd(minute); }
+ uint8_t get_time_hour() { return bcd_to_integer(m_data[REG_HOURS]); }
+ void set_time_hour(uint8_t hour) { m_data[REG_HOURS] = convert_to_bcd(hour); }
+
+ // get/set date
+ uint8_t get_date_day() { return bcd_to_integer(m_data[REG_DAYS]); }
+ void set_date_day(uint8_t day) { m_data[REG_DAYS] = convert_to_bcd(day); }
+ uint8_t get_date_month() { return bcd_to_integer(m_data[REG_MONTHS]); }
+ void set_date_month(uint8_t month) { m_data[REG_MONTHS] = convert_to_bcd(month); }
+
+ devcb_write_line m_comp_cb;
+ devcb_write_line m_min_cb;
+ devcb_write_line m_sec_cb;
+
+ // timers
+ emu_timer *m_clock_timer;
+
+ // internal state
+ uint8_t m_data[8];
+ int m_slave_address;
+ int m_scl;
+ int m_sdaw;
+ int m_sdar;
+ int m_state;
+ int m_bits;
+ int m_shift;
+ int m_devsel;
+ int m_mode_pointer;
+ int m_address;
+ int m_status;
+
+ enum { STATE_IDLE, STATE_ADDRESS, STATE_MODE, STATE_DATAIN, STATE_DATAOUT, STATE_READSELACK };
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(PCF8573, pcf8573_device)
+
+#endif // MAME_MACHINE_PCF8573_H
diff --git a/src/devices/machine/pcf8583.cpp b/src/devices/machine/pcf8583.cpp
index 47babd1a2ac..40c9d201a88 100644
--- a/src/devices/machine/pcf8583.cpp
+++ b/src/devices/machine/pcf8583.cpp
@@ -1,77 +1,80 @@
// license:BSD-3-Clause
-// copyright-holders:Tim Schuerewegen, Ryan Holtz
+// copyright-holders:Nigel Barnes
/*********************************************************************
Philips PCF8583 Clock and Calendar with 240 x 8-bit RAM
TODO:
- - Alarm mode
- - Event-counter mode
- - Clock select
- - Clock output
- - Interrupts
+ - Event-counter mode
*********************************************************************/
#include "emu.h"
#include "pcf8583.h"
+#define LOG_DATA (1U << 1)
+#define LOG_LINE (1U << 2)
+
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
DEFINE_DEVICE_TYPE(PCF8583, pcf8583_device, "pcf8583", "PCF8583 RTC with 240x8 RAM")
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// pcf8583_device - constructor
+//-------------------------------------------------
+
pcf8583_device::pcf8583_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PCF8583, tag, owner, clock)
, device_rtc_interface(mconfig, *this)
, device_nvram_interface(mconfig, *this)
- , m_irq_callback(*this)
+ , m_region(*this, DEVICE_SELF)
+ , m_irq_cb(*this)
+ , m_slave_address(PCF8583_SLAVE_ADDRESS)
+ , m_scl(0)
+ , m_sdaw(0)
+ , m_sdar(1)
+ , m_state(STATE_IDLE)
+ , m_bits(0)
+ , m_shift(0)
+ , m_devsel(0)
+ , m_register(0)
+ , m_timer(nullptr)
{
}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
void pcf8583_device::device_start()
{
- std::fill(std::begin(m_register), std::end(m_register), 0);
-
- m_timer = timer_alloc(TIMER_TICK);
+ m_timer = timer_alloc(FUNC(pcf8583_device::clock_tick), this);
m_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
save_item(NAME(m_scl));
- save_item(NAME(m_sda));
- save_item(NAME(m_inp));
- save_item(NAME(m_transfer_active));
- save_item(NAME(m_bit_index));
+ save_item(NAME(m_sdaw));
+ save_item(NAME(m_sdar));
+ save_item(NAME(m_state));
+ save_item(NAME(m_bits));
+ save_item(NAME(m_shift));
+ save_item(NAME(m_devsel));
+ save_item(NAME(m_register));
save_item(NAME(m_irq));
- save_item(NAME(m_data_recv_index));
- save_item(NAME(m_data_recv));
- save_item(NAME(m_mode));
- save_item(NAME(m_pos));
- save_item(NAME(m_write_address));
- save_item(NAME(m_read_address));
-
- m_irq_callback.resolve_safe();
-}
-
-void pcf8583_device::device_reset()
-{
- m_scl = 1;
- m_sda = 1;
- m_transfer_active = false;
- m_inp = 0;
- m_mode = RTC_MODE_RECV;
- m_bit_index = 0;
- m_irq = false;
- m_pos = 0;
- clear_rx_buffer();
- set_time(true, get_date_year(), get_date_month(), get_date_day(), 0, get_time_hour(), get_time_minute(), get_time_second());
+ save_item(NAME(m_data));
+ save_item(NAME(m_slave_address));
}
-void pcf8583_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pcf8583_device::clock_tick)
{
- switch(id)
- {
- case TIMER_TICK:
- if (!BIT(m_data[REG_CONTROL], CONTROL_STOP_BIT))
- advance_hundredths();
- break;
- }
+ if (!BIT(m_data[REG_CONTROL], CONTROL_STOP_BIT))
+ advance_hundredths();
}
void pcf8583_device::advance_hundredths()
@@ -83,8 +86,8 @@ void pcf8583_device::advance_hundredths()
hundredths = 0;
advance_seconds();
m_irq = !m_irq;
- printf("Toggling IRQ: %d\n", m_irq ? 1 : 0);
- m_irq_callback(m_irq);
+
+ m_irq_cb(m_irq);
}
m_data[REG_HUNDREDTHS] = convert_to_bcd(hundredths);
}
@@ -98,138 +101,320 @@ void pcf8583_device::rtc_clock_updated(int year, int month, int day, int day_of_
set_date_day(day);
set_date_month(month);
set_date_year(year);
+
+ if (BIT(m_data[REG_HOURS], 7)) // 12h format
+ {
+ // update AM/PM flag
+ m_data[REG_HOURS] = (m_data[REG_HOURS] & 0xbf) | (bcd_to_integer(m_data[REG_HOURS] & 0x3f) >= 12 ? 0x40 : 0x00);
+ // convert from 24h to 12h
+ m_data[REG_HOURS] = (m_data[REG_HOURS] & 0xc0) | convert_to_bcd(bcd_to_integer((m_data[REG_HOURS] & 0x3f) % 12));
+ }
+
+ if (BIT(m_data[REG_CONTROL], 2)) // alarm enabled
+ {
+ switch (m_data[REG_ALARM_CONTROL] & 0x30)
+ {
+ case 0x00: // no alarm
+ break;
+
+ case 0x10: // daily alarm
+ if (m_data[REG_HUNDREDTHS] == m_data[REG_ALARM_HUNDREDTHS] && m_data[REG_SECONDS] == m_data[REG_ALARM_SECONDS] &&
+ m_data[REG_MINUTES] == m_data[REG_ALARM_MINUTES] && m_data[REG_HOURS] == m_data[REG_ALARM_HOURS])
+ {
+ m_data[REG_ALARM_CONTROL] |= 0x80;
+ }
+ break;
+
+ case 0x20: // weekday alarm
+ if (BIT(m_data[REG_ALARM_MONTH], m_data[REG_MONTH_DAY] >> 5)) // weekday enabled
+ {
+ if (m_data[REG_HUNDREDTHS] == m_data[REG_ALARM_HUNDREDTHS] && m_data[REG_SECONDS] == m_data[REG_ALARM_SECONDS] &&
+ m_data[REG_MINUTES] == m_data[REG_ALARM_MINUTES] && m_data[REG_HOURS] == m_data[REG_ALARM_HOURS])
+ {
+ m_data[REG_ALARM_CONTROL] |= 0x80;
+ }
+ }
+ break;
+
+ case 0x30: // dated alarm
+ if (m_data[REG_HUNDREDTHS] == m_data[REG_ALARM_HUNDREDTHS] && m_data[REG_SECONDS] == m_data[REG_ALARM_SECONDS] &&
+ m_data[REG_MINUTES] == m_data[REG_ALARM_MINUTES] && m_data[REG_HOURS] == m_data[REG_ALARM_HOURS] &&
+ (m_data[REG_YEAR_DATE] & 0x3f) == m_data[REG_ALARM_DATE] && (m_data[REG_MONTH_DAY] & 0x1f) == m_data[REG_ALARM_MONTH])
+ {
+ m_data[REG_ALARM_CONTROL] |= 0x80;
+ }
+ break;
+ }
+
+ // alarm interrupt enable
+ m_irq_cb(BIT(m_data[REG_ALARM_CONTROL], 7));
+ }
}
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
void pcf8583_device::nvram_default()
{
- std::fill(std::begin(m_data), std::end(m_data), 0);
+ // populate from a memory region if present
+ if (m_region.found())
+ {
+ if (m_region->bytes() != 0x100)
+ {
+ fatalerror("pcf8583 region '%s' wrong size (expected size = 0x100)\n", tag());
+ }
+
+ std::copy_n(m_region->base(), m_region->bytes(), &m_data[0]);
+ }
+ else
+ {
+ std::fill(std::begin(m_data), std::end(m_data), 0);
+ }
}
-void pcf8583_device::nvram_read(emu_file &file)
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+bool pcf8583_device::nvram_read(util::read_stream &file)
{
- file.read(m_data, sizeof(m_data));
+ auto const [err, actual] = read(file, m_data, sizeof(m_data));
+ return !err && (actual == sizeof(m_data));
}
-void pcf8583_device::nvram_write(emu_file &file)
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+bool pcf8583_device::nvram_write(util::write_stream &file)
{
- file.write(m_data, sizeof(m_data));
+ auto const [err, actual] = write(file, m_data, sizeof(m_data));
+ return !err;
}
-void pcf8583_device::write_register(uint8_t offset, uint8_t data)
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void pcf8583_device::a0_w(int state)
{
- logerror("%s: write_register: address %02x = %02x\n", machine().describe_context(), offset, data);
- m_data[offset] = data;
+ state &= 1;
+ if (BIT(m_slave_address, 1) != state)
+ {
+ LOGMASKED(LOG_LINE, "set a0 %d\n", state );
+ m_slave_address = (m_slave_address & 0xfd) | (state << 1);
+ }
}
-WRITE_LINE_MEMBER(pcf8583_device::scl_w)
+void pcf8583_device::scl_w(int state)
{
- if (m_transfer_active && !m_scl && state)
+ if (m_scl != state)
{
- switch (m_mode)
+ m_scl = state;
+ LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_scl);
+
+ switch (m_state)
{
- case RTC_MODE_RECV:
+ case STATE_DEVSEL:
+ case STATE_REGISTER:
+ case STATE_DATAIN:
+ if (m_bits < 8)
{
- logerror("%s: scl_w: Receiving bit %d in receive mode\n", machine().describe_context(), m_sda ? 1 : 0);
- if (m_sda)
- m_data_recv |= (0x80 >> m_bit_index);
- m_bit_index++;
-
- if (m_bit_index > 8) // ignore ACK bit
+ if (m_scl)
+ {
+ m_shift = ((m_shift << 1) | m_sdaw) & 0xff;
+ m_bits++;
+ }
+ }
+ else
+ {
+ if (m_scl)
+ {
+ m_bits++;
+ }
+ else
{
- if (m_data_recv_index == 0)
+ if( m_bits == 8 )
{
- if (m_data_recv == m_read_address)
+ switch (m_state)
{
- logerror("%s: scl_w: Received byte 0 (%02x), matches read address, entering read/send mode\n", machine().describe_context(), m_data_recv);
- m_mode = RTC_MODE_SEND;
- }
- else if (m_data_recv == m_write_address)
- {
- logerror("%s: scl_w: Received byte 0 (%02x), matches write address, entering read/send mode\n", machine().describe_context(), m_data_recv);
- m_mode = RTC_MODE_RECV;
+ case STATE_DEVSEL:
+ m_devsel = m_shift;
+
+ if ((m_devsel & 0xfe) != m_slave_address)
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: not this device\n", m_devsel);
+ m_state = STATE_IDLE;
+ }
+ else if ((m_devsel & 1) == 0)
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: write\n", m_devsel);
+ m_state = STATE_REGISTER;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "devsel %02x: read\n", m_devsel);
+ m_state = STATE_READSELACK;
+ }
+ break;
+
+ case STATE_REGISTER:
+ m_register = m_shift;
+
+ LOGMASKED(LOG_DATA, "register %02x\n", m_register);
+
+ m_state = STATE_DATAIN;
+ break;
+
+ case STATE_DATAIN:
+ LOGMASKED(LOG_DATA, "data[ %02x ] <- %02x\n", m_register, m_shift);
+
+ m_data[m_register] = m_shift;
+
+ switch (m_register)
+ {
+ case REG_CONTROL:
+ if ((m_shift & 0x24) == 0x04)
+ logerror("Timer not implemented");
+ break;
+ case REG_SECONDS:
+ set_clock_register(RTC_SECOND, bcd_to_integer(m_data[REG_SECONDS]));
+ break;
+ case REG_MINUTES:
+ set_clock_register(RTC_MINUTE, bcd_to_integer(m_data[REG_MINUTES]));
+ break;
+ case REG_HOURS:
+ set_clock_register(RTC_HOUR, bcd_to_integer(m_data[REG_HOURS]));
+ break;
+ case REG_YEAR_DATE:
+ set_clock_register(RTC_DAY, bcd_to_integer(m_data[REG_YEAR_DATE] & 0x3f));
+ set_clock_register(RTC_YEAR, bcd_to_integer(m_data[REG_YEAR_DATE] >> 6));
+ break;
+ case REG_MONTH_DAY:
+ set_clock_register(RTC_MONTH, bcd_to_integer(m_data[REG_MONTH_DAY] & 0x1f));
+ set_clock_register(RTC_DAY_OF_WEEK, bcd_to_integer((m_data[REG_MONTH_DAY] >> 5) + 1));
+ break;
+ case REG_ALARM_CONTROL:
+ m_irq_cb(m_data[REG_ALARM_CONTROL] & 0x88 ? 1 : 0);
+ break;
+ }
+
+ m_register++;
+ break;
}
- else
+
+ if (m_state != STATE_IDLE)
{
- logerror("%s: scl_w: Received byte 0 (%02x), unknown address, going idle\n", machine().describe_context(), m_data_recv);
- m_mode = RTC_MODE_NONE;
+ m_sdar = 0 ;
}
}
- else if (m_data_recv_index == 1)
+ else
{
- logerror("%s: scl_w: Received byte 1 (%02x), setting current read/write pos\n", machine().describe_context(), m_data_recv);
- m_pos = m_data_recv;
+ m_bits = 0;
+ m_sdar = 1;
}
- else if (m_data_recv_index >= 2)
- {
- logerror("%s: scl_w: Received byte 2+ (%d: %02x), storing to memory\n", machine().describe_context(), m_data_recv_index, m_data_recv);
- write_register(m_pos, m_data_recv);
- m_pos++;
- }
-
- m_bit_index = 0;
- m_data_recv = 0;
- m_data_recv_index++;
}
}
break;
- case RTC_MODE_SEND:
+ case STATE_READSELACK:
+ m_bits = 0;
+ m_state = STATE_DATAOUT;
+ break;
+
+ case STATE_DATAOUT:
+ if (m_bits < 8)
{
- if (m_bit_index < 8)
+ if (m_scl)
{
- m_inp = BIT(m_data[m_pos], 7 - m_bit_index);
- logerror("%s: scl_w: In send mode, reading bit %d from ram[0x%02x]=%02x (%d)\n", machine().describe_context(), m_bit_index, m_pos, m_data[m_pos], m_inp);
+ m_bits++;
}
- m_bit_index++;
+ else
+ {
+ if (m_bits == 0)
+ {
+ m_shift = m_data[m_register];
- if (m_bit_index > 8)
+ switch (m_register)
+ {
+ case 0x05:
+ if (BIT(m_data[0x00], 3)) // mask flag
+ m_shift &= 0x3f;
+ break;
+ case 0x06:
+ if (BIT(m_data[0x00], 3)) // mask flag
+ m_shift &= 0x1f;
+ break;
+ }
+
+ LOGMASKED(LOG_DATA, "data[ %02x ] -> %02x\n", m_register, m_shift);
+ m_register++;
+ }
+
+ m_sdar = (m_shift >> 7) & 1;
+
+ m_shift = (m_shift << 1) & 0xff;
+ }
+ }
+ else
+ {
+ if (m_scl)
{
- m_bit_index = 0;
- m_pos++;
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "nack\n");
+ m_state = STATE_IDLE;
+ }
+
+ m_bits = 0;
+ }
+ else
+ {
+ m_sdar = 1;
}
}
break;
}
}
-
- m_scl = state;
}
-WRITE_LINE_MEMBER(pcf8583_device::sda_w)
+void pcf8583_device::sda_w(int state)
{
- if (m_scl)
+ state &= 1;
+ if (m_sdaw != state)
{
- if (!state && m_sda)
- {
- // start condition (high to low when clock is high)
- m_transfer_active = true;
- m_bit_index = 0;
- m_data_recv_index = 0;
- clear_rx_buffer();
- }
- else if (state && !m_sda)
+ LOGMASKED(LOG_LINE, "set sda %d\n", state);
+ m_sdaw = state;
+
+ if (m_scl)
{
- // stop condition (low to high when clock is high)
- m_transfer_active = false;
+ if (m_sdaw)
+ {
+ LOGMASKED(LOG_DATA, "stop\n");
+ m_state = STATE_IDLE;
+ }
+ else
+ {
+ LOGMASKED(LOG_DATA, "start\n");
+ m_state = STATE_DEVSEL;
+ m_bits = 0;
+ }
+
+ m_sdar = 1;
}
}
-
- m_sda = state;
}
-READ_LINE_MEMBER(pcf8583_device::sda_r)
+int pcf8583_device::sda_r()
{
- return m_inp;
-}
+ int res = m_sdar & 1;
-void pcf8583_device::clear_rx_buffer()
-{
- m_data_recv = 0;
- m_data_recv_index = 0;
-}
+ LOGMASKED(LOG_LINE, "read sda %d\n", res);
-void pcf8583_device::set_a0(uint8_t a0)
-{
- m_read_address = READ_ADDRESS_BASE | (a0 << 1);
- m_write_address = WRITE_ADDRESS_BASE | (a0 << 1);
+ return res;
}
diff --git a/src/devices/machine/pcf8583.h b/src/devices/machine/pcf8583.h
index f8d98295cb1..2086eeef6bf 100644
--- a/src/devices/machine/pcf8583.h
+++ b/src/devices/machine/pcf8583.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Tim Schuerewegen, Ryan Holtz
+// copyright-holders:Nigel Barnes
/*********************************************************************
Philips PCF8583 Clock and Calendar with 240 x 8-bit RAM
@@ -62,37 +62,48 @@
#include "dirtc.h"
-class pcf8583_device : public device_t,
- public device_rtc_interface,
- public device_nvram_interface
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> pcf8583_device
+
+class pcf8583_device :
+ public device_t,
+ public device_rtc_interface,
+ public device_nvram_interface
{
public:
- pcf8583_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 32'768);
+ pcf8583_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- auto irq() { return m_irq_callback.bind(); }
+ auto irq() { return m_irq_cb.bind(); }
- void set_a0(uint8_t a0);
+ void set_a0(int a0) { m_slave_address = (m_slave_address & 0xfd) | (a0 << 1); }
- DECLARE_WRITE_LINE_MEMBER(scl_w);
- DECLARE_WRITE_LINE_MEMBER(sda_w);
- DECLARE_READ_LINE_MEMBER(sda_r);
+ void a0_w(int state);
+ void scl_w(int state);
+ void sda_w(int state);
+ int sda_r();
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_rtc_interface overrides
virtual bool rtc_feature_y2k() const override { return true; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ TIMER_CALLBACK_MEMBER(clock_tick);
private:
+ static constexpr uint8_t PCF8583_SLAVE_ADDRESS = 0xa0;
+
enum
{
REG_CONTROL = 0x00,
@@ -115,11 +126,9 @@ private:
enum
{
- CONTROL_STOP_BIT = 0x80
+ CONTROL_STOP_BIT = 7
};
- static const device_timer_id TIMER_TICK = 0;
-
// get/set date
uint8_t get_date_year() { return (m_data[REG_YEAR_DATE] >> 6) & 3; }
void set_date_year(uint8_t year) { m_data[REG_YEAR_DATE] = (m_data[REG_YEAR_DATE] & 0x3f) | ((year % 4) << 6); }
@@ -136,31 +145,27 @@ private:
uint8_t get_time_second() { return bcd_to_integer(m_data[REG_SECONDS]); }
void set_time_second(uint8_t second){ m_data[REG_SECONDS] = convert_to_bcd(second); }
- void write_register(uint8_t offset, uint8_t data);
void advance_hundredths();
- void clear_rx_buffer();
- devcb_write_line m_irq_callback;
+ optional_memory_region m_region;
+
+ devcb_write_line m_irq_cb;
// internal state
- uint8_t m_data[256];
- int m_scl;
- int m_sda;
- int m_inp;
- bool m_transfer_active;
- int m_bit_index;
- bool m_irq;
- uint8_t m_data_recv_index;
- uint8_t m_data_recv;
- uint8_t m_mode;
- uint8_t m_pos;
- uint8_t m_write_address;
- uint8_t m_read_address;
+ uint8_t m_data[256];
+ int m_slave_address;
+ int m_scl;
+ int m_sdaw;
+ int m_sdar;
+ int m_state;
+ int m_bits;
+ int m_shift;
+ int m_devsel;
+ int m_register;
+ bool m_irq;
emu_timer * m_timer;
- enum { RTC_MODE_NONE, RTC_MODE_SEND, RTC_MODE_RECV };
- static constexpr uint8_t WRITE_ADDRESS_BASE = 0xa0;
- static constexpr uint8_t READ_ADDRESS_BASE = 0xa1;
+ enum { STATE_IDLE, STATE_DEVSEL, STATE_REGISTER, STATE_DATAIN, STATE_DATAOUT, STATE_READSELACK };
};
// device type definition
diff --git a/src/devices/machine/pcf8584.cpp b/src/devices/machine/pcf8584.cpp
index 31d78e73008..79d8a013c6a 100644
--- a/src/devices/machine/pcf8584.cpp
+++ b/src/devices/machine/pcf8584.cpp
@@ -54,7 +54,7 @@ const char *const pcf8584_device::s_bus_function[4] = { "NOP", "stop", "start",
pcf8584_device::pcf8584_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, PCF8584, tag, owner, clock)
- , m_sda_callback(*this)
+ , m_sda_callback(*this, 1)
, m_sda_out_callback(*this)
, m_scl_callback(*this)
, m_int_callback(*this)
@@ -71,21 +71,6 @@ pcf8584_device::pcf8584_device(const machine_config &mconfig, const char *tag, d
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void pcf8584_device::device_resolve_objects()
-{
- m_sda_callback.resolve_safe(1);
- m_sda_out_callback.resolve_safe();
- m_scl_callback.resolve_safe();
- m_int_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
diff --git a/src/devices/machine/pcf8584.h b/src/devices/machine/pcf8584.h
index 68886a7affc..cbf2dff9c82 100644
--- a/src/devices/machine/pcf8584.h
+++ b/src/devices/machine/pcf8584.h
@@ -57,8 +57,7 @@ public:
IRQ_CALLBACK_MEMBER(iack);
protected:
- // device-specific overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
diff --git a/src/devices/machine/pcf8593.cpp b/src/devices/machine/pcf8593.cpp
index 331e12ccdbd..9c16476cfb5 100644
--- a/src/devices/machine/pcf8593.cpp
+++ b/src/devices/machine/pcf8593.cpp
@@ -11,14 +11,17 @@
#include "emu.h"
#include "pcf8593.h"
+#define LOG_LEVEL0 (1U << 1)
+#define LOG_LEVEL1 (1U << 2)
+#define LOG_LEVEL2 (1U << 3)
+#define VERBOSE (LOG_LEVEL0)
+#include "logmacro.h"
+
/***************************************************************************
PARAMETERS/CONSTANTS/MACROS
***************************************************************************/
-#define LOG_LEVEL 1
-#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
-
// get/set date
#define RTC_GET_DATE_YEAR ((m_data[5] >> 6) & 3)
#define RTC_SET_DATE_YEAR(x) m_data[5] = (m_data[5] & 0x3F) | (((x) % 4) << 6)
@@ -61,9 +64,9 @@ pcf8593_device::pcf8593_device(const machine_config &mconfig, const char *tag, d
void pcf8593_device::device_start()
{
- _logerror( 0, ("pcf8593_init\n"));
+ LOGMASKED(LOG_LEVEL0, "pcf8593_init\n");
memset(m_register, 0, sizeof(m_register));
- m_timer = timer_alloc(TIMER_UPDATE_COUNTER);
+ m_timer = timer_alloc(FUNC(pcf8593_device::clock_tick), this);
m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
}
@@ -73,11 +76,11 @@ void pcf8593_device::device_start()
void pcf8593_device::device_reset()
{
- _logerror( 0, ("pcf8593_reset\n"));
+ LOGMASKED(LOG_LEVEL0, "pcf8593_reset\n");
m_pin_scl = 1;
m_pin_sda = 1;
m_active = false;
- m_inp = 0;
+ m_inp = 0; // FIXME: sda should default 1 not 0.
m_mode = RTC_MODE_RECV;
m_bits = 0;
m_pos = 0;
@@ -87,20 +90,15 @@ void pcf8593_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// clock_tick - advance the RTC if enabled
//-------------------------------------------------
-void pcf8593_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pcf8593_device::clock_tick)
{
- switch(id)
- {
- case TIMER_UPDATE_COUNTER:
- _logerror( 2, ("pcf8593_timer_callback (%d)\n", param));
- // check if counting is enabled
- if (!(m_data[0] & 0x80))
- advance_seconds();
- break;
- }
+ LOGMASKED(LOG_LEVEL2, "pcf8593_timer_callback (%d)\n", param);
+ // check if counting is enabled
+ if (!(m_data[0] & 0x80))
+ advance_seconds();
}
@@ -134,9 +132,10 @@ void pcf8593_device::nvram_default()
// .nv file
//-------------------------------------------------
-void pcf8593_device::nvram_read(emu_file &file)
+bool pcf8593_device::nvram_read(util::read_stream &file)
{
- file.read(m_data, sizeof(m_data));
+ auto const [err, actual] = read(file, m_data, sizeof(m_data));
+ return !err && (actual == sizeof(m_data));
}
@@ -145,9 +144,10 @@ void pcf8593_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void pcf8593_device::nvram_write(emu_file &file)
+bool pcf8593_device::nvram_write(util::write_stream &file)
{
- file.write(m_data, sizeof(m_data));
+ auto const [err, actual] = write(file, m_data, sizeof(m_data));
+ return !err;
}
@@ -156,9 +156,13 @@ void pcf8593_device::nvram_write(emu_file &file)
pcf8593_pin_scl
-------------------------------------------------*/
-WRITE_LINE_MEMBER(pcf8593_device::scl_w)
+void pcf8593_device::scl_w(int state)
{
// send bit
+ // FIXME: Processing on the rising edge of the clock causes sda output to
+ // change while clock is high. This is not allowed.
+ // All received data is currently acknowledge, need to add checks for
+ // valid device-id and ACK/NAK as required.
if ((m_active) && (!m_pin_scl) && (state))
{
switch (m_mode)
@@ -172,7 +176,7 @@ WRITE_LINE_MEMBER(pcf8593_device::scl_w)
// bit 9 = end
if (m_bits > 8)
{
- _logerror( 2, ("pcf8593_write_byte(%02X)\n", m_data_recv[m_data_recv_index]));
+ LOGMASKED(LOG_LEVEL2, "pcf8593_write_byte(%02X)\n", m_data_recv[m_data_recv_index]);
// enter receive mode when 1st byte = 0xA3
if ((m_data_recv[0] == 0xA3) && (m_data_recv_index == 0))
{
@@ -208,11 +212,11 @@ WRITE_LINE_MEMBER(pcf8593_device::scl_w)
// bit 9 = end
if (m_bits > 8)
{
- _logerror( 2, ("pcf8593_read_byte(%02X)\n", m_data[m_pos]));
+ LOGMASKED(LOG_LEVEL2, "pcf8593_read_byte(%02X)\n", m_data[m_pos]);
// end ?
if (m_pin_sda)
{
- _logerror( 2, ("pcf8593 end\n"));
+ LOGMASKED(LOG_LEVEL2, "pcf8593 end\n");
m_mode = RTC_MODE_RECV;
clear_buffer_rx();
}
@@ -234,17 +238,17 @@ WRITE_LINE_MEMBER(pcf8593_device::scl_w)
pcf8593_pin_sda_w
-------------------------------------------------*/
-WRITE_LINE_MEMBER(pcf8593_device::sda_w)
+void pcf8593_device::sda_w(int state)
{
// clock is high
if (m_pin_scl)
{
// log init I2C
- if (state) _logerror( 1, ("pcf8593 init i2c\n"));
+ if (state) LOGMASKED(LOG_LEVEL1, "pcf8593 init i2c\n");
// start condition (high to low when clock is high)
if ((!state) && (m_pin_sda))
{
- _logerror( 1, ("pcf8593 start condition\n"));
+ LOGMASKED(LOG_LEVEL1, "pcf8593 start condition\n");
m_active = true;
m_bits = 0;
m_data_recv_index = 0;
@@ -254,7 +258,7 @@ WRITE_LINE_MEMBER(pcf8593_device::sda_w)
// stop condition (low to high when clock is high)
if ((state) && (!m_pin_sda))
{
- _logerror( 1, ("pcf8593 stop condition\n"));
+ LOGMASKED(LOG_LEVEL1, "pcf8593 stop condition\n");
m_active = false;
}
}
@@ -268,7 +272,7 @@ WRITE_LINE_MEMBER(pcf8593_device::sda_w)
pcf8593_pin_sda_r
-------------------------------------------------*/
-READ_LINE_MEMBER(pcf8593_device::sda_r)
+int pcf8593_device::sda_r()
{
return m_inp;
}
diff --git a/src/devices/machine/pcf8593.h b/src/devices/machine/pcf8593.h
index 2b6d76bc853..27f112f68c5 100644
--- a/src/devices/machine/pcf8593.h
+++ b/src/devices/machine/pcf8593.h
@@ -24,15 +24,14 @@ class pcf8593_device : public device_t,
public:
pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- DECLARE_WRITE_LINE_MEMBER(scl_w);
- DECLARE_WRITE_LINE_MEMBER(sda_w);
- DECLARE_READ_LINE_MEMBER(sda_r);
+ void scl_w(int state);
+ void sda_w(int state);
+ int sda_r();
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_rtc_interface overrides
virtual bool rtc_feature_y2k() const override { return true; }
@@ -40,14 +39,14 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ TIMER_CALLBACK_MEMBER(clock_tick);
private:
void clear_buffer_rx();
- static const device_timer_id TIMER_UPDATE_COUNTER = 0;
-
// internal state
uint8_t m_data[16];
int m_pin_scl;
diff --git a/src/devices/machine/pci-ide.cpp b/src/devices/machine/pci-ide.cpp
index fed9182e312..9c4d3a4fda2 100644
--- a/src/devices/machine/pci-ide.cpp
+++ b/src/devices/machine/pci-ide.cpp
@@ -12,8 +12,7 @@ ide_pci_device::ide_pci_device(const machine_config &mconfig, const char *tag, d
m_irq_handler(*this),
m_legacy_top(0x000),
m_pif(0x8a),
- m_bus_master_tag(":pci:00.0"),
- m_bus_master_space(AS_DATA)
+ m_bus_master_space(*this, ":pci:00.0", AS_DATA)
{
}
@@ -58,11 +57,11 @@ void ide_pci_device::device_add_mconfig(machine_config &config)
{
BUS_MASTER_IDE_CONTROLLER(config, m_ide).options(ata_devices, "hdd", "cdrom", true);
m_ide->irq_handler().set(FUNC(ide_pci_device::ide_interrupt));
- m_ide->set_bus_master_space(m_bus_master_tag, m_bus_master_space);
+ m_ide->set_bus_master_space(m_bus_master_space);
BUS_MASTER_IDE_CONTROLLER(config, m_ide2).options(ata_devices, "hdd", "cdrom", true);
m_ide2->irq_handler().set(FUNC(ide_pci_device::ide_interrupt));
- m_ide2->set_bus_master_space(m_bus_master_tag, m_bus_master_space);
+ m_ide2->set_bus_master_space(m_bus_master_space);
}
void ide_pci_device::device_start()
@@ -86,8 +85,6 @@ void ide_pci_device::device_start()
pci_bar[3] = 0x374;
pci_bar[4] = 0xf00;
- m_irq_handler.resolve_safe();
-
intr_pin = 0x1;
intr_line = 0xe;
@@ -145,7 +142,7 @@ void ide_pci_device::ide2_write_cs1(offs_t offset, uint32_t data, uint32_t mem_m
m_ide2->write_cs1(1, data, mem_mask);
}
-WRITE_LINE_MEMBER(ide_pci_device::ide_interrupt)
+void ide_pci_device::ide_interrupt(int state)
{
// Call the callback
m_irq_handler(state);
diff --git a/src/devices/machine/pci-ide.h b/src/devices/machine/pci-ide.h
index 140db524f50..d258f8b288e 100644
--- a/src/devices/machine/pci-ide.h
+++ b/src/devices/machine/pci-ide.h
@@ -26,18 +26,17 @@ public:
: ide_pci_device(mconfig, tag, owner, clock)
{
set_ids(main_id, revision, 0x01018a, subdevice_id);
- m_bus_master_tag = bmtag;
- m_bus_master_space = bmspace;
+ m_bus_master_space.set_tag(bmtag, bmspace);
}
ide_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto irq_handler() { return m_irq_handler.bind(); }
// This will set the top 12 bits for address decoding in legacy mode. Needed for seattle driver.
- void set_legacy_top(int val) { m_legacy_top = val & 0xfff; };
+ void set_legacy_top(int val) { m_legacy_top = val & 0xfff; }
// Sets the default Programming Interface (PIF) register
- void set_pif(int val) { m_pif = val & 0xff; };
+ void set_pif(int val) { m_pif = val & 0xff; }
protected:
virtual void device_start() override;
@@ -49,7 +48,7 @@ protected:
virtual void config_map(address_map &map) override;
private:
- DECLARE_WRITE_LINE_MEMBER(ide_interrupt);
+ void ide_interrupt(int state);
void prog_if_w(uint8_t data);
uint32_t pcictrl_r(offs_t offset);
void pcictrl_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
@@ -69,8 +68,7 @@ private:
// Bits 31-20 for legacy mode hack
uint32_t m_legacy_top;
uint32_t m_pif;
- const char* m_bus_master_tag;
- uint32_t m_bus_master_space;
+ required_address_space m_bus_master_space;
uint32_t m_config_data[0x10];
void chan1_data_command_map(address_map &map);
diff --git a/src/devices/machine/pci-smbus.h b/src/devices/machine/pci-smbus.h
index 9c7cd79aa74..e2c5d7a07d8 100644
--- a/src/devices/machine/pci-smbus.h
+++ b/src/devices/machine/pci-smbus.h
@@ -14,12 +14,13 @@ public:
}
smbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ void map(address_map &map);
+
protected:
virtual void device_start() override;
virtual void device_reset() override;
private:
- void map(address_map &map);
uint8_t hst_sts_r();
void hst_sts_w(uint8_t data);
diff --git a/src/devices/machine/pci.cpp b/src/devices/machine/pci.cpp
index 55fdfcdfce9..e4c582e29a8 100644
--- a/src/devices/machine/pci.cpp
+++ b/src/devices/machine/pci.cpp
@@ -1,7 +1,13 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
+/*
+ * References:
+ * - PCI local bus (rev 2.x)
+ * - https://wiki.osdev.org/PCI
+ */
#include "emu.h"
#include "pci.h"
+#include "bus/pci/pci_slot.h"
DEFINE_DEVICE_TYPE(PCI_ROOT, pci_root_device, "pci_root", "PCI virtual root")
DEFINE_DEVICE_TYPE(PCI_BRIDGE, pci_bridge_device, "pci_bridge", "PCI-PCI Bridge")
@@ -87,6 +93,12 @@ pci_device::pci_device(const machine_config &mconfig, device_type type, const ch
}
}
+// main_id << 16 = vendor ID ($00-$01)
+// main_id & 0xffff = device ID ($02-$03)
+// revision = board versioning ($08)
+// pclass = programming interface/sub class code/base class code ($09-$0b)
+// subsystem_id << 16 = sub vendor ID ($2c-$2d) - NB: not all cards have these
+// subsystem_id & 0xffff = sub device ID ($2e-$2f) /
void pci_device::set_ids(uint32_t _main_id, uint8_t _revision, uint32_t _pclass, uint32_t _subsystem_id)
{
main_id = _main_id;
@@ -97,21 +109,27 @@ void pci_device::set_ids(uint32_t _main_id, uint8_t _revision, uint32_t _pclass,
void pci_device::device_start()
{
- command = 0x0080;
+ command = 0x0000;
command_mask = 0x01bf;
status = 0x0000;
bank_count = 0;
bank_reg_count = 0;
- for (int i = 0; i < ARRAY_LENGTH(bank_infos); i++) {
- save_item(NAME(bank_infos[i].adr), i);
- }
+ save_item(STRUCT_MEMBER(bank_infos, adr));
save_item(NAME(command));
save_item(NAME(command_mask));
save_item(NAME(status));
save_item(NAME(intr_line));
save_item(NAME(intr_pin));
+
+ device_t *root = owner();
+ while(root && root->type() != PCI_ROOT)
+ root = root->owner();
+ if(!root)
+ fatalerror("PCI device %s is without a PCI root\n", tag());
+
+ m_pci_root = downcast<pci_root_device *>(root);
}
void pci_device::device_reset()
@@ -259,6 +277,17 @@ void pci_device::expansion_base_w(offs_t offset, uint32_t data, uint32_t mem_mas
remap_cb();
}
+// if non-zero a CAPability PoinTeR marks an offset in PCI config space where a standard extension is located
+// For example if capptr_r is 0xc0 then [offset+0xc0] has a capability identifier that is set with:
+// bits 31-16 <capability dependant, usually revision and supported sub-features>
+// bits 15-8 next capptr offset, 0x00 to determine the given item as last
+// bits 7-0 capability ID:
+// - 0x01 PMI Power Management Interface
+// - 0x02 AGP Accelerated Graphics Port
+// - 0x03 VPD Vital Product Data
+// - 0x04 Slot Identification
+// - 0x05 MSI Message Signaled Interrupts
+// - 0x06 CompactPCI Hot Swap
uint8_t pci_device::capptr_r()
{
return 0x00;
@@ -489,13 +518,25 @@ void pci_bridge_device::device_start()
for (device_t &d : bus_root()->subdevices())
{
- const char *t = d.tag();
- int l = strlen(t);
- if(l <= 4 || t[l-5] != ':' || t[l-2] != '.')
- continue;
- int id = strtol(t+l-4, nullptr, 16);
- int fct = t[l-1] - '0';
- sub_devices[(id << 3) | fct] = downcast<pci_device *>(&d);
+ if(d.type() == PCI_SLOT) {
+ pci_slot_device &slot = downcast<pci_slot_device &>(d);
+ pci_device *card = slot.get_card();
+ if(card) {
+ int id = slot.get_slot();
+ sub_devices[id << 3] = card;
+ }
+
+ } else {
+ const char *t = d.tag();
+ int l = strlen(t);
+ if(l <= 4 || t[l-5] != ':' || t[l-2] != '.') {
+ logerror("Device %s unhandled\n", t);
+ continue;
+ }
+ int id = strtol(t+l-4, nullptr, 16);
+ int fct = t[l-1] - '0';
+ sub_devices[(id << 3) | fct] = downcast<pci_device *>(&d);
+ }
}
mapper_cb cf_cb(&pci_bridge_device::regenerate_config_mapping, this);
@@ -524,6 +565,10 @@ void pci_bridge_device::device_reset()
primary_bus = 0x00;
secondary_bus = 0x00;
subordinate_bus = 0x00;
+}
+
+void pci_bridge_device::interface_post_reset()
+{
regenerate_config_mapping();
}
@@ -843,6 +888,12 @@ void pci_host_device::io_configuration_access_map(address_map &map)
map(0xcfc, 0xcff).rw(FUNC(pci_host_device::config_data_r), FUNC(pci_host_device::config_data_w));
}
+void pci_host_device::set_spaces(address_space *memory, address_space *io, address_space *busmaster)
+{
+ memory_space = memory;
+ io_space = io ? io : memory;
+ m_pci_root->set_pci_busmaster_space(busmaster ? busmaster : memory);
+}
pci_host_device::pci_host_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: pci_bridge_device(mconfig, type, tag, owner, clock)
@@ -873,11 +924,16 @@ void pci_host_device::device_reset()
{
pci_bridge_device::device_reset();
reset_all_mappings();
- regenerate_mapping();
config_address = 0;
}
+void pci_host_device::interface_post_reset()
+{
+ pci_bridge_device::interface_post_reset();
+ regenerate_mapping();
+}
+
void pci_host_device::regenerate_mapping()
{
logerror("Regenerating mapping\n");
@@ -909,6 +965,38 @@ void pci_host_device::config_data_w(offs_t offset, uint32_t data, uint32_t mem_m
root_config_write((config_address >> 16) & 0xff, (config_address >> 8) & 0xff, config_address & 0xfc, data, mem_mask);
}
+uint32_t pci_host_device::config_data_ex_r(offs_t offset, uint32_t mem_mask)
+{
+ // is this a Type 0 or Type 1 configuration address? (page 31, PCI 2.2 Specification)
+ if ((config_address & 3) == 0)
+ {
+ const int devnum = 31 - count_leading_zeros_32(config_address & 0xfffff800);
+ return root_config_read(0, devnum << 3, config_address & 0xfc, mem_mask);
+ }
+ else if ((config_address & 3) == 1)
+ return config_address & 0x80000000 ? root_config_read((config_address >> 16) & 0xff, (config_address >> 8) & 0xff, config_address & 0xfc, mem_mask) : 0xffffffff;
+
+ logerror("pci: configuration address format %d unsupported", config_address & 3);
+ return 0xffffffff;
+}
+
+void pci_host_device::config_data_ex_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ // is this a Type 0 or Type 1 configuration address? (page 31, PCI 2.2 Specification)
+ if ((config_address & 3) == 0)
+ {
+ const int devnum = 31 - count_leading_zeros_32(config_address & 0xfffff800);
+ root_config_write(0, devnum << 3, config_address & 0xfc, data, mem_mask);
+ }
+ else if ((config_address & 3) == 1)
+ {
+ if (config_address & 0x80000000)
+ root_config_write((config_address >> 16) & 0xff, (config_address >> 8) & 0xff, config_address & 0xfc, data, mem_mask);
+ }
+ else
+ logerror("pci: configuration address format %d unsupported", config_address & 3);
+}
+
uint32_t pci_host_device::root_config_read(uint8_t bus, uint8_t device, uint16_t reg, uint32_t mem_mask)
{
if(bus == 0x00)
@@ -928,7 +1016,10 @@ void pci_host_device::root_config_write(uint8_t bus, uint8_t device, uint16_t re
pci_root_device::pci_root_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, PCI_ROOT, tag, owner, clock)
+ : device_t(mconfig, PCI_ROOT, tag, owner, clock),
+ m_pin_mapper(*this),
+ m_irq_handler(*this),
+ m_pci_busmaster_space(nullptr)
{
}
@@ -939,3 +1030,13 @@ void pci_root_device::device_start()
void pci_root_device::device_reset()
{
}
+
+void pci_root_device::irq_pin_w(int pin, int state)
+{
+ m_irq_handler(m_pin_mapper(pin), state);
+}
+
+void pci_root_device::irq_w(int line, int state)
+{
+ m_irq_handler(line, state);
+}
diff --git a/src/devices/machine/pci.h b/src/devices/machine/pci.h
index 37ad677a476..d95bf58afbf 100644
--- a/src/devices/machine/pci.h
+++ b/src/devices/machine/pci.h
@@ -5,7 +5,6 @@
#pragma once
-
class pci_device : public device_t {
public:
typedef delegate<void ()> mapper_cb;
@@ -102,6 +101,8 @@ protected:
int bank_count, bank_reg_count;
bank_reg_info bank_reg_infos[6];
+ class pci_root_device *m_pci_root;
+
uint32_t main_id, subsystem_id;
uint32_t pclass;
uint8_t revision;
@@ -121,6 +122,10 @@ protected:
address_map_constructor delegate(map, name, static_cast<T *>(this));
add_map(size, flags, delegate);
}
+ template <typename T> void add_map(uint64_t size, int flags, T &device, void (T::*map)(address_map &map), const char *name) {
+ address_map_constructor delegate(map, name, &device);
+ add_map(size, flags, delegate, &device);
+ }
void add_rom(const uint8_t *data, uint32_t size);
void add_rom_from_region();
@@ -128,6 +133,8 @@ protected:
void set_map_address(int id, uint64_t adr);
void set_map_size(int id, uint64_t size);
void set_map_flags(int id, int flags);
+
+ inline address_space *get_pci_busmaster_space() const;
};
class agp_device : public pci_device {
@@ -189,7 +196,7 @@ public:
uint16_t iolimitu_r();
void iolimitu_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t bridge_control_r();
- void bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ virtual void bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
protected:
enum
@@ -201,6 +208,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
+ virtual void interface_post_reset() override;
virtual space_config_vector memory_space_config() const override;
virtual device_t *bus_root();
@@ -237,6 +245,8 @@ class pci_host_device : public pci_bridge_device {
public:
void io_configuration_access_map(address_map &map);
+ void set_spaces(address_space *memory, address_space *io = nullptr, address_space *busmaster = nullptr);
+
protected:
pci_host_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -244,9 +254,12 @@ protected:
void config_address_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t config_data_r(offs_t offset, uint32_t mem_mask = ~0);
void config_data_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint32_t config_data_ex_r(offs_t offset, uint32_t mem_mask = ~0);
+ void config_data_ex_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
virtual void device_start() override;
virtual void device_reset() override;
+ virtual void interface_post_reset() override;
virtual device_t *bus_root() override;
@@ -255,23 +268,47 @@ protected:
void regenerate_mapping();
- address_space *memory_space, *io_space;
-
uint64_t memory_window_start, memory_window_end, memory_offset;
uint64_t io_window_start, io_window_end, io_offset;
uint32_t config_address;
+
+private:
+ address_space *memory_space, *io_space;
};
+using pci_pin_mapper = device_delegate<int (int)>;
+using pci_irq_handler = device_delegate<void (int, int)>;
+
class pci_root_device : public device_t {
public:
pci_root_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ void irq_pin_w(int pin, int state);
+ void irq_w(int line, int state);
+
+ void set_pin_mapper(pci_pin_mapper &&mapper) { m_pin_mapper = std::move(mapper); }
+ void set_irq_handler(pci_irq_handler &&handler) { m_irq_handler = std::move(handler); }
+
+ address_space *get_pci_busmaster_space() const { return m_pci_busmaster_space; }
+
+ void set_pci_busmaster_space(address_space *space) { m_pci_busmaster_space = space; }
+
protected:
virtual void device_start() override;
virtual void device_reset() override;
+
+private:
+ pci_pin_mapper m_pin_mapper;
+ pci_irq_handler m_irq_handler;
+ address_space *m_pci_busmaster_space;
};
+address_space *pci_device::get_pci_busmaster_space() const
+{
+ return m_pci_root->get_pci_busmaster_space();
+}
+
DECLARE_DEVICE_TYPE(PCI_ROOT, pci_root_device)
DECLARE_DEVICE_TYPE(PCI_BRIDGE, pci_bridge_device)
diff --git a/src/devices/machine/pci9050.cpp b/src/devices/machine/pci9050.cpp
index 9f5c63c621e..c3425d01a4b 100644
--- a/src/devices/machine/pci9050.cpp
+++ b/src/devices/machine/pci9050.cpp
@@ -41,7 +41,7 @@ void pci9050_device::map(address_map &map)
pci9050_device::pci9050_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: pci_device(mconfig, PCI9050, tag, owner, clock)
- , m_user_input_handler(*this), m_user_output_handler(*this)
+ , m_user_input_handler(*this, 0), m_user_output_handler(*this)
{
set_ids(0x10b59050, 0x01, 0x06800000, 0x10b59050);
for(int i=0; i<4; i++) {
@@ -69,8 +69,6 @@ void pci9050_device::device_start()
else
add_map(0, M_MEM | M_DISABLED, address_map_constructor(), nullptr);
- m_user_input_handler.resolve();
- m_user_output_handler.resolve();
// Save states
save_item(NAME(m_lasrr));
save_item(NAME(m_lasba));
@@ -267,7 +265,7 @@ void pci9050_device::intcsr_w(uint32_t data)
uint32_t pci9050_device::cntrl_r()
{
- if (!m_user_input_handler.isnull())
+ if (!m_user_input_handler.isunset())
{
int readData = m_user_input_handler();
for (int userIndex = 0; userIndex < 4; userIndex++)
@@ -288,7 +286,7 @@ void pci9050_device::cntrl_w(uint32_t data)
remap_rom();
if ((oldData ^ m_cntrl) & 0x3000)
remap_cb();
- if (!m_user_output_handler.isnull()) {
+ if (!m_user_output_handler.isunset()) {
int userData = 0;
for (int userIndex = 0; userIndex < 4; userIndex++)
userData |= ((m_cntrl >> (2 + userIndex * 3)) & 1) << userIndex;
diff --git a/src/devices/machine/pckeybrd.cpp b/src/devices/machine/pckeybrd.cpp
index 7062c59c8fa..3e59b741798 100644
--- a/src/devices/machine/pckeybrd.cpp
+++ b/src/devices/machine/pckeybrd.cpp
@@ -24,8 +24,10 @@
/* AT keyboard documentation comes from www.beyondlogic.org and HelpPC documentation */
-/* to enable logging of keyboard read/writes */
-#define LOG_KEYBOARD 0
+/* for logging of keyboard read/writes */
+#define LOG_KEYBOARD (1U << 1)
+#define VERBOSE (0)
+#include "logmacro.h"
/*
@@ -300,7 +302,7 @@ at_keyboard_device::at_keyboard_device(const machine_config &mconfig, const char
}
-void pc_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pc_keyboard_device::poll_keys)
{
polling();
if(!charqueue_empty())
@@ -315,26 +317,27 @@ void pc_keyboard_device::device_start()
save_item(NAME(m_on));
save_item(NAME(m_head));
save_item(NAME(m_tail));
- save_pointer(NAME(m_queue), ARRAY_LENGTH(m_queue));
- save_pointer(NAME(m_make), ARRAY_LENGTH(m_make));
+ save_item(NAME(m_queue));
+ save_item(NAME(m_make));
- memset(m_make, 0, sizeof(m_make));
+ std::fill(std::begin(m_make), std::end(m_make), 0);
- machine().ioport().natkeyboard().configure(
+ machine().natkeyboard().configure(
ioport_queue_chars_delegate(&pc_keyboard_device::queue_chars, this),
ioport_accept_char_delegate(&pc_keyboard_device::accept_char, this),
ioport_charqueue_empty_delegate(&pc_keyboard_device::charqueue_empty, this));
- m_out_keypress_func.resolve_safe();
- m_keyboard_timer = timer_alloc();
+ m_keyboard_timer = timer_alloc(FUNC(at_keyboard_device::poll_keys), this);
}
void at_keyboard_device::device_start()
{
- save_item(NAME(m_scan_code_set));
- save_item(NAME(m_input_state));
pc_keyboard_device::device_start();
+
m_leds.resolve();
+
+ save_item(NAME(m_scan_code_set));
+ save_item(NAME(m_input_state));
}
void pc_keyboard_device::device_reset()
@@ -378,12 +381,11 @@ void pc_keyboard_device::enable(int state)
/* insert a code into the buffer */
void pc_keyboard_device::queue_insert(uint8_t data)
{
- if (LOG_KEYBOARD)
- logerror("keyboard queueing %.2x\n",data);
+ LOGMASKED(LOG_KEYBOARD, "keyboard queueing %.2x\n", data);
m_queue[m_head] = data;
m_head++;
- m_head %= ARRAY_LENGTH(m_queue);
+ m_head %= std::size(m_queue);
}
@@ -392,7 +394,7 @@ int pc_keyboard_device::queue_size(void)
int queue_size;
queue_size = m_head - m_tail;
if (queue_size < 0)
- queue_size += ARRAY_LENGTH(m_queue);
+ queue_size += std::size(m_queue);
return queue_size;
}
@@ -622,11 +624,10 @@ uint8_t pc_keyboard_device::read()
data = m_queue[m_tail];
- if (LOG_KEYBOARD)
- logerror("read(): Keyboard Read 0x%02x\n",data);
+ LOGMASKED(LOG_KEYBOARD, "read(): Keyboard Read 0x%02x\n", data);
m_tail++;
- m_tail %= ARRAY_LENGTH(m_queue);
+ m_tail %= std::size(m_queue);
return data;
}
@@ -690,8 +691,7 @@ SeeAlso: #P046
void at_keyboard_device::write(uint8_t data)
{
- if (LOG_KEYBOARD)
- logerror("keyboard write %.2x\n",data);
+ LOGMASKED(LOG_KEYBOARD, "keyboard write %.2x\n", data);
switch (m_input_state)
{
diff --git a/src/devices/machine/pckeybrd.h b/src/devices/machine/pckeybrd.h
index 8eeb2118b6b..e52981b10c4 100644
--- a/src/devices/machine/pckeybrd.h
+++ b/src/devices/machine/pckeybrd.h
@@ -40,7 +40,9 @@ protected:
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(poll_keys);
+
void queue_insert(uint8_t data);
void clear_buffer();
diff --git a/src/devices/machine/pdc.cpp b/src/devices/machine/pdc.cpp
index cf23be8eaa5..73aca052620 100644
--- a/src/devices/machine/pdc.cpp
+++ b/src/devices/machine/pdc.cpp
@@ -244,14 +244,6 @@ static void pdc_harddisks(device_slot_interface &device)
}
//-------------------------------------------------
-// FLOPPY_FORMATS( floppy_formats )
-//-------------------------------------------------
-
-FLOPPY_FORMATS_MEMBER( pdc_device::floppy_formats )
- FLOPPY_PC_FORMAT
-FLOPPY_FORMATS_END
-
-//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
@@ -269,7 +261,7 @@ void pdc_device::device_add_mconfig(machine_config &config)
m_fdc->drq_wr_callback().set(m_dma8237, FUNC(am9517a_device::dreq0_w)); //.invert();
// Floppy disk drive
- FLOPPY_CONNECTOR(config, FDC_TAG":0", pdc_floppies, "35hd", pdc_device::floppy_formats);
+ FLOPPY_CONNECTOR(config, FDC_TAG":0", pdc_floppies, "35hd", floppy_image_device::default_pc_floppy_formats);
/* DMA Controller - Intel P8237A-5 */
/* Channel 0: uPD765a Floppy Disk Controller */
@@ -312,7 +304,7 @@ pdc_device::pdc_device(const machine_config &mconfig, const char *tag, device_t
m_fdc(*this, FDC_TAG),
m_hdc9224(*this, HDC_TAG),
m_pdc_ram(*this, "pdc_ram"),
- m_m68k_r_cb(*this),
+ m_m68k_r_cb(*this, 0),
m_m68k_w_cb(*this)
{
}
@@ -323,10 +315,6 @@ pdc_device::pdc_device(const machine_config &mconfig, const char *tag, device_t
void pdc_device::device_start()
{
- /* Resolve callbacks */
- m_m68k_r_cb.resolve_safe(0);
- m_m68k_w_cb.resolve_safe();
-
/* Save States */
save_item(NAME(reg_p0));
save_item(NAME(reg_p1));
diff --git a/src/devices/machine/pdc.h b/src/devices/machine/pdc.h
index a80b97c5fa8..9a9eb1d4d42 100644
--- a/src/devices/machine/pdc.h
+++ b/src/devices/machine/pdc.h
@@ -14,7 +14,6 @@
#include "cpu/z80/z80.h"
#include "machine/upd765.h"
#include "machine/am9517a.h"
-#include "formats/pc_dsk.h"
#include "machine/hdc92x4.h"
#include "imagedev/mfmhd.h"
@@ -77,7 +76,6 @@ private:
void m68k_dma_w(uint8_t data);
void fdc_irq(int state);
- DECLARE_FLOPPY_FORMATS( floppy_formats );
uint8_t p0_7_r(offs_t offset);
void p0_7_w(offs_t offset, uint8_t data);
diff --git a/src/devices/machine/phi.cpp b/src/devices/machine/phi.cpp
index c131f2f3191..174b00be1ad 100644
--- a/src/devices/machine/phi.cpp
+++ b/src/devices/machine/phi.cpp
@@ -48,12 +48,12 @@ namespace {
return (T)1U << n;
}
- template<typename T> void BIT_CLR(T& w , unsigned n)
+ template<typename T> void BIT_CLR(T& w, unsigned n)
{
w &= ~BIT_MASK<T>(n);
}
- template<typename T> void BIT_SET(T& w , unsigned n)
+ template<typename T> void BIT_SET(T& w, unsigned n)
{
w |= BIT_MASK<T>(n);
}
@@ -187,14 +187,14 @@ constexpr uint8_t CONTROLLER_ADDR = 0x1e; // PHI always has this address when
DEFINE_DEVICE_TYPE(PHI, phi_device, "hp_phi", "HP Processor-to-HPIB Interface")
// Constructors
-phi_device::phi_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- m_dio_read_func(*this),
- m_dio_write_func(*this),
- m_signal_wr_fns(*this),
- m_int_write_func(*this),
- m_dmarq_write_func(*this),
- m_sys_cntrl_read_func(*this)
+phi_device::phi_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_dio_read_func(*this, 0xff),
+ m_dio_write_func(*this),
+ m_signal_wr_fns(*this),
+ m_int_write_func(*this),
+ m_dmarq_write_func(*this),
+ m_sys_cntrl_read_func(*this, 0)
{
}
@@ -203,44 +203,44 @@ phi_device::phi_device(const machine_config &mconfig, const char *tag, device_t
{
}
-WRITE_LINE_MEMBER(phi_device::eoi_w)
+void phi_device::eoi_w(int state)
{
- set_ext_signal(PHI_488_EOI , state);
+ set_ext_signal(PHI_488_EOI, state);
}
-WRITE_LINE_MEMBER(phi_device::dav_w)
+void phi_device::dav_w(int state)
{
- set_ext_signal(PHI_488_DAV , state);
+ set_ext_signal(PHI_488_DAV, state);
}
-WRITE_LINE_MEMBER(phi_device::nrfd_w)
+void phi_device::nrfd_w(int state)
{
- set_ext_signal(PHI_488_NRFD , state);
+ set_ext_signal(PHI_488_NRFD, state);
}
-WRITE_LINE_MEMBER(phi_device::ndac_w)
+void phi_device::ndac_w(int state)
{
- set_ext_signal(PHI_488_NDAC , state);
+ set_ext_signal(PHI_488_NDAC, state);
}
-WRITE_LINE_MEMBER(phi_device::ifc_w)
+void phi_device::ifc_w(int state)
{
- set_ext_signal(PHI_488_IFC , state);
+ set_ext_signal(PHI_488_IFC, state);
}
-WRITE_LINE_MEMBER(phi_device::srq_w)
+void phi_device::srq_w(int state)
{
- set_ext_signal(PHI_488_SRQ , state);
+ set_ext_signal(PHI_488_SRQ, state);
}
-WRITE_LINE_MEMBER(phi_device::atn_w)
+void phi_device::atn_w(int state)
{
- set_ext_signal(PHI_488_ATN , state);
+ set_ext_signal(PHI_488_ATN, state);
}
-WRITE_LINE_MEMBER(phi_device::ren_w)
+void phi_device::ren_w(int state)
{
- set_ext_signal(PHI_488_REN , state);
+ set_ext_signal(PHI_488_REN, state);
}
void phi_device::bus_dio_w(uint8_t data)
@@ -248,27 +248,27 @@ void phi_device::bus_dio_w(uint8_t data)
update_pp();
}
-void phi_device::set_ext_signal(phi_488_signal_t signal , int state)
+void phi_device::set_ext_signal(phi_488_signal_t signal, int state)
{
state = !state;
- if (m_ext_signals[ signal ] != state) {
- m_ext_signals[ signal ] = state;
- LOG_NOISY("EXT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
- m_ext_signals[ PHI_488_EOI ] ,
- m_ext_signals[ PHI_488_DAV ] ,
- m_ext_signals[ PHI_488_NRFD ] ,
- m_ext_signals[ PHI_488_NDAC ] ,
- m_ext_signals[ PHI_488_IFC ] ,
- m_ext_signals[ PHI_488_SRQ ] ,
- m_ext_signals[ PHI_488_ATN ] ,
- m_ext_signals[ PHI_488_REN ]);
+ if (m_ext_signals[signal] != state) {
+ m_ext_signals[signal] = state;
+ LOG_NOISY("EXT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n",
+ m_ext_signals[PHI_488_EOI],
+ m_ext_signals[PHI_488_DAV],
+ m_ext_signals[PHI_488_NRFD],
+ m_ext_signals[PHI_488_NDAC],
+ m_ext_signals[PHI_488_IFC],
+ m_ext_signals[PHI_488_SRQ],
+ m_ext_signals[PHI_488_ATN],
+ m_ext_signals[PHI_488_REN]);
update_fsm();
}
}
void phi_device::reg16_w(offs_t offset, uint16_t data)
{
- int_reg_w(offset , data & REG_ALL_MASK);
+ int_reg_w(offset, data & REG_ALL_MASK);
}
uint16_t phi_device::reg16_r(offs_t offset)
@@ -330,13 +330,13 @@ uint16_t phi_device::reg16_r(offs_t offset)
((res & REG_D0D1_MASK) >> (REG_D0D1_SHIFT - REG_STATUS_D0D1_BIT));
}
- LOG_REG("R %u=%04x\n" , offset , res);
+ LOG_REG("R %u=%04x\n", offset, res);
return res;
}
void phi_device::reg8_w(offs_t offset, uint8_t data)
{
- int_reg_w(offset , data);
+ int_reg_w(offset, data);
}
uint8_t phi_device::reg8_r(offs_t offset)
@@ -374,15 +374,8 @@ void phi_device::device_start()
save_item(NAME(m_reg_address));
save_item(NAME(m_nba_origin));
- m_dio_read_func.resolve_safe(0xff);
- m_dio_write_func.resolve_safe();
- m_signal_wr_fns.resolve_all_safe();
- m_int_write_func.resolve_safe();
- m_dmarq_write_func.resolve_safe();
- m_sys_cntrl_read_func.resolve_safe(0);
-
- m_sh_dly_timer = timer_alloc(SH_DELAY_TMR_ID);
- m_c_dly_timer = timer_alloc(C_DELAY_TMR_ID);
+ m_sh_dly_timer = timer_alloc(FUNC(phi_device::delayed_update), this);
+ m_c_dly_timer = timer_alloc(FUNC(phi_device::delayed_update), this);
}
void phi_device::device_reset()
@@ -417,20 +410,20 @@ void phi_device::device_reset()
update_488();
}
-void phi_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(phi_device::delayed_update)
{
- LOG_NOISY("tmr %d enabled %d\n" , id , timer.enabled());
+ LOG_NOISY("tmr %d enabled\n", param);
update_fsm();
}
-void phi_device::int_reg_w(offs_t offset , uint16_t data)
+void phi_device::int_reg_w(offs_t offset, uint16_t data)
{
- if (BIT(m_reg_control , REG_CTRL_8BIT_PROC_BIT)) {
+ if (BIT(m_reg_control, REG_CTRL_8BIT_PROC_BIT)) {
// In 8-bit mode, D0/D1 come from status register
data = (data & REG_D08D15_MASK) | ((m_reg_status << (REG_D0D1_SHIFT - REG_STATUS_D0D1_BIT)) & REG_D0D1_MASK);
}
- LOG_REG("W %u=%04x\n" , offset , data);
+ LOG_REG("W %u=%04x\n", offset, data);
switch (offset) {
case REG_W_INT_COND:
@@ -457,7 +450,7 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
// Copy D0/D1 access bits into status register
m_reg_status = (m_reg_status & ~(3U << REG_STATUS_D0D1_BIT)) |
(data & (3U << REG_STATUS_D0D1_BIT));
- if (BIT(data , REG_STATUS_DATA_FREEZE_BIT) && m_fifo_in.empty()) {
+ if (BIT(data, REG_STATUS_DATA_FREEZE_BIT) && m_fifo_in.empty()) {
BIT_CLR(m_reg_status, REG_STATUS_DATA_FREEZE_BIT);
}
update_fsm();
@@ -466,17 +459,17 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
case REG_W_CONTROL:
// D0/D1/D15 are not mapped into register
m_reg_control = data & 0xfe;
- if (BIT(data , REG_CTRL_INIT_OFIFO_BIT)) {
+ if (BIT(data, REG_CTRL_INIT_OFIFO_BIT)) {
m_fifo_out.clear();
if (m_c_state == PHI_C_CSBS) {
// Take control asynchronously
m_c_state = PHI_C_CSWS;
- m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T7));
+ m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T7), 1);
}
}
if (m_loopback) {
// TODO: better?
- m_id_enabled = BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT);
+ m_id_enabled = BIT(m_reg_control, REG_CTRL_PP_RESPONSE_BIT);
}
update_fsm();
break;
@@ -485,18 +478,18 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
{
// No D0/D1 in register
data &= REG_D08D15_MASK;
- bool prev_ol = BIT(m_reg_address , REG_ADDR_ONLINE_BIT);
+ bool prev_ol = BIT(m_reg_address, REG_ADDR_ONLINE_BIT);
m_reg_address = data;
- bool current_ol = BIT(m_reg_address , REG_ADDR_ONLINE_BIT);
+ bool current_ol = BIT(m_reg_address, REG_ADDR_ONLINE_BIT);
m_sys_controller = !current_ol || m_sys_cntrl_read_func();
m_loopback = !current_ol;
if (!current_ol) {
// IDENTIFY is enabled by PP_RESPONSE bit in control register
- m_id_enabled = BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT);
+ m_id_enabled = BIT(m_reg_control, REG_CTRL_PP_RESPONSE_BIT);
} else if (!prev_ol) {
// Going on-line
pon_msg();
- m_id_enabled = BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT);
+ m_id_enabled = BIT(m_reg_control, REG_CTRL_PP_RESPONSE_BIT);
}
configure_pp_response();
if (prev_ol != current_ol) {
@@ -536,7 +529,7 @@ uint8_t phi_device::get_dio(void)
void phi_device::set_dio(uint8_t data)
{
if (data != m_dio) {
- LOG_NOISY("DIO=%02x\n" , data);
+ LOG_NOISY("DIO=%02x\n", data);
m_dio = data;
if (!m_loopback) {
m_dio_write_func(~data);
@@ -547,27 +540,27 @@ void phi_device::set_dio(uint8_t data)
bool phi_device::get_signal(phi_488_signal_t signal)
{
if (m_loopback) {
- return m_signals[ signal ];
+ return m_signals[signal];
} else {
- return m_ext_signals[ signal ];
+ return m_ext_signals[signal];
}
}
-void phi_device::set_signal(phi_488_signal_t signal , bool state)
+void phi_device::set_signal(phi_488_signal_t signal, bool state)
{
- if (state != m_signals[ signal ]) {
- m_signals[ signal ] = state;
- LOG_NOISY("INT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
- m_signals[ PHI_488_EOI ] ,
- m_signals[ PHI_488_DAV ] ,
- m_signals[ PHI_488_NRFD ] ,
- m_signals[ PHI_488_NDAC ] ,
- m_signals[ PHI_488_IFC ] ,
- m_signals[ PHI_488_SRQ ] ,
- m_signals[ PHI_488_ATN ] ,
- m_signals[ PHI_488_REN ]);
+ if (state != m_signals[signal]) {
+ m_signals[signal] = state;
+ LOG_NOISY("INT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n",
+ m_signals[PHI_488_EOI],
+ m_signals[PHI_488_DAV],
+ m_signals[PHI_488_NRFD],
+ m_signals[PHI_488_NDAC],
+ m_signals[PHI_488_IFC],
+ m_signals[PHI_488_SRQ],
+ m_signals[PHI_488_ATN],
+ m_signals[PHI_488_REN]);
if (!m_loopback) {
- m_signal_wr_fns[ signal ](!state);
+ m_signal_wr_fns[signal](!state);
}
}
}
@@ -598,7 +591,7 @@ void phi_device::update_488(void)
} else {
m_dio_write_func(~m_dio);
for (unsigned i = 0; i < PHI_488_SIGNAL_COUNT; i++) {
- m_signal_wr_fns[ i ](!m_signals[ i ]);
+ m_signal_wr_fns[i](!m_signals[i]);
}
}
}
@@ -612,13 +605,13 @@ void phi_device::update_fsm(void)
}
m_no_recursion = true;
- set_signal(PHI_488_IFC , m_sys_controller && BIT(m_reg_control , REG_CTRL_IFC_BIT));
- set_signal(PHI_488_REN , m_sys_controller && BIT(m_reg_control , REG_CTRL_REN_BIT));
+ set_signal(PHI_488_IFC, m_sys_controller && BIT(m_reg_control, REG_CTRL_IFC_BIT));
+ set_signal(PHI_488_REN, m_sys_controller && BIT(m_reg_control, REG_CTRL_REN_BIT));
// TODO: improve (see SR FSM)
// This is not entirely correct but it works for now (on HP64K, the only system
// where it's relevant)
- set_signal(PHI_488_SRQ , BIT(m_reg_control , REG_CTRL_SERVICE_REQ_BIT));
+ set_signal(PHI_488_SRQ, BIT(m_reg_control, REG_CTRL_SERVICE_REQ_BIT));
bool changed = true;
int prev_state;
@@ -628,10 +621,10 @@ void phi_device::update_fsm(void)
// TODO: SR FSM
// Loop until all changes settle
while (changed) {
- LOG_NOISY("SH %d AH %d T %d SPMS %d L %d SR %d PP %d PPR %u S %d C %d SA %d\n" ,
- m_sh_state , m_ah_state , m_t_state , m_t_spms , m_l_state , m_sr_state ,
- m_pp_state , m_ppr_msg , m_s_sense , m_c_state , m_sa_state);
- LOG_NOISY("O E/F=%d/%d I E/F=%d/%d\n" , m_fifo_out.empty() , m_fifo_out.full() , m_fifo_in.empty() , m_fifo_in.full());
+ LOG_NOISY("SH %d AH %d T %d SPMS %d L %d SR %d PP %d PPR %u S %d C %d SA %d\n",
+ m_sh_state, m_ah_state, m_t_state, m_t_spms, m_l_state, m_sr_state,
+ m_pp_state, m_ppr_msg, m_s_sense, m_c_state, m_sa_state);
+ LOG_NOISY("O E/F=%d/%d I E/F=%d/%d\n", m_fifo_out.empty(), m_fifo_out.full(), m_fifo_in.empty(), m_fifo_in.full());
changed = false;
// SH FSM
@@ -656,10 +649,10 @@ void phi_device::update_fsm(void)
break;
case PHI_SH_SGNS:
- if ((m_nba_origin = nba_msg(new_byte , new_eoi)) != NBA_NONE) {
+ if ((m_nba_origin = nba_msg(new_byte, new_eoi)) != NBA_NONE) {
m_sh_state = PHI_SH_SDYS;
- m_sh_dly_timer->adjust(attotime::from_nsec(DELAY_T1));
- LOG_NOISY("SH DLY enabled %d\n" , m_sh_dly_timer->enabled());
+ m_sh_dly_timer->adjust(attotime::from_nsec(DELAY_T1), 0);
+ LOG_NOISY("SH DLY enabled %d\n", m_sh_dly_timer->enabled());
}
break;
@@ -671,14 +664,14 @@ void phi_device::update_fsm(void)
case PHI_SH_STRS:
if (!get_signal(PHI_488_NDAC)) {
- LOG("%.6f TX %02x/%d\n" , machine().time().as_double() , m_dio , m_signals[ PHI_488_EOI ]);
+ LOG("%.6f TX %02x/%d\n", machine().time().as_double(), m_dio, m_signals[PHI_488_EOI]);
m_sh_state = PHI_SH_SGNS;
clear_nba((nba_origin_t)m_nba_origin);
}
break;
default:
- logerror("Invalid SH state %d\n" , m_sh_state);
+ logerror("Invalid SH state %d\n", m_sh_state);
m_sh_state = PHI_SH_SIDS;
}
}
@@ -690,9 +683,9 @@ void phi_device::update_fsm(void)
// EOI is controlled by SH & C FSMs
bool eoi_signal = false;
uint8_t dio_byte = 0;
- set_signal(PHI_488_DAV , m_sh_state == PHI_SH_STRS);
+ set_signal(PHI_488_DAV, m_sh_state == PHI_SH_STRS);
if (m_sh_state == PHI_SH_SDYS || m_sh_state == PHI_SH_STRS) {
- nba_msg(new_byte , new_eoi);
+ nba_msg(new_byte, new_eoi);
dio_byte = new_byte;
eoi_signal = new_eoi;
}
@@ -733,9 +726,9 @@ void phi_device::update_fsm(void)
uint8_t if_cmd = get_dio();
bool parity_ok = odd_parity(if_cmd);
if (!parity_ok) {
- BIT_SET(m_reg_int_cond , REG_INT_PARITY_ERR_BIT);
+ BIT_SET(m_reg_int_cond, REG_INT_PARITY_ERR_BIT);
}
- if (BIT(m_reg_control , REG_CTRL_PAR_FREEZE_BIT) && !parity_ok) {
+ if (BIT(m_reg_control, REG_CTRL_PAR_FREEZE_BIT) && !parity_ok) {
// With even parity and PARITY FREEZE set, command is ignored and
// AH FSM freezes in ACDS
m_ah_state = PHI_AH_ACDS_FROZEN;
@@ -746,7 +739,7 @@ void phi_device::update_fsm(void)
m_ah_state = PHI_AH_AWNS;
}
}
- } else if (byte_received(get_dio() , get_signal(PHI_488_EOI))) {
+ } else if (byte_received(get_dio(), get_signal(PHI_488_EOI))) {
m_ah_state = PHI_AH_AWNS;
}
break;
@@ -759,7 +752,7 @@ void phi_device::update_fsm(void)
break;
default:
- logerror("Invalid AH state %d\n" , m_ah_state);
+ logerror("Invalid AH state %d\n", m_ah_state);
m_ah_state = PHI_AH_AIDS;
}
}
@@ -767,8 +760,8 @@ void phi_device::update_fsm(void)
changed = true;
}
// AH outputs
- set_signal(PHI_488_NRFD , m_ah_state == PHI_AH_ANRS || m_ah_state == PHI_AH_ACDS || m_ah_state == PHI_AH_ACDS_FROZEN || m_ah_state == PHI_AH_AWNS);
- set_signal(PHI_488_NDAC , m_ah_state == PHI_AH_ANRS || m_ah_state == PHI_AH_ACRS || m_ah_state == PHI_AH_ACDS || m_ah_state == PHI_AH_ACDS_FROZEN);
+ set_signal(PHI_488_NRFD, m_ah_state == PHI_AH_ANRS || m_ah_state == PHI_AH_ACDS || m_ah_state == PHI_AH_ACDS_FROZEN || m_ah_state == PHI_AH_AWNS);
+ set_signal(PHI_488_NDAC, m_ah_state == PHI_AH_ANRS || m_ah_state == PHI_AH_ACRS || m_ah_state == PHI_AH_ACDS || m_ah_state == PHI_AH_ACDS_FROZEN);
// T FSM
prev_state = m_t_state;
@@ -828,7 +821,7 @@ void phi_device::update_fsm(void)
break;
default:
- logerror("Invalid T state %d\n" , m_t_state);
+ logerror("Invalid T state %d\n", m_t_state);
m_t_state = PHI_T_TIDS;
}
}
@@ -862,7 +855,7 @@ void phi_device::update_fsm(void)
break;
default:
- logerror("Invalid L state %d\n" , m_l_state);
+ logerror("Invalid L state %d\n", m_l_state);
m_l_state = PHI_L_LIDS;
}
}
@@ -897,15 +890,15 @@ void phi_device::update_fsm(void)
break;
default:
- logerror("Invalid PP state %d\n" , m_pp_state);
+ logerror("Invalid PP state %d\n", m_pp_state);
m_pp_state = PHI_PP_PPIS;
}
if (m_pp_state != prev_state) {
changed = true;
}
// PP outputs
- if (m_pp_state == PHI_PP_PPAS && m_s_sense == !!BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT)) {
- LOG("%.6f PP %u\n" , machine().time().as_double() , m_ppr_msg);
+ if (m_pp_state == PHI_PP_PPAS && m_s_sense == !!BIT(m_reg_control, REG_CTRL_PP_RESPONSE_BIT)) {
+ LOG("%.6f PP %u\n", machine().time().as_double(), m_ppr_msg);
dio_byte |= BIT_MASK<uint8_t>(m_ppr_msg);
}
@@ -931,7 +924,7 @@ void phi_device::update_fsm(void)
case PHI_C_CACS:
// If there are ifcmds to send, just stay in CACS
// else wait for SH to finish its current transfer then decide what to do
- if (nba_msg(new_byte , new_eoi) != NBA_CMD_FROM_OFIFO &&
+ if (nba_msg(new_byte, new_eoi) != NBA_CMD_FROM_OFIFO &&
m_sh_state != PHI_SH_STRS && m_sh_state != PHI_SH_SDYS) {
if (!m_fifo_out.empty()) {
// Possible cases
@@ -953,14 +946,14 @@ void phi_device::update_fsm(void)
case PHI_C_CPPS:
if (!rpp_msg()) {
m_c_state = PHI_C_CAWS;
- m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T9));
+ m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T9), 1);
}
break;
case PHI_C_CSBS:
if (tcs_msg() && m_ah_state == PHI_AH_ANRS) {
m_c_state = PHI_C_CSHS;
- m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T10));
+ m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T10), 1);
}
break;
@@ -968,7 +961,7 @@ void phi_device::update_fsm(void)
// tcs_msg cannot go false here
if (!m_c_dly_timer->enabled()) {
m_c_state = PHI_C_CSWS;
- m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T7));
+ m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T7), 1);
}
break;
@@ -990,12 +983,12 @@ void phi_device::update_fsm(void)
case PHI_C_CSWS:
if (m_t_state == PHI_T_TADS || !m_c_dly_timer->enabled()) {
m_c_state = PHI_C_CAWS;
- m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T9));
+ m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T9), 1);
}
break;
default:
- logerror("Invalid C state %d\n" , m_c_state);
+ logerror("Invalid C state %d\n", m_c_state);
m_c_state = PHI_C_CIDS;
}
}
@@ -1003,11 +996,11 @@ void phi_device::update_fsm(void)
changed = true;
}
// C outputs
- set_signal(PHI_488_ATN , m_c_state == PHI_C_CACS ||
+ set_signal(PHI_488_ATN, m_c_state == PHI_C_CACS ||
m_c_state == PHI_C_CPPS || m_c_state == PHI_C_CSWS ||
m_c_state == PHI_C_CAWS || m_c_state == PHI_C_CTRS);
eoi_signal = eoi_signal || m_c_state == PHI_C_CPPS;
- set_signal(PHI_488_EOI , eoi_signal);
+ set_signal(PHI_488_EOI, eoi_signal);
set_dio(dio_byte);
}
@@ -1035,7 +1028,7 @@ void phi_device::update_fsm(void)
}
m_reg_int_cond &= ~REG_INT_STATE_MASK;
if (m_fifo_out.empty()) {
- BIT_SET(m_reg_int_cond , REG_INT_FIFO_IDLE_BIT);
+ BIT_SET(m_reg_int_cond, REG_INT_FIFO_IDLE_BIT);
}
if (!m_fifo_in.empty()) {
BIT_SET(m_reg_int_cond, REG_INT_FIFO_AV_BIT);
@@ -1053,7 +1046,7 @@ void phi_device::update_fsm(void)
m_no_recursion = false;
}
-phi_device::nba_origin_t phi_device::nba_msg(uint8_t& new_byte , bool& new_eoi) const
+phi_device::nba_origin_t phi_device::nba_msg(uint8_t& new_byte, bool& new_eoi) const
{
if (controller_in_charge() && m_c_state == PHI_C_CACS && !m_fifo_out.empty()) {
uint16_t word = m_fifo_out.peek();
@@ -1070,14 +1063,14 @@ phi_device::nba_origin_t phi_device::nba_msg(uint8_t& new_byte , bool& new_eoi)
switch (m_t_state) {
case PHI_T_TACS:
- if (!BIT(m_reg_status , REG_STATUS_DATA_FREEZE_BIT) &&
- !BIT(m_reg_int_cond , REG_INT_DEV_CLEAR_BIT) &&
+ if (!BIT(m_reg_status, REG_STATUS_DATA_FREEZE_BIT) &&
+ !BIT(m_reg_int_cond, REG_INT_DEV_CLEAR_BIT) &&
!m_fifo_out.empty()) {
uint16_t word = m_fifo_out.peek();
- if (!BIT(word , REG_OFIFO_SPECIAL_BIT)) {
+ if (!BIT(word, REG_OFIFO_SPECIAL_BIT)) {
// Talker sends a data byte
new_byte = (uint8_t)word;
- new_eoi = BIT(word , REG_OFIFO_END_BIT);
+ new_eoi = BIT(word, REG_OFIFO_END_BIT);
return NBA_BYTE_FROM_OFIFO;
}
}
@@ -1131,7 +1124,7 @@ void phi_device::clear_nba(nba_origin_t origin)
bool phi_device::if_cmd_received(uint8_t byte)
{
- LOG("%.6f RX cmd: %02x\n" , machine().time().as_double() , byte);
+ LOG("%.6f RX cmd: %02x\n", machine().time().as_double(), byte);
bool accepted = true;
@@ -1264,9 +1257,9 @@ bool phi_device::if_cmd_received(uint8_t byte)
case PHI_SA_PACS:
if ((byte & IFCMD_PPX_MASK) == IFCMD_PPE_VALUE && m_pp_state == PHI_PP_PPIS) {
// PPE
- m_s_sense = BIT(byte , IFCMD_PPE_S_BIT);
+ m_s_sense = BIT(byte, IFCMD_PPE_S_BIT);
m_ppr_msg = byte & IFCMD_PPE_PPR_MASK;
- LOG("PPE s=%d ppr=%u\n" , m_s_sense , m_ppr_msg);
+ LOG("PPE s=%d ppr=%u\n", m_s_sense, m_ppr_msg);
m_pp_state = PHI_PP_PPSS;
} else if ((byte & IFCMD_PPX_MASK) == IFCMD_PPD_VALUE && m_pp_state == PHI_PP_PPSS) {
// PPD
@@ -1277,7 +1270,7 @@ bool phi_device::if_cmd_received(uint8_t byte)
case PHI_SA_TPAS:
case PHI_SA_LPAS:
// command is a secondary address after MTA or MLA
- if (m_fifo_in.full() || BIT(m_reg_int_cond , REG_INT_DEV_CLEAR_BIT)) {
+ if (m_fifo_in.full() || BIT(m_reg_int_cond, REG_INT_DEV_CLEAR_BIT)) {
// No room for secondary address in FIFO, stall handshake
accepted = false;
} else {
@@ -1304,7 +1297,7 @@ bool phi_device::if_cmd_received(uint8_t byte)
return accepted;
}
-bool phi_device::byte_received(uint8_t byte , bool eoi)
+bool phi_device::byte_received(uint8_t byte, bool eoi)
{
// Start with D0/D1 = 00
uint16_t word = byte;
@@ -1321,7 +1314,7 @@ bool phi_device::byte_received(uint8_t byte , bool eoi)
// Monitoring bytes being transferred on the bus
if (eoi) {
end_of_transfer = true;
- } else if (!BIT(be_word , REG_OFIFO_LF_INH_BIT) && byte == 0x0a) {
+ } else if (!BIT(be_word, REG_OFIFO_LF_INH_BIT) && byte == 0x0a) {
// LF received -> D0/D1 = 11
word |= REG_IFIFO_LAST_MASK;
end_of_transfer = true;
@@ -1332,10 +1325,10 @@ bool phi_device::byte_received(uint8_t byte , bool eoi)
}
}
- LOG("%.6f RX word:%04x\n" , machine().time().as_double() , word);
+ LOG("%.6f RX word:%04x\n", machine().time().as_double(), word);
if (m_l_state == PHI_L_LACS) {
- if (m_fifo_in.full() || BIT(m_reg_int_cond , REG_INT_DEV_CLEAR_BIT)) {
+ if (m_fifo_in.full() || BIT(m_reg_int_cond, REG_INT_DEV_CLEAR_BIT)) {
// No room for received byte, stall handshake
LOG_NOISY("..stalled\n");
return false;
@@ -1366,12 +1359,12 @@ void phi_device::rx_n_data_freeze(uint16_t word)
bool phi_device::ton_msg(void) const
{
- return BIT(m_reg_address , REG_ADDR_TA_BIT);
+ return BIT(m_reg_address, REG_ADDR_TA_BIT);
}
bool phi_device::lon_msg(void) const
{
- return BIT(m_reg_address , REG_ADDR_LA_BIT);
+ return BIT(m_reg_address, REG_ADDR_LA_BIT);
}
bool phi_device::odd_parity(uint8_t byte) const
@@ -1401,7 +1394,7 @@ bool phi_device::tcs_msg(void) const
// * There's an interface command to be sent at head of OFIFO
return (m_c_state == PHI_C_CSBS || m_c_state == PHI_C_CSHS || m_c_state == PHI_C_CSWS) &&
(rpp_msg() ||
- nba_msg(new_byte , new_eoi) == NBA_CMD_FROM_OFIFO);
+ nba_msg(new_byte, new_eoi) == NBA_CMD_FROM_OFIFO);
}
bool phi_device::rpp_msg(void) const
@@ -1437,9 +1430,9 @@ void phi_device::update_pp()
{
if (m_c_state == PHI_C_CPPS) {
if (m_fifo_in.empty() && get_pp_response()) {
- BIT_SET(m_reg_int_cond , REG_INT_PP_RESPONSE_BIT);
+ BIT_SET(m_reg_int_cond, REG_INT_PP_RESPONSE_BIT);
} else {
- BIT_CLR(m_reg_int_cond , REG_INT_PP_RESPONSE_BIT);
+ BIT_CLR(m_reg_int_cond, REG_INT_PP_RESPONSE_BIT);
}
update_interrupt();
}
@@ -1451,7 +1444,7 @@ void phi_device::update_interrupt()
bool int_line = false;
if (int_pending) {
BIT_SET(m_reg_int_cond, REG_INT_PENDING_BIT);
- if (BIT(m_reg_int_mask , REG_INT_PENDING_BIT)) {
+ if (BIT(m_reg_int_mask, REG_INT_PENDING_BIT)) {
int_line = true;
}
} else {
@@ -1459,7 +1452,7 @@ void phi_device::update_interrupt()
}
if (int_line != m_int_line) {
m_int_line = int_line;
- LOG_INT("INT %d\n" , m_int_line);
+ LOG_INT("INT %d\n", m_int_line);
m_int_write_func(m_int_line);
}
}
@@ -1467,14 +1460,14 @@ void phi_device::update_interrupt()
void phi_device::update_dmarq()
{
bool new_dmarq_line;
- if (BIT(m_reg_control , REG_CTRL_DMA_FIFO_BIT)) {
- new_dmarq_line = BIT(m_reg_int_cond , REG_INT_FIFO_ROOM_BIT);
+ if (BIT(m_reg_control, REG_CTRL_DMA_FIFO_BIT)) {
+ new_dmarq_line = BIT(m_reg_int_cond, REG_INT_FIFO_ROOM_BIT);
} else {
- new_dmarq_line = BIT(m_reg_int_cond , REG_INT_FIFO_AV_BIT);
+ new_dmarq_line = BIT(m_reg_int_cond, REG_INT_FIFO_AV_BIT);
}
if (new_dmarq_line != m_dmarq_line) {
m_dmarq_line = new_dmarq_line;
- LOG_INT("DRQ %d\n" , m_dmarq_line);
+ LOG_INT("DRQ %d\n", m_dmarq_line);
m_dmarq_write_func(m_dmarq_line);
}
}
diff --git a/src/devices/machine/phi.h b/src/devices/machine/phi.h
index 755f073a2d9..292c5d45f9b 100644
--- a/src/devices/machine/phi.h
+++ b/src/devices/machine/phi.h
@@ -36,14 +36,14 @@ public:
auto dio_read_cb() { return m_dio_read_func.bind(); }
auto dio_write_cb() { return m_dio_write_func.bind(); }
// Set write callbacks to access uniline signals on IEEE-488
- auto eoi_write_cb() { return m_signal_wr_fns[ PHI_488_EOI ].bind(); }
- auto dav_write_cb() { return m_signal_wr_fns[ PHI_488_DAV ].bind(); }
- auto nrfd_write_cb() { return m_signal_wr_fns[ PHI_488_NRFD ].bind(); }
- auto ndac_write_cb() { return m_signal_wr_fns[ PHI_488_NDAC ].bind(); }
- auto ifc_write_cb() { return m_signal_wr_fns[ PHI_488_IFC ].bind(); }
- auto srq_write_cb() { return m_signal_wr_fns[ PHI_488_SRQ ].bind(); }
- auto atn_write_cb() { return m_signal_wr_fns[ PHI_488_ATN ].bind(); }
- auto ren_write_cb() { return m_signal_wr_fns[ PHI_488_REN ].bind(); }
+ auto eoi_write_cb() { return m_signal_wr_fns[PHI_488_EOI].bind(); }
+ auto dav_write_cb() { return m_signal_wr_fns[PHI_488_DAV].bind(); }
+ auto nrfd_write_cb() { return m_signal_wr_fns[PHI_488_NRFD].bind(); }
+ auto ndac_write_cb() { return m_signal_wr_fns[PHI_488_NDAC].bind(); }
+ auto ifc_write_cb() { return m_signal_wr_fns[PHI_488_IFC].bind(); }
+ auto srq_write_cb() { return m_signal_wr_fns[PHI_488_SRQ].bind(); }
+ auto atn_write_cb() { return m_signal_wr_fns[PHI_488_ATN].bind(); }
+ auto ren_write_cb() { return m_signal_wr_fns[PHI_488_REN].bind(); }
// Set write callback for INT signal
auto int_write_cb() { return m_int_write_func.bind(); }
// Set write callback for DMARQ signal
@@ -51,18 +51,18 @@ public:
// Set read callback for SYS_CNTRL signal
auto sys_cntrl_read_cb() { return m_sys_cntrl_read_func.bind(); }
- 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);
+ void eoi_w(int state);
+ void dav_w(int state);
+ void nrfd_w(int state);
+ void ndac_w(int state);
+ void ifc_w(int state);
+ void srq_w(int state);
+ void atn_w(int state);
+ void ren_w(int state);
void bus_dio_w(uint8_t data);
- void set_ext_signal(phi_488_signal_t signal , int state);
+ void set_ext_signal(phi_488_signal_t signal, int state);
// Register read/write
// Mapping of PHI register bits:
@@ -95,7 +95,8 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(delayed_update);
private:
// Depth of inbound/outbound FIFOs
@@ -113,8 +114,8 @@ private:
// Internal copy of bus signals
// These signals have the "right" polarity (i.e. the opposite of bus signals, 1=L)
uint8_t m_dio;
- bool m_signals[ PHI_488_SIGNAL_COUNT ];
- bool m_ext_signals[ PHI_488_SIGNAL_COUNT ];
+ bool m_signals[PHI_488_SIGNAL_COUNT];
+ bool m_ext_signals[PHI_488_SIGNAL_COUNT];
bool m_no_recursion;
@@ -227,8 +228,8 @@ private:
uint16_t m_reg_2nd_id;
uint16_t m_reg_control;
uint16_t m_reg_address;
- util::fifo<uint16_t , FIFO_SIZE> m_fifo_in;
- util::fifo<uint16_t , FIFO_SIZE> m_fifo_out;
+ util::fifo<uint16_t, FIFO_SIZE> m_fifo_in;
+ util::fifo<uint16_t, FIFO_SIZE> m_fifo_out;
typedef enum {
NBA_NONE,
@@ -245,20 +246,20 @@ private:
emu_timer *m_sh_dly_timer;
emu_timer *m_c_dly_timer;
- void int_reg_w(offs_t offset , uint16_t data);
+ void int_reg_w(offs_t offset, uint16_t data);
uint8_t get_dio(void);
void set_dio(uint8_t data);
bool get_signal(phi_488_signal_t signal);
- void set_signal(phi_488_signal_t signal , bool state);
+ void set_signal(phi_488_signal_t signal, bool state);
void pon_msg(void);
void update_488(void);
void update_fsm(void);
- nba_origin_t nba_msg(uint8_t& new_byte , bool& new_eoi) const;
+ nba_origin_t nba_msg(uint8_t& new_byte, bool& new_eoi) const;
void clear_nba(nba_origin_t origin);
bool if_cmd_received(uint8_t byte);
- bool byte_received(uint8_t byte , bool eoi);
+ bool byte_received(uint8_t byte, bool eoi);
void rx_n_data_freeze(uint16_t word);
bool ton_msg(void) const;
bool lon_msg(void) const;
diff --git a/src/devices/machine/pic8259.cpp b/src/devices/machine/pic8259.cpp
index d5104413691..b641abe3c97 100644
--- a/src/devices/machine/pic8259.cpp
+++ b/src/devices/machine/pic8259.cpp
@@ -14,9 +14,8 @@
**********************************************************************/
#include "emu.h"
-#include "machine/pic8259.h"
+#include "pic8259.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_ICW (1U << 1)
#define LOG_OCW (1U << 2)
@@ -29,7 +28,7 @@
ALLOW_SAVE_TYPE(pic8259_device::state_t); // allow save_item on a non-fundamental type
-void pic8259_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pic8259_device::irq_timer_tick)
{
/* check the various IRQs */
for (int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
@@ -63,18 +62,15 @@ void pic8259_device::set_irq_line(int irq, int state)
{
uint8_t mask = (1 << irq);
- if (state)
+ if (state && !(m_irq_lines & mask))
{
/* setting IRQ line */
LOG("set_irq_line(): PIC set IR%d line\n", irq);
- if(m_level_trig_mode || (!m_level_trig_mode && !(m_irq_lines & mask)))
- {
- m_irr |= mask;
- }
+ m_irr |= mask;
m_irq_lines |= mask;
}
- else
+ else if (!state && (m_irq_lines & mask))
{
/* clearing IRQ line */
LOG("set_irq_line(): PIC cleared IR%d line\n", irq);
@@ -84,7 +80,7 @@ void pic8259_device::set_irq_line(int irq, int state)
}
if (m_inta_sequence == 0)
- set_timer();
+ m_irq_timer->adjust(attotime::zero);
}
@@ -99,13 +95,13 @@ uint8_t pic8259_device::acknowledge()
if (!machine().side_effects_disabled())
{
LOG("pic8259_acknowledge(): PIC acknowledge IR%d\n", m_current_level);
- if (!m_level_trig_mode)
+ if (!m_level_trig_mode && (!m_master || !(m_slave & mask)))
m_irr &= ~mask;
if (!m_auto_eoi)
m_isr |= mask;
- set_timer();
+ m_irq_timer->adjust(attotime::zero);
}
if ((m_cascade!=0) && (m_master!=0) && (mask & m_slave))
@@ -138,7 +134,7 @@ uint8_t pic8259_device::acknowledge()
LOG("pic8259_acknowledge(): PIC acknowledge IR%d\n", m_current_level);
uint8_t mask = 1 << m_current_level;
- if (!m_level_trig_mode)
+ if (!m_level_trig_mode && (!m_master || !(m_slave & mask)))
m_irr &= ~mask;
m_isr |= mask;
}
@@ -167,7 +163,7 @@ uint8_t pic8259_device::acknowledge()
m_inta_sequence = 0;
if (m_auto_eoi && m_current_level != -1)
m_isr &= ~(1 << m_current_level);
- set_timer();
+ m_irq_timer->adjust(attotime::zero);
}
if (m_cascade && m_master && m_current_level != -1 && BIT(m_slave, m_current_level))
return m_read_slave_ack_func(m_current_level);
@@ -199,13 +195,13 @@ uint8_t pic8259_device::read(offs_t offset)
{
data = 0x80 | m_current_level;
- if (!m_level_trig_mode)
+ if (!m_level_trig_mode && (!m_master || !BIT(m_slave, m_current_level)))
m_irr &= ~(1 << m_current_level);
if (!m_auto_eoi)
m_isr |= 1 << m_current_level;
- set_timer();
+ m_irq_timer->adjust(attotime::zero);
}
}
else
@@ -246,6 +242,7 @@ void pic8259_device::write(offs_t offset, uint8_t data)
m_imr = 0x00;
m_isr = 0x00;
m_irr = 0x00;
+ m_slave = 0x00;
m_level_trig_mode = (data & 0x08) ? 1 : 0;
m_vector_size = (data & 0x04) ? 1 : 0;
m_cascade = (data & 0x02) ? 0 : 1;
@@ -263,6 +260,7 @@ void pic8259_device::write(offs_t offset, uint8_t data)
/* write OCW3 */
LOGOCW("pic8259_device::write(): OCW3; data=0x%02X\n", data);
+ // TODO: special mask mode
m_ocw3 = data;
}
else if ((data & 0x18) == 0x00)
@@ -376,22 +374,7 @@ void pic8259_device::write(offs_t offset, uint8_t data)
}
break;
}
- set_timer();
-}
-
-
-//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void pic8259_device::device_resolve_objects()
-{
- // resolve callbacks
- m_out_int_func.resolve_safe();
- m_in_sp_func.resolve_safe(1);
- m_read_slave_ack_func.resolve_safe(0);
+ m_irq_timer->adjust(attotime::zero);
}
@@ -427,6 +410,8 @@ void pic8259_device::device_start()
save_item(NAME(m_inta_sequence));
m_inta_sequence = 0;
+
+ m_irq_timer = timer_alloc(FUNC(pic8259_device::irq_timer_tick), this);
}
@@ -464,12 +449,13 @@ void pic8259_device::device_reset()
DEFINE_DEVICE_TYPE(PIC8259, pic8259_device, "pic8259", "Intel 8259 PIC")
DEFINE_DEVICE_TYPE(V5X_ICU, v5x_icu_device, "v5x_icu", "NEC V5X ICU")
+DEFINE_DEVICE_TYPE(MK98PIC, mk98pic_device, "mk98pic", "Elektronika MK-98 PIC")
pic8259_device::pic8259_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, m_out_int_func(*this)
- , m_in_sp_func(*this)
- , m_read_slave_ack_func(*this)
+ , m_in_sp_func(*this, 1)
+ , m_read_slave_ack_func(*this, 0)
, m_irr(0)
, m_irq_lines(0)
, m_level_trig_mode(0)
@@ -485,3 +471,8 @@ v5x_icu_device::v5x_icu_device(const machine_config &mconfig, const char *tag, d
: pic8259_device(mconfig, V5X_ICU, tag, owner, clock)
{
}
+
+mk98pic_device::mk98pic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pic8259_device(mconfig, MK98PIC, tag, owner, clock)
+{
+}
diff --git a/src/devices/machine/pic8259.h b/src/devices/machine/pic8259.h
index a1f14b4c51d..0444cc5ae1d 100644
--- a/src/devices/machine/pic8259.h
+++ b/src/devices/machine/pic8259.h
@@ -41,35 +41,31 @@ public:
void write(offs_t offset, uint8_t data);
uint8_t acknowledge();
- DECLARE_WRITE_LINE_MEMBER( ir0_w ) { set_irq_line(0, state); }
- DECLARE_WRITE_LINE_MEMBER( ir1_w ) { set_irq_line(1, state); }
- DECLARE_WRITE_LINE_MEMBER( ir2_w ) { set_irq_line(2, state); }
- DECLARE_WRITE_LINE_MEMBER( ir3_w ) { set_irq_line(3, state); }
- DECLARE_WRITE_LINE_MEMBER( ir4_w ) { set_irq_line(4, state); }
- DECLARE_WRITE_LINE_MEMBER( ir5_w ) { set_irq_line(5, state); }
- DECLARE_WRITE_LINE_MEMBER( ir6_w ) { set_irq_line(6, state); }
- DECLARE_WRITE_LINE_MEMBER( ir7_w ) { set_irq_line(7, state); }
+ void ir0_w(int state) { set_irq_line(0, state); }
+ void ir1_w(int state) { set_irq_line(1, state); }
+ void ir2_w(int state) { set_irq_line(2, state); }
+ void ir3_w(int state) { set_irq_line(3, state); }
+ void ir4_w(int state) { set_irq_line(4, state); }
+ void ir5_w(int state) { set_irq_line(5, state); }
+ void ir6_w(int state) { set_irq_line(6, state); }
+ void ir7_w(int state) { set_irq_line(7, state); }
IRQ_CALLBACK_MEMBER(inta_cb);
protected:
pic8259_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual bool is_x86() const { return m_is_x86; }
-private:
- static constexpr device_timer_id TIMER_CHECK_IRQ = 0;
+ TIMER_CALLBACK_MEMBER(irq_timer_tick);
- inline void set_timer() { timer_set(attotime::zero, TIMER_CHECK_IRQ); }
+private:
void set_irq_line(int irq, int state);
-
enum class state_t : u8
{
ICW1,
@@ -83,6 +79,7 @@ private:
devcb_read_line m_in_sp_func;
devcb_read8 m_read_slave_ack_func;
+ emu_timer *m_irq_timer;
state_t m_state;
uint8_t m_isr;
@@ -127,7 +124,17 @@ protected:
virtual bool is_x86() const override { return true; }
};
+class mk98pic_device : public pic8259_device
+{
+public:
+ mk98pic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+protected:
+ virtual bool is_x86() const override { return true; }
+};
+
DECLARE_DEVICE_TYPE(PIC8259, pic8259_device)
DECLARE_DEVICE_TYPE(V5X_ICU, v5x_icu_device)
+DECLARE_DEVICE_TYPE(MK98PIC, mk98pic_device)
#endif // MAME_MACHINE_PIC8259_H
diff --git a/src/devices/machine/pit8253.cpp b/src/devices/machine/pit8253.cpp
index 7d0d4246b67..c75c8b6a9cc 100644
--- a/src/devices/machine/pit8253.cpp
+++ b/src/devices/machine/pit8253.cpp
@@ -21,7 +21,7 @@
*****************************************************************************/
#include "emu.h"
-#include "machine/pit8253.h"
+#include "pit8253.h"
/***************************************************************************
@@ -98,7 +98,6 @@ void pit8253_device::device_resolve_objects()
{
for (int timer = 0; timer < 3; timer++)
{
- m_out_handler[timer].resolve_safe();
m_counter[timer]->m_index = timer;
m_counter[timer]->m_clockin = m_clk[timer];
m_counter[timer]->m_clock_period = (m_clk[timer] != 0) ? attotime::from_hz(m_clk[timer]) : attotime::never;
@@ -112,8 +111,8 @@ void pit8253_device::device_resolve_objects()
void pit_counter_device::device_start()
{
- /* initialize timer */
- m_updatetimer = timer_alloc(TID_UPDATE);
+ /* initialize timers */
+ m_update_timer = timer_alloc(FUNC(pit_counter_device::update_tick), this);
adjust_timer(attotime::never);
/* set up state save values */
@@ -204,7 +203,7 @@ inline void pit_counter_device::adjust_timer(attotime target)
// if (target != m_next_update)
{
m_next_update = target;
- m_updatetimer->adjust(target - machine().time());
+ m_update_timer->adjust(target - machine().time());
}
}
@@ -293,9 +292,6 @@ void pit_counter_device::load_counter_value()
{
m_value = m_count;
m_null_count = 0;
-
- if (CTRL_MODE(m_control) == 3 && m_output == 0)
- m_value &= 0xfffe;
}
@@ -507,7 +503,7 @@ void pit_counter_device::simulate(int64_t elapsed_cycles)
}
}
- if (elapsed_cycles > 0 && m_phase == 3)
+ if (elapsed_cycles >= adjusted_value && m_phase == 3)
{
/* Reload counter, output goes high */
elapsed_cycles -= adjusted_value;
@@ -770,9 +766,8 @@ void pit_counter_device::update()
}
-/* We recycle bit 0 of m_value to hold the phase in mode 3 when count is
- odd. Since read commands in mode 3 always return even numbers, we need to
- mask this bit off. */
+/* Since read commands in mode 3 always return even numbers,
+ we need to mask bit 0 off. */
uint16_t pit_counter_device::masked_value() const
{
if ((CTRL_MODE(m_control) == 3) && (downcast<pit8253_device *>(owner())->m_type != pit_type::FE2010))
@@ -972,30 +967,15 @@ void pit8254_device::readback_command(uint8_t data)
m_counter[timer]->readback(read_command);
}
-void pit_counter_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(pit_counter_device::update_tick)
{
update();
- switch (id)
- {
- case TID_UPDATE:
- break;
-
- case TID_CONTROL:
- control_w_deferred(param);
- break;
-
- case TID_COUNT:
- count_w_deferred(param);
- break;
-
- case TID_GATE:
- gate_w_deferred(param);
- break;
- }
}
-void pit_counter_device::control_w_deferred(uint8_t data)
+TIMER_CALLBACK_MEMBER(pit_counter_device::control_w_deferred)
{
+ update();
+ uint8_t data = (uint8_t)param;
if (CTRL_ACCESS(data) == 0)
{
LOG1("write(): readback\n");
@@ -1017,8 +997,10 @@ void pit_counter_device::control_w_deferred(uint8_t data)
}
}
-void pit_counter_device::count_w_deferred(uint8_t data)
+TIMER_CALLBACK_MEMBER(pit_counter_device::count_w_deferred)
{
+ update();
+ uint8_t data = (uint8_t)param;
bool middle_of_a_cycle = (machine().time() > m_last_updated && m_clockin != 0);
switch (CTRL_ACCESS(m_control))
@@ -1102,8 +1084,10 @@ void pit8253_device::write(offs_t offset, uint8_t data)
m_counter[offset]->count_w(data);
}
-void pit_counter_device::gate_w_deferred(int state)
+TIMER_CALLBACK_MEMBER(pit_counter_device::gate_w_deferred)
{
+ update();
+ int state = param;
LOG2("gate_w(): state=%d\n", state);
if (state != m_gate)
diff --git a/src/devices/machine/pit8253.h b/src/devices/machine/pit8253.h
index c602a64a3d1..b9f67a30c02 100644
--- a/src/devices/machine/pit8253.h
+++ b/src/devices/machine/pit8253.h
@@ -42,14 +42,6 @@ class pit_counter_device : public device_t
friend class pit8253_device;
friend class pit8254_device;
- enum
- {
- TID_UPDATE = 1,
- TID_CONTROL,
- TID_COUNT,
- TID_GATE
- };
-
public:
// construction/destruction
pit_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -58,7 +50,6 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
inline uint32_t adjusted_count() const;
@@ -67,17 +58,18 @@ private:
void load_counter_value();
void set_output(int output);
void simulate(int64_t elapsed_cycles);
+ TIMER_CALLBACK_MEMBER(update_tick);
void update();
uint16_t masked_value() const;
uint8_t read();
void load_count(uint16_t newcount);
void readback(int command);
- void control_w(uint8_t data) { synchronize(TID_CONTROL, data); }
- void control_w_deferred(uint8_t data);
- void count_w(uint8_t data) { synchronize(TID_COUNT, data); }
- void count_w_deferred(uint8_t data);
- void gate_w(int state) { synchronize(TID_GATE, state); }
- void gate_w_deferred(int state);
+ void control_w(uint8_t data) { machine().scheduler().synchronize(timer_expired_delegate(FUNC(pit_counter_device::control_w_deferred), this), data); }
+ TIMER_CALLBACK_MEMBER(control_w_deferred);
+ void count_w(uint8_t data) { machine().scheduler().synchronize(timer_expired_delegate(FUNC(pit_counter_device::count_w_deferred), this), data); }
+ TIMER_CALLBACK_MEMBER(count_w_deferred);
+ void gate_w(int state) { machine().scheduler().synchronize(timer_expired_delegate(FUNC(pit_counter_device::gate_w_deferred), this), state); }
+ TIMER_CALLBACK_MEMBER(gate_w_deferred);
void set_clock_signal(int state);
void set_clockin(double new_clockin);
@@ -90,7 +82,7 @@ private:
attotime m_last_updated; // time when last updated
attotime m_next_update; // time of next update
- emu_timer *m_updatetimer; // MAME timer to process updates
+ emu_timer *m_update_timer; // MAME timer to process updates
uint16_t m_value; // current counter value ("CE" in Intel docs)
uint16_t m_latch; // latched counter value ("OL" in Intel docs)
@@ -127,9 +119,9 @@ public:
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- WRITE_LINE_MEMBER(write_gate0) { m_counter[0]->gate_w(state); }
- WRITE_LINE_MEMBER(write_gate1) { m_counter[1]->gate_w(state); }
- WRITE_LINE_MEMBER(write_gate2) { m_counter[2]->gate_w(state); }
+ void write_gate0(int state) { m_counter[0]->gate_w(state); }
+ void write_gate1(int state) { m_counter[1]->gate_w(state); }
+ void write_gate2(int state) { m_counter[2]->gate_w(state); }
/* In the 8253/8254 the CLKx input lines can be attached to a regular clock
signal. Another option is to use the output from one timer as the input
@@ -141,9 +133,9 @@ public:
to 0 with pit8253_set_clockin and call pit8253_clkX_w to change
the state of the input CLKx signal.
*/
- WRITE_LINE_MEMBER(write_clk0) { m_counter[0]->set_clock_signal(state); }
- WRITE_LINE_MEMBER(write_clk1) { m_counter[1]->set_clock_signal(state); }
- WRITE_LINE_MEMBER(write_clk2) { m_counter[2]->set_clock_signal(state); }
+ void write_clk0(int state) { m_counter[0]->set_clock_signal(state); }
+ void write_clk1(int state) { m_counter[1]->set_clock_signal(state); }
+ void write_clk2(int state) { m_counter[2]->set_clock_signal(state); }
void set_clockin(int timer, double new_clockin) { m_counter[timer]->set_clockin(new_clockin); }
diff --git a/src/devices/machine/pla.cpp b/src/devices/machine/pla.cpp
index 7ad690b11cd..b74ba500fc8 100644
--- a/src/devices/machine/pla.cpp
+++ b/src/devices/machine/pla.cpp
@@ -11,7 +11,7 @@
#include "jedparse.h"
#include "plaparse.h"
-#define LOG_TERMS (1 << 0U)
+#define LOG_TERMS (1U << 1)
//#define VERBOSE (LOG_TERMS)
#include "logmacro.h"
@@ -108,18 +108,22 @@ int pla_device::parse_fusemap()
int result = JEDERR_NONE;
// read pla file
- switch (m_format)
+ auto file = util::ram_read(m_region->base(), m_region->bytes());
+ if (file)
{
+ switch (m_format)
+ {
case FMT::JEDBIN:
- result = jedbin_parse(m_region->base(), m_region->bytes(), &jed);
+ result = jedbin_parse(*file, &jed);
break;
case FMT::BERKELEY:
- result = pla_parse(m_region->base(), m_region->bytes(), &jed);
+ result = pla_parse(*file, &jed);
break;
+ }
}
- if (result != JEDERR_NONE)
+ if (!file || result != JEDERR_NONE)
{
for (int p = 0; p < m_terms; p++)
{
diff --git a/src/devices/machine/ps2timer.cpp b/src/devices/machine/ps2timer.cpp
index 2f7111b1a22..667fed7622c 100644
--- a/src/devices/machine/ps2timer.cpp
+++ b/src/devices/machine/ps2timer.cpp
@@ -42,10 +42,10 @@ ps2_timer_device::ps2_timer_device(const machine_config &mconfig, const char *ta
void ps2_timer_device::device_start()
{
if (!m_compare_timer)
- m_compare_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ps2_timer_device::compare), this));
+ m_compare_timer = timer_alloc(FUNC(ps2_timer_device::compare), this);
if (!m_overflow_timer)
- m_overflow_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ps2_timer_device::overflow), this));
+ m_overflow_timer = timer_alloc(FUNC(ps2_timer_device::overflow), this);
}
void ps2_timer_device::device_reset()
diff --git a/src/devices/machine/psion_asic1.cpp b/src/devices/machine/psion_asic1.cpp
new file mode 100644
index 00000000000..f733c55a590
--- /dev/null
+++ b/src/devices/machine/psion_asic1.cpp
@@ -0,0 +1,484 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC1
+
+ ASIC1 is the main system controller chip for the SIBO architecture. It connects
+ directly to the 8086-based processor (i.e. the V30H) controlling all bus cycles
+ to and from the processor. This configuration effectively forms a micro-controller
+ like device that executes 8086 instruction codes. ASIC 1 is made up of a number of
+ functional blocks including a bus controller, a programmable timer, an eight input
+ interrupt controller, an LCD controller and the memory decoding circuitry.
+
+******************************************************************************/
+
+#include "emu.h"
+#include "psion_asic1.h"
+#include "screen.h"
+
+
+#define VERBOSE 0
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PSION_ASIC1, psion_asic1_device, "psion_asic1", "Psion ASIC1")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+psion_asic1_device::psion_asic1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PSION_ASIC1, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , device_video_interface(mconfig, *this)
+ , m_space_config("program", ENDIANNESS_LITTLE, 16, 20, 0)
+ , m_tick_timer(nullptr)
+ , m_frc_timer(nullptr)
+ , m_watchdog_timer(nullptr)
+ , m_int_cb(*this)
+ , m_nmi_cb(*this)
+ , m_frcovl_cb(*this)
+ , m_laptop_mode(false)
+{
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector psion_asic1_device::memory_space_config() const
+{
+ return space_config_vector{
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_asic1_device::device_start()
+{
+ m_space = &space();
+
+ m_tick_timer = timer_alloc(FUNC(psion_asic1_device::tick), this);
+ m_frc_timer = timer_alloc(FUNC(psion_asic1_device::frc), this);
+ m_watchdog_timer = timer_alloc(FUNC(psion_asic1_device::watchdog), this);
+
+ m_a1_status = 0x00;
+
+ save_item(NAME(m_a1_status));
+ save_item(NAME(m_a1_lcd_size));
+ save_item(NAME(m_a1_lcd_control));
+ save_item(NAME(m_a1_interrupt_status));
+ save_item(NAME(m_a1_interrupt_mask));
+ save_item(NAME(m_a1_protection_mode));
+ save_item(NAME(m_a1_protection_lower));
+ save_item(NAME(m_a1_protection_upper));
+ save_item(NAME(m_frc_count));
+ save_item(NAME(m_frc_reload));
+ save_item(NAME(m_watchdog_count));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_asic1_device::device_reset()
+{
+ m_tick_timer->adjust(attotime::from_hz(4), 0, attotime::from_hz(4));
+ m_frc_timer->adjust(attotime::from_hz(512000), 0, attotime::from_hz(512000));
+ m_watchdog_timer->adjust(attotime::from_hz(4), 0, attotime::from_hz(4));
+
+ m_frc_count = 0;
+ m_frc_reload = 0;
+ m_frc_ovl = 0;
+ m_watchdog_count = 0;
+
+ m_a1_interrupt_status = 0x00;
+ m_a1_interrupt_mask = 0x00;
+
+ m_a1_protection_mode = false;
+ m_a1_protection_lower = 0x00;
+ m_a1_protection_upper = 0x00;
+}
+
+
+TIMER_CALLBACK_MEMBER(psion_asic1_device::tick)
+{
+ m_a1_interrupt_status |= 0x01; // Timer
+ update_interrupts();
+}
+
+TIMER_CALLBACK_MEMBER(psion_asic1_device::frc)
+{
+ switch (--m_frc_count)
+ {
+ case 0x0000:
+ m_frcovl_cb(m_frc_ovl ^= 1);
+
+ m_a1_interrupt_status |= 0x20; // FrcExpired
+ update_interrupts();
+ break;
+
+ case 0xffff:
+ if (BIT(m_a1_status, 0)) // FrcMode
+ m_frc_count = m_frc_reload;
+ break;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(psion_asic1_device::watchdog)
+{
+ m_watchdog_count++;
+ m_watchdog_count &= 3;
+
+ if (m_watchdog_count == 3)
+ {
+ m_a1_status |= 0x0100; // WatchDogNmi
+ update_interrupts();
+ }
+}
+
+void psion_asic1_device::eint1_w(int state)
+{
+ if (state)
+ m_a1_interrupt_status |= 0x04; // ExpIntRightB
+ else
+ m_a1_interrupt_status &= ~0x04;
+
+ update_interrupts();
+}
+
+void psion_asic1_device::eint2_w(int state)
+{
+ if (state)
+ m_a1_interrupt_status |= 0x08; // ExpIntLeftA
+ else
+ m_a1_interrupt_status &= ~0x08;
+
+ update_interrupts();
+}
+
+void psion_asic1_device::eint3_w(int state)
+{
+ if (state)
+ m_a1_interrupt_status |= 0x10; // Asic2Int
+ else
+ m_a1_interrupt_status &= ~0x10;
+
+ update_interrupts();
+}
+
+void psion_asic1_device::enmi_w(int state)
+{
+ if (state)
+ m_a1_status |= 0x0200; // ExternalNmi
+ else
+ m_a1_status &= ~0x0200;
+
+ update_interrupts();
+}
+
+void psion_asic1_device::update_interrupts(bool address_trap)
+{
+ bool irq = m_a1_interrupt_status & m_a1_interrupt_mask;
+ bool nmi = (m_a1_status & 0x0300) || address_trap;
+
+ m_int_cb(irq ? ASSERT_LINE : CLEAR_LINE);
+ m_nmi_cb(nmi ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+IRQ_CALLBACK_MEMBER(psion_asic1_device::inta_cb)
+{
+ // IRQ Vector Name Description
+ // 0 0x78 TINT Tick interrupt at 2 or 32 Hz
+ // 1 0x79 EINT0 External interrupt usually connected to mains detect bit
+ // 2 0x7A EINT1 External interrupt from expansion port one
+ // 3 0x7B EINT2 External interrupt from expansion port two
+ // 4 0x7C EINT3 External interrupt from ASIC2
+ // 5 0x7D OVINT Timer overflow interrupt
+ // 6 0x7E SRXI SLD sound receive interrupt
+ // 7 0x7F STXI SLD sound transmit interrupt
+ uint8_t vector = 0x78;
+ for (int irq = 0; irq < 8; irq++)
+ {
+ if (m_a1_interrupt_status & m_a1_interrupt_mask & (1 << irq))
+ {
+ vector += irq;
+ break;
+ }
+ }
+ return vector;
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+bool psion_asic1_device::is_protected(offs_t offset)
+{
+ if (m_a1_protection_mode && (offset <= m_a1_protection_lower || offset > m_a1_protection_upper))
+ {
+ LOG("%s is_protected: %05x < %05x <= %05x\n", machine().describe_context(), m_a1_protection_lower, offset, m_a1_protection_upper);
+ update_interrupts(true);
+ return true;
+ }
+ return false;
+}
+
+
+uint16_t psion_asic1_device::mem_r(offs_t offset, uint16_t mem_mask)
+{
+ return m_space->read_word(offset << 1, mem_mask);
+}
+
+void psion_asic1_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ if (!is_protected(offset << 1))
+ m_space->write_word(offset << 1, data, mem_mask);
+}
+
+
+uint16_t psion_asic1_device::io_r(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t data = 0x00;
+
+ switch (offset << 1)
+ {
+ case 0x02: // A1Status
+ // b0 FrcMode
+ // b1 TickRate
+ // b2 FrcSource
+ // b3 Ram128
+ // b4 Ram512
+ // b5 LcdEnable
+ // b6 A1SldEnable
+ // b7 SldTx
+ // b8 WatchDogNmi
+ // b9 ExternalNmi
+ // b10 Rtc32Hz
+ // b11 ComboBusy
+ // b12 SldMsw
+ // b13 Rtc4Hz
+ // b14-b15 LcdData - LCD id as follows:
+ // 0 = Lcd640X400
+ // 1 = Lcd640X200Small
+ // 2 = Lcd640X200Big
+ // 3 = Lcd720X348
+ // 4 = Lcd160X80
+ data = m_a1_status;
+ data |= lcd_type() << 14;
+ LOG("%s io_r: A1Status => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x06: // A1InterruptStatus
+ data = m_a1_interrupt_status & m_a1_interrupt_mask;
+ LOG("%s io_r: A1InterruptStatus => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x08: // A1InterruptMask
+ data = m_a1_interrupt_mask;
+ LOG("%s io_r: A1InterruptMask => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x12: // A1FrcControl
+ data = m_frc_count;
+ LOG("%s io_r: A1FrcControl => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x14: // A1ProtectionOff
+ if (!machine().side_effects_disabled())
+ {
+ //LOG("%s io_r: A1ProtectionOff => %04x\n", machine().describe_context(), data);
+ m_a1_protection_mode = false;
+ }
+ break;
+
+ default:
+ data = 0xffff;
+ LOG("%s io_r: Unhandled register %02x => %04x\n", machine().describe_context(), offset << 1, data);
+ break;
+ }
+ return data;
+}
+
+void psion_asic1_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ switch (offset << 1)
+ {
+ case 0x02: // A1Control
+ // b0 FrcMode
+ // b1 TickRate
+ // b2 FrcSource
+ // b3 Ram128
+ // b4 Ram512
+ // b5 LcdEnable
+ // b6 A1SldEnable
+ // b7 SldTx
+ LOG("%s io_w: A1Control <= %04x\n", machine().describe_context(), data);
+ if (BIT(data, 1) != BIT(m_a1_status, 1))
+ {
+ if (data & 0x02) // TickRate
+ m_tick_timer->adjust(attotime::zero, 0, attotime::from_hz(32.768)); // RTC from PS34
+ else
+ m_tick_timer->adjust(attotime::zero, 0, attotime::from_hz(4));
+ }
+ m_a1_status = (m_a1_status & 0xff00) | (data & 0xff);
+ break;
+
+ case 0x04: // A1LcdSize
+ // b0-b9 LcdEndOfFrame - (Total pixels in display / 128) - 1
+ // b10-b14 LcdNumberOfPixels - (No. pixels in line / 32) - 1
+ // b15 LcdMLineEnable - 1 to enable the M line magic.
+ LOG("%s io_w: A1LcdSize <= %04x, Pixels in line %d, Total pixels in display %d\n", machine().describe_context(), data, (BIT(data, 10, 5) + 1) * 32, (BIT(data, 0, 10) + 1) * 128);
+ m_a1_lcd_size = data;
+ break;
+
+ case 0x06: // A1LcdControl
+ // b0-b4 LcdRate - LCDCLK = SYSCLK / (2*(n+1))
+ // b5-b9 LcdMLineRate - 13
+ // b10-b11 LcdMode - 3 (Dual Screen mode)
+ LOG("%s io_w: A1LcdControl <= %04x, LCD clock %dHz, %s\n", machine().describe_context(), data, clock() * 4 / (screen().width() * screen().height() * 2 * (BIT(data, 0, 5) + 1)), BIT(data, 10, 2) == 3 ? "Dual screen" : "Single screen");
+ m_a1_lcd_control = data;
+ break;
+
+ case 0x08: // A1InterruptMask
+ // b0 Timer
+ // b1 Mains
+ // b2 ExpIntRightB
+ // b3 ExpIntLeftA
+ // b4 Asic2Int
+ // b5 FrcExpired
+ // b6 SldReceive
+ // b7 SldTransmit
+ LOG("%s io_w: A1InterruptMask <= %02x\n", machine().describe_context(), data);
+ m_a1_interrupt_mask = data & 0xff;
+ update_interrupts();
+ break;
+
+ case 0x0a: // A1NonSpecificEoi
+ LOG("%s io_w: A1NonSpecificEoi <= %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x0c: // A1TimerEoi
+ LOG("%s io_w: A1TimerEoi <= %04x\n", machine().describe_context(), data);
+ m_a1_interrupt_status &= ~0x01; // Timer
+ update_interrupts();
+ break;
+
+ case 0x0e: // A1FrcEoi
+ LOG("%s io_w: A1FrcEoi <= %04x\n", machine().describe_context(), data);
+ m_a1_interrupt_status &= ~0x20; // FrcExpired
+ update_interrupts();
+ break;
+
+ case 0x10: // A1ResetWatchDog
+ //LOG("% io_w: A1ResetWatchDog <= %04x\n", machine().describe_context(), data);
+ m_watchdog_count = 0;
+ break;
+
+ case 0x12: // A1FrcControl
+ LOG("%s io_w: A1FrcControl <= %04x\n", machine().describe_context(), data);
+ m_frc_reload = data;
+ m_frc_count = data;
+ break;
+
+ case 0x14: // A1ProtectionOn
+ //LOG("%s io_w: A1ProtectionOn <= %04x\n", machine().describe_context(), data);
+ m_a1_protection_mode = true;
+ break;
+
+ case 0x16: // A1ProtectionUpper
+ //LOG("%s io_w: A1ProtectionUpper <= %04x\n", machine().describe_context(), data);
+ m_a1_protection_upper = (data << 4) | 0x0f;
+ break;
+
+ case 0x18: // A1ProtectionLower
+ //LOG("%s io_w: A1ProtectionLower <= %04x\n", machine().describe_context(), data);
+ m_a1_protection_lower = data << 4;
+ break;
+
+ case 0x1a: // A1SoundLsw
+ LOG("%s io_w: A1SoundLsw <= %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x1c: // A1SoundMsw
+ LOG("%s io_w: A1SoundMsw <= %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x1e: // A1SoundControl
+ LOG("%s io_w: A1SoundControl <= %04x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s io_w: Unhandled register %02x <= %04x\n", machine().describe_context(), offset << 1, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// LCD Controller
+//-------------------------------------------------
+
+uint8_t psion_asic1_device::lcd_type()
+{
+ if (m_laptop_mode)
+ {
+ switch (screen().height())
+ {
+ case 400: return 0;
+ case 200: return 1;
+ }
+ }
+ return 0;
+}
+
+uint32_t psion_asic1_device::screen_update_single(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ return screen_update(screen, bitmap, cliprect, 1);
+}
+
+uint32_t psion_asic1_device::screen_update_dual(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ return screen_update(screen, bitmap, cliprect, 2);
+}
+
+uint32_t psion_asic1_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int screens)
+{
+ if (m_a1_status & 0x0020) // LCD enable bit
+ {
+ pen_t const *const pens = screen.palette().pens();
+
+ offs_t videoram = m_laptop_mode ? 0xb8000 : 0x00400;
+ int const width = (BIT(m_a1_lcd_size, 10, 5) + 1) * 32;
+ int const height = screen.height() / screens;
+
+ for (int vmap = 0; vmap < screens; vmap++)
+ {
+ for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y / screens; y++)
+ {
+ for (int x = screen.visible_area().min_x; x <= (screen.visible_area().max_x / 8); x++)
+ {
+ uint8_t const pixels = m_space->read_byte(videoram + (vmap << 14) + (y * (width / 8)) + x);
+ uint16_t *p = &bitmap.pix((vmap * height) + y, x << 3);
+ for (int i = 0; i < 8; i++)
+ *p++ = pens[BIT(pixels, i)];
+ }
+ }
+ }
+ }
+ else
+ {
+ bitmap.fill(0, cliprect);
+ }
+ return 0;
+}
diff --git a/src/devices/machine/psion_asic1.h b/src/devices/machine/psion_asic1.h
new file mode 100644
index 00000000000..09805d725d3
--- /dev/null
+++ b/src/devices/machine/psion_asic1.h
@@ -0,0 +1,100 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC1
+
+******************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_ASIC1_H
+#define MAME_MACHINE_PSION_ASIC1_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> psion_asic1_device
+
+class psion_asic1_device : public device_t,
+ public device_memory_interface,
+ public device_video_interface
+{
+public:
+ // construction/destruction
+ psion_asic1_device(const machine_config &mconfig, const char* tag, device_t* owner, uint32_t clock);
+
+ void set_laptop_mode(bool laptop) { m_laptop_mode = laptop; }
+
+ // callbacks
+ auto int_cb() { return m_int_cb.bind(); }
+ auto nmi_cb() { return m_nmi_cb.bind(); }
+ auto frcovl_cb() { return m_frcovl_cb.bind(); }
+
+ uint16_t mem_r(offs_t offset, uint16_t mem_mask);
+ void mem_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ uint16_t io_r(offs_t offset, uint16_t mem_mask);
+ void io_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ IRQ_CALLBACK_MEMBER(inta_cb);
+
+ void eint1_w(int state);
+ void eint2_w(int state);
+ void eint3_w(int state);
+ void enmi_w(int state);
+
+ uint32_t screen_update_single(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ uint32_t screen_update_dual(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ const address_space_config m_space_config;
+ address_space *m_space;
+
+ emu_timer *m_tick_timer;
+ emu_timer *m_frc_timer;
+ emu_timer *m_watchdog_timer;
+
+ TIMER_CALLBACK_MEMBER(tick);
+ TIMER_CALLBACK_MEMBER(frc);
+ TIMER_CALLBACK_MEMBER(watchdog);
+
+ void update_interrupts(bool address_trap = false);
+ bool is_protected(offs_t offset);
+
+ uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int plates);
+
+ uint16_t m_a1_status;
+ uint16_t m_a1_lcd_size;
+ uint16_t m_a1_lcd_control;
+ uint16_t m_frc_count;
+ uint16_t m_frc_reload;
+ int m_frc_ovl;
+ uint8_t m_watchdog_count;
+ bool m_a1_protection_mode;
+ uint32_t m_a1_protection_upper;
+ uint32_t m_a1_protection_lower;
+
+ uint8_t m_a1_interrupt_status;
+ uint8_t m_a1_interrupt_mask;
+
+ devcb_write_line m_int_cb;
+ devcb_write_line m_nmi_cb;
+ devcb_write_line m_frcovl_cb;
+
+ bool m_laptop_mode;
+ uint8_t lcd_type();
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_ASIC1, psion_asic1_device)
+
+#endif // MAME_MACHINE_PSION_ASIC1_H
diff --git a/src/devices/machine/psion_asic2.cpp b/src/devices/machine/psion_asic2.cpp
new file mode 100644
index 00000000000..e91dd370b67
--- /dev/null
+++ b/src/devices/machine/psion_asic2.cpp
@@ -0,0 +1,448 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC2
+
+ ASIC2 is the peripheral controller chip for the SIBO architecture. It contains
+ the system clock oscillator and controls switching between the standby and
+ operating states. ASIC2 provides an interface to the power supply, keyboard,
+ buzzer and SSDs. ASIC 2 includes the eight-channel SIBO serial protocol
+ controller and provides interface circuitry to both the reduced external and
+ extended internal peripheral expansion ports.
+
+******************************************************************************/
+
+#include "emu.h"
+#include "psion_asic2.h"
+
+#define VERBOSE 0
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PSION_ASIC2, psion_asic2_device, "psion_asic2", "Psion ASIC2")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+psion_asic2_device::psion_asic2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PSION_ASIC2, tag, owner, clock)
+ , m_int_cb(*this)
+ , m_nmi_cb(*this)
+ , m_cbusy_cb(*this)
+ , m_buz_cb(*this)
+ , m_buzvol_cb(*this)
+ , m_dr_cb(*this)
+ , m_col_cb(*this, 0xff)
+ , m_read_pd_cb(*this, 0x00)
+ , m_write_pd_cb(*this)
+ , m_data_r(*this, 0x00)
+ , m_data_w(*this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_asic2_device::device_start()
+{
+ m_a2_status = 0x00;
+
+ m_busy_timer = timer_alloc(FUNC(psion_asic2_device::busy), this);
+
+ save_item(NAME(m_a2_index));
+ save_item(NAME(m_a2_icontrol0));
+ save_item(NAME(m_a2_icontrol1));
+ save_item(NAME(m_a2_iddr));
+ save_item(NAME(m_a2_control1));
+ save_item(NAME(m_a2_control2));
+ save_item(NAME(m_a2_control3));
+ save_item(NAME(m_a2_serial_data));
+ save_item(NAME(m_a2_serial_control));
+ save_item(NAME(m_a2_interrupt_status));
+ save_item(NAME(m_a2_status));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_asic2_device::device_reset()
+{
+ m_a2_index = 0x00;
+ m_a2_icontrol0 = 0x00;
+ m_a2_icontrol1 = 0x00;
+ m_a2_iddr = 0x00;
+ m_a2_control1 = 0x00;
+ m_a2_control2 = 0x00;
+ m_a2_control3 = 0x00;
+ m_a2_serial_data = 0x00;
+ m_a2_serial_control = 0x00;
+ m_a2_interrupt_status = 0x00;
+ m_a2_status = 0x00;
+ m_a2_channel_control = 0x00;
+}
+
+
+void psion_asic2_device::on_clr_w(int state)
+{
+ if (state)
+ m_a2_status |= 0x01; // A1OnKey
+ else
+ m_a2_status &= ~0x01;
+
+ update_interrupts();
+}
+
+void psion_asic2_device::sds_int_w(int state)
+{
+ if (state)
+ m_a2_status |= 0x20; // A2Sdis
+ else
+ m_a2_status &= ~0x20;
+
+ update_interrupts();
+}
+
+void psion_asic2_device::dnmi_w(int state)
+{
+ if (state)
+ m_a2_interrupt_status |= 0x01; // DNMI
+ else
+ m_a2_interrupt_status &= ~0x01;
+
+ update_interrupts();
+}
+
+void psion_asic2_device::frcovl_w(int state)
+{
+ if (BIT(m_a2_control2, 4))
+ {
+ m_buz_cb(state);
+ }
+}
+
+void psion_asic2_device::reset_w(int state)
+{
+ if (!state)
+ m_a2_status |= 0x04; // A1ResetFlag
+}
+
+void psion_asic2_device::update_interrupts()
+{
+ int irq = m_a2_status & 0x21;
+ int nmi = BIT(m_a2_interrupt_status, 0, 2) & BIT(m_a2_control3, 4, 2);
+
+ m_int_cb(irq ? ASSERT_LINE : CLEAR_LINE);
+ m_nmi_cb(nmi ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+TIMER_CALLBACK_MEMBER(psion_asic2_device::busy)
+{
+ m_a2_status &= ~0x10; // clear data serial controller is busy
+ m_cbusy_cb(1);
+}
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+uint8_t psion_asic2_device::io_r(offs_t offset)
+{
+ uint8_t data = 0x00;
+
+ switch (offset & 7)
+ {
+ case 0x00: // A2Index - Index Register
+ data = m_a2_index;
+ LOG("%s io_r: A2Index => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x01: // A2Control - Indexed Control Register
+ switch (m_a2_index)
+ {
+ case 0: // A2IControl0 - System Control Register 0
+ data = m_a2_icontrol0;
+ LOG("%s io_r: A2IControl0 => %02x\n", machine().describe_context(), data);
+ break;
+ case 1: // A2IControl1 - Serial Clock Control Register
+ data = m_a2_icontrol1;
+ LOG("%s io_r: A2IControl1 => %02x\n", machine().describe_context(), data);
+ break;
+ case 2: // A2IWrite - Port Output Data Register (Write only)
+ LOG("%s io_r: A2IWrite => %02x\n", machine().describe_context(), data);
+ break;
+ case 3: // A2IDDR - Port Data Direction Register
+ data = m_a2_iddr;
+ LOG("%s io_r: A2IDDR => %02x\n", machine().describe_context(), data);
+ break;
+ }
+ break;
+
+ case 0x02: // A2External - External status register
+ switch (m_a2_control1 & 0x0f)
+ {
+ case 0x0f: // all keyboard columns
+ for (int i = 0; i < 10; i++)
+ data |= m_col_cb(i);
+ break;
+
+ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0a:
+ data = m_col_cb((m_a2_control1 & 0x0f) - 1);
+ break;
+
+ default:
+ data = 0x00;
+ break;
+ }
+ LOG("%s io_r: A2External => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x03: // A2InterruptStatus - Interrupt status register
+ // b0 DoorInterrupt - Status of pack doors, 1 if open
+ // b1 ExpansionInterrupt - Status of expansion interface doors, 1 if open
+ // b2 SlaveDataValid - Slave data valid, 1 if valid frame arrived
+ // b3 SlaveDataControl - Slave control or data frame, 1 if control frame
+ // b4 SlaveDataOverrun - Slave data overrun, 1 if overrun
+ // b5 LowBatteryNMI - Low battery NMI, 1 if NMI occurred
+ // b6 0
+ // b7 0
+ data = m_a2_interrupt_status;
+ LOG("%s io_r: A2InterruptStatus => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x04: // A2Status - Status register
+ // b0 A1OnKey - 1 if on key pressed
+ // b1 WakeUp - 1 if external wakeup valid
+ // b2 A1ResetFlag - 1 if system reset
+ // b3 SerialClockState - 1 if slave clock is high
+ // b4 SerialBusy - 1 while data serial controller is busy
+ // b5 A2Sdis - 1 if slave data signal is high
+ // b6 Ext - 1 in Extended Mode, 0 in Compatible Mode
+ // b7 RevId - 1 if Revision 4 part
+ data = m_a2_status;
+ if (!machine().side_effects_disabled())
+ {
+ m_a2_status &= ~0x01; // clear A1OnKey
+ m_a2_status &= ~0x04; // clear A1ResetFlag
+ }
+ LOG("%s io_r: A2Status => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x05: // A2SerialData - Serial channel read data register
+ data = m_a2_serial_data;
+ if ((m_a2_serial_control & 0x10) == 0x10)
+ m_a2_serial_data = receive_frame();
+ LOG("%s io_r: A2SerialData => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x06: // A2KeyData - Keyboard poll register
+ // Extended mode read from Port I/O lines
+ data = m_read_pd_cb();
+ LOG("%s io_r: A2KeyData => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x07: // A2SlaveData - Slave data read register
+ data = 0x00;
+ LOG("%s io_r: A2SlaveData => %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s io_r: Unhandled register %02x => %02x\n", machine().describe_context(), offset, data);
+ break;
+ }
+ return data;
+}
+
+void psion_asic2_device::io_w(offs_t offset, uint8_t data)
+{
+ switch (offset & 7)
+ {
+ case 0x00: // A2Index - Index Register
+ // b0-b1 INDEX0,1 - Register 1 Index
+ LOG("%s io_w: A2Index <= %02x\n", machine().describe_context(), data);
+ m_a2_index = data & 3;
+ break;
+
+ case 0x01: // A2Control - Indexed Control Register
+ switch (m_a2_index)
+ {
+ case 0: // A2IControl0 - System Control Register 0
+ // b0-b1 CLKSEL0-1 - Crystal Divider Select (0,1 - 23.04MHz divider = 3, 2 - 15.36MHz divider = 2, 3 - 7.68MHz divider = 1)
+ // b2 CHEN3 - Serial Channel 3 is enabled when this bit is set
+ // b3 CHEN4 - Serial Channel 4 is enabled when this bit is set
+ // b4 CHEN6 - Serial Channel 6 is enabled when this bit is set
+ // b5 EXONOFF - EXON & SCKS witch-on is disabled when this bit is set
+ // b6 INTSEL - Interrupt Source Select (0 - Frame received, 1 - SDIS direct)
+ LOG("%s io_w: A2IControl0 => %02x\n", machine().describe_context(), data);
+ m_a2_icontrol0 = data;
+ break;
+ case 1: // A2IControl1 - Serial Clock Control Register
+ // b0 CKEN1 - Serial Channel 1 continuous clock is enabled when this bit is set
+ // b1 CKEN2 - Serial Channel 2 continuous clock is enabled when this bit is set
+ // b2 CKEN3 - Serial Channel 3 continuous clock is enabled when this bit is set
+ // b3 CKEN4 - Serial Channel 4 continuous clock is enabled when this bit is set
+ LOG("%s io_w: A2IControl1 => %02x\n", machine().describe_context(), data);
+ m_a2_icontrol1 = data;
+ break;
+ case 2: // A2IWrite - Port Output Data Register
+ LOG("%s io_w: A2IWrite => %02x\n", machine().describe_context(), data);
+ m_write_pd_cb(data & m_a2_iddr);
+ break;
+ case 3: // A2IDDR - Port Data Direction Register
+ // b0-b7 DO0-7 - 0 = PD* is and input, 1 = PD* is an output
+ LOG("%s io_w: A2IDDR => %02x\n", machine().describe_context(), data);
+ m_a2_iddr = data;
+ break;
+ }
+ break;
+
+ case 0x02: // A2Control1 - Control register 1
+ // b0-b3 KeyScan - Values 0-15 drive the keyboard poll columns
+ // b4-b5 SerialClockRate - Sets the clock frequency for channels 1-4 and 7 as below:
+ // 0 = ClockRateMedium 1.536 MHz
+ // 2 = ClockRateSlow 256 KHz
+ // 3 = ClockRateFast 3.84 MHz
+ LOG("%s io_w: A2Control1 <= %02x\n", machine().describe_context(), data);
+ m_a2_control1 = data;
+ break;
+
+ case 0x03: // A2Control2 - Control register 2
+ // b0 DigitizerEnable - 1 to enable digitizer drivers
+ // b1 XySwitch - 0 to drive digitizer X scan, 1 to drive Y
+ // b2 BuzzerToggle - Toggles the piezo speaker
+ // b3 BuzzerVolume - 1 if loud buzzer volume, 0 is soft
+ // b4 BuzzerMode - Piezo driving mode, 0 - toggled by BZTOG, 1 - driven by FRC
+ // b5 ClockEnable5 - Enable continuous clock on serial channel 5
+ // b6 ClockEnable6 - Enable continuous clock on serial channel 6
+ // b7 ClockEnable7 - Enable continuous clock on serial channel 7
+ LOG("%s io_w: A2Control2 <= %02x\n", machine().describe_context(), data);
+ m_a2_control2 = data;
+ m_dr_cb(BIT(data, 1));
+ if (!BIT(data, 4))
+ {
+ m_buz_cb(BIT(data, 2));
+ }
+ m_buzvol_cb(BIT(data, 3));
+ break;
+
+ case 0x04: // A2Control3 - Control register 3
+ // b0 SerialNull - 1 to send a null frame
+ // b1 Ps34Acknowledge - 1 to reset PS34 on power up
+ // b2 A2SldEnable - 1 to enable SLD bus clock
+ // b3 SerialEnable - 1 to enable access to pack channels 1-4
+ // b4 DoorEnable - 1 to enable pack door NMIs
+ // b5 ExpansionEnable - 1 to enable expansion door NMIs
+ // b6 VhControl - 1 to enable VPP to packs
+ // b7 ElEnable - 1 to enable LCD back light
+ LOG("%s io_w: A2Control3 <= %02x\n", machine().describe_context(), data);
+ m_a2_control3 = data;
+ if (BIT(m_a2_control3, 0))
+ transmit_frame(NULL_FRAME);
+ break;
+
+ case 0x05: // A2SerialData - Serial channel write data register
+ LOG("%s io_w: A2SerialData <= %02x\n", machine().describe_context(), data);
+ if ((m_a2_serial_control & 0xc0) == 0x80)
+ transmit_frame(DATA_FRAME | data);
+ break;
+
+ case 0x06: // A2SerialControl - Serial channel write control register
+ // WriteSingle 10000000b; ReadSingle 11000000b
+ // WriteMulti 10010000b; ReadMulti 11010000b
+ // Reset 00000000b; Select 01000000b
+ // Asic2SlaveId 001h; Asic5PackId 002h
+ // Asic5NormalId 003h; Asic6Id 004h
+ // Asic8Id 005h; Asic4Id 006h
+ LOG("%s io_w: A2SerialControl <= %02x\n", machine().describe_context(), data);
+ m_a2_serial_control = data;
+ transmit_frame(CONTROL_FRAME | data);
+
+ if ((m_a2_serial_control & 0x40) == 0x40)
+ m_a2_serial_data = receive_frame();
+ break;
+
+ case 0x07: // A2ChannelControl - Serial channel select register
+ // b0 Pack1Enable - 1 to select pack 1
+ // b1 Pack2Enable - 1 to select pack 2
+ // b2 Pack3Enable - 1 to select pack 3
+ // b3 Pack4Enable - 1 to select pack 4
+ // b4-b6 ChannelSelect - 0-7 to select channel 0,5-8 as below:
+ // 4 = PK0, 5 = PK5, 6 = PK6, 7 = PK7
+ // b7 MultiplexEnable - 1 to loop slave channel to pack channel
+ LOG("%s io_w: A2ChannelControl <= %02x Channels %c %c %c %c %c %c %c %c\n", machine().describe_context(), data,
+ BIT(data, 4, 3) == 4 ? '0' : ' ',
+ BIT(data, 0) ? '1' : ' ',
+ BIT(data, 1) ? '2' : ' ',
+ BIT(data, 2) ? '3' : ' ',
+ BIT(data, 3) ? '4' : ' ',
+ BIT(data, 4, 3) == 5 ? '5' : ' ',
+ BIT(data, 4, 3) == 6 ? '6' : ' ',
+ BIT(data, 4, 3) == 7 ? '7' : ' ');
+ m_a2_channel_control = data;
+ break;
+
+ default:
+ LOG("%s io_w: Unhandled register %02x <= %02x\n", machine().describe_context(), offset, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// SIBO Serial Protocol Controller
+//-------------------------------------------------
+
+bool psion_asic2_device::channel_active(int channel)
+{
+ switch (channel)
+ {
+ case 0:
+ return BIT(m_a2_channel_control, 4, 3) == 4;
+ case 1: case 2: case 3: case 4:
+ return BIT(m_a2_channel_control, channel - 1);
+ case 5: case 6: case 7:
+ return BIT(m_a2_channel_control, 4, 3) == channel;
+ }
+ return false;
+}
+
+void psion_asic2_device::transmit_frame(uint16_t data)
+{
+ m_a2_status |= 0x10; // set data serial controller is busy
+ m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2));
+ m_cbusy_cb(0);
+
+ for (int ch = 0; ch < 8; ch++)
+ {
+ if (channel_active(ch))
+ {
+ LOG("%s Channel %d Transmit %s frame %02x\n", machine().describe_context(), ch, (data & DATA_FRAME) ? "Data" : (data & CONTROL_FRAME) ? "Control" : "Null", data & 0xff);
+ m_data_w[ch](data);
+ }
+ }
+}
+
+uint8_t psion_asic2_device::receive_frame()
+{
+ uint8_t data = 0x00;
+
+ m_a2_status |= 0x10; // set data serial controller is busy
+ m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2));
+ m_cbusy_cb(0);
+
+ for (int ch = 0; ch < 8; ch++)
+ {
+ if (channel_active(ch))
+ {
+ data |= m_data_r[ch]();
+ LOG("%s Channel %d Receive Data frame %02x\n", machine().describe_context(), ch, data);
+ }
+ }
+
+ return data;
+}
diff --git a/src/devices/machine/psion_asic2.h b/src/devices/machine/psion_asic2.h
new file mode 100644
index 00000000000..48dcfb2c690
--- /dev/null
+++ b/src/devices/machine/psion_asic2.h
@@ -0,0 +1,100 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC2
+
+******************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_ASIC2_H
+#define MAME_MACHINE_PSION_ASIC2_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> psion_asic2_device
+
+class psion_asic2_device : public device_t
+{
+public:
+ // construction/destruction
+ psion_asic2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // callbacks
+ auto int_cb() { return m_int_cb.bind(); }
+ auto nmi_cb() { return m_nmi_cb.bind(); }
+ auto cbusy_cb() { return m_cbusy_cb.bind(); }
+ auto buz_cb() { return m_buz_cb.bind(); }
+ auto buzvol_cb() { return m_buzvol_cb.bind(); }
+ auto dr_cb() { return m_dr_cb.bind(); }
+ auto col_cb() { return m_col_cb.bind(); }
+ auto read_pd_cb() { return m_read_pd_cb.bind(); }
+ auto write_pd_cb() { return m_write_pd_cb.bind(); }
+
+ template <unsigned N> auto data_r() { static_assert(N < 8); return m_data_r[N].bind(); }
+ template <unsigned N> auto data_w() { static_assert(N < 8); return m_data_w[N].bind(); }
+
+ uint8_t io_r(offs_t offset);
+ void io_w(offs_t offset, uint8_t data);
+
+ void on_clr_w(int state);
+ void sds_int_w(int state);
+ void dnmi_w(int state);
+ void frcovl_w(int state);
+ void reset_w(int state);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ void update_interrupts();
+
+ uint8_t m_a2_index;
+ uint8_t m_a2_icontrol0;
+ uint8_t m_a2_icontrol1;
+ uint8_t m_a2_iddr;
+ uint8_t m_a2_control1;
+ uint8_t m_a2_control2;
+ uint8_t m_a2_control3;
+ uint8_t m_a2_serial_data;
+ uint8_t m_a2_serial_control;
+ uint8_t m_a2_interrupt_status;
+ uint8_t m_a2_status;
+ uint8_t m_a2_channel_control;
+
+ devcb_write_line m_int_cb;
+ devcb_write_line m_nmi_cb;
+ devcb_write_line m_cbusy_cb;
+ devcb_write_line m_buz_cb;
+ devcb_write_line m_buzvol_cb;
+ devcb_write_line m_dr_cb;
+ devcb_read8 m_col_cb;
+ devcb_read8 m_read_pd_cb;
+ devcb_write8 m_write_pd_cb;
+
+ devcb_read8::array<8> m_data_r;
+ devcb_write16::array<8> m_data_w;
+
+ emu_timer *m_busy_timer;
+
+ TIMER_CALLBACK_MEMBER(busy);
+
+ bool channel_active(int channel);
+ void transmit_frame(uint16_t data);
+ uint8_t receive_frame();
+
+ static constexpr uint16_t NULL_FRAME = 0x000;
+ static constexpr uint16_t CONTROL_FRAME = 0x100;
+ static constexpr uint16_t DATA_FRAME = 0x200;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_ASIC2, psion_asic2_device)
+
+#endif // MAME_MACHINE_PSION_ASIC2_H
diff --git a/src/devices/machine/psion_asic3.cpp b/src/devices/machine/psion_asic3.cpp
new file mode 100644
index 00000000000..d7e71866f72
--- /dev/null
+++ b/src/devices/machine/psion_asic3.cpp
@@ -0,0 +1,302 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC3/PS34
+
+ MC and HC power supplies are based on a full custom liner ASIC known as ASIC3.
+ This custom chip is manufactured by Maxim and has the Maxim part number MAX616.
+
+ TODO:
+ - Battery status readings, maybe different analogue channel.
+ - Resolve ambiguity about status register, S3 and MC/HC machines expect different data.
+
+******************************************************************************/
+
+#include "emu.h"
+#include "psion_asic3.h"
+
+#define VERBOSE 0
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PSION_PSU_ASIC3, psion_psu_asic3_device, "psion_psu_asic3", "Psion PSU (ASIC3)")
+DEFINE_DEVICE_TYPE(PSION_PSU_ASIC5, psion_psu_asic5_device, "psion_psu_asic5", "Psion PSU (ASIC5)")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+psion_asic3_device::psion_asic3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_adin_cb(*this, 0)
+{
+}
+
+psion_psu_asic5_device::psion_psu_asic5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : psion_asic3_device(mconfig, PSION_PSU_ASIC5, tag, owner, clock)
+{
+}
+
+psion_psu_asic3_device::psion_psu_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : psion_asic3_device(mconfig, PSION_PSU_ASIC3, tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_asic3_device::device_start()
+{
+ save_item(NAME(m_a3_control1));
+ save_item(NAME(m_a3_control2));
+ save_item(NAME(m_a3_control3));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_asic3_device::device_reset()
+{
+ m_a3_control1 = 0x00;
+ m_a3_control2 = 0x00;
+ m_a3_control3 = 0x00;
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void psion_psu_asic5_device::data_w(uint16_t data)
+{
+ switch (data & 0x300)
+ {
+ case NULL_FRAME:
+ device_reset();
+ break;
+
+ case CONTROL_FRAME:
+ m_sibo_control = data & 0xff;
+ break;
+
+ case DATA_FRAME:
+ data &= 0xff;
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x01: // A3Control1
+ // b0-b4 DtoaBits
+ // b5 Vcc3Enable LCD
+ // b6 Vcc4Enable Sound subsystem
+ // b7 Vcc5Enable SSDs
+ LOG("%s data_w: A3Control1 register %02x\n", machine().describe_context(), data);
+ m_a3_control1 = data;
+ break;
+
+ case 0x02: // A3Setup
+ LOG("%s data_w: A3Setup register %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x03: // A3Control2
+ // b0 Vee1Enable LCD
+ // b1 Vee2Enable Sound subsystem
+ // b2 VhEnable
+ // b3 Vee1SoftStart
+ // b4 Vee2SoftStart
+ // b5 VhSoftStart
+ // b6-b7 AnalogueMultiplex
+ LOG("%s data_w: A3Control2 register %02x\n", machine().describe_context(), data);
+ m_a3_control2 = data;
+ break;
+
+ case 0x07: // A3Control3
+ // b0 0
+ // b1 OffEnable
+ // b2 AdcReadHighEnable
+ // b3-b7 0
+ LOG("%s data_w: A3Control3 register %02x\n", machine().describe_context(), data);
+ m_a3_control3 = data;
+ break;
+
+ default:
+ LOG("%s data_w: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ }
+}
+
+uint8_t psion_psu_asic5_device::data_r()
+{
+ uint8_t data = 0x00;
+
+ switch (m_sibo_control & 0xc0)
+ {
+ case 0x40: // SerialSelect
+ if (m_sibo_control == 0x43) // A3SelectId
+ data = 0x80; // A3InfoByte
+ break;
+
+ case 0xc0: // SerialRead
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x00: // A3Adc
+ {
+ // A3AdcLsbR
+ // b0-b6 OtherBits
+ // b7 InvertedBit
+ // A3AdcMsbR
+ // b0-b3 AdcBits
+ // b4 Overrange
+ // b5 Polarity
+ uint16_t data_in = 0;
+ switch (BIT(m_a3_control2, 6, 2)) // AnalogueMultiplex
+ {
+ case 0: // AdcDigitizer
+ data_in = m_adin_cb();
+ break;
+ case 1: // AdcVh
+ break;
+ case 2: // AdcMainBattery
+ data_in = 0x7ff;
+ break;
+ case 3: // AdcLithiumBattery
+ data_in = 0x7ff;
+ break;
+ }
+ if (BIT(m_a3_control3, 2)) // AdcReadHighEnable
+ data = BIT(data_in, 8, 4);
+ else
+ data = (data_in & 0xff) ^ 0x80;
+ LOG("%s data_r: A3Adc %d register %02x\n", machine().describe_context(), BIT(m_a3_control2, 6, 2), data);
+ break;
+ }
+ case 0x0d: // A3Status
+ // b0 ColdStart
+ // b1 PowerFail
+ data = 0x00; // ColdStart
+ LOG("%s data_r: A3Status register %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s data_r: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ break;
+ }
+
+ return data;
+}
+
+
+void psion_psu_asic3_device::data_w(uint16_t data)
+{
+ switch (data & 0x300)
+ {
+ case NULL_FRAME:
+ device_reset();
+ break;
+
+ case CONTROL_FRAME:
+ m_sibo_control = data & 0xff;
+ break;
+
+ case DATA_FRAME:
+ data &= 0xff;
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x00: // PS34W_CONTROL
+ // b0-b1 Vhpower
+ // b2 Vh
+ // b3 Vcc5
+ // b4 Vee2
+ // b5 Vcc4
+ // b6 Vee1
+ // b7 Vcc3
+ LOG("%s data_w: PS34W_CONTROL %02x\n", machine().describe_context(), data);
+ m_a3_control1 = data;
+ break;
+
+ case 0x01: // PS34W_DTOA
+ // b0-b4 Dac
+ // b5-b6 Adcsel
+ // b7 Ncc
+ LOG("%s data_w: PS34W_DTOA %02x\n", machine().describe_context(), data);
+ m_a3_control2 = data;
+ break;
+
+ default:
+ LOG("%s data_w: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ }
+}
+
+uint8_t psion_psu_asic3_device::data_r()
+{
+ uint8_t data = 0x00;
+
+ switch (m_sibo_control & 0xc0)
+ {
+ case 0x40: // SerialSelect
+ if (m_sibo_control == 0x43) // A3SelectId
+ data = 0x80; // A3InfoByte
+ break;
+
+ case 0xc0: // SerialRead
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x00: // PS34R_ADC
+ switch (BIT(m_a3_control2, 5, 2)) // Adcsel
+ {
+ case 0: // ADCSEL_ADCIN
+ data = m_adin_cb() & 0xff;
+ break;
+ case 1: // ADCSEL_VIN
+ data = 0xff;
+ break;
+ case 2: // ADCSEL_VH
+ break;
+ case 3: // ADCSEL_VBATT
+ data = 0xff;
+ break;
+ }
+ LOG("%s data_r: PS34R_ADC %d %02x\n", machine().describe_context(), BIT(m_a3_control2, 5, 2), data);
+ break;
+
+ case 0x01: // PS34R_STATUS
+ // b0-b2 Admsb
+ // b3 Nc
+ // b4 Penup
+ // b5 Vhready
+ // b6 ColdStart
+ // b7 PowerFail
+ switch (BIT(m_a3_control2, 5, 2)) // Adcsel
+ {
+ case 0: // ADCSEL_ADCIN
+ data = BIT(m_adin_cb(), 8, 3);
+ break;
+ case 1: // ADCSEL_VIN
+ data = 0x07;
+ break;
+ case 2: // ADCSEL_VH
+ break;
+ case 3: // ADCSEL_VBATT
+ data = 0x07;
+ break;
+ }
+ data |= 0x40; // ColdStart
+ LOG("%s data_r: PS34R_STATUS %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s data_r: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ break;
+ }
+
+ return data;
+}
diff --git a/src/devices/machine/psion_asic3.h b/src/devices/machine/psion_asic3.h
new file mode 100644
index 00000000000..7002746a23e
--- /dev/null
+++ b/src/devices/machine/psion_asic3.h
@@ -0,0 +1,79 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC3/PS34
+
+******************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_ASIC3_H
+#define MAME_MACHINE_PSION_ASIC3_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> psion_asic3_device
+
+class psion_asic3_device : public device_t
+{
+public:
+ // callbacks
+ auto adin_cb() { return m_adin_cb.bind(); }
+
+ virtual void data_w(uint16_t data) { }
+ virtual uint8_t data_r() { return 0x00; }
+
+protected:
+ psion_asic3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ static constexpr uint16_t NULL_FRAME = 0x000;
+ static constexpr uint16_t CONTROL_FRAME = 0x100;
+ static constexpr uint16_t DATA_FRAME = 0x200;
+
+ devcb_read16 m_adin_cb;
+
+ uint8_t m_sibo_control;
+ uint8_t m_a3_control1;
+ uint8_t m_a3_control2;
+ uint8_t m_a3_control3;
+};
+
+
+// ======================> psion_psu_asic5_device
+
+class psion_psu_asic5_device : public psion_asic3_device
+{
+public:
+ // construction/destruction
+ psion_psu_asic5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ virtual void data_w(uint16_t data) override;
+ virtual uint8_t data_r() override;
+};
+
+
+// ======================> psion_psu_asic3_device
+
+class psion_psu_asic3_device : public psion_asic3_device
+{
+public:
+ // construction/destruction
+ psion_psu_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ virtual void data_w(uint16_t data) override;
+ virtual uint8_t data_r() override;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_PSU_ASIC3, psion_psu_asic3_device)
+DECLARE_DEVICE_TYPE(PSION_PSU_ASIC5, psion_psu_asic5_device)
+
+#endif // MAME_MACHINE_PSION_ASIC3_H
diff --git a/src/devices/machine/psion_asic4.cpp b/src/devices/machine/psion_asic4.cpp
new file mode 100644
index 00000000000..0ed603eaa74
--- /dev/null
+++ b/src/devices/machine/psion_asic4.cpp
@@ -0,0 +1,170 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC4
+
+ ASIC4 is a serial protocol slave IC for addressing memory and general
+ memory-mapped peripherals. It is used in SSDs to convert SIBO serial protocol
+ signals into addresses within the memory range of the memory pack. ASIC4 was
+ designed to be a cut-down version of ASIC5 which was the original SIBO serial
+ protocol slave chip.
+
+ A27 A26 A25 A24 D7 D6 D5 D4 D3 D2 D1 D0
+ M Peripheral Id Memory Type No. devices Memory Size
+ 1 0 0 0 No peripheral 0 0 0 RAM 0 0 1 device 0 0 0 No memory
+ 0 0 1 Turbo RS232 (16550) 0 0 1 Type 1 Flash 0 1 2 devices 0 0 1 32K
+ 0 1 0 3Fax 0 1 0 Type 2 Flash 1 0 3 devices 0 1 0 64K
+ 1 1 1 Extended info in ROM 1 1 0 ROM 1 1 4 devices 0 1 1 128K
+ 1 0 0 256K
+ 1 0 1 512K
+ 1 1 0 1M
+
+******************************************************************************/
+
+#include "emu.h"
+#include "psion_asic4.h"
+
+#define VERBOSE 0
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PSION_ASIC4, psion_asic4_device, "psion_asic4", "Psion ASIC4")
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+psion_asic4_device::psion_asic4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PSION_ASIC4, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , m_space_config("program", ENDIANNESS_LITTLE, 8, 28)
+{
+}
+
+
+device_memory_interface::space_config_vector psion_asic4_device::memory_space_config() const
+{
+ return space_config_vector{ std::make_pair(0, &m_space_config) };
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_asic4_device::device_start()
+{
+ m_space = &space(0);
+
+ save_item(NAME(m_addr_latch));
+ save_item(NAME(m_addr_writes));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_asic4_device::device_reset()
+{
+ m_addr_latch = 0x00;
+ m_addr_writes = 0;
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void psion_asic4_device::data_w(uint16_t data)
+{
+ switch (data & 0x300)
+ {
+ case NULL_FRAME:
+ device_reset();
+ break;
+
+ case CONTROL_FRAME:
+ m_sibo_control = data & 0xff;
+
+ // reset address register to LSB
+ m_addr_writes = 0;
+ break;
+
+ case DATA_FRAME:
+ data &= 0xff;
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x00: // Data register
+ LOG("%s data_w: Data register %02x\n", machine().describe_context(), data);
+ m_space->write_byte(m_addr_latch, data);
+ break;
+
+ case 0x01: // Device Size register
+ LOG("%s data_w: Device Size register %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x02: // Address Increment register
+ LOG("%s data_w: Address Increment register %02x\n", machine().describe_context(), data);
+ m_addr_latch = (m_addr_latch & 0xffffff0) | ((m_addr_latch + 1) & 0x0f);
+ break;
+
+ case 0x03: // Address register
+ LOG("%s data_w: Address register %02x\n", machine().describe_context(), data);
+ if (m_addr_writes == 0)
+ m_addr_latch = 0x00;
+ m_addr_latch |= data << (m_addr_writes << 3);
+ m_addr_writes = (m_addr_writes + 1) & 3;
+ break;
+
+ case 0x07: // Control register
+ LOG("%s data_w: Control register %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s data_w: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ break;
+ }
+}
+
+uint8_t psion_asic4_device::data_r()
+{
+ uint8_t data = 0x00;
+
+ switch (m_sibo_control & 0xc0)
+ {
+ case 0x40: // SerialSelect
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x06: // Asic4Id
+ data = m_info_byte & 0xff; // A4InfoByte
+ break;
+ }
+ break;
+
+ case 0xc0: // SerialRead
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x00: // Data register
+ data = m_space->read_byte(m_addr_latch);
+ LOG("%s data_r: Data register %02x\n", machine().describe_context(), data);
+ m_addr_latch++;
+ break;
+
+ case 0x01: // Input register
+ data = (m_info_byte >> 4) & 0xf0;
+ LOG("%s data_r: Input register %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s data_r: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ break;
+ }
+
+ return data;
+}
diff --git a/src/devices/machine/psion_asic4.h b/src/devices/machine/psion_asic4.h
new file mode 100644
index 00000000000..42860d1c11d
--- /dev/null
+++ b/src/devices/machine/psion_asic4.h
@@ -0,0 +1,59 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC4
+
+******************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_ASIC4_H
+#define MAME_MACHINE_PSION_ASIC4_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> psion_asic4_device
+
+class psion_asic4_device : public device_t, public device_memory_interface
+{
+public:
+ psion_asic4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ void set_ext_info_byte(uint16_t info) { m_info_byte = info; }
+
+ void data_w(uint16_t data);
+ uint8_t data_r();
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ address_space_config m_space_config;
+
+ address_space *m_space;
+
+ static constexpr uint16_t NULL_FRAME = 0x000;
+ static constexpr uint16_t CONTROL_FRAME = 0x100;
+ static constexpr uint16_t DATA_FRAME = 0x200;
+
+ uint32_t m_addr_latch;
+ uint8_t m_addr_writes;
+
+ uint16_t m_info_byte;
+ uint8_t m_sibo_control;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_ASIC4, psion_asic4_device)
+
+#endif // MAME_MACHINE_PSION_ASIC4_H
diff --git a/src/devices/machine/psion_asic5.cpp b/src/devices/machine/psion_asic5.cpp
new file mode 100644
index 00000000000..4dfa2c17bb8
--- /dev/null
+++ b/src/devices/machine/psion_asic5.cpp
@@ -0,0 +1,458 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC5
+
+ ASIC5 is a general purpose I/O chip with a built-in UART that can be set to
+ run in a number of different modes thereby simplifying the task of peripheral
+ design. For example, it is possible to set up ASIC5 to run as a Centronics
+ parallel port interface, an 8-bit parallel I/O port, a serial bar code
+ controller or a serial RS232 converter.
+
+ PC6 PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0
+ Pack Mode Memory Type No. devices Memory Size
+ 1 0 0 0 RAM 0 0 1 device 0 0 0 No memory
+ 0 0 1 Type 1 Flash 0 1 2 devices 0 0 1 32K
+ 0 1 0 Type 2 Flash 1 0 3 devices 0 1 0 64K
+ 1 1 0 ROM 1 1 4 devices 0 1 1 128K
+ 1 1 1 Write protect 1 0 0 256K
+ 1 0 1 512K
+ 1 1 0 1M
+ Peripheral Mode Type
+ 0 x x 0 x x x x 1 RS232 port
+ x x 0 x x x 1 x Centronics (Parallel) port
+ x x 0 x x 1 x x ROM
+ x x 0 x 1 x x x Magnetic Card Reader
+ x x 0 0 x x x x Barcode reader
+ x x 0 1 x x x x USA modem
+ x 1 0 x x x x x Modem
+ 1 x 0 x x x x x RS232 TTL
+
+******************************************************************************/
+
+#include "emu.h"
+#include "psion_asic5.h"
+
+#define VERBOSE 0
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PSION_ASIC5, psion_asic5_device, "psion_asic5", "Psion ASIC5")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+psion_asic5_device::psion_asic5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PSION_ASIC5, tag, owner, clock)
+ , device_serial_interface(mconfig, *this)
+ , m_mode(~uint8_t(0))
+ , m_in_a_handler(*this, 0)
+ , m_in_b_handler(*this, 0)
+ , m_in_c_handler(*this, 0)
+ , m_out_a_handler(*this)
+ , m_out_b_handler(*this)
+ , m_out_c_handler(*this)
+ , m_out_d_handler(*this)
+ , m_out_cs_handler(*this)
+ , m_int_handler(*this)
+ , m_txd_handler(*this)
+ , m_rts_handler(*this)
+ , m_dtr_handler(*this)
+ , m_rxd(0)
+ , m_cts(0)
+ , m_dsr(0)
+ , m_dcd(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_validity_check - device-specific checks
+//-------------------------------------------------
+
+void psion_asic5_device::device_validity_check(validity_checker &valid) const
+{
+ if ((PACK_MODE != m_mode) && (PERIPHERAL_MODE != m_mode))
+ osd_printf_error("Power on reset pin PC6 not configured\n");
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_asic5_device::device_start()
+{
+ save_item(NAME(m_port_b_counter));
+ save_item(NAME(m_port_b_latch));
+ save_item(NAME(m_port_b_mode));
+ save_item(NAME(m_port_dc_select));
+ save_item(NAME(m_int_mask));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_control));
+ save_item(NAME(m_bdr));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_asic5_device::device_reset()
+{
+ m_port_b_counter = 0x00;
+ m_port_b_latch = 0x00;
+ m_port_b_mode = 0x00;
+ m_port_dc_select = false;
+ m_int_mask = 0x00;
+ m_int_status = 0x02; // UART transmitter empty
+ m_control = 0x00;
+ m_bdr = 0xffff;
+
+ receive_register_reset();
+ transmit_register_reset();
+}
+
+
+void psion_asic5_device::update_interrupts()
+{
+ int irq = m_int_status & m_int_mask;
+
+ m_int_handler(irq ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+void psion_asic5_device::rcv_callback()
+{
+ if (BIT(m_port_b_mode, 0)) // UART enabled
+ receive_register_update_bit(m_rxd);
+}
+
+void psion_asic5_device::rcv_complete()
+{
+ if (is_receive_framing_error() || is_receive_parity_error())
+ m_int_status |= 0x04;
+
+ m_int_status |= 0x01;
+ update_interrupts();
+}
+
+void psion_asic5_device::tra_callback()
+{
+ if (BIT(m_port_b_mode, 0)) // UART enabled
+ m_txd_handler(transmit_register_get_data_bit());
+}
+
+void psion_asic5_device::tra_complete()
+{
+ m_int_status |= 0x02;
+ update_interrupts();
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+void psion_asic5_device::data_w(uint16_t data)
+{
+ switch (data & 0x300)
+ {
+ case NULL_FRAME:
+ device_reset();
+ break;
+
+ case CONTROL_FRAME:
+ m_sibo_control = data & 0xff;
+
+ switch (m_sibo_control & 0xc0)
+ {
+ case 0x80: // SerialWrite
+ if (m_sibo_control == 0x93) // Multi Port D and C writes
+ m_port_dc_select = false;
+ break;
+ }
+ break;
+
+ case DATA_FRAME:
+ data &= 0xff;
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x00: // Port A write data
+ LOG("%s data_w: Port A write data %02x\n", machine().describe_context(), data);
+ m_out_a_handler(data);
+ if (BIT(m_port_b_mode, 1, 2) == 0) // Counter mode
+ {
+ m_out_b_handler(++m_port_b_counter);
+ }
+ break;
+
+ case 0x01: // Port B write data
+ LOG("%s data_w: Port B write data %02x\n", machine().describe_context(), data);
+ if (BIT(m_port_b_mode, 1, 2) == 1 && !BIT(m_control, 3)) // Latch mode
+ {
+ m_out_b_handler(m_port_b_latch = data);
+ }
+ break;
+
+ case 0x02: // Port B control
+ // b0 0 Memory mode, 1 Peripheral mode - enables UART
+ // b1 Port B mode
+ // b2 Port B mode
+ // b3 0 Normal mode, 1 Test mode
+ // b4 Not used
+ // b5 Not used
+ // b6 Not used
+ // b7 Not used
+ //
+ // Port B mode
+ // b2 b1 Mode
+ // 0 0 Counter mode
+ // 0 1 Latch mode
+ // 1 0 Baud rate out on port B
+ // 1 1 Test bus output on port B
+ LOG("%s data_w: Port B mode %02x\n", machine().describe_context(), data);
+ m_port_b_mode = data;
+ break;
+
+ case 0x03: // Port D and C write data
+ switch (BIT(m_port_b_mode, 0))
+ {
+ case 0:
+ if (m_port_dc_select)
+ {
+ LOG("%s data_w: Port C write data %02x\n", machine().describe_context(), data);
+ m_out_c_handler(data);
+ }
+ else
+ {
+ LOG("%s data_w: Port D write data %02x\n", machine().describe_context(), data);
+ m_out_d_handler(data);
+ if (BIT(m_port_b_mode, 1, 2) == 0) // Counter mode
+ {
+ m_out_b_handler(m_port_b_counter = 0);
+ }
+ }
+ m_port_dc_select = true;
+ break;
+ case 1: // UART enabled
+ m_rts_handler(BIT(data, 1));
+ m_dtr_handler(BIT(data, 2));
+ break;
+ }
+ break;
+
+ case 0x06: // Interrupt mask write
+ // b0 UART - UART character received
+ // b1 UART - UART transmitter empty
+ // b2 UART - UART error or modem line status change
+ // b3 PC7 - Barcode switch/general interrupt
+ // b4 SR - Synchronous port1 character received
+ // b5 SR - Synchronous port2 character received
+ // b6 PC4 - Barcode data/general interrupt
+ // b7 PA4 - Centronics busy low/general interrupt
+ LOG("%s data_w: Interrupt mask write %02x\n", machine().describe_context(), data);
+ m_int_mask = data;
+ update_interrupts();
+ break;
+
+ case 0x07: // Control register
+ LOG("%s data_w: Control register %02x\n", machine().describe_context(), data);
+ m_control = data;
+ m_out_cs_handler(data & 7);
+ break;
+
+ case 0x08: // UART Control register
+ // b0 Generate break character
+ // b1 Character length 1
+ // b2 Character length 2
+ // b3 Parity enabled if set
+ // b4 Odd parity if, even if clear
+ // b5 Set for two stop bits, clear for one
+ // b6 Not used
+ // b7 Not used
+ LOG("%s data_w: UART Control register %02x\n", machine().describe_context(), data);
+ set_data_frame(1, 5 + BIT(data, 1, 2), BIT(data, 3) ? (BIT(data, 4) ? PARITY_ODD : PARITY_EVEN) : PARITY_NONE, BIT(data, 5) ? STOP_BITS_2 : STOP_BITS_1);
+ receive_register_reset();
+ transmit_register_reset();
+ break;
+
+ case 0x09: // UART Transmit holding register
+ LOG("%s data_w: UART Transmit holding register %02x\n", machine().describe_context(), data);
+ transmit_register_setup(data);
+ m_int_status &= ~0x02;
+ update_interrupts();
+ break;
+
+ case 0x0a:
+ case 0x0b: // UART Baud rate
+ switch (m_sibo_control & 1)
+ {
+ case 0: m_bdr = (m_bdr & 0xff00) | (data << 0); break; // LSB
+ case 1: m_bdr = (m_bdr & 0x00ff) | (data << 8); break; // MSB
+ }
+ LOG("%s data_w: UART Baud rate divisor %04x, Baud rate %d\n", machine().describe_context(), m_bdr, clock() / 16 / (1 - m_bdr));
+ set_rate(clock() / 16 / (1 - m_bdr));
+ break;
+
+ case 0x0c: // Port 1 and 2 reset
+ LOG("%s data_w: Port 1 and 2 reset %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s data_w: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ break;
+ }
+}
+
+
+uint8_t psion_asic5_device::data_r()
+{
+ uint8_t data = 0x00;
+
+ switch (m_sibo_control & 0xc0)
+ {
+ case 0x40: // SerialSelect
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x02: // Asic5PackId
+ case 0x03: // Asic5NormalId
+ if (BIT(m_sibo_control, 0) == m_mode)
+ data = m_info_byte; // A5InfoByte
+ break;
+ }
+ break;
+
+ case 0xc0: // SerialRead
+ switch (m_sibo_control & 0x0f)
+ {
+ case 0x00: // Port A read data
+ data = m_in_a_handler();
+ LOG("%s data_r: Port A read data %02x\n", machine().describe_context(), data);
+ if (BIT(m_port_b_mode, 1, 2) == 0) // Counter mode
+ {
+ m_out_b_handler(++m_port_b_counter);
+ }
+ break;
+
+ case 0x01: // Port B read data
+ if (BIT(m_port_b_mode, 1, 2) == 1) // Latch mode
+ {
+ data = m_port_b_latch;
+ }
+ LOG("%s data_r: Port B read data %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x02: // Port B counter
+ if (BIT(m_port_b_mode, 1, 2) == 0) // Counter mode
+ {
+ m_out_b_handler(++m_port_b_counter);
+ }
+ LOG("%s data_r: Port B counter %02x\n", machine().describe_context(), m_port_b_counter);
+ break;
+
+ case 0x06: // Interrupt mask read
+ data = m_int_mask;
+ LOG("%s data_r: Interrupt mask read %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x07: // Interrupt status read
+ data = m_int_status & m_int_mask;
+ LOG("%s data_r: Interrupt status read %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x08: // UART Status register
+ // b0 State of the CTS line (PA1)
+ // b1 State of the DSR line (PA2)
+ // b2 State of the DCD line (PA3)
+ // b3 Transmitter buffer empty
+ // b4 Transmitter busy
+ // b5 Receive data waiting
+ // b6 Overrun or framing error
+ // b7 Parity error
+ data |= m_cts << 0;
+ data |= m_dsr << 1;
+ data |= m_dcd << 2;
+ data |= is_transmit_register_empty() ? 1 << 3 : 0;
+ data |= !is_transmit_register_empty() ? 1 << 4 : 0;
+ data |= is_receive_register_full() ? 1 << 5 : 0;
+ data |= is_receive_framing_error() ? 1 << 6 : 0;
+ data |= is_receive_parity_error() ? 1 << 7 : 0;
+ LOG("%s data_r: UART Status register %02x\n", machine().describe_context(), data);
+ m_int_status &= ~0x04;
+ update_interrupts();
+ break;
+
+ case 0x09: // UART Receive register
+ receive_register_extract();
+ data = get_received_char();
+ LOG("%s data_r: UART Receive register %02x\n", machine().describe_context(), data);
+ m_int_status &= ~0x01;
+ update_interrupts();
+ break;
+
+ case 0x0c: // Synchronous Port 1 read
+ LOG("%s data_r: Synchronous Port 1 read %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x0d: // Barcode read data
+ // b0 PC4
+ // b1 PC7
+ // b2 PB2
+ // b3 PB3
+ // b4 PB4
+ // b5 PB5
+ // b6 PB6
+ // b7 PB7
+ LOG("%s data_r: Barcode read data %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x0e: // Synchronous Port 2 read
+ LOG("%s data_r: Synchronous Port 2 read %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s data_r: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
+ break;
+ }
+ break;
+ }
+
+ return data;
+}
+
+
+void psion_asic5_device::write_rxd(int state)
+{
+ m_rxd = state;
+ device_serial_interface::rx_w(state);
+}
+
+void psion_asic5_device::write_cts(int state)
+{
+ if (m_cts != state)
+ m_int_status |= 0x04;
+ m_cts = state;
+ update_interrupts();
+
+}
+void psion_asic5_device::write_dsr(int state)
+{
+ if (m_dsr != state)
+ m_int_status |= 0x04;
+ m_dsr = state;
+ update_interrupts();
+}
+
+void psion_asic5_device::write_dcd(int state)
+{
+ if (m_dcd != state)
+ m_int_status |= 0x04;
+ m_dcd = state;
+ update_interrupts();
+}
diff --git a/src/devices/machine/psion_asic5.h b/src/devices/machine/psion_asic5.h
new file mode 100644
index 00000000000..3d6a17011dc
--- /dev/null
+++ b/src/devices/machine/psion_asic5.h
@@ -0,0 +1,121 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC5
+
+******************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_ASIC5_H
+#define MAME_MACHINE_PSION_ASIC5_H
+
+#pragma once
+
+#include "diserial.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> psion_asic5_device
+
+class psion_asic5_device : public device_t, public device_serial_interface
+{
+public:
+ enum pc6_state
+ {
+ PACK_MODE = 0,
+ PERIPHERAL_MODE = 1
+ };
+
+ psion_asic5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ static constexpr feature_type imperfect_features() { return feature::COMMS; }
+
+ void set_mode(pc6_state mode) { m_mode = mode; }
+
+ auto readpa_handler() { return m_in_a_handler.bind(); }
+ auto readpb_handler() { return m_in_b_handler.bind(); }
+ auto readpc_handler() { return m_in_c_handler.bind(); }
+
+ auto writepa_handler() { return m_out_a_handler.bind(); }
+ auto writepb_handler() { return m_out_b_handler.bind(); }
+ auto writepc_handler() { return m_out_c_handler.bind(); }
+ auto writepd_handler() { return m_out_d_handler.bind(); }
+ auto writecs_handler() { return m_out_cs_handler.bind(); }
+
+ // UART handlers
+ auto int_handler() { return m_int_handler.bind(); }
+ auto txd_handler() { return m_txd_handler.bind(); }
+ auto rts_handler() { return m_rts_handler.bind(); }
+ auto dtr_handler() { return m_dtr_handler.bind(); }
+
+ void write_rxd(int state);
+ void write_cts(int state);
+ void write_dsr(int state);
+ void write_dcd(int state);
+
+ void set_info_byte(uint8_t info) { m_info_byte = info; }
+
+ void data_w(uint16_t data);
+ uint8_t data_r();
+
+protected:
+ // device_t overrides
+ virtual void device_validity_check(validity_checker &valid) const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_serial overrides
+ virtual void rcv_callback() override;
+ virtual void rcv_complete() override;
+ virtual void tra_callback() override;
+ virtual void tra_complete() override;
+
+private:
+ static constexpr uint16_t NULL_FRAME = 0x000;
+ static constexpr uint16_t CONTROL_FRAME = 0x100;
+ static constexpr uint16_t DATA_FRAME = 0x200;
+
+ void update_interrupts();
+
+ uint8_t m_mode;
+
+ devcb_read8 m_in_a_handler;
+ devcb_read8 m_in_b_handler;
+ devcb_read8 m_in_c_handler;
+ devcb_write8 m_out_a_handler;
+ devcb_write8 m_out_b_handler;
+ devcb_write8 m_out_c_handler;
+ devcb_write8 m_out_d_handler;
+ devcb_write8 m_out_cs_handler;
+
+ devcb_write_line m_int_handler;
+ devcb_write_line m_txd_handler;
+ devcb_write_line m_rts_handler;
+ devcb_write_line m_dtr_handler;
+
+ int m_rxd;
+ int m_cts;
+ int m_dsr;
+ int m_dcd;
+
+ uint8_t m_port_b_counter;
+ uint8_t m_port_b_latch;
+ uint8_t m_port_b_mode;
+ bool m_port_dc_select;
+ uint8_t m_int_mask;
+ uint8_t m_int_status;
+ uint8_t m_control;
+ int16_t m_bdr;
+
+ uint8_t m_info_byte;
+ uint8_t m_sibo_control;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_ASIC5, psion_asic5_device)
+
+#endif // MAME_MACHINE_PSION_ASIC5_H
diff --git a/src/devices/machine/psion_asic9.cpp b/src/devices/machine/psion_asic9.cpp
new file mode 100644
index 00000000000..6bc54cd8332
--- /dev/null
+++ b/src/devices/machine/psion_asic9.cpp
@@ -0,0 +1,1202 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC9
+
+ ASIC9 is a composite chip comprising of a V30H processor, ASIC1, ASIC2 and
+ general I/O and PSU control logic all on one IC. ASIC9 thus integrates all
+ the digital logic required to produce a SIBO architecture computer less the
+ memory onto one chip. ASIC9 has a few additional features such as an extra
+ free-running clock (FRC) and a codec interface for sound.
+
+ TODO:
+ - improve RAM configuration for mx machines
+ - set RTC timer
+ - ASIC9MX implements V30MX, and likely the Temic (Condor) device found in 3c/Siena
+
+******************************************************************************/
+
+#include "emu.h"
+#include "psion_asic9.h"
+#include "cpu/nec/nec.h"
+#include "screen.h"
+
+
+#define VERBOSE 0
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PSION_ASIC9, psion_asic9_device, "psion_asic9", "Psion ASIC9 V30H")
+DEFINE_DEVICE_TYPE(PSION_ASIC9MX, psion_asic9mx_device, "psion_asic9mx", "Psion ASIC9 V30MX")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+psion_asic9_device::psion_asic9_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , device_video_interface(mconfig, *this)
+ , m_v30(*this, "v30")
+ , m_ram(*this, finder_base::DUMMY_TAG)
+ , m_rom(*this, finder_base::DUMMY_TAG)
+ , m_ram_config("asic9_ram", ENDIANNESS_LITTLE, 16, 24, 0)
+ , m_rom_config("asic9_rom", ENDIANNESS_LITTLE, 16, 24, 0)
+ , m_tick_timer(nullptr)
+ , m_frc1_timer(nullptr)
+ , m_frc2_timer(nullptr)
+ , m_watchdog_timer(nullptr)
+ , m_rtc_timer(nullptr)
+ , m_snd_timer(nullptr)
+ , m_buz_cb(*this)
+ , m_col_cb(*this)
+ , m_port_ab_r(*this, 0)
+ , m_port_ab_w(*this)
+ , m_pcm_in(*this, 0)
+ , m_pcm_out(*this)
+ , m_data_r(*this, 0x00)
+ , m_data_w(*this)
+{
+}
+
+psion_asic9_device::psion_asic9_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : psion_asic9_device(mconfig, PSION_ASIC9, tag, owner, clock)
+{
+}
+
+psion_asic9mx_device::psion_asic9mx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : psion_asic9_device(mconfig, PSION_ASIC9MX, tag, owner, clock)
+{
+}
+
+
+void psion_asic9_device::mem_map(address_map &map)
+{
+ map(0x00000, 0xfffff).rw(FUNC(psion_asic9_device::mem_r), FUNC(psion_asic9_device::mem_w));
+}
+
+void psion_asic9_device::io_map(address_map &map)
+{
+ map(0x0000, 0x00ff).rw(FUNC(psion_asic9_device::io_r), FUNC(psion_asic9_device::io_w));
+}
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void psion_asic9_device::device_add_mconfig(machine_config &config)
+{
+ V30(config, m_v30, DERIVED_CLOCK(1, 1));
+ m_v30->set_addrmap(AS_PROGRAM, &psion_asic9_device::mem_map);
+ m_v30->set_addrmap(AS_IO, &psion_asic9_device::io_map);
+ m_v30->set_irq_acknowledge_callback(FUNC(psion_asic9_device::inta_cb));
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector psion_asic9_device::memory_space_config() const
+{
+ return space_config_vector{
+ std::make_pair(AS_A9_RAM, &m_ram_config),
+ std::make_pair(AS_A9_ROM, &m_rom_config)
+ };
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_asic9_device::device_start()
+{
+ if (!m_ram->started())
+ throw device_missing_dependencies();
+
+ m_ram_space = &space(AS_A9_RAM);
+ m_rom_space = &space(AS_A9_ROM);
+
+ switch (m_ram->size())
+ {
+ case 0x010000: case 0x020000:
+ m_ram_type = 0;
+ break;
+
+ case 0x040000: case 0x080000:
+ m_ram_type = 1;
+ break;
+
+ case 0x100000: case 0x200000:
+ m_ram_type = 2;
+ break;
+
+ case 0x400000: case 0x800000:
+ m_ram_type = 3;
+ break;
+ }
+
+ configure_ram(m_ram_type);
+ configure_rom();
+
+ m_tick_timer = timer_alloc(FUNC(psion_asic9_device::tick), this);
+ m_frc1_timer = timer_alloc(FUNC(psion_asic9_device::frc1), this);
+ m_frc2_timer = timer_alloc(FUNC(psion_asic9_device::frc2), this);
+ m_watchdog_timer = timer_alloc(FUNC(psion_asic9_device::watchdog), this);
+ m_rtc_timer = timer_alloc(FUNC(psion_asic9_device::rtc), this);
+ m_snd_timer = timer_alloc(FUNC(psion_asic9_device::snd), this);
+ m_busy_timer = timer_alloc(FUNC(psion_asic9_device::busy), this);
+
+ m_a9_control = 0x00;
+ m_a9_status = 0x00;
+
+ save_item(NAME(m_a9_control));
+ save_item(NAME(m_a9_lcd_size));
+ save_item(NAME(m_a9_interrupt_status));
+ save_item(NAME(m_a9_interrupt_mask));
+ save_item(NAME(m_a9_protection_mode));
+ save_item(NAME(m_a9_protection_upper));
+ save_item(NAME(m_a9_protection_lower));
+ save_item(NAME(m_a9_port_ab_ddr));
+ save_item(NAME(m_a9_port_c_ddr));
+ save_item(NAME(m_a9_port_d_ddr));
+ save_item(NAME(m_a9_psel_6000));
+ save_item(NAME(m_a9_psel_7000));
+ save_item(NAME(m_a9_psel_8000));
+ save_item(NAME(m_a9_psel_9000));
+ save_item(NAME(m_a9_control_extra));
+ save_item(NAME(m_frc1_count));
+ save_item(NAME(m_frc1_reload));
+ save_item(NAME(m_frc2_count));
+ save_item(NAME(m_frc2_reload));
+ save_item(NAME(m_watchdog_count));
+ save_item(NAME(m_rtc));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_asic9_device::device_reset()
+{
+ m_tick_timer->adjust(attotime::from_hz(32.768), 0, attotime::from_hz(32.768));
+ m_frc1_timer->adjust(attotime::from_hz(512000), 0, attotime::from_hz(512000));
+ m_frc2_timer->adjust(attotime::from_hz(512000), 0, attotime::from_hz(512000));
+ m_watchdog_timer->adjust(attotime::from_hz(4), 0, attotime::from_hz(4));
+ m_rtc_timer->adjust(attotime::from_hz(1), 0, attotime::from_hz(1));
+ m_snd_timer->adjust(attotime::from_hz(8000), 0, attotime::from_hz(8000)); // unknown data rate
+
+ m_post = 0x00;
+
+ m_a9_interrupt_status = 0x00;
+ m_a9_interrupt_mask = 0x00;
+
+ m_frc1_count = 0;
+ m_frc1_reload = 0;
+ m_frc2_count = 0;
+ m_frc2_reload = 0;
+ m_buz_toggle = 0;
+ m_watchdog_count = 0;
+ m_a9_protection_mode = false;
+ m_a9_protection_lower = 0x00;
+ m_a9_protection_upper = 0x00;
+ m_a9_port_ab_ddr = 0x00;
+ m_a9_port_c_ddr = 0x00;
+ m_a9_port_d_ddr = 0x00;
+ m_a9_psel_6000 = 0x00;
+ m_a9_psel_7000 = 0x00;
+ m_a9_psel_8000 = 0x00;
+ m_a9_psel_9000 = 0x00;
+ m_a9_control_extra = 0x00;
+ m_rtc = 0;
+
+ m_a9_status |= 0x0020; // A9MMainsPresent
+ m_a9_status |= 0xe000; // A9MCold
+
+ m_a9_serial_control = 0x00;
+ m_a9_channel_select = 0x00;
+}
+
+
+TIMER_CALLBACK_MEMBER(psion_asic9_device::tick)
+{
+ m_a9_interrupt_status |= 0x02; // Timer
+ update_interrupts();
+}
+
+TIMER_CALLBACK_MEMBER(psion_asic9_device::frc1)
+{
+ switch (--m_frc1_count)
+ {
+ case 0x0000:
+ if (BIT(m_a9_control_extra, 5)) // A9MBuzzFromFrc1OrTog
+ {
+ m_buz_cb(m_buz_toggle ^= 1);
+ }
+ m_a9_interrupt_status |= 0x40; // A9MFrc1
+ update_interrupts();
+ break;
+
+ case 0xffff:
+ if (BIT(m_a9_control, 12)) // A9MFrc1PreScale
+ m_frc1_count = m_frc1_reload;
+ break;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(psion_asic9_device::frc2)
+{
+ switch (--m_frc2_count)
+ {
+ case 0x0000:
+ m_a9_interrupt_status |= 0x80; // A9MFrc2
+ update_interrupts();
+ break;
+
+ case 0xffff:
+ if (BIT(m_a9_control, 14)) // A9MFrc2PreScale
+ m_frc2_count = m_frc2_reload;
+ break;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(psion_asic9_device::watchdog)
+{
+ m_watchdog_count++;
+ m_watchdog_count &= 3;
+
+ if (m_watchdog_count == 3)
+ {
+ m_a9_status |= 0x0001; // A9MWatchDogNMI
+ update_interrupts();
+ }
+}
+
+TIMER_CALLBACK_MEMBER(psion_asic9_device::rtc)
+{
+ m_rtc++;
+}
+
+TIMER_CALLBACK_MEMBER(psion_asic9_device::snd)
+{
+ if (BIT(m_a9_control, 11)) // A9MSoundEnable
+ {
+ switch (BIT(m_a9_control_extra, 7)) // A9MSoundDir
+ {
+ case 0:
+ if (!m_snd_fifo.full())
+ m_snd_fifo.enqueue(m_pcm_in());
+ if (m_snd_fifo.full())
+ m_a9_status |= 0x0800;
+ break;
+
+ case 1:
+ if (!m_snd_fifo.empty())
+ m_pcm_out(m_snd_fifo.dequeue());
+ if (!m_snd_fifo.full())
+ m_a9_status &= ~0x0800;
+ break;
+ }
+ m_a9_interrupt_status |= 0x01; // Sound
+ update_interrupts();
+ }
+}
+
+void psion_asic9_device::sds_int_w(int state)
+{
+ if (state)
+ m_a9_interrupt_status |= 0x04; // A9MSlave
+ else
+ m_a9_interrupt_status &= ~0x04;
+
+ update_interrupts();
+}
+
+void psion_asic9_device::eint0_w(int state)
+{
+ if (state)
+ m_a9_interrupt_status |= 0x08; // A9MExpIntC
+ else
+ m_a9_interrupt_status &= ~0x08;
+
+ update_interrupts();
+}
+
+void psion_asic9_device::eint1_w(int state)
+{
+ if (state)
+ m_a9_interrupt_status |= 0x10; // A9MExpIntA
+ else
+ m_a9_interrupt_status &= ~0x10;
+
+ update_interrupts();
+}
+
+void psion_asic9_device::eint2_w(int state)
+{
+ if (state)
+ m_a9_interrupt_status |= 0x20; // A9MExpIntB
+ else
+ m_a9_interrupt_status &= ~0x20;
+
+ update_interrupts();
+}
+
+
+void psion_asic9_device::medchng_w(int state)
+{
+ if (state)
+ m_a9_status |= 0x04; // A9MDoorNMI
+ else
+ m_a9_status &= ~0x04;
+
+ update_interrupts();
+}
+
+void psion_asic9_device::update_interrupts()
+{
+ bool irq = m_a9_interrupt_status & m_a9_interrupt_mask;
+ bool nmi = m_a9_status & 0x000f;
+
+ m_v30->set_input_line(INPUT_LINE_IRQ0, irq ? ASSERT_LINE : CLEAR_LINE);
+ m_v30->set_input_line(INPUT_LINE_NMI, nmi ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+IRQ_CALLBACK_MEMBER(psion_asic9_device::inta_cb)
+{
+ // IRQ Vector Name Description
+ // 0 0x78 CSINT CODEC sound interrupt.
+ // 1 0x79 TINT 32 Hz tick interrupt.
+ // 2 0x7A SSINT Serial slave interrupt.
+ // 3 0x7B EINT0 External interrupt input 0.
+ // 4 0x7C EINT1 External interrupt input 1 (inverted).
+ // 5 0x7D EINT2 External interrupt input 2 (inverted).
+ // 6 0x7E FRC1OI FRC1 overflow interrupt.
+ // 7 0x7F FRC2OI FRC2 overflow interrupt.
+ uint8_t vector = 0x78;
+ for (int irq = 0; irq < 8; irq++)
+ {
+ if (m_a9_interrupt_status & m_a9_interrupt_mask & (1 << irq))
+ {
+ vector += irq;
+ break;
+ }
+ }
+ return vector;
+}
+
+
+TIMER_CALLBACK_MEMBER(psion_asic9_device::busy)
+{
+ m_v30->set_input_line(NEC_INPUT_LINE_POLL, ASSERT_LINE);
+}
+
+
+//**************************************************************************
+// RAM/ROM CONFIGURATION
+//**************************************************************************
+
+uint32_t psion_asic9_device::ram_device_size(uint8_t device_type)
+{
+ uint32_t size = 0;
+
+ switch (device_type & 3)
+ {
+ case 0: size = 0x010000; break; // 256KBits
+ case 1: size = 0x040000; break; // 1MBits
+ case 2: size = 0x100000; break; // 4MBits
+ case 3: size = 0x400000; break; // 16MBits
+ }
+ return size;
+}
+
+void psion_asic9_device::configure_ram(uint8_t device_type)
+{
+ uint32_t device_size_actual = ram_device_size(m_ram_type);
+ uint32_t device_size_test = ram_device_size(device_type);
+
+ m_ram_space->unmap_readwrite(0, 0xffffff);
+
+ for (int i = 0; i < (m_ram->size() / device_size_actual); i++)
+ {
+ offs_t addrstart = device_size_test * i;
+ offs_t addrend = (device_size_test * i) + std::min(device_size_actual, device_size_test) - 1;
+ offs_t addrmirror = 0xffffff ^ ((device_size_test * 4) - 1);
+
+ if (device_size_actual < device_size_test)
+ addrmirror ^= (device_size_test - device_size_actual);
+
+ LOG("configure_ram: %d type %d ramsize %06x devsize %06x start %06x end %06x mirror %06x\n", i, device_type, m_ram->size(), device_size_actual, addrstart, addrend, addrmirror);
+ m_ram_space->install_ram(addrstart, addrend, addrmirror, m_ram->pointer() + (device_size_actual * i));
+ }
+}
+
+void psion_asic9_device::configure_rom()
+{
+ m_rom_space->install_rom(0x800000, 0x800000 + m_rom->bytes() - 1, 0x7fffff ^ (m_rom->bytes() - 1), m_rom->base());
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+uint8_t psion_asic9_device::col_r()
+{
+ return m_a9_control_extra & 0x0f;
+}
+
+
+bool psion_asic9_device::is_protected(offs_t offset)
+{
+ if (m_a9_protection_mode && (offset <= m_a9_protection_lower || offset > m_a9_protection_upper))
+ {
+ LOG("%s is_protected: %05x < %05x <= %05x\n", machine().describe_context(), m_a9_protection_lower, offset, m_a9_protection_upper);
+ m_a9_status |= 0x0002; // A9MProtectedModeNMI
+ update_interrupts();
+ return true;
+ }
+ return false;
+}
+
+offs_t psion_asic9_device::translate_address(offs_t offset)
+{
+ switch (offset & 0xf0000)
+ {
+ case 0x00000: case 0x10000: case 0x20000: case 0x30000: case 0x40000: case 0x50000:
+ break;
+
+ case 0x60000:
+ offset = (m_a9_psel_6000 << 16) | (offset & 0xffff);
+ break;
+
+ case 0x70000:
+ offset = (m_a9_psel_7000 << 16) | (offset & 0xffff);
+ break;
+
+ case 0x80000:
+ offset = (m_a9_psel_8000 << 16) | (offset & 0xffff);
+ break;
+
+ case 0x90000:
+ offset = (m_a9_psel_9000 << 16) | (offset & 0xffff);
+ break;
+
+ case 0xa0000: case 0xb0000: case 0xc0000: case 0xd0000: case 0xe0000: case 0xf0000:
+ offset = 0xf00000 | offset;
+ break;
+ }
+ return offset;
+}
+
+uint16_t psion_asic9_device::mem_r(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t data = 0xffff;
+
+ offset <<= 1;
+
+ offs_t addr = translate_address(offset);
+
+ switch (offset & 0x80000)
+ {
+ case 0x00000:
+ data = m_ram_space->read_word(addr, mem_mask);
+ break;
+
+ case 0x80000:
+ data = m_rom_space->read_word(addr, mem_mask);
+ break;
+ }
+
+ return data;
+}
+
+void psion_asic9_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ offset <<= 1;
+
+ offs_t addr = translate_address(offset);
+
+ if (!is_protected(addr))
+ {
+ switch (offset & 0x80000)
+ {
+ case 0x00000:
+ m_ram_space->write_word(addr, data, mem_mask);
+ break;
+ }
+ }
+}
+
+
+uint16_t psion_asic9_device::io_r(offs_t offset, uint16_t mem_mask)
+{
+ uint16_t data = 0x00;
+
+ offset <<= 1;
+
+ switch (offset)
+ {
+ case 0x00: // A9Index - Not used
+ LOG("%s io_r: A9Index => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x02: // A9WControl
+ // b0 A9MDisableClockDivide
+ // b1 A9MDisableIoWait
+ // b2 A9MDisableMemWait
+ // b3-b4 A9MRamDeviceSize
+ // b5 A9MDisableDMADivide
+ // b6 A9MArmStandBy
+ // b7 A9MZeroIsGrayMode
+ // b8 A9MDoorNMIEnable
+ // b9 A9MLowBatNMIEnable
+ // b10 A9MLcdEnable
+ // b11 A9MSoundEnable
+ // b12 A9MFrc1PreScale
+ // b13 A9MFrc1Is512KHzOr1Hz
+ // b14 A9MFrc2PreScale
+ // b15 A9MFrc2Is512KHzOr1KHz
+ data = m_a9_control; // | 0x18;
+ LOG("%s io_r: A9WControl => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x04: // A9WStatus
+ // b0 A9MWatchDogNMI
+ // b1 A9MProtectedModeNMI
+ // b2 A9MDoorNMI
+ // b3 A9MLowBatNMI
+ // b4 A9MDoorSwitch
+ // b5 A9MMainsPresent
+ // b6 A9MSlaveClock
+ // b7 A9MKeyboard
+ // b8 A9MSlaveDataValid
+ // b9 A9MSlaveControlFrame
+ // b10 A9MSlaveOverrun
+ // b11 A9MFifoFull
+ // b12 A9MNoBattery
+ // b13 A9MReset
+ // b14 A9MPowerFail
+ // b15 A9MCold
+ data = m_a9_status;
+ if (!machine().side_effects_disabled())
+ {
+ m_a9_status &= ~0x2000; // clear A9MReset
+ }
+ LOG("%s io_r: A9WStatus => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x06: // A9BInterruptStatus
+ if (ACCESSING_BITS_0_7)
+ {
+ data = m_a9_interrupt_status & m_a9_interrupt_mask;
+ LOG("%s io_r: A9InterruptStatus => %02x\n", machine().describe_context(), data);
+ }
+ break;
+
+ case 0x08: // A9BInterruptMask
+ if (ACCESSING_BITS_0_7)
+ {
+ data = m_a9_interrupt_mask;
+ LOG("%s io_r: A9BInterruptMask => %02x\n", machine().describe_context(), data);
+ }
+ break;
+
+ case 0x12: // A9WFrc1Data
+ data = m_frc1_count;
+ LOG("%s io_r: A9WFrc1Data => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x14: // A9BProtectionOff
+ if (ACCESSING_BITS_0_7)
+ {
+ //LOG("%s io_r: A9BProtectionOff => %02x\n", machine().describe_context(), data);
+ m_a9_protection_mode = false;
+ }
+ break;
+
+ case 0x1a: // A9BSoundData
+ if (ACCESSING_BITS_0_7)
+ {
+ data = m_snd_fifo.dequeue();
+ if (!m_snd_fifo.full())
+ m_a9_status &= ~0x0800;
+ LOG("%s io_r: A9BSoundData => %02x\n", machine().describe_context(), data);
+ }
+ break;
+
+ case 0x1e: // A9WFrc2Data
+ data = m_frc2_count;
+ LOG("%s io_r: A9WFrc2Data => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x20: // A9WPortABData
+ data = m_port_ab_r() & ~m_a9_port_ab_ddr;
+ LOG("%s io_r: A9WPortABData => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x22: // A9WPortABDDR
+ if (ACCESSING_BITS_0_7)
+ {
+ data |= m_a9_port_ab_ddr & 0x00ff;
+ LOG("%s io_r: A9WPortADDR => %02x\n", machine().describe_context(), data);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ data |= m_a9_port_ab_ddr & 0xff00;
+ LOG("%s io_r: A9WPortBDDR => %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x24: // A9WPortCDData
+ if (ACCESSING_BITS_0_7)
+ {
+ data |= 0x00;
+ LOG("%s io_r: A9WPortCData => %02x\n", machine().describe_context(), data);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ data |= 0x00 << 8;
+ LOG("%s io_r: A9WPortDData => %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x26: // A9BPortCDDDR
+ if (ACCESSING_BITS_0_7)
+ {
+ data |= m_a9_port_c_ddr;
+ LOG("%s io_r: A9BPortCDDR => %04x\n", machine().describe_context(), data);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ data |= m_a9_port_d_ddr << 8;
+ LOG("%s io_r: A9WPortDDDR <= %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x28: // A9BPageSelect6000
+ if (ACCESSING_BITS_0_7)
+ {
+ data |= m_a9_psel_6000;
+ LOG("%s io_r: A9BPageSelect6000 => %02x\n", machine().describe_context(), data);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ data |= m_a9_psel_7000 << 8;
+ LOG("%s io_r: A9BPageSelect7000 => %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x2a: // A9BPageSelect8000
+ if (ACCESSING_BITS_0_7)
+ {
+ data |= m_a9_psel_8000;
+ //LOG("%s io_r: A9BPageSelect8000 => %02x\n", machine().describe_context(), data);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ data |= m_a9_psel_9000 << 8;
+ //LOG("%s io_r: A9BPageSelect9000 => %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x2c: // A9WControlExtra
+ data = m_a9_control_extra;
+ LOG("%s io_r: A9WControlExtra => %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x2e: // A9WPumpControl
+ LOG("%s io_r: A9WPumpControl <= %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x80: // A9WRtcLSW
+ data = m_rtc & 0x0000ffff;
+ //LOG("%s io_r: A9WRtcLSW <= %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x82: // A9WRtcMSW
+ data = (m_rtc & 0xffff0000) >> 16;
+ //LOG("%s io_r: A9WRtcMSW <= %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x88: // A9BSlaveData
+ LOG("%s io_r: A9BSlaveData <= %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x8a: // A9BSerialData
+ data = m_a9_serial_data;
+ if ((m_a9_serial_control & 0x10) == 0x10)
+ m_a9_serial_data = receive_frame();
+ LOG("%s io_r: A9BSerialData => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x8e: // A9BChannelSelect
+ data = m_a9_channel_select;
+ break;
+
+ default:
+ logerror("%s io_r: Unhandled register %02x => %04x\n", machine().describe_context(), offset, data);
+ break;
+ }
+ return data;
+}
+
+void psion_asic9_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ offset <<= 1;
+
+ switch (offset)
+ {
+ case 0x00: // Post
+ if (m_post != data)
+ {
+ switch (data)
+ {
+ case 0x10: LOG("%s io_w: Post <= %02x ROM Test\n", machine().describe_context(), data); break;
+ case 0x20: LOG("%s io_w: Post <= %02x System RAM Test\n", machine().describe_context(), data); break;
+ case 0x30: LOG("%s io_w: Post <= %02x Video RAM Test\n", machine().describe_context(), data); break;
+ case 0xf0: LOG("%s io_w: Post <= %02x Complete\n", machine().describe_context(), data); break;
+ default: LOG("%s io_w: Post <= %02x Unknown\n", machine().describe_context(), data); break;
+ }
+ m_post = data;
+ }
+ break;
+
+ case 0x02: // A9WControl
+ // b0 A9MDisableClockDivide
+ // b1 A9MDisableIoWait
+ // b2 A9MDisableMemWait
+ // b3-b4 A9MRamDeviceSize
+ // b5 A9MDisableDMADivide
+ // b6 A9MArmStandBy
+ // b7 A9MZeroIsGrayMode
+ // b8 A9MDoorNMIEnable
+ // b9 A9MLowBatNMIEnable
+ // b10 A9MLcdEnable
+ // b11 A9MSoundEnable
+ // b12 A9MFrc1PreScale
+ // b13 A9MFrc1Is512KHzOr1Hz
+ // b14 A9MFrc2PreScale
+ // b15 A9MFrc2Is512KHzOr1KHz
+ LOG("%s io_w: A9WControl <= %04x, RamDeviceSize %s, Frc1 %s%s, Frc2 %s%s\n", machine().describe_context(), data,
+ BIT(data, 3,2) == 0 ? "256KBits" : (BIT(data, 3,2) == 1 ? "1MBits" : (BIT(data, 3,2) == 2 ? "4MBits" : "16MBits")),
+ BIT(data, 13) ? "512KHz" : "1Hz", BIT(data, 12) ? " PreScale" : "",
+ BIT(data, 15) ? "512KHz" : "1024Hz", BIT(data, 14) ? " PreScale" : "");
+
+ if (BIT(data, 3, 2) != BIT(m_a9_control, 3, 2))
+ {
+ configure_ram(BIT(data, 3, 2));
+ }
+ if (BIT(data, 13) != BIT(m_a9_control, 13))
+ {
+ if (data & 0x2000)
+ m_frc1_timer->adjust(attotime::zero, 0, attotime::from_hz(512000));
+ else
+ m_frc1_timer->adjust(attotime::zero, 0, attotime::from_hz(1));
+ }
+ if (BIT(data, 15) != BIT(m_a9_control, 15))
+ {
+ if (data & 0x8000)
+ m_frc2_timer->adjust(attotime::zero, 0, attotime::from_hz(512000));
+ else
+ m_frc2_timer->adjust(attotime::zero, 0, attotime::from_hz(1024));
+ }
+ m_a9_control = data;
+ break;
+
+ case 0x04: // A9WLcdSize
+ // b0-b10 A9MLcdNumberOfPixels - (end of frame address / 16) - 1
+ // b11-b15 A9MLcdLineLength - (number of pixels per line / 32) - 1
+ LOG("%s io_w: A9WLcdSize <= %04x, Pixels in line %d, Total pixels in display %d\n", machine().describe_context(), data, (BIT(data, 11, 5) + 1) * 32, (BIT(data, 0, 11) + 1) * 128);
+ m_a9_lcd_size = data;
+ break;
+
+ case 0x06: // A9WLcdControl
+ // b0-b4 LcdPixelRate - 3
+ // b5-b9 LcdACLineRate - 13
+ // b10-b11 LcdMode - 3 (Dual Screen mode)
+ LOG("%s io_w: A9WLcdControl <= %04x, Mode %d %s Page\n", machine().describe_context(), data, BIT(data, 10,2), BIT(data, 10,2) == 3 ? "Dual" : "Single");
+ break;
+
+ case 0x08: // A9BInterruptMask
+ if (ACCESSING_BITS_0_7)
+ {
+ // b0 A9MSound
+ // b1 A9MTimer
+ // b2 A9MSlave
+ // b3 A9MExpIntC
+ // b4 A9MExpIntA
+ // b5 A9MExpIntB
+ // b6 A9MFrc1
+ // b7 A9MFrc2
+ LOG("%s io_w: A9BInterruptMask <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_interrupt_mask = data & 0xff;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9BNmiClear <= %02x\n", machine().describe_context(), data >> 8);
+ m_a9_status &= 0xfff0;
+ }
+ update_interrupts();
+ break;
+
+ case 0x0a: // A9BNonSpecificEoi
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9BNonSpecificEoi <= %02x\n", machine().describe_context(), data & 0xff);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9BStartFlagClear <= %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x0c: // A9BTimerEoiW
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9BTimerEoi <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_interrupt_status &= ~0x02; // Timer
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9BSerialSlaveEoi <= %02x\n", machine().describe_context(), data >> 8);
+ m_a9_interrupt_status &= ~0x04; // SerialSlave
+ }
+ update_interrupts();
+ break;
+
+ case 0x0e: // A9Frc1Eoi
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9Frc1Eoi <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_interrupt_status &= ~0x40; // Frc1Expired
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9Frc2Eoi <= %02x\n", machine().describe_context(), data >> 8);
+ m_a9_interrupt_status &= ~0x80; // Frc2Expired
+ }
+ update_interrupts();
+ break;
+
+ case 0x10: // A9WResetWatchDog
+ //LOG("%s io_w: A9WResetWatchDog <= %04x\n", machine().describe_context(), data);
+ m_watchdog_count = 0;
+ break;
+
+ case 0x12: // A9WFrc1Data
+ LOG("%s io_w: A9WFrc1Data <= %04x\n", machine().describe_context(), data);
+ m_frc1_reload = data;
+ m_frc1_count = data;
+ break;
+
+ case 0x14: // A9BProtectionOn
+ if (ACCESSING_BITS_0_7)
+ {
+ //LOG("%s io_w: A9BProtectionOn <= %02x\n", machine().describe_context(), data);
+ m_a9_protection_mode = true;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ //LOG("%s io_w: A9BProtectionOff <= %02x\n", machine().describe_context(), data);
+ m_a9_protection_mode = false;
+ }
+ break;
+
+ case 0x16: // A9WProtectionUpper
+ //LOG("%s io_w: A9WProtectionUpper <= %04x\n", machine().describe_context(), data);
+ m_a9_protection_upper = (data << 4) | 0x0f;
+ break;
+
+ case 0x18: // A9WProtectionLower
+ //LOG("%s io_w: A9WProtectionLower <= %04x\n", machine().describe_context(), data);
+ m_a9_protection_lower = data << 4;
+ break;
+
+ case 0x1a: // A9BSoundData
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9BSoundData <= %04x\n", machine().describe_context(), data);
+ m_snd_fifo.enqueue(data & 0xff);
+ if (m_snd_fifo.full())
+ m_a9_status |= 0x0800;
+ }
+ break;
+
+ case 0x1c: // A9BSoundEoi
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9BSoundEoi <= %02x\n", machine().describe_context(), data);
+ m_a9_interrupt_status &= ~0x01; // Sound
+ update_interrupts();
+ }
+ break;
+
+ case 0x1e: // A9WFrc2Data
+ LOG("%s io_w: A9WFrc2Data <= %04x\n", machine().describe_context(), data);
+ m_frc2_reload = data;
+ m_frc2_count = data;
+ break;
+
+ case 0x20: // A9WPortABData
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9WPortAData <= %02x\n", machine().describe_context(), data & 0xff);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9WPortBData <= %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x22: // A9WPortABDDR
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9WPortADDR <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_port_ab_ddr = (m_a9_port_ab_ddr & 0xff00) | data;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9WPortBDDR <= %02x\n", machine().describe_context(), data >> 8);
+ m_a9_port_ab_ddr = (m_a9_port_ab_ddr & 0x00ff) | (data << 8);
+ }
+ break;
+
+ case 0x24: // A9WPortCDData
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9WPortCData <= %02x\n", machine().describe_context(), data & 0xff);
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9WPortDData <= %02x\n", machine().describe_context(), data >> 8);
+ }
+ break;
+
+ case 0x26: // A9BPortCDDDR
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9WPortCDDR <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_port_c_ddr = data & 0xff;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9WPortDDDR <= %02x\n", machine().describe_context(), data >> 8);
+ m_a9_port_d_ddr = data >> 8;
+ }
+ break;
+
+ case 0x28: // A9BPageSelect6000
+ if (ACCESSING_BITS_0_7)
+ {
+ LOG("%s io_w: A9BPageSelect6000 <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_psel_6000 = data & 0xff;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ LOG("%s io_w: A9BPageSelect7000 <= %02x\n", machine().describe_context(), data >> 8);
+ m_a9_psel_7000 = data >> 8;
+ }
+ break;
+
+ case 0x2a: // A9BPageSelect8000
+ if (ACCESSING_BITS_0_7)
+ {
+ //LOG("%s io_w: A9BPageSelect8000 <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_psel_8000 = data & 0xff;
+ }
+ if (ACCESSING_BITS_8_15)
+ {
+ //LOG("%s io_w: A9BPageSelect9000 <= %02x\n", machine().describe_context(), data >> 8);
+ m_a9_psel_9000 = data >> 8;
+ }
+ break;
+
+ case 0x2c: // A9WControlExtra
+ // b0-b3 A9MKeyCol
+ // b4 A9MBuzzTog
+ // b5 A9MBuzzFromFrc1OrTog
+ // b6 A9MExonDisable
+ // b7 A9MSoundDir
+ // b8 A9MClockEnable1
+ // b9 A9MClockEnable2
+ // b10 A9MClockEnable3
+ // b11 A9MClockEnable4
+ // b12 A9MClockEnable5
+ // b13-b14 A9MClkDiv
+ // b15 A9MSlaveIntEnable
+ LOG("%s io_w: A9WControlExtra <= %04x\n", machine().describe_context(), data);
+ m_a9_control_extra = data;
+
+ // enable keyboard COLs
+ switch (data & 0xf)
+ {
+ case 0x0: m_col_cb(0xff); break;
+ case 0x8: m_col_cb(0x01); break;
+ case 0x9: m_col_cb(0x02); break;
+ case 0xa: m_col_cb(0x04); break;
+ case 0xb: m_col_cb(0x08); break;
+ case 0xc: m_col_cb(0x10); break;
+ case 0xd: m_col_cb(0x20); break;
+ case 0xe: m_col_cb(0x40); break;
+ case 0xf: m_col_cb(0x80); break;
+ default: m_col_cb(0x00); break;
+ }
+
+ if (!BIT(data, 5))
+ {
+ m_buz_cb(BIT(data, 4));
+ }
+ break;
+
+ case 0x2e: // A9WPumpControl
+ LOG("%s io_w: A9WPumpControl <= %04x\n", machine().describe_context(), data);
+ break;
+
+ case 0x80: // A9WRtcLSW
+ //LOG("%s io_w: A9WRtcLSW <= %04x\n", machine().describe_context(), data);
+ m_rtc = (m_rtc & 0xffff0000) | data;
+ break;
+
+ case 0x82: // A9WRtcMSW
+ //LOG("%s io_w: A9WRtcMSW <= %04x\n", machine().describe_context(), data);
+ m_rtc = (m_rtc & 0x0000ffff) | (data << 16);
+ break;
+
+ case 0x84: // A9WNullFrame
+ LOG("%s io_w: A9WNullFrame <= %02x\n", machine().describe_context(), data);
+ transmit_frame(NULL_FRAME);
+ break;
+
+ case 0x8a: // A9BSerialData
+ LOG("%s io_w: A9BSerialData <= %02x\n", machine().describe_context(), data & 0xff);
+ if ((m_a9_serial_control & 0xc0) == 0x80)
+ transmit_frame(DATA_FRAME | (data & 0xff));
+ break;
+
+ case 0x8c: // A9BSerialControl - Serial channel write control register
+ // WriteSingle 10000000b; ReadSingle 11000000b
+ // WriteMulti 10010000b; ReadMulti 11010000b
+ // Reset 00000000b; Select 01000000b
+ // Asic2SlaveId 001h; Asic5PackId 002h
+ // Asic5NormalId 003h; Asic6Id 004h
+ // Asic8Id 005h; Asic4Id 006h
+ LOG("%s io_w: A2SerialControl <= %02x\n", machine().describe_context(), data & 0xff);
+ m_a9_serial_control = data & 0xff;
+ transmit_frame(CONTROL_FRAME | m_a9_serial_control);
+
+ if ((m_a9_serial_control & 0x40) == 0x40)
+ m_a9_serial_data = receive_frame();
+ break;
+
+ case 0x8e: // A9BChannelSelect - Serial channel select register
+ // b0 Pack1Enable - 1 to select pack 1
+ // b1 Pack2Enable - 1 to select pack 2
+ // b2 Pack3Enable - 1 to select pack 3
+ // b3 Pack4Enable - 1 to select pack 4
+ // b4 Pack5Enable - 1 to select pack 5
+ // b5-b6 SerialClockRate - 0 Medium, 1 Special, 2 Slow, 3 Fast
+ // b7 MultiplexEnable - 1 to loop slave channel to pack channel
+ LOG("%s io_w: A9BChannelSelect <= %02x Channels %c %c %c %c %c\n", machine().describe_context(), data & 0xff,
+ BIT(data, 0) ? '0' : ' ',
+ BIT(data, 1) ? '1' : ' ',
+ BIT(data, 2) ? '2' : ' ',
+ BIT(data, 3) ? '3' : ' ',
+ BIT(data, 4) ? '4' : ' ');
+ m_a9_channel_select = data & 0xff;
+ break;
+
+ default:
+ logerror("%s io_w: Unhandled register %02x <= %04x\n", machine().describe_context(), offset, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// SIBO Serial Protocol Controller
+//-------------------------------------------------
+
+bool psion_asic9_device::channel_active(int channel)
+{
+ switch (channel)
+ {
+ case 0: case 1: case 2: case 3: case 4:
+ return BIT(m_a9_channel_select, channel);
+ }
+ return false;
+}
+
+void psion_asic9_device::transmit_frame(uint16_t data)
+{
+ m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2));
+ m_v30->set_input_line(NEC_INPUT_LINE_POLL, CLEAR_LINE);
+
+ for (int ch = 0; ch < 8; ch++)
+ {
+ if (channel_active(ch))
+ {
+ LOG("%s Channel %d Transmit %s frame %02x\n", machine().describe_context(), ch, (data & DATA_FRAME) ? "Data" : (data & CONTROL_FRAME) ? "Control" : "Null", data & 0xff);
+ m_data_w[ch](data);
+ }
+ }
+}
+
+uint8_t psion_asic9_device::receive_frame()
+{
+ uint8_t data = 0x00;
+
+ m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2));
+ m_v30->set_input_line(NEC_INPUT_LINE_POLL, CLEAR_LINE);
+
+ for (int ch = 0; ch < 8; ch++)
+ {
+ if (channel_active(ch))
+ {
+ data |= m_data_r[ch]();
+ LOG("%s Channel %d Receive Data frame %02x\n", machine().describe_context(), ch, data);
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// LCD Controller
+//-------------------------------------------------
+
+uint32_t psion_asic9_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (m_a9_control & 0x0400) // LCD enable bit
+ {
+ pen_t const *const pens = screen.palette().pens();
+
+ int const width = (BIT(m_a9_lcd_size, 11, 5) + 1) * 32;
+ uint16_t const size = (BIT(m_a9_lcd_size, 0, 11) + 1) * 16;
+
+ for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++)
+ {
+ for (int x = screen.visible_area().min_x; x <= (screen.visible_area().max_x / 8); x++)
+ {
+ uint8_t const black = m_ram_space->read_byte(0x0400 + y * (width / 8) + x);
+ uint8_t const grey = m_ram_space->read_byte(0x0400 + size + y * (width / 8) + x);
+ uint16_t *p = &bitmap.pix(y, x << 3);
+ for (int i = 0; i < 8; i++)
+ *p++ = BIT(black, i) ? pens[1] : (BIT(grey, i) ? pens[2] : pens[0]);
+ }
+ }
+ }
+ else
+ {
+ bitmap.fill(0, cliprect);
+ }
+ return 0;
+}
diff --git a/src/devices/machine/psion_asic9.h b/src/devices/machine/psion_asic9.h
new file mode 100644
index 00000000000..bdbe4ed618e
--- /dev/null
+++ b/src/devices/machine/psion_asic9.h
@@ -0,0 +1,179 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion ASIC9
+
+******************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_ASIC9_H
+#define MAME_MACHINE_PSION_ASIC9_H
+
+#pragma once
+
+#include "machine/ram.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> psion_asic9_device
+
+class psion_asic9_device : public device_t,
+ public device_memory_interface,
+ public device_video_interface
+{
+public:
+ psion_asic9_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T, typename U> void set_ram_rom(T &&ram_tag, U &&rom_tag) { m_ram.set_tag(std::forward<T>(ram_tag)); m_rom.set_tag(std::forward<U>(rom_tag)); }
+
+ // callbacks
+ auto buz_cb() { return m_buz_cb.bind(); }
+ auto col_cb() { return m_col_cb.bind(); }
+ auto port_ab_r() { return m_port_ab_r.bind(); }
+ auto port_ab_w() { return m_port_ab_w.bind(); }
+ auto pcm_in() { return m_pcm_in.bind(); }
+ auto pcm_out() { return m_pcm_out.bind(); }
+
+ template <unsigned N> auto data_r() { static_assert(N < 8); return m_data_r[N].bind(); }
+ template <unsigned N> auto data_w() { static_assert(N < 8); return m_data_w[N].bind(); }
+
+ address_space &io_space() const { return m_v30->space(AS_IO); }
+
+ uint16_t io_r(offs_t offset, uint16_t mem_mask);
+ void io_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ uint16_t mem_r(offs_t offset, uint16_t mem_mask);
+ void mem_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+ uint8_t col_r();
+
+ IRQ_CALLBACK_MEMBER(inta_cb);
+
+ void sds_int_w(int state);
+ void eint0_w(int state);
+ void eint1_w(int state);
+ void eint2_w(int state);
+ void medchng_w(int state);
+
+ uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ psion_asic9_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual space_config_vector memory_space_config() const override;
+
+private:
+ required_device<cpu_device> m_v30;
+ required_device<ram_device> m_ram;
+ required_memory_region m_rom;
+
+ void mem_map(address_map &map);
+ void io_map(address_map &map);
+
+ static constexpr int AS_A9_RAM = AS_OPCODES + 1;
+ static constexpr int AS_A9_ROM = AS_OPCODES + 2;
+
+ const address_space_config m_ram_config;
+ const address_space_config m_rom_config;
+
+ address_space *m_ram_space;
+ address_space *m_rom_space;
+
+ emu_timer *m_tick_timer;
+ emu_timer *m_frc1_timer;
+ emu_timer *m_frc2_timer;
+ emu_timer *m_watchdog_timer;
+ emu_timer *m_rtc_timer;
+ emu_timer *m_snd_timer;
+
+ TIMER_CALLBACK_MEMBER(tick);
+ TIMER_CALLBACK_MEMBER(frc1);
+ TIMER_CALLBACK_MEMBER(frc2);
+ TIMER_CALLBACK_MEMBER(watchdog);
+ TIMER_CALLBACK_MEMBER(rtc);
+ TIMER_CALLBACK_MEMBER(snd);
+
+ void update_interrupts();
+ bool is_protected(offs_t offset);
+ offs_t translate_address(offs_t offset);
+
+ uint8_t m_ram_type;
+ uint32_t ram_device_size(uint8_t device_type);
+ void configure_ram(uint8_t device_type = 0);
+ void configure_rom();
+
+ uint8_t m_post;
+ uint16_t m_a9_control;
+ uint16_t m_a9_status;
+ uint16_t m_a9_lcd_size;
+ uint8_t m_a9_interrupt_status;
+ uint8_t m_a9_interrupt_mask;
+ uint16_t m_frc1_count;
+ uint16_t m_frc1_reload;
+ uint16_t m_frc2_count;
+ uint16_t m_frc2_reload;
+ int m_buz_toggle;
+ uint8_t m_watchdog_count;
+ bool m_a9_protection_mode;
+ uint32_t m_a9_protection_upper;
+ uint32_t m_a9_protection_lower;
+ uint16_t m_a9_port_ab_ddr;
+ uint8_t m_a9_port_c_ddr;
+ uint8_t m_a9_port_d_ddr;
+ uint8_t m_a9_psel_6000;
+ uint8_t m_a9_psel_7000;
+ uint8_t m_a9_psel_8000;
+ uint8_t m_a9_psel_9000;
+ uint16_t m_a9_control_extra;
+ uint32_t m_rtc;
+ util::fifo<uint8_t, 16> m_snd_fifo;
+
+ uint8_t m_a9_serial_data;
+ uint8_t m_a9_serial_control;
+ uint8_t m_a9_channel_select;
+
+ devcb_write_line m_buz_cb;
+ devcb_write8 m_col_cb;
+ devcb_read16 m_port_ab_r;
+ devcb_write16 m_port_ab_w;
+ devcb_read8 m_pcm_in;
+ devcb_write8 m_pcm_out;
+
+ devcb_read8::array<8> m_data_r;
+ devcb_write16::array<8> m_data_w;
+
+ emu_timer *m_busy_timer;
+
+ TIMER_CALLBACK_MEMBER(busy);
+
+ bool channel_active(int channel);
+ void transmit_frame(uint16_t data);
+ uint8_t receive_frame();
+
+ static constexpr uint16_t NULL_FRAME = 0x000;
+ static constexpr uint16_t CONTROL_FRAME = 0x100;
+ static constexpr uint16_t DATA_FRAME = 0x200;
+};
+
+
+// ======================> psion_asic9mx_device
+
+class psion_asic9mx_device : public psion_asic9_device
+{
+public:
+ // construction/destruction
+ psion_asic9mx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_ASIC9, psion_asic9_device)
+DECLARE_DEVICE_TYPE(PSION_ASIC9MX, psion_asic9mx_device)
+
+#endif // MAME_MACHINE_PSION_ASIC9_H
diff --git a/src/devices/machine/psion_condor.cpp b/src/devices/machine/psion_condor.cpp
new file mode 100644
index 00000000000..f9cc6d7d494
--- /dev/null
+++ b/src/devices/machine/psion_condor.cpp
@@ -0,0 +1,278 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion Condor
+
+ The Condor chip was introduced with the Series 3c and Siena for serial
+ communications. The new chip enabled serial port speeds upto 57.6K baud on
+ the Series 3c (19.2K baud on the Siena)
+
+ This is a 64 pin package and pinout is unknown, so everything needs verifying
+ if a datasheet/specification is ever found.
+
+ TODO:
+ - everything, require datasheet/specification and 3c/Siena schematic for info.
+
+******************************************************************************/
+
+#include "emu.h"
+#include "psion_condor.h"
+
+#define VERBOSE 0
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(PSION_CONDOR, psion_condor_device, "psion_condor", "Psion Condor")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+psion_condor_device::psion_condor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PSION_CONDOR, tag, owner, clock)
+ , device_serial_interface(mconfig, *this)
+ , m_txd_handler(*this)
+ , m_rxc_handler(*this)
+ , m_rts_handler(*this)
+ , m_dtr_handler(*this)
+ , m_int_handler(*this)
+ , m_cts(1)
+ , m_dsr(1)
+ , m_ri(1)
+ , m_dcd(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_condor_device::device_start()
+{
+ save_item(NAME(m_cts));
+ save_item(NAME(m_dsr));
+ save_item(NAME(m_ri));
+ save_item(NAME(m_dcd));
+ save_item(NAME(m_uart_divisor));
+ save_item(NAME(m_uart_line_control));
+ save_item(NAME(m_int_mask));
+ save_item(NAME(m_control1));
+ save_item(NAME(m_parallel_ddr));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_condor_device::device_reset()
+{
+ m_int_mask = 0x00;
+ m_control1 = 0x00;
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+uint8_t psion_condor_device::read(offs_t offset)
+{
+ uint8_t data = 0x00;
+
+ switch (offset & 0x0f)
+ {
+ case 0x00: // UARTReceiveBufferRegister
+ //receive_register_extract();
+ //data = get_received_char();
+ LOG("%s read: UARTReceiveBufferRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x01: // UARTInterruptEnableRegister
+ LOG("%s read: UARTInterruptEnableRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x02: // UARTInterruptIdentificRegister
+ // b0 ERBF
+ // b1 ETBEI - Enable Transmit Interrupts
+ // b2 ELSI
+ // b3 EDSSI - Enable Modem Status Interrupts
+ LOG("%s read: UARTInterruptIdentificRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x05: // UARTLineStatusRegister
+ // b5 THRE
+ // b6 TEMT - Transmitter Empty
+ data |= is_transmit_register_empty() ? 0x40 : 0x00;
+ LOG("%s read: UARTLineStatusRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x06: // UARTModemStatusRegister
+ // b4 CTSLine
+ // b5 DSRLine
+ // b6 RILine
+ // b7 DCDLine
+ data |= m_cts << 4;
+ data |= m_dsr << 5;
+ data |= m_ri << 6;
+ data |= m_dcd << 7;
+ LOG("%s read: UARTModemStatusRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x08: // FifoDataRegister
+ data = m_rx_fifo.dequeue();
+ LOG("%s read: FifoDataRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x0a: // ParallelDataRegister
+ // b7 HighPowerEnable
+ LOG("%s read: ParallelDataRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x0c: // InterruptStatusRegister
+ // b0 UINT
+ // b1 RHFINT - Receive Half Full
+ // b2 RTOINT
+ // b3 THEINT - Transmit Half Empty
+ // b4 MP1INT
+ // b5 MP2INT
+ LOG("%s read: InterruptStatusRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x0e: // StatusRegister
+ // b0 RXFE - Receive FIFO Empty
+ // b1 TXFE - Transmit FIFO Empty
+ // b2 RFERR
+ // b3 RFE - Receive Framing Error
+ // b4 RPE - Receive Parity Error
+ // b5 FOVR
+ // b6 PLOCK - Phase Locked Loop Locked
+ data |= m_rx_fifo.empty() ? 0x01 : 0x00;
+ data |= m_tx_fifo.empty() ? 0x02 : 0x00;
+ data |= is_receive_framing_error() ? 0x08 : 0x00;
+ data |= is_receive_parity_error() ? 0x10 : 0x00;
+ //LOG("%s read: StatusRegister => %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s read: unknown register %02x => %02x\n", machine().describe_context(), offset, data);
+ break;
+ }
+
+ return data;
+}
+
+
+void psion_condor_device::write(offs_t offset, uint8_t data)
+{
+ switch (offset & 0x0f)
+ {
+ case 0x00: // UARTTransmitterHoldingRegister / UARTDivisorLatchLSB
+ if (BIT(m_uart_line_control, 7))
+ {
+ LOG("%s write: UARTDivisorLatchLSB <= %02x\n", machine().describe_context(), data);
+ m_uart_divisor = (m_uart_divisor & 0xff00) | data;
+ }
+ else
+ {
+ LOG("%s write: UARTTransmitterHoldingRegister <= %02x\n", machine().describe_context(), data);
+ //transmit_byte(data);
+ }
+ break;
+
+ case 0x01: // UARTInterruptEnableRegister / UARTDivisorLatchMSB
+ if (BIT(m_uart_line_control, 7))
+ {
+ LOG("%s write: UARTDivisorLatchMSB <= %02x\n", machine().describe_context(), data);
+ m_uart_divisor = (m_uart_divisor & 0x00ff) | (data << 8);
+ }
+ else
+ {
+ // b0 ERBF
+ // b1 ETBEI - Enable Transmit Interrupts
+ // b2 ELSI
+ // b3 EDSSI - Enable Modem Status Interrupts
+ LOG("%s write: UARTInterruptEnableRegister <= %02x\n", machine().describe_context(), data);
+ }
+ break;
+
+ case 0x03: // UARTLineControlRegister
+ // b2 - Select Two Stop Bits
+ // b7 DLAB - Divisor Latch
+ LOG("%s write: UARTLineControlRegister <= %02x\n", machine().describe_context(), data);
+ m_uart_line_control = data;
+ set_data_frame(1, 8, PARITY_NONE, BIT(data, 2) ? STOP_BITS_2 : STOP_BITS_1);
+ break;
+
+ case 0x04: // UARTModemControlRegister
+ // b0 DTRLine1
+ // b1 RTSLine1
+ // b2 DTRLine2
+ // b3 RTSLine2
+ // b4 LOOPBACK
+ m_dtr_handler(BIT(data, 0));
+ m_rts_handler(BIT(data, 1));
+ LOG("%s write: UARTModemControlRegister <= %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x07: // UARTScratchRegister
+ LOG("%s write: UARTScratchRegister <= %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x08: // FifoDataRegister
+ LOG("%s write: FifoDataRegister <= %02x\n", machine().describe_context(), data);
+ m_tx_fifo.enqueue(data);
+ break;
+
+ case 0x09: // ControlRegister1
+ // b0 TFCLR - Transmit FIFO Clear
+ // b1 RFCLR - Receive FIFO Clear
+ // b2
+ // b3 IRSD
+ // b4 ESEL1
+ // b5 ESEL2
+ // b6 CLKEN
+ // b7 PSRST
+ LOG("%s write: ControlRegister1 <= %02x\n", machine().describe_context(), data);
+ m_control1 = data;
+ if (BIT(data, 0)) m_tx_fifo.clear();
+ if (BIT(data, 1)) m_rx_fifo.clear();
+ break;
+
+ case 0x0a: // ParallelDataRegister
+ // b7 HighPowerEnable
+ LOG("%s write: ParallelDataRegister <= %02x\n", machine().describe_context(), data);
+ break;
+
+ case 0x0b: // ParallelDataDirectionRegister
+ LOG("%s write: ParallelDataDirectionRegister <= %02x\n", machine().describe_context(), data);
+ m_parallel_ddr = data;
+ break;
+
+ case 0x0d: // InterruptMaskAndMiscRegister
+ // b0 EUINT
+ // b1 ERHFINT
+ // b2 ERTOINT
+ // b3 ETHEINT
+ // b4 PLLBP
+ // b5 EMPINT
+ // b6 RS232PORT1
+ // b7 RS232PORT2
+ LOG("%s write: InterruptMaskAndMiscRegister <= %02x\n", machine().describe_context(), data);
+ m_int_mask = data;
+ break;
+
+ case 0x0f: // ControlRegister2
+ // b0 THECLR - Clear Transmit Interrupt
+ // b1 RHFCLR - Clear Receive Interrupt
+ LOG("%s write: ControlRegister2 <= %02x\n", machine().describe_context(), data);
+ break;
+
+ default:
+ LOG("%s write: unknown register %02x <= %02x\n", machine().describe_context(), offset, data);
+ break;
+ }
+}
diff --git a/src/devices/machine/psion_condor.h b/src/devices/machine/psion_condor.h
new file mode 100644
index 00000000000..f62ae91fa91
--- /dev/null
+++ b/src/devices/machine/psion_condor.h
@@ -0,0 +1,75 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/******************************************************************************
+
+ Psion Condor
+
+******************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_CONDOR_H
+#define MAME_MACHINE_PSION_CONDOR_H
+
+#pragma once
+
+#include "diserial.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> psion_condor_device
+
+class psion_condor_device : public device_t, public device_serial_interface
+{
+public:
+ psion_condor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ static constexpr feature_type unemulated_features() { return feature::COMMS; }
+
+ auto txd_handler() { return m_txd_handler.bind(); }
+ auto rxc_handler() { return m_rxc_handler.bind(); }
+ auto rts_handler() { return m_rts_handler.bind(); }
+ auto dtr_handler() { return m_dtr_handler.bind(); }
+ auto int_handler() { return m_int_handler.bind(); }
+
+ void write_rxd(int state) { }
+ void write_cts(int state) { m_cts = state; }
+ void write_dsr(int state) { m_dsr = state; }
+ void write_dcd(int state) { m_dcd = state; }
+
+ uint8_t read(offs_t offset);
+ void write(offs_t offset, uint8_t data);
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ devcb_write_line m_txd_handler;
+ devcb_write_line m_rxc_handler;
+ devcb_write_line m_rts_handler;
+ devcb_write_line m_dtr_handler;
+ devcb_write_line m_int_handler;
+
+ util::fifo<uint8_t, 8> m_rx_fifo;
+ util::fifo<uint8_t, 8> m_tx_fifo;
+
+ int m_cts;
+ int m_dsr;
+ int m_ri;
+ int m_dcd;
+
+ uint16_t m_uart_divisor;
+ uint8_t m_uart_line_control;
+ uint8_t m_int_mask;
+ uint8_t m_control1;
+ uint8_t m_parallel_ddr;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_CONDOR, psion_condor_device)
+
+#endif // MAME_MACHINE_PSION_CONDOR_H
diff --git a/src/devices/machine/psion_ssd.cpp b/src/devices/machine/psion_ssd.cpp
new file mode 100644
index 00000000000..74b223959cc
--- /dev/null
+++ b/src/devices/machine/psion_ssd.cpp
@@ -0,0 +1,292 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/****************************************************************************
+
+ Psion Solid State Disk emulation
+
+
+ Memory Type No. devices Memory Size
+ D7 D6 D5 D4 D3 D2 D1 D0
+ 0 0 0 RAM 0 0 1 device 0 0 0 No memory
+ 0 0 1 Type 1 Flash 0 1 2 devices 0 0 1 32K
+ 0 1 0 Type 2 Flash 1 0 3 devices 0 1 0 64K
+ 0 1 1 Type 3 Flash 1 1 4 devices 0 1 1 128K
+ 1 0 0 Type 4 Flash 1 0 0 256K
+ 1 0 1 Type 5 Flash 1 0 1 512K
+ 1 1 0 Read only SSD (ROM) 1 1 0 1M
+ 1 1 1 Hardware Write protected SSD 1 1 1 2M
+
+ Info Byte (* = confirmed)
+ Psion Solid State Disk 64K Flash 001 01 001 0x29
+ Psion Solid State Disk 128K Flash * 001 00 011 0x23
+ - MC200 System Disk * 111 00 011 0xE3
+ - MC400 System Disk * 111 00 011 0xE3
+ Psion Solid State Disk 256K Flash * 001 01 011 0x2B
+ - MC Word System Disk * 111 01 011 0xEB
+ Psion Solid State Disk 512K Flash 001 01 100 0x2C
+ Psion Solid State Disk 1MB Flash * 001 11 100 0x3C
+ Psion Solid State Disk 2MB Flash * 001 11 101 0x3D
+ Psion Solid State Disk 4MB Flash 001 11 110 0x3E
+ Psion Solid State Disk 8MB Flash * 001 11 111 0x3F
+
+ Psion Solid State Disk 64K RAM 000 01 001 0x09
+ Psion Solid State Disk 128K RAM 000 11 001 0x19
+ Psion Solid State Disk 512K RAM 000 11 011 0x1B
+ Psion Solid State Disk 1MB RAM 000 11 100 0x1C
+ Psion Solid State Disk 2MB RAM 000 11 101 0x1D
+
+****************************************************************************/
+
+#include "emu.h"
+#include "psion_ssd.h"
+
+#include "softlist_dev.h"
+
+#include <tuple>
+
+
+DEFINE_DEVICE_TYPE(PSION_SSD, psion_ssd_device, "psion_ssd", "Psion Solid State Disk")
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void psion_ssd_device::device_add_mconfig(machine_config &config)
+{
+ PSION_ASIC5(config, m_asic5, DERIVED_CLOCK(1, 1)).set_mode(psion_asic5_device::PACK_MODE);
+ m_asic5->readpa_handler().set([this]() { return m_ssd_data[latched_addr()]; });
+ m_asic5->writepa_handler().set([this](uint8_t data) { m_ssd_data[latched_addr()] = data; });
+ m_asic5->writepb_handler().set([this](uint8_t data) { m_port_latch = (m_port_latch & 0xffff00) | (data << 0); });
+ m_asic5->writepd_handler().set([this](uint8_t data) { m_port_latch = (m_port_latch & 0xff00ff) | (data << 8); });
+ m_asic5->writepc_handler().set([this](uint8_t data) { m_port_latch = (m_port_latch & 0x00ffff) | (data << 16); });
+}
+
+
+//-------------------------------------------------
+// psion_ssd_device - constructor
+//-------------------------------------------------
+
+psion_ssd_device::psion_ssd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PSION_SSD, tag, owner, clock)
+ , device_memcard_image_interface(mconfig, *this)
+ , m_region(*this, DEVICE_SELF)
+ , m_asic5(*this, "asic5")
+ , m_door_cb(*this)
+ , m_door_timer(nullptr)
+ , m_info_byte(0)
+ , m_port_latch(0)
+ , m_mem_width(0)
+{
+}
+
+
+//-------------------------------------------------
+// psion_ssd_device - destructor
+//-------------------------------------------------
+
+psion_ssd_device::~psion_ssd_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void psion_ssd_device::device_start()
+{
+ m_ssd_data = make_unique_clear<uint8_t[]>(0x800000);
+
+ // insert default System disk
+ if (m_region.found())
+ {
+ uint32_t size = m_region->bytes();
+ memcpy(&m_ssd_data[0], m_region->base(), size);
+ set_info_byte(size, SSD_FLASH1);
+ }
+
+ m_door_timer = timer_alloc(FUNC(psion_ssd_device::close_door), this);
+ m_door_timer->reset();
+
+ save_pointer(NAME(m_ssd_data), 0x800000);
+ save_item(NAME(m_info_byte));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void psion_ssd_device::device_reset()
+{
+ m_port_latch = 0x00;
+
+ // open the door
+ m_door_cb(ASSERT_LINE);
+
+ // setup the timer to close the door
+ m_door_timer->adjust(attotime::from_msec(200));
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void psion_ssd_device::device_config_complete()
+{
+ add_format("ssd", "Psion Solid State Disk image", "bin,rom", "");
+}
+
+
+//-------------------------------------------------
+// get_software_list_loader -
+//-------------------------------------------------
+
+const software_list_loader &psion_ssd_device::get_software_list_loader() const
+{
+ return image_software_list_loader::instance();
+}
+
+
+TIMER_CALLBACK_MEMBER(psion_ssd_device::close_door)
+{
+ // close the door
+ m_door_cb(CLEAR_LINE);
+}
+
+
+std::pair<std::error_condition, std::string> psion_ssd_device::call_load()
+{
+ uint32_t const size = length();
+
+ if (size < 0x10000 || size > 0x800000 || (size & (size - 1)) != 0)
+ return std::make_pair(image_error::INVALIDLENGTH, "Invalid size, must be 64K, 128K, 256K, 512K, 1M, 2M, 4M, 8M");
+
+ std::error_condition err;
+ size_t actual;
+ std::tie(err, m_ssd_data, actual) = read(image_core_file(), size);
+ if (err || (actual != size))
+ return std::make_pair(err ? err : std::errc::io_error, std::string());
+
+ // check for Flash header
+ if ((m_ssd_data[0] | (m_ssd_data[1] << 8)) == 0xf1a5) // Flash
+ set_info_byte(size, SSD_FLASH1);
+ else
+ set_info_byte(size, SSD_RAM);
+
+ if (loaded_through_softlist())
+ battery_load(m_ssd_data.get(), size, nullptr);
+
+ // open the door
+ m_door_cb(ASSERT_LINE);
+
+ // setup the timer to close the door
+ m_door_timer->adjust(attotime::from_msec(200));
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+
+std::pair<std::error_condition, std::string> psion_ssd_device::call_create(int format_type, util::option_resolution *create_args)
+{
+ uint32_t const size = 0x20000;
+
+ // 128k RAM Solid State Disk by default
+ set_info_byte(size, SSD_RAM);
+
+ std::fill_n(m_ssd_data.get(), sizeof(m_ssd_data), 0);
+
+ fwrite(m_ssd_data.get(), size);
+
+ // open the door
+ m_door_cb(ASSERT_LINE);
+
+ // setup the timer to close the door
+ m_door_timer->adjust(attotime::from_msec(200));
+
+ return std::make_pair(std::error_condition(), std::string());
+}
+
+
+void psion_ssd_device::call_unload()
+{
+ uint32_t const size = length();
+
+ if ((m_info_byte & 0xe0) == 0x00) // not write protected
+ {
+ if (!loaded_through_softlist())
+ {
+ // write to original file
+ fseek(0, SEEK_SET);
+ fwrite(m_ssd_data.get(), size);
+ }
+ else
+ {
+ // write to nvram
+ battery_save(m_ssd_data.get(), size);
+ }
+ }
+
+ set_info_byte(0);
+
+ std::fill_n(m_ssd_data.get(), sizeof(m_ssd_data), 0);
+
+ // open the door
+ m_door_cb(ASSERT_LINE);
+
+ // setup the timer to close the door
+ m_door_timer->adjust(attotime::from_msec(200));
+}
+
+
+uint32_t psion_ssd_device::latched_addr()
+{
+ return (m_port_latch & make_bitmask<uint32_t>(m_mem_width)) | (BIT(m_port_latch, 22, 2) << m_mem_width);
+}
+
+
+void psion_ssd_device::set_info_byte(uint32_t size, uint8_t type)
+{
+ m_info_byte = 0x00;
+
+ // Type 1 Flash or RAM
+ if (type != SSD_RAM)
+ m_info_byte |= 0xe0; // write protected
+
+ // No. devices and size
+ switch (size)
+ {
+ case 0x010000: m_info_byte |= 0x09; m_mem_width = 15; break; // 64K (2 x 32K)
+ case 0x020000: m_info_byte |= 0x03; m_mem_width = 17; break; // 128K (1 x 128K)
+ case 0x040000: m_info_byte |= 0x0b; m_mem_width = 17; break; // 256K (2 x 128K)
+ case 0x080000: m_info_byte |= 0x0c; m_mem_width = 18; break; // 512K (2 x 256K)
+ case 0x100000: m_info_byte |= 0x1c; m_mem_width = 18; break; // 1M (4 x 256K)
+ case 0x200000: m_info_byte |= 0x1d; m_mem_width = 19; break; // 2M (4 x 512K)
+ case 0x400000: m_info_byte |= 0x1e; m_mem_width = 20; break; // 4M (4 x 1M)
+ case 0x800000: m_info_byte |= 0x1f; m_mem_width = 21; break; // 8M (4 x 2M)
+ }
+
+ // set pull-ups on ASIC5
+ m_asic5->set_info_byte(m_info_byte);
+}
+
+
+uint8_t psion_ssd_device::data_r()
+{
+ if (m_info_byte & 7)
+ {
+ return m_asic5->data_r();
+ }
+ return 0x00;
+}
+
+void psion_ssd_device::data_w(uint16_t data)
+{
+ if (m_info_byte & 7)
+ {
+ m_asic5->data_w(data);
+ }
+}
diff --git a/src/devices/machine/psion_ssd.h b/src/devices/machine/psion_ssd.h
new file mode 100644
index 00000000000..7dd9cb777aa
--- /dev/null
+++ b/src/devices/machine/psion_ssd.h
@@ -0,0 +1,82 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/****************************************************************************
+
+ Psion Solid State Disk emulation
+
+****************************************************************************/
+
+#ifndef MAME_MACHINE_PSION_SSD_H
+#define MAME_MACHINE_PSION_SSD_H
+
+#include "machine/psion_asic5.h"
+#include "imagedev/memcard.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> psion_ssd_device
+
+class psion_ssd_device : public device_t, public device_memcard_image_interface
+{
+public:
+ // construction/destruction
+ psion_ssd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ virtual ~psion_ssd_device();
+
+ // callbacks
+ auto door_cb() { return m_door_cb.bind(); }
+
+ uint8_t data_r();
+ void data_w(uint16_t data);
+
+protected:
+ // device_t implementation
+ virtual void device_config_complete() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ // device_image_interface implementation
+ virtual std::pair<std::error_condition, std::string> call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *create_args) override;
+ virtual void call_unload() override;
+
+ virtual bool is_reset_on_load() const noexcept override { return false; }
+ virtual const char *image_interface() const noexcept override { return "psion_ssd"; }
+ virtual const char *file_extensions() const noexcept override { return "rom,bin"; }
+ virtual const char *image_type_name() const noexcept override { return "ssd"; }
+ virtual const char *image_brief_type_name() const noexcept override { return "ssd"; }
+
+ // device_image_interface implementation
+ virtual const software_list_loader &get_software_list_loader() const override;
+
+private:
+ optional_memory_region m_region;
+ required_device<psion_asic5_device> m_asic5;
+
+ TIMER_CALLBACK_MEMBER(close_door);
+
+ devcb_write_line m_door_cb;
+ emu_timer *m_door_timer;
+
+ std::unique_ptr<uint8_t[]> m_ssd_data;
+
+ void set_info_byte(uint32_t size, uint8_t type = 0);
+ uint32_t latched_addr();
+
+ uint8_t m_info_byte;
+ uint32_t m_port_latch;
+ int m_mem_width;
+
+ static constexpr uint8_t SSD_RAM = 0;
+ static constexpr uint8_t SSD_FLASH1 = 1;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(PSION_SSD, psion_ssd_device)
+
+#endif // MAME_MACHINE_PSION_SSD_H
diff --git a/src/devices/machine/pxa255.cpp b/src/devices/machine/pxa255.cpp
index 6bd82ec987c..1f1dff2e452 100644
--- a/src/devices/machine/pxa255.cpp
+++ b/src/devices/machine/pxa255.cpp
@@ -15,38 +15,260 @@
#include "screen.h"
#include "speaker.h"
-#define LOG_UNKNOWN (1 << 1)
-#define LOG_I2S (1 << 2)
-#define LOG_DMA (1 << 3)
-#define LOG_OSTIMER (1 << 4)
-#define LOG_INTC (1 << 5)
-#define LOG_GPIO (1 << 6)
-#define LOG_LCD_DMA (1 << 7)
-#define LOG_LCD (1 << 8)
-#define LOG_POWER (1 << 9)
-#define LOG_RTC (1 << 10)
-#define LOG_CLOCKS (1 << 11)
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_I2S (1U << 2)
+#define LOG_DMA (1U << 3)
+#define LOG_OSTIMER (1U << 4)
+#define LOG_INTC (1U << 5)
+#define LOG_GPIO (1U << 6)
+#define LOG_LCD_DMA (1U << 7)
+#define LOG_LCD (1U << 8)
+#define LOG_POWER (1U << 9)
+#define LOG_RTC (1U << 10)
+#define LOG_CLOCKS (1U << 11)
#define LOG_ALL (LOG_UNKNOWN | LOG_I2S | LOG_DMA | LOG_OSTIMER | LOG_INTC | LOG_GPIO | LOG_LCD_DMA | LOG_LCD | LOG_POWER | LOG_RTC | LOG_CLOCKS)
-#define VERBOSE (LOG_ALL)
+#define VERBOSE (LOG_GPIO)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(PXA255_PERIPHERALS, pxa255_periphs_device, "pxa255_periphs", "Intel XScale PXA255 Peripherals")
-pxa255_periphs_device::pxa255_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+pxa255_periphs_device::pxa255_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, PXA255_PERIPHERALS, tag, owner, clock)
- , m_gpio0_w(*this)
- , m_gpio1_w(*this)
- , m_gpio2_w(*this)
- , m_gpio0_r(*this)
- , m_gpio1_r(*this)
- , m_gpio2_r(*this)
+ , m_gpio_w(*this)
, m_maincpu(*this, finder_base::DUMMY_TAG)
, m_dmadac(*this, "dac%u", 1U)
, m_palette(*this, "palette")
{
}
+void pxa255_periphs_device::map(address_map &map)
+{
+ map(0x00000000, 0x0000003f).rw(FUNC(pxa255_periphs_device::dma_dcsr_r), FUNC(pxa255_periphs_device::dma_dcsr_w));
+ map(0x000000f0, 0x000000f3).rw(FUNC(pxa255_periphs_device::dma_dint_r), FUNC(pxa255_periphs_device::dma_dint_w));
+ map(0x00000100, 0x0000019f).rw(FUNC(pxa255_periphs_device::dma_drcmr_r), FUNC(pxa255_periphs_device::dma_drcmr_w));
+ map(0x00000200, 0x00000203).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<0>), FUNC(pxa255_periphs_device::dma_ddadr_w<0>));
+ map(0x00000204, 0x00000207).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<0>), FUNC(pxa255_periphs_device::dma_dsadr_w<0>));
+ map(0x00000208, 0x0000020b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<0>), FUNC(pxa255_periphs_device::dma_dtadr_w<0>));
+ map(0x0000020c, 0x0000020f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<0>), FUNC(pxa255_periphs_device::dma_dcmd_w<0>));
+ map(0x00000210, 0x00000213).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<1>), FUNC(pxa255_periphs_device::dma_ddadr_w<1>));
+ map(0x00000214, 0x00000217).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<1>), FUNC(pxa255_periphs_device::dma_dsadr_w<1>));
+ map(0x00000218, 0x0000021b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<1>), FUNC(pxa255_periphs_device::dma_dtadr_w<1>));
+ map(0x0000021c, 0x0000021f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<1>), FUNC(pxa255_periphs_device::dma_dcmd_w<1>));
+ map(0x00000220, 0x00000223).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<2>), FUNC(pxa255_periphs_device::dma_ddadr_w<2>));
+ map(0x00000224, 0x00000227).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<2>), FUNC(pxa255_periphs_device::dma_dsadr_w<2>));
+ map(0x00000228, 0x0000022b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<2>), FUNC(pxa255_periphs_device::dma_dtadr_w<2>));
+ map(0x0000022c, 0x0000022f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<2>), FUNC(pxa255_periphs_device::dma_dcmd_w<2>));
+ map(0x00000230, 0x00000233).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<3>), FUNC(pxa255_periphs_device::dma_ddadr_w<3>));
+ map(0x00000234, 0x00000237).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<3>), FUNC(pxa255_periphs_device::dma_dsadr_w<3>));
+ map(0x00000238, 0x0000023b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<3>), FUNC(pxa255_periphs_device::dma_dtadr_w<3>));
+ map(0x0000023c, 0x0000023f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<3>), FUNC(pxa255_periphs_device::dma_dcmd_w<3>));
+ map(0x00000240, 0x00000243).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<4>), FUNC(pxa255_periphs_device::dma_ddadr_w<4>));
+ map(0x00000244, 0x00000247).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<4>), FUNC(pxa255_periphs_device::dma_dsadr_w<4>));
+ map(0x00000248, 0x0000024b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<4>), FUNC(pxa255_periphs_device::dma_dtadr_w<4>));
+ map(0x0000024c, 0x0000024f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<4>), FUNC(pxa255_periphs_device::dma_dcmd_w<4>));
+ map(0x00000250, 0x00000253).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<5>), FUNC(pxa255_periphs_device::dma_ddadr_w<5>));
+ map(0x00000254, 0x00000257).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<5>), FUNC(pxa255_periphs_device::dma_dsadr_w<5>));
+ map(0x00000258, 0x0000025b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<5>), FUNC(pxa255_periphs_device::dma_dtadr_w<5>));
+ map(0x0000025c, 0x0000025f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<5>), FUNC(pxa255_periphs_device::dma_dcmd_w<5>));
+ map(0x00000260, 0x00000263).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<6>), FUNC(pxa255_periphs_device::dma_ddadr_w<6>));
+ map(0x00000264, 0x00000267).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<6>), FUNC(pxa255_periphs_device::dma_dsadr_w<6>));
+ map(0x00000268, 0x0000026b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<6>), FUNC(pxa255_periphs_device::dma_dtadr_w<6>));
+ map(0x0000026c, 0x0000026f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<6>), FUNC(pxa255_periphs_device::dma_dcmd_w<6>));
+ map(0x00000270, 0x00000273).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<7>), FUNC(pxa255_periphs_device::dma_ddadr_w<7>));
+ map(0x00000274, 0x00000277).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<7>), FUNC(pxa255_periphs_device::dma_dsadr_w<7>));
+ map(0x00000278, 0x0000027b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<7>), FUNC(pxa255_periphs_device::dma_dtadr_w<7>));
+ map(0x0000027c, 0x0000027f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<7>), FUNC(pxa255_periphs_device::dma_dcmd_w<7>));
+ map(0x00000280, 0x00000283).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<8>), FUNC(pxa255_periphs_device::dma_ddadr_w<8>));
+ map(0x00000284, 0x00000287).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<8>), FUNC(pxa255_periphs_device::dma_dsadr_w<8>));
+ map(0x00000288, 0x0000028b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<8>), FUNC(pxa255_periphs_device::dma_dtadr_w<8>));
+ map(0x0000028c, 0x0000028f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<8>), FUNC(pxa255_periphs_device::dma_dcmd_w<8>));
+ map(0x00000290, 0x00000293).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<9>), FUNC(pxa255_periphs_device::dma_ddadr_w<9>));
+ map(0x00000294, 0x00000297).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<9>), FUNC(pxa255_periphs_device::dma_dsadr_w<9>));
+ map(0x00000298, 0x0000029b).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<9>), FUNC(pxa255_periphs_device::dma_dtadr_w<9>));
+ map(0x0000029c, 0x0000029f).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<9>), FUNC(pxa255_periphs_device::dma_dcmd_w<9>));
+ map(0x000002a0, 0x000002a3).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<10>), FUNC(pxa255_periphs_device::dma_ddadr_w<10>));
+ map(0x000002a4, 0x000002a7).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<10>), FUNC(pxa255_periphs_device::dma_dsadr_w<10>));
+ map(0x000002a8, 0x000002ab).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<10>), FUNC(pxa255_periphs_device::dma_dtadr_w<10>));
+ map(0x000002ac, 0x000002af).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<10>), FUNC(pxa255_periphs_device::dma_dcmd_w<10>));
+ map(0x000002b0, 0x000002b3).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<11>), FUNC(pxa255_periphs_device::dma_ddadr_w<11>));
+ map(0x000002b4, 0x000002b7).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<11>), FUNC(pxa255_periphs_device::dma_dsadr_w<11>));
+ map(0x000002b8, 0x000002bb).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<11>), FUNC(pxa255_periphs_device::dma_dtadr_w<11>));
+ map(0x000002bc, 0x000002bf).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<11>), FUNC(pxa255_periphs_device::dma_dcmd_w<11>));
+ map(0x000002c0, 0x000002c3).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<12>), FUNC(pxa255_periphs_device::dma_ddadr_w<12>));
+ map(0x000002c4, 0x000002c7).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<12>), FUNC(pxa255_periphs_device::dma_dsadr_w<12>));
+ map(0x000002c8, 0x000002cb).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<12>), FUNC(pxa255_periphs_device::dma_dtadr_w<12>));
+ map(0x000002cc, 0x000002cf).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<12>), FUNC(pxa255_periphs_device::dma_dcmd_w<12>));
+ map(0x000002d0, 0x000002d3).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<13>), FUNC(pxa255_periphs_device::dma_ddadr_w<13>));
+ map(0x000002d4, 0x000002d7).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<13>), FUNC(pxa255_periphs_device::dma_dsadr_w<13>));
+ map(0x000002d8, 0x000002db).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<13>), FUNC(pxa255_periphs_device::dma_dtadr_w<13>));
+ map(0x000002dc, 0x000002df).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<13>), FUNC(pxa255_periphs_device::dma_dcmd_w<13>));
+ map(0x000002e0, 0x000002e3).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<14>), FUNC(pxa255_periphs_device::dma_ddadr_w<14>));
+ map(0x000002e4, 0x000002e7).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<14>), FUNC(pxa255_periphs_device::dma_dsadr_w<14>));
+ map(0x000002e8, 0x000002eb).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<14>), FUNC(pxa255_periphs_device::dma_dtadr_w<14>));
+ map(0x000002ec, 0x000002ef).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<14>), FUNC(pxa255_periphs_device::dma_dcmd_w<14>));
+ map(0x000002f0, 0x000002f3).rw(FUNC(pxa255_periphs_device::dma_ddadr_r<15>), FUNC(pxa255_periphs_device::dma_ddadr_w<15>));
+ map(0x000002f4, 0x000002f7).rw(FUNC(pxa255_periphs_device::dma_dsadr_r<15>), FUNC(pxa255_periphs_device::dma_dsadr_w<15>));
+ map(0x000002f8, 0x000002fb).rw(FUNC(pxa255_periphs_device::dma_dtadr_r<15>), FUNC(pxa255_periphs_device::dma_dtadr_w<15>));
+ map(0x000002fc, 0x000002ff).rw(FUNC(pxa255_periphs_device::dma_dcmd_r<15>), FUNC(pxa255_periphs_device::dma_dcmd_w<15>));
+ map(0x00900000, 0x00900003).rw(FUNC(pxa255_periphs_device::rtc_rcnr_r), FUNC(pxa255_periphs_device::rtc_rcnr_w));
+ map(0x00900004, 0x00900007).rw(FUNC(pxa255_periphs_device::rtc_rtar_r), FUNC(pxa255_periphs_device::rtc_rtar_w));
+ map(0x00900008, 0x0090000b).rw(FUNC(pxa255_periphs_device::rtc_rtsr_r), FUNC(pxa255_periphs_device::rtc_rtsr_w));
+ map(0x0090000c, 0x0090000f).rw(FUNC(pxa255_periphs_device::rtc_rttr_r), FUNC(pxa255_periphs_device::rtc_rttr_w));
+ map(0x00400000, 0x00400003).rw(FUNC(pxa255_periphs_device::i2s_sacr0_r), FUNC(pxa255_periphs_device::i2s_sacr0_w));
+ map(0x00400004, 0x00400007).rw(FUNC(pxa255_periphs_device::i2s_sacr1_r), FUNC(pxa255_periphs_device::i2s_sacr1_w));
+ map(0x0040000c, 0x0040000f).rw(FUNC(pxa255_periphs_device::i2s_sasr0_r), FUNC(pxa255_periphs_device::i2s_sasr0_w));
+ map(0x00400014, 0x00400017).rw(FUNC(pxa255_periphs_device::i2s_saimr_r), FUNC(pxa255_periphs_device::i2s_saimr_w));
+ map(0x00400018, 0x0040001b).rw(FUNC(pxa255_periphs_device::i2s_saicr_r), FUNC(pxa255_periphs_device::i2s_saicr_w));
+ map(0x00400060, 0x00400063).rw(FUNC(pxa255_periphs_device::i2s_sadiv_r), FUNC(pxa255_periphs_device::i2s_sadiv_w));
+ map(0x00400080, 0x00400083).rw(FUNC(pxa255_periphs_device::i2s_sadr_r), FUNC(pxa255_periphs_device::i2s_sadr_w));
+ map(0x00a00000, 0x00a00003).rw(FUNC(pxa255_periphs_device::tmr_osmr_r<0>), FUNC(pxa255_periphs_device::tmr_osmr_w<0>));
+ map(0x00a00004, 0x00a00007).rw(FUNC(pxa255_periphs_device::tmr_osmr_r<1>), FUNC(pxa255_periphs_device::tmr_osmr_w<1>));
+ map(0x00a00008, 0x00a0000b).rw(FUNC(pxa255_periphs_device::tmr_osmr_r<2>), FUNC(pxa255_periphs_device::tmr_osmr_w<2>));
+ map(0x00a0000c, 0x00a0000f).rw(FUNC(pxa255_periphs_device::tmr_osmr_r<3>), FUNC(pxa255_periphs_device::tmr_osmr_w<3>));
+ map(0x00a00010, 0x00a00013).rw(FUNC(pxa255_periphs_device::tmr_oscr_r), FUNC(pxa255_periphs_device::tmr_oscr_w));
+ map(0x00a00014, 0x00a00017).rw(FUNC(pxa255_periphs_device::tmr_ossr_r), FUNC(pxa255_periphs_device::tmr_ossr_w));
+ map(0x00a00018, 0x00a0001b).rw(FUNC(pxa255_periphs_device::tmr_ower_r), FUNC(pxa255_periphs_device::tmr_ower_w));
+ map(0x00a0001c, 0x00a0001f).rw(FUNC(pxa255_periphs_device::tmr_oier_r), FUNC(pxa255_periphs_device::tmr_oier_w));
+ map(0x00d00000, 0x00d00003).rw(FUNC(pxa255_periphs_device::intc_icip_r), FUNC(pxa255_periphs_device::intc_icip_w));
+ map(0x00d00004, 0x00d00007).rw(FUNC(pxa255_periphs_device::intc_icmr_r), FUNC(pxa255_periphs_device::intc_icmr_w));
+ map(0x00d00008, 0x00d0000b).rw(FUNC(pxa255_periphs_device::intc_iclr_r), FUNC(pxa255_periphs_device::intc_iclr_w));
+ map(0x00d0000c, 0x00d0000f).rw(FUNC(pxa255_periphs_device::intc_icfp_r), FUNC(pxa255_periphs_device::intc_icfp_w));
+ map(0x00d00010, 0x00d00013).rw(FUNC(pxa255_periphs_device::intc_icpr_r), FUNC(pxa255_periphs_device::intc_icpr_w));
+ map(0x00d00014, 0x00d00017).rw(FUNC(pxa255_periphs_device::intc_iccr_r), FUNC(pxa255_periphs_device::intc_iccr_w));
+ map(0x00e00000, 0x00e00003).rw(FUNC(pxa255_periphs_device::gpio_gplr_r<0>), FUNC(pxa255_periphs_device::gpio_gplr_w<0>));
+ map(0x00e00004, 0x00e00007).rw(FUNC(pxa255_periphs_device::gpio_gplr_r<1>), FUNC(pxa255_periphs_device::gpio_gplr_w<1>));
+ map(0x00e00008, 0x00e0000b).rw(FUNC(pxa255_periphs_device::gpio_gplr_r<2>), FUNC(pxa255_periphs_device::gpio_gplr_w<2>));
+ map(0x00e0000c, 0x00e0000f).rw(FUNC(pxa255_periphs_device::gpio_gpdr_r<0>), FUNC(pxa255_periphs_device::gpio_gpdr_w<0>));
+ map(0x00e00010, 0x00e00013).rw(FUNC(pxa255_periphs_device::gpio_gpdr_r<1>), FUNC(pxa255_periphs_device::gpio_gpdr_w<1>));
+ map(0x00e00014, 0x00e00017).rw(FUNC(pxa255_periphs_device::gpio_gpdr_r<2>), FUNC(pxa255_periphs_device::gpio_gpdr_w<2>));
+ map(0x00e00018, 0x00e0001b).rw(FUNC(pxa255_periphs_device::gpio_gpsr_r<0>), FUNC(pxa255_periphs_device::gpio_gpsr_w<0>));
+ map(0x00e0001c, 0x00e0001f).rw(FUNC(pxa255_periphs_device::gpio_gpsr_r<1>), FUNC(pxa255_periphs_device::gpio_gpsr_w<1>));
+ map(0x00e00020, 0x00e00023).rw(FUNC(pxa255_periphs_device::gpio_gpsr_r<2>), FUNC(pxa255_periphs_device::gpio_gpsr_w<2>));
+ map(0x00e00024, 0x00e00027).rw(FUNC(pxa255_periphs_device::gpio_gpcr_r<0>), FUNC(pxa255_periphs_device::gpio_gpcr_w<0>));
+ map(0x00e00028, 0x00e0002b).rw(FUNC(pxa255_periphs_device::gpio_gpcr_r<1>), FUNC(pxa255_periphs_device::gpio_gpcr_w<1>));
+ map(0x00e0002c, 0x00e0002f).rw(FUNC(pxa255_periphs_device::gpio_gpcr_r<2>), FUNC(pxa255_periphs_device::gpio_gpcr_w<2>));
+ map(0x00e00030, 0x00e00033).rw(FUNC(pxa255_periphs_device::gpio_grer_r<0>), FUNC(pxa255_periphs_device::gpio_grer_w<0>));
+ map(0x00e00034, 0x00e00037).rw(FUNC(pxa255_periphs_device::gpio_grer_r<1>), FUNC(pxa255_periphs_device::gpio_grer_w<1>));
+ map(0x00e00038, 0x00e0003b).rw(FUNC(pxa255_periphs_device::gpio_grer_r<2>), FUNC(pxa255_periphs_device::gpio_grer_w<2>));
+ map(0x00e0003c, 0x00e0003f).rw(FUNC(pxa255_periphs_device::gpio_gfer_r<0>), FUNC(pxa255_periphs_device::gpio_gfer_w<0>));
+ map(0x00e00040, 0x00e00043).rw(FUNC(pxa255_periphs_device::gpio_gfer_r<1>), FUNC(pxa255_periphs_device::gpio_gfer_w<1>));
+ map(0x00e00044, 0x00e00047).rw(FUNC(pxa255_periphs_device::gpio_gfer_r<2>), FUNC(pxa255_periphs_device::gpio_gfer_w<2>));
+ map(0x00e00048, 0x00e0004b).rw(FUNC(pxa255_periphs_device::gpio_gedr_r<0>), FUNC(pxa255_periphs_device::gpio_gedr_w<0>));
+ map(0x00e0004c, 0x00e0004f).rw(FUNC(pxa255_periphs_device::gpio_gedr_r<1>), FUNC(pxa255_periphs_device::gpio_gedr_w<1>));
+ map(0x00e00050, 0x00e00053).rw(FUNC(pxa255_periphs_device::gpio_gedr_r<2>), FUNC(pxa255_periphs_device::gpio_gedr_w<2>));
+ map(0x00e00054, 0x00e00057).rw(FUNC(pxa255_periphs_device::gpio_gafrl_r<0>), FUNC(pxa255_periphs_device::gpio_gafrl_w<0>));
+ map(0x00e00058, 0x00e0005b).rw(FUNC(pxa255_periphs_device::gpio_gafru_r<0>), FUNC(pxa255_periphs_device::gpio_gafru_w<0>));
+ map(0x00e0005c, 0x00e0005f).rw(FUNC(pxa255_periphs_device::gpio_gafrl_r<1>), FUNC(pxa255_periphs_device::gpio_gafrl_w<1>));
+ map(0x00e00060, 0x00e00063).rw(FUNC(pxa255_periphs_device::gpio_gafru_r<1>), FUNC(pxa255_periphs_device::gpio_gafru_w<1>));
+ map(0x00e00064, 0x00e00067).rw(FUNC(pxa255_periphs_device::gpio_gafrl_r<2>), FUNC(pxa255_periphs_device::gpio_gafrl_w<2>));
+ map(0x00e00068, 0x00e0006b).rw(FUNC(pxa255_periphs_device::gpio_gafru_r<2>), FUNC(pxa255_periphs_device::gpio_gafru_w<2>));
+ map(0x00f00000, 0x00f00003).rw(FUNC(pxa255_periphs_device::pwr_pmcr_r), FUNC(pxa255_periphs_device::pwr_pmcr_w));
+ map(0x00f00004, 0x00f00007).rw(FUNC(pxa255_periphs_device::pwr_pssr_r), FUNC(pxa255_periphs_device::pwr_pssr_w));
+ map(0x00f00008, 0x00f0000b).rw(FUNC(pxa255_periphs_device::pwr_pspr_r), FUNC(pxa255_periphs_device::pwr_pspr_w));
+ map(0x00f0000c, 0x00f0000f).rw(FUNC(pxa255_periphs_device::pwr_pwer_r), FUNC(pxa255_periphs_device::pwr_pwer_w));
+ map(0x00f00010, 0x00f00013).rw(FUNC(pxa255_periphs_device::pwr_prer_r), FUNC(pxa255_periphs_device::pwr_prer_w));
+ map(0x00f00014, 0x00f00017).rw(FUNC(pxa255_periphs_device::pwr_pfer_r), FUNC(pxa255_periphs_device::pwr_pfer_w));
+ map(0x00f00018, 0x00f0001b).rw(FUNC(pxa255_periphs_device::pwr_pedr_r), FUNC(pxa255_periphs_device::pwr_pedr_w));
+ map(0x00f0001c, 0x00f0001f).rw(FUNC(pxa255_periphs_device::pwr_pcfr_r), FUNC(pxa255_periphs_device::pwr_pcfr_w));
+ map(0x00f00020, 0x00f00023).rw(FUNC(pxa255_periphs_device::pwr_pgsr_r<0>), FUNC(pxa255_periphs_device::pwr_pgsr_w<0>));
+ map(0x00f00024, 0x00f00027).rw(FUNC(pxa255_periphs_device::pwr_pgsr_r<1>), FUNC(pxa255_periphs_device::pwr_pgsr_w<1>));
+ map(0x00f00028, 0x00f0002b).rw(FUNC(pxa255_periphs_device::pwr_pgsr_r<2>), FUNC(pxa255_periphs_device::pwr_pgsr_w<2>));
+ map(0x00f00030, 0x00f00033).r(FUNC(pxa255_periphs_device::pwr_rcsr_r));
+ map(0x00f00034, 0x00f00037).rw(FUNC(pxa255_periphs_device::pwr_pmfw_r), FUNC(pxa255_periphs_device::pwr_pmfw_w));
+ map(0x01300000, 0x01300003).rw(FUNC(pxa255_periphs_device::clk_cccr_r), FUNC(pxa255_periphs_device::clk_cccr_w));
+ map(0x01300004, 0x01300007).rw(FUNC(pxa255_periphs_device::clk_cken_r), FUNC(pxa255_periphs_device::clk_cken_w));
+ map(0x01300008, 0x0130000b).rw(FUNC(pxa255_periphs_device::clk_oscc_r), FUNC(pxa255_periphs_device::clk_oscc_w));
+ map(0x04000000, 0x04000003).rw(FUNC(pxa255_periphs_device::lcd_lccr_r<0>), FUNC(pxa255_periphs_device::lcd_lccr_w<0>));
+ map(0x04000004, 0x04000007).rw(FUNC(pxa255_periphs_device::lcd_lccr_r<1>), FUNC(pxa255_periphs_device::lcd_lccr_w<1>));
+ map(0x04000008, 0x0400000b).rw(FUNC(pxa255_periphs_device::lcd_lccr_r<2>), FUNC(pxa255_periphs_device::lcd_lccr_w<2>));
+ map(0x0400000c, 0x0400000f).rw(FUNC(pxa255_periphs_device::lcd_lccr_r<3>), FUNC(pxa255_periphs_device::lcd_lccr_w<3>));
+ map(0x04000020, 0x04000023).rw(FUNC(pxa255_periphs_device::lcd_fbr_r<0>), FUNC(pxa255_periphs_device::lcd_fbr_w<0>));
+ map(0x04000024, 0x04000027).rw(FUNC(pxa255_periphs_device::lcd_fbr_r<1>), FUNC(pxa255_periphs_device::lcd_fbr_w<1>));
+ map(0x04000038, 0x0400003b).rw(FUNC(pxa255_periphs_device::lcd_lcsr_r), FUNC(pxa255_periphs_device::lcd_lcsr_w));
+ map(0x0400003c, 0x0400003f).rw(FUNC(pxa255_periphs_device::lcd_liidr_r), FUNC(pxa255_periphs_device::lcd_liidr_w));
+ map(0x04000040, 0x04000043).rw(FUNC(pxa255_periphs_device::lcd_trgbr_r), FUNC(pxa255_periphs_device::lcd_trgbr_w));
+ map(0x04000044, 0x04000047).rw(FUNC(pxa255_periphs_device::lcd_tcr_r), FUNC(pxa255_periphs_device::lcd_tcr_w));
+ map(0x04000200, 0x04000203).rw(FUNC(pxa255_periphs_device::lcd_fdadr_r<0>), FUNC(pxa255_periphs_device::lcd_fdadr_w<0>));
+ map(0x04000204, 0x04000207).rw(FUNC(pxa255_periphs_device::lcd_fsadr_r<0>), FUNC(pxa255_periphs_device::lcd_fsadr_w<0>));
+ map(0x04000208, 0x0400020b).rw(FUNC(pxa255_periphs_device::lcd_fidr_r<0>), FUNC(pxa255_periphs_device::lcd_fidr_w<0>));
+ map(0x0400020c, 0x0400020f).rw(FUNC(pxa255_periphs_device::lcd_ldcmd_r<0>), FUNC(pxa255_periphs_device::lcd_ldcmd_w<0>));
+ map(0x04000210, 0x04000213).rw(FUNC(pxa255_periphs_device::lcd_fdadr_r<1>), FUNC(pxa255_periphs_device::lcd_fdadr_w<1>));
+ map(0x04000214, 0x04000217).rw(FUNC(pxa255_periphs_device::lcd_fsadr_r<1>), FUNC(pxa255_periphs_device::lcd_fsadr_w<1>));
+ map(0x04000218, 0x0400021b).rw(FUNC(pxa255_periphs_device::lcd_fidr_r<1>), FUNC(pxa255_periphs_device::lcd_fidr_w<1>));
+ map(0x0400021c, 0x0400021f).rw(FUNC(pxa255_periphs_device::lcd_ldcmd_r<1>), FUNC(pxa255_periphs_device::lcd_ldcmd_w<1>));
+}
+
+void pxa255_periphs_device::device_start()
+{
+ for (int index = 0; index < 16; index++)
+ {
+ if (index != 3)
+ {
+ m_dma_regs.timer[index] = timer_alloc(FUNC(pxa255_periphs_device::dma_end_tick), this);
+ }
+ else
+ {
+ m_dma_regs.timer[index] = timer_alloc(FUNC(pxa255_periphs_device::audio_dma_end_tick), this);
+ }
+ }
+
+ for (int index = 0; index < 4; index++)
+ {
+ m_ostimer_regs.timer[index] = timer_alloc(FUNC(pxa255_periphs_device::ostimer_match_tick), this);
+ }
+
+ m_lcd_regs.dma[0].eof = timer_alloc(FUNC(pxa255_periphs_device::lcd_dma_eof_tick), this);
+ m_lcd_regs.dma[1].eof = timer_alloc(FUNC(pxa255_periphs_device::lcd_dma_eof_tick), this);
+
+ m_lcd_palette = make_unique_clear<u32[]>(0x100);
+ m_lcd_framebuffer = make_unique_clear<u8[]>(0x100000);
+ m_samples = make_unique_clear<s16[]>(0x1000);
+
+ m_rtc_regs.timer = timer_alloc(FUNC(pxa255_periphs_device::rtc_tick), this);
+}
+
+void pxa255_periphs_device::device_reset()
+{
+ for (int index = 0; index < 16; index++)
+ {
+ m_dma_regs.dcsr[index] = 0x00000008;
+ }
+
+ m_rtc_regs.rcnr = 0x00000000;
+ m_rtc_regs.rtar = 0x00000000;
+ m_rtc_regs.rtsr = 0x00000000;
+ m_rtc_regs.rttr = 0x00007fff;
+ m_rtc_regs.timer->adjust(attotime::from_hz(1));
+
+ memset(&m_intc_regs, 0, sizeof(m_intc_regs));
+
+ m_lcd_regs.trgbr = 0x00aa5500;
+ m_lcd_regs.tcr = 0x0000754f;
+
+ memset(&m_gpio_regs, 0, sizeof(m_gpio_regs));
+ memset(&m_power_regs, 0, sizeof(m_power_regs));
+ memset(&m_clk_regs, 0, sizeof(m_clk_regs));
+}
+
+void pxa255_periphs_device::device_add_mconfig(machine_config &config)
+{
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_refresh_hz(60);
+ screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ screen.set_size(1024, 1024);
+ screen.set_visarea(0, 295, 0, 479);
+ screen.set_screen_update(FUNC(pxa255_periphs_device::screen_update));
+
+ PALETTE(config, m_palette).set_entries(256);
+
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+
+ DMADAC(config, m_dmadac[0]).add_route(ALL_OUTPUTS, "lspeaker", 1.0);
+ DMADAC(config, m_dmadac[1]).add_route(ALL_OUTPUTS, "rspeaker", 1.0);
+}
+
/*
PXA255 Inter-Integrated-Circuit Sound (I2S) Controller
@@ -55,88 +277,110 @@ pxa255_periphs_device::pxa255_periphs_device(const machine_config &mconfig, cons
*/
-uint32_t pxa255_periphs_device::i2s_r(offs_t offset, uint32_t mem_mask)
+u32 pxa255_periphs_device::i2s_sacr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_i2s_regs.sacr0;
+ LOGMASKED(LOG_I2S, "%s: i2s_sacr0_r: Serial Audio Controller Global Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::i2s_sacr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_I2S, "%s: i2s_sacr0_r: Serial Audio Controller Global Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_i2s_regs.sacr0 = data & 0x0000ff3d;
+}
+
+u32 pxa255_periphs_device::i2s_sacr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_i2s_regs.sacr1;
+ LOGMASKED(LOG_I2S, "%s: i2s_sacr1_r: Serial Audio Controller I2S/MSB-Justified Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::i2s_sacr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_I2S, "%s: i2s_sacr1_w: Serial Audio Controller I2S/MSB-Justified Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_i2s_regs.sacr1 = data & 0x00000039;
+}
+
+u32 pxa255_periphs_device::i2s_sasr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_i2s_regs.sasr0;
+ LOGMASKED(LOG_I2S, "%s: i2s_sasr0_r: Serial Audio Controller I2S/MSB-Justified Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::i2s_sasr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_I2S, "%s: i2s_sasr0_w: Serial Audio Controller I2S/MSB-Justified Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_i2s_regs.sasr0 = data & 0x0000ff7f;
+}
+
+u32 pxa255_periphs_device::i2s_saimr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_i2s_regs.saimr;
+ LOGMASKED(LOG_I2S, "%s: i2s_saimr_r: Serial Audio Interrupt Mask Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::i2s_saimr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_I2S, "%s: i2s_saimr_w: Serial Audio Interrupt Mask Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_i2s_regs.saimr = data & 0x00000078;
+}
+
+u32 pxa255_periphs_device::i2s_saicr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_i2s_regs.saicr;
+ LOGMASKED(LOG_I2S, "%s: i2s_saimr_r: Serial Audio Interrupt Clear Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::i2s_saicr_w(offs_t offset, u32 data, u32 mem_mask)
{
- switch(PXA255_I2S_BASE_ADDR | (offset << 2))
+ LOGMASKED(LOG_I2S, "%s: i2s_saicr_w: Serial Audio Interrupt Clear Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ if (m_i2s_regs.saicr & SAICR_ROR)
{
- case PXA255_SACR0:
- LOGMASKED(LOG_I2S, "pxa255_i2s_r: Serial Audio Controller Global Control Register: %08x & %08x\n", m_i2s_regs.sacr0, mem_mask);
- return m_i2s_regs.sacr0;
- case PXA255_SACR1:
- LOGMASKED(LOG_I2S, "pxa255_i2s_r: Serial Audio Controller I2S/MSB-Justified Control Register: %08x & %08x\n", m_i2s_regs.sacr1, mem_mask);
- return m_i2s_regs.sacr1;
- case PXA255_SASR0:
- LOGMASKED(LOG_I2S, "pxa255_i2s_r: Serial Audio Controller I2S/MSB-Justified Status Register: %08x & %08x\n", m_i2s_regs.sasr0, mem_mask);
- return m_i2s_regs.sasr0;
- case PXA255_SAIMR:
- LOGMASKED(LOG_I2S, "pxa255_i2s_r: Serial Audio Interrupt Mask Register: %08x & %08x\n", m_i2s_regs.saimr, mem_mask);
- return m_i2s_regs.saimr;
- case PXA255_SAICR:
- LOGMASKED(LOG_I2S, "pxa255_i2s_r: Serial Audio Interrupt Clear Register: %08x & %08x\n", m_i2s_regs.saicr, mem_mask);
- return m_i2s_regs.saicr;
- case PXA255_SADIV:
- LOGMASKED(LOG_I2S, "pxa255_i2s_r: Serial Audio Clock Divider Register: %08x & %08x\n", m_i2s_regs.sadiv, mem_mask);
- return m_i2s_regs.sadiv;
- case PXA255_SADR:
- LOGMASKED(LOG_I2S, "pxa255_i2s_r: Serial Audio Data Register: %08x & %08x\n", m_i2s_regs.sadr, mem_mask);
- return m_i2s_regs.sadr;
- default:
- LOGMASKED(LOG_I2S | LOG_UNKNOWN, "pxa255_i2s_r: Unknown address: %08x\n", PXA255_I2S_BASE_ADDR | (offset << 2));
- break;
+ m_i2s_regs.sasr0 &= ~SASR0_ROR;
+ }
+ if (m_i2s_regs.saicr & SAICR_TUR)
+ {
+ m_i2s_regs.sasr0 &= ~SASR0_TUR;
}
- return 0;
}
-void pxa255_periphs_device::i2s_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+u32 pxa255_periphs_device::i2s_sadiv_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_I2S_BASE_ADDR | (offset << 2))
+ const u32 data = m_i2s_regs.sadiv;
+ LOGMASKED(LOG_I2S, "%s: i2s_sadiv_r: Serial Audio Clock Divider Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::i2s_sadiv_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_I2S, "%s: i2s_saicr_w: Serial Audio Clock Divider Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_i2s_regs.sadiv = data & 0x0000007f;
+ for (int i = 0; i < 2; i++)
{
- case PXA255_SACR0:
- LOGMASKED(LOG_I2S, "pxa255_i2s_w: Serial Audio Controller Global Control Register: %08x & %08x\n", data, mem_mask);
- m_i2s_regs.sacr0 = data & 0x0000ff3d;
- break;
- case PXA255_SACR1:
- LOGMASKED(LOG_I2S, "pxa255_i2s_w: Serial Audio Controller I2S/MSB-Justified Control Register: %08x & %08x\n", data, mem_mask);
- m_i2s_regs.sacr1 = data & 0x00000039;
- break;
- case PXA255_SASR0:
- LOGMASKED(LOG_I2S, "pxa255_i2s_w: Serial Audio Controller I2S/MSB-Justified Status Register: %08x & %08x\n", data, mem_mask);
- m_i2s_regs.sasr0 = data & 0x0000ff7f;
- break;
- case PXA255_SAIMR:
- LOGMASKED(LOG_I2S, "pxa255_i2s_w: Serial Audio Interrupt Mask Register: %08x & %08x\n", data, mem_mask);
- m_i2s_regs.saimr = data & 0x00000078;
- break;
- case PXA255_SAICR:
- LOGMASKED(LOG_I2S, "pxa255_i2s_w: Serial Audio Interrupt Clear Register: %08x & %08x\n", data, mem_mask);
- if(m_i2s_regs.saicr & PXA255_SAICR_ROR)
- {
- m_i2s_regs.sasr0 &= ~PXA255_SASR0_ROR;
- }
- if(m_i2s_regs.saicr & PXA255_SAICR_TUR)
- {
- m_i2s_regs.sasr0 &= ~PXA255_SASR0_TUR;
- }
- break;
- case PXA255_SADIV:
- LOGMASKED(LOG_I2S, "pxa255_i2s_w: Serial Audio Clock Divider Register: %08x & %08x\n", data, mem_mask);
- m_i2s_regs.sadiv = data & 0x0000007f;
- for (int i = 0; i < 2; i++)
- {
- m_dmadac[i]->set_frequency(((double)147600000 / (double)m_i2s_regs.sadiv) / 256.0);
- m_dmadac[i]->enable(1);
- }
- break;
- case PXA255_SADR:
- LOGMASKED(LOG_I2S, "pxa255_i2s_w: Serial Audio Data Register: %08x & %08x\n", data, mem_mask);
- m_i2s_regs.sadr = data;
- break;
- default:
- LOGMASKED(LOG_I2S | LOG_UNKNOWN, "pxa255_i2s_w: Unknown address: %08x = %08x & %08x\n", PXA255_I2S_BASE_ADDR | (offset << 2), data, mem_mask);
- break;
+ m_dmadac[i]->set_frequency(((double)147600000 / (double)m_i2s_regs.sadiv) / 256.0);
+ m_dmadac[i]->enable(1);
}
}
+u32 pxa255_periphs_device::i2s_sadr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_i2s_regs.sadr;
+ LOGMASKED(LOG_I2S, "%s: i2s_sadr_r: Serial Audio Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::i2s_sadr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_I2S, "%s: i2s_sadr_r: Serial Audio Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_i2s_regs.sadr = data;
+}
+
+
/*
PXA255 DMA controller
@@ -150,7 +394,7 @@ void pxa255_periphs_device::dma_irq_check()
int set_irq = 0;
for (int channel = 0; channel < 16; channel++)
{
- if (m_dma_regs.dcsr[channel] & (PXA255_DCSR_ENDINTR | PXA255_DCSR_STARTINTR | PXA255_DCSR_BUSERRINTR))
+ if (m_dma_regs.dcsr[channel] & (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERRINTR))
{
m_dma_regs.dint |= 1 << channel;
set_irq = 1;
@@ -161,7 +405,7 @@ void pxa255_periphs_device::dma_irq_check()
}
}
- set_irq_line(PXA255_INT_DMA, set_irq);
+ set_irq_line(INT_DMA, set_irq);
}
void pxa255_periphs_device::dma_load_descriptor_and_start(int channel)
@@ -174,7 +418,6 @@ void pxa255_periphs_device::dma_load_descriptor_and_start(int channel)
}
// Load the next descriptor
-
address_space &space = m_maincpu->space(AS_PROGRAM);
m_dma_regs.dsadr[channel] = space.read_dword(m_dma_regs.ddadr[channel] + 0x4);
m_dma_regs.dtadr[channel] = space.read_dword(m_dma_regs.ddadr[channel] + 0x8);
@@ -182,7 +425,7 @@ void pxa255_periphs_device::dma_load_descriptor_and_start(int channel)
m_dma_regs.ddadr[channel] = space.read_dword(m_dma_regs.ddadr[channel]);
// Start our end-of-transfer timer
- switch(channel)
+ switch (channel)
{
case 3:
m_dma_regs.timer[channel]->adjust(attotime::from_hz((147600000 / m_i2s_regs.sadiv) / (4 * 64)) * (m_dma_regs.dcmd[channel] & 0x00001fff), channel);
@@ -193,260 +436,222 @@ void pxa255_periphs_device::dma_load_descriptor_and_start(int channel)
}
// Interrupt as necessary
- if(m_dma_regs.dcmd[channel] & PXA255_DCMD_STARTIRQEN)
+ if (m_dma_regs.dcmd[channel] & DCMD_STARTIRQEN)
{
- m_dma_regs.dcsr[channel] |= PXA255_DCSR_STARTINTR;
+ m_dma_regs.dcsr[channel] |= DCSR_STARTINTR;
}
- m_dma_regs.dcsr[channel] &= ~PXA255_DCSR_STOPSTATE;
+ m_dma_regs.dcsr[channel] &= ~DCSR_STOPSTATE;
}
-void pxa255_periphs_device::dma_end_tick(int channel)
+TIMER_CALLBACK_MEMBER(pxa255_periphs_device::audio_dma_end_tick)
{
- uint32_t sadr = m_dma_regs.dsadr[channel];
- uint32_t tadr = m_dma_regs.dtadr[channel];
- uint32_t count = m_dma_regs.dcmd[channel] & 0x00001fff;
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ const u32 count = m_dma_regs.dcmd[3] & 0x00001fff;
+ u32 sadr = m_dma_regs.dsadr[3];
+ s16 *out_samples = &m_samples[0];
+ for (u32 index = 0; index < count; index += 4, sadr += 4)
+ {
+ const u32 word = space.read_dword(sadr);
+ *out_samples++ = (s16)(word >> 16);
+ *out_samples++ = (s16)(word & 0xffff);
+ }
+
+ for (int index = 0; index < 2; index++)
+ {
+ m_dmadac[index]->flush();
+ m_dmadac[index]->transfer(index, 2, 2, count/4, m_samples.get());
+ }
+
+ dma_finish(param);
+}
+
+TIMER_CALLBACK_MEMBER(pxa255_periphs_device::dma_end_tick)
+{
address_space &space = m_maincpu->space(AS_PROGRAM);
- switch (channel)
+ const u32 count = m_dma_regs.dcmd[param] & 0x00001fff;
+ u32 sadr = m_dma_regs.dsadr[param];
+ u32 tadr = m_dma_regs.dtadr[param];
+
+ static const u32 s_inc_size[4] = { 0, 1, 2, 4 };
+ const u32 inc_index = (m_dma_regs.dcmd[param] >> DCMD_SIZE_SHIFT) & DCMD_SIZE_MASK;
+ const u32 inc_val = s_inc_size[inc_index];
+ const u32 sadr_inc = (m_dma_regs.dcmd[param] & DCMD_INCSRCADDR) ? inc_val : 0;
+ const u32 tadr_inc = (m_dma_regs.dcmd[param] & DCMD_INCTRGADDR) ? inc_val : 0;
+
+ if (inc_val > 0)
{
- case 3:
- for (uint32_t index = 0; index < count; index += 4)
- {
- m_words[index >> 2] = space.read_dword(sadr);
- m_samples[(index >> 1) + 0] = (int16_t)(m_words[index >> 2] >> 16);
- m_samples[(index >> 1) + 1] = (int16_t)(m_words[index >> 2] & 0xffff);
- sadr += 4;
- }
- for (int index = 0; index < 2; index++)
- {
- m_dmadac[index]->flush();
- m_dmadac[index]->transfer(index, 2, 2, count/4, m_samples.get());
- }
- break;
- default:
- for (uint32_t index = 0; index < count;)
- {
- switch (m_dma_regs.dcmd[channel] & PXA255_DCMD_SIZE)
- {
- case PXA255_DCMD_SIZE_8:
- space.write_byte(tadr, space.read_byte(sadr));
- index++;
- break;
- case PXA255_DCMD_SIZE_16:
- space.write_word(tadr, space.read_word(sadr));
- index += 2;
- break;
- case PXA255_DCMD_SIZE_32:
- space.write_dword(tadr, space.read_dword(sadr));
- index += 4;
- break;
- default:
- logerror( "pxa255_dma_dma_end: Unsupported DMA size\n" );
- break;
- }
-
- if (m_dma_regs.dcmd[channel] & PXA255_DCMD_INCSRCADDR)
- {
- switch(m_dma_regs.dcmd[channel] & PXA255_DCMD_SIZE)
- {
- case PXA255_DCMD_SIZE_8:
- sadr++;
- break;
- case PXA255_DCMD_SIZE_16:
- sadr += 2;
- break;
- case PXA255_DCMD_SIZE_32:
- sadr += 4;
- break;
- default:
- break;
- }
- }
- if(m_dma_regs.dcmd[channel] & PXA255_DCMD_INCTRGADDR)
- {
- switch(m_dma_regs.dcmd[channel] & PXA255_DCMD_SIZE)
- {
- case PXA255_DCMD_SIZE_8:
- tadr++;
- break;
- case PXA255_DCMD_SIZE_16:
- tadr += 2;
- break;
- case PXA255_DCMD_SIZE_32:
- tadr += 4;
- break;
- default:
- break;
- }
- }
- }
- break;
+ switch (inc_val)
+ {
+ case DCMD_SIZE_8:
+ for (u32 index = 0; index < count; index += inc_val, sadr += sadr_inc, tadr += tadr_inc)
+ space.write_byte(tadr, space.read_byte(sadr));
+ break;
+ case DCMD_SIZE_16:
+ for (u32 index = 0; index < count; index += inc_val, sadr += sadr_inc, tadr += tadr_inc)
+ space.write_word(tadr, space.read_byte(sadr));
+ break;
+ case DCMD_SIZE_32:
+ for (u32 index = 0; index < count; index += inc_val, sadr += sadr_inc, tadr += tadr_inc)
+ space.write_dword(tadr, space.read_byte(sadr));
+ break;
+ default:
+ LOGMASKED(LOG_DMA, "pxa255_dma_dma_end: Unsupported DMA size\n");
+ break;
+ }
}
- if (m_dma_regs.dcmd[channel] & PXA255_DCMD_ENDIRQEN)
+ dma_finish(param);
+}
+
+void pxa255_periphs_device::dma_finish(int channel)
+{
+ if (m_dma_regs.dcmd[channel] & DCMD_ENDIRQEN)
{
- m_dma_regs.dcsr[channel] |= PXA255_DCSR_ENDINTR;
+ m_dma_regs.dcsr[channel] |= DCSR_ENDINTR;
}
- if (!(m_dma_regs.ddadr[channel] & PXA255_DDADR_STOP) && (m_dma_regs.dcsr[channel] & PXA255_DCSR_RUN))
+ if (!(m_dma_regs.ddadr[channel] & DDADR_STOP) && (m_dma_regs.dcsr[channel] & DCSR_RUN))
{
- if (m_dma_regs.dcsr[channel] & PXA255_DCSR_RUN)
+ if (m_dma_regs.dcsr[channel] & DCSR_RUN)
{
dma_load_descriptor_and_start(channel);
}
else
{
- m_dma_regs.dcsr[channel] &= ~PXA255_DCSR_RUN;
- m_dma_regs.dcsr[channel] |= PXA255_DCSR_STOPSTATE;
+ m_dma_regs.dcsr[channel] &= ~DCSR_RUN;
+ m_dma_regs.dcsr[channel] |= DCSR_STOPSTATE;
}
}
else
{
- m_dma_regs.dcsr[channel] &= ~PXA255_DCSR_RUN;
- m_dma_regs.dcsr[channel] |= PXA255_DCSR_STOPSTATE;
+ m_dma_regs.dcsr[channel] &= ~DCSR_RUN;
+ m_dma_regs.dcsr[channel] |= DCSR_STOPSTATE;
}
dma_irq_check();
}
-uint32_t pxa255_periphs_device::dma_r(offs_t offset, uint32_t mem_mask)
+u32 pxa255_periphs_device::dma_dcsr_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_DMA_BASE_ADDR | (offset << 2))
- {
- case PXA255_DCSR0: case PXA255_DCSR1: case PXA255_DCSR2: case PXA255_DCSR3:
- case PXA255_DCSR4: case PXA255_DCSR5: case PXA255_DCSR6: case PXA255_DCSR7:
- case PXA255_DCSR8: case PXA255_DCSR9: case PXA255_DCSR10: case PXA255_DCSR11:
- case PXA255_DCSR12: case PXA255_DCSR13: case PXA255_DCSR14: case PXA255_DCSR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_r: DMA Channel Control/Status Register %d: %08x & %08x\n", offset, m_dma_regs.dcsr[offset], mem_mask);
- return m_dma_regs.dcsr[offset];
- case PXA255_DINT:
- LOGMASKED(LOG_DMA, "pxa255_dma_r: DMA Interrupt Register: %08x & %08x\n", m_dma_regs.dint, mem_mask);
- return m_dma_regs.dint;
- case PXA255_DRCMR0: case PXA255_DRCMR1: case PXA255_DRCMR2: case PXA255_DRCMR3:
- case PXA255_DRCMR4: case PXA255_DRCMR5: case PXA255_DRCMR6: case PXA255_DRCMR7:
- case PXA255_DRCMR8: case PXA255_DRCMR9: case PXA255_DRCMR10: case PXA255_DRCMR11:
- case PXA255_DRCMR12: case PXA255_DRCMR13: case PXA255_DRCMR14: case PXA255_DRCMR15:
- case PXA255_DRCMR16: case PXA255_DRCMR17: case PXA255_DRCMR18: case PXA255_DRCMR19:
- case PXA255_DRCMR20: case PXA255_DRCMR21: case PXA255_DRCMR22: case PXA255_DRCMR23:
- case PXA255_DRCMR24: case PXA255_DRCMR25: case PXA255_DRCMR26: case PXA255_DRCMR27:
- case PXA255_DRCMR28: case PXA255_DRCMR29: case PXA255_DRCMR30: case PXA255_DRCMR31:
- case PXA255_DRCMR32: case PXA255_DRCMR33: case PXA255_DRCMR34: case PXA255_DRCMR35:
- case PXA255_DRCMR36: case PXA255_DRCMR37: case PXA255_DRCMR38: case PXA255_DRCMR39:
- LOGMASKED(LOG_DMA, "pxa255_dma_r: DMA Request to Channel Map Register %d: %08x & %08x\n", offset - (0x100 >> 2), 0, mem_mask);
- return m_dma_regs.drcmr[offset - (0x100 >> 2)];
- case PXA255_DDADR0: case PXA255_DDADR1: case PXA255_DDADR2: case PXA255_DDADR3:
- case PXA255_DDADR4: case PXA255_DDADR5: case PXA255_DDADR6: case PXA255_DDADR7:
- case PXA255_DDADR8: case PXA255_DDADR9: case PXA255_DDADR10: case PXA255_DDADR11:
- case PXA255_DDADR12: case PXA255_DDADR13: case PXA255_DDADR14: case PXA255_DDADR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_r: DMA Descriptor Address Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, 0, mem_mask);
- return m_dma_regs.ddadr[(offset - (0x200 >> 2)) >> 2];
- case PXA255_DSADR0: case PXA255_DSADR1: case PXA255_DSADR2: case PXA255_DSADR3:
- case PXA255_DSADR4: case PXA255_DSADR5: case PXA255_DSADR6: case PXA255_DSADR7:
- case PXA255_DSADR8: case PXA255_DSADR9: case PXA255_DSADR10: case PXA255_DSADR11:
- case PXA255_DSADR12: case PXA255_DSADR13: case PXA255_DSADR14: case PXA255_DSADR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_r: DMA Source Address Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, 0, mem_mask);
- return m_dma_regs.dsadr[(offset - (0x200 >> 2)) >> 2];
- case PXA255_DTADR0: case PXA255_DTADR1: case PXA255_DTADR2: case PXA255_DTADR3:
- case PXA255_DTADR4: case PXA255_DTADR5: case PXA255_DTADR6: case PXA255_DTADR7:
- case PXA255_DTADR8: case PXA255_DTADR9: case PXA255_DTADR10: case PXA255_DTADR11:
- case PXA255_DTADR12: case PXA255_DTADR13: case PXA255_DTADR14: case PXA255_DTADR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_r: DMA Target Address Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, 0, mem_mask);
- return m_dma_regs.dtadr[(offset - (0x200 >> 2)) >> 2];
- case PXA255_DCMD0: case PXA255_DCMD1: case PXA255_DCMD2: case PXA255_DCMD3:
- case PXA255_DCMD4: case PXA255_DCMD5: case PXA255_DCMD6: case PXA255_DCMD7:
- case PXA255_DCMD8: case PXA255_DCMD9: case PXA255_DCMD10: case PXA255_DCMD11:
- case PXA255_DCMD12: case PXA255_DCMD13: case PXA255_DCMD14: case PXA255_DCMD15:
- LOGMASKED(LOG_DMA, "pxa255_dma_r: DMA Command Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, 0, mem_mask);
- return m_dma_regs.dcmd[(offset - (0x200 >> 2)) >> 2];
- default:
- LOGMASKED(LOG_DMA | LOG_UNKNOWN, "pxa255_dma_r: Unknown address: %08x\n", PXA255_DMA_BASE_ADDR | (offset << 2));
- break;
- }
- return 0;
+ const u32 data = m_dma_regs.dcsr[offset];
+ LOGMASKED(LOG_DMA, "%s: dma_dcsr_r: DMA Channel Control/Status Register %d: %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ return data;
}
-void pxa255_periphs_device::dma_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void pxa255_periphs_device::dma_dcsr_w(offs_t offset, u32 data, u32 mem_mask)
{
- switch (PXA255_DMA_BASE_ADDR | (offset << 2))
+ LOGMASKED(LOG_DMA, "%s: dma_dcsr_w: DMA Channel Control/Status Register %d = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_dma_regs.dcsr[offset] &= ~(data & 0x00000007);
+ m_dma_regs.dcsr[offset] &= ~0x60000000;
+ m_dma_regs.dcsr[offset] |= data & 0x60000000;
+ if ((data & DCSR_RUN) && !(m_dma_regs.dcsr[offset] & DCSR_RUN))
{
- case PXA255_DCSR0: case PXA255_DCSR1: case PXA255_DCSR2: case PXA255_DCSR3:
- case PXA255_DCSR4: case PXA255_DCSR5: case PXA255_DCSR6: case PXA255_DCSR7:
- case PXA255_DCSR8: case PXA255_DCSR9: case PXA255_DCSR10: case PXA255_DCSR11:
- case PXA255_DCSR12: case PXA255_DCSR13: case PXA255_DCSR14: case PXA255_DCSR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_w: DMA Channel Control/Status Register %d: %08x & %08x\n", offset, data, mem_mask);
- m_dma_regs.dcsr[offset] &= ~(data & 0x00000007);
- m_dma_regs.dcsr[offset] &= ~0x60000000;
- m_dma_regs.dcsr[offset] |= data & 0x60000000;
- if ((data & PXA255_DCSR_RUN) && !(m_dma_regs.dcsr[offset] & PXA255_DCSR_RUN))
- {
- m_dma_regs.dcsr[offset] |= PXA255_DCSR_RUN;
- if (data & PXA255_DCSR_NODESCFETCH)
- {
- LOGMASKED(LOG_DMA, " No-Descriptor-Fetch mode is not supported.\n");
- break;
- }
-
- dma_load_descriptor_and_start(offset);
- }
- else if(!(data & PXA255_DCSR_RUN))
- {
- m_dma_regs.dcsr[offset] &= ~PXA255_DCSR_RUN;
- }
+ m_dma_regs.dcsr[offset] |= DCSR_RUN;
+ if (data & DCSR_NODESCFETCH)
+ {
+ LOGMASKED(LOG_DMA, "%s: No-Descriptor-Fetch mode is not supported.\n", machine().describe_context());
+ return;
+ }
- dma_irq_check();
- break;
- case PXA255_DINT:
- LOGMASKED(LOG_DMA, "pxa255_dma_w: DMA Interrupt Register: %08x & %08x\n", data, mem_mask);
- m_dma_regs.dint &= ~data;
- break;
- case PXA255_DRCMR0: case PXA255_DRCMR1: case PXA255_DRCMR2: case PXA255_DRCMR3:
- case PXA255_DRCMR4: case PXA255_DRCMR5: case PXA255_DRCMR6: case PXA255_DRCMR7:
- case PXA255_DRCMR8: case PXA255_DRCMR9: case PXA255_DRCMR10: case PXA255_DRCMR11:
- case PXA255_DRCMR12: case PXA255_DRCMR13: case PXA255_DRCMR14: case PXA255_DRCMR15:
- case PXA255_DRCMR16: case PXA255_DRCMR17: case PXA255_DRCMR18: case PXA255_DRCMR19:
- case PXA255_DRCMR20: case PXA255_DRCMR21: case PXA255_DRCMR22: case PXA255_DRCMR23:
- case PXA255_DRCMR24: case PXA255_DRCMR25: case PXA255_DRCMR26: case PXA255_DRCMR27:
- case PXA255_DRCMR28: case PXA255_DRCMR29: case PXA255_DRCMR30: case PXA255_DRCMR31:
- case PXA255_DRCMR32: case PXA255_DRCMR33: case PXA255_DRCMR34: case PXA255_DRCMR35:
- case PXA255_DRCMR36: case PXA255_DRCMR37: case PXA255_DRCMR38: case PXA255_DRCMR39:
- LOGMASKED(LOG_DMA, "pxa255_dma_w: DMA Request to Channel Map Register %d: %08x & %08x\n", offset - (0x100 >> 2), data, mem_mask);
- m_dma_regs.drcmr[offset - (0x100 >> 2)] = data & 0x0000008f;
- break;
- case PXA255_DDADR0: case PXA255_DDADR1: case PXA255_DDADR2: case PXA255_DDADR3:
- case PXA255_DDADR4: case PXA255_DDADR5: case PXA255_DDADR6: case PXA255_DDADR7:
- case PXA255_DDADR8: case PXA255_DDADR9: case PXA255_DDADR10: case PXA255_DDADR11:
- case PXA255_DDADR12: case PXA255_DDADR13: case PXA255_DDADR14: case PXA255_DDADR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_w: DMA Descriptor Address Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, data, mem_mask);
- m_dma_regs.ddadr[(offset - (0x200 >> 2)) >> 2] = data & 0xfffffff1;
- break;
- case PXA255_DSADR0: case PXA255_DSADR1: case PXA255_DSADR2: case PXA255_DSADR3:
- case PXA255_DSADR4: case PXA255_DSADR5: case PXA255_DSADR6: case PXA255_DSADR7:
- case PXA255_DSADR8: case PXA255_DSADR9: case PXA255_DSADR10: case PXA255_DSADR11:
- case PXA255_DSADR12: case PXA255_DSADR13: case PXA255_DSADR14: case PXA255_DSADR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_w: DMA Source Address Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, data, mem_mask);
- m_dma_regs.dsadr[(offset - (0x200 >> 2)) >> 2] = data & 0xfffffffc;
- break;
- case PXA255_DTADR0: case PXA255_DTADR1: case PXA255_DTADR2: case PXA255_DTADR3:
- case PXA255_DTADR4: case PXA255_DTADR5: case PXA255_DTADR6: case PXA255_DTADR7:
- case PXA255_DTADR8: case PXA255_DTADR9: case PXA255_DTADR10: case PXA255_DTADR11:
- case PXA255_DTADR12: case PXA255_DTADR13: case PXA255_DTADR14: case PXA255_DTADR15:
- LOGMASKED(LOG_DMA, "pxa255_dma_w: DMA Target Address Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, data, mem_mask);
- m_dma_regs.dtadr[(offset - (0x200 >> 2)) >> 2] = data & 0xfffffffc;
- break;
- case PXA255_DCMD0: case PXA255_DCMD1: case PXA255_DCMD2: case PXA255_DCMD3:
- case PXA255_DCMD4: case PXA255_DCMD5: case PXA255_DCMD6: case PXA255_DCMD7:
- case PXA255_DCMD8: case PXA255_DCMD9: case PXA255_DCMD10: case PXA255_DCMD11:
- case PXA255_DCMD12: case PXA255_DCMD13: case PXA255_DCMD14: case PXA255_DCMD15:
- LOGMASKED(LOG_DMA, "pxa255_dma_w: DMA Command Register %d: %08x & %08x\n", (offset - (0x200 >> 2)) >> 2, data, mem_mask);
- m_dma_regs.dcmd[(offset - (0x200 >> 2)) >> 2] = data & 0xf067dfff;
- break;
- default:
- LOGMASKED(LOG_DMA | LOG_UNKNOWN, "pxa255_dma_w: Unknown address: %08x = %08x & %08x\n", PXA255_DMA_BASE_ADDR | (offset << 2), data, mem_mask);
- break;
+ dma_load_descriptor_and_start(offset);
+ }
+ else if (!(data & DCSR_RUN))
+ {
+ m_dma_regs.dcsr[offset] &= ~DCSR_RUN;
}
+
+ dma_irq_check();
+}
+
+u32 pxa255_periphs_device::dma_dint_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs.dint;
+ LOGMASKED(LOG_DMA, "%s: dma_dint_r: DMA Interrupt Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
+void pxa255_periphs_device::dma_dint_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dint_w: DMA Interrupt Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_dma_regs.dint &= ~data;
+}
+
+u32 pxa255_periphs_device::dma_drcmr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs.drcmr[offset];
+ LOGMASKED(LOG_DMA, "%s: dma_drcmr_r: DMA Request to Channel Map Register %d: %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::dma_drcmr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_drcmr_w: DMA Request to Channel Map Register %d = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_dma_regs.drcmr[offset] = data & 0x0000008f;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::dma_ddadr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs.ddadr[Which];
+ LOGMASKED(LOG_DMA, "%s: dma_ddadr_r: DMA Descriptor Address Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::dma_ddadr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_ddadr_w: DMA Descriptor Address Register %d = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_dma_regs.ddadr[offset] = data & 0xfffffff1;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::dma_dsadr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs.dsadr[Which];
+ LOGMASKED(LOG_DMA, "%s: dma_dsadr_r: DMA Source Address Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::dma_dsadr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dsadr_w: DMA Source Address Register %d = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_dma_regs.dsadr[offset] = data & 0xfffffffc;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::dma_dtadr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs.dtadr[Which];
+ LOGMASKED(LOG_DMA, "%s: dma_dtadr_r: DMA Target Address Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::dma_dtadr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dtadr_w: DMA Target Address Register %d = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_dma_regs.dtadr[Which] = data & 0xfffffffc;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::dma_dcmd_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs.dcmd[Which];
+ LOGMASKED(LOG_DMA, "%s: dma_dcmd_r: DMA Command Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::dma_dcmd_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dcmd_w: DMA Command Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_dma_regs.dcmd[offset] = data & 0xf067dfff;
+}
+
+
/*
PXA255 Real-Time Clock
@@ -455,13 +660,13 @@ void pxa255_periphs_device::dma_w(offs_t offset, uint32_t data, uint32_t mem_mas
*/
-void pxa255_periphs_device::rtc_tick()
+TIMER_CALLBACK_MEMBER(pxa255_periphs_device::rtc_tick)
{
m_rtc_regs.rcnr++;
if (BIT(m_rtc_regs.rtsr, 3))
{
m_rtc_regs.rtsr |= (1 << 1);
- set_irq_line(PXA255_INT_RTC_HZ, 1);
+ set_irq_line(INT_RTC_HZ, 1);
}
if (m_rtc_regs.rcnr == m_rtc_regs.rtar)
@@ -469,73 +674,75 @@ void pxa255_periphs_device::rtc_tick()
if (BIT(m_rtc_regs.rtsr, 2))
{
m_rtc_regs.rtsr |= (1 << 0);
- set_irq_line(PXA255_INT_RTC_ALARM, 1);
+ set_irq_line(INT_RTC_ALARM, 1);
}
}
}
-uint32_t pxa255_periphs_device::rtc_r(offs_t offset, uint32_t mem_mask)
+u32 pxa255_periphs_device::rtc_rcnr_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_RTC_BASE_ADDR | (offset << 2))
- {
- case PXA255_RCNR:
- LOGMASKED(LOG_RTC, "%s: pxa255 rtc_r: RTC Counter Register: %08x\n", machine().describe_context(), m_rtc_regs.rcnr);
- return m_rtc_regs.rcnr;
- case PXA255_RTAR:
- LOGMASKED(LOG_RTC, "%s: pxa255 rtc_r: RTC Alarm Register: %08x\n", machine().describe_context(), m_rtc_regs.rtar);
- return m_rtc_regs.rtar;
- case PXA255_RTSR:
- LOGMASKED(LOG_RTC, "%s: pxa255 rtc_r: RTC Status Register: %08x\n", machine().describe_context(), m_rtc_regs.rtsr);
- return m_rtc_regs.rtsr;
- case PXA255_RTTR:
- LOGMASKED(LOG_RTC, "%s: pxa255 rtc_r: RTC Trim Register: %08x\n", machine().describe_context(), m_rtc_regs.rttr);
- return m_rtc_regs.rttr;
- default:
- LOGMASKED(LOG_RTC | LOG_UNKNOWN, "pxa255 rtc_r: Unknown address: %08x\n", PXA255_RTC_BASE_ADDR | (offset << 2));
- break;
- }
- return 0;
+ const u32 data = m_rtc_regs.rcnr;
+ LOGMASKED(LOG_RTC, "%s: rtc_rcnr_r: RTC Counter Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
-void pxa255_periphs_device::rtc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void pxa255_periphs_device::rtc_rcnr_w(offs_t offset, u32 data, u32 mem_mask)
{
- switch(PXA255_RTC_BASE_ADDR | (offset << 2))
+ LOGMASKED(LOG_RTC, "%s: rtc_rcnr_w: RTC Counter Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_rtc_regs.rcnr);
+}
+
+u32 pxa255_periphs_device::rtc_rtar_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rtc_regs.rtar;
+ LOGMASKED(LOG_RTC, "%s: rtc_rtar_r: RTC Alarm Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::rtc_rtar_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: rtc_rtar_w: RTC Alarm Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_rtc_regs.rtar);
+}
+
+u32 pxa255_periphs_device::rtc_rtsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rtc_regs.rtsr;
+ LOGMASKED(LOG_RTC, "%s: rtc_rtsr_r: RTC Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::rtc_rtsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: rtc_rtsr_w: RTC Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_rtc_regs.rtsr;
+ m_rtc_regs.rtsr &= ~(data & 0x00000003);
+ m_rtc_regs.rtsr &= ~0x0000000c;
+ m_rtc_regs.rtsr |= data & 0x0000000c;
+ const u32 diff = old ^ m_rtc_regs.rtsr;
+ if (BIT(diff, 1))
+ set_irq_line(INT_RTC_HZ, 0);
+ if (BIT(diff, 0))
+ set_irq_line(INT_RTC_ALARM, 0);
+}
+
+u32 pxa255_periphs_device::rtc_rttr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rtc_regs.rttr;
+ LOGMASKED(LOG_RTC, "%s: rtc_rttr_r: RTC Trim Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::rtc_rttr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: rtc_rttr_w: RTC Trim Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ if (!BIT(m_rtc_regs.rttr, 31))
{
- case PXA255_RCNR:
- LOGMASKED(LOG_RTC, "pxa255 rtc_w: RTC Counter Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_rtc_regs.rcnr);
- break;
- case PXA255_RTAR:
- LOGMASKED(LOG_RTC, "pxa255 rtc_w: RTC Alarm Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_rtc_regs.rtar);
- break;
- case PXA255_RTSR:
- {
- LOGMASKED(LOG_RTC, "pxa255 rtc_w: RTC Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
- const uint32_t old = m_rtc_regs.rtsr;
- m_rtc_regs.rtsr &= ~(data & 0x00000003);
- m_rtc_regs.rtsr &= ~0x0000000c;
- m_rtc_regs.rtsr |= data & 0x0000000c;
- const uint32_t diff = old ^ m_rtc_regs.rtsr;
- if (BIT(diff, 1))
- set_irq_line(PXA255_INT_RTC_HZ, 0);
- if (BIT(diff, 0))
- set_irq_line(PXA255_INT_RTC_ALARM, 0);
- break;
- }
- case PXA255_RTTR:
- LOGMASKED(LOG_RTC, "pxa255 rtc_w: RTC Trim Register (not yet implemented): %08x & %08x\n", machine().describe_context(), data, mem_mask);
- if (!BIT(m_rtc_regs.rttr, 31))
- {
- COMBINE_DATA(&m_rtc_regs.rttr);
- }
- break;
- default:
- LOGMASKED(LOG_RTC | LOG_UNKNOWN, "pxa255 rtc_w: Unknown address: %08x = %08x & %08x\n", PXA255_RTC_BASE_ADDR | (offset << 2), data, mem_mask);
- break;
+ COMBINE_DATA(&m_rtc_regs.rttr);
}
}
+
/*
PXA255 OS Timer register
@@ -546,124 +753,118 @@ void pxa255_periphs_device::rtc_w(offs_t offset, uint32_t data, uint32_t mem_mas
void pxa255_periphs_device::ostimer_irq_check()
{
- set_irq_line(PXA255_INT_OSTIMER0, (m_ostimer_regs.oier & PXA255_OIER_E0) ? ((m_ostimer_regs.ossr & PXA255_OSSR_M0) ? 1 : 0) : 0);
- //set_irq_line(PXA255_INT_OSTIMER1, (m_ostimer_regs.oier & PXA255_OIER_E1) ? ((m_ostimer_regs.ossr & PXA255_OSSR_M1) ? 1 : 0) : 0);
- //set_irq_line(PXA255_INT_OSTIMER2, (m_ostimer_regs.oier & PXA255_OIER_E2) ? ((m_ostimer_regs.ossr & PXA255_OSSR_M2) ? 1 : 0) : 0);
- //set_irq_line(PXA255_INT_OSTIMER3, (m_ostimer_regs.oier & PXA255_OIER_E3) ? ((m_ostimer_regs.ossr & PXA255_OSSR_M3) ? 1 : 0) : 0);
+ set_irq_line(INT_OSTIMER0, (m_ostimer_regs.oier & OIER_E0) ? ((m_ostimer_regs.ossr & OSSR_M0) ? 1 : 0) : 0);
+ //set_irq_line(INT_OSTIMER1, (m_ostimer_regs.oier & OIER_E1) ? ((m_ostimer_regs.ossr & OSSR_M1) ? 1 : 0) : 0);
+ //set_irq_line(INT_OSTIMER2, (m_ostimer_regs.oier & OIER_E2) ? ((m_ostimer_regs.ossr & OSSR_M2) ? 1 : 0) : 0);
+ //set_irq_line(INT_OSTIMER3, (m_ostimer_regs.oier & OIER_E3) ? ((m_ostimer_regs.ossr & OSSR_M3) ? 1 : 0) : 0);
}
-void pxa255_periphs_device::ostimer_match_tick(int channel)
+TIMER_CALLBACK_MEMBER(pxa255_periphs_device::ostimer_match_tick)
{
- m_ostimer_regs.ossr |= (1 << channel);
- m_ostimer_regs.oscr = m_ostimer_regs.osmr[channel];
+ m_ostimer_regs.ossr |= (1 << param);
+ m_ostimer_regs.oscr = m_ostimer_regs.osmr[param];
ostimer_irq_check();
}
-uint32_t pxa255_periphs_device::ostimer_r(offs_t offset, uint32_t mem_mask)
+template <int Which>
+void pxa255_periphs_device::ostimer_update_interrupts()
{
- switch(PXA255_OSTMR_BASE_ADDR | (offset << 2))
+ if ((m_ostimer_regs.oier & (OIER_E0 << Which)) && Which != 3)
{
- case PXA255_OSMR0:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Match Register 0: %08x & %08x\n", m_ostimer_regs.osmr[0], mem_mask);
- return m_ostimer_regs.osmr[0];
- case PXA255_OSMR1:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Match Register 1: %08x & %08x\n", m_ostimer_regs.osmr[1], mem_mask);
- return m_ostimer_regs.osmr[1];
- case PXA255_OSMR2:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Match Register 2: %08x & %08x\n", m_ostimer_regs.osmr[2], mem_mask);
- return m_ostimer_regs.osmr[2];
- case PXA255_OSMR3:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Match Register 3: %08x & %08x\n", m_ostimer_regs.osmr[3], mem_mask);
- return m_ostimer_regs.osmr[3];
- case PXA255_OSCR:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Count Register: %08x & %08x\n", m_ostimer_regs.oscr, mem_mask);
- // free-running 3.something MHz counter. this is a complete hack.
- m_ostimer_regs.oscr += 0x300;
- return m_ostimer_regs.oscr;
- case PXA255_OSSR:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Status Register: %08x & %08x\n", m_ostimer_regs.ossr, mem_mask);
- return m_ostimer_regs.ossr;
- case PXA255_OWER:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Watchdog Match Enable Register: %08x & %08x\n", m_ostimer_regs.ower, mem_mask);
- return m_ostimer_regs.ower;
- case PXA255_OIER:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_r: OS Timer Interrupt Enable Register: %08x & %08x\n", m_ostimer_regs.oier, mem_mask);
- return m_ostimer_regs.oier;
- default:
- LOGMASKED(LOG_OSTIMER | LOG_UNKNOWN, "pxa255_ostimer_r: Unknown address: %08x\n", PXA255_OSTMR_BASE_ADDR | (offset << 2));
- break;
+ m_ostimer_regs.timer[Which]->adjust(attotime::from_hz(3846400) * (m_ostimer_regs.osmr[Which] - m_ostimer_regs.oscr), Which);
}
- return 0;
}
-void pxa255_periphs_device::ostimer_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void pxa255_periphs_device::ostimer_update_count()
{
- switch(PXA255_OSTMR_BASE_ADDR | (offset << 2))
- {
- case PXA255_OSMR0:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Match Register 0: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.osmr[0] = data;
- if (m_ostimer_regs.oier & PXA255_OIER_E0)
- {
- m_ostimer_regs.timer[0]->adjust(attotime::from_hz(3846400) * (m_ostimer_regs.osmr[0] - m_ostimer_regs.oscr));
- }
- break;
- case PXA255_OSMR1:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Match Register 1: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.osmr[1] = data;
- if (m_ostimer_regs.oier & PXA255_OIER_E1)
- {
- m_ostimer_regs.timer[1]->adjust(attotime::from_hz(3846400) * (m_ostimer_regs.osmr[1] - m_ostimer_regs.oscr), 1);
- }
- break;
- case PXA255_OSMR2:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Match Register 2: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.osmr[2] = data;
- if (m_ostimer_regs.oier & PXA255_OIER_E2)
- {
- m_ostimer_regs.timer[2]->adjust(attotime::from_hz(3846400) * (m_ostimer_regs.osmr[2] - m_ostimer_regs.oscr), 2);
- }
- break;
- case PXA255_OSMR3:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Match Register 3: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.osmr[3] = data;
- if (m_ostimer_regs.oier & PXA255_OIER_E3)
- {
- //m_ostimer_regs.timer[3]->adjust(attotime::from_hz(3846400) * (m_ostimer_regs.osmr[3] - m_ostimer_regs.oscr), 3);
- }
- break;
- case PXA255_OSCR:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Count Register: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.oscr = data;
- break;
- case PXA255_OSSR:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Status Register: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.ossr &= ~data;
- ostimer_irq_check();
- break;
- case PXA255_OWER:
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Watchdog Enable Register: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.ower = data & 0x00000001;
- break;
- case PXA255_OIER:
- {
- LOGMASKED(LOG_OSTIMER, "pxa255_ostimer_w: OS Timer Interrupt Enable Register: %08x & %08x\n", data, mem_mask);
- m_ostimer_regs.oier = data & 0x0000000f;
- for (int index = 0; index < 4; index++)
- {
- if (m_ostimer_regs.oier & (1 << index))
- {
- //m_ostimer_regs.timer[index]->adjust(attotime::from_hz(200000000) * m_ostimer_regs.osmr[index], index);
- }
- }
- break;
- }
- default:
- LOGMASKED(LOG_OSTIMER | LOG_UNKNOWN, "pxa255_ostimer_w: Unknown address: %08x = %08x & %08x\n", PXA255_OSTMR_BASE_ADDR | (offset << 2), data, mem_mask);
- break;
- }
+ const attotime time_delta = machine().time() - m_ostimer_regs.last_count_sync;
+ const uint64_t ticks_elapsed = time_delta.as_ticks(INTERNAL_OSC);
+ if (ticks_elapsed == 0ULL) // Accrue time until we can tick at least once
+ return;
+
+ const uint32_t wrapped_ticks = (uint32_t)ticks_elapsed;
+ m_ostimer_regs.oscr += wrapped_ticks;
+ m_ostimer_regs.last_count_sync = machine().time();
+ ostimer_update_interrupts<0>();
+ ostimer_update_interrupts<1>();
+ ostimer_update_interrupts<2>();
+ ostimer_update_interrupts<3>();
+}
+
+template <int Which>
+u32 pxa255_periphs_device::tmr_osmr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostimer_regs.osmr[Which];
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_osmr_r: OS Timer Match Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::tmr_osmr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: pxa255_ostimer_w: OS Timer Match Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ ostimer_update_count();
+ m_ostimer_regs.osmr[Which] = data;
+ ostimer_update_count();
+ ostimer_update_interrupts<Which>();
+}
+
+u32 pxa255_periphs_device::tmr_oscr_r(offs_t offset, u32 mem_mask)
+{
+ ostimer_update_count();
+ const u32 data = m_ostimer_regs.oscr;
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_oscr_r: OS Timer Count Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return m_ostimer_regs.oscr;
+}
+
+void pxa255_periphs_device::tmr_oscr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_oscr_w: OS Timer Count Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_ostimer_regs.oscr = data;
+ m_ostimer_regs.last_count_sync = machine().time();
+}
+
+u32 pxa255_periphs_device::tmr_ossr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostimer_regs.ossr;
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ossr_r: OS Timer Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::tmr_ossr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ossr_w: OS Timer Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_ostimer_regs.ossr &= ~data;
+ ostimer_irq_check();
+}
+
+u32 pxa255_periphs_device::tmr_ower_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostimer_regs.ower;
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ower_r: OS Timer Watchdog Match Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::tmr_ower_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ower_w: OS Timer Watchdog Match Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_ostimer_regs.ower = data & 0x00000001;
}
+u32 pxa255_periphs_device::tmr_oier_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostimer_regs.oier;
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_oier_r: OS Timer Interrupt Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::tmr_oier_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_oier_w: OS Timer Interrupt Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_ostimer_regs.oier = data & 0x0000000f;
+}
+
+
/*
PXA255 Interrupt registers
@@ -680,73 +881,89 @@ void pxa255_periphs_device::update_interrupts()
m_maincpu->set_input_line(ARM7_IRQ_LINE, m_intc_regs.icip ? ASSERT_LINE : CLEAR_LINE);
}
-void pxa255_periphs_device::set_irq_line(uint32_t line, int irq_state)
+void pxa255_periphs_device::set_irq_line(u32 line, int irq_state)
{
m_intc_regs.icpr &= ~line;
m_intc_regs.icpr |= irq_state ? line : 0;
update_interrupts();
}
-uint32_t pxa255_periphs_device::intc_r(offs_t offset, uint32_t mem_mask)
+u32 pxa255_periphs_device::intc_icip_r(offs_t offset, u32 mem_mask)
{
- switch (PXA255_INTC_BASE_ADDR | (offset << 2))
- {
- case PXA255_ICIP:
- LOGMASKED(LOG_INTC, "pxa255_intc_r: Interrupt Controller IRQ Pending Register: %08x & %08x\n", m_intc_regs.icip, mem_mask);
- return m_intc_regs.icip;
- case PXA255_ICMR:
- LOGMASKED(LOG_INTC, "pxa255_intc_r: Interrupt Controller Mask Register: %08x & %08x\n", m_intc_regs.icmr, mem_mask);
- return m_intc_regs.icmr;
- case PXA255_ICLR:
- LOGMASKED(LOG_INTC, "pxa255_intc_r: Interrupt Controller Level Register: %08x & %08x\n", m_intc_regs.iclr, mem_mask);
- return m_intc_regs.iclr;
- case PXA255_ICFP:
- LOGMASKED(LOG_INTC, "pxa255_intc_r: Interrupt Controller FIQ Pending Register: %08x & %08x\n", m_intc_regs.icfp, mem_mask);
- return m_intc_regs.icfp;
- case PXA255_ICPR:
- LOGMASKED(LOG_INTC, "pxa255_intc_r: Interrupt Controller Pending Register: %08x & %08x\n", m_intc_regs.icpr, mem_mask);
- return m_intc_regs.icpr;
- case PXA255_ICCR:
- LOGMASKED(LOG_INTC, "pxa255_intc_r: Interrupt Controller Control Register: %08x & %08x\n", m_intc_regs.iccr, mem_mask);
- return m_intc_regs.iccr;
- default:
- LOGMASKED(LOG_INTC | LOG_UNKNOWN, "pxa255_intc_r: Unknown address: %08x\n", PXA255_INTC_BASE_ADDR | (offset << 2));
- break;
- }
- return 0;
+ const u32 data = m_intc_regs.icip;
+ LOGMASKED(LOG_INTC, "%s: intc_icip_r: Interrupt Controller IRQ Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
-void pxa255_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void pxa255_periphs_device::intc_icip_w(offs_t offset, u32 data, u32 mem_mask)
{
- switch (PXA255_INTC_BASE_ADDR | (offset << 2))
- {
- case PXA255_ICIP:
- LOGMASKED(LOG_INTC, "pxa255_intc_w: (Invalid Write) Interrupt Controller IRQ Pending Register: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_ICMR:
- LOGMASKED(LOG_INTC, "pxa255_intc_w: Interrupt Controller Mask Register: %08x & %08x\n", data, mem_mask);
- m_intc_regs.icmr = data & 0xfffe7f00;
- break;
- case PXA255_ICLR:
- LOGMASKED(LOG_INTC, "pxa255_intc_w: Interrupt Controller Level Register: %08x & %08x\n", data, mem_mask);
- m_intc_regs.iclr = data & 0xfffe7f00;
- break;
- case PXA255_ICFP:
- LOGMASKED(LOG_INTC, "pxa255_intc_w: (Invalid Write) Interrupt Controller FIQ Pending Register: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_ICPR:
- LOGMASKED(LOG_INTC, "pxa255_intc_w: (Invalid Write) Interrupt Controller Pending Register: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_ICCR:
- LOGMASKED(LOG_INTC, "pxa255_intc_w: Interrupt Controller Control Register: %08x & %08x\n", data, mem_mask);
- m_intc_regs.iccr = data & 0x00000001;
- break;
- default:
- LOGMASKED(LOG_INTC | LOG_UNKNOWN, "pxa255_intc_w: Unknown address: %08x = %08x & %08x\n", PXA255_INTC_BASE_ADDR | (offset << 2), data, mem_mask);
- break;
- }
+ LOGMASKED(LOG_INTC, "%s: intc_icip_w: (Invalid Write) Interrupt Controller IRQ Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
}
+u32 pxa255_periphs_device::intc_icmr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.icmr;
+ LOGMASKED(LOG_INTC, "%s: intc_icmr_r: Interrupt Controller Mask Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::intc_icmr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_icmr_w: Interrupt Controller Mask Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_intc_regs.icmr = data & 0xfffe7f00;
+}
+
+u32 pxa255_periphs_device::intc_iclr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.iclr;
+ LOGMASKED(LOG_INTC, "%s: intc_iclr_r: Interrupt Controller Level Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::intc_iclr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_iclr_w: Interrupt Controller Level Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_intc_regs.iclr = data & 0xfffe7f00;
+}
+
+u32 pxa255_periphs_device::intc_icfp_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.icfp;
+ LOGMASKED(LOG_INTC, "%s: intc_icfp_r: Interrupt Controller FIQ Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::intc_icfp_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_icfp_w: (Invalid Write) Interrupt Controller FIQ Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 pxa255_periphs_device::intc_icpr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.icpr;
+ LOGMASKED(LOG_INTC, "%s: intc_icpr_r: Interrupt Controller Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::intc_icpr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_icpr_w: (Invalid Write) Interrupt Controller Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 pxa255_periphs_device::intc_iccr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.iccr;
+ LOGMASKED(LOG_INTC, "%s: intc_iccr_r: Interrupt Controller control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::intc_iccr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_iccr_w: Interrupt Controller Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_intc_regs.iccr = data & 0x00000001;
+}
+
+
/*
PXA255 General-Purpose I/O registers
@@ -755,321 +972,358 @@ void pxa255_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_ma
*/
-void pxa255_periphs_device::gpio_bit_w(offs_t offset, uint8_t data, uint8_t mem_mask)
+template <int Which>
+void pxa255_periphs_device::update_gpio_outputs(const u32 old)
{
- const uint32_t val = (data != 0 ? 1 : 0);
- LOGMASKED(LOG_GPIO, "pxa255: GPIO%d written: %d\n", offset, val);
- if (offset < 32)
+ const u32 new_data = (m_gpio_regs.in_data[Which] & ~m_gpio_regs.gpdr[Which]) | (m_gpio_regs.out_data[Which] & m_gpio_regs.gpdr[Which]);
+ const u32 changed = old ^ new_data;
+ if (changed == 0)
+ return;
+
+ for (u32 bit = 0; bit < 32; bit++)
{
- const uint32_t old = m_gpio_regs.gplr0;
- m_gpio_regs.gplr0 &= ~(1 << offset);
- m_gpio_regs.gplr0 |= (val << offset);
+ if (!BIT(changed, bit))
+ continue;
+ LOGMASKED(LOG_GPIO, "Setting GPIO bit %d: %d\n", Which * 32 + bit, BIT(new_data, bit));
+ m_gpio_w[Which * 32 + bit](BIT(new_data, bit));
+ }
+}
+
+template <int Which>
+void pxa255_periphs_device::check_gpio_irqs(const u32 old)
+{
+ const u32 new_data = (m_gpio_regs.in_data[Which] & ~m_gpio_regs.gpdr[Which]) | (m_gpio_regs.out_data[Which] & m_gpio_regs.gpdr[Which]);
+ if (old == new_data)
+ return;
+
+ const u32 rising = ~old & new_data;
+ const u32 falling = old & ~new_data;
- LOGMASKED(LOG_GPIO, "pxa255: Old GPLR0 %08x, New GPLR0 %08x\n", old, m_gpio_regs.gplr0);
+ LOGMASKED(LOG_GPIO, "pxa255: Rising %08x, Falling %08x\n", rising, falling);
- const uint32_t rising = ~old & m_gpio_regs.gplr0;
- const uint32_t falling = old & ~m_gpio_regs.gplr0;
+ const u32 old_gedr = m_gpio_regs.gedr[Which];
+ m_gpio_regs.gedr[Which] |= rising & m_gpio_regs.grer[Which];
+ m_gpio_regs.gedr[Which] |= falling & m_gpio_regs.gfer[Which];
- LOGMASKED(LOG_GPIO, "pxa255: Rising %08x, Falling %08x\n", rising, falling);
+ LOGMASKED(LOG_GPIO, "pxa255: Old GEDR%d %08x, New GEDR%d %08x\n", Which, old_gedr, Which, m_gpio_regs.gedr[Which]);
+ const u32 changed_gedr = old_gedr ^ m_gpio_regs.gedr[Which];
+ if (changed_gedr == 0)
+ return;
- const uint32_t old_gedr = m_gpio_regs.gedr0;
- m_gpio_regs.gedr0 |= (rising & m_gpio_regs.grer0);
- m_gpio_regs.gedr0 |= (falling & m_gpio_regs.gfer0);
+ for (u32 bit = 0; bit < 32; bit++)
+ {
+ if (!BIT(changed_gedr, bit))
+ continue;
- LOGMASKED(LOG_GPIO, "pxa255: Old GEDR0 %08x, New GEDR0 %08x\n", old_gedr, m_gpio_regs.gedr0);
- if (old_gedr != m_gpio_regs.gedr0)
+ LOGMASKED(LOG_GPIO, "pxa255: Edge detected on GPIO%d Pin %d\n", Which, bit);
+ if (Which == 0)
{
- LOGMASKED(LOG_GPIO, "pxa255: Edge detected on GPIO%d\n", offset);
- if (offset > 1)
- set_irq_line(PXA255_INT_GPIO84_2, 1);
- else if (offset == 1)
- set_irq_line(PXA255_INT_GPIO1, 1);
+ if (bit > 1)
+ set_irq_line(INT_GPIO84_2, 1);
+ else if (bit == 1)
+ set_irq_line(INT_GPIO1, 1);
else
- set_irq_line(PXA255_INT_GPIO0, 1);
+ set_irq_line(INT_GPIO0, 1);
}
- }
- else if (offset < 64)
- {
- const uint32_t old = m_gpio_regs.gplr1;
- m_gpio_regs.gplr1 &= ~(1 << (offset - 32));
- m_gpio_regs.gplr1 |= ~(val << (offset - 32));
-
- const uint32_t rising = ~old & m_gpio_regs.gplr1;
- const uint32_t falling = old & ~m_gpio_regs.gplr1;
-
- const uint32_t old_gedr = m_gpio_regs.gedr1;
- m_gpio_regs.gedr1 |= (rising & m_gpio_regs.grer1);
- m_gpio_regs.gedr1 |= (falling & m_gpio_regs.gfer1);
- if (old_gedr != m_gpio_regs.gedr1)
+ else if (Which == 1)
+ {
+ set_irq_line(INT_GPIO84_2, 1);
+ }
+ else if (Which == 2)
{
- LOGMASKED(LOG_GPIO, "pxa255: Edge detected on GPIO%d\n", offset);
- set_irq_line(PXA255_INT_GPIO84_2, 1);
+ set_irq_line(INT_GPIO84_2, 1);
}
}
- else if (offset < 85)
- {
- const uint32_t old = m_gpio_regs.gplr2;
- m_gpio_regs.gplr2 &= ~(1 << (offset - 64));
- m_gpio_regs.gplr2 |= ~(val << (offset - 64));
+}
- const uint32_t rising = ~old & m_gpio_regs.gplr2;
- const uint32_t falling = old & ~m_gpio_regs.gplr2;
+template void pxa255_periphs_device::gpio_in<0>(int state);
+template void pxa255_periphs_device::gpio_in<1>(int state);
+template void pxa255_periphs_device::gpio_in<2>(int state);
+template void pxa255_periphs_device::gpio_in<3>(int state);
+template void pxa255_periphs_device::gpio_in<4>(int state);
+template void pxa255_periphs_device::gpio_in<5>(int state);
+template void pxa255_periphs_device::gpio_in<6>(int state);
+template void pxa255_periphs_device::gpio_in<7>(int state);
+template void pxa255_periphs_device::gpio_in<8>(int state);
+template void pxa255_periphs_device::gpio_in<9>(int state);
+template void pxa255_periphs_device::gpio_in<10>(int state);
+template void pxa255_periphs_device::gpio_in<11>(int state);
+template void pxa255_periphs_device::gpio_in<12>(int state);
+template void pxa255_periphs_device::gpio_in<13>(int state);
+template void pxa255_periphs_device::gpio_in<14>(int state);
+template void pxa255_periphs_device::gpio_in<15>(int state);
+template void pxa255_periphs_device::gpio_in<16>(int state);
+template void pxa255_periphs_device::gpio_in<17>(int state);
+template void pxa255_periphs_device::gpio_in<18>(int state);
+template void pxa255_periphs_device::gpio_in<19>(int state);
+template void pxa255_periphs_device::gpio_in<20>(int state);
+template void pxa255_periphs_device::gpio_in<21>(int state);
+template void pxa255_periphs_device::gpio_in<22>(int state);
+template void pxa255_periphs_device::gpio_in<23>(int state);
+template void pxa255_periphs_device::gpio_in<24>(int state);
+template void pxa255_periphs_device::gpio_in<25>(int state);
+template void pxa255_periphs_device::gpio_in<26>(int state);
+template void pxa255_periphs_device::gpio_in<27>(int state);
+template void pxa255_periphs_device::gpio_in<28>(int state);
+template void pxa255_periphs_device::gpio_in<29>(int state);
+template void pxa255_periphs_device::gpio_in<30>(int state);
+template void pxa255_periphs_device::gpio_in<31>(int state);
+template void pxa255_periphs_device::gpio_in<32>(int state);
+template void pxa255_periphs_device::gpio_in<33>(int state);
+template void pxa255_periphs_device::gpio_in<34>(int state);
+template void pxa255_periphs_device::gpio_in<35>(int state);
+template void pxa255_periphs_device::gpio_in<36>(int state);
+template void pxa255_periphs_device::gpio_in<37>(int state);
+template void pxa255_periphs_device::gpio_in<38>(int state);
+template void pxa255_periphs_device::gpio_in<39>(int state);
+template void pxa255_periphs_device::gpio_in<40>(int state);
+template void pxa255_periphs_device::gpio_in<41>(int state);
+template void pxa255_periphs_device::gpio_in<42>(int state);
+template void pxa255_periphs_device::gpio_in<43>(int state);
+template void pxa255_periphs_device::gpio_in<44>(int state);
+template void pxa255_periphs_device::gpio_in<45>(int state);
+template void pxa255_periphs_device::gpio_in<46>(int state);
+template void pxa255_periphs_device::gpio_in<47>(int state);
+template void pxa255_periphs_device::gpio_in<48>(int state);
+template void pxa255_periphs_device::gpio_in<49>(int state);
+template void pxa255_periphs_device::gpio_in<50>(int state);
+template void pxa255_periphs_device::gpio_in<51>(int state);
+template void pxa255_periphs_device::gpio_in<52>(int state);
+template void pxa255_periphs_device::gpio_in<53>(int state);
+template void pxa255_periphs_device::gpio_in<54>(int state);
+template void pxa255_periphs_device::gpio_in<55>(int state);
+template void pxa255_periphs_device::gpio_in<56>(int state);
+template void pxa255_periphs_device::gpio_in<57>(int state);
+template void pxa255_periphs_device::gpio_in<58>(int state);
+template void pxa255_periphs_device::gpio_in<59>(int state);
+template void pxa255_periphs_device::gpio_in<60>(int state);
+template void pxa255_periphs_device::gpio_in<61>(int state);
+template void pxa255_periphs_device::gpio_in<62>(int state);
+template void pxa255_periphs_device::gpio_in<63>(int state);
+template void pxa255_periphs_device::gpio_in<64>(int state);
+template void pxa255_periphs_device::gpio_in<65>(int state);
+template void pxa255_periphs_device::gpio_in<66>(int state);
+template void pxa255_periphs_device::gpio_in<67>(int state);
+template void pxa255_periphs_device::gpio_in<68>(int state);
+template void pxa255_periphs_device::gpio_in<69>(int state);
+template void pxa255_periphs_device::gpio_in<70>(int state);
+template void pxa255_periphs_device::gpio_in<71>(int state);
+template void pxa255_periphs_device::gpio_in<72>(int state);
+template void pxa255_periphs_device::gpio_in<73>(int state);
+template void pxa255_periphs_device::gpio_in<74>(int state);
+template void pxa255_periphs_device::gpio_in<75>(int state);
+template void pxa255_periphs_device::gpio_in<76>(int state);
+template void pxa255_periphs_device::gpio_in<77>(int state);
+template void pxa255_periphs_device::gpio_in<78>(int state);
+template void pxa255_periphs_device::gpio_in<79>(int state);
+template void pxa255_periphs_device::gpio_in<80>(int state);
+template void pxa255_periphs_device::gpio_in<81>(int state);
+template void pxa255_periphs_device::gpio_in<82>(int state);
+template void pxa255_periphs_device::gpio_in<83>(int state);
+template void pxa255_periphs_device::gpio_in<84>(int state);
+template void pxa255_periphs_device::gpio_in<85>(int state);
+template void pxa255_periphs_device::gpio_in<86>(int state);
+template void pxa255_periphs_device::gpio_in<87>(int state);
+template void pxa255_periphs_device::gpio_in<88>(int state);
+template void pxa255_periphs_device::gpio_in<89>(int state);
+template void pxa255_periphs_device::gpio_in<90>(int state);
+template void pxa255_periphs_device::gpio_in<91>(int state);
+template void pxa255_periphs_device::gpio_in<92>(int state);
+template void pxa255_periphs_device::gpio_in<93>(int state);
+template void pxa255_periphs_device::gpio_in<94>(int state);
+template void pxa255_periphs_device::gpio_in<95>(int state);
+
+template <int Bit>
+void pxa255_periphs_device::gpio_in(int state)
+{
+ LOGMASKED(LOG_GPIO, "pxa255: GPIO Pin %d written: %d\n", Bit, state);
- const uint32_t old_gedr = m_gpio_regs.gedr2;
- m_gpio_regs.gedr2 |= (rising & m_gpio_regs.grer2);
- m_gpio_regs.gedr2 |= (falling & m_gpio_regs.gfer2);
- if (old_gedr != m_gpio_regs.gedr2)
- {
- LOGMASKED(LOG_GPIO, "pxa255: Edge detected on GPIO%d\n", offset);
- set_irq_line(PXA255_INT_GPIO84_2, 1);
- }
+ const u32 which = Bit >> 5;
+ const u32 old = m_gpio_regs.in_data[which] & ~m_gpio_regs.gpdr[which];
+ if (state)
+ m_gpio_regs.in_data[which] |= (1 << (Bit & 31));
+ else
+ m_gpio_regs.in_data[which] &= ~(1 << (Bit & 31));
+
+ const u32 new_inputs = m_gpio_regs.in_data[which] & ~m_gpio_regs.gpdr[which];
+ LOGMASKED(LOG_GPIO, "pxa255: Old GPIO Pin %d Input %08x, New GPIO Pin %d Input %08x\n", Bit, old, Bit, new_inputs);
+
+ if (Bit < 32)
+ check_gpio_irqs<0>(old);
+ else if (Bit < 64)
+ check_gpio_irqs<1>(old);
+ else
+ check_gpio_irqs<2>(old);
+}
+
+template <int Which>
+u32 pxa255_periphs_device::gpio_gplr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = (m_gpio_regs.in_data[Which] & ~m_gpio_regs.gpdr[Which]) | (m_gpio_regs.out_data[Which] & m_gpio_regs.gpdr[Which]);
+ LOGMASKED(LOG_GPIO, "%s: gpio_gplr_r: GPIO Pin-Level Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_gplr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gplr_w: (Invalid Write) GPIO Pin-Level Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+}
+
+template <int Which>
+u32 pxa255_periphs_device::gpio_gpdr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gpdr[Which];
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpdr_r: GPIO Pin Direction Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_gpdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpdr_w: GPIO Pin Direction Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_gpio_regs.gpdr[Which] = data;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::gpio_gpsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = 0;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpsr_r: (Invalid Read) GPIO Pin Output Set Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_gpsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpsr_w: GPIO Pin Output Set Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_gpio_regs.out_data[Which] |= data & mem_mask;
+ const u32 set = data & mem_mask & m_gpio_regs.gpdr[Which];
+ for (u32 i = 0; i < 32; i++)
+ {
+ if (BIT(set, i))
+ m_gpio_w[Which * 32 + i](1);
}
}
-uint32_t pxa255_periphs_device::gpio_r(offs_t offset, uint32_t mem_mask)
+template <int Which>
+u32 pxa255_periphs_device::gpio_gpcr_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_GPIO_BASE_ADDR | (offset << 2))
+ const u32 data = 0;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpcr_r: (Invalid Read) GPIO Pin Output Clear Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_gpcr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpcr_w: GPIO Pin Output Clear Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_gpio_regs.out_data[Which] &= ~(data & mem_mask);
+ const u32 cleared = data & mem_mask & m_gpio_regs.gpdr[Which];
+ for (u32 i = 0; i < 32; i++)
{
- case PXA255_GPLR0:
- {
- const uint32_t value = (m_gpio_regs.gplr0 & m_gpio_regs.gpdr0) | m_gpio0_r(0, ~m_gpio_regs.gpdr0);
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Pin-Level Register 0: %08x & %08x\n", m_gpio_regs.gplr0, mem_mask);
- return value;
- }
- case PXA255_GPLR1:
- {
- const uint32_t value = (m_gpio_regs.gplr1 & m_gpio_regs.gpdr1) | m_gpio1_r(0, ~m_gpio_regs.gpdr1);
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Pin-Level Register 1: %08x & %08x\n", m_gpio_regs.gplr1, mem_mask);
- return value;
- }
- case PXA255_GPLR2:
- {
- const uint32_t value = (m_gpio_regs.gplr2 & m_gpio_regs.gpdr2) | m_gpio2_r(0, ~m_gpio_regs.gpdr2);
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Pin-Level Register 2: %08x & %08x\n", m_gpio_regs.gplr2, mem_mask);
- return value;
- }
- case PXA255_GPDR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Pin Direction Register 0: %08x & %08x\n", m_gpio_regs.gpdr0, mem_mask);
- return m_gpio_regs.gpdr0;
- case PXA255_GPDR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Pin Direction Register 1: %08x & %08x\n", m_gpio_regs.gpdr1, mem_mask);
- return m_gpio_regs.gpdr1;
- case PXA255_GPDR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Pin Direction Register 2: %08x & %08x\n", m_gpio_regs.gpdr2, mem_mask);
- return m_gpio_regs.gpdr2;
- case PXA255_GPSR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: (Invalid Read) GPIO Pin Output Set Register 0: %08x & %08x\n", machine().rand(), mem_mask);
- return machine().rand();
- case PXA255_GPSR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: (Invalid Read) GPIO Pin Output Set Register 1: %08x & %08x\n", machine().rand(), mem_mask);
- return machine().rand();
- case PXA255_GPSR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: (Invalid Read) GPIO Pin Output Set Register 2: %08x & %08x\n", machine().rand(), mem_mask);
- return machine().rand();
- case PXA255_GPCR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: (Invalid Read) GPIO Pin Output Clear Register 0: %08x & %08x\n", machine().rand(), mem_mask);
- return machine().rand();
- case PXA255_GPCR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: (Invalid Read) GPIO Pin Output Clear Register 1: %08x & %08x\n", machine().rand(), mem_mask);
- return machine().rand();
- case PXA255_GPCR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: (Invalid Read) GPIO Pin Output Clear Register 2: %08x & %08x\n", machine().rand(), mem_mask);
- return machine().rand();
- case PXA255_GRER0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Rising Edge Detect Enable Register 0: %08x & %08x\n", m_gpio_regs.grer0, mem_mask);
- return m_gpio_regs.grer0;
- case PXA255_GRER1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Rising Edge Detect Enable Register 1: %08x & %08x\n", m_gpio_regs.grer1, mem_mask);
- return m_gpio_regs.grer1;
- case PXA255_GRER2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Rising Edge Detect Enable Register 2: %08x & %08x\n", m_gpio_regs.grer2, mem_mask);
- return m_gpio_regs.grer2;
- case PXA255_GFER0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Falling Edge Detect Enable Register 0: %08x & %08x\n", m_gpio_regs.gfer0, mem_mask);
- return m_gpio_regs.gfer0;
- case PXA255_GFER1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Falling Edge Detect Enable Register 1: %08x & %08x\n", m_gpio_regs.gfer1, mem_mask);
- return m_gpio_regs.gfer1;
- case PXA255_GFER2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Falling Edge Detect Enable Register 2: %08x & %08x\n", m_gpio_regs.gfer2, mem_mask);
- return m_gpio_regs.gfer2;
- case PXA255_GEDR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Edge Detect Status Register 0: %08x & %08x\n", m_gpio_regs.gedr0, mem_mask);
- return m_gpio_regs.gedr0;
- case PXA255_GEDR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Edge Detect Status Register 1: %08x & %08x\n", m_gpio_regs.gedr1, mem_mask);
- return m_gpio_regs.gedr1;
- case PXA255_GEDR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Edge Detect Status Register 2: %08x & %08x\n", m_gpio_regs.gedr2, mem_mask);
- return m_gpio_regs.gedr2;
- case PXA255_GAFR0_L:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Alternate Function Register 0 Lower: %08x & %08x\n", m_gpio_regs.gafr0l, mem_mask);
- return m_gpio_regs.gafr0l;
- case PXA255_GAFR0_U:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Alternate Function Register 0 Upper: %08x & %08x\n", m_gpio_regs.gafr0u, mem_mask);
- return m_gpio_regs.gafr0u;
- case PXA255_GAFR1_L:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Alternate Function Register 1 Lower: %08x & %08x\n", m_gpio_regs.gafr1l, mem_mask);
- return m_gpio_regs.gafr1l;
- case PXA255_GAFR1_U:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Alternate Function Register 1 Upper: %08x & %08x\n", m_gpio_regs.gafr1u, mem_mask);
- return m_gpio_regs.gafr1u;
- case PXA255_GAFR2_L:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Alternate Function Register 2 Lower: %08x & %08x\n", m_gpio_regs.gafr2l, mem_mask);
- return m_gpio_regs.gafr2l;
- case PXA255_GAFR2_U:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_r: GPIO Alternate Function Register 2 Upper: %08x & %08x\n", m_gpio_regs.gafr2u, mem_mask);
- return m_gpio_regs.gafr2u;
- default:
- LOGMASKED(LOG_GPIO | LOG_UNKNOWN, "pxa255_gpio_r: Unknown address: %08x\n", PXA255_GPIO_BASE_ADDR | (offset << 2));
- break;
+ if (BIT(cleared, i))
+ m_gpio_w[Which * 32 + i](0);
}
- return 0;
}
-void pxa255_periphs_device::gpio_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+template <int Which>
+u32 pxa255_periphs_device::gpio_grer_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.grer[Which];
+ LOGMASKED(LOG_GPIO, "%s: gpio_grer_r: GPIO Rising Edge Detect Enable Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_grer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_grer_w: GPIO Rising Edge Detect Enable Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_gpio_regs.grer[Which] = data;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::gpio_gfer_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gfer[Which];
+ LOGMASKED(LOG_GPIO, "%s: gpio_grer_r: GPIO Falling Edge Detect Enable Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_gfer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gfer_w: GPIO Falling Edge Detect Enable Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_gpio_regs.gfer[Which] = data;
+}
+template <int Which>
+u32 pxa255_periphs_device::gpio_gedr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gedr[Which];
+ LOGMASKED(LOG_GPIO, "%s: gpio_gedr_r: GPIO Edge Detect Status Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_gedr_w(offs_t offset, u32 data, u32 mem_mask)
{
- switch(PXA255_GPIO_BASE_ADDR | (offset << 2))
+ LOGMASKED(LOG_GPIO, "%s: gpio_gedr_w: GPIO Edge Detect Status Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ const u32 old = m_gpio_regs.gedr[Which];
+ m_gpio_regs.gedr[Which] &= ~data;
+ const u32 lowered = old & ~m_gpio_regs.gedr[Which];
+ if (Which == 0)
{
- case PXA255_GPLR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: (Invalid Write) GPIO Pin-Level Register 0: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_GPLR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: (Invalid Write) GPIO Pin-Level Register 1: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_GPLR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: (Invalid Write) GPIO Pin-Level Register 2: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_GPDR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Direction Register 0: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpdr0 = data;
- break;
- case PXA255_GPDR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Direction Register 1: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpdr1 = data;
- break;
- case PXA255_GPDR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Direction Register 2: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpdr2 = data;
- break;
- case PXA255_GPSR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Output Set Register 0: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpsr0 |= data & m_gpio_regs.gpdr0;
- m_gpio0_w(0, data, m_gpio_regs.gpdr0);
- break;
- case PXA255_GPSR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Output Set Register 1: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpsr1 |= data & m_gpio_regs.gpdr1;
- m_gpio1_w(0, data, m_gpio_regs.gpdr1);
- break;
- case PXA255_GPSR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Output Set Register 2: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpsr2 |= data & m_gpio_regs.gpdr2;
- m_gpio2_w(0, data, m_gpio_regs.gpdr2);
- break;
- case PXA255_GPCR0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Output Clear Register 0: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpsr0 &= ~(data & m_gpio_regs.gpdr0);
- m_gpio0_w(0, data, m_gpio_regs.gpdr0);
- break;
- case PXA255_GPCR1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Output Clear Register 1: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpsr1 &= ~(data & m_gpio_regs.gpdr1);
- m_gpio1_w(0, data, m_gpio_regs.gpdr1);
- break;
- case PXA255_GPCR2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Pin Output Clear Register 2: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gpsr2 &= ~(data & m_gpio_regs.gpdr2);
- m_gpio2_w(0, data, m_gpio_regs.gpdr2);
- break;
- case PXA255_GRER0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Rising Edge Detect Enable Register 0: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.grer0 = data;
- break;
- case PXA255_GRER1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Rising Edge Detect Enable Register 1: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.grer1 = data;
- break;
- case PXA255_GRER2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Rising Edge Detect Enable Register 2: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.grer2 = data;
- break;
- case PXA255_GFER0:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Falling Edge Detect Enable Register 0: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gfer0 = data;
- break;
- case PXA255_GFER1:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Falling Edge Detect Enable Register 1: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gfer1 = data;
- break;
- case PXA255_GFER2:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Falling Edge Detect Enable Register 2: %08x & %08x\n", data, mem_mask);
- m_gpio_regs.gfer2 = data;
- break;
- case PXA255_GEDR0:
+ if (BIT(lowered, 0))
{
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Edge Detect Status Register 0: %08x & %08x\n", m_gpio_regs.gedr0, mem_mask);
- const uint32_t old = m_gpio_regs.gedr0;
- m_gpio_regs.gedr0 &= ~data;
- const uint32_t lowered = old & ~m_gpio_regs.gedr0;
- if (BIT(lowered, 0))
- set_irq_line(PXA255_INT_GPIO0, 0);
- else if (BIT(lowered, 1))
- set_irq_line(PXA255_INT_GPIO1, 0);
- else if ((lowered & 0xfffffffc) && !m_gpio_regs.gedr0 && !m_gpio_regs.gedr1 && !m_gpio_regs.gedr2)
- set_irq_line(PXA255_INT_GPIO84_2, 0);
- break;
+ set_irq_line(INT_GPIO0, 0);
+ return;
}
- case PXA255_GEDR1:
+ else if (BIT(lowered, 1))
{
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Edge Detect Status Register 1: %08x & %08x\n", m_gpio_regs.gedr1, mem_mask);
- const uint32_t old = m_gpio_regs.gedr1;
- m_gpio_regs.gedr1 &= ~data;
- const uint32_t lowered = old & !m_gpio_regs.gedr1;
- if (lowered && !m_gpio_regs.gedr0 && !m_gpio_regs.gedr1 && !m_gpio_regs.gedr2)
- set_irq_line(PXA255_INT_GPIO84_2, 0);
- break;
+ set_irq_line(INT_GPIO1, 0);
+ return;
}
- case PXA255_GEDR2:
+ else if (!(lowered & 0xfffffffc))
{
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Edge Detect Status Register 2: %08x & %08x\n", m_gpio_regs.gedr2, mem_mask);
- const uint32_t old = m_gpio_regs.gedr2;
- m_gpio_regs.gedr2 &= ~data;
- const uint32_t lowered = old & !m_gpio_regs.gedr2;
- if (lowered && !m_gpio_regs.gedr0 && !m_gpio_regs.gedr1 && !m_gpio_regs.gedr2)
- set_irq_line(PXA255_INT_GPIO84_2, 0);
- break;
+ return;
}
- case PXA255_GAFR0_L:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Alternate Function Register 0 Lower: %08x & %08x\n", m_gpio_regs.gafr0l, mem_mask);
- m_gpio_regs.gafr0l = data;
- break;
- case PXA255_GAFR0_U:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Alternate Function Register 0 Upper: %08x & %08x\n", m_gpio_regs.gafr0u, mem_mask);
- m_gpio_regs.gafr0u = data;
- break;
- case PXA255_GAFR1_L:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Alternate Function Register 1 Lower: %08x & %08x\n", m_gpio_regs.gafr1l, mem_mask);
- m_gpio_regs.gafr1l = data;
- break;
- case PXA255_GAFR1_U:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Alternate Function Register 1 Upper: %08x & %08x\n", m_gpio_regs.gafr1u, mem_mask);
- m_gpio_regs.gafr1u = data;
- break;
- case PXA255_GAFR2_L:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Alternate Function Register 2 Lower: %08x & %08x\n", m_gpio_regs.gafr2l, mem_mask);
- m_gpio_regs.gafr2l = data;
- break;
- case PXA255_GAFR2_U:
- LOGMASKED(LOG_GPIO, "pxa255_gpio_w: GPIO Alternate Function Register 2 Upper: %08x & %08x\n", m_gpio_regs.gafr2u, mem_mask);
- m_gpio_regs.gafr2u = data;
- break;
- default:
- LOGMASKED(LOG_GPIO | LOG_UNKNOWN, "pxa255_gpio_w: Unknown address: %08x = %08x & %08x\n", PXA255_GPIO_BASE_ADDR | (offset << 2), data, mem_mask);
- break;
}
+
+ if (!m_gpio_regs.gedr[0] && !m_gpio_regs.gedr[1] && !m_gpio_regs.gedr[2])
+ set_irq_line(INT_GPIO84_2, 0);
+}
+
+template <int Which>
+u32 pxa255_periphs_device::gpio_gafrl_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gafrl[Which];
+ LOGMASKED(LOG_GPIO, "%s: gpio_gafrl_r: GPIO Alternate Function Register %d Lower: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
}
+template <int Which>
+void pxa255_periphs_device::gpio_gafrl_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gafrl_w: GPIO Alternate Function Register %d Lower = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_gpio_regs.gafrl[Which] = data;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::gpio_gafru_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gafru[Which];
+ LOGMASKED(LOG_GPIO, "%s: gpio_gafru_r: GPIO Alternate Function Register %d Upper: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::gpio_gafru_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gafru_w: GPIO Alternate Function Register %d Upper = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_gpio_regs.gafru[Which] = data;
+}
+
+
/*
PXA255 LCD Controller
@@ -1078,8 +1332,34 @@ void pxa255_periphs_device::gpio_w(offs_t offset, uint32_t data, uint32_t mem_ma
*/
-void pxa255_periphs_device::lcd_load_dma_descriptor(address_space & space, uint32_t address, int channel)
+u32 pxa255_periphs_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ for (int y = 0; y <= (m_lcd_regs.lccr[2] & LCCR2_LPP); y++)
+ {
+ u32 *dst = &bitmap.pix(y);
+ for (int x = 0; x <= (m_lcd_regs.lccr[1] & LCCR1_PPL); x++)
+ {
+ *dst++ = m_lcd_palette[m_lcd_framebuffer[y * ((m_lcd_regs.lccr[1] & LCCR1_PPL) + 1) + x]];
+ }
+ }
+ return 0;
+}
+
+TIMER_CALLBACK_MEMBER(pxa255_periphs_device::lcd_dma_eof_tick)
+{
+ LOGMASKED(LOG_LCD_DMA, "End of frame callback\n" );
+ if (m_lcd_regs.dma[param].ldcmd & LDCMD_EOFINT)
+ {
+ m_lcd_regs.liidr = m_lcd_regs.dma[param].fidr;
+ m_lcd_regs.lcsr |= LCSR_EOF;
+ }
+ lcd_check_load_next_branch(param);
+ lcd_irq_check();
+}
+
+void pxa255_periphs_device::lcd_load_dma_descriptor(u32 address, int channel)
{
+ address_space & space = m_maincpu->space(AS_PROGRAM);
m_lcd_regs.dma[channel].fdadr = space.read_dword(address);
m_lcd_regs.dma[channel].fsadr = space.read_dword(address + 0x04);
m_lcd_regs.dma[channel].fidr = space.read_dword(address + 0x08);
@@ -1093,41 +1373,41 @@ void pxa255_periphs_device::lcd_load_dma_descriptor(address_space & space, uint3
void pxa255_periphs_device::lcd_irq_check()
{
- if(((m_lcd_regs.lcsr & PXA255_LCSR_BS) != 0 && (m_lcd_regs.lccr0 & PXA255_LCCR0_BM) == 0) ||
- ((m_lcd_regs.lcsr & PXA255_LCSR_EOF) != 0 && (m_lcd_regs.lccr0 & PXA255_LCCR0_EFM) == 0) ||
- ((m_lcd_regs.lcsr & PXA255_LCSR_SOF) != 0 && (m_lcd_regs.lccr0 & PXA255_LCCR0_SFM) == 0))
+ if (((m_lcd_regs.lcsr & LCSR_BS) != 0 && (m_lcd_regs.lccr[0] & LCCR0_BM) == 0) ||
+ ((m_lcd_regs.lcsr & LCSR_EOF) != 0 && (m_lcd_regs.lccr[0] & LCCR0_EFM) == 0) ||
+ ((m_lcd_regs.lcsr & LCSR_SOF) != 0 && (m_lcd_regs.lccr[0] & LCCR0_SFM) == 0))
{
- set_irq_line(PXA255_INT_LCD, 1);
+ set_irq_line(INT_LCD, 1);
}
else
{
- set_irq_line(PXA255_INT_LCD, 0);
+ set_irq_line(INT_LCD, 0);
}
}
void pxa255_periphs_device::lcd_dma_kickoff(int channel)
{
- if(m_lcd_regs.dma[channel].fdadr != 0)
+ if (m_lcd_regs.dma[channel].fdadr != 0)
{
attotime period = attotime::from_hz(20000000) * (m_lcd_regs.dma[channel].ldcmd & 0x000fffff);
m_lcd_regs.dma[channel].eof->adjust(period, channel);
- if(m_lcd_regs.dma[channel].ldcmd & PXA255_LDCMD_SOFINT)
+ if (m_lcd_regs.dma[channel].ldcmd & LDCMD_SOFINT)
{
m_lcd_regs.liidr = m_lcd_regs.dma[channel].fidr;
- m_lcd_regs.lcsr |= PXA255_LCSR_SOF;
+ m_lcd_regs.lcsr |= LCSR_SOF;
lcd_irq_check();
}
- if(m_lcd_regs.dma[channel].ldcmd & PXA255_LDCMD_PAL)
+ if (m_lcd_regs.dma[channel].ldcmd & LDCMD_PAL)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
int length = m_lcd_regs.dma[channel].ldcmd & 0x000fffff;
int index = 0;
for(index = 0; index < length; index += 2)
{
- uint16_t color = space.read_word((m_lcd_regs.dma[channel].fsadr &~ 1) + index);
+ u16 color = space.read_word((m_lcd_regs.dma[channel].fsadr &~ 1) + index);
m_lcd_palette[index >> 1] = (((((color >> 11) & 0x1f) << 3) | (color >> 13)) << 16) | (((((color >> 5) & 0x3f) << 2) | ((color >> 9) & 0x3)) << 8) | (((color & 0x1f) << 3) | ((color >> 2) & 0x7));
m_palette->set_pen_color(index >> 1, (((color >> 11) & 0x1f) << 3) | (color >> 13), (((color >> 5) & 0x3f) << 2) | ((color >> 9) & 0x3), ((color & 0x1f) << 3) | ((color >> 2) & 0x7));
}
@@ -1147,465 +1427,379 @@ void pxa255_periphs_device::lcd_dma_kickoff(int channel)
void pxa255_periphs_device::lcd_check_load_next_branch(int channel)
{
- if(m_lcd_regs.fbr[channel] & 1)
+ if (m_lcd_regs.fbr[channel] & 1)
{
LOGMASKED(LOG_LCD_DMA, "lcd_check_load_next_branch: Taking branch\n" );
m_lcd_regs.fbr[channel] &= ~1;
address_space &space = m_maincpu->space(AS_PROGRAM);
- //m_lcd_regs.fbr[channel] = (space.read_dword(m_lcd_regs.fbr[channel] & 0xfffffff0) & 0xfffffff0) | (m_lcd_regs.fbr[channel] & 0x00000003);
- //printf( "%08x\n", m_lcd_regs.fbr[channel] );
- lcd_load_dma_descriptor(space, m_lcd_regs.fbr[channel] & 0xfffffff0, 0);
+ lcd_load_dma_descriptor(m_lcd_regs.fbr[channel] & 0xfffffff0, 0);
m_lcd_regs.fbr[channel] = (space.read_dword(m_lcd_regs.fbr[channel] & 0xfffffff0) & 0xfffffff0) | (m_lcd_regs.fbr[channel] & 0x00000003);
lcd_dma_kickoff(0);
- if(m_lcd_regs.fbr[channel] & 2)
+ if (m_lcd_regs.fbr[channel] & 2)
{
m_lcd_regs.fbr[channel] &= ~2;
- if(!(m_lcd_regs.lccr0 & PXA255_LCCR0_BM))
+ if (!(m_lcd_regs.lccr[0] & LCCR0_BM))
{
- m_lcd_regs.lcsr |= PXA255_LCSR_BS;
+ m_lcd_regs.lcsr |= LCSR_BS;
}
}
}
else
{
- LOGMASKED(LOG_LCD_DMA, "pxa255_lcd_check_load_next_branch: Not taking branch\n" );
+ LOGMASKED(LOG_LCD_DMA, "lcd_check_load_next_branch: Not taking branch\n" );
}
}
-void pxa255_periphs_device::lcd_dma_eof_tick(int channel)
+template <int Which>
+u32 pxa255_periphs_device::lcd_lccr_r(offs_t offset, u32 mem_mask)
{
- LOGMASKED(LOG_LCD_DMA, "End of frame callback\n" );
- if(m_lcd_regs.dma[channel].ldcmd & PXA255_LDCMD_EOFINT)
+ const u32 data = m_lcd_regs.lccr[Which];
+ LOGMASKED(LOG_LCD, "%s: lcd_lccr_r: LCD Control Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::lcd_lccr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_lccr_w: LCD Control Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ if (Which == 0)
+ m_lcd_regs.lccr[Which] = data & 0x00fffeff;
+ else
+ m_lcd_regs.lccr[Which] = data;
+}
+
+template <int Which>
+u32 pxa255_periphs_device::lcd_fbr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_lcd_regs.fbr[Which];
+ LOGMASKED(LOG_LCD, "%s: lcd_fbr_r: LCD Frame Branch Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::lcd_fbr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_lccr_w: LCD Frame Branch Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ m_lcd_regs.fbr[Which] = data & 0xfffffff3;
+ if (!m_lcd_regs.dma[Which].eof->enabled())
{
- m_lcd_regs.liidr = m_lcd_regs.dma[channel].fidr;
- m_lcd_regs.lcsr |= PXA255_LCSR_EOF;
+ LOGMASKED(LOG_LCD, "ch%d EOF timer is not enabled, taking branch now\n", Which);
+ lcd_check_load_next_branch(Which);
+ lcd_irq_check();
}
- lcd_check_load_next_branch(channel);
+}
+
+u32 pxa255_periphs_device::lcd_lcsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_lcd_regs.lcsr;
+ LOGMASKED(LOG_LCD, "%s: lcd_lcsr_r: LCD Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::lcd_lcsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_lcsr_w: LCD Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_lcd_regs.lcsr &= ~data;
lcd_irq_check();
}
-uint32_t pxa255_periphs_device::lcd_r(offs_t offset, uint32_t mem_mask)
+u32 pxa255_periphs_device::lcd_liidr_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_LCD_BASE_ADDR | (offset << 2))
- {
- case PXA255_LCCR0: // 0x44000000
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Control 0: %08x & %08x\n", m_lcd_regs.lccr0, mem_mask);
- return m_lcd_regs.lccr0;
- case PXA255_LCCR1: // 0x44000004
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Control 1: %08x & %08x\n", m_lcd_regs.lccr1, mem_mask);
- return m_lcd_regs.lccr1;
- case PXA255_LCCR2: // 0x44000008
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Control 2: %08x & %08x\n", m_lcd_regs.lccr2, mem_mask);
- return m_lcd_regs.lccr2;
- case PXA255_LCCR3: // 0x4400000c
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Control 3: %08x & %08x\n", m_lcd_regs.lccr3, mem_mask);
- return m_lcd_regs.lccr3;
- case PXA255_FBR0: // 0x44000020
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Frame Branch Register 0: %08x & %08x\n", m_lcd_regs.fbr[0], mem_mask);
- return m_lcd_regs.fbr[0];
- case PXA255_FBR1: // 0x44000024
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Frame Branch Register 1: %08x & %08x\n", m_lcd_regs.fbr[1], mem_mask);
- return m_lcd_regs.fbr[1];
- case PXA255_LCSR: // 0x44000038
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Status Register: %08x & %08x\n", m_lcd_regs.lcsr, mem_mask);
- return m_lcd_regs.lcsr;
- case PXA255_LIIDR: // 0x4400003c
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD Interrupt ID Register: %08x & %08x\n", m_lcd_regs.liidr, mem_mask);
- return m_lcd_regs.liidr;
- case PXA255_TRGBR: // 0x44000040
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: TMED RGB Seed Register: %08x & %08x\n", m_lcd_regs.trgbr, mem_mask);
- return m_lcd_regs.trgbr;
- case PXA255_TCR: // 0x44000044
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: TMED RGB Seed Register: %08x & %08x\n", m_lcd_regs.tcr, mem_mask);
- return m_lcd_regs.tcr;
- case PXA255_FDADR0: // 0x44000200
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Frame Descriptor Address Register 0: %08x & %08x\n", m_lcd_regs.dma[0].fdadr, mem_mask);
- return m_lcd_regs.dma[0].fdadr;
- case PXA255_FSADR0: // 0x44000204
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Frame Source Address Register 0: %08x & %08x\n", m_lcd_regs.dma[0].fsadr, mem_mask);
- return m_lcd_regs.dma[0].fsadr;
- case PXA255_FIDR0: // 0x44000208
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Frame ID Register 0: %08x & %08x\n", m_lcd_regs.dma[0].fidr, mem_mask);
- return m_lcd_regs.dma[0].fidr;
- case PXA255_LDCMD0: // 0x4400020c
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Command Register 0: %08x & %08x\n", m_lcd_regs.dma[0].ldcmd & 0xfff00000, mem_mask);
- return m_lcd_regs.dma[0].ldcmd & 0xfff00000;
- case PXA255_FDADR1: // 0x44000210
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Frame Descriptor Address Register 1: %08x & %08x\n", m_lcd_regs.dma[1].fdadr, mem_mask);
- return m_lcd_regs.dma[1].fdadr;
- case PXA255_FSADR1: // 0x44000214
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Frame Source Address Register 1: %08x & %08x\n", m_lcd_regs.dma[1].fsadr, mem_mask);
- return m_lcd_regs.dma[1].fsadr;
- case PXA255_FIDR1: // 0x44000218
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Frame ID Register 1: %08x & %08x\n", m_lcd_regs.dma[1].fidr, mem_mask);
- return m_lcd_regs.dma[1].fidr;
- case PXA255_LDCMD1: // 0x4400021c
- LOGMASKED(LOG_LCD, "pxa255_lcd_r: LCD DMA Command Register 1: %08x & %08x\n", m_lcd_regs.dma[1].ldcmd & 0xfff00000, mem_mask);
- return m_lcd_regs.dma[1].ldcmd & 0xfff00000;
- default:
- LOGMASKED(LOG_LCD | LOG_UNKNOWN, "pxa255_lcd_r: Unknown address: %08x\n", PXA255_LCD_BASE_ADDR | (offset << 2));
- break;
- }
- return 0;
+ const u32 data = m_lcd_regs.liidr;
+ LOGMASKED(LOG_LCD, "%s: lcd_liidr_r: LCD Interrupt ID Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
-void pxa255_periphs_device::lcd_w(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask)
+void pxa255_periphs_device::lcd_liidr_w(offs_t offset, u32 data, u32 mem_mask)
{
- switch(PXA255_LCD_BASE_ADDR | (offset << 2))
- {
- case PXA255_LCCR0: // 0x44000000
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Control 0: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.lccr0 = data & 0x00fffeff;
- break;
- case PXA255_LCCR1: // 0x44000004
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Control 1: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.lccr1 = data;
- break;
- case PXA255_LCCR2: // 0x44000008
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Control 2: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.lccr2 = data;
- break;
- case PXA255_LCCR3: // 0x4400000c
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Control 3: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.lccr3 = data;
- break;
- case PXA255_FBR0: // 0x44000020
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Frame Branch Register 0: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.fbr[0] = data & 0xfffffff3;
- if(!m_lcd_regs.dma[0].eof->enabled())
- {
- LOGMASKED(LOG_LCD, "ch0 EOF timer is not enabled, taking branch now\n" );
- lcd_check_load_next_branch(0);
- lcd_irq_check();
- }
- break;
- case PXA255_FBR1: // 0x44000024
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Frame Branch Register 1: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.fbr[1] = data & 0xfffffff3;
- if(!m_lcd_regs.dma[1].eof->enabled())
- {
- LOGMASKED(LOG_LCD, "ch1 EOF timer is not enabled, taking branch now\n" );
- lcd_check_load_next_branch(1);
- lcd_irq_check();
- }
- break;
- case PXA255_LCSR: // 0x44000038
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Controller Status Register: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.lcsr &= ~data;
- lcd_irq_check();
- break;
- case PXA255_LIIDR: // 0x4400003c
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD Controller Interrupt ID Register: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_TRGBR: // 0x44000040
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: TMED RGB Seed Register: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.trgbr = data & 0x00ffffff;
- break;
- case PXA255_TCR: // 0x44000044
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: TMED Control Register: %08x & %08x\n", data, mem_mask);
- m_lcd_regs.tcr = data & 0x00004fff;
- break;
- case PXA255_FDADR0: // 0x44000200
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD DMA Frame Descriptor Address Register 0: %08x & %08x\n", data, mem_mask);
- if(!m_lcd_regs.dma[0].eof->enabled())
- {
- lcd_load_dma_descriptor(space, data & 0xfffffff0, 0);
- }
- else
- {
- m_lcd_regs.fbr[0] &= 0x00000003;
- m_lcd_regs.fbr[0] |= data & 0xfffffff0;
- }
- break;
- case PXA255_FSADR0: // 0x44000204
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: (Invalid Write) LCD DMA Frame Source Address Register 0: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_FIDR0: // 0x44000208
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: (Invalid Write) LCD DMA Frame ID Register 0: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_LDCMD0: // 0x4400020c
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: (Invalid Write) LCD DMA Command Register 0: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_FDADR1: // 0x44000210
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: LCD DMA Frame Descriptor Address Register 1: %08x & %08x\n", data, mem_mask);
- if(!m_lcd_regs.dma[1].eof->enabled())
- {
- lcd_load_dma_descriptor(space, data & 0xfffffff0, 1);
- }
- else
- {
- m_lcd_regs.fbr[1] &= 0x00000003;
- m_lcd_regs.fbr[1] |= data & 0xfffffff0;
- }
- break;
- case PXA255_FSADR1: // 0x44000214
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: (Invalid Write) LCD DMA Frame Source Address Register 1: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_FIDR1: // 0x44000218
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: (Invalid Write) LCD DMA Frame ID Register 1: %08x & %08x\n", data, mem_mask);
- break;
- case PXA255_LDCMD1: // 0x4400021c
- LOGMASKED(LOG_LCD, "pxa255_lcd_w: (Invalid Write) LCD DMA Command Register 1: %08x & %08x\n", data, mem_mask);
- break;
- default:
- LOGMASKED(LOG_LCD | LOG_UNKNOWN, "pxa255_lcd_w: Unknown address: %08x = %08x & %08x\n", PXA255_LCD_BASE_ADDR | (offset << 2), data, mem_mask);
- break;
- }
+ LOGMASKED(LOG_LCD, "%s: lcd_liidr_w: LCD Interrupt ID Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
}
-uint32_t pxa255_periphs_device::power_r(offs_t offset, uint32_t mem_mask)
+u32 pxa255_periphs_device::lcd_trgbr_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_POWER_BASE_ADDR | (offset << 2))
- {
- case PXA255_PMCR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Control Register: %08x\n", machine().describe_context(), m_power_regs.pmcr);
- return m_power_regs.pmcr;
- case PXA255_PSSR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Sleep Status Register: %08x\n", machine().describe_context(), m_power_regs.pssr);
- return m_power_regs.pssr;
- case PXA255_PSPR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Scratch Pad Register: %08x\n", machine().describe_context(), m_power_regs.pspr);
- return m_power_regs.pspr;
- case PXA255_PWER:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Wake-up Enable Register: %08x\n", machine().describe_context(), m_power_regs.pwer);
- return m_power_regs.pwer;
- case PXA255_PRER:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Rising-Edge Detect Enable Register: %08x\n", machine().describe_context(), m_power_regs.prer);
- return m_power_regs.prer;
- case PXA255_PFER:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Falling-Edge Detect Enable Register: %08x\n", machine().describe_context(), m_power_regs.pfer);
- return m_power_regs.pfer;
- case PXA255_PEDR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Edge Detect Status Register: %08x\n", machine().describe_context(), m_power_regs.pedr);
- return m_power_regs.pedr;
- case PXA255_PCFR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager General Configuration Register: %08x\n", machine().describe_context(), m_power_regs.pcfr);
- return m_power_regs.pcfr;
- case PXA255_PGSR0:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Sleep State Register for GP[31-0]: %08x\n", machine().describe_context(), m_power_regs.pgsr0);
- return m_power_regs.pgsr0;
- case PXA255_PGSR1:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Sleep State Register for GP[63-32]: %08x\n", machine().describe_context(), m_power_regs.pgsr1);
- return m_power_regs.pgsr1;
- case PXA255_PGSR2:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Sleep State Register for GP[84-64]: %08x\n", machine().describe_context(), m_power_regs.pgsr2);
- return m_power_regs.pgsr2;
- case PXA255_RCSR:
- LOGMASKED(LOG_POWER, "%s: power_r: Reset Controller Status Register: %08x\n", machine().describe_context(), m_power_regs.rcsr);
- return m_power_regs.rcsr;
- case PXA255_PMFW:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Fast Sleep Walk-Up Configuration Register: %08x\n", machine().describe_context(), m_power_regs.pmfw);
- return m_power_regs.pmfw;
- default:
- LOGMASKED(LOG_POWER | LOG_UNKNOWN, "%s: power_r: Unknown address: %08x\n", machine().describe_context(), PXA255_POWER_BASE_ADDR | (offset << 2));
- break;
- }
- return 0;
+ const u32 data = m_lcd_regs.trgbr;
+ LOGMASKED(LOG_LCD, "%s: lcd_trgbr_r: TMED RGB Seed Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::lcd_trgbr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_trgbr_w: TMED RGB Seed Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_lcd_regs.trgbr = data & 0x00ffffff;
+}
+
+u32 pxa255_periphs_device::lcd_tcr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_lcd_regs.tcr;
+ LOGMASKED(LOG_LCD, "%s: lcd_tcr_r: TMED Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::lcd_tcr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_tcr_w: TMED Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_lcd_regs.tcr = data & 0x00004fff;
}
-void pxa255_periphs_device::power_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+template <int Which>
+u32 pxa255_periphs_device::lcd_fdadr_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_POWER_BASE_ADDR | (offset << 2))
+ const u32 data = m_lcd_regs.dma[Which].fdadr;
+ LOGMASKED(LOG_LCD, "%s: lcd_fdadr_r: LCD DMA Frame Descriptor Address Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::lcd_fdadr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_fdadr_w: LCD DMA Frame Descriptor Address Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ if (!m_lcd_regs.dma[Which].eof->enabled())
{
- case PXA255_PMCR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pmcr);
- break;
- case PXA255_PSSR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Sleep Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- m_power_regs.pssr &= ~(data & 0x00000037);
- break;
- case PXA255_PSPR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Scratch Pad Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pspr);
- break;
- case PXA255_PWER:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Wake-Up Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pwer);
- break;
- case PXA255_PRER:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Rising-Edge Detect Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.prer);
- break;
- case PXA255_PFER:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Falling-Edge Detect Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pfer);
- break;
- case PXA255_PEDR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager GPIO Edge Detect Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- m_power_regs.pedr &= ~(data & 0x0000ffff);
- break;
- case PXA255_PCFR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager General Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pcfr);
- break;
- case PXA255_PGSR0:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager GPIO Sleep State Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pgsr0);
- break;
- case PXA255_PGSR1:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager GPIO Sleep State Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pgsr1);
- break;
- case PXA255_PGSR2:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager GPIO Sleep State Register 2 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pgsr2);
- break;
- case PXA255_PMFW:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Fast Sleep Walk-Up Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pmfw);
- break;
- default:
- LOGMASKED(LOG_POWER | LOG_UNKNOWN, "%s: power_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), PXA255_POWER_BASE_ADDR | (offset << 2),
- data, mem_mask);
- break;
+ lcd_load_dma_descriptor(data & 0xfffffff0, Which);
+ }
+ else
+ {
+ m_lcd_regs.fbr[Which] &= 0x00000003;
+ m_lcd_regs.fbr[Which] |= data & 0xfffffff0;
}
}
+template <int Which>
+u32 pxa255_periphs_device::lcd_fsadr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_lcd_regs.dma[Which].fsadr;
+ LOGMASKED(LOG_LCD, "%s: lcd_fsadr_r: LCD DMA Frame Source Address Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::lcd_fsadr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_fsadr_w: (Ignored) LCD DMA Frame Source Address Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+}
+
+template <int Which>
+u32 pxa255_periphs_device::lcd_fidr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_lcd_regs.dma[Which].fidr;
+ LOGMASKED(LOG_LCD, "%s: lcd_fidr_r: LCD DMA Frame ID Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::lcd_fidr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_fidr_w: (Ignored) LCD DMA Frame ID Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+}
+
+template <int Which>
+u32 pxa255_periphs_device::lcd_ldcmd_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_lcd_regs.dma[Which].ldcmd & 0xfff00000;
+ LOGMASKED(LOG_LCD, "%s: lcd_ldcmd_r: LCD DMA Command Register %d: %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+ return data;
+}
+
+template <int Which>
+void pxa255_periphs_device::lcd_ldcmd_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_LCD, "%s: lcd_ldcmd_w: (Ignored) LCD DMA Command Register %d = %08x & %08x\n", machine().describe_context(), Which, data, mem_mask);
+}
+
+
/*
- PXA255 Clock controller
- pg. 96 to 100, PXA255 Processor Developers Manual [278693-002].pdf
+ PXA255 Power Controller
+
+ pg. 85 to 96, PXA255 Processor Developers Manual [278693-002].pdf
*/
-uint32_t pxa255_periphs_device::clocks_r(offs_t offset, uint32_t mem_mask)
+u32 pxa255_periphs_device::pwr_pmcr_r(offs_t offset, u32 mem_mask)
{
- switch(PXA255_CLOCKS_BASE_ADDR | (offset << 2))
- {
- case PXA255_CCCR:
- LOGMASKED(LOG_CLOCKS, "%s: clocks_r: Core Clock Configuration Register: %08x\n", machine().describe_context(), m_clocks_regs.cccr);
- return m_clocks_regs.cccr;
- case PXA255_CKEN:
- LOGMASKED(LOG_CLOCKS, "%s: clocks_r: Clock Enable Register: %08x\n", machine().describe_context(), m_clocks_regs.cken);
- return m_clocks_regs.cken;
- case PXA255_OSCC:
- LOGMASKED(LOG_CLOCKS, "%s: clocks_r: Oscillator Configuration Register: %08x\n", machine().describe_context(), m_clocks_regs.oscc);
- return BIT(m_clocks_regs.oscc, 0);
- default:
- LOGMASKED(LOG_CLOCKS | LOG_UNKNOWN, "%s: clocks_r: Unknown address: %08x\n", machine().describe_context(), PXA255_CLOCKS_BASE_ADDR | (offset << 2));
- break;
- }
- return 0;
+ const u32 data = m_power_regs.pmcr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pmcr_r: Power Manager Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
-void pxa255_periphs_device::clocks_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void pxa255_periphs_device::pwr_pmcr_w(offs_t offset, u32 data, u32 mem_mask)
{
- switch(PXA255_CLOCKS_BASE_ADDR | (offset << 2))
- {
- case PXA255_CCCR:
- LOGMASKED(LOG_CLOCKS, "%s: clocks_w: Core Clock Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_clocks_regs.cccr);
- break;
- case PXA255_CKEN:
- LOGMASKED(LOG_CLOCKS, "%s: clocks_w: Clock Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_clocks_regs.cken);
- break;
- case PXA255_OSCC:
- LOGMASKED(LOG_CLOCKS, "%s: clocks_w: Oscillator Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- if (BIT(data, 1))
- {
- m_clocks_regs.oscc |= 0x00000003;
- }
- break;
- default:
- LOGMASKED(LOG_CLOCKS | LOG_UNKNOWN, "%s: clocks_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), PXA255_CLOCKS_BASE_ADDR | (offset << 2),
- data, mem_mask);
- break;
- }
+ LOGMASKED(LOG_POWER, "%s: pwr_pmcr_w: Power Manager Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pmcr);
}
-void pxa255_periphs_device::device_start()
+u32 pxa255_periphs_device::pwr_pssr_r(offs_t offset, u32 mem_mask)
{
- for (int index = 0; index < 16; index++)
- {
- m_dma_regs.timer[index] = timer_alloc(TIMER_DMA0 + index);
- }
+ const u32 data = m_power_regs.pssr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pssr_r: Power Manager Sleep Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
- for (int index = 0; index < 4; index++)
- {
- m_ostimer_regs.timer[index] = timer_alloc(TIMER_OSTIMER0 + index);
- }
+void pxa255_periphs_device::pwr_pssr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pssr_w: Power Manager Sleep Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_power_regs.pssr &= ~(data & 0x00000037);
+}
- m_lcd_regs.dma[0].eof = timer_alloc(TIMER_LCD_EOF0);
- m_lcd_regs.dma[1].eof = timer_alloc(TIMER_LCD_EOF0 + 1);
+u32 pxa255_periphs_device::pwr_pspr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pspr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pspr_r: Power Manager Scratch Pad Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
- m_lcd_palette = make_unique_clear<uint32_t[]>(0x100);
- m_lcd_framebuffer = make_unique_clear<uint8_t[]>(0x100000);
- m_words = make_unique_clear<uint32_t[]>(0x800);
- m_samples = make_unique_clear<int16_t[]>(0x1000);
+void pxa255_periphs_device::pwr_pspr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pspr_w: Power Manager Scratch Pad Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pspr);
+}
- m_gpio0_w.resolve_safe();
- m_gpio1_w.resolve_safe();
- m_gpio2_w.resolve_safe();
- m_gpio0_r.resolve_safe(0xffffffff);
- m_gpio1_r.resolve_safe(0xffffffff);
- m_gpio2_r.resolve_safe(0xffffffff);
+u32 pxa255_periphs_device::pwr_pwer_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pwer;
+ LOGMASKED(LOG_POWER, "%s: pwr_pwer_r: Power Manager Wake-Up Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
- m_rtc_regs.timer = timer_alloc(TIMER_RTC);
+void pxa255_periphs_device::pwr_pwer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pwer_w: Power Manager Wake-Up Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pwer);
}
-void pxa255_periphs_device::device_reset()
+u32 pxa255_periphs_device::pwr_prer_r(offs_t offset, u32 mem_mask)
{
- for (int index = 0; index < 16; index++)
- {
- m_dma_regs.dcsr[index] = 0x00000008;
- }
+ const u32 data = m_power_regs.prer;
+ LOGMASKED(LOG_POWER, "%s: pwr_prer_r: Power Manager GPIO Rising-Edge Detect Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
- m_rtc_regs.rcnr = 0x00000000;
- m_rtc_regs.rtar = 0x00000000;
- m_rtc_regs.rtsr = 0x00000000;
- m_rtc_regs.rttr = 0x00007fff;
- m_rtc_regs.timer->adjust(attotime::from_hz(1));
+void pxa255_periphs_device::pwr_prer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_prer_w: Power Manager GPIO Rising-Edge Detect Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.prer);
+}
- memset(&m_intc_regs, 0, sizeof(m_intc_regs));
+u32 pxa255_periphs_device::pwr_pfer_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pfer;
+ LOGMASKED(LOG_POWER, "%s: pwr_pfer_r: Power Manager GPIO Falling-Edge Detect Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
- m_lcd_regs.trgbr = 0x00aa5500;
- m_lcd_regs.tcr = 0x0000754f;
+void pxa255_periphs_device::pwr_pfer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pfer_w: Power Manager GPIO Falling-Edge Detect Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pfer);
+}
- memset(&m_power_regs, 0, sizeof(m_power_regs));
- memset(&m_clocks_regs, 0, sizeof(m_clocks_regs));
+u32 pxa255_periphs_device::pwr_pedr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pedr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pedr_r: Power Manager GPIO Edge Detect Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
-void pxa255_periphs_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void pxa255_periphs_device::pwr_pedr_w(offs_t offset, u32 data, u32 mem_mask)
{
- if (id < TIMER_OSTIMER0)
- dma_end_tick(id);
- else if (id < TIMER_LCD_EOF0)
- ostimer_match_tick(id - TIMER_OSTIMER0);
- else if (id < TIMER_RTC)
- lcd_dma_eof_tick(id - TIMER_LCD_EOF0);
- else if (id == TIMER_RTC)
- rtc_tick();
+ LOGMASKED(LOG_POWER, "%s: pwr_pedr_w: Power Manager GPIO Edge-Detect Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_power_regs.pedr &= ~(data & 0x0000ffff);
}
-uint32_t pxa255_periphs_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+u32 pxa255_periphs_device::pwr_pcfr_r(offs_t offset, u32 mem_mask)
{
- for (int y = 0; y <= (m_lcd_regs.lccr2 & PXA255_LCCR2_LPP); y++)
- {
- uint32_t *dst = &bitmap.pix(y);
- for (int x = 0; x <= (m_lcd_regs.lccr1 & PXA255_LCCR1_PPL); x++)
- {
- *dst++ = m_lcd_palette[m_lcd_framebuffer[y * ((m_lcd_regs.lccr1 & PXA255_LCCR1_PPL) + 1) + x]];
- }
- }
- return 0;
+ const u32 data = m_power_regs.pcfr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pcfr_r: Power Manager General Configuration Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
-void pxa255_periphs_device::device_add_mconfig(machine_config &config)
+void pxa255_periphs_device::pwr_pcfr_w(offs_t offset, u32 data, u32 mem_mask)
{
- screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
- screen.set_refresh_hz(60);
- screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
- screen.set_size(1024, 1024);
- screen.set_visarea(0, 295, 0, 479);
- screen.set_screen_update(FUNC(pxa255_periphs_device::screen_update));
+ LOGMASKED(LOG_POWER, "%s: pwr_pcfr_w: Power Manager General Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pcfr);
+}
- PALETTE(config, m_palette).set_entries(256);
+template <int Which>
+u32 pxa255_periphs_device::pwr_pgsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pgsr[Which];
+ LOGMASKED(LOG_POWER, "%s: pwr_pgsr_r: Power Manager GPIO Sleep State Register for GPIO%d-%d: %08x & %08x\n", machine().describe_context(), Which * 32, Which * 32 + 31, data, mem_mask);
+ return data;
+}
- SPEAKER(config, "lspeaker").front_left();
- SPEAKER(config, "rspeaker").front_right();
+template <int Which>
+void pxa255_periphs_device::pwr_pgsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pgsr_w: Power Manager GPIO Sleep State Register for GPIO%d-%d = %08x & %08x\n", machine().describe_context(), Which * 32, Which * 32 + 31, data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pgsr[Which]);
+}
- DMADAC(config, m_dmadac[0]).add_route(ALL_OUTPUTS, "lspeaker", 1.0);
- DMADAC(config, m_dmadac[1]).add_route(ALL_OUTPUTS, "rspeaker", 1.0);
+u32 pxa255_periphs_device::pwr_rcsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.rcsr;
+ LOGMASKED(LOG_POWER, "%s: pwr_rcsr_r: Reset Controller Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+u32 pxa255_periphs_device::pwr_pmfw_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pmfw;
+ LOGMASKED(LOG_POWER, "%s: pwr_pmfw_r: Power Manager Fast Sleep Wake-Up Configuration Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::pwr_pmfw_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pmfw_w: Power Manager Fast Sleep Wake-Up Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pmfw);
+}
+
+
+/*
+ PXA255 Clock controller
+
+ pg. 96 to 100, PXA255 Processor Developers Manual [278693-002].pdf
+
+*/
+
+u32 pxa255_periphs_device::clk_cccr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_clk_regs.cccr;
+ LOGMASKED(LOG_CLOCKS, "%s: clk_cccr_r: Core Clock Configuration Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::clk_cccr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_CLOCKS, "%s: clk_cccr_w: Core Clock Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_clk_regs.cccr);
+}
+
+u32 pxa255_periphs_device::clk_cken_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_clk_regs.cken;
+ LOGMASKED(LOG_CLOCKS, "%s: clk_cken_r: Clock Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::clk_cken_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_CLOCKS, "%s: clk_cken_w: Clock Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_clk_regs.cken);
+}
+
+u32 pxa255_periphs_device::clk_oscc_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_clk_regs.cccr;
+ LOGMASKED(LOG_CLOCKS, "%s: clk_oscc_r: Oscillator Configuration Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void pxa255_periphs_device::clk_oscc_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_CLOCKS, "%s: clk_oscc_w: Oscillator Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ if (BIT(data, 1))
+ {
+ m_clk_regs.oscc |= 0x00000003;
+ }
}
diff --git a/src/devices/machine/pxa255.h b/src/devices/machine/pxa255.h
index 87a7cef0ce8..3cc9b43c8a9 100644
--- a/src/devices/machine/pxa255.h
+++ b/src/devices/machine/pxa255.h
@@ -19,258 +19,461 @@
#include "sound/dmadac.h"
#include "emupal.h"
-#include "pxa255defs.h"
-
class pxa255_periphs_device : public device_t
{
public:
template <typename T>
- pxa255_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ pxa255_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&cpu_tag)
: pxa255_periphs_device(mconfig, tag, owner, clock)
{
m_maincpu.set_tag(std::forward<T>(cpu_tag));
}
- pxa255_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto gpio0_write() { return m_gpio0_w.bind(); }
- auto gpio0_read() { return m_gpio0_r.bind(); }
- auto gpio1_write() { return m_gpio1_w.bind(); }
- auto gpio1_read() { return m_gpio1_r.bind(); }
- auto gpio2_write() { return m_gpio2_w.bind(); }
- auto gpio2_read() { return m_gpio2_r.bind(); }
-
- uint32_t dma_r(offs_t offset, uint32_t mem_mask = ~0);
- void dma_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t i2s_r(offs_t offset, uint32_t mem_mask = ~0);
- void i2s_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t rtc_r(offs_t offset, uint32_t mem_mask = ~0);
- void rtc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t ostimer_r(offs_t offset, uint32_t mem_mask = ~0);
- void ostimer_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t intc_r(offs_t offset, uint32_t mem_mask = ~0);
- void intc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- void gpio_bit_w(offs_t offset, uint8_t data, uint8_t mem_mask = ~0);
- uint32_t gpio_r(offs_t offset, uint32_t mem_mask = ~0);
- void gpio_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t lcd_r(offs_t offset, uint32_t mem_mask = ~0);
- void lcd_w(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t power_r(offs_t offset, uint32_t mem_mask = ~0);
- void power_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t clocks_r(offs_t offset, uint32_t mem_mask = ~0);
- void clocks_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ pxa255_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ template <int Bit> auto gpio_out() { return m_gpio_w[Bit].bind(); }
+ template <int Bit> void gpio_in(int state);
+
+ void map(address_map &map);
+
+ // gpio_bit_w
protected:
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- static const device_timer_id TIMER_DMA0 = 0;
- static const device_timer_id TIMER_OSTIMER0 = 16;
- static const device_timer_id TIMER_LCD_EOF0 = 20;
- static const device_timer_id TIMER_RTC = 22;
+ static constexpr u32 INTERNAL_OSC = 3686400;
+ // DMA Hardware
void dma_irq_check();
void dma_load_descriptor_and_start(int channel);
- void ostimer_irq_check();
- void update_interrupts();
- void lcd_load_dma_descriptor(address_space & space, uint32_t address, int channel);
- void lcd_irq_check();
- void lcd_dma_kickoff(int channel);
- void lcd_check_load_next_branch(int channel);
-
- uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
-
- void dma_end_tick(int channel);
- void ostimer_match_tick(int channel);
- void lcd_dma_eof_tick(int channel);
- void rtc_tick();
-
- void set_irq_line(uint32_t line, int state);
+ TIMER_CALLBACK_MEMBER(audio_dma_end_tick);
+ TIMER_CALLBACK_MEMBER(dma_end_tick);
+ void dma_finish(int channel);
+
+ u32 dma_dcsr_r(offs_t offset, u32 mem_mask);
+ void dma_dcsr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 dma_dint_r(offs_t offset, u32 mem_mask);
+ void dma_dint_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 dma_drcmr_r(offs_t offset, u32 mem_mask);
+ void dma_drcmr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 dma_ddadr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void dma_ddadr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 dma_dsadr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void dma_dsadr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 dma_dtadr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void dma_dtadr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 dma_dcmd_r(offs_t offset, u32 mem_mask);
+ template <int Which> void dma_dcmd_w(offs_t offset, u32 data, u32 mem_mask);
+
+ enum dma_bits_t : u32
+ {
+ DCSR_BUSERRINTR = 1u << 0,
+ DCSR_STARTINTR = 1u << 1,
+ DCSR_ENDINTR = 1u << 2,
+ DCSR_STOPSTATE = 1u << 3,
+ DCSR_REQPEND = 1u << 8,
+ DCSR_STOPIRQ = 1u << 29,
+ DCSR_NODESCFETCH = 1u << 30,
+ DCSR_RUN = 1u << 31,
+
+ DDADR_STOP = 1u << 0,
+
+ DCMD_INCSRCADDR = 1u << 31,
+ DCMD_INCTRGADDR = 1u << 30,
+ DCMD_STARTIRQEN = 1u << 22,
+ DCMD_ENDIRQEN = 1u << 21,
+ DCMD_SIZE_SHIFT = 16,
+ DCMD_SIZE_MASK = 3,
+ DCMD_SIZE_0 = 0,
+ DCMD_SIZE_8 = 1,
+ DCMD_SIZE_16 = 2,
+ DCMD_SIZE_32 = 3
+ };
struct dma_regs
{
- uint32_t dcsr[16];
- uint32_t pad0[44];
+ u32 dcsr[16];
+ u32 dint;
+ u32 drcmr[40];
- uint32_t dint;
- uint32_t pad1[3];
-
- uint32_t drcmr[40];
- uint32_t pad2[24];
-
- uint32_t ddadr[16];
- uint32_t dsadr[16];
- uint32_t dtadr[16];
- uint32_t dcmd[16];
+ u32 ddadr[16];
+ u32 dsadr[16];
+ u32 dtadr[16];
+ u32 dcmd[16];
emu_timer* timer[16];
};
- struct i2s_regs
- {
- uint32_t sacr0;
- uint32_t sacr1;
- uint32_t pad0;
+ dma_regs m_dma_regs;
- uint32_t sasr0;
- uint32_t pad1;
+ // RTC Hardware
+ TIMER_CALLBACK_MEMBER(rtc_tick);
+ u32 rtc_rcnr_r(offs_t offset, u32 mem_mask);
+ void rtc_rcnr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 rtc_rtar_r(offs_t offset, u32 mem_mask);
+ void rtc_rtar_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 rtc_rtsr_r(offs_t offset, u32 mem_mask);
+ void rtc_rtsr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 rtc_rttr_r(offs_t offset, u32 mem_mask);
+ void rtc_rttr_w(offs_t offset, u32 data, u32 mem_mask);
- uint32_t saimr;
- uint32_t saicr;
- uint32_t pad2[17];
+ struct rtc_regs
+ {
+ u32 rcnr;
+ u32 rtar;
+ u32 rtsr;
+ u32 rttr;
+ emu_timer *timer;
+ };
- uint32_t sadiv;
- uint32_t pad3[6];
+ rtc_regs m_rtc_regs;
- uint32_t sadr;
+ // I2S (Audio) Hardware
+ u32 i2s_sacr0_r(offs_t offset, u32 mem_mask);
+ void i2s_sacr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 i2s_sacr1_r(offs_t offset, u32 mem_mask);
+ void i2s_sacr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 i2s_sasr0_r(offs_t offset, u32 mem_mask);
+ void i2s_sasr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 i2s_saimr_r(offs_t offset, u32 mem_mask);
+ void i2s_saimr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 i2s_saicr_r(offs_t offset, u32 mem_mask);
+ void i2s_saicr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 i2s_sadiv_r(offs_t offset, u32 mem_mask);
+ void i2s_sadiv_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 i2s_sadr_r(offs_t offset, u32 mem_mask);
+ void i2s_sadr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ enum i2s_bits_t : u32
+ {
+ SASR0_TNF = 1u << 0,
+ SASR0_RNE = 1u << 1,
+ SASR0_BSY = 1u << 2,
+ SASR0_TFS = 1u << 3,
+ SASR0_RFS = 1u << 4,
+ SASR0_TUR = 1u << 5,
+ SASR0_ROR = 1u << 6,
+ SASR0_TFL = 15u << 8,
+ SASR0_RFL = 15u << 12,
+
+ SAICR_TUR = 1u << 5,
+ SAICR_ROR = 1u << 6,
};
- struct rtc_regs
+ struct i2s_regs
{
- uint32_t rcnr;
- uint32_t rtar;
- uint32_t rtsr;
- uint32_t rttr;
- emu_timer *timer;
+ u32 sacr0;
+ u32 sacr1;
+ u32 sasr0;
+ u32 saimr;
+ u32 saicr;
+ u32 sadiv;
+ u32 sadr;
+ };
+
+ i2s_regs m_i2s_regs;
+
+ // Timer Hardware
+ void ostimer_irq_check();
+ TIMER_CALLBACK_MEMBER(ostimer_match_tick);
+ template <int Which> void ostimer_update_interrupts();
+ void ostimer_update_count();
+
+ template <int Which> u32 tmr_osmr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void tmr_osmr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_oscr_r(offs_t offset, u32 mem_mask);
+ void tmr_oscr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_ossr_r(offs_t offset, u32 mem_mask);
+ void tmr_ossr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_ower_r(offs_t offset, u32 mem_mask);
+ void tmr_ower_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_oier_r(offs_t offset, u32 mem_mask);
+ void tmr_oier_w(offs_t offset, u32 data, u32 mem_mask);
+
+ enum tmr_bits_t : u32
+ {
+ OSSR_M0 = 1u << 0,
+ OSSR_M1 = 1u << 1,
+ OSSR_M2 = 1u << 2,
+ OSSR_M3 = 1u << 3,
+
+ OIER_E0 = 1u << 0,
+ OIER_E1 = 1u << 1,
+ OIER_E2 = 1u << 2,
+ OIER_E3 = 1u << 3
};
struct ostmr_regs
{
- uint32_t osmr[4];
- uint32_t oscr;
- uint32_t ossr;
- uint32_t ower;
- uint32_t oier;
+ u32 osmr[4];
+ u32 oscr;
+ u32 ossr;
+ u32 ower;
+ u32 oier;
emu_timer* timer[4];
+ attotime last_count_sync;
};
+ ostmr_regs m_ostimer_regs;
+
+ // Interrupt Hardware
+ enum intc_bits_t : u32
+ {
+ INT_HUART = 1u << 7,
+ INT_GPIO0 = 1u << 8,
+ INT_GPIO1 = 1u << 9,
+ INT_GPIO84_2 = 1u << 10,
+ INT_USB = 1u << 11,
+ INT_PMU = 1u << 12,
+ INT_I2S = 1u << 13,
+ INT_AC97 = 1u << 14,
+ INT_NETWORK = 1u << 16,
+ INT_LCD = 1u << 17,
+ INT_I2C = 1u << 18,
+ INT_ICP = 1u << 19,
+ INT_STUART = 1u << 20,
+ INT_BTUART = 1u << 21,
+ INT_FFUART = 1u << 22,
+ INT_MMC = 1u << 23,
+ INT_SSP = 1u << 24,
+ INT_DMA = 1u << 25,
+ INT_OSTIMER0 = 1u << 26,
+ INT_OSTIMER1 = 1u << 27,
+ INT_OSTIMER2 = 1u << 28,
+ INT_OSTIMER3 = 1u << 29,
+ INT_RTC_HZ = 1u << 30,
+ INT_RTC_ALARM = 1u << 31
+ };
+
+ void update_interrupts();
+ u32 intc_icip_r(offs_t offset, u32 mem_mask);
+ void intc_icip_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_icmr_r(offs_t offset, u32 mem_mask);
+ void intc_icmr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_iclr_r(offs_t offset, u32 mem_mask);
+ void intc_iclr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_icfp_r(offs_t offset, u32 mem_mask);
+ void intc_icfp_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_icpr_r(offs_t offset, u32 mem_mask);
+ void intc_icpr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_iccr_r(offs_t offset, u32 mem_mask);
+ void intc_iccr_w(offs_t offset, u32 data, u32 mem_mask);
+
struct intc_regs
{
- uint32_t icip;
- uint32_t icmr;
- uint32_t iclr;
- uint32_t icfp;
- uint32_t icpr;
- uint32_t iccr;
+ u32 icip;
+ u32 icmr;
+ u32 iclr;
+ u32 icfp;
+ u32 icpr;
+ u32 iccr;
};
+ intc_regs m_intc_regs;
+
+ // GPIO Hardware
+ template <int Which> void update_gpio_outputs(const u32 old);
+ template <int Which> void check_gpio_irqs(const u32 old);
+ template <int Which> u32 gpio_gplr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gplr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_gpdr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gpdr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_gpsr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gpsr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_gpcr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gpcr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_grer_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_grer_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_gfer_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gfer_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_gedr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gedr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_gafrl_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gafrl_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 gpio_gafru_r(offs_t offset, u32 mem_mask);
+ template <int Which> void gpio_gafru_w(offs_t offset, u32 data, u32 mem_mask);
+
struct gpio_regs
{
- uint32_t gplr0; // GPIO Pin-Level
- uint32_t gplr1;
- uint32_t gplr2;
-
- uint32_t gpdr0;
- uint32_t gpdr1;
- uint32_t gpdr2;
-
- uint32_t gpsr0;
- uint32_t gpsr1;
- uint32_t gpsr2;
-
- uint32_t gpcr0;
- uint32_t gpcr1;
- uint32_t gpcr2;
-
- uint32_t grer0;
- uint32_t grer1;
- uint32_t grer2;
-
- uint32_t gfer0;
- uint32_t gfer1;
- uint32_t gfer2;
-
- uint32_t gedr0;
- uint32_t gedr1;
- uint32_t gedr2;
-
- uint32_t gafr0l;
- uint32_t gafr0u;
- uint32_t gafr1l;
- uint32_t gafr1u;
- uint32_t gafr2l;
- uint32_t gafr2u;
+ u32 gpdr[3];
+ u32 gpsr[3];
+ u32 gpcr[3];
+ u32 grer[3];
+ u32 gfer[3];
+ u32 gedr[3];
+ u32 gafrl[3];
+ u32 gafru[3];
+ u32 out_data[3]; // Output data
+ u32 in_data[3]; // Input data
+ };
+
+ gpio_regs m_gpio_regs;
+
+ // LCD Hardware
+ u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ TIMER_CALLBACK_MEMBER(lcd_dma_eof_tick);
+ void lcd_load_dma_descriptor(u32 address, int channel);
+ void lcd_irq_check();
+ void lcd_dma_kickoff(int channel);
+ void lcd_check_load_next_branch(int channel);
+
+ template <int Which> u32 lcd_lccr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void lcd_lccr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 lcd_fbr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void lcd_fbr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 lcd_lcsr_r(offs_t offset, u32 mem_mask);
+ void lcd_lcsr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 lcd_liidr_r(offs_t offset, u32 mem_mask);
+ void lcd_liidr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 lcd_trgbr_r(offs_t offset, u32 mem_mask);
+ void lcd_trgbr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 lcd_tcr_r(offs_t offset, u32 mem_mask);
+ void lcd_tcr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 lcd_fdadr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void lcd_fdadr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 lcd_fsadr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void lcd_fsadr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 lcd_fidr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void lcd_fidr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 lcd_ldcmd_r(offs_t offset, u32 mem_mask);
+ template <int Which> void lcd_ldcmd_w(offs_t offset, u32 data, u32 mem_mask);
+
+ enum lcd_bits_t : u32
+ {
+ LCCR0_ENB = 1u << 0,
+ LCCR0_CMS = 1u << 1,
+ LCCR0_SDS = 1u << 2,
+ LCCR0_LDM = 1u << 3,
+ LCCR0_SFM = 1u << 4,
+ LCCR0_IUM = 1u << 5,
+ LCCR0_EFM = 1u << 6,
+ LCCR0_PAS = 1u << 7,
+ LCCR0_DPD = 1u << 9,
+ LCCR0_DIS = 1u << 10,
+ LCCR0_QDM = 1u << 11,
+ LCCR0_PDD = 0xff << 12,
+ LCCR0_BM = 1u << 20,
+ LCCR0_OUM = 1u << 21,
+
+ LCCR1_PPL = 0x000003ff,
+
+ LCCR2_LPP = 0x000003ff,
+
+ LCSR_LDD = 1u << 0,
+ LCSR_SOF = 1u << 1,
+ LCSR_BER = 1u << 2,
+ LCSR_ABC = 1u << 3,
+ LCSR_IUL = 1u << 4,
+ LCSR_IUU = 1u << 5,
+ LCSR_OU = 1u << 6,
+ LCSR_QD = 1u << 7,
+ LCSR_EOF = 1u << 8,
+ LCSR_BS = 1u << 9,
+ LCSR_SINT = 1u << 10,
+
+ LDCMD_EOFINT = 1u << 21,
+ LDCMD_SOFINT = 1u << 22,
+ LDCMD_PAL = 1u << 26
};
struct lcd_dma_regs
{
- uint32_t fdadr;
- uint32_t fsadr;
- uint32_t fidr;
- uint32_t ldcmd;
+ u32 fdadr;
+ u32 fsadr;
+ u32 fidr;
+ u32 ldcmd;
emu_timer *eof;
};
struct lcd_regs
{
- uint32_t lccr0;
- uint32_t lccr1;
- uint32_t lccr2;
- uint32_t lccr3;
+ u32 lccr[4];
- uint32_t fbr[2];
+ u32 fbr[2];
- uint32_t lcsr;
- uint32_t liidr;
- uint32_t trgbr;
- uint32_t tcr;
+ u32 lcsr;
+ u32 liidr;
+ u32 trgbr;
+ u32 tcr;
lcd_dma_regs dma[2];
};
+ lcd_regs m_lcd_regs;
+
+ // Power Management Hardware
+ u32 pwr_pmcr_r(offs_t offset, u32 mem_mask);
+ void pwr_pmcr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pssr_r(offs_t offset, u32 mem_mask);
+ void pwr_pssr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pspr_r(offs_t offset, u32 mem_mask);
+ void pwr_pspr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pwer_r(offs_t offset, u32 mem_mask);
+ void pwr_pwer_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_prer_r(offs_t offset, u32 mem_mask);
+ void pwr_prer_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pfer_r(offs_t offset, u32 mem_mask);
+ void pwr_pfer_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pedr_r(offs_t offset, u32 mem_mask);
+ void pwr_pedr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pcfr_r(offs_t offset, u32 mem_mask);
+ void pwr_pcfr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Which> u32 pwr_pgsr_r(offs_t offset, u32 mem_mask);
+ template <int Which> void pwr_pgsr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_rcsr_r(offs_t offset, u32 mem_mask);
+ u32 pwr_pmfw_r(offs_t offset, u32 mem_mask);
+ void pwr_pmfw_w(offs_t offset, u32 data, u32 mem_mask);
+
struct power_regs
{
- uint32_t pmcr;
- uint32_t pssr;
- uint32_t pspr;
- uint32_t pwer;
- uint32_t prer;
- uint32_t pfer;
- uint32_t pedr;
- uint32_t pcfr;
- uint32_t pgsr0;
- uint32_t pgsr1;
- uint32_t pgsr2;
- uint32_t rcsr;
- uint32_t pmfw;
+ u32 pmcr;
+ u32 pssr;
+ u32 pspr;
+ u32 pwer;
+ u32 prer;
+ u32 pfer;
+ u32 pedr;
+ u32 pcfr;
+ u32 pgsr[3];
+ u32 rcsr;
+ u32 pmfw;
};
- struct clocks_regs
+ power_regs m_power_regs;
+
+ // System Clock Hardware
+ u32 clk_cccr_r(offs_t offset, u32 mem_mask);
+ void clk_cccr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 clk_cken_r(offs_t offset, u32 mem_mask);
+ void clk_cken_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 clk_oscc_r(offs_t offset, u32 mem_mask);
+ void clk_oscc_w(offs_t offset, u32 data, u32 mem_mask);
+
+ struct clk_regs
{
- uint32_t cccr;
- uint32_t cken;
- uint32_t oscc;
+ u32 cccr;
+ u32 cken;
+ u32 oscc;
};
- dma_regs m_dma_regs;
- i2s_regs m_i2s_regs;
- rtc_regs m_rtc_regs;
- ostmr_regs m_ostimer_regs;
- intc_regs m_intc_regs;
- gpio_regs m_gpio_regs;
- lcd_regs m_lcd_regs;
- power_regs m_power_regs;
- clocks_regs m_clocks_regs;
+ clk_regs m_clk_regs;
+
+ void set_irq_line(u32 line, int state);
- devcb_write32 m_gpio0_w;
- devcb_write32 m_gpio1_w;
- devcb_write32 m_gpio2_w;
- devcb_read32 m_gpio0_r;
- devcb_read32 m_gpio1_r;
- devcb_read32 m_gpio2_r;
+ devcb_write_line::array<96> m_gpio_w;
required_device<cpu_device> m_maincpu;
required_device_array<dmadac_sound_device, 2> m_dmadac;
required_device<palette_device> m_palette;
- std::unique_ptr<uint32_t[]> m_lcd_palette; // 0x100
- std::unique_ptr<uint8_t[]> m_lcd_framebuffer; // 0x100000
- std::unique_ptr<uint32_t[]> m_words; // 0x800
- std::unique_ptr<int16_t[]> m_samples; // 0x1000
+ std::unique_ptr<u32[]> m_lcd_palette; // 0x100
+ std::unique_ptr<u8[]> m_lcd_framebuffer; // 0x100000
+ std::unique_ptr<s16[]> m_samples; // 0x1000
};
DECLARE_DEVICE_TYPE(PXA255_PERIPHERALS, pxa255_periphs_device)
diff --git a/src/devices/machine/pxa255defs.h b/src/devices/machine/pxa255defs.h
deleted file mode 100644
index 9857a0871d3..00000000000
--- a/src/devices/machine/pxa255defs.h
+++ /dev/null
@@ -1,426 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/**************************************************************************
- *
- * Intel XScale PXA255 peripheral emulation defines
- *
- **************************************************************************/
-
-#ifndef MAME_MACHINE_PXA255DEFS
-#define MAME_MACHINE_PXA255DEFS
-
-#pragma once
-
-/*
- PXA255 DMA controller
-
- pg. 151 to 182, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_DMA_BASE_ADDR (0x40000000)
-#define PXA255_DCSR0 (PXA255_DMA_BASE_ADDR + 0x00000000)
-#define PXA255_DCSR1 (PXA255_DMA_BASE_ADDR + 0x00000004)
-#define PXA255_DCSR2 (PXA255_DMA_BASE_ADDR + 0x00000008)
-#define PXA255_DCSR3 (PXA255_DMA_BASE_ADDR + 0x0000000c)
-#define PXA255_DCSR4 (PXA255_DMA_BASE_ADDR + 0x00000010)
-#define PXA255_DCSR5 (PXA255_DMA_BASE_ADDR + 0x00000014)
-#define PXA255_DCSR6 (PXA255_DMA_BASE_ADDR + 0x00000018)
-#define PXA255_DCSR7 (PXA255_DMA_BASE_ADDR + 0x0000001c)
-#define PXA255_DCSR8 (PXA255_DMA_BASE_ADDR + 0x00000020)
-#define PXA255_DCSR9 (PXA255_DMA_BASE_ADDR + 0x00000024)
-#define PXA255_DCSR10 (PXA255_DMA_BASE_ADDR + 0x00000028)
-#define PXA255_DCSR11 (PXA255_DMA_BASE_ADDR + 0x0000002c)
-#define PXA255_DCSR12 (PXA255_DMA_BASE_ADDR + 0x00000030)
-#define PXA255_DCSR13 (PXA255_DMA_BASE_ADDR + 0x00000034)
-#define PXA255_DCSR14 (PXA255_DMA_BASE_ADDR + 0x00000038)
-#define PXA255_DCSR15 (PXA255_DMA_BASE_ADDR + 0x0000003c)
- #define PXA255_DCSR_RUN (0x80000000)
- #define PXA255_DCSR_NODESCFETCH (0x40000000)
- #define PXA255_DCSR_STOPIRQ (0x20000000)
- #define PXA255_DCSR_REQPEND (0x00000100)
- #define PXA255_DCSR_STOPSTATE (0x00000008)
- #define PXA255_DCSR_ENDINTR (0x00000004)
- #define PXA255_DCSR_STARTINTR (0x00000002)
- #define PXA255_DCSR_BUSERRINTR (0x00000001)
-#define PXA255_DINT (PXA255_DMA_BASE_ADDR + 0x000000f0)
-#define PXA255_DRCMR0 (PXA255_DMA_BASE_ADDR + 0x00000100)
-#define PXA255_DRCMR1 (PXA255_DMA_BASE_ADDR + 0x00000104)
-#define PXA255_DRCMR2 (PXA255_DMA_BASE_ADDR + 0x00000108)
-#define PXA255_DRCMR3 (PXA255_DMA_BASE_ADDR + 0x0000010c)
-#define PXA255_DRCMR4 (PXA255_DMA_BASE_ADDR + 0x00000110)
-#define PXA255_DRCMR5 (PXA255_DMA_BASE_ADDR + 0x00000114)
-#define PXA255_DRCMR6 (PXA255_DMA_BASE_ADDR + 0x00000118)
-#define PXA255_DRCMR7 (PXA255_DMA_BASE_ADDR + 0x0000011c)
-#define PXA255_DRCMR8 (PXA255_DMA_BASE_ADDR + 0x00000120)
-#define PXA255_DRCMR9 (PXA255_DMA_BASE_ADDR + 0x00000124)
-#define PXA255_DRCMR10 (PXA255_DMA_BASE_ADDR + 0x00000128)
-#define PXA255_DRCMR11 (PXA255_DMA_BASE_ADDR + 0x0000012c)
-#define PXA255_DRCMR12 (PXA255_DMA_BASE_ADDR + 0x00000130)
-#define PXA255_DRCMR13 (PXA255_DMA_BASE_ADDR + 0x00000134)
-#define PXA255_DRCMR14 (PXA255_DMA_BASE_ADDR + 0x00000138)
-#define PXA255_DRCMR15 (PXA255_DMA_BASE_ADDR + 0x0000013c)
-#define PXA255_DRCMR16 (PXA255_DMA_BASE_ADDR + 0x00000140)
-#define PXA255_DRCMR17 (PXA255_DMA_BASE_ADDR + 0x00000144)
-#define PXA255_DRCMR18 (PXA255_DMA_BASE_ADDR + 0x00000148)
-#define PXA255_DRCMR19 (PXA255_DMA_BASE_ADDR + 0x0000014c)
-#define PXA255_DRCMR20 (PXA255_DMA_BASE_ADDR + 0x00000150)
-#define PXA255_DRCMR21 (PXA255_DMA_BASE_ADDR + 0x00000154)
-#define PXA255_DRCMR22 (PXA255_DMA_BASE_ADDR + 0x00000158)
-#define PXA255_DRCMR23 (PXA255_DMA_BASE_ADDR + 0x0000015c)
-#define PXA255_DRCMR24 (PXA255_DMA_BASE_ADDR + 0x00000160)
-#define PXA255_DRCMR25 (PXA255_DMA_BASE_ADDR + 0x00000164)
-#define PXA255_DRCMR26 (PXA255_DMA_BASE_ADDR + 0x00000168)
-#define PXA255_DRCMR27 (PXA255_DMA_BASE_ADDR + 0x0000016c)
-#define PXA255_DRCMR28 (PXA255_DMA_BASE_ADDR + 0x00000170)
-#define PXA255_DRCMR29 (PXA255_DMA_BASE_ADDR + 0x00000174)
-#define PXA255_DRCMR30 (PXA255_DMA_BASE_ADDR + 0x00000178)
-#define PXA255_DRCMR31 (PXA255_DMA_BASE_ADDR + 0x0000017c)
-#define PXA255_DRCMR32 (PXA255_DMA_BASE_ADDR + 0x00000180)
-#define PXA255_DRCMR33 (PXA255_DMA_BASE_ADDR + 0x00000184)
-#define PXA255_DRCMR34 (PXA255_DMA_BASE_ADDR + 0x00000188)
-#define PXA255_DRCMR35 (PXA255_DMA_BASE_ADDR + 0x0000018c)
-#define PXA255_DRCMR36 (PXA255_DMA_BASE_ADDR + 0x00000190)
-#define PXA255_DRCMR37 (PXA255_DMA_BASE_ADDR + 0x00000194)
-#define PXA255_DRCMR38 (PXA255_DMA_BASE_ADDR + 0x00000198)
-#define PXA255_DRCMR39 (PXA255_DMA_BASE_ADDR + 0x0000019c)
-#define PXA255_DDADR0 (PXA255_DMA_BASE_ADDR + 0x00000200)
-#define PXA255_DSADR0 (PXA255_DMA_BASE_ADDR + 0x00000204)
-#define PXA255_DTADR0 (PXA255_DMA_BASE_ADDR + 0x00000208)
-#define PXA255_DCMD0 (PXA255_DMA_BASE_ADDR + 0x0000020c)
-#define PXA255_DDADR1 (PXA255_DMA_BASE_ADDR + 0x00000210)
-#define PXA255_DSADR1 (PXA255_DMA_BASE_ADDR + 0x00000214)
-#define PXA255_DTADR1 (PXA255_DMA_BASE_ADDR + 0x00000218)
-#define PXA255_DCMD1 (PXA255_DMA_BASE_ADDR + 0x0000021c)
-#define PXA255_DDADR2 (PXA255_DMA_BASE_ADDR + 0x00000220)
-#define PXA255_DSADR2 (PXA255_DMA_BASE_ADDR + 0x00000224)
-#define PXA255_DTADR2 (PXA255_DMA_BASE_ADDR + 0x00000228)
-#define PXA255_DCMD2 (PXA255_DMA_BASE_ADDR + 0x0000022c)
-#define PXA255_DDADR3 (PXA255_DMA_BASE_ADDR + 0x00000230)
-#define PXA255_DSADR3 (PXA255_DMA_BASE_ADDR + 0x00000234)
-#define PXA255_DTADR3 (PXA255_DMA_BASE_ADDR + 0x00000238)
-#define PXA255_DCMD3 (PXA255_DMA_BASE_ADDR + 0x0000023c)
-#define PXA255_DDADR4 (PXA255_DMA_BASE_ADDR + 0x00000240)
-#define PXA255_DSADR4 (PXA255_DMA_BASE_ADDR + 0x00000244)
-#define PXA255_DTADR4 (PXA255_DMA_BASE_ADDR + 0x00000248)
-#define PXA255_DCMD4 (PXA255_DMA_BASE_ADDR + 0x0000024c)
-#define PXA255_DDADR5 (PXA255_DMA_BASE_ADDR + 0x00000250)
-#define PXA255_DSADR5 (PXA255_DMA_BASE_ADDR + 0x00000254)
-#define PXA255_DTADR5 (PXA255_DMA_BASE_ADDR + 0x00000258)
-#define PXA255_DCMD5 (PXA255_DMA_BASE_ADDR + 0x0000025c)
-#define PXA255_DDADR6 (PXA255_DMA_BASE_ADDR + 0x00000260)
-#define PXA255_DSADR6 (PXA255_DMA_BASE_ADDR + 0x00000264)
-#define PXA255_DTADR6 (PXA255_DMA_BASE_ADDR + 0x00000268)
-#define PXA255_DCMD6 (PXA255_DMA_BASE_ADDR + 0x0000026c)
-#define PXA255_DDADR7 (PXA255_DMA_BASE_ADDR + 0x00000270)
-#define PXA255_DSADR7 (PXA255_DMA_BASE_ADDR + 0x00000274)
-#define PXA255_DTADR7 (PXA255_DMA_BASE_ADDR + 0x00000278)
-#define PXA255_DCMD7 (PXA255_DMA_BASE_ADDR + 0x0000027c)
-#define PXA255_DDADR8 (PXA255_DMA_BASE_ADDR + 0x00000280)
-#define PXA255_DSADR8 (PXA255_DMA_BASE_ADDR + 0x00000284)
-#define PXA255_DTADR8 (PXA255_DMA_BASE_ADDR + 0x00000288)
-#define PXA255_DCMD8 (PXA255_DMA_BASE_ADDR + 0x0000028c)
-#define PXA255_DDADR9 (PXA255_DMA_BASE_ADDR + 0x00000290)
-#define PXA255_DSADR9 (PXA255_DMA_BASE_ADDR + 0x00000294)
-#define PXA255_DTADR9 (PXA255_DMA_BASE_ADDR + 0x00000298)
-#define PXA255_DCMD9 (PXA255_DMA_BASE_ADDR + 0x0000029c)
-#define PXA255_DDADR10 (PXA255_DMA_BASE_ADDR + 0x000002a0)
-#define PXA255_DSADR10 (PXA255_DMA_BASE_ADDR + 0x000002a4)
-#define PXA255_DTADR10 (PXA255_DMA_BASE_ADDR + 0x000002a8)
-#define PXA255_DCMD10 (PXA255_DMA_BASE_ADDR + 0x000002ac)
-#define PXA255_DDADR11 (PXA255_DMA_BASE_ADDR + 0x000002b0)
-#define PXA255_DSADR11 (PXA255_DMA_BASE_ADDR + 0x000002b4)
-#define PXA255_DTADR11 (PXA255_DMA_BASE_ADDR + 0x000002b8)
-#define PXA255_DCMD11 (PXA255_DMA_BASE_ADDR + 0x000002bc)
-#define PXA255_DDADR12 (PXA255_DMA_BASE_ADDR + 0x000002c0)
-#define PXA255_DSADR12 (PXA255_DMA_BASE_ADDR + 0x000002c4)
-#define PXA255_DTADR12 (PXA255_DMA_BASE_ADDR + 0x000002c8)
-#define PXA255_DCMD12 (PXA255_DMA_BASE_ADDR + 0x000002cc)
-#define PXA255_DDADR13 (PXA255_DMA_BASE_ADDR + 0x000002d0)
-#define PXA255_DSADR13 (PXA255_DMA_BASE_ADDR + 0x000002d4)
-#define PXA255_DTADR13 (PXA255_DMA_BASE_ADDR + 0x000002d8)
-#define PXA255_DCMD13 (PXA255_DMA_BASE_ADDR + 0x000002dc)
-#define PXA255_DDADR14 (PXA255_DMA_BASE_ADDR + 0x000002e0)
-#define PXA255_DSADR14 (PXA255_DMA_BASE_ADDR + 0x000002e4)
-#define PXA255_DTADR14 (PXA255_DMA_BASE_ADDR + 0x000002e8)
-#define PXA255_DCMD14 (PXA255_DMA_BASE_ADDR + 0x000002ec)
-#define PXA255_DDADR15 (PXA255_DMA_BASE_ADDR + 0x000002f0)
- #define PXA255_DDADR_STOP (0x00000001)
-#define PXA255_DSADR15 (PXA255_DMA_BASE_ADDR + 0x000002f4)
-#define PXA255_DTADR15 (PXA255_DMA_BASE_ADDR + 0x000002f8)
-#define PXA255_DCMD15 (PXA255_DMA_BASE_ADDR + 0x000002fc)
- #define PXA255_DCMD_INCSRCADDR (0x80000000)
- #define PXA255_DCMD_INCTRGADDR (0x40000000)
- #define PXA255_DCMD_FLOWSRC (0x20000000)
- #define PXA255_DCMD_FLOWTRG (0x10000000)
- #define PXA255_DCMD_STARTIRQEN (0x00400000)
- #define PXA255_DCMD_ENDIRQEN (0x00200000)
- #define PXA255_DCMD_ENDIAN (0x00040000)
- #define PXA255_DCMD_SIZE (0x00030000)
- #define PXA255_DCMD_SIZE_0 (0x00000000)
- #define PXA255_DCMD_SIZE_8 (0x00010000)
- #define PXA255_DCMD_SIZE_16 (0x00020000)
- #define PXA255_DCMD_SIZE_32 (0x00030000)
- #define PXA255_DCMD_WIDTH (0x0000c000)
- #define PXA255_DCMD_WIDTH_0 (0x00000000)
- #define PXA255_DCMD_WIDTH_1 (0x00004000)
- #define PXA255_DCMD_WIDTH_2 (0x00008000)
- #define PXA255_DCMD_WIDTH_4 (0x0000c000)
-
-/*
-
- PXA255 Inter-Integrated-Circuit Sound (I2S) Controller
-
- pg. 489 to 504, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_I2S_BASE_ADDR (0x40400000)
-#define PXA255_SACR0 (PXA255_I2S_BASE_ADDR + 0x00000000)
- #define PXA255_SACR0_ENB (0x00000001) // Enable I2S function: 0 = Disable, 1 = Enable
- #define PXA255_SACR0_BCKD (0x00000004) // Input/Output direction of BITCLK: 0 = Input, 1 = Output
- #define PXA255_SACR0_RST (0x00000008) // Reset FIFO Logic and all registers: 0 = Not Reset, 1 = Reset is active
- #define PXA255_SACR0_EFWR (0x00000010) // Special-purpose FIFO Write/Read Enable: 0 = Disable, 1 = Enable
- #define PXA255_SACR0_STRF (0x00000020) // Select Transmit or Receive FIFO for EFWR-based special-purpose function: 0 = Xmit FIFO, 1 = Recv FIFO
- #define PXA255_SACR0_TFTH (0x00000f00) // Transmit FIFO interrupt or DMA threshold
- #define PXA255_SACR0_TFTH_S (8)
- #define PXA255_SACR0_RFTH (0x0000f000) // Receive FIFO interrupt or DMA threshold
- #define PXA255_SACR0_RFTH_S (12)
-#define PXA255_SACR1 (PXA255_I2S_BASE_ADDR + 0x00000004)
- #define PXA255_SACR1_AMSL (0x00000001) // Alternate Mode: 0 = I2S Operation Mode, 1 = MSB-Justified Operation Mode
- #define PXA255_SACR1_DREC (0x00000008) // Disable Recording: 0 = Recording Function is enabled, 1 = Recording Function is disabled
- #define PXA255_SACR1_DRPL (0x00000010) // Disable Replaying: 0 = Replaying Function is enabled, 1 = Recording Function is disabled
- #define PXA255_SACR1_ENLBF (0x00000020) // Enable I2S/MSB Interface Loopback
-#define PXA255_SASR0 (PXA255_I2S_BASE_ADDR + 0x0000000c)
- #define PXA255_SASR0_TNF (0x00000001)
- #define PXA255_SASR0_RNE (0x00000002)
- #define PXA255_SASR0_BSY (0x00000004)
- #define PXA255_SASR0_TFS (0x00000008)
- #define PXA255_SASR0_RFS (0x00000010)
- #define PXA255_SASR0_TUR (0x00000020)
- #define PXA255_SASR0_ROR (0x00000040)
- #define PXA255_SASR0_TFL (0x00000f00)
- #define PXA255_SASR0_RFL (0x0000f000)
-#define PXA255_SAIMR (PXA255_I2S_BASE_ADDR + 0x00000014)
- #define PXA255_SAIMR_TFS (0x00000008)
- #define PXA255_SAIMR_RFS (0x00000010)
- #define PXA255_SAIMR_TUR (0x00000020)
- #define PXA255_SAIMR_ROR (0x00000040)
-#define PXA255_SAICR (PXA255_I2S_BASE_ADDR + 0x00000018)
- #define PXA255_SAICR_TUR (0x00000020)
- #define PXA255_SAICR_ROR (0x00000040)
-#define PXA255_SADIV (PXA255_I2S_BASE_ADDR + 0x00000060)
-#define PXA255_SADR (PXA255_I2S_BASE_ADDR + 0x00000080)
-
-/*
-
- PXA255 Real-Time Clock
-
- pg. 132 to 138, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_RTC_BASE_ADDR (0x40900000)
-#define PXA255_RCNR (PXA255_RTC_BASE_ADDR + 0x00000000)
-#define PXA255_RTAR (PXA255_RTC_BASE_ADDR + 0x00000004)
-#define PXA255_RTSR (PXA255_RTC_BASE_ADDR + 0x00000008)
-#define PXA255_RTTR (PXA255_RTC_BASE_ADDR + 0x0000000c)
-
-/*
-
- PXA255 OS Timer register
-
- pg. 138 to 142, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_OSTMR_BASE_ADDR (0x40a00000)
-#define PXA255_OSMR0 (PXA255_OSTMR_BASE_ADDR + 0x00000000)
-#define PXA255_OSMR1 (PXA255_OSTMR_BASE_ADDR + 0x00000004)
-#define PXA255_OSMR2 (PXA255_OSTMR_BASE_ADDR + 0x00000008)
-#define PXA255_OSMR3 (PXA255_OSTMR_BASE_ADDR + 0x0000000c)
-#define PXA255_OSCR (PXA255_OSTMR_BASE_ADDR + 0x00000010)
-#define PXA255_OSSR (PXA255_OSTMR_BASE_ADDR + 0x00000014)
- #define PXA255_OSSR_M0 (0x00000001)
- #define PXA255_OSSR_M1 (0x00000002)
- #define PXA255_OSSR_M2 (0x00000004)
- #define PXA255_OSSR_M3 (0x00000008)
-#define PXA255_OWER (PXA255_OSTMR_BASE_ADDR + 0x00000018)
-#define PXA255_OIER (PXA255_OSTMR_BASE_ADDR + 0x0000001c)
- #define PXA255_OIER_E0 (0x00000001)
- #define PXA255_OIER_E1 (0x00000002)
- #define PXA255_OIER_E2 (0x00000004)
- #define PXA255_OIER_E3 (0x00000008)
-
-/*
-
- PXA255 Interrupt registers
-
- pg. 124 to 132, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_INTC_BASE_ADDR (0x40d00000)
-#define PXA255_ICIP (PXA255_INTC_BASE_ADDR + 0x00000000)
-#define PXA255_ICMR (PXA255_INTC_BASE_ADDR + 0x00000004)
-#define PXA255_ICLR (PXA255_INTC_BASE_ADDR + 0x00000008)
-#define PXA255_ICFP (PXA255_INTC_BASE_ADDR + 0x0000000c)
-#define PXA255_ICPR (PXA255_INTC_BASE_ADDR + 0x00000010)
-#define PXA255_ICCR (PXA255_INTC_BASE_ADDR + 0x00000014)
-
-#define PXA255_INT_HUART (1 << 7)
-#define PXA255_INT_GPIO0 (1 << 8)
-#define PXA255_INT_GPIO1 (1 << 9)
-#define PXA255_INT_GPIO84_2 (1 << 10)
-#define PXA255_INT_USB (1 << 11)
-#define PXA255_INT_PMU (1 << 12)
-#define PXA255_INT_I2S (1 << 13)
-#define PXA255_INT_AC97 (1 << 14)
-#define PXA255_INT_NETWORK (1 << 16)
-#define PXA255_INT_LCD (1 << 17)
-#define PXA255_INT_I2C (1 << 18)
-#define PXA255_INT_ICP (1 << 19)
-#define PXA255_INT_STUART (1 << 20)
-#define PXA255_INT_BTUART (1 << 21)
-#define PXA255_INT_FFUART (1 << 22)
-#define PXA255_INT_MMC (1 << 23)
-#define PXA255_INT_SSP (1 << 24)
-#define PXA255_INT_DMA (1 << 25)
-#define PXA255_INT_OSTIMER0 (1 << 26)
-#define PXA255_INT_OSTIMER1 (1 << 27)
-#define PXA255_INT_OSTIMER2 (1 << 28)
-#define PXA255_INT_OSTIMER3 (1 << 29)
-#define PXA255_INT_RTC_HZ (1 << 30)
-#define PXA255_INT_RTC_ALARM (1 << 31)
-
-/*
-
- PXA255 General-Purpose I/O registers
-
- pg. 105 to 124, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_GPIO_BASE_ADDR (0x40e00000)
-#define PXA255_GPLR0 (PXA255_GPIO_BASE_ADDR + 0x00000000)
-#define PXA255_GPLR1 (PXA255_GPIO_BASE_ADDR + 0x00000004)
-#define PXA255_GPLR2 (PXA255_GPIO_BASE_ADDR + 0x00000008)
-#define PXA255_GPDR0 (PXA255_GPIO_BASE_ADDR + 0x0000000c)
-#define PXA255_GPDR1 (PXA255_GPIO_BASE_ADDR + 0x00000010)
-#define PXA255_GPDR2 (PXA255_GPIO_BASE_ADDR + 0x00000014)
-#define PXA255_GPSR0 (PXA255_GPIO_BASE_ADDR + 0x00000018)
-#define PXA255_GPSR1 (PXA255_GPIO_BASE_ADDR + 0x0000001c)
-#define PXA255_GPSR2 (PXA255_GPIO_BASE_ADDR + 0x00000020)
-#define PXA255_GPCR0 (PXA255_GPIO_BASE_ADDR + 0x00000024)
-#define PXA255_GPCR1 (PXA255_GPIO_BASE_ADDR + 0x00000028)
-#define PXA255_GPCR2 (PXA255_GPIO_BASE_ADDR + 0x0000002c)
-#define PXA255_GRER0 (PXA255_GPIO_BASE_ADDR + 0x00000030)
-#define PXA255_GRER1 (PXA255_GPIO_BASE_ADDR + 0x00000034)
-#define PXA255_GRER2 (PXA255_GPIO_BASE_ADDR + 0x00000038)
-#define PXA255_GFER0 (PXA255_GPIO_BASE_ADDR + 0x0000003c)
-#define PXA255_GFER1 (PXA255_GPIO_BASE_ADDR + 0x00000040)
-#define PXA255_GFER2 (PXA255_GPIO_BASE_ADDR + 0x00000044)
-#define PXA255_GEDR0 (PXA255_GPIO_BASE_ADDR + 0x00000048)
-#define PXA255_GEDR1 (PXA255_GPIO_BASE_ADDR + 0x0000004c)
-#define PXA255_GEDR2 (PXA255_GPIO_BASE_ADDR + 0x00000050)
-#define PXA255_GAFR0_L (PXA255_GPIO_BASE_ADDR + 0x00000054)
-#define PXA255_GAFR0_U (PXA255_GPIO_BASE_ADDR + 0x00000058)
-#define PXA255_GAFR1_L (PXA255_GPIO_BASE_ADDR + 0x0000005c)
-#define PXA255_GAFR1_U (PXA255_GPIO_BASE_ADDR + 0x00000060)
-#define PXA255_GAFR2_L (PXA255_GPIO_BASE_ADDR + 0x00000064)
-#define PXA255_GAFR2_U (PXA255_GPIO_BASE_ADDR + 0x00000068)
-
-/*
-
- PXA255 LCD Controller
-
- pg. 265 to 310, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_LCD_BASE_ADDR (0x44000000)
-#define PXA255_LCCR0 (PXA255_LCD_BASE_ADDR + 0x00000000)
- #define PXA255_LCCR0_OUM (0x00200000)
- #define PXA255_LCCR0_BM (0x00100000)
- #define PXA255_LCCR0_PDD (0x000ff000)
- #define PXA255_LCCR0_QDM (0x00000800)
- #define PXA255_LCCR0_DIS (0x00000400)
- #define PXA255_LCCR0_DPD (0x00000200)
- #define PXA255_LCCR0_PAS (0x00000080)
- #define PXA255_LCCR0_EFM (0x00000040)
- #define PXA255_LCCR0_IUM (0x00000020)
- #define PXA255_LCCR0_SFM (0x00000010)
- #define PXA255_LCCR0_LDM (0x00000008)
- #define PXA255_LCCR0_SDS (0x00000004)
- #define PXA255_LCCR0_CMS (0x00000002)
- #define PXA255_LCCR0_ENB (0x00000001)
-#define PXA255_LCCR1 (PXA255_LCD_BASE_ADDR + 0x00000004)
- #define PXA255_LCCR1_PPL (0x000003ff)
-#define PXA255_LCCR2 (PXA255_LCD_BASE_ADDR + 0x00000008)
- #define PXA255_LCCR2_LPP (0x000003ff)
-#define PXA255_LCCR3 (PXA255_LCD_BASE_ADDR + 0x0000000c)
-#define PXA255_FBR0 (PXA255_LCD_BASE_ADDR + 0x00000020)
- #define PXA255_FBR_BAR (0x00000001)
- #define PXA255_FBR_BINT (0x00000003)
-#define PXA255_FBR1 (PXA255_LCD_BASE_ADDR + 0x00000024)
-#define PXA255_LCSR (PXA255_LCD_BASE_ADDR + 0x00000038)
- #define PXA255_LCSR_LDD (0x00000001)
- #define PXA255_LCSR_SOF (0x00000002)
- #define PXA255_LCSR_BER (0x00000004)
- #define PXA255_LCSR_ABC (0x00000008)
- #define PXA255_LCSR_IUL (0x00000010)
- #define PXA255_LCSR_IUU (0x00000020)
- #define PXA255_LCSR_OU (0x00000040)
- #define PXA255_LCSR_QD (0x00000080)
- #define PXA255_LCSR_EOF (0x00000100)
- #define PXA255_LCSR_BS (0x00000200)
- #define PXA255_LCSR_SINT (0x00000400)
-#define PXA255_LIIDR (PXA255_LCD_BASE_ADDR + 0x0000003c)
-#define PXA255_TRGBR (PXA255_LCD_BASE_ADDR + 0x00000040)
-#define PXA255_TCR (PXA255_LCD_BASE_ADDR + 0x00000044)
-#define PXA255_FDADR0 (PXA255_LCD_BASE_ADDR + 0x00000200)
-#define PXA255_FSADR0 (PXA255_LCD_BASE_ADDR + 0x00000204)
-#define PXA255_FIDR0 (PXA255_LCD_BASE_ADDR + 0x00000208)
-#define PXA255_LDCMD0 (PXA255_LCD_BASE_ADDR + 0x0000020c)
- #define PXA255_LDCMD_EOFINT (0x00200000)
- #define PXA255_LDCMD_SOFINT (0x00400000)
- #define PXA255_LDCMD_PAL (0x04000000)
-#define PXA255_FDADR1 (PXA255_LCD_BASE_ADDR + 0x00000210)
-#define PXA255_FSADR1 (PXA255_LCD_BASE_ADDR + 0x00000214)
-#define PXA255_FIDR1 (PXA255_LCD_BASE_ADDR + 0x00000218)
-#define PXA255_LDCMD1 (PXA255_LCD_BASE_ADDR + 0x0000021c)
-
-/*
- PXA255 Power controller
-
- pg. 85 to 96, PXA255 Processor Developers Manual [278693-002].pdf
-*/
-
-#define PXA255_POWER_BASE_ADDR (0x40f00000)
-#define PXA255_PMCR (PXA255_POWER_BASE_ADDR + 0x00000000)
-#define PXA255_PSSR (PXA255_POWER_BASE_ADDR + 0x00000004)
-#define PXA255_PSPR (PXA255_POWER_BASE_ADDR + 0x00000008)
-#define PXA255_PWER (PXA255_POWER_BASE_ADDR + 0x0000000c)
-#define PXA255_PRER (PXA255_POWER_BASE_ADDR + 0x00000010)
-#define PXA255_PFER (PXA255_POWER_BASE_ADDR + 0x00000014)
-#define PXA255_PEDR (PXA255_POWER_BASE_ADDR + 0x00000018)
-#define PXA255_PCFR (PXA255_POWER_BASE_ADDR + 0x0000001c)
-#define PXA255_PGSR0 (PXA255_POWER_BASE_ADDR + 0x00000020)
-#define PXA255_PGSR1 (PXA255_POWER_BASE_ADDR + 0x00000024)
-#define PXA255_PGSR2 (PXA255_POWER_BASE_ADDR + 0x00000028)
-#define PXA255_RCSR (PXA255_POWER_BASE_ADDR + 0x00000030)
-#define PXA255_PMFW (PXA255_POWER_BASE_ADDR + 0x00000034)
-
-/*
- PXA255 Clock controller
-
- pg. 96 to 100, PXA255 Processor Developers Manual [278693-002].pdf
-
-*/
-
-#define PXA255_CLOCKS_BASE_ADDR (0x41300000)
-#define PXA255_CCCR (PXA255_CLOCKS_BASE_ADDR + 0x00000000)
-#define PXA255_CKEN (PXA255_CLOCKS_BASE_ADDR + 0x00000004)
-#define PXA255_OSCC (PXA255_CLOCKS_BASE_ADDR + 0x00000008)
-
-#endif // MAME_MACHINE_PXA255DEFS
diff --git a/src/devices/machine/r10696.cpp b/src/devices/machine/r10696.cpp
index ce9140ef7d5..2172c9d1b86 100644
--- a/src/devices/machine/r10696.cpp
+++ b/src/devices/machine/r10696.cpp
@@ -30,7 +30,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/r10696.h"
+#include "r10696.h"
//#define VERBOSE 1
#include "logmacro.h"
@@ -47,7 +47,7 @@ DEFINE_DEVICE_TYPE(R10696, r10696_device, "r10696", "Rockwell 10696 GPIO")
r10696_device::r10696_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, R10696, tag, owner, clock)
, m_io_a(0), m_io_b(0), m_io_c(0)
- , m_iord(*this), m_iowr(*this)
+ , m_iord(*this, 0), m_iowr(*this)
{
}
@@ -56,9 +56,6 @@ r10696_device::r10696_device(const machine_config &mconfig, const char *tag, dev
*/
void r10696_device::device_start()
{
- m_iord.resolve();
- m_iowr.resolve();
-
save_item(NAME(m_io_a));
save_item(NAME(m_io_b));
save_item(NAME(m_io_c));
diff --git a/src/devices/machine/r10788.cpp b/src/devices/machine/r10788.cpp
index c273c70a4ee..fd8e69c9b3c 100644
--- a/src/devices/machine/r10788.cpp
+++ b/src/devices/machine/r10788.cpp
@@ -13,7 +13,7 @@
KTR 1 1 x x x 1 1 0 0 Transfer Keyboard Return
KTS 1 1 x x x 1 0 1 0 Transfer Keyboard Strobe
KLA 1 1 x x x 1 1 1 0 Load Display Register A
- KLB 1 1 x x x 1 1 0 1 Load Display Register A
+ KLB 1 1 x x x 1 1 0 1 Load Display Register B
KDN 1 1 x x x 0 0 1 1 Turn On Display
KAF 1 1 x x x 1 0 1 1 Turn Off A
KBF 1 1 x x x 0 1 1 1 Turn Off B
@@ -34,10 +34,13 @@
7.) KER takes a maximum of 10-bit times to complete (= 80 clocks)
Therefore, there must be at least 10 bit times between KER
and the next KTS instruction.
+ 8.) This device has only been tested on the gts1 driver. It does
+ not use the keyboard. The digit data is inverted (so it stores
+ 6 when we want to display 9).
**********************************************************************/
#include "emu.h"
-#include "machine/r10788.h"
+#include "r10788.h"
//#define VERBOSE 1
#include "logmacro.h"
@@ -64,8 +67,6 @@ r10788_device::r10788_device(const machine_config &mconfig, const char *tag, dev
*/
void r10788_device::device_start()
{
- m_display.resolve();
-
save_item(NAME(m_reg));
save_item(NAME(m_ktr));
save_item(NAME(m_kts));
@@ -77,7 +78,7 @@ void r10788_device::device_start()
save_item(NAME(m_io_counter));
save_item(NAME(m_scan_counter));
- m_timer = timer_alloc(TIMER_DISPLAY);
+ m_timer = timer_alloc(FUNC(r10788_device::display_update), this);
// recurring timer every 36 cycles
m_timer->adjust(clocks_to_attotime(36), 0, clocks_to_attotime(36));
}
@@ -99,27 +100,11 @@ void r10788_device::device_reset()
}
-/**
- * @brief r10788_device::device_timer timer event callback
- * @param timer emu_timer which fired
- * @param id timer identifier
- * @param param parameter
- * @param ptr pointer parameter
- */
-void r10788_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(r10788_device::display_update)
{
- uint8_t data;
- switch (id)
- {
- case TIMER_DISPLAY:
- data = (m_reg[0][m_scan_counter] & m_mask_a) +
- 16 * (m_reg[1][m_scan_counter] & m_mask_b);
- LOG("%s: scan counter:%2d data:%02x\n", __FUNCTION__, m_scan_counter, data);
- m_display(m_scan_counter, data, 0xff);
- break;
- default:
- LOG("%s: invalid timer id:%d\n", __FUNCTION__, id);
- }
+ uint8_t data = ((m_reg[1][m_scan_counter] & m_mask_b) << 4) | (m_reg[0][m_scan_counter] & m_mask_a);
+ LOG("display_update: scan counter:%2d data:%02x\n", m_scan_counter, data);
+ m_display(m_scan_counter, data, 0xff);
m_scan_counter = (m_scan_counter + 1) % 16;
}
@@ -137,7 +122,7 @@ void r10788_device::device_timer(emu_timer &timer, device_timer_id id, int param
void r10788_device::io_w(offs_t offset, uint8_t data)
{
- assert(offset < 16);
+ offset &= 15;
switch (offset)
{
case KTR: // Transfer Keyboard Return
@@ -149,6 +134,7 @@ void r10788_device::io_w(offs_t offset, uint8_t data)
m_kts = data;
break;
case KLA: // Load Display Register A
+ m_io_counter = (m_io_counter + 1) % 16;
LOG("%s: KLA [%2d] data:%02x\n", __FUNCTION__, m_io_counter, data);
m_kla = data;
m_reg[0][m_io_counter] = m_kla;
@@ -156,21 +142,22 @@ void r10788_device::io_w(offs_t offset, uint8_t data)
case KLB: // Load Display Register B
LOG("%s: KLB [%2d] data:%02x\n", __FUNCTION__, m_io_counter, data);
m_klb = data;
- m_reg[1][m_io_counter] = m_kla;
+ m_reg[1][m_io_counter] = m_klb;
break;
case KDN: // Turn On Display
LOG("%s: KDN data:%02x\n", __FUNCTION__, data);
m_mask_a = 15;
m_mask_b = 15;
+ m_io_counter = 15;
break;
case KAF: // Turn Off A
LOG("%s: KAF data:%02x\n", __FUNCTION__, data);
m_mask_a = 0;
- m_mask_b &= ~3;
+ m_mask_b &= 12;
break;
case KBF: // Turn Off B
LOG("%s: KBF data:%02x\n", __FUNCTION__, data);
- m_mask_b &= ~12;
+ m_mask_b &= 3;
break;
case KER: // Reset Keyboard Error
LOG("%s: KER data:%02x\n", __FUNCTION__, data);
@@ -182,7 +169,7 @@ void r10788_device::io_w(offs_t offset, uint8_t data)
uint8_t r10788_device::io_r(offs_t offset)
{
- assert(offset < 16);
+ offset &= 15;
uint8_t data = 0xf;
switch (offset)
{
@@ -203,8 +190,6 @@ uint8_t r10788_device::io_r(offs_t offset)
m_klb = m_reg[1][m_io_counter];
data = m_klb;
LOG("%s: KLB [%2d] data:%02x\n", __FUNCTION__, m_io_counter, data);
- // FIXME: does it automagically increment at KLB write?
- m_io_counter = (m_io_counter + 1) % 16;
break;
case KDN: // Turn On Display
LOG("%s: KDN data:%02x\n", __FUNCTION__, data);
diff --git a/src/devices/machine/r10788.h b/src/devices/machine/r10788.h
index 6ef21ccc466..9a94ad65b5c 100644
--- a/src/devices/machine/r10788.h
+++ b/src/devices/machine/r10788.h
@@ -43,11 +43,10 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-private:
- static const device_timer_id TIMER_DISPLAY = 0;
+ TIMER_CALLBACK_MEMBER(display_update);
+private:
uint8_t m_reg[2][16]; //!< display registers
uint8_t m_ktr; //!< transfer keyboard return value
uint8_t m_kts; //!< transfer keyboard strobe value
diff --git a/src/devices/machine/ra17xx.cpp b/src/devices/machine/ra17xx.cpp
index 3cf2c5775e7..a49205695a0 100644
--- a/src/devices/machine/ra17xx.cpp
+++ b/src/devices/machine/ra17xx.cpp
@@ -38,7 +38,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/ra17xx.h"
+#include "ra17xx.h"
//#define VERBOSE 1
#include "logmacro.h"
@@ -55,7 +55,7 @@ DEFINE_DEVICE_TYPE(RA17XX, ra17xx_device, "ra17xx", "Rockwell A17xx")
ra17xx_device::ra17xx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, RA17XX, tag, owner, clock)
, m_enable(false)
- , m_iord(*this)
+ , m_iord(*this, 0)
, m_iowr(*this)
, m_cpu(*this, finder_base::DUMMY_TAG)
{
@@ -66,9 +66,6 @@ ra17xx_device::ra17xx_device(const machine_config &mconfig, const char *tag, dev
*/
void ra17xx_device::device_start()
{
- m_iord.resolve();
- m_iowr.resolve();
-
save_item(NAME(m_line));
}
@@ -104,7 +101,7 @@ void ra17xx_device::io_w(address_space &space, offs_t offset, uint8_t data)
// SOS command
if (m_bl >= 16)
{
- logerror("Attempt to write to nonexistent output %d\n");
+ logerror("Attempt to write to nonexistent output 0x%02X\n",m_bl);
}
else if (data & (1 << 3))
{
diff --git a/src/devices/machine/ram.cpp b/src/devices/machine/ram.cpp
index 30195810ac2..40b361bdc6a 100644
--- a/src/devices/machine/ram.cpp
+++ b/src/devices/machine/ram.cpp
@@ -1,15 +1,24 @@
// license:BSD-3-Clause
-// copyright-holders: Dirk Best
+// copyright-holders:Nathan Woods, Dirk Best
/*************************************************************************
- RAM device
+RAM device
- Provides a configurable amount of RAM to drivers
+Provides a configurable amount of RAM to drivers
+
+TODO:
+- add RAM size options to UI, eg. under Machine Configuration
+- remove limitations due to hardcoded RAM_TAG:
+ + *configurable* RAM device can only be added to root device
+ (that is the driver device)
+ + can only have one *configurable* RAM device per machine driver
**************************************************************************/
#include "emu.h"
#include "ram.h"
+
+#include "corestr.h"
#include "emuopts.h"
#include <cstdio>
@@ -115,7 +124,7 @@ ram_device::ram_device(const machine_config &mconfig, const char *tag, device_t
: device_t(mconfig, RAM, tag, owner, clock)
, m_size(0)
, m_default_size(0)
- , m_default_value(0xCD)
+ , m_default_value(0xff)
, m_extra_options_string(nullptr)
{
}
diff --git a/src/devices/machine/ram.h b/src/devices/machine/ram.h
index 2af1f800ab4..8b17b3eadc5 100644
--- a/src/devices/machine/ram.h
+++ b/src/devices/machine/ram.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders: Dirk Best
+// copyright-holders:Nathan Woods, Dirk Best
/*************************************************************************
RAM device
@@ -42,7 +42,7 @@ public:
u32 size() const { return m_size; }
u32 mask() const { return m_size - 1; }
u8 *pointer() { return &m_pointer[0]; }
- char const *default_size_string() const { return m_default_size; };
+ char const *default_size_string() const { return m_default_size; }
u32 default_size() const;
extra_option_vector const &extra_options() const;
diff --git a/src/devices/machine/rf5c296.cpp b/src/devices/machine/rf5c296.cpp
index f0756c60471..37a0adf3a3b 100644
--- a/src/devices/machine/rf5c296.cpp
+++ b/src/devices/machine/rf5c296.cpp
@@ -18,7 +18,7 @@ void rf5c296_device::device_start()
{
}
-void rf5c296_device::reg_w(ATTR_UNUSED uint8_t reg, uint8_t data)
+void rf5c296_device::reg_w(uint8_t reg, uint8_t data)
{
// fprintf(stderr, "%s rf5c296_reg_w %02x, %02x\n", machine().describe_context().c_str(), reg, data);
switch (reg)
@@ -37,7 +37,7 @@ void rf5c296_device::reg_w(ATTR_UNUSED uint8_t reg, uint8_t data)
}
}
-uint8_t rf5c296_device::reg_r(ATTR_UNUSED uint8_t reg)
+uint8_t rf5c296_device::reg_r(uint8_t reg)
{
// fprintf(stderr, "%s rf5c296_reg_r %02x\n", machine().describe_context().c_str(), reg);
return 0x00;
diff --git a/src/devices/machine/rf5c296.h b/src/devices/machine/rf5c296.h
index b2d0f68a3cf..b5f3beea7fc 100644
--- a/src/devices/machine/rf5c296.h
+++ b/src/devices/machine/rf5c296.h
@@ -26,8 +26,8 @@ protected:
virtual void device_start() override;
private:
- void reg_w(ATTR_UNUSED uint8_t reg, uint8_t data);
- uint8_t reg_r(ATTR_UNUSED uint8_t reg);
+ void reg_w(uint8_t reg, uint8_t data);
+ uint8_t reg_r(uint8_t reg);
unsigned char m_rf5c296_reg;
required_device<pccard_slot_device> m_pccard;
diff --git a/src/devices/machine/ripple_counter.cpp b/src/devices/machine/ripple_counter.cpp
index 96ce53aeec6..6c60d7238a5 100644
--- a/src/devices/machine/ripple_counter.cpp
+++ b/src/devices/machine/ripple_counter.cpp
@@ -15,7 +15,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/ripple_counter.h"
+#include "ripple_counter.h"
//**************************************************************************
// GLOBAL VARIABLES
@@ -33,16 +33,16 @@ DEFINE_DEVICE_TYPE(RIPPLE_COUNTER, ripple_counter_device, "ripple_counter", "Gen
// ripple_counter_device - constructor
//-------------------------------------------------
-ripple_counter_device::ripple_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, RIPPLE_COUNTER, tag, owner, clock),
- device_rom_interface(mconfig, *this),
- m_count_out_cb(*this),
- m_rom_out_cb(*this),
- m_count_timer(nullptr),
- m_count_mask(0),
- m_count(1),
- m_clk(false),
- m_reset(false)
+ripple_counter_device::ripple_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, RIPPLE_COUNTER, tag, owner, clock),
+ device_rom_interface(mconfig, *this),
+ m_count_out_cb(*this),
+ m_rom_out_cb(*this),
+ m_count_timer(nullptr),
+ m_count_mask(0),
+ m_count(1),
+ m_clk(false),
+ m_reset(false)
{
}
@@ -54,7 +54,7 @@ ripple_counter_device::ripple_counter_device(const machine_config &mconfig, cons
device_memory_interface::space_config_vector ripple_counter_device::memory_space_config() const
{
- if (m_rom_out_cb.isnull())
+ if (m_rom_out_cb.isunset())
return space_config_vector();
else
return device_rom_interface::memory_space_config();
@@ -74,27 +74,13 @@ void ripple_counter_device::device_validity_check(validity_checker &valid) const
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void ripple_counter_device::device_resolve_objects()
-{
- // resolve callbacks
- m_count_out_cb.resolve_safe();
- m_rom_out_cb.resolve();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void ripple_counter_device::device_start()
{
// initialize timers
- m_count_timer = timer_alloc(TIMER_COUNT);
+ m_count_timer = timer_alloc(FUNC(ripple_counter_device::advance_counter), this);
// register internal state
save_item(NAME(m_count));
@@ -116,11 +102,11 @@ void ripple_counter_device::device_clock_changed()
//-------------------------------------------------
-// rom_bank_updated - called when the ROM bank
-// is changed
+// rom_bank_post_change - called after the ROM
+// bank is changed
//-------------------------------------------------
-void ripple_counter_device::rom_bank_updated()
+void ripple_counter_device::rom_bank_post_change()
{
m_rom_out_cb(read_byte(m_count));
}
@@ -135,7 +121,7 @@ void ripple_counter_device::set_count(u32 count)
{
m_count = count;
m_count_out_cb(count);
- if (!m_rom_out_cb.isnull())
+ if (!m_rom_out_cb.isunset())
m_rom_out_cb(read_byte(count));
}
@@ -144,7 +130,7 @@ void ripple_counter_device::set_count(u32 count)
// clock_w - handle falling-edge clock input
//-------------------------------------------------
-WRITE_LINE_MEMBER(ripple_counter_device::clock_w)
+void ripple_counter_device::clock_w(int state)
{
if (m_clk != bool(state))
{
@@ -159,7 +145,7 @@ WRITE_LINE_MEMBER(ripple_counter_device::clock_w)
// reset_w - handle active-high reset input
//-------------------------------------------------
-WRITE_LINE_MEMBER(ripple_counter_device::reset_w)
+void ripple_counter_device::reset_w(int state)
{
if (m_reset != bool(state))
{
@@ -174,16 +160,10 @@ WRITE_LINE_MEMBER(ripple_counter_device::reset_w)
//-------------------------------------------------
-// device_timer - called whenever a device timer
-// fires
+// advance_counter -
//-------------------------------------------------
-void ripple_counter_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ripple_counter_device::advance_counter)
{
- switch (id)
- {
- case TIMER_COUNT:
- set_count((m_count + 1) & m_count_mask);
- break;
- }
+ set_count((m_count + 1) & m_count_mask);
}
diff --git a/src/devices/machine/ripple_counter.h b/src/devices/machine/ripple_counter.h
index 450dc2118bb..3a623a3ce35 100644
--- a/src/devices/machine/ripple_counter.h
+++ b/src/devices/machine/ripple_counter.h
@@ -31,23 +31,23 @@ public:
auto rom_out_cb() { return m_rom_out_cb.bind(); }
// control line handlers
- DECLARE_WRITE_LINE_MEMBER(clock_w);
- DECLARE_WRITE_LINE_MEMBER(reset_w);
+ void clock_w(int state);
+ void reset_w(int state);
// getters
u32 count() const { return m_count; }
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_validity_check(validity_checker &valid) const override;
- virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_clock_changed() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- // device_rom_interface overrides
+ // device_rom_interface implementation
virtual space_config_vector memory_space_config() const override;
- virtual void rom_bank_updated() override;
+ virtual void rom_bank_post_change() override;
+
+ TIMER_CALLBACK_MEMBER(advance_counter);
private:
// internal helpers
@@ -58,10 +58,6 @@ private:
devcb_write8 m_rom_out_cb;
// device timers
- enum
- {
- TIMER_COUNT
- };
emu_timer *m_count_timer;
// configuration parameters
diff --git a/src/devices/machine/roc10937.cpp b/src/devices/machine/roc10937.cpp
index e50c0a48710..9e64e5ce4fb 100644
--- a/src/devices/machine/roc10937.cpp
+++ b/src/devices/machine/roc10937.cpp
@@ -3,7 +3,7 @@
/**********************************************************************
Rockwell 10937/10957 interface and emulation by J.Wallace
- OKI MSC1937 is a clone of this chip
+ OKI MSC1937 is a clone of this chip, used in many displays
**********************************************************************/
@@ -14,7 +14,7 @@
/*
- Rockwell 10937 16 segment charset lookup table
+ Rockwell 10937 16 segment charset lookup table (from MCU)
0 1
---- ----
|\ | /|
@@ -33,7 +33,8 @@ a charset.
Note that, although we call this a '16 segment' display,
we actually have 18 segments, including the semicolon portions.
-16-bit tables are used to hold the main characters, the rest are OR'd in
+16-bit tables are used to hold the main characters in the MCU memory,
+the other characters come in separate to this lookup.
*/
static const uint16_t roc10937charset[]=
@@ -131,6 +132,7 @@ static const int roc10937poslut[]=
rocvfd_device::rocvfd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
m_outputs(),
+ m_cursor_pos(0),
m_port_val(0)
{
}
@@ -141,43 +143,49 @@ void rocvfd_device::device_start()
m_outputs = std::make_unique<output_finder<16> >(*this, "vfd%u", unsigned(m_port_val * 16));
m_outputs->resolve();
+ m_brightness = std::make_unique<output_finder<1> >(*this, "vfdduty%u", unsigned(m_port_val));
+ m_brightness->resolve();
+
+ m_sclk = 0;
+ m_data = 0;
+ m_por = 0;
+
save_item(NAME(m_cursor_pos));
save_item(NAME(m_window_size));
save_item(NAME(m_shift_count));
save_item(NAME(m_shift_data));
save_item(NAME(m_pcursor_pos));
save_item(NAME(m_chars));
- save_item(NAME(m_brightness));
save_item(NAME(m_count));
save_item(NAME(m_sclk));
save_item(NAME(m_data));
+ save_item(NAME(m_por));
save_item(NAME(m_duty));
- save_item(NAME(m_disp));
+
+ std::fill(std::begin(m_chars), std::end(m_chars), 0);
+ std::fill(std::begin(*m_outputs), std::end(*m_outputs), 0);
+
}
void rocvfd_device::device_reset()
{
+ //We don't clear the buffers on reset as JPM games rely on the buffers being intact after POR
+ //On real hardware, garbage patterns can appear unless specifically cleared, so this makes sense.
m_cursor_pos = 0;
m_window_size = 16;
m_shift_count = 0;
m_shift_data = 0;
m_pcursor_pos = 0;
- m_brightness =31;
- m_count=0;
- m_duty=31;
- m_disp = 0;
- m_sclk = 0;
- m_data = 0;
+ m_count = 0;
+ m_duty = 0;
- std::fill(std::begin(m_chars), std::end(m_chars), 0);
- std::fill(std::begin(*m_outputs), std::end(*m_outputs), 0);
+ (*m_brightness)[0] = 0;
}
///////////////////////////////////////////////////////////////////////////
uint32_t rocvfd_device::set_display(uint32_t segin)
{
return bitswap<32>(segin, 31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,11,9,15,13,12,8,10,14,7,6,5,4,3,2,1,0);
-
}
///////////////////////////////////////////////////////////////////////////
@@ -189,25 +197,34 @@ void rocvfd_device::device_post_load()
void rocvfd_device::update_display()
{
std::transform(std::begin(m_chars), std::end(m_chars), std::begin(*m_outputs), set_display);
+ (*m_brightness)[0] = m_duty;
}
-WRITE_LINE_MEMBER( rocvfd_device::sclk )
+void rocvfd_device::sclk(int state)
{
shift_clock(state);
}
-WRITE_LINE_MEMBER( rocvfd_device::data )
+void rocvfd_device::data(int state)
{
- m_data = state;
+ if (state)
+ {
+ m_data = 1;
+ }
+ else
+ {
+ m_data = 0;
+ }
}
-WRITE_LINE_MEMBER( rocvfd_device::por )
+void rocvfd_device::por(int state)
{
//If line goes low, reset mode is engaged, until such a time as it goes high again.
if (!state)
{
reset();
}
+ m_por = state;
}
@@ -216,7 +233,7 @@ void rocvfd_device::shift_clock(int state)
if (m_sclk != state)
{
//Clock data on FALLING edge
- if (!m_sclk)
+ if (!m_sclk && m_por)
{
m_shift_data <<= 1;
@@ -229,10 +246,9 @@ void rocvfd_device::shift_clock(int state)
m_shift_data = 0;
}
update_display();
-
}
+ m_sclk = state;
}
- m_sclk = state;
}
///////////////////////////////////////////////////////////////////////////
@@ -240,7 +256,7 @@ DEFINE_DEVICE_TYPE(ROC10937, roc10937_device, "roc10937", "Rockwell 10937 VFD co
DEFINE_DEVICE_TYPE(MSC1937, msc1937_device, "msc1937", "OKI MSC1937 VFD controller")
DEFINE_DEVICE_TYPE(MIC10937, mic10937_device, "mic10937", "Micrel MIC10937 VFD controller")
DEFINE_DEVICE_TYPE(ROC10957, roc10957_device, "roc10957", "Rockwell 10957 VFD controller") // and compatible
-DEFINE_DEVICE_TYPE(S16LF01, s16lf01_device, "s16lf01", "Samsung 16LF01 Series VFD controller") // and compatible
+DEFINE_DEVICE_TYPE(S16LF01, s16lf01_device, "s16lf01", "Samsung 16LF01 Series VFD") // and compatible, basically the MSC1937 on a 16 seg display
roc10937_device::roc10937_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: rocvfd_device(mconfig, ROC10937, tag, owner, clock)
@@ -278,17 +294,17 @@ void rocvfd_device::write_char(int data)
else m_window_size = data;
}
else if ( (data & 0xE0) == 0xE0 ) // 111x xxxx
- { // 111x xxxx Set duty cycle ( brightness )
- m_brightness = (data & 0x1F);
+ { // 111x xxxx Set duty cycle ( power to display )
+ m_duty = (data & 0x1F);
}
else if ( (data & 0xE0) == 0x80 ) // 100x ---
{ // 100x xxxx Test mode
- m_duty =4;
+ popmessage("TEST MODE ENABLED!");
}
}
else
{ // Display data
-// data &= 0x3F;
+ data &= 0x3F;
switch ( data )
{
@@ -334,8 +350,8 @@ void roc10957_device::write_char(int data)
else m_window_size = data;
}
else if ( (data & 0xE0) == 0xE0 ) // 111x xxxx
- { // 111x xxxx Set duty cycle ( brightness )
- m_brightness = (data & 0x1F);
+ { // 111x xxxx Set duty cycle ( power to display )
+ m_duty = (data & 0x1F);
}
else if ( (data & 0xE0) == 0x80 ) // 100x ---
{ // 100x xxxx Test mode
@@ -360,9 +376,7 @@ void roc10957_device::write_char(int data)
m_chars[m_pcursor_pos] |= (1<<16);//.
break;
case 0x6E: //
- {
- m_chars[m_pcursor_pos] = 0;
- }
+ m_chars[m_pcursor_pos] |= (1<<17);//,
break;
default :
m_pcursor_pos = m_cursor_pos;
diff --git a/src/devices/machine/roc10937.h b/src/devices/machine/roc10937.h
index 8adacfef5e5..1095d78ccfb 100644
--- a/src/devices/machine/roc10937.h
+++ b/src/devices/machine/roc10937.h
@@ -21,27 +21,27 @@ public:
virtual void update_display();
void shift_clock(int data);
void write_char(int data);
- DECLARE_WRITE_LINE_MEMBER( sclk );
- DECLARE_WRITE_LINE_MEMBER( data );
- DECLARE_WRITE_LINE_MEMBER( por );
+ void sclk(int state);
+ void data(int state);
+ void por(int state);
protected:
rocvfd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
std::unique_ptr<output_finder<16> > m_outputs;
+ std::unique_ptr<output_finder<1> > m_brightness;
int m_cursor_pos;
int m_window_size;
int m_shift_count;
int m_shift_data;
int m_pcursor_pos;
- int m_brightness;
int m_count;
int m_data;
int m_duty;
- int m_disp;
int m_sclk;
+ int m_por;
uint8_t m_cursor;
uint32_t m_chars[16];
diff --git a/src/devices/machine/rp5c01.cpp b/src/devices/machine/rp5c01.cpp
index 67850396213..a5d097995e2 100644
--- a/src/devices/machine/rp5c01.cpp
+++ b/src/devices/machine/rp5c01.cpp
@@ -13,6 +13,8 @@
- 12 hour clock
- test register
- timer reset
+ - convert I/O to address maps & views
+ - lh5045 doesn't really wrap time correctly
*/
@@ -23,6 +25,7 @@
// device type definitions
DEFINE_DEVICE_TYPE(RP5C01, rp5c01_device, "rp5c01", "Ricoh RP5C01 RTC")
DEFINE_DEVICE_TYPE(TC8521, tc8521_device, "tc8521", "Toshiba TC8521 RTC")
+DEFINE_DEVICE_TYPE(LH5045, lh5045_device, "lh5045", "Sharp LH5045 RTC")
//**************************************************************************
@@ -195,16 +198,13 @@ rp5c01_device::rp5c01_device(const machine_config &mconfig, device_type type, co
void rp5c01_device::device_start()
{
- // resolve callbacks
- m_out_alarm_cb.resolve_safe();
-
// allocate timers
if (clock() > 0)
{
- m_clock_timer = timer_alloc(TIMER_CLOCK);
+ m_clock_timer = timer_alloc(FUNC(rp5c01_device::advance_1hz_clock), this);
m_clock_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384));
- m_16hz_timer = timer_alloc(TIMER_16HZ);
+ m_16hz_timer = timer_alloc(FUNC(rp5c01_device::advance_16hz_clock), this);
m_16hz_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024));
}
@@ -227,28 +227,29 @@ void rp5c01_device::device_start()
//-------------------------------------------------
-// device_timer - handler timer events
+// advance_1hz_clock -
//-------------------------------------------------
-void rp5c01_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(rp5c01_device::advance_1hz_clock)
{
- switch (id)
+ if (m_1hz && (m_mode & MODE_TIMER_EN))
{
- case TIMER_CLOCK:
- if (m_1hz && (m_mode & MODE_TIMER_EN))
- {
- advance_seconds();
- }
+ advance_seconds();
+ }
- m_1hz = !m_1hz;
- set_alarm_line();
- break;
+ m_1hz = !m_1hz;
+ set_alarm_line();
+}
- case TIMER_16HZ:
- m_16hz = !m_16hz;
- set_alarm_line();
- break;
- }
+
+//-------------------------------------------------
+// advance_16hz_clock -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(rp5c01_device::advance_16hz_clock)
+{
+ m_16hz = !m_16hz;
+ set_alarm_line();
}
@@ -287,10 +288,10 @@ void rp5c01_device::nvram_default()
// .nv file
//-------------------------------------------------
-void rp5c01_device::nvram_read(emu_file &file)
+bool rp5c01_device::nvram_read(util::read_stream &file)
{
- if (m_battery_backed)
- file.read(m_ram, RAM_SIZE);
+ auto const [err, actual] = util::read(file, m_ram, RAM_SIZE);
+ return !err && (actual == RAM_SIZE);
}
@@ -299,10 +300,10 @@ void rp5c01_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void rp5c01_device::nvram_write(emu_file &file)
+bool rp5c01_device::nvram_write(util::write_stream &file)
{
- if (m_battery_backed)
- file.write(m_ram, RAM_SIZE);
+ auto const [err, actual] = util::write(file, m_ram, RAM_SIZE);
+ return !err;
}
@@ -431,3 +432,22 @@ tc8521_device::tc8521_device(const machine_config &mconfig, const char *tag, dev
: rp5c01_device(mconfig, TC8521, tag, owner, clock)
{
}
+
+//-------------------------------------------------
+// lh5045_device - constructor
+//-------------------------------------------------
+
+lh5045_device::lh5045_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : rp5c01_device(mconfig, LH5045, tag, owner, clock)
+{
+}
+
+TIMER_CALLBACK_MEMBER(lh5045_device::advance_1hz_clock)
+{
+ // inverted & different bit compared to rp5c01
+ if (m_1hz && (!BIT(m_mode, 2)))
+ advance_seconds();
+
+ m_1hz = !m_1hz;
+ set_alarm_line();
+}
diff --git a/src/devices/machine/rp5c01.h b/src/devices/machine/rp5c01.h
index f26a382db67..511663b47c0 100644
--- a/src/devices/machine/rp5c01.h
+++ b/src/devices/machine/rp5c01.h
@@ -41,7 +41,7 @@ public:
rp5c01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto out_alarm_callback() { return m_out_alarm_cb.bind(); }
- void remove_battery() { m_battery_backed = false; }
+ void remove_battery() { m_battery_backed = false; nvram_enable_backup(false); }
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
@@ -54,7 +54,6 @@ protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_rtc_interface overrides
virtual bool rtc_feature_leap_year() const override { return true; }
@@ -63,22 +62,22 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
- virtual bool nvram_can_write() override { return m_battery_backed; }
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ virtual TIMER_CALLBACK_MEMBER(advance_1hz_clock);
+ TIMER_CALLBACK_MEMBER(advance_16hz_clock);
-private:
inline void set_alarm_line();
+private:
inline int read_counter(int counter);
inline void write_counter(int counter, int value);
inline void check_alarm();
- static const device_timer_id TIMER_CLOCK = 0;
- static const device_timer_id TIMER_16HZ = 1;
-
devcb_write_line m_out_alarm_cb;
bool m_battery_backed;
+protected:
uint8_t m_reg[2][13]; // clock registers
uint8_t m_ram[13]; // RAM
@@ -89,6 +88,7 @@ private:
int m_1hz; // 1 Hz condition
int m_16hz; // 16 Hz condition
+private:
// timers
emu_timer *m_clock_timer;
emu_timer *m_16hz_timer;
@@ -103,9 +103,19 @@ public:
tc8521_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
+class lh5045_device : public rp5c01_device
+{
+public:
+ // construction/destruction
+ lh5045_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+private:
+ virtual TIMER_CALLBACK_MEMBER(advance_1hz_clock) override;
+};
// device type definition
DECLARE_DEVICE_TYPE(RP5C01, rp5c01_device)
DECLARE_DEVICE_TYPE(TC8521, tc8521_device)
+DECLARE_DEVICE_TYPE(LH5045, lh5045_device)
#endif // MAME_MACHINE_RP5C01_H
diff --git a/src/devices/machine/rp5c15.cpp b/src/devices/machine/rp5c15.cpp
index 78d71d42000..f2b8ff4a037 100644
--- a/src/devices/machine/rp5c15.cpp
+++ b/src/devices/machine/rp5c15.cpp
@@ -109,6 +109,14 @@ enum
DEFINE_DEVICE_TYPE(RP5C15, rp5c15_device, "rp5c15", "Ricoh RP5C15 RTC")
+// x68k wants an epoch base (1980-2079) on init, mz2500 do not ("print date$" under basicv2)
+// megast_* tbd
+void rp5c15_device::set_current_time(const system_time &systime)
+{
+ const system_time::full_time &time = m_use_utc ? systime.utc_time : systime.local_time;
+ set_time(true, time.year + m_year_offset, time.month + 1, time.mday, time.weekday + 1,
+ time.hour, time.minute, time.second);
+}
//**************************************************************************
// INLINE HELPERS
@@ -202,18 +210,14 @@ rp5c15_device::rp5c15_device(const machine_config &mconfig, const char *tag, dev
void rp5c15_device::device_start()
{
- // resolve callbacks
- m_out_alarm_cb.resolve_safe();
- m_out_clkout_cb.resolve_safe();
-
// allocate timers
- m_clock_timer = timer_alloc(TIMER_CLOCK);
+ m_clock_timer = timer_alloc(FUNC(rp5c15_device::advance_1hz_clock), this);
m_clock_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384));
- m_16hz_timer = timer_alloc(TIMER_16HZ);
+ m_16hz_timer = timer_alloc(FUNC(rp5c15_device::advance_16hz_clock), this);
m_16hz_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024));
- m_clkout_timer = timer_alloc(TIMER_CLKOUT);
+ m_clkout_timer = timer_alloc(FUNC(rp5c15_device::advance_output_clock), this);
memset(m_reg, 0, sizeof(m_reg));
memset(m_ram, 0, sizeof(m_ram));
@@ -239,33 +243,40 @@ void rp5c15_device::device_start()
//-------------------------------------------------
-// device_timer - handler timer events
+// advance_1hz_clock -
//-------------------------------------------------
-void rp5c15_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(rp5c15_device::advance_1hz_clock)
{
- switch (id)
+ if (m_1hz && (m_mode & MODE_TIMER_EN))
{
- case TIMER_CLOCK:
- if (m_1hz && (m_mode & MODE_TIMER_EN))
- {
- advance_seconds();
- }
+ advance_seconds();
+ }
- m_1hz = !m_1hz;
- set_alarm_line();
- break;
+ m_1hz = !m_1hz;
+ set_alarm_line();
+}
- case TIMER_16HZ:
- m_16hz = !m_16hz;
- set_alarm_line();
- break;
- case TIMER_CLKOUT:
- m_clkout = !m_clkout;
- m_out_clkout_cb(m_clkout);
- break;
- }
+//-------------------------------------------------
+// advance_16hz_clock -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(rp5c15_device::advance_16hz_clock)
+{
+ m_16hz = !m_16hz;
+ set_alarm_line();
+}
+
+
+//-------------------------------------------------
+// advance_output_clock -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(rp5c15_device::advance_output_clock)
+{
+ m_clkout = !m_clkout;
+ m_out_clkout_cb(m_clkout);
}
diff --git a/src/devices/machine/rp5c15.h b/src/devices/machine/rp5c15.h
index 6d4e161ac3e..6630260fc8c 100644
--- a/src/devices/machine/rp5c15.h
+++ b/src/devices/machine/rp5c15.h
@@ -34,29 +34,31 @@ public:
auto alarm() { return m_out_alarm_cb.bind(); }
auto clkout() { return m_out_clkout_cb.bind(); }
+ void set_year_offset(int year) { m_year_offset = year; }
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
+ virtual void set_current_time(const system_time &systime) override;
+
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_rtc_interface overrides
virtual bool rtc_feature_leap_year() const override { return true; }
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+ TIMER_CALLBACK_MEMBER(advance_1hz_clock);
+ TIMER_CALLBACK_MEMBER(advance_16hz_clock);
+ TIMER_CALLBACK_MEMBER(advance_output_clock);
+
private:
inline void set_alarm_line();
inline int read_counter(int counter);
inline void write_counter(int counter, int value);
inline void check_alarm();
- static const device_timer_id TIMER_CLOCK = 0;
- static const device_timer_id TIMER_16HZ = 1;
- static const device_timer_id TIMER_CLKOUT = 2;
-
devcb_write_line m_out_alarm_cb;
devcb_write_line m_out_clkout_cb;
@@ -71,6 +73,8 @@ private:
int m_16hz; // 16 Hz condition
int m_clkout; // clock output
+ int m_year_offset = 0;
+
// timers
emu_timer *m_clock_timer;
emu_timer *m_16hz_timer;
diff --git a/src/devices/machine/rp5h01.cpp b/src/devices/machine/rp5h01.cpp
index 655ffd5f841..bdd3f7b1c97 100644
--- a/src/devices/machine/rp5h01.cpp
+++ b/src/devices/machine/rp5h01.cpp
@@ -17,7 +17,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/rp5h01.h"
+#include "rp5h01.h"
// this is the contents of an unprogrammed PROM
uint8_t const rp5h01_device::s_initial_data[0x10] =
@@ -80,7 +80,7 @@ void rp5h01_device::device_reset()
enable_w
-------------------------------------------------*/
-WRITE_LINE_MEMBER( rp5h01_device::enable_w )
+void rp5h01_device::enable_w(int state)
{
/* process the /CE signal and enable/disable the IC */
m_enabled = state ? 0 : 1;
@@ -90,7 +90,7 @@ WRITE_LINE_MEMBER( rp5h01_device::enable_w )
reset_w
-------------------------------------------------*/
-WRITE_LINE_MEMBER( rp5h01_device::reset_w )
+void rp5h01_device::reset_w(int state)
{
/* if it's not enabled, ignore */
if (!m_enabled)
@@ -111,7 +111,7 @@ WRITE_LINE_MEMBER( rp5h01_device::reset_w )
cs_w
-------------------------------------------------*/
-WRITE_LINE_MEMBER( rp5h01_device::cs_w )
+void rp5h01_device::cs_w(int state)
{
/* if it's not enabled, ignore */
if (!m_enabled)
@@ -128,7 +128,7 @@ WRITE_LINE_MEMBER( rp5h01_device::cs_w )
clock_w
-------------------------------------------------*/
-WRITE_LINE_MEMBER( rp5h01_device::clock_w )
+void rp5h01_device::clock_w(int state)
{
/* if it's not enabled, ignore */
if (!m_enabled)
@@ -149,7 +149,7 @@ WRITE_LINE_MEMBER( rp5h01_device::clock_w )
test_w
-------------------------------------------------*/
-WRITE_LINE_MEMBER( rp5h01_device::test_w )
+void rp5h01_device::test_w(int state)
{
/* if it's not enabled, ignore */
if (!m_enabled)
@@ -163,7 +163,7 @@ WRITE_LINE_MEMBER( rp5h01_device::test_w )
counter_r
-------------------------------------------------*/
-READ_LINE_MEMBER( rp5h01_device::counter_r )
+int rp5h01_device::counter_r()
{
/* if it's not enabled, ignore */
if (!m_enabled)
@@ -177,7 +177,7 @@ READ_LINE_MEMBER( rp5h01_device::counter_r )
data_r
-------------------------------------------------*/
-READ_LINE_MEMBER( rp5h01_device::data_r )
+int rp5h01_device::data_r()
{
/* if it's not enabled, ignore */
if (!m_enabled)
diff --git a/src/devices/machine/rp5h01.h b/src/devices/machine/rp5h01.h
index 686367c694e..53b301831d7 100644
--- a/src/devices/machine/rp5h01.h
+++ b/src/devices/machine/rp5h01.h
@@ -33,13 +33,13 @@ class rp5h01_device : public device_t
public:
rp5h01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER( enable_w ); /* /CE */
- DECLARE_WRITE_LINE_MEMBER( reset_w ); /* RESET */
- DECLARE_WRITE_LINE_MEMBER( cs_w ); /* CS */
- DECLARE_WRITE_LINE_MEMBER( clock_w ); /* DATA CLOCK (active low) */
- DECLARE_WRITE_LINE_MEMBER( test_w ); /* TEST */
- DECLARE_READ_LINE_MEMBER( counter_r ); /* COUNTER OUT */
- DECLARE_READ_LINE_MEMBER( data_r ); /* DATA */
+ void enable_w(int state); // /CE
+ void reset_w(int state); // RESET
+ void cs_w(int state); // CS
+ void clock_w(int state); // DATA CLOCK (active low)
+ void test_w(int state); // TEST
+ int counter_r(); // COUNTER OUT
+ int data_r(); // DATA
protected:
// device-level overrides
diff --git a/src/devices/machine/rstbuf.cpp b/src/devices/machine/rstbuf.cpp
index 9e13d72743a..ad6324a184e 100644
--- a/src/devices/machine/rstbuf.cpp
+++ b/src/devices/machine/rstbuf.cpp
@@ -56,7 +56,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/rstbuf.h"
+#include "rstbuf.h"
// device type definition
DEFINE_DEVICE_TYPE(RST_POS_BUFFER, rst_pos_buffer_device, "rst_pos_buffer", "RST Interrupt Buffer (positive modification)")
@@ -100,18 +100,6 @@ rst_neg_buffer_device::rst_neg_buffer_device(const machine_config &mconfig, cons
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void rst_buffer_device::device_resolve_objects()
-{
- m_int_cb.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
diff --git a/src/devices/machine/rstbuf.h b/src/devices/machine/rstbuf.h
index 718a96f4861..b6bdd871ff4 100644
--- a/src/devices/machine/rstbuf.h
+++ b/src/devices/machine/rstbuf.h
@@ -32,8 +32,7 @@ protected:
// device base class constructor
rst_buffer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
// synchronization helpers
@@ -57,13 +56,13 @@ public:
rst_pos_buffer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
// set RST 1/RST 08H request line (modifies bit 3 of vector)
- DECLARE_WRITE_LINE_MEMBER(rst1_w) { sync_input(state, 0x08); }
+ void rst1_w(int state) { sync_input(state, 0x08); }
// set RST 2/RST 10H request line (modifies bit 4 of vector)
- DECLARE_WRITE_LINE_MEMBER(rst2_w) { sync_input(state, 0x10); }
+ void rst2_w(int state) { sync_input(state, 0x10); }
// set RST 3/RST 20H request line (modifies bit 5 of vector)
- DECLARE_WRITE_LINE_MEMBER(rst4_w) { sync_input(state, 0x20); }
+ void rst4_w(int state) { sync_input(state, 0x20); }
protected:
// getter (required override)
@@ -79,13 +78,13 @@ public:
rst_neg_buffer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
// set RST 30H request line (modifies bit 3 of vector)
- DECLARE_WRITE_LINE_MEMBER(rst30_w) { sync_input(state, 0x08); }
+ void rst30_w(int state) { sync_input(state, 0x08); }
// set RST 28H request line (modifies bit 4 of vector)
- DECLARE_WRITE_LINE_MEMBER(rst28_w) { sync_input(state, 0x10); }
+ void rst28_w(int state) { sync_input(state, 0x10); }
// set RST 18H request line (modifies bit 5 of vector)
- DECLARE_WRITE_LINE_MEMBER(rst18_w) { sync_input(state, 0x20); }
+ void rst18_w(int state) { sync_input(state, 0x20); }
protected:
// getter (required override)
diff --git a/src/devices/machine/rtc4543.cpp b/src/devices/machine/rtc4543.cpp
index 28cdfa69bb7..977da7e0bff 100644
--- a/src/devices/machine/rtc4543.cpp
+++ b/src/devices/machine/rtc4543.cpp
@@ -70,10 +70,8 @@ rtc4543_device::rtc4543_device(const machine_config &mconfig, device_type type,
void rtc4543_device::device_start()
{
- m_data_cb.resolve_safe();
-
// allocate timers
- m_clock_timer = timer_alloc();
+ m_clock_timer = timer_alloc(FUNC(rtc4543_device::advance_clock), this);
m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
// state saving
@@ -101,10 +99,10 @@ void rtc4543_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// advance_clock -
//-------------------------------------------------
-void rtc4543_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(rtc4543_device::advance_clock)
{
advance_seconds();
}
@@ -132,7 +130,7 @@ void rtc4543_device::rtc_clock_updated(int year, int month, int day, int day_of_
// ce_w - chip enable write
//-------------------------------------------------
-WRITE_LINE_MEMBER( rtc4543_device::ce_w )
+void rtc4543_device::ce_w(int state)
{
if (!state && m_ce) // complete transfer
{
@@ -175,7 +173,7 @@ void rtc4543_device::ce_falling()
// wr_w - data direction line write
//-------------------------------------------------
-WRITE_LINE_MEMBER( rtc4543_device::wr_w )
+void rtc4543_device::wr_w(int state)
{
if (state != m_wr)
LOG("WR: %u\n", state);
@@ -188,7 +186,7 @@ WRITE_LINE_MEMBER( rtc4543_device::wr_w )
// clk_w - serial clock write
//-------------------------------------------------
-WRITE_LINE_MEMBER( rtc4543_device::clk_w )
+void rtc4543_device::clk_w(int state)
{
if (m_ce)
{
@@ -246,7 +244,7 @@ void rtc4543_device::clk_falling()
// data_w - I/O write
//-------------------------------------------------
-WRITE_LINE_MEMBER( rtc4543_device::data_w )
+void rtc4543_device::data_w(int state)
{
m_data = state & 1;
}
@@ -256,7 +254,7 @@ WRITE_LINE_MEMBER( rtc4543_device::data_w )
// data_r - I/O read
//-------------------------------------------------
-READ_LINE_MEMBER( rtc4543_device::data_r )
+int rtc4543_device::data_r()
{
return m_data;
}
@@ -268,7 +266,7 @@ READ_LINE_MEMBER( rtc4543_device::data_r )
void rtc4543_device::load_bit(int reg)
{
- assert(reg < ARRAY_LENGTH(m_regs));
+ assert(reg < std::size(m_regs));
int bit = m_curbit & 7;
// reload data?
@@ -289,7 +287,7 @@ void rtc4543_device::load_bit(int reg)
void rtc4543_device::store_bit(int reg)
{
- assert(reg < ARRAY_LENGTH(m_regs));
+ assert(reg < std::size(m_regs));
int bit = m_curbit & 7;
m_regs[reg] &= ~(1 << bit);
diff --git a/src/devices/machine/rtc4543.h b/src/devices/machine/rtc4543.h
index f93fa097d59..21fd2914deb 100644
--- a/src/devices/machine/rtc4543.h
+++ b/src/devices/machine/rtc4543.h
@@ -30,11 +30,11 @@ public:
// construction/destruction
rtc4543_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER( ce_w );
- DECLARE_WRITE_LINE_MEMBER( wr_w );
- DECLARE_WRITE_LINE_MEMBER( clk_w );
- DECLARE_READ_LINE_MEMBER( data_r );
- DECLARE_WRITE_LINE_MEMBER( data_w );
+ void ce_w(int state);
+ void wr_w(int state);
+ void clk_w(int state);
+ int data_r();
+ void data_w(int state);
auto data_cb() { return m_data_cb.bind(); }
@@ -44,7 +44,6 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
@@ -60,6 +59,8 @@ protected:
void advance_bit();
void update_effective();
+ TIMER_CALLBACK_MEMBER(advance_clock);
+
devcb_write_line m_data_cb;
int m_ce;
diff --git a/src/devices/machine/rtc65271.cpp b/src/devices/machine/rtc65271.cpp
index 1eb84d89171..adea3cb29d6 100644
--- a/src/devices/machine/rtc65271.cpp
+++ b/src/devices/machine/rtc65271.cpp
@@ -21,6 +21,9 @@
#include "emu.h"
#include "rtc65271.h"
+#include <tuple>
+
+
/* Delay between the beginning (UIP asserted) and the end (UIP cleared and
update interrupt asserted) of the update cycle */
#define UPDATE_CYCLE_TIME attotime::from_usec(1984)
@@ -162,10 +165,18 @@ static uint8_t BCD_to_binary(uint8_t data)
void rtc65271_device::nvram_default()
{
- memset(m_regs,0, sizeof(m_regs));
- memset(m_xram,0, sizeof(m_xram));
-
- m_regs[reg_B] |= reg_B_DM; // Firebeat assumes the chip factory defaults to non-BCD mode (or maybe Konami programs it that way?)
+ if (m_default_data.found())
+ {
+ auto file = util::ram_read(m_default_data, m_default_data.bytes());
+ if (file != nullptr)
+ nvram_read(*file);
+ }
+ else
+ {
+ memset(m_regs, 0, sizeof(m_regs));
+ memset(m_xram, 0, sizeof(m_xram));
+ m_regs[reg_B] |= reg_B_DM; // Firebeat assumes the chip factory defaults to non-BCD mode (or maybe Konami programs it that way?)
+ }
}
//-------------------------------------------------
@@ -173,84 +184,96 @@ void rtc65271_device::nvram_default()
// .nv file
//-------------------------------------------------
-void rtc65271_device::nvram_read(emu_file &file)
+bool rtc65271_device::nvram_read(util::read_stream &file)
{
uint8_t buf;
+ std::error_condition err;
+ size_t actual;
/* version flag */
- if (file.read(&buf, 1) != 1)
- return;
+ std::tie(err, actual) = util::read(file, &buf, 1);
+ if (err || (actual != 1))
+ return false;
if (buf != 0)
- return;
+ return false;
/* control registers */
- if (file.read(&buf, 1) != 1)
- return;
+ std::tie(err, actual) = util::read(file, &buf, 1);
+ if (err || (actual != 1))
+ return false;
m_regs[reg_A] = buf & (reg_A_DV /*| reg_A_RS*/);
- if (file.read(&buf, 1) != 1)
- return;
+ std::tie(err, actual) = util::read(file, &buf, 1);
+ if (err || (actual != 1))
+ return false;
m_regs[reg_B] = buf & (reg_B_SET | reg_B_DM | reg_B_24h | reg_B_DSE);
/* alarm registers */
- if (file.read(&m_regs[reg_alarm_second], 1) != 1)
- return;
- if (file.read(&m_regs[reg_alarm_minute], 1) != 1)
- return;
- if (file.read(&m_regs[reg_alarm_hour], 1) != 1)
- return;
+ std::tie(err, actual) = util::read(file, &m_regs[reg_alarm_second], 1);
+ if (err || (actual != 1))
+ return false;
+ std::tie(err, actual) = util::read(file, &m_regs[reg_alarm_minute], 1);
+ if (err || (actual != 1))
+ return false;
+ std::tie(err, actual) = util::read(file, &m_regs[reg_alarm_hour], 1);
+ if (err || (actual != 1))
+ return false;
/* user RAM */
- if (file.read(m_regs+14, 50) != 50)
- return;
+ std::tie(err, actual) = util::read(file, m_regs+14, 50);
+ if (err || (actual != 50))
+ return false;
/* extended RAM */
- if (file.read(m_xram, 4096) != 4096)
- return;
+ std::tie(err, actual) = util::read(file, m_xram, 4096);
+ if (err || (actual != 4096))
+ return false;
m_regs[reg_D] |= reg_D_VRT; /* the data was backed up successfully */
/*m_dirty = false;*/
- {
- system_time systime;
-
- /* get the current date/time from the core */
- machine().current_datetime(systime);
+ return true;
+}
- /* set clock registers */
- m_regs[reg_second] = systime.local_time.second;
- m_regs[reg_minute] = systime.local_time.minute;
- if (m_regs[reg_B] & reg_B_24h)
- /* 24-hour mode */
- m_regs[reg_hour] = systime.local_time.hour;
- else
- { /* 12-hour mode */
- if (systime.local_time.hour >= 12)
- {
- m_regs[reg_hour] = 0x80;
- systime.local_time.hour -= 12;
- }
- else
- {
- m_regs[reg_hour] = 0;
- }
+//-------------------------------------------------
+// rtc_clock_updated - update clock with real time
+//-------------------------------------------------
- // Firebeat indicates non-BCD 12-hour mode has 0-based hour, so 12 AM is 0x00 and 12 PM is 0x80
- m_regs[reg_hour] |= systime.local_time.hour; // ? systime.local_time.hour : 12;
+void rtc65271_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ /* set clock registers */
+ m_regs[reg_second] = second;
+ m_regs[reg_minute] = minute;
+ if (m_regs[reg_B] & reg_B_24h)
+ /* 24-hour mode */
+ m_regs[reg_hour] = hour;
+ else
+ { /* 12-hour mode */
+ if (hour >= 12)
+ {
+ m_regs[reg_hour] = 0x80;
+ hour -= 12;
}
- m_regs[reg_weekday] = systime.local_time.weekday + 1;
- m_regs[reg_monthday] = systime.local_time.mday;
- m_regs[reg_month] = systime.local_time.month + 1;
- m_regs[reg_year] = systime.local_time.year % 100;
- if (! (m_regs[reg_B] & reg_B_DM))
- { /* BCD mode */
- m_regs[reg_second] = binary_to_BCD(m_regs[reg_second]);
- m_regs[reg_minute] = binary_to_BCD(m_regs[reg_minute]);
- m_regs[reg_hour] = (m_regs[reg_hour] & 0x80) | binary_to_BCD(m_regs[reg_hour] & 0x7f);
- /*m_regs[reg_weekday] = binary_to_BCD(m_regs[reg_weekday]);*/
- m_regs[reg_monthday] = binary_to_BCD(m_regs[reg_monthday]);
- m_regs[reg_month] = binary_to_BCD(m_regs[reg_month]);
- m_regs[reg_year] = binary_to_BCD(m_regs[reg_year]);
+ else
+ {
+ m_regs[reg_hour] = 0;
}
+
+ // Firebeat indicates non-BCD 12-hour mode has 0-based hour, so 12 AM is 0x00 and 12 PM is 0x80
+ m_regs[reg_hour] |= hour; // ? hour : 12;
+ }
+ m_regs[reg_weekday] = day_of_week;
+ m_regs[reg_monthday] = day;
+ m_regs[reg_month] = month;
+ m_regs[reg_year] = year % 100;
+ if (! (m_regs[reg_B] & reg_B_DM))
+ { /* BCD mode */
+ m_regs[reg_second] = binary_to_BCD(m_regs[reg_second]);
+ m_regs[reg_minute] = binary_to_BCD(m_regs[reg_minute]);
+ m_regs[reg_hour] = (m_regs[reg_hour] & 0x80) | binary_to_BCD(m_regs[reg_hour] & 0x7f);
+ /*m_regs[reg_weekday] = binary_to_BCD(m_regs[reg_weekday]);*/
+ m_regs[reg_monthday] = binary_to_BCD(m_regs[reg_monthday]);
+ m_regs[reg_month] = binary_to_BCD(m_regs[reg_month]);
+ m_regs[reg_year] = binary_to_BCD(m_regs[reg_year]);
}
}
@@ -259,39 +282,50 @@ void rtc65271_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void rtc65271_device::nvram_write(emu_file &file)
+bool rtc65271_device::nvram_write(util::write_stream &file)
{
uint8_t buf;
-
+ std::error_condition err;
+ size_t actual;
/* version flag */
buf = 0;
- if (file.write(& buf, 1) != 1)
- return;
+ std::tie(err, actual) = util::write(file, &buf, 1);
+ if (err)
+ return false;
/* control registers */
buf = m_regs[reg_A] & (reg_A_DV | reg_A_RS);
- if (file.write(&buf, 1) != 1)
- return;
+ std::tie(err, actual) = util::write(file, &buf, 1);
+ if (err)
+ return false;
buf = m_regs[reg_B] & (reg_B_SET | reg_B_DM | reg_B_24h | reg_B_DSE);
- if (file.write(&buf, 1) != 1)
- return;
+ std::tie(err, actual) = util::write(file, &buf, 1);
+ if (err)
+ return false;
/* alarm registers */
- if (file.write(&m_regs[reg_alarm_second], 1) != 1)
- return;
- if (file.write(&m_regs[reg_alarm_minute], 1) != 1)
- return;
- if (file.write(&m_regs[reg_alarm_hour], 1) != 1)
- return;
+ std::tie(err, actual) = util::write(file, &m_regs[reg_alarm_second], 1);
+ if (err)
+ return false;
+ std::tie(err, actual) = util::write(file, &m_regs[reg_alarm_minute], 1);
+ if (err)
+ return false;
+ std::tie(err, actual) = util::write(file, &m_regs[reg_alarm_hour], 1);
+ if (err)
+ return false;
/* user RAM */
- if (file.write(m_regs+14, 50) != 50)
- return;
+ std::tie(err, actual) = util::write(file, m_regs+14, 50);
+ if (err)
+ return false;
/* extended RAM */
- if (file.write(m_xram, 4096) != 4096)
- return;
+ std::tie(err, actual) = util::write(file, m_xram, 4096);
+ if (err)
+ return false;
+
+ return true;
}
/*
@@ -392,7 +426,7 @@ void rtc65271_device::write(int xramsel, offs_t offset, uint8_t data)
{
attotime period = attotime::from_hz(SQW_freq_table[data & reg_A_RS]);
attotime half_period = period / 2;
- attotime elapsed = m_update_timer->elapsed();
+ attotime elapsed = m_begin_update_timer->elapsed();
if (half_period > elapsed)
m_SQW_timer->adjust(half_period - elapsed);
@@ -451,18 +485,16 @@ void rtc65271_device::field_interrupts()
if (m_regs[reg_C] & m_regs[reg_B] & (reg_C_PF | reg_C_AF | reg_C_UF))
{
m_regs[reg_C] |= reg_C_IRQF;
- if (!m_interrupt_cb.isnull())
- m_interrupt_cb(1);
+ m_interrupt_cb(1);
}
else
{
m_regs[reg_C] &= ~reg_C_IRQF;
- if (!m_interrupt_cb.isnull())
- m_interrupt_cb(0);
+ m_interrupt_cb(0);
}
}
-READ_LINE_MEMBER(rtc65271_device::intrq_r)
+int rtc65271_device::intrq_r()
{
return (m_regs[reg_C] & reg_C_IRQF)? ASSERT_LINE : CLEAR_LINE;
}
@@ -497,7 +529,7 @@ TIMER_CALLBACK_MEMBER(rtc65271_device::rtc_begin_update_cb)
m_regs[reg_A] |= reg_A_UIP;
/* schedule end of update cycle */
- machine().scheduler().timer_set(UPDATE_CYCLE_TIME, timer_expired_delegate(FUNC(rtc65271_device::rtc_end_update_cb), this));
+ m_end_update_timer->adjust(UPDATE_CYCLE_TIME);
}
}
@@ -659,7 +691,9 @@ DEFINE_DEVICE_TYPE(RTC65271, rtc65271_device, "rtc65271", "Epson RTC-65271 RTC")
rtc65271_device::rtc65271_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, RTC65271, tag, owner, clock)
, device_nvram_interface(mconfig, *this)
+ , device_rtc_interface(mconfig, *this)
, m_interrupt_cb(*this)
+ , m_default_data(*this, DEVICE_SELF)
{
}
@@ -668,10 +702,11 @@ rtc65271_device::rtc65271_device(const machine_config &mconfig, const char *tag,
//-------------------------------------------------
void rtc65271_device::device_start()
{
- m_update_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(rtc65271_device::rtc_begin_update_cb), this));
- m_update_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
- m_SQW_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(rtc65271_device::rtc_SQW_cb), this));
- m_interrupt_cb.resolve();
+ m_begin_update_timer = timer_alloc(FUNC(rtc65271_device::rtc_begin_update_cb), this);
+ m_begin_update_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+ m_end_update_timer = timer_alloc(FUNC(rtc65271_device::rtc_end_update_cb), this);
+ m_end_update_timer->adjust(attotime::never);
+ m_SQW_timer = timer_alloc(FUNC(rtc65271_device::rtc_SQW_cb), this);
save_item(NAME(m_regs));
save_item(NAME(m_cur_reg));
diff --git a/src/devices/machine/rtc65271.h b/src/devices/machine/rtc65271.h
index 151344d6e7c..430af624c73 100644
--- a/src/devices/machine/rtc65271.h
+++ b/src/devices/machine/rtc65271.h
@@ -9,11 +9,14 @@
#pragma once
+#include "dirtc.h"
+
// ======================> rtc65271_device
class rtc65271_device : public device_t,
- public device_nvram_interface
+ public device_nvram_interface,
+ public device_rtc_interface
{
public:
// construction/destruction
@@ -29,15 +32,21 @@ public:
uint8_t read(int xramsel, offs_t offset);
void write(int xramsel, offs_t offset, uint8_t data);
- DECLARE_READ_LINE_MEMBER(intrq_r);
+ int intrq_r();
protected:
// device-level overrides
virtual void device_start() override;
+
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return false; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
private:
void field_interrupts();
@@ -55,7 +64,8 @@ private:
uint8_t m_cur_xram_page;
/* update timer: called every second */
- emu_timer *m_update_timer;
+ emu_timer *m_begin_update_timer = nullptr;
+ emu_timer *m_end_update_timer = nullptr;
/* SQW timer: called every periodic clock half-period */
emu_timer *m_SQW_timer;
@@ -63,6 +73,8 @@ private:
/* callback called when interrupt pin state changes (may be nullptr) */
devcb_write_line m_interrupt_cb;
+
+ optional_region_ptr<u8> m_default_data;
};
// device type definition
diff --git a/src/devices/machine/rtc9701.cpp b/src/devices/machine/rtc9701.cpp
index a8ccc5cec7f..7f521d43063 100644
--- a/src/devices/machine/rtc9701.cpp
+++ b/src/devices/machine/rtc9701.cpp
@@ -12,7 +12,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/rtc9701.h"
+#include "rtc9701.h"
ALLOW_SAVE_TYPE(rtc9701_device::state_t);
@@ -37,6 +37,7 @@ DEFINE_DEVICE_TYPE(RTC9701, rtc9701_device, "rtc9701", "Epson RTC-9701-JE RTC/EE
rtc9701_device::rtc9701_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, RTC9701, tag, owner, clock)
, device_nvram_interface(mconfig, *this)
+ , device_rtc_interface(mconfig, *this)
, m_latch(0)
, m_reset_line(CLEAR_LINE)
, m_clock_line(CLEAR_LINE)
@@ -92,20 +93,9 @@ void rtc9701_device::device_validity_check(validity_checker &valid) const
void rtc9701_device::device_start()
{
/* let's call the timer callback every second */
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(rtc9701_device::timer_callback), this));
+ m_timer = timer_alloc(FUNC(rtc9701_device::timer_callback), this);
m_timer->adjust(attotime::from_hz(clock() / XTAL(32'768)), 0, attotime::from_hz(clock() / XTAL(32'768)));
- system_time systime;
- machine().base_datetime(systime);
-
- m_rtc.day = ((systime.local_time.mday / 10)<<4) | ((systime.local_time.mday % 10) & 0xf);
- m_rtc.month = (((systime.local_time.month+1) / 10) << 4) | (((systime.local_time.month+1) % 10) & 0xf);
- m_rtc.wday = 1 << systime.local_time.weekday;
- m_rtc.year = (((systime.local_time.year % 100)/10)<<4) | ((systime.local_time.year % 10) & 0xf);
- m_rtc.hour = ((systime.local_time.hour / 10)<<4) | ((systime.local_time.hour % 10) & 0xf);
- m_rtc.min = ((systime.local_time.minute / 10)<<4) | ((systime.local_time.minute % 10) & 0xf);
- m_rtc.sec = ((systime.local_time.second / 10)<<4) | ((systime.local_time.second % 10) & 0xf);
-
rtc_state = state_t::CMD_WAIT;
cmd_stream_pos = 0;
current_cmd = 0;
@@ -132,6 +122,22 @@ void rtc9701_device::device_start()
//-------------------------------------------------
+// rtc_clock_updated - update clock with real time
+//-------------------------------------------------
+
+void rtc9701_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ m_rtc.day = ((day / 10)<<4) | ((day % 10) & 0xf);
+ m_rtc.month = ((month / 10) << 4) | ((month % 10) & 0xf);
+ m_rtc.wday = 1 << (day_of_week - 1);
+ m_rtc.year = (((year % 100)/10)<<4) | ((year % 10) & 0xf);
+ m_rtc.hour = ((hour / 10)<<4) | ((hour % 10) & 0xf);
+ m_rtc.min = ((minute / 10)<<4) | ((minute % 10) & 0xf);
+ m_rtc.sec = ((second / 10)<<4) | ((second % 10) & 0xf);
+}
+
+
+//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
@@ -160,9 +166,10 @@ void rtc9701_device::nvram_default()
// .nv file
//-------------------------------------------------
-void rtc9701_device::nvram_read(emu_file &file)
+bool rtc9701_device::nvram_read(util::read_stream &file)
{
- file.read(rtc9701_data, 0x200);
+ auto const [err, actual] = read(file, rtc9701_data, 0x200);
+ return !err && (actual == 0x200);
}
@@ -171,9 +178,10 @@ void rtc9701_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void rtc9701_device::nvram_write(emu_file &file)
+bool rtc9701_device::nvram_write(util::write_stream &file)
{
- file.write(rtc9701_data, 0x200);
+ auto const [err, actual] = write(file, rtc9701_data, 0x200);
+ return !err;
}
//-------------------------------------------------
@@ -220,13 +228,13 @@ inline void rtc9701_device::rtc_write(uint8_t offset,uint8_t data)
// READ/WRITE HANDLERS
//**************************************************************************
-WRITE_LINE_MEMBER( rtc9701_device::write_bit )
+void rtc9701_device::write_bit(int state)
{
m_latch = state;
}
-READ_LINE_MEMBER( rtc9701_device::read_bit )
+int rtc9701_device::read_bit()
{
if (rtc_state == state_t::RTC_READ)
{
@@ -251,7 +259,7 @@ READ_LINE_MEMBER( rtc9701_device::read_bit )
}
-WRITE_LINE_MEMBER( rtc9701_device::set_cs_line )
+void rtc9701_device::set_cs_line(int state)
{
//logerror("set reset line %d\n",state);
m_reset_line = state;
@@ -271,7 +279,7 @@ WRITE_LINE_MEMBER( rtc9701_device::set_cs_line )
-WRITE_LINE_MEMBER( rtc9701_device::set_clock_line )
+void rtc9701_device::set_clock_line(int state)
{
//logerror("set clock line %d\n",state);
diff --git a/src/devices/machine/rtc9701.h b/src/devices/machine/rtc9701.h
index 922fc6a0ad6..8d25983fefb 100644
--- a/src/devices/machine/rtc9701.h
+++ b/src/devices/machine/rtc9701.h
@@ -13,6 +13,8 @@
#pragma once
+#include "dirtc.h"
+
//**************************************************************************
// TYPE DEFINITIONS
@@ -22,7 +24,8 @@
// ======================> rtc9701_device
class rtc9701_device : public device_t,
- public device_nvram_interface
+ public device_nvram_interface,
+ public device_rtc_interface
{
public:
// construction/destruction
@@ -30,10 +33,10 @@ public:
// I/O operations
- DECLARE_WRITE_LINE_MEMBER( write_bit );
- DECLARE_READ_LINE_MEMBER( read_bit );
- DECLARE_WRITE_LINE_MEMBER( set_cs_line );
- DECLARE_WRITE_LINE_MEMBER( set_clock_line );
+ void write_bit(int state);
+ int read_bit();
+ void set_cs_line(int state);
+ void set_clock_line(int state);
TIMER_CALLBACK_MEMBER(timer_callback);
protected:
@@ -60,11 +63,16 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
inline uint8_t rtc_read(uint8_t offset);
inline void rtc_write(uint8_t offset,uint8_t data);
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return false; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+
int m_latch;
int m_reset_line;
int m_clock_line;
diff --git a/src/devices/machine/s2350.cpp b/src/devices/machine/s2350.cpp
new file mode 100644
index 00000000000..06370b5f340
--- /dev/null
+++ b/src/devices/machine/s2350.cpp
@@ -0,0 +1,414 @@
+// license:BSD-3-Clause
+// copyright-holders:Mark Garlanger
+/***************************************************************************
+
+ American Microsystems, Inc. (AMI) S2350 Universal Synchronous Receiver/Transmitter(USRT)
+
+ Chip Features
+ - 500kHz Data Rates
+ - Internal Sync Detection
+ - Fill Character Register
+ - Double Buffered Input/Output
+ - Bus Oriented Outputs
+ - 5-8 Bit Characters
+ - Odd/Even or No Parity
+ - Error Status Flags
+
+
+ Current assumptions:
+ - Data size == 8
+ - Parity == NONE
+
+ Not Implemented
+ - parity
+ - data size (other than 8)
+
+ **********************************************************************
+ _____ _____
+ GND 1 |* \_/ | 40 NDB2
+ Vcc 2 | | 39 NDB1
+ NPB 3 | | 38 TDS
+ POE 4 | | 37 RCP
+ CS 5 | | 36 TCP
+ TSO 6 | | 35 RDE
+ FCT 7 | | 34 SWE
+ SCR 8 | | 33 RD0
+ TBMT 9 | AMI | 32 RD1
+ RPE 10 | S2350 | 31 RD2
+ ROR 11 | | 30 RD3
+ RDA 12 | | 29 RD4
+ RR 13 | | 28 RD5
+ RESET 14 | | 27 RD6
+ D0 15 | | 26 RD7
+ D1 16 | | 25 RSI
+ D2 17 | | 24 TFS
+ D3 18 | | 23 RSS
+ D4 19 | | 22 D7
+ D5 20 |_____________| 21 D6
+
+
+Name Pin No. Function
+----------------------------------------------------------------------
+
+D0-D7 15-22 Data Inputs
+
+RD7-RD70 26-33 Received Data Outputs
+
+TDS 38 Transmit Data Strobe
+
+TFS 24 Transmit Fill Strobe
+
+RSS 23 Receiver Sync Strobe
+
+TBMT 9 Transmit Buffer Empty
+
+TSO 6 Transmitter Serial Output
+
+TCP 36 Transmit Clock
+
+RDE 35 Receive Data Enable
+
+FCT 7 Fill Character Transmitted
+
+RSI 25 Receiver Serial Input
+
+RCP 37 Receiver Clock
+
+RDA 12 Received Data Available
+
+SCR 8 Sync Character Received
+
+SWE 34 Status Word Enable
+
+ROR 11 Receiver Overrun
+
+RPE 10 Receiver Parity Error
+
+RR 13 Receiver Restart
+
+NDB1/NDB2 39-40 Number Data Bits
+
+NPB 3 No Parity Bit
+
+POE 4 Parity Odd/Even
+
+CS 5 Control Strobe
+
+RESET 14 Master Reset
+
+Vcc 2 +5.0V
+
+GND 1 Ground
+***************************************************************************/
+
+
+#include "emu.h"
+#include "s2350.h"
+
+// Shows register setup
+#define LOG_REG (1U << 1)
+// Show control lines
+#define LOG_LINE (1U << 2)
+// Function calls
+#define LOG_FUNC (1U << 3)
+// Sync detect
+#define LOG_SYNC (1U << 4)
+
+//#define VERBOSE (0xff)
+
+#include "logmacro.h"
+
+#define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__)
+#define LOGLINE(...) LOGMASKED(LOG_LINE, __VA_ARGS__)
+#define LOGFUNC(...) LOGMASKED(LOG_FUNC, __VA_ARGS__)
+#define LOGSYNC(...) LOGMASKED(LOG_SYNC, __VA_ARGS__)
+
+#ifdef _MSC_VER
+#define FUNCNAME __func__
+#else
+#define FUNCNAME __PRETTY_FUNCTION__
+#endif
+
+
+DEFINE_DEVICE_TYPE(S2350, s2350_device, "s2350", "American Microsystems Inc. S2350 USRT")
+
+
+s2350_device::s2350_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, S2350, tag, owner, clock),
+ m_tbmt(*this),
+ m_fct(*this),
+ m_tx_cb(*this),
+ m_rda(*this),
+ m_scr(*this),
+ m_ror(*this),
+ m_rpe(*this)
+{
+}
+
+void s2350_device::device_start()
+{
+ save_item(NAME(m_transmit_buffer_empty));
+ save_item(NAME(m_fill_char_transmitted));
+ save_item(NAME(m_transmitter_holding_reg));
+ save_item(NAME(m_transmitter_fill_reg));
+ save_item(NAME(m_transmitter_shift_reg));
+ save_item(NAME(m_serial_tx_state));
+
+ save_item(NAME(m_received_data_available));
+ save_item(NAME(m_receiver_overrun));
+ save_item(NAME(m_receiver_parity_error));
+ save_item(NAME(m_sync_character_received));
+
+ save_item(NAME(m_receiver_output_reg));
+ save_item(NAME(m_receiver_sync_reg));
+ save_item(NAME(m_receiver_shift_reg));
+ save_item(NAME(m_serial_rx_state));
+
+ save_item(NAME(m_in_sync));
+}
+
+void s2350_device::device_reset()
+{
+ // transmitter flags
+ set_transmit_buffer_empty(true);
+ set_fill_char_transmitted(false);
+
+ // transmitter registers
+ m_transmitter_shift_reg = 0xff;
+ m_transmitter_holding_reg = 0xff;
+ m_transmitter_fill_reg = 0x00;
+
+ m_serial_tx_state = 0;
+
+ set_received_data_available(false);
+ set_receiver_overrun(false);
+ set_receiver_parity_error(false);
+ set_sync_character_received(false);
+
+ m_sync_search_active = false;
+ m_in_sync = false;
+
+ m_serial_rx_state = 0;
+
+ // receiver registers
+ m_receiver_output_reg = 0x00;
+ m_receiver_sync_reg = 0x00;
+ m_receiver_shift_reg = 0x00;
+}
+
+void s2350_device::transmitter_holding_reg_w(u8 data)
+{
+ LOGREG("%s: 0x%02x\n", FUNCNAME, data);
+
+ m_transmitter_holding_reg = data;
+ set_transmit_buffer_empty(false);
+}
+
+void s2350_device::transmit_fill_reg_w(u8 data)
+{
+ LOGREG("%s: 0x%02x\n", FUNCNAME, data);
+
+ m_transmitter_fill_reg = data;
+}
+
+void s2350_device::receiver_sync_reg_w(u8 data)
+{
+ LOGREG("%s: 0x%02x\n", FUNCNAME, data);
+
+ m_receiver_sync_reg = data;
+}
+
+u8 s2350_device::receiver_sync_search()
+{
+ set_sync_character_received(false);
+ m_sync_search_active = true;
+
+ LOGREG("%s: 0x%02x\n", FUNCNAME, m_receiver_sync_reg);
+
+ return m_receiver_sync_reg;
+}
+
+u8 s2350_device::receiver_output_reg_r()
+{
+ set_received_data_available(false);
+
+ LOGREG("%s: 0x%02x\n", FUNCNAME, m_receiver_output_reg);
+
+ return m_receiver_output_reg;
+}
+
+u8 s2350_device::status_word_r()
+{
+ u8 status = 0x00;
+
+ status |= m_received_data_available ? 0x01 : 0x00;
+ status |= m_receiver_overrun ? 0x02 : 0x00;
+ status |= m_receiver_parity_error ? 0x04 : 0x00;
+ status |= m_sync_character_received ? 0x08 : 0x00;
+ status |= m_fill_char_transmitted ? 0x40 : 0x00;
+ status |= m_transmit_buffer_empty ? 0x80 : 0x00;
+
+ if (!machine().side_effects_disabled())
+ {
+ set_fill_char_transmitted(false);
+ set_receiver_overrun(false);
+ set_receiver_parity_error(false);
+ set_sync_character_received(false);
+ }
+
+ LOGREG("%s: 0x%02x\n", FUNCNAME, status);
+
+ return status;
+}
+
+void s2350_device::rx_w(int state)
+{
+ m_serial_rx_line = state;
+}
+
+void s2350_device::receiver_restart()
+{
+ LOGFUNC("%s\n", FUNCNAME);
+
+ set_received_data_available(false);
+ set_sync_character_received(false);
+ set_receiver_overrun(false);
+ set_receiver_parity_error(false);
+
+ m_sync_search_active = true;
+ m_serial_rx_state = 0;
+ m_serial_tx_state = 0;
+}
+
+void s2350_device::receive_byte(u8 data)
+{
+ if (m_received_data_available)
+ {
+ set_receiver_overrun(true);
+ }
+
+ m_receiver_output_reg = data;
+ set_received_data_available(true);
+}
+
+void s2350_device::set_transmit_buffer_empty(bool val)
+{
+ LOGLINE("%s - val: %d\n", FUNCNAME, val);
+
+ m_transmit_buffer_empty = val;
+
+ m_tbmt(val);
+}
+
+void s2350_device::set_fill_char_transmitted(bool val)
+{
+ LOGLINE("%s - val: %d\n", FUNCNAME, val);
+
+ m_fill_char_transmitted = val;
+
+ m_fct(val);
+}
+
+void s2350_device::set_received_data_available(bool val)
+{
+ LOGLINE("%s - val: %d\n", FUNCNAME, val);
+
+ m_received_data_available = val;
+
+ m_rda(val);
+}
+
+void s2350_device::set_receiver_overrun(bool val)
+{
+ LOGLINE("%s - val: %d\n", FUNCNAME, val);
+
+ m_receiver_overrun = val;
+
+ m_ror(val);
+}
+
+void s2350_device::set_receiver_parity_error(bool val)
+{
+ LOGLINE("%s - val: %d\n", FUNCNAME, val);
+
+ m_receiver_parity_error = val;
+
+ m_rpe(val);
+}
+
+void s2350_device::set_sync_character_received(bool val)
+{
+ LOGLINE("%s - val: %d\n", FUNCNAME, val);
+
+ m_sync_character_received = val;
+
+ m_scr(val);
+}
+
+void s2350_device::update_receiver_shift()
+{
+ m_receiver_sync_reg >>= 1;
+
+ m_receiver_shift_reg |= m_serial_rx_line ? 0x80 : 0x00;
+}
+
+void s2350_device::rcp_w()
+{
+ if (m_in_sync)
+ {
+ if (m_serial_rx_state++ == 0)
+ {
+ m_receiver_shift_reg = 0;
+ }
+
+ update_receiver_shift();
+
+ if (m_serial_rx_state == 8)
+ {
+ receive_byte(m_receiver_shift_reg);
+
+ m_serial_rx_state = 0;
+ }
+ }
+ else if (m_sync_search_active)
+ {
+ LOGSYNC("%s - searching for sync\n", FUNCNAME);
+
+ update_receiver_shift();
+
+ // check for a match
+ if (m_receiver_sync_reg == m_receiver_shift_reg)
+ {
+ LOGSYNC("%s - sync found\n", FUNCNAME);
+
+ m_serial_rx_line = 0;
+ m_in_sync = true;
+ }
+ }
+ else
+ {
+ LOGSYNC("%s - ignoring data\n", FUNCNAME);
+ }
+}
+
+void s2350_device::tcp_w()
+{
+ if (m_serial_tx_state == 0)
+ {
+ if (m_transmit_buffer_empty)
+ {
+ set_fill_char_transmitted(true);
+ m_transmitter_shift_reg = m_transmitter_fill_reg;
+ }
+ else
+ {
+ set_transmit_buffer_empty(false);
+ set_fill_char_transmitted(false);
+ m_transmitter_shift_reg = m_transmitter_holding_reg;
+ }
+ }
+
+ m_tx_cb(BIT(m_transmitter_shift_reg, m_serial_tx_state));
+
+ m_serial_tx_state = (m_serial_tx_state + 1) & 0x7;
+}
diff --git a/src/devices/machine/s2350.h b/src/devices/machine/s2350.h
new file mode 100644
index 00000000000..8726f1af611
--- /dev/null
+++ b/src/devices/machine/s2350.h
@@ -0,0 +1,119 @@
+// license:BSD-3-Clause
+// copyright-holders:Mark Garlanger
+/**********************************************************************
+
+ American Systems Inc. S2350 Universal Synchronous Receiver/Transmitter
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_S2350_H
+#define MAME_MACHINE_S2350_H
+
+#pragma once
+
+#include "machine/timer.h"
+
+
+//
+// AMI S2350 USRT
+//
+class s2350_device : public device_t
+{
+public:
+ s2350_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // transmit bits
+ auto tx_handler() { return m_tx_cb.bind(); }
+
+ // transmit statuses
+ auto transmit_buffer_empty_cb() { return m_tbmt.bind(); }
+ auto fill_character_transmitted_cb() { return m_fct.bind(); }
+
+ // receive statuses
+ auto received_data_available_cb() { return m_rda.bind(); }
+ auto sync_character_received_cb() { return m_scr.bind(); }
+ auto receiver_overrun_cb() { return m_ror.bind(); }
+ auto receiver_parity_error_cb() { return m_rpe.bind(); }
+
+ void rx_w(int state);
+
+ void transmitter_holding_reg_w(uint8_t data);
+ void transmit_fill_reg_w(uint8_t data);
+ void receiver_sync_reg_w(uint8_t data);
+
+ u8 receiver_output_reg_r();
+ u8 status_word_r();
+ u8 receiver_sync_search();
+
+ void receiver_restart();
+
+ // transmitter clock
+ void tcp_w();
+ // receiver clock
+ void rcp_w();
+
+protected:
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void update_receiver_shift();
+
+ void set_transmit_buffer_empty(bool val);
+ void set_fill_char_transmitted(bool val);
+
+ void set_received_data_available(bool val);
+ void set_receiver_overrun(bool val);
+ void set_receiver_parity_error(bool val);
+ void set_sync_character_received(bool val);
+
+ void receive_byte(uint8_t data);
+
+ u8 m_serial_rx_line;
+
+ // transmit flags
+ bool m_transmit_buffer_empty;
+ bool m_fill_char_transmitted;
+
+ // transmit registers
+ u8 m_transmitter_holding_reg;
+ u8 m_transmitter_fill_reg;
+ u8 m_transmitter_shift_reg;
+
+ // transmit state (current bit being sent)
+ uint8_t m_serial_tx_state;
+
+ // transmit status callbacks
+ devcb_write_line m_tbmt; // Transmit Buffer Empty
+ devcb_write_line m_fct; // Fill Character Transmitted
+
+ // transmit data callback
+ devcb_write_line m_tx_cb;
+
+ // receive flags
+ bool m_received_data_available;
+ bool m_receiver_overrun;
+ bool m_receiver_parity_error; // not currently used
+ bool m_sync_character_received;
+
+ // receive registers
+ u8 m_receiver_output_reg;
+ u8 m_receiver_sync_reg;
+ u8 m_receiver_shift_reg;
+
+ // receiver state
+ u8 m_serial_rx_state; // current bit being received
+ bool m_sync_search_active;
+ bool m_in_sync;
+
+ // receiver status callbacks
+ devcb_write_line m_rda; // Received Data Available
+ devcb_write_line m_scr; // Sync Character Received
+ devcb_write_line m_ror; // Receiver Overrun
+ devcb_write_line m_rpe; // Receiver Parity Error
+};
+
+
+DECLARE_DEVICE_TYPE(S2350, s2350_device)
+
+#endif // MAME_MACHINE_S2350_H
diff --git a/src/devices/machine/s2636.cpp b/src/devices/machine/s2636.cpp
index 8ad26690bcf..c8e90251799 100644
--- a/src/devices/machine/s2636.cpp
+++ b/src/devices/machine/s2636.cpp
@@ -119,7 +119,7 @@
*************************************************************/
#include "emu.h"
-#include "machine/s2636.h"
+#include "s2636.h"
#include "screen.h"
@@ -206,8 +206,6 @@ void s2636_device::device_start()
m_stream = stream_alloc(0, 1, machine().sample_rate());
save_item(NAME(m_sample_cnt));
save_item(NAME(m_sound_lvl));
-
- m_intreq_cb.resolve_safe();
}
diff --git a/src/devices/machine/s3520cf.cpp b/src/devices/machine/s3520cf.cpp
index abdd1d83638..567e9792b66 100644
--- a/src/devices/machine/s3520cf.cpp
+++ b/src/devices/machine/s3520cf.cpp
@@ -15,8 +15,7 @@ TODO:
***************************************************************************/
#include "emu.h"
-#include "machine/s3520cf.h"
-
+#include "s3520cf.h"
//**************************************************************************
@@ -44,6 +43,7 @@ s3520cf_device::s3520cf_device(const machine_config &mconfig, const char *tag, d
s3520cf_device::s3520cf_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, device_nvram_interface(mconfig, *this)
+ , device_rtc_interface(mconfig, *this)
, m_region(*this, DEVICE_SELF)
, m_dir(0), m_latch(0), m_reset_line(0), m_read_latch(0), m_bitstream(0), m_stream_pos(0), m_mode(0), m_sysr(0), m_cntrl1(0), m_cntrl2(0)
{
@@ -105,20 +105,9 @@ void s3520cf_device::device_validity_check(validity_checker &valid) const
void s3520cf_device::device_start()
{
/* let's call the timer callback every second for now */
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3520cf_device::timer_callback), this));
+ m_timer = timer_alloc(FUNC(s3520cf_device::timer_callback), this);
m_timer->adjust(attotime::from_hz(clock() / XTAL(32'768)), 0, attotime::from_hz(clock() / XTAL(32'768)));
- system_time systime;
- machine().base_datetime(systime);
-
- m_rtc.day = ((systime.local_time.mday / 10)<<4) | ((systime.local_time.mday % 10) & 0xf);
- m_rtc.month = (((systime.local_time.month+1) / 10) << 4) | (((systime.local_time.month+1) % 10) & 0xf);
- m_rtc.wday = systime.local_time.weekday;
- m_rtc.year = (((systime.local_time.year % 100)/10)<<4) | ((systime.local_time.year % 10) & 0xf);
- m_rtc.hour = ((systime.local_time.hour / 10)<<4) | ((systime.local_time.hour % 10) & 0xf);
- m_rtc.min = ((systime.local_time.minute / 10)<<4) | ((systime.local_time.minute % 10) & 0xf);
- m_rtc.sec = ((systime.local_time.second / 10)<<4) | ((systime.local_time.second % 10) & 0xf);
-
save_item(NAME(m_dir));
save_item(NAME(m_latch));
save_item(NAME(m_reset_line));
@@ -172,9 +161,10 @@ void s3520cf_device::nvram_default()
// .nv file
//-------------------------------------------------
-void s3520cf_device::nvram_read(emu_file &file)
+bool s3520cf_device::nvram_read(util::read_stream &file)
{
- file.read(m_nvdata, 15);
+ auto const [err, actual] = read(file, m_nvdata, 15);
+ return !err && (actual == 15);
}
//-------------------------------------------------
@@ -182,9 +172,21 @@ void s3520cf_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void s3520cf_device::nvram_write(emu_file &file)
+bool s3520cf_device::nvram_write(util::write_stream &file)
+{
+ auto const [err, actual] = write(file, m_nvdata, 15);
+ return !err;
+}
+
+void s3520cf_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
{
- file.write(m_nvdata, 15);
+ m_rtc.day = ((day / 10)<<4) | ((day % 10) & 0xf);
+ m_rtc.month = ((month / 10) << 4) | ((month % 10) & 0xf);
+ m_rtc.wday = day_of_week - 1;
+ m_rtc.year = (((year % 100)/10)<<4) | ((year % 10) & 0xf);
+ m_rtc.hour = ((hour / 10)<<4) | ((hour % 10) & 0xf);
+ m_rtc.min = ((minute / 10)<<4) | ((minute % 10) & 0xf);
+ m_rtc.sec = ((second / 10)<<4) | ((second % 10) & 0xf);
}
//-------------------------------------------------
@@ -279,19 +281,19 @@ inline void s3520cf_device::rtc_write(u8 offset,u8 data)
// READ/WRITE HANDLERS
//**************************************************************************
-READ_LINE_MEMBER( s3520cf_device::read_bit )
+int s3520cf_device::read_bit()
{
return m_read_latch;
}
-WRITE_LINE_MEMBER( s3520cf_device::set_dir_line )
+void s3520cf_device::set_dir_line(int state)
{
//printf("%d DIR LINE\n",state);
m_dir = state;
}
-WRITE_LINE_MEMBER( s3520cf_device::set_cs_line )
+void s3520cf_device::set_cs_line(int state)
{
m_reset_line = state;
@@ -305,13 +307,13 @@ WRITE_LINE_MEMBER( s3520cf_device::set_cs_line )
}
}
-WRITE_LINE_MEMBER( s3520cf_device::write_bit )
+void s3520cf_device::write_bit(int state)
{
m_latch = state;
// printf("%d LATCH LINE\n",state);
}
-WRITE_LINE_MEMBER( s3520cf_device::set_clock_line )
+void s3520cf_device::set_clock_line(int state)
{
// NOTE: this device use 1-cycle (8 clocks) delayed data output
if(state == 1 && m_reset_line == CLEAR_LINE)
diff --git a/src/devices/machine/s3520cf.h b/src/devices/machine/s3520cf.h
index 11e739c9b9e..da4c1083fce 100644
--- a/src/devices/machine/s3520cf.h
+++ b/src/devices/machine/s3520cf.h
@@ -11,6 +11,8 @@ Seiko/Epson S-3520CF
#pragma once
+#include "dirtc.h"
+
//**************************************************************************
// TYPE DEFINITIONS
@@ -19,18 +21,19 @@ Seiko/Epson S-3520CF
// ======================> s3520cf_device
class s3520cf_device : public device_t,
- public device_nvram_interface
+ public device_nvram_interface,
+ public device_rtc_interface
{
public:
// construction/destruction
s3520cf_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 32'768);
// I/O operations
- DECLARE_READ_LINE_MEMBER( read_bit );
- DECLARE_WRITE_LINE_MEMBER( set_dir_line );
- DECLARE_WRITE_LINE_MEMBER( set_cs_line );
- DECLARE_WRITE_LINE_MEMBER( set_clock_line );
- DECLARE_WRITE_LINE_MEMBER( write_bit );
+ int read_bit();
+ void set_dir_line(int state);
+ void set_cs_line(int state);
+ void set_clock_line(int state);
+ void write_bit(int state);
TIMER_CALLBACK_MEMBER(timer_callback);
protected:
@@ -48,8 +51,13 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return false; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
optional_memory_region m_region;
diff --git a/src/devices/machine/s3c2400.cpp b/src/devices/machine/s3c2400.cpp
index 69649d04db0..437612a8331 100644
--- a/src/devices/machine/s3c2400.cpp
+++ b/src/devices/machine/s3c2400.cpp
@@ -9,7 +9,7 @@
*******************************************************************************/
#include "emu.h"
-#include "machine/s3c2400.h"
+#include "s3c2400.h"
#include "cpu/arm7/arm7.h"
#include "cpu/arm7/arm7core.h"
@@ -166,14 +166,14 @@ s3c2400_device::s3c2400_device(const machine_config &mconfig, const char *tag, d
, m_cpu(*this, ":maincpu")
, m_palette(*this, finder_base::DUMMY_TAG)
, m_screen(*this, finder_base::DUMMY_TAG)
- , m_pin_r_cb(*this)
+ , m_pin_r_cb(*this, 0)
, m_pin_w_cb(*this)
- , m_port_r_cb(*this)
+ , m_port_r_cb(*this, 0)
, m_port_w_cb(*this)
, m_scl_w_cb(*this)
- , m_sda_r_cb(*this)
+ , m_sda_r_cb(*this, 1)
, m_sda_w_cb(*this)
- , m_data_r_cb(*this)
+ , m_data_r_cb(*this, 0)
, m_data_w_cb(*this)
, m_flags(0)
{
diff --git a/src/devices/machine/s3c2410.cpp b/src/devices/machine/s3c2410.cpp
index e630174b326..e5017ddaed4 100644
--- a/src/devices/machine/s3c2410.cpp
+++ b/src/devices/machine/s3c2410.cpp
@@ -9,7 +9,7 @@
*******************************************************************************/
#include "emu.h"
-#include "machine/s3c2410.h"
+#include "s3c2410.h"
#include "cpu/arm7/arm7.h"
#include "cpu/arm7/arm7core.h"
@@ -222,18 +222,18 @@ s3c2410_device::s3c2410_device(const machine_config &mconfig, const char *tag, d
, m_cpu(*this, ":maincpu")
, m_palette(*this, finder_base::DUMMY_TAG)
, m_screen(*this, finder_base::DUMMY_TAG)
- , m_pin_r_cb(*this)
+ , m_pin_r_cb(*this, 0)
, m_pin_w_cb(*this)
- , m_port_r_cb(*this)
+ , m_port_r_cb(*this, 0)
, m_port_w_cb(*this)
, m_scl_w_cb(*this)
- , m_sda_r_cb(*this)
+ , m_sda_r_cb(*this, 1)
, m_sda_w_cb(*this)
- , m_data_r_cb(*this)
+ , m_data_r_cb(*this, 0)
, m_data_w_cb(*this)
, m_command_w_cb(*this)
, m_address_w_cb(*this)
- , m_nand_data_r_cb(*this)
+ , m_nand_data_r_cb(*this, 0)
, m_nand_data_w_cb(*this)
, m_flags(0)
{
@@ -320,7 +320,7 @@ void s3c2410_device::s3c2410_touch_screen( int state)
s3c24xx_touch_screen(state);
}
-WRITE_LINE_MEMBER( s3c2410_device::frnb_w )
+void s3c2410_device::frnb_w(int state)
{
s3c24xx_pin_frnb_w(state);
}
diff --git a/src/devices/machine/s3c2410.h b/src/devices/machine/s3c2410.h
index 46b16b441d8..d86193c365f 100644
--- a/src/devices/machine/s3c2410.h
+++ b/src/devices/machine/s3c2410.h
@@ -155,7 +155,7 @@ public:
auto nand_data_w_callback() { return m_nand_data_w_cb.bind(); }
void set_lcd_flags(int flags) { m_flags = flags; }
- DECLARE_WRITE_LINE_MEMBER( frnb_w );
+ void frnb_w(int state);
uint32_t s3c24xx_lcd_r(offs_t offset, uint32_t mem_mask = ~0);
@@ -335,7 +335,7 @@ protected:
uint32_t s3c24xx_nand_r(offs_t offset, uint32_t mem_mask = ~0);
void s3c24xx_nand_init_ecc();
void s3c24xx_nand_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- ATTR_UNUSED WRITE_LINE_MEMBER( s3c24xx_pin_frnb_w );
+ [[maybe_unused]] void s3c24xx_pin_frnb_w(int state);
void s3c24xx_nand_auto_boot();
void s3c24xx_device_reset();
void s3c24xx_device_start();
diff --git a/src/devices/machine/s3c2440.cpp b/src/devices/machine/s3c2440.cpp
index 801c21dd01d..3bec1249b11 100644
--- a/src/devices/machine/s3c2440.cpp
+++ b/src/devices/machine/s3c2440.cpp
@@ -9,7 +9,7 @@
*******************************************************************************/
#include "emu.h"
-#include "machine/s3c2440.h"
+#include "s3c2440.h"
#include "cpu/arm7/arm7.h"
#include "cpu/arm7/arm7core.h"
@@ -237,19 +237,19 @@ s3c2440_device::s3c2440_device(const machine_config &mconfig, const char *tag, d
, m_cpu(*this, ":maincpu")
, m_palette(*this, finder_base::DUMMY_TAG)
, m_screen(*this, finder_base::DUMMY_TAG)
- , m_pin_r_cb(*this)
+ , m_pin_r_cb(*this, 0)
, m_pin_w_cb(*this)
- , m_port_r_cb(*this)
+ , m_port_r_cb(*this, 0)
, m_port_w_cb(*this)
, m_scl_w_cb(*this)
- , m_sda_r_cb(*this)
+ , m_sda_r_cb(*this, 1)
, m_sda_w_cb(*this)
- , m_data_r_cb(*this)
+ , m_data_r_cb(*this, 0)
, m_data_w_cb(*this)
, m_flags(0)
, m_command_w_cb(*this)
, m_address_w_cb(*this)
- , m_nand_data_r_cb(*this)
+ , m_nand_data_r_cb(*this, 0)
, m_nand_data_w_cb(*this)
{
memset(m_steppingstone, 0, sizeof(m_steppingstone));
@@ -350,7 +350,7 @@ void s3c2440_device::s3c2440_request_eint(uint32_t number)
s3c24xx_request_eint( number);
}
-WRITE_LINE_MEMBER( s3c2440_device::frnb_w )
+void s3c2440_device::frnb_w(int state)
{
s3c24xx_pin_frnb_w(state);
}
diff --git a/src/devices/machine/s3c2440.h b/src/devices/machine/s3c2440.h
index 18bdeecacc7..0c3f71391d7 100644
--- a/src/devices/machine/s3c2440.h
+++ b/src/devices/machine/s3c2440.h
@@ -175,7 +175,7 @@ public:
auto nand_data_w_callback() { return m_nand_data_w_cb.bind(); }
void set_lcd_flags(int flags) { m_flags = flags; }
- DECLARE_WRITE_LINE_MEMBER( frnb_w );
+ void frnb_w(int state);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
@@ -356,7 +356,7 @@ protected:
uint32_t s3c24xx_nand_r(offs_t offset, uint32_t mem_mask = ~0);
void s3c24xx_nand_init_ecc();
void s3c24xx_nand_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- ATTR_UNUSED WRITE_LINE_MEMBER( s3c24xx_pin_frnb_w );
+ [[maybe_unused]] void s3c24xx_pin_frnb_w(int state);
uint32_t s3c24xx_cam_r(offs_t offset, uint32_t mem_mask = ~0);
void s3c24xx_cam_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t s3c24xx_ac97_r(offs_t offset, uint32_t mem_mask = ~0);
diff --git a/src/devices/machine/s3c24xx.hxx b/src/devices/machine/s3c24xx.hxx
index 8fae9ee616e..d4deb1f0ceb 100644
--- a/src/devices/machine/s3c24xx.hxx
+++ b/src/devices/machine/s3c24xx.hxx
@@ -133,14 +133,7 @@ void S3C24_CLASS_NAME::s3c24xx_reset()
int S3C24_CLASS_NAME::iface_core_pin_r(int pin)
{
- if (!m_pin_r_cb.isnull())
- {
- return (m_pin_r_cb)(pin);
- }
- else
- {
- return 0;
- }
+ return m_pin_r_cb(pin);
}
/* LCD Controller */
@@ -1155,12 +1148,6 @@ void S3C24_CLASS_NAME::s3c24xx_check_pending_irq()
temp = (m_irq.regs.srcpnd & ~m_irq.regs.intmsk) & m_irq.regs.intmod;
if (temp != 0)
{
- uint32_t int_type = 0;
- while ((temp & 1) == 0)
- {
- int_type++;
- temp = temp >> 1;
- }
if (m_irq.line_fiq != ASSERT_LINE)
{
LOGMASKED(LOG_IRQS, "asserting FIQ line\n");
@@ -1204,7 +1191,7 @@ void S3C24_CLASS_NAME::s3c24xx_check_pending_subirq()
}
}
-ATTR_UNUSED void S3C24_CLASS_NAME::s3c24xx_request_subirq( uint32_t int_type)
+[[maybe_unused]] void S3C24_CLASS_NAME::s3c24xx_request_subirq( uint32_t int_type)
{
LOGMASKED(LOG_IRQS, "request subirq %d\n", int_type);
m_irq.regs.subsrcpnd |= (1 << int_type);
@@ -1233,7 +1220,7 @@ void S3C24_CLASS_NAME::s3c24xx_check_pending_eint()
}
}
-ATTR_UNUSED void S3C24_CLASS_NAME::s3c24xx_request_eint(uint32_t number)
+[[maybe_unused]] void S3C24_CLASS_NAME::s3c24xx_request_eint(uint32_t number)
{
LOGMASKED(LOG_IRQS, "request external interrupt %d\n", number);
if (number < 4)
@@ -1760,25 +1747,15 @@ void S3C24_CLASS_NAME::s3c24xx_gpio_reset()
uint32_t S3C24_CLASS_NAME::iface_gpio_port_r(int port, uint32_t mask)
{
- if (!m_port_r_cb.isnull())
- {
- // TO CHECK : masking is not done in any of handlers
- // devcb do it automatically so guess is masks are not proper right now
- // without masking works fine
- return (m_port_r_cb)( port ); //, mask);
- }
- else
- {
- return 0;
- }
+ // TO CHECK : masking is not done in any of handlers
+ // devcb do it automatically so guess is masks are not proper right now
+ // without masking works fine
+ return m_port_r_cb( port ); //, mask);
}
void S3C24_CLASS_NAME::iface_gpio_port_w(int port, uint32_t mask, uint32_t data)
{
- if (!m_port_w_cb.isnull())
- {
- (m_port_w_cb)( port, data, mask );
- }
+ m_port_w_cb( port, data, mask );
}
uint16_t S3C24_CLASS_NAME::s3c24xx_gpio_get_mask( uint32_t con, int val)
@@ -1919,7 +1896,7 @@ void S3C24_CLASS_NAME::s3c24xx_gpio_w(offs_t offset, uint32_t data, uint32_t mem
uint32_t S3C24_CLASS_NAME::s3c24xx_memcon_r(offs_t offset, uint32_t mem_mask)
{
- assert(offset < ARRAY_LENGTH(m_memcon.regs.data));
+ assert(offset < std::size(m_memcon.regs.data));
uint32_t data = m_memcon.regs.data[offset];
LOGMASKED(LOG_MEMCON, "%s: memcon read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_MEMCON + (offset << 2), data, mem_mask);
return data;
@@ -2234,22 +2211,17 @@ void S3C24_CLASS_NAME::s3c24xx_iic_reset()
void S3C24_CLASS_NAME::iface_i2c_scl_w( int state)
{
- if (!m_scl_w_cb.isnull())
- m_scl_w_cb(state);
+ m_scl_w_cb(state);
}
void S3C24_CLASS_NAME::iface_i2c_sda_w(int state)
{
- if (!m_sda_w_cb.isnull())
- m_sda_w_cb(state);
+ m_sda_w_cb(state);
}
int S3C24_CLASS_NAME::iface_i2c_sda_r()
{
- if (!m_sda_r_cb.isnull())
- return m_sda_r_cb();
- else
- return 1;
+ return m_sda_r_cb();
}
void S3C24_CLASS_NAME::i2c_send_start()
@@ -2453,8 +2425,7 @@ TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_iic_timer_exp )
void S3C24_CLASS_NAME::iface_i2s_data_w(int ch, uint16_t data)
{
- if (!m_data_w_cb.isnull())
- (m_data_w_cb)(ch, data, 0);
+ m_data_w_cb(ch, data, 0);
}
void S3C24_CLASS_NAME::s3c24xx_iis_start()
@@ -2604,21 +2575,14 @@ void S3C24_CLASS_NAME::s3c24xx_adc_reset()
uint32_t S3C24_CLASS_NAME::iface_adc_data_r(int ch)
{
- if (!m_data_r_cb.isnull())
- {
- int offs = ch;
+ int offs = ch;
#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
- if (BIT(m_adc.regs.adctsc, 2) != 0)
- {
- offs += 2;
- }
-#endif
- return m_data_r_cb(offs, 0);
- }
- else
+ if (BIT(m_adc.regs.adctsc, 2) != 0)
{
- return 0;
+ offs += 2;
}
+#endif
+ return m_data_r_cb(offs, 0);
}
uint32_t S3C24_CLASS_NAME::s3c24xx_adc_r(offs_t offset, uint32_t mem_mask)
@@ -2817,32 +2781,22 @@ void S3C24_CLASS_NAME::s3c24xx_nand_reset()
void S3C24_CLASS_NAME::iface_nand_command_w(uint8_t data)
{
- if (!m_command_w_cb.isnull())
- {
- m_command_w_cb(0, data, 0xff);
- }
+ m_command_w_cb(0, data, 0xff);
}
void S3C24_CLASS_NAME::iface_nand_address_w(uint8_t data)
{
- if (!m_address_w_cb.isnull())
- {
- m_address_w_cb(0, data, 0xff);
- }
+ m_address_w_cb(0, data, 0xff);
}
uint8_t S3C24_CLASS_NAME::iface_nand_data_r()
{
- if (!m_nand_data_r_cb.isnull())
- return m_nand_data_r_cb(0, 0xff);
- else
- return 0;
+ return m_nand_data_r_cb(0, 0xff);
}
void S3C24_CLASS_NAME::iface_nand_data_w(uint8_t data)
{
- if (!m_nand_data_w_cb.isnull())
- m_nand_data_w_cb(0, data, 0xff);
+ m_nand_data_w_cb(0, data, 0xff);
}
void S3C24_CLASS_NAME::nand_update_mecc(uint8_t *ecc, int pos, uint8_t data)
@@ -3086,7 +3040,7 @@ void S3C24_CLASS_NAME::s3c24xx_nand_w(offs_t offset, uint32_t data, uint32_t mem
}
}
-ATTR_UNUSED WRITE_LINE_MEMBER( S3C24_CLASS_NAME::s3c24xx_pin_frnb_w )
+[[maybe_unused]] void S3C24_CLASS_NAME::s3c24xx_pin_frnb_w(int state)
{
LOGMASKED(LOG_FLASH, "s3c24xx_pin_frnb_w (%d)\n", state);
#if defined(DEVICE_S3C2440)
@@ -3256,31 +3210,16 @@ void S3C24_CLASS_NAME::s3c24xx_device_reset()
void S3C24_CLASS_NAME::s3c24xx_device_start()
{
LOGMASKED(LOG_RESET, "s3c24xx device start\n");
- m_pin_r_cb.resolve();
- m_pin_w_cb.resolve_safe();
- m_port_r_cb.resolve();
- m_port_w_cb.resolve();
- m_scl_w_cb.resolve();
- m_sda_r_cb.resolve();
- m_sda_w_cb.resolve();
- m_data_r_cb.resolve();
- m_data_w_cb.resolve();
-#if !defined(DEVICE_S3C2400)
- m_command_w_cb.resolve();
- m_address_w_cb.resolve();
- m_nand_data_r_cb.resolve();
- m_nand_data_w_cb.resolve();
-#endif
for (int i = 0; i < 5; i++)
- m_pwm.timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_pwm_timer_exp), this));
+ m_pwm.timer[i] = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_pwm_timer_exp), this);
for (auto & elem : m_dma)
- elem.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_dma_timer_exp), this));
- m_iic.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_iic_timer_exp), this));
- m_iis.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_iis_timer_exp), this));
- m_lcd.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_lcd_timer_exp), this));
- m_rtc.timer_tick_count = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_tick_count_exp), this));
- m_rtc.timer_update = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_update_exp), this));
- m_wdt.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_wdt_timer_exp), this));
+ elem.timer = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_dma_timer_exp), this);
+ m_iic.timer = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_iic_timer_exp), this);
+ m_iis.timer = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_iis_timer_exp), this);
+ m_lcd.timer = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_lcd_timer_exp), this);
+ m_rtc.timer_tick_count = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_tick_count_exp), this);
+ m_rtc.timer_update = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_update_exp), this);
+ m_wdt.timer = timer_alloc(FUNC(S3C24_CLASS_NAME::s3c24xx_wdt_timer_exp), this);
#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
int om0 = iface_core_pin_r(S3C24XX_CORE_PIN_OM0);
diff --git a/src/devices/machine/s3c44b0.cpp b/src/devices/machine/s3c44b0.cpp
index bf3a1ed811c..a67be48455c 100644
--- a/src/devices/machine/s3c44b0.cpp
+++ b/src/devices/machine/s3c44b0.cpp
@@ -9,15 +9,14 @@
*******************************************************************************/
#include "emu.h"
-#include "machine/s3c44b0.h"
+#include "s3c44b0.h"
#include "cpu/arm7/arm7.h"
#include "cpu/arm7/arm7core.h"
#include "screen.h"
-#include "coreutil.h"
-
#include <algorithm>
+#include <cstdarg>
#define S3C44B0_INTCON (0x00 / 4) // Interrupt Control
@@ -228,12 +227,12 @@ s3c44b0_device::s3c44b0_device(const machine_config &mconfig, const char *tag, d
: device_t(mconfig, S3C44B0, tag, owner, clock)
, device_video_interface(mconfig, *this)
, m_cpu(*this, finder_base::DUMMY_TAG)
- , m_port_r_cb(*this)
+ , m_port_r_cb(*this, 0)
, m_port_w_cb(*this)
, m_scl_w_cb(*this)
- , m_sda_r_cb(*this)
+ , m_sda_r_cb(*this, 0)
, m_sda_w_cb(*this)
- , m_data_r_cb(*this)
+ , m_data_r_cb(*this, 0)
, m_data_w_cb(*this)
{
memset(&m_irq, 0, sizeof(s3c44b0_irq_t));
@@ -258,27 +257,19 @@ s3c44b0_device::s3c44b0_device(const machine_config &mconfig, const char *tag, d
void s3c44b0_device::device_start()
{
- m_port_r_cb.resolve();
- m_port_w_cb.resolve();
- m_scl_w_cb.resolve();
- m_sda_r_cb.resolve();
- m_sda_w_cb.resolve();
- m_data_r_cb.resolve_safe(0);
- m_data_w_cb.resolve();
-
m_cpu->space(AS_PROGRAM).cache(m_cache);
- for (int i = 0; i < 6; i++) m_pwm.timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::pwm_timer_exp),this));
- for (auto & elem : m_uart) elem.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::uart_timer_exp),this));
- for (auto & elem : m_zdma) elem.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::zdma_timer_exp),this));
- for (auto & elem : m_bdma) elem.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::bdma_timer_exp),this));
+ for (int i = 0; i < 6; i++) m_pwm.timer[i] = timer_alloc(FUNC(s3c44b0_device::pwm_timer_exp), this);
+ for (auto & elem : m_uart) elem.timer = timer_alloc(FUNC(s3c44b0_device::uart_timer_exp), this);
+ for (auto & elem : m_zdma) elem.timer = timer_alloc(FUNC(s3c44b0_device::zdma_timer_exp), this);
+ for (auto & elem : m_bdma) elem.timer = timer_alloc(FUNC(s3c44b0_device::bdma_timer_exp), this);
- m_lcd.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::lcd_timer_exp),this));
- m_wdt.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::wdt_timer_exp),this));
- m_sio.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::sio_timer_exp),this));
- m_adc.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::adc_timer_exp),this));
- m_iic.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::iic_timer_exp),this));
- m_iis.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::iis_timer_exp),this));
+ m_lcd.timer = timer_alloc(FUNC(s3c44b0_device::lcd_timer_exp), this);
+ m_wdt.timer = timer_alloc(FUNC(s3c44b0_device::wdt_timer_exp), this);
+ m_sio.timer = timer_alloc(FUNC(s3c44b0_device::sio_timer_exp), this);
+ m_adc.timer = timer_alloc(FUNC(s3c44b0_device::adc_timer_exp), this);
+ m_iic.timer = timer_alloc(FUNC(s3c44b0_device::iic_timer_exp), this);
+ m_iis.timer = timer_alloc(FUNC(s3c44b0_device::iis_timer_exp), this);
video_start();
@@ -916,12 +907,6 @@ void s3c44b0_device::check_pending_irq()
temp = (m_irq.regs.intpnd & ~m_irq.regs.intmsk) & m_irq.regs.intmod;
if (temp != 0)
{
- uint32_t int_type = 0;
- while ((temp & 1) == 0)
- {
- int_type++;
- temp = temp >> 1;
- }
if (m_irq.line_fiq != ASSERT_LINE)
{
m_cpu->set_input_line(ARM7_FIRQ_LINE, ASSERT_LINE);
@@ -947,17 +932,8 @@ void s3c44b0_device::request_irq(uint32_t int_type)
void s3c44b0_device::check_pending_eint()
{
- uint32_t temp = m_gpio.regs.extintpnd;
- if (temp != 0)
- {
- uint32_t int_type = 0;
- while ((temp & 1) == 0)
- {
- int_type++;
- temp = temp >> 1;
- }
+ if (m_gpio.regs.extintpnd != 0)
request_irq(S3C44B0_INT_EINT4_7);
- }
}
void s3c44b0_device::request_eint(uint32_t number)
@@ -1236,22 +1212,17 @@ TIMER_CALLBACK_MEMBER( s3c44b0_device::pwm_timer_exp )
inline void s3c44b0_device::iface_i2c_scl_w(int state)
{
- if (!m_scl_w_cb.isnull())
- (m_scl_w_cb)( state);
+ m_scl_w_cb(state);
}
inline void s3c44b0_device::iface_i2c_sda_w(int state)
{
- if (!m_sda_w_cb.isnull())
- (m_sda_w_cb)( state);
+ m_sda_w_cb(state);
}
inline int s3c44b0_device::iface_i2c_sda_r()
{
- if (!m_sda_r_cb.isnull())
- return (m_sda_r_cb)();
- else
- return 0;
+ return m_sda_r_cb();
}
void s3c44b0_device::i2c_send_start()
@@ -1458,16 +1429,12 @@ TIMER_CALLBACK_MEMBER( s3c44b0_device::iic_timer_exp )
inline uint32_t s3c44b0_device::iface_gpio_port_r(int port)
{
- if (!m_port_r_cb.isnull())
- return (m_port_r_cb)(port);
- else
- return 0;
+ return m_port_r_cb(port);
}
inline void s3c44b0_device::iface_gpio_port_w(int port, uint32_t data)
{
- if (!m_port_w_cb.isnull())
- (m_port_w_cb)(port, data, 0xffff);
+ m_port_w_cb(port, data, 0xffff);
}
uint32_t s3c44b0_device::gpio_r(offs_t offset, uint32_t mem_mask)
@@ -1896,8 +1863,7 @@ TIMER_CALLBACK_MEMBER( s3c44b0_device::sio_timer_exp )
inline void s3c44b0_device::iface_i2s_data_w(int ch, uint16_t data)
{
- if (!m_data_w_cb.isnull())
- (m_data_w_cb)(ch, data, 0);
+ m_data_w_cb(ch, data, 0);
}
void s3c44b0_device::iis_start()
diff --git a/src/devices/machine/s_smp.cpp b/src/devices/machine/s_smp.cpp
index fb4396b68d5..957f64dbe7a 100644
--- a/src/devices/machine/s_smp.cpp
+++ b/src/devices/machine/s_smp.cpp
@@ -61,7 +61,7 @@ s_smp_device::s_smp_device(const machine_config &mconfig, const char *tag, devic
: spc700_device(mconfig, S_SMP, tag, owner, clock, address_map_constructor(FUNC(s_smp_device::internal_map), this))
, m_data_config("data", ENDIANNESS_LITTLE, 8, 16)
, m_ipl_region(*this, "sound_ipl")
- , m_dsp_io_r_cb(*this)
+ , m_dsp_io_r_cb(*this, 0)
, m_dsp_io_w_cb(*this)
{
}
@@ -83,13 +83,10 @@ const tiny_rom_entry *s_smp_device::device_rom_region() const
void s_smp_device::device_start()
{
- m_dsp_io_r_cb.resolve_safe(0);
- m_dsp_io_w_cb.resolve_safe();
-
space(AS_DATA).specific(m_data);
space(AS_DATA).cache(m_dcache);
- m_tick_timer = timer_alloc(TIMER_TICK_ID);
+ m_tick_timer = timer_alloc(FUNC(s_smp_device::update_timers), this);
save_item(NAME(m_timer_enabled));
save_item(NAME(m_subcounter));
@@ -179,11 +176,8 @@ inline void s_smp_device::update_timer_tick(u8 which)
}
}
-void s_smp_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(s_smp_device::update_timers)
{
- if (id != TIMER_TICK_ID)
- throw emu_fatalerror("Unknown id in s_smp_device::device_timer");
-
for (int ch = 0; ch < 3; ch++)
update_timer_tick(ch);
}
@@ -284,7 +278,7 @@ void s_smp_device::io_w(offs_t offset, u8 data)
// osd_printf_debug("%s SPC: %02x to APU @ %d\n", machine().describe_context(), data, offset & 3);
m_port_out[offset - 4] = data;
// Unneeded, we already run at perfect_interleave
- // machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(20));
+ // machine().scheduler().perfect_quantum(attotime::from_usec(20));
break;
case 0xa: /* Timer 0 */
case 0xb: /* Timer 1 */
diff --git a/src/devices/machine/s_smp.h b/src/devices/machine/s_smp.h
index 9fd0232329c..45f83755507 100644
--- a/src/devices/machine/s_smp.h
+++ b/src/devices/machine/s_smp.h
@@ -31,7 +31,8 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_clock_changed() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_timers);
// device_memory_interface configuration
virtual space_config_vector memory_space_config() const override;
@@ -56,10 +57,6 @@ private:
u8 io_r(offs_t offset);
void io_w(offs_t offset, u8 data);
- enum
- {
- TIMER_TICK_ID = 1
- };
/* timers */
emu_timer *m_tick_timer;
bool m_timer_enabled[3];
diff --git a/src/devices/machine/sa1110.cpp b/src/devices/machine/sa1110.cpp
index 4a767de0d85..3e1c2f95f77 100644
--- a/src/devices/machine/sa1110.cpp
+++ b/src/devices/machine/sa1110.cpp
@@ -1,113 +1,1895 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
-/**************************************************************************
- *
- * Intel XScale SA1110 peripheral emulation
- *
- **************************************************************************/
+/***************************************************************************
+
+ Intel XScale SA1110 peripheral emulation
+
+***************************************************************************/
#include "emu.h"
#include "sa1110.h"
-#define LOG_UNKNOWN (1 << 1)
-#define LOG_INTC (1 << 2)
-#define LOG_POWER (1 << 3)
-#define LOG_ALL (LOG_UNKNOWN | LOG_INTC | LOG_POWER)
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_ICP (1U << 2)
+#define LOG_UART3 (1U << 3)
+#define LOG_UART3_HF (1U << 4)
+#define LOG_MCP (1U << 5)
+#define LOG_SSP (1U << 6)
+#define LOG_OSTIMER (1U << 7)
+#define LOG_OSTIMER_HF (1U << 8)
+#define LOG_RTC (1U << 9)
+#define LOG_RTC_HF (1U << 10)
+#define LOG_POWER (1U << 11)
+#define LOG_POWER_HF (1U << 12)
+#define LOG_RESET (1U << 13)
+#define LOG_GPIO (1U << 14)
+#define LOG_GPIO_HF (1U << 15)
+#define LOG_INTC (1U << 16)
+#define LOG_PPC (1U << 17)
+#define LOG_DMA (1U << 18)
+#define LOG_UDC (1U << 19)
+#define LOG_ALL (LOG_UNKNOWN | LOG_ICP | LOG_UART3 | LOG_MCP | LOG_OSTIMER | LOG_RTC | LOG_POWER | LOG_RESET | LOG_GPIO | LOG_INTC | LOG_PPC | LOG_DMA | LOG_UDC)
-#define VERBOSE (LOG_ALL)
+#define VERBOSE (0)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(SA1110_PERIPHERALS, sa1110_periphs_device, "sa1110_periphs", "Intel XScale SA1110 Peripherals")
-sa1110_periphs_device::sa1110_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+sa1110_periphs_device::sa1110_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, SA1110_PERIPHERALS, tag, owner, clock)
+ , device_serial_interface(mconfig, *this)
, m_maincpu(*this, finder_base::DUMMY_TAG)
+ , m_uart3_irqs(*this, "uart3irq")
+ , m_mcp_irqs(*this, "mcpirq")
+ , m_codec(*this, finder_base::DUMMY_TAG)
+ , m_gpio_out(*this)
+ , m_ssp_out(*this)
+ , m_uart3_tx_out(*this)
+{
+}
+
+void sa1110_periphs_device::map(address_map &map)
{
+ map(0x00000000, 0x00000003).rw(FUNC(sa1110_periphs_device::udc_udccr_r), FUNC(sa1110_periphs_device::udc_udccr_w));
+ map(0x00000004, 0x00000007).rw(FUNC(sa1110_periphs_device::udc_udcar_r), FUNC(sa1110_periphs_device::udc_udcar_w));
+ map(0x00000008, 0x0000000b).rw(FUNC(sa1110_periphs_device::udc_udcomp_r), FUNC(sa1110_periphs_device::udc_udcomp_w));
+ map(0x0000000c, 0x0000000f).rw(FUNC(sa1110_periphs_device::udc_udcimp_r), FUNC(sa1110_periphs_device::udc_udcimp_w));
+ map(0x00000010, 0x00000013).rw(FUNC(sa1110_periphs_device::udc_udccs0_r), FUNC(sa1110_periphs_device::udc_udccs0_w));
+ map(0x00000014, 0x00000017).rw(FUNC(sa1110_periphs_device::udc_udccs1_r), FUNC(sa1110_periphs_device::udc_udccs1_w));
+ map(0x00000018, 0x0000001b).rw(FUNC(sa1110_periphs_device::udc_udccs2_r), FUNC(sa1110_periphs_device::udc_udccs2_w));
+ map(0x0000001c, 0x0000001f).rw(FUNC(sa1110_periphs_device::udc_udcd0_r), FUNC(sa1110_periphs_device::udc_udcd0_w));
+ map(0x00000020, 0x00000023).rw(FUNC(sa1110_periphs_device::udc_udcwc_r), FUNC(sa1110_periphs_device::udc_udcwc_w));
+ map(0x00000028, 0x0000002b).rw(FUNC(sa1110_periphs_device::udc_udcdr_r), FUNC(sa1110_periphs_device::udc_udcdr_w));
+ map(0x00000030, 0x00000033).rw(FUNC(sa1110_periphs_device::udc_udcsr_r), FUNC(sa1110_periphs_device::udc_udcsr_w));
+
+ map(0x00030000, 0x00030003).rw(FUNC(sa1110_periphs_device::icp_utcr0_r), FUNC(sa1110_periphs_device::icp_utcr0_w));
+ map(0x00030004, 0x00030007).rw(FUNC(sa1110_periphs_device::icp_utcr1_r), FUNC(sa1110_periphs_device::icp_utcr1_w));
+ map(0x00030008, 0x0003000b).rw(FUNC(sa1110_periphs_device::icp_utcr2_r), FUNC(sa1110_periphs_device::icp_utcr2_w));
+ map(0x0003000c, 0x0003000f).rw(FUNC(sa1110_periphs_device::icp_utcr3_r), FUNC(sa1110_periphs_device::icp_utcr3_w));
+ map(0x00030010, 0x00030013).rw(FUNC(sa1110_periphs_device::icp_utcr4_r), FUNC(sa1110_periphs_device::icp_utcr4_w));
+ map(0x00030014, 0x00030017).rw(FUNC(sa1110_periphs_device::icp_utdr_r), FUNC(sa1110_periphs_device::icp_utdr_w));
+ map(0x0003001c, 0x0003001f).rw(FUNC(sa1110_periphs_device::icp_utcr0_r), FUNC(sa1110_periphs_device::icp_utcr0_w));
+ map(0x00030020, 0x00030023).r(FUNC(sa1110_periphs_device::icp_utcr1_r));
+ map(0x00030060, 0x00030063).rw(FUNC(sa1110_periphs_device::icp_hscr0_r), FUNC(sa1110_periphs_device::icp_hscr0_w));
+ map(0x00030064, 0x00030067).rw(FUNC(sa1110_periphs_device::icp_hscr1_r), FUNC(sa1110_periphs_device::icp_hscr1_w));
+ map(0x0003006c, 0x0003006f).rw(FUNC(sa1110_periphs_device::icp_hsdr_r), FUNC(sa1110_periphs_device::icp_hsdr_w));
+ map(0x00030074, 0x00030077).rw(FUNC(sa1110_periphs_device::icp_hssr0_r), FUNC(sa1110_periphs_device::icp_hssr0_w));
+ map(0x00030078, 0x0003007b).rw(FUNC(sa1110_periphs_device::icp_hssr1_r), FUNC(sa1110_periphs_device::icp_hssr1_w));
+
+ map(0x00050000, 0x00050003).rw(FUNC(sa1110_periphs_device::uart3_utcr0_r), FUNC(sa1110_periphs_device::uart3_utcr0_w));
+ map(0x00050004, 0x00050007).rw(FUNC(sa1110_periphs_device::uart3_utcr1_r), FUNC(sa1110_periphs_device::uart3_utcr1_w));
+ map(0x00050008, 0x0005000b).rw(FUNC(sa1110_periphs_device::uart3_utcr2_r), FUNC(sa1110_periphs_device::uart3_utcr2_w));
+ map(0x0005000c, 0x0005000f).rw(FUNC(sa1110_periphs_device::uart3_utcr3_r), FUNC(sa1110_periphs_device::uart3_utcr3_w));
+ map(0x00050014, 0x00050017).rw(FUNC(sa1110_periphs_device::uart3_utdr_r), FUNC(sa1110_periphs_device::uart3_utdr_w));
+ map(0x0005001c, 0x0005001f).r(FUNC(sa1110_periphs_device::uart3_utsr0_r));
+ map(0x00050020, 0x00050023).rw(FUNC(sa1110_periphs_device::uart3_utsr1_r), FUNC(sa1110_periphs_device::uart3_utsr1_w));
+
+ map(0x00060000, 0x00060003).rw(FUNC(sa1110_periphs_device::mcp_mccr0_r), FUNC(sa1110_periphs_device::mcp_mccr0_w));
+ map(0x00060008, 0x0006000b).rw(FUNC(sa1110_periphs_device::mcp_mcdr0_r), FUNC(sa1110_periphs_device::mcp_mcdr0_w));
+ map(0x0006000c, 0x0006000f).rw(FUNC(sa1110_periphs_device::mcp_mcdr1_r), FUNC(sa1110_periphs_device::mcp_mcdr1_w));
+ map(0x00060010, 0x00060013).rw(FUNC(sa1110_periphs_device::mcp_mcdr2_r), FUNC(sa1110_periphs_device::mcp_mcdr2_w));
+ map(0x00060018, 0x0006001b).rw(FUNC(sa1110_periphs_device::mcp_mcsr_r), FUNC(sa1110_periphs_device::mcp_mcsr_w));
+
+ map(0x00070060, 0x00070063).rw(FUNC(sa1110_periphs_device::ssp_sscr0_r), FUNC(sa1110_periphs_device::ssp_sscr0_w));
+ map(0x00070064, 0x00070067).rw(FUNC(sa1110_periphs_device::ssp_sscr1_r), FUNC(sa1110_periphs_device::ssp_sscr1_w));
+ map(0x0007006c, 0x0007006f).rw(FUNC(sa1110_periphs_device::ssp_ssdr_r), FUNC(sa1110_periphs_device::ssp_ssdr_w));
+ map(0x00070074, 0x00070077).rw(FUNC(sa1110_periphs_device::ssp_sssr_r), FUNC(sa1110_periphs_device::ssp_sssr_w));
+
+ map(0x10000000, 0x10000003).rw(FUNC(sa1110_periphs_device::tmr_osmr0_r), FUNC(sa1110_periphs_device::tmr_osmr0_w));
+ map(0x10000004, 0x10000007).rw(FUNC(sa1110_periphs_device::tmr_osmr1_r), FUNC(sa1110_periphs_device::tmr_osmr1_w));
+ map(0x10000008, 0x1000000b).rw(FUNC(sa1110_periphs_device::tmr_osmr2_r), FUNC(sa1110_periphs_device::tmr_osmr2_w));
+ map(0x1000000c, 0x1000000f).rw(FUNC(sa1110_periphs_device::tmr_osmr3_r), FUNC(sa1110_periphs_device::tmr_osmr3_w));
+ map(0x10000010, 0x10000013).rw(FUNC(sa1110_periphs_device::tmr_oscr_r), FUNC(sa1110_periphs_device::tmr_oscr_w));
+ map(0x10000014, 0x10000017).rw(FUNC(sa1110_periphs_device::tmr_ossr_r), FUNC(sa1110_periphs_device::tmr_ossr_w));
+ map(0x10000018, 0x1000001b).rw(FUNC(sa1110_periphs_device::tmr_ower_r), FUNC(sa1110_periphs_device::tmr_ower_w));
+ map(0x1000001c, 0x1000001f).rw(FUNC(sa1110_periphs_device::tmr_oier_r), FUNC(sa1110_periphs_device::tmr_oier_w));
+
+ map(0x10010000, 0x10010003).rw(FUNC(sa1110_periphs_device::rtc_rtar_r), FUNC(sa1110_periphs_device::rtc_rtar_w));
+ map(0x10010004, 0x10010007).rw(FUNC(sa1110_periphs_device::rtc_rcnr_r), FUNC(sa1110_periphs_device::rtc_rcnr_w));
+ map(0x10010008, 0x1001000b).rw(FUNC(sa1110_periphs_device::rtc_rttr_r), FUNC(sa1110_periphs_device::rtc_rttr_w));
+ map(0x10010010, 0x10010013).rw(FUNC(sa1110_periphs_device::rtc_rtsr_r), FUNC(sa1110_periphs_device::rtc_rtsr_w));
+
+ map(0x10020000, 0x10020003).rw(FUNC(sa1110_periphs_device::pwr_pmcr_r), FUNC(sa1110_periphs_device::pwr_pmcr_w));
+ map(0x10020004, 0x10020007).rw(FUNC(sa1110_periphs_device::pwr_pssr_r), FUNC(sa1110_periphs_device::pwr_pssr_w));
+ map(0x10020008, 0x1002000b).rw(FUNC(sa1110_periphs_device::pwr_pspr_r), FUNC(sa1110_periphs_device::pwr_pspr_w));
+ map(0x1002000c, 0x1002000f).rw(FUNC(sa1110_periphs_device::pwr_pwer_r), FUNC(sa1110_periphs_device::pwr_pwer_w));
+ map(0x10020010, 0x10020013).rw(FUNC(sa1110_periphs_device::pwr_pcfr_r), FUNC(sa1110_periphs_device::pwr_pcfr_w));
+ map(0x10020014, 0x10020017).rw(FUNC(sa1110_periphs_device::pwr_ppcr_r), FUNC(sa1110_periphs_device::pwr_ppcr_w));
+ map(0x10020018, 0x1002001b).rw(FUNC(sa1110_periphs_device::pwr_pgsr_r), FUNC(sa1110_periphs_device::pwr_pgsr_w));
+ map(0x1002001c, 0x1002001f).rw(FUNC(sa1110_periphs_device::pwr_posr_r), FUNC(sa1110_periphs_device::pwr_posr_w));
+
+ map(0x10030000, 0x10030003).rw(FUNC(sa1110_periphs_device::rst_rsrr_r), FUNC(sa1110_periphs_device::rst_rsrr_w));
+ map(0x10030004, 0x10030007).rw(FUNC(sa1110_periphs_device::rst_rcsr_r), FUNC(sa1110_periphs_device::rst_rcsr_w));
+
+ map(0x10040000, 0x10040003).rw(FUNC(sa1110_periphs_device::gpio_gplr_r), FUNC(sa1110_periphs_device::gpio_gplr_w));
+ map(0x10040004, 0x10040007).rw(FUNC(sa1110_periphs_device::gpio_gpdr_r), FUNC(sa1110_periphs_device::gpio_gpdr_w));
+ map(0x10040008, 0x1004000b).rw(FUNC(sa1110_periphs_device::gpio_gpsr_r), FUNC(sa1110_periphs_device::gpio_gpsr_w));
+ map(0x1004000c, 0x1004000f).rw(FUNC(sa1110_periphs_device::gpio_gpcr_r), FUNC(sa1110_periphs_device::gpio_gpcr_w));
+ map(0x10040010, 0x10040013).rw(FUNC(sa1110_periphs_device::gpio_grer_r), FUNC(sa1110_periphs_device::gpio_grer_w));
+ map(0x10040014, 0x10040017).rw(FUNC(sa1110_periphs_device::gpio_gfer_r), FUNC(sa1110_periphs_device::gpio_gfer_w));
+ map(0x10040018, 0x1004001b).rw(FUNC(sa1110_periphs_device::gpio_gedr_r), FUNC(sa1110_periphs_device::gpio_gedr_w));
+ map(0x1004001c, 0x1004001f).rw(FUNC(sa1110_periphs_device::gpio_gafr_r), FUNC(sa1110_periphs_device::gpio_gafr_w));
+
+ map(0x10050000, 0x10050003).rw(FUNC(sa1110_periphs_device::intc_icip_r), FUNC(sa1110_periphs_device::intc_icip_w));
+ map(0x10050004, 0x10050007).rw(FUNC(sa1110_periphs_device::intc_icmr_r), FUNC(sa1110_periphs_device::intc_icmr_w));
+ map(0x10050008, 0x1005000b).rw(FUNC(sa1110_periphs_device::intc_iclr_r), FUNC(sa1110_periphs_device::intc_iclr_w));
+ map(0x1005000c, 0x1005000f).rw(FUNC(sa1110_periphs_device::intc_iccr_r), FUNC(sa1110_periphs_device::intc_iccr_w));
+ map(0x10050010, 0x10050013).rw(FUNC(sa1110_periphs_device::intc_icfp_r), FUNC(sa1110_periphs_device::intc_icfp_w));
+ map(0x10050014, 0x10050017).rw(FUNC(sa1110_periphs_device::intc_icpr_r), FUNC(sa1110_periphs_device::intc_icpr_w));
+
+ map(0x10060000, 0x10060003).rw(FUNC(sa1110_periphs_device::ppc_ppdr_r), FUNC(sa1110_periphs_device::ppc_ppdr_w));
+ map(0x10060004, 0x10060007).rw(FUNC(sa1110_periphs_device::ppc_ppsr_r), FUNC(sa1110_periphs_device::ppc_ppsr_w));
+ map(0x10060008, 0x1006000b).rw(FUNC(sa1110_periphs_device::ppc_ppar_r), FUNC(sa1110_periphs_device::ppc_ppar_w));
+ map(0x1006000c, 0x1006000f).rw(FUNC(sa1110_periphs_device::ppc_psdr_r), FUNC(sa1110_periphs_device::ppc_psdr_w));
+ map(0x10060010, 0x10060013).rw(FUNC(sa1110_periphs_device::ppc_ppfr_r), FUNC(sa1110_periphs_device::ppc_ppfr_w));
+
+ map(0x30000000, 0x30000003).rw(FUNC(sa1110_periphs_device::dma_ddar_r<0>), FUNC(sa1110_periphs_device::dma_ddar_w<0>));
+ map(0x30000004, 0x30000007).rw(FUNC(sa1110_periphs_device::dma_dssr_r<0>), FUNC(sa1110_periphs_device::dma_dssr_w<0>));
+ map(0x30000008, 0x3000000b).rw(FUNC(sa1110_periphs_device::dma_dcsr_r<0>), FUNC(sa1110_periphs_device::dma_dcsr_w<0>));
+ map(0x3000000c, 0x3000000f).rw(FUNC(sa1110_periphs_device::dma_dsr_r<0>), FUNC(sa1110_periphs_device::dma_dsr_w<0>));
+ map(0x30000010, 0x30000013).rw(FUNC(sa1110_periphs_device::dma_dbsa_r<0>), FUNC(sa1110_periphs_device::dma_dbsa_w<0>));
+ map(0x30000014, 0x30000017).rw(FUNC(sa1110_periphs_device::dma_dbta_r<0>), FUNC(sa1110_periphs_device::dma_dbta_w<0>));
+ map(0x30000018, 0x3000001b).rw(FUNC(sa1110_periphs_device::dma_dbsb_r<0>), FUNC(sa1110_periphs_device::dma_dbsb_w<0>));
+ map(0x3000001c, 0x3000001f).rw(FUNC(sa1110_periphs_device::dma_dbtb_r<0>), FUNC(sa1110_periphs_device::dma_dbtb_w<0>));
+ map(0x30000020, 0x30000023).rw(FUNC(sa1110_periphs_device::dma_ddar_r<1>), FUNC(sa1110_periphs_device::dma_ddar_w<1>));
+ map(0x30000024, 0x30000027).rw(FUNC(sa1110_periphs_device::dma_dssr_r<1>), FUNC(sa1110_periphs_device::dma_dssr_w<1>));
+ map(0x30000028, 0x3000002b).rw(FUNC(sa1110_periphs_device::dma_dcsr_r<1>), FUNC(sa1110_periphs_device::dma_dcsr_w<1>));
+ map(0x3000002c, 0x3000002f).rw(FUNC(sa1110_periphs_device::dma_dsr_r<1>), FUNC(sa1110_periphs_device::dma_dsr_w<1>));
+ map(0x30000030, 0x30000033).rw(FUNC(sa1110_periphs_device::dma_dbsa_r<1>), FUNC(sa1110_periphs_device::dma_dbsa_w<1>));
+ map(0x30000034, 0x30000037).rw(FUNC(sa1110_periphs_device::dma_dbta_r<1>), FUNC(sa1110_periphs_device::dma_dbta_w<1>));
+ map(0x30000038, 0x3000003b).rw(FUNC(sa1110_periphs_device::dma_dbsb_r<1>), FUNC(sa1110_periphs_device::dma_dbsb_w<1>));
+ map(0x3000003c, 0x3000003f).rw(FUNC(sa1110_periphs_device::dma_dbtb_r<1>), FUNC(sa1110_periphs_device::dma_dbtb_w<1>));
+ map(0x30000040, 0x30000043).rw(FUNC(sa1110_periphs_device::dma_ddar_r<2>), FUNC(sa1110_periphs_device::dma_ddar_w<2>));
+ map(0x30000044, 0x30000047).rw(FUNC(sa1110_periphs_device::dma_dssr_r<2>), FUNC(sa1110_periphs_device::dma_dssr_w<2>));
+ map(0x30000048, 0x3000004b).rw(FUNC(sa1110_periphs_device::dma_dcsr_r<2>), FUNC(sa1110_periphs_device::dma_dcsr_w<2>));
+ map(0x3000004c, 0x3000004f).rw(FUNC(sa1110_periphs_device::dma_dsr_r<2>), FUNC(sa1110_periphs_device::dma_dsr_w<2>));
+ map(0x30000050, 0x30000053).rw(FUNC(sa1110_periphs_device::dma_dbsa_r<2>), FUNC(sa1110_periphs_device::dma_dbsa_w<2>));
+ map(0x30000054, 0x30000057).rw(FUNC(sa1110_periphs_device::dma_dbta_r<2>), FUNC(sa1110_periphs_device::dma_dbta_w<2>));
+ map(0x30000058, 0x3000005b).rw(FUNC(sa1110_periphs_device::dma_dbsb_r<2>), FUNC(sa1110_periphs_device::dma_dbsb_w<2>));
+ map(0x3000005c, 0x3000005f).rw(FUNC(sa1110_periphs_device::dma_dbtb_r<2>), FUNC(sa1110_periphs_device::dma_dbtb_w<2>));
+ map(0x30000060, 0x30000063).rw(FUNC(sa1110_periphs_device::dma_ddar_r<3>), FUNC(sa1110_periphs_device::dma_ddar_w<3>));
+ map(0x30000064, 0x30000067).rw(FUNC(sa1110_periphs_device::dma_dssr_r<3>), FUNC(sa1110_periphs_device::dma_dssr_w<3>));
+ map(0x30000068, 0x3000006b).rw(FUNC(sa1110_periphs_device::dma_dcsr_r<3>), FUNC(sa1110_periphs_device::dma_dcsr_w<3>));
+ map(0x3000006c, 0x3000006f).rw(FUNC(sa1110_periphs_device::dma_dsr_r<3>), FUNC(sa1110_periphs_device::dma_dsr_w<3>));
+ map(0x30000070, 0x30000073).rw(FUNC(sa1110_periphs_device::dma_dbsa_r<3>), FUNC(sa1110_periphs_device::dma_dbsa_w<3>));
+ map(0x30000074, 0x30000077).rw(FUNC(sa1110_periphs_device::dma_dbta_r<3>), FUNC(sa1110_periphs_device::dma_dbta_w<3>));
+ map(0x30000078, 0x3000007b).rw(FUNC(sa1110_periphs_device::dma_dbsb_r<3>), FUNC(sa1110_periphs_device::dma_dbsb_w<3>));
+ map(0x3000007c, 0x3000007f).rw(FUNC(sa1110_periphs_device::dma_dbtb_r<3>), FUNC(sa1110_periphs_device::dma_dbtb_w<3>));
+ map(0x30000080, 0x30000083).rw(FUNC(sa1110_periphs_device::dma_ddar_r<4>), FUNC(sa1110_periphs_device::dma_ddar_w<4>));
+ map(0x30000084, 0x30000087).rw(FUNC(sa1110_periphs_device::dma_dssr_r<4>), FUNC(sa1110_periphs_device::dma_dssr_w<4>));
+ map(0x30000088, 0x3000008b).rw(FUNC(sa1110_periphs_device::dma_dcsr_r<4>), FUNC(sa1110_periphs_device::dma_dcsr_w<4>));
+ map(0x3000008c, 0x3000008f).rw(FUNC(sa1110_periphs_device::dma_dsr_r<4>), FUNC(sa1110_periphs_device::dma_dsr_w<4>));
+ map(0x30000090, 0x30000093).rw(FUNC(sa1110_periphs_device::dma_dbsa_r<4>), FUNC(sa1110_periphs_device::dma_dbsa_w<4>));
+ map(0x30000094, 0x30000097).rw(FUNC(sa1110_periphs_device::dma_dbta_r<4>), FUNC(sa1110_periphs_device::dma_dbta_w<4>));
+ map(0x30000098, 0x3000009b).rw(FUNC(sa1110_periphs_device::dma_dbsb_r<4>), FUNC(sa1110_periphs_device::dma_dbsb_w<4>));
+ map(0x3000009c, 0x3000009f).rw(FUNC(sa1110_periphs_device::dma_dbtb_r<4>), FUNC(sa1110_periphs_device::dma_dbtb_w<4>));
+ map(0x300000a0, 0x300000a3).rw(FUNC(sa1110_periphs_device::dma_ddar_r<5>), FUNC(sa1110_periphs_device::dma_ddar_w<5>));
+ map(0x300000a4, 0x300000a7).rw(FUNC(sa1110_periphs_device::dma_dssr_r<5>), FUNC(sa1110_periphs_device::dma_dssr_w<5>));
+ map(0x300000a8, 0x300000ab).rw(FUNC(sa1110_periphs_device::dma_dcsr_r<5>), FUNC(sa1110_periphs_device::dma_dcsr_w<5>));
+ map(0x300000ac, 0x300000af).rw(FUNC(sa1110_periphs_device::dma_dsr_r<5>), FUNC(sa1110_periphs_device::dma_dsr_w<5>));
+ map(0x300000b0, 0x300000b3).rw(FUNC(sa1110_periphs_device::dma_dbsa_r<5>), FUNC(sa1110_periphs_device::dma_dbsa_w<5>));
+ map(0x300000b4, 0x300000b7).rw(FUNC(sa1110_periphs_device::dma_dbta_r<5>), FUNC(sa1110_periphs_device::dma_dbta_w<5>));
+ map(0x300000b8, 0x300000bb).rw(FUNC(sa1110_periphs_device::dma_dbsb_r<5>), FUNC(sa1110_periphs_device::dma_dbsb_w<5>));
+ map(0x300000bc, 0x300000bf).rw(FUNC(sa1110_periphs_device::dma_dbtb_r<5>), FUNC(sa1110_periphs_device::dma_dbtb_w<5>));
}
/*
- Intel SA-1110 Interrupt Controller
+ Intel SA-1110 UDC - USB Device Controller
- pg. 81 to 88 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+ pg. 235 to 258 Intel StrongARM SA-1110 Microprocessor Developer's Manual
*/
-void sa1110_periphs_device::update_interrupts()
+u32 sa1110_periphs_device::udc_udccr_r(offs_t offset, u32 mem_mask)
{
- m_intc_regs.icfp = (m_intc_regs.icpr & m_intc_regs.icmr) & m_intc_regs.iclr;
- m_intc_regs.icip = (m_intc_regs.icpr & m_intc_regs.icmr) & (~m_intc_regs.iclr);
- m_maincpu->set_input_line(ARM7_FIRQ_LINE, m_intc_regs.icfp ? ASSERT_LINE : CLEAR_LINE);
- m_maincpu->set_input_line(ARM7_IRQ_LINE, m_intc_regs.icip ? ASSERT_LINE : CLEAR_LINE);
+ const u32 data = m_udc_regs.udccr;
+ LOGMASKED(LOG_UDC, "%s: udc_udccr_r: UDC Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
-void sa1110_periphs_device::set_irq_line(uint32_t line, int irq_state)
+void sa1110_periphs_device::udc_udccr_w(offs_t offset, u32 data, u32 mem_mask)
{
- m_intc_regs.icpr &= ~line;
- m_intc_regs.icpr |= irq_state ? line : 0;
- update_interrupts();
+ LOGMASKED(LOG_UDC, "%s: udc_udccr_w: UDC Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udccr);
}
-uint32_t sa1110_periphs_device::intc_r(offs_t offset, uint32_t mem_mask)
-{
- switch (offset)
- {
- case REG_ICIP:
- LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller IRQ Pending Register: %08x & %08x\n", m_intc_regs.icip, mem_mask);
- return m_intc_regs.icip;
- case REG_ICMR:
- LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Mask Register: %08x & %08x\n", m_intc_regs.icmr, mem_mask);
- return m_intc_regs.icmr;
- case REG_ICLR:
- LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Level Register: %08x & %08x\n", m_intc_regs.iclr, mem_mask);
- return m_intc_regs.iclr;
- case REG_ICFP:
- LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller FIQ Pending Register: %08x & %08x\n", m_intc_regs.icfp, mem_mask);
- return m_intc_regs.icfp;
- case REG_ICPR:
- LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Pending Register: %08x & %08x\n", m_intc_regs.icpr, mem_mask);
- return m_intc_regs.icpr;
- case REG_ICCR:
- LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Control Register: %08x & %08x\n", m_intc_regs.iccr, mem_mask);
- return m_intc_regs.iccr;
- default:
- LOGMASKED(LOG_INTC | LOG_UNKNOWN, "sa1110 intc_r: Unknown address: %08x\n", INTC_BASE_ADDR | (offset << 2));
- break;
- }
+u32 sa1110_periphs_device::udc_udcar_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udcar;
+ LOGMASKED(LOG_UDC, "%s: udc_udcar_r: UDC Address Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udcar_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udcar_w: UDC Address Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udcar);
+}
+
+u32 sa1110_periphs_device::udc_udcomp_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udcomp;
+ LOGMASKED(LOG_UDC, "%s: udc_udcomp_r: UDC OUT Max Packet Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udcomp_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udcomp_w: UDC OUT Max Packet Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udcomp);
+}
+
+u32 sa1110_periphs_device::udc_udcimp_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udcimp;
+ LOGMASKED(LOG_UDC, "%s: udc_udiomp_r: UDC IN Max Packet Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udcimp_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udcimp_w: UDC IN Max Packet Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udcimp);
+}
+
+u32 sa1110_periphs_device::udc_udccs0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udccs0;
+ LOGMASKED(LOG_UDC, "%s: udc_udccs0_r: UDC Endpoint 0 Control/Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udccs0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udccs0_w: UDC Endpoint 0 Control/Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udccs0);
+}
+
+u32 sa1110_periphs_device::udc_udccs1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udccs1;
+ LOGMASKED(LOG_UDC, "%s: udc_udccs1_r: UDC Endpoint 1 (OUT) Control/Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udccs1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udccs1_w: UDC Endpoint 1 (OUT) Control/Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udccs1);
+}
+
+u32 sa1110_periphs_device::udc_udccs2_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udccs2;
+ LOGMASKED(LOG_UDC, "%s: udc_udccs2_r: UDC Endpoint 2 (IN) Control/Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udccs2_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udccs2_w: UDC Endpoint 2 (IN) Control/Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udccs2);
+}
+
+u32 sa1110_periphs_device::udc_udcd0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = 0;
+ LOGMASKED(LOG_UDC, "%s: udc_udcd0_r: UDC Endpoint 0 Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udcd0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udcd0_w: UDC Endpoint 0 Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::udc_udcwc_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udcwc;
+ LOGMASKED(LOG_UDC, "%s: udc_udcwc_r: UDC Endpoint 0 Write Count Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udcwc_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udcwc_w: UDC Endpoint 0 Write Count Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_udc_regs.udcwc);
+}
+
+u32 sa1110_periphs_device::udc_udcdr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = 0; //udc_rx_fifo_pop();
+ LOGMASKED(LOG_UDC, "%s: udc_udcdr_r: UDC Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udcdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udcdr_w: UDC Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::udc_udcsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_udc_regs.udcsr;
+ LOGMASKED(LOG_UDC, "%s: udc_udcsr_r: UDC Status/Interrupt Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::udc_udcsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UDC, "%s: udc_udcsr_w: UDC Status/Interrupt Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+
+/*
+
+ Intel SA-1110 ICP - Serial Port 2
+
+ pg. 264 to 288 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::icp_rx_callback)
+{
+}
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::icp_tx_callback)
+{
+}
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::hssp_rx_callback)
+{
+}
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::hssp_tx_callback)
+{
+}
+
+void sa1110_periphs_device::icp_uart_set_receiver_enabled(bool enabled)
+{
+}
+
+void sa1110_periphs_device::icp_uart_set_transmitter_enabled(bool enabled)
+{
+}
+
+void sa1110_periphs_device::icp_uart_set_receive_irq_enabled(bool enabled)
+{
+}
+
+void sa1110_periphs_device::icp_uart_set_transmit_irq_enabled(bool enabled)
+{
+}
+
+u8 sa1110_periphs_device::icp_uart_read_receive_fifo()
+{
return 0;
}
-void sa1110_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void sa1110_periphs_device::icp_uart_write_transmit_fifo(u8 data)
+{
+}
+
+u16 sa1110_periphs_device::icp_hssp_read_receive_fifo()
+{
+ return 0;
+}
+
+void sa1110_periphs_device::icp_hssp_write_transmit_fifo(u8 data)
+{
+}
+
+void sa1110_periphs_device::icp_uart_set_receiver_idle()
+{
+}
+
+void sa1110_periphs_device::icp_uart_begin_of_break()
+{
+}
+
+void sa1110_periphs_device::icp_uart_end_of_break()
{
- switch (offset)
+}
+
+u32 sa1110_periphs_device::icp_utcr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.uart.utcr[0];
+ LOGMASKED(LOG_ICP, "%s: icp_utcr0_r: UART Control Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_utcr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_utcr0_w: UART Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_ICP, "%s: Parity Enable: %d\n", machine().describe_context(), BIT(data, 0));
+ LOGMASKED(LOG_ICP, "%s: Parity Mode: %s\n", machine().describe_context(), BIT(data, 1) ? "Even" : "Odd");
+ LOGMASKED(LOG_ICP, "%s: Stop Bits: %d\n", machine().describe_context(), BIT(data, 2) + 1);
+ LOGMASKED(LOG_ICP, "%s: Data Size: %d\n", machine().describe_context(), BIT(data, 3) ? 8 : 7);
+ LOGMASKED(LOG_ICP, "%s: Sample Clock: %s\n", machine().describe_context(), BIT(data, 4) ? "External" : "Internal");
+ LOGMASKED(LOG_ICP, "%s: Receive Edge: %s\n", machine().describe_context(), BIT(data, 5) ? "Falling" : "Rising");
+ LOGMASKED(LOG_ICP, "%s: Transmit Edge: %s\n", machine().describe_context(), BIT(data, 6) ? "Falling" : "Rising");
+
+ //stop_bits_t stop_bits = (BIT(data, 2) ? STOP_BITS_2 : STOP_BITS_1);
+
+ //parity_t parity = PARITY_NONE;
+ //if (BIT(data, 0))
+ //{
+ // parity = (BIT(data, 1) ? PARITY_EVEN : PARITY_ODD);
+ //}
+
+ //set_data_frame(1, BIT(data, 3) ? 8 : 7, parity, stop_bits);
+ //receive_register_reset();
+ //transmit_register_reset();
+
+ COMBINE_DATA(&m_icp_regs.uart.utcr[0]);
+}
+
+u32 sa1110_periphs_device::icp_utcr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.uart.utcr[1];
+ LOGMASKED(LOG_ICP, "%s: icp_utcr1_r: UART Control Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_utcr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_utcr1_w: UART Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_ICP, "%s: Baud Rate Divisor MSB: %02x\n", machine().describe_context(), data & 0x0f);
+ //const u8 old = m_uart_regs.utcr[1] & 0x0f;
+ COMBINE_DATA(&m_icp_regs.uart.utcr[1]);
+ //if ((m_uart_regs.utcr[1] & 0x0f) != old)
+ // icp_uart_recalculate_divisor();
+}
+
+u32 sa1110_periphs_device::icp_utcr2_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.uart.utcr[2];
+ LOGMASKED(LOG_ICP, "%s: icp_utcr2_r: UART Control Register 2: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_utcr2_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_utcr2_w: UART Control Register 2 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_ICP, "%s: Baud Rate Divisor LSB: %02x\n", machine().describe_context(), (u8)data);
+ //const u8 old = m_uart_regs.utcr[2] & 0xff;
+ COMBINE_DATA(&m_icp_regs.uart.utcr[2]);
+ //if ((m_uart_regs.utcr[2] & 0xff) != old)
+ // icp_uart_recalculate_divisor();
+}
+
+u32 sa1110_periphs_device::icp_utcr3_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.uart.utcr[3];
+ LOGMASKED(LOG_ICP, "%s: icp_utcr3_r: UART Control Register 3: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_utcr3_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_utcr3_w: UART Control Register 3 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_ICP, "%s: Receive Enable: %d\n", machine().describe_context(), BIT(data, 0));
+ LOGMASKED(LOG_ICP, "%s: Transmit Enable: %d\n", machine().describe_context(), BIT(data, 1));
+ LOGMASKED(LOG_ICP, "%s: Send Break: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_ICP, "%s: Receive FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 3));
+ LOGMASKED(LOG_ICP, "%s: Transmit FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 4));
+ LOGMASKED(LOG_ICP, "%s: Loopback Enable: %d\n", machine().describe_context(), BIT(data, 5));
+ const u32 old = m_icp_regs.uart.utcr[3];
+ COMBINE_DATA(&m_icp_regs.uart.utcr[3]);
+ const u32 changed = old ^ m_icp_regs.uart.utcr[3];
+ if (BIT(changed, 0))
+ icp_uart_set_receiver_enabled(BIT(data, 0));
+ if (BIT(changed, 1))
+ icp_uart_set_transmitter_enabled(BIT(data, 1));
+ if (BIT(changed, 3))
+ icp_uart_set_receive_irq_enabled(BIT(data, 3));
+ if (BIT(changed, 4))
+ icp_uart_set_transmit_irq_enabled(BIT(data, 4));
+}
+
+u32 sa1110_periphs_device::icp_utcr4_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.utcr4;
+ LOGMASKED(LOG_ICP, "%s: icp_utcr4_r: UART Control Register 4: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_utcr4_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_utcr4_w: UART Control Register 4 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_ICP, "%s: HP-SIR enable: %d\n", machine().describe_context(), BIT(data, UTCR4_HSE_BIT), mem_mask);
+ LOGMASKED(LOG_ICP, "%s: Low-Power enable: %d\n", machine().describe_context(), BIT(data, UTCR4_LPM_BIT), mem_mask);
+ COMBINE_DATA(&m_icp_regs.utcr4);
+}
+
+u32 sa1110_periphs_device::icp_utdr_r(offs_t offset, u32 mem_mask)
+{
+ const u8 data = icp_uart_read_receive_fifo();
+ LOGMASKED(LOG_ICP, "%s: icp_utdr_r: UART Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_utdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_utdr_w: UART Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ if (data == 0x0d || data == 0x0a || (data >= 0x20 && data < 0x7f))
{
- case REG_ICIP:
- LOGMASKED(LOG_INTC, "sa1110 intc_w: (Invalid Write) Interrupt Controller IRQ Pending Register: %08x & %08x\n", data, mem_mask);
- break;
- case REG_ICMR:
- LOGMASKED(LOG_INTC, "sa1110 intc_w: Interrupt Controller Mask Register: %08x & %08x\n", data, mem_mask);
- COMBINE_DATA(&m_intc_regs.icmr);
- break;
- case REG_ICLR:
- LOGMASKED(LOG_INTC, "sa1110 intc_w: Interrupt Controller Level Register: %08x & %08x\n", data, mem_mask);
- COMBINE_DATA(&m_intc_regs.iclr);
- break;
- case REG_ICFP:
- LOGMASKED(LOG_INTC, "sa1110 intc_w: (Invalid Write) Interrupt Controller FIQ Pending Register: %08x & %08x\n", data, mem_mask);
- break;
- case REG_ICPR:
- LOGMASKED(LOG_INTC, "sa1110_intc_w: (Invalid Write) Interrupt Controller Pending Register: %08x & %08x\n", data, mem_mask);
- break;
- case REG_ICCR:
- LOGMASKED(LOG_INTC, "sa1110 intc_w: Interrupt Controller Control Register: %08x & %08x\n", data, mem_mask);
- m_intc_regs.iccr = BIT(data, 0);
- break;
- default:
- LOGMASKED(LOG_INTC | LOG_UNKNOWN, "sa1110 intc_w: Unknown address: %08x = %08x & %08x\n", INTC_BASE_ADDR | (offset << 2), data, mem_mask);
+ osd_printf_debug("%c", (char)data);
+ }
+ icp_uart_write_transmit_fifo((u8)data);
+}
+
+u32 sa1110_periphs_device::icp_utsr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.uart.utsr0;
+ LOGMASKED(LOG_ICP, "%s: icp_utsr0_r: UART Status Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_utsr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_utsr0_w: UART Status Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_ICP, "%s: Receiver Idle Status: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_ICP, "%s: Receiver Begin of Break Status: %d\n", machine().describe_context(), BIT(data, 3));
+ LOGMASKED(LOG_ICP, "%s: Receiver End of Break Status: %d\n", machine().describe_context(), BIT(data, 4));
+ if (BIT(data, 2))
+ icp_uart_set_receiver_idle();
+ if (BIT(data, 3))
+ icp_uart_begin_of_break();
+ if (BIT(data, 4))
+ icp_uart_end_of_break();
+}
+
+u32 sa1110_periphs_device::icp_utsr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.uart.utsr1;
+ LOGMASKED(LOG_ICP, "%s: icp_utsr1_r: UART Status Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+u32 sa1110_periphs_device::icp_hscr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.hssp.hscr0;
+ LOGMASKED(LOG_ICP, "%s: icp_hscr0_r: HSSP Control Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_hscr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_hscr0_w: HSSP Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::icp_hscr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.hssp.hscr1;
+ LOGMASKED(LOG_ICP, "%s: icp_hscr1_r: HSSP Control Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_hscr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_hscr1_w: HSSP Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::icp_hsdr_r(offs_t offset, u32 mem_mask)
+{
+ const u16 data = icp_hssp_read_receive_fifo();
+ LOGMASKED(LOG_ICP, "%s: icp_r: HSSP Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_hsdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_hsdr_w: HSSP Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ icp_hssp_write_transmit_fifo((u8)data);
+}
+
+u32 sa1110_periphs_device::icp_hssr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.hssp.hssr0;
+ LOGMASKED(LOG_ICP, "%s: icp_hssr0_r: HSSP Status Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_hssr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_hssr0_w: HSSP Status Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::icp_hssr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_icp_regs.hssp.hssr1;
+ LOGMASKED(LOG_ICP, "%s: icp_hssr1_r: HSSP Status Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::icp_hssr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_ICP, "%s: icp_hssr1_w: HSSP Status Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+
+/*
+
+ Intel SA-1110 Serial Port 3 - UART
+
+ pg. 289 to 306 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+void sa1110_periphs_device::uart3_irq_callback(int state)
+{
+ set_irq_line(INT_UART3, state);
+}
+
+// Rx completed receiving byte
+void sa1110_periphs_device::rcv_complete()
+{
+ receive_register_extract();
+
+ u16 data_and_flags = 0;
+ if (is_receive_framing_error())
+ data_and_flags |= 0x200;
+ if (is_receive_parity_error())
+ data_and_flags |= 0x100;
+ data_and_flags |= get_received_char();
+
+ uart_write_receive_fifo(data_and_flags);
+}
+
+// Tx completed sending byte
+void sa1110_periphs_device::tra_complete()
+{
+ m_uart_regs.tx_fifo_count--;
+ m_uart_regs.tx_fifo_read_idx = (m_uart_regs.tx_fifo_read_idx + 1) % std::size(m_uart_regs.tx_fifo);
+ m_uart_regs.utsr1 |= (1 << UTSR1_TNF_BIT);
+
+ if (m_uart_regs.tx_fifo_count)
+ transmit_register_setup(m_uart_regs.tx_fifo[m_uart_regs.tx_fifo_read_idx]);
+ else
+ m_uart_regs.utsr1 &= ~(1 << UTSR1_TBY_BIT);
+
+ uart_check_tx_fifo_service();
+}
+
+// Tx send bit
+void sa1110_periphs_device::tra_callback()
+{
+ // TODO: Handle loopback mode
+ m_uart3_tx_out(transmit_register_get_data_bit());
+}
+
+void sa1110_periphs_device::uart_recalculate_divisor()
+{
+ // TODO: Handle external UART clocking
+ const int multiplier = (((m_uart_regs.utcr[1] & 0x0f) << 8) | (m_uart_regs.utcr[2] & 0xff)) + 1;
+ set_rcv_rate(INTERNAL_OSC, multiplier * 16);
+ set_tra_rate(INTERNAL_OSC, multiplier * 16);
+
+ receive_register_reset();
+ transmit_register_reset();
+}
+
+void sa1110_periphs_device::uart_update_eif_status()
+{
+ bool has_error = false;
+ for (int i = 0; i < 4 && i < m_uart_regs.rx_fifo_count; i++)
+ {
+ const int read_idx = (m_uart_regs.rx_fifo_read_idx + i) % std::size(m_uart_regs.rx_fifo);
+ if (m_uart_regs.rx_fifo[read_idx] & 0x700)
+ {
+ has_error = true;
break;
+ }
+ }
+
+ if (has_error)
+ {
+ m_uart_regs.utsr0 |= (1 << UTSR0_EIF_BIT);
+ m_uart3_irqs->in_w<UART3_EIF>(1);
+ }
+ else
+ {
+ m_uart_regs.utsr0 &= ~(1 << UTSR0_EIF_BIT);
+ m_uart3_irqs->in_w<UART3_EIF>(0);
+ }
+}
+
+void sa1110_periphs_device::uart_write_receive_fifo(u16 data_and_flags)
+{
+ if (m_uart_regs.rx_fifo_count >= std::size(m_uart_regs.rx_fifo))
+ return;
+ if (!BIT(m_uart_regs.utcr[3], UTCR3_RXE_BIT))
+ return;
+
+ // fill FIFO entry
+ m_uart_regs.rx_fifo[m_uart_regs.rx_fifo_write_idx] = data_and_flags;
+ m_uart_regs.rx_fifo_count++;
+ m_uart_regs.rx_fifo_write_idx = (m_uart_regs.rx_fifo_write_idx + 1) % std::size(m_uart_regs.rx_fifo);
+
+ // update error flags
+ uart_update_eif_status();
+
+ // update FIFO-service interrupt
+ uart_check_rx_fifo_service();
+}
+
+u8 sa1110_periphs_device::uart_read_receive_fifo()
+{
+ const u8 data = m_uart_regs.rx_fifo[m_uart_regs.rx_fifo_read_idx];
+ if (m_uart_regs.rx_fifo_count)
+ {
+ m_uart_regs.rx_fifo_read_idx = (m_uart_regs.rx_fifo_read_idx + 1) % std::size(m_uart_regs.rx_fifo);
+ m_uart_regs.rx_fifo_count--;
+ if (m_uart_regs.rx_fifo_count)
+ {
+ const u16 fifo_bottom_flags = ((m_uart_regs.rx_fifo[m_uart_regs.rx_fifo_read_idx]) >> 8) & 7;
+ m_uart_regs.utsr1 &= ~((1 << UTSR1_PRE_BIT) | (1 << UTSR1_FRE_BIT) | (1 << UTSR1_ROR_BIT));
+ m_uart_regs.utsr1 |= fifo_bottom_flags << UTSR1_PRE_BIT;
+ }
+ uart_update_eif_status();
+ }
+ uart_check_rx_fifo_service();
+ return data;
+}
+
+void sa1110_periphs_device::uart_check_rx_fifo_service()
+{
+ if (m_uart_regs.rx_fifo_count != 0)
+ m_uart_regs.utsr1 |= (1 << UTSR1_RNE_BIT);
+ else
+ m_uart_regs.utsr1 &= ~(1 << UTSR1_RNE_BIT);
+
+ if (m_uart_regs.rx_fifo_count > 4)
+ {
+ m_uart_regs.utsr0 |= (1 << UTSR0_RFS_BIT);
+ if (BIT(m_uart_regs.utcr[3], UTCR3_RIE_BIT))
+ {
+ m_uart3_irqs->in_w<UART3_RFS>(1);
+ }
+ }
+ else
+ {
+ m_uart_regs.utsr0 &= ~(1 << UTSR0_RFS_BIT);
+ m_uart3_irqs->in_w<UART3_RFS>(0);
+ }
+}
+
+void sa1110_periphs_device::uart_write_transmit_fifo(u8 data)
+{
+ if (m_uart_regs.tx_fifo_count >= std::size(m_uart_regs.tx_fifo))
+ return;
+ if (!BIT(m_uart_regs.utcr[3], UTCR3_TXE_BIT))
+ return;
+
+ // immediately start transmitting if FIFO is empty
+ if (m_uart_regs.tx_fifo_count == 0)
+ {
+ m_uart_regs.utsr1 |= (1 << UTSR1_TBY_BIT);
+ transmit_register_setup(data);
+ }
+
+ // fill FIFO entry
+ m_uart_regs.tx_fifo[m_uart_regs.tx_fifo_write_idx] = data;
+ m_uart_regs.tx_fifo_count++;
+ m_uart_regs.tx_fifo_write_idx = (m_uart_regs.tx_fifo_write_idx + 1) % std::size(m_uart_regs.tx_fifo);
+
+ // update FIFO-service interrupt
+ uart_check_tx_fifo_service();
+}
+
+void sa1110_periphs_device::uart_check_tx_fifo_service()
+{
+ if (m_uart_regs.tx_fifo_count < std::size(m_uart_regs.tx_fifo))
+ m_uart_regs.utsr1 |= (1 << UTSR1_TNF_BIT);
+ else
+ m_uart_regs.utsr1 &= ~(1 << UTSR1_TNF_BIT);
+
+ if (m_uart_regs.tx_fifo_count <= 4)
+ {
+ m_uart_regs.utsr0 |= (1 << UTSR0_TFS_BIT);
+ if (BIT(m_uart_regs.utcr[3], UTCR3_TIE_BIT))
+ {
+ m_uart3_irqs->in_w<UART3_TFS>(1);
+ }
+ }
+ else
+ {
+ m_uart_regs.utsr0 &= ~(1 << UTSR0_TFS_BIT);
+ m_uart3_irqs->in_w<UART3_TFS>(0);
+ }
+}
+
+void sa1110_periphs_device::uart_set_receiver_idle()
+{
+}
+
+void sa1110_periphs_device::uart_begin_of_break()
+{
+}
+
+void sa1110_periphs_device::uart_end_of_break()
+{
+}
+
+void sa1110_periphs_device::uart_set_receiver_enabled(bool enabled)
+{
+ if (!enabled)
+ {
+ m_uart_regs.utsr0 &= ~(1 << UTSR0_RFS_BIT);
+ m_uart3_irqs->in_w<UART3_RFS>(0);
+
+ m_uart_regs.utsr1 &= ~(1 << UTSR1_RNE_BIT);
+
+ m_uart_regs.rx_fifo_count = 0;
+ m_uart_regs.rx_fifo_read_idx = 0;
+ m_uart_regs.rx_fifo_write_idx = 0;
+
+ receive_register_reset();
+ }
+}
+
+void sa1110_periphs_device::uart_set_transmitter_enabled(bool enabled)
+{
+ if (enabled)
+ {
+ //m_uart_regs.utsr0 |= (1 << UTSR0_TFS_BIT);
+ //m_uart3_irqs->in_w<UART3_TFS>(1);
+
+ //m_uart_regs.utsr1 |= (1 << UTSR1_TNF_BIT);
+ }
+ else
+ {
+ //m_uart_regs.utsr0 &= ~(1 << UTSR0_TFS_BIT);
+ //m_uart3_irqs->in_w<UART3_TFS>(0);
+
+ //m_uart_regs.utsr1 &= ~(1 << UTSR1_TBY_BIT);
+ //m_uart_regs.utsr1 &= ~(1 << UTSR1_TNF_BIT);
+
+ m_uart_regs.tx_fifo_count = 0;
+ m_uart_regs.tx_fifo_read_idx = 0;
+ m_uart_regs.tx_fifo_write_idx = 0;
+
+ transmit_register_reset();
+ }
+
+ uart_check_tx_fifo_service();
+}
+
+void sa1110_periphs_device::uart_set_receive_irq_enabled(bool enabled)
+{
+}
+
+void sa1110_periphs_device::uart_set_transmit_irq_enabled(bool enabled)
+{
+}
+
+u32 sa1110_periphs_device::uart3_utcr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_uart_regs.utcr[0];
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr0_r: UART Control Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::uart3_utcr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr0_w: UART Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_UART3, "%s: Parity Enable: %d\n", machine().describe_context(), BIT(data, 0));
+ LOGMASKED(LOG_UART3, "%s: Parity Mode: %s\n", machine().describe_context(), BIT(data, 1) ? "Even" : "Odd");
+ LOGMASKED(LOG_UART3, "%s: Stop Bits: %d\n", machine().describe_context(), BIT(data, 2) + 1);
+ LOGMASKED(LOG_UART3, "%s: Data Size: %d\n", machine().describe_context(), BIT(data, 3) ? 8 : 7);
+ LOGMASKED(LOG_UART3, "%s: Sample Clock: %s\n", machine().describe_context(), BIT(data, 4) ? "External" : "Internal");
+ LOGMASKED(LOG_UART3, "%s: Receive Edge: %s\n", machine().describe_context(), BIT(data, 5) ? "Falling" : "Rising");
+ LOGMASKED(LOG_UART3, "%s: Transmit Edge: %s\n", machine().describe_context(), BIT(data, 6) ? "Falling" : "Rising");
+
+ stop_bits_t stop_bits = (BIT(data, 2) ? STOP_BITS_2 : STOP_BITS_1);
+
+ parity_t parity = PARITY_NONE;
+ if (BIT(data, 0))
+ {
+ parity = (BIT(data, 1) ? PARITY_EVEN : PARITY_ODD);
+ }
+
+ set_data_frame(1, BIT(data, 3) ? 8 : 7, parity, stop_bits);
+ receive_register_reset();
+ transmit_register_reset();
+
+ COMBINE_DATA(&m_uart_regs.utcr[0]);
+}
+
+u32 sa1110_periphs_device::uart3_utcr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_uart_regs.utcr[1];
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr1_r: UART Control Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::uart3_utcr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr1_w: UART Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_UART3, "%s: Baud Rate Divisor MSB: %02x\n", machine().describe_context(), data & 0x0f);
+ const u8 old = m_uart_regs.utcr[1] & 0x0f;
+ COMBINE_DATA(&m_uart_regs.utcr[1]);
+ if ((m_uart_regs.utcr[1] & 0x0f) != old)
+ uart_recalculate_divisor();
+}
+
+u32 sa1110_periphs_device::uart3_utcr2_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_uart_regs.utcr[2];
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr2_r: UART Control Register 2: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::uart3_utcr2_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr2_w: UART Control Register 2 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_UART3, "%s: Baud Rate Divisor LSB: %02x\n", machine().describe_context(), (u8)data);
+ const u8 old = m_uart_regs.utcr[2] & 0xff;
+ COMBINE_DATA(&m_uart_regs.utcr[2]);
+ if ((m_uart_regs.utcr[2] & 0xff) != old)
+ uart_recalculate_divisor();
+}
+
+u32 sa1110_periphs_device::uart3_utcr3_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_uart_regs.utcr[3];
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr3_r: UART Control Register 3: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::uart3_utcr3_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UART3, "%s: uart3_utcr3_w: UART Control Register 3 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_UART3, "%s: Receive Enable: %d\n", machine().describe_context(), BIT(data, 0));
+ LOGMASKED(LOG_UART3, "%s: Transmit Enable: %d\n", machine().describe_context(), BIT(data, 1));
+ LOGMASKED(LOG_UART3, "%s: Send Break: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_UART3, "%s: Receive FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 3));
+ LOGMASKED(LOG_UART3, "%s: Transmit FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 4));
+ LOGMASKED(LOG_UART3, "%s: Loopback Enable: %d\n", machine().describe_context(), BIT(data, 5));
+ const u32 old = m_uart_regs.utcr[3];
+ COMBINE_DATA(&m_uart_regs.utcr[3]);
+ const u32 changed = old ^ m_uart_regs.utcr[3];
+ if (BIT(changed, 0))
+ uart_set_receiver_enabled(BIT(data, 0));
+ if (BIT(changed, 1))
+ uart_set_transmitter_enabled(BIT(data, 1));
+ if (BIT(changed, 3))
+ uart_set_receive_irq_enabled(BIT(data, 3));
+ if (BIT(changed, 4))
+ uart_set_transmit_irq_enabled(BIT(data, 4));
+}
+
+u32 sa1110_periphs_device::uart3_utdr_r(offs_t offset, u32 mem_mask)
+{
+ const u8 data = uart_read_receive_fifo();
+ LOGMASKED(LOG_UART3, "%s: uart3_utdr_r: UART Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::uart3_utdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UART3, "%s: uart3_utdr_w: UART Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ if (data == 0x0d || data == 0x0a || (data >= 0x20 && data < 0x7f))
+ {
+ osd_printf_debug("%c", (char)data);
+ }
+ uart_write_transmit_fifo((u8)data);
+}
+
+u32 sa1110_periphs_device::uart3_utsr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_uart_regs.utsr0;
+ LOGMASKED(LOG_UART3, "%s: uart3_utsr0_r: UART Status Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::uart3_utsr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_UART3, "%s: uart3_utsr1_w: UART Status Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_UART3, "%s: Receiver Idle Status: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_UART3, "%s: Receiver Begin of Break Status: %d\n", machine().describe_context(), BIT(data, 3));
+ LOGMASKED(LOG_UART3, "%s: Receiver End of Break Status: %d\n", machine().describe_context(), BIT(data, 4));
+ if (BIT(data, 2))
+ uart_set_receiver_idle();
+ if (BIT(data, 3))
+ uart_begin_of_break();
+ if (BIT(data, 4))
+ uart_end_of_break();
+}
+
+u32 sa1110_periphs_device::uart3_utsr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_uart_regs.utsr1;
+ LOGMASKED(LOG_UART3_HF, "%s: uart3_utsr1_r: UART Status Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+
+/*
+
+ Intel SA-1110 MCP - Serial Port 4
+
+ pg. 306 to 346 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+void sa1110_periphs_device::mcp_irq_callback(int state)
+{
+ set_irq_line(INT_MCP, state);
+}
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::mcp_audio_tx_callback)
+{
+ if (!m_codec)
+ return;
+
+ const u16 sample = m_mcp_regs.audio_tx_fifo[m_mcp_regs.audio_tx_fifo_read_idx];
+ m_codec->audio_sample_in(sample);
+
+ if (m_mcp_regs.audio_tx_fifo_count)
+ {
+ m_mcp_regs.audio_tx_fifo_count--;
+ m_mcp_regs.audio_tx_fifo_read_idx = (m_mcp_regs.audio_tx_fifo_read_idx + 1) % std::size(m_mcp_regs.audio_tx_fifo);
+
+ m_mcp_regs.mcsr &= ~(1 << MCSR_ATU_BIT);
+ m_mcp_irqs->in_w<MCP_AUDIO_UNDERRUN>(0);
+ }
+ else
+ {
+ m_mcp_regs.mcsr |= (1 << MCSR_ATU_BIT);
+ m_mcp_irqs->in_w<MCP_AUDIO_UNDERRUN>(1);
+ }
+
+ m_mcp_regs.mcsr |= (1 << MCSR_ANF_BIT);
+}
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::mcp_telecom_tx_callback)
+{
+ if (!m_codec)
+ return;
+
+ const u16 sample = m_mcp_regs.telecom_tx_fifo[m_mcp_regs.telecom_tx_fifo_read_idx];
+ m_codec->telecom_sample_in(sample);
+
+ if (m_mcp_regs.telecom_tx_fifo_count)
+ {
+ m_mcp_regs.telecom_tx_fifo_count--;
+ m_mcp_regs.telecom_tx_fifo_read_idx = (m_mcp_regs.telecom_tx_fifo_read_idx + 1) % std::size(m_mcp_regs.telecom_tx_fifo);
+
+ m_mcp_regs.mcsr &= ~(1 << MCSR_TTU_BIT);
+ m_mcp_irqs->in_w<MCP_TELECOM_UNDERRUN>(0);
+ }
+ else
+ {
+ m_mcp_regs.mcsr |= (1 << MCSR_TTU_BIT);
+ m_mcp_irqs->in_w<MCP_TELECOM_UNDERRUN>(1);
+ }
+
+ m_mcp_regs.mcsr |= (1 << MCSR_TNF_BIT);
+}
+
+u16 sa1110_periphs_device::mcp_read_audio_fifo()
+{
+ const u16 data = m_mcp_regs.audio_rx_fifo[m_mcp_regs.audio_rx_fifo_read_idx];
+ if (m_mcp_regs.audio_rx_fifo_count)
+ {
+ m_mcp_regs.audio_rx_fifo_count--;
+ m_mcp_regs.audio_rx_fifo_read_idx = (m_mcp_regs.audio_rx_fifo_read_idx + 1) % std::size(m_mcp_regs.audio_rx_fifo);
+
+ const bool half_full = m_mcp_regs.audio_rx_fifo_count >= 4;
+ m_mcp_regs.mcsr &= ~(1 << MCSR_ARS_BIT);
+ if (half_full)
+ {
+ m_mcp_regs.mcsr |= (1 << MCSR_ARS_BIT);
+ }
+ bool fifo_interrupt = BIT(m_mcp_regs.mccr0, MCCR0_ARE_BIT) && half_full;
+ m_mcp_irqs->in_w<MCP_AUDIO_RX>((int)fifo_interrupt);
+
+ if (m_mcp_regs.audio_rx_fifo_count)
+ m_mcp_regs.mcsr &= ~(1 << MCSR_ANE_BIT);
+ else
+ m_mcp_regs.mcsr |= (1 << MCSR_ANE_BIT);
+ }
+ return data;
+}
+
+u16 sa1110_periphs_device::mcp_read_telecom_fifo()
+{
+ const u16 data = m_mcp_regs.telecom_rx_fifo[m_mcp_regs.telecom_rx_fifo_read_idx];
+ if (m_mcp_regs.telecom_rx_fifo_count)
+ {
+ m_mcp_regs.telecom_rx_fifo_count--;
+ m_mcp_regs.telecom_rx_fifo_read_idx = (m_mcp_regs.telecom_rx_fifo_read_idx + 1) % std::size(m_mcp_regs.telecom_rx_fifo);
+
+ const bool half_full = m_mcp_regs.telecom_rx_fifo_count >= 4;
+ m_mcp_regs.mcsr &= ~(1 << MCSR_TRS_BIT);
+ if (half_full)
+ {
+ m_mcp_regs.mcsr |= (1 << MCSR_TRS_BIT);
+ }
+ bool fifo_interrupt = BIT(m_mcp_regs.mccr0, MCCR0_TRE_BIT) && half_full;
+ m_mcp_irqs->in_w<MCP_TELECOM_RX>((int)fifo_interrupt);
+
+ if (m_mcp_regs.telecom_rx_fifo_count)
+ m_mcp_regs.mcsr &= ~(1 << MCSR_TNE_BIT);
+ else
+ m_mcp_regs.mcsr |= (1 << MCSR_TNE_BIT);
+ }
+ return data;
+}
+
+attotime sa1110_periphs_device::mcp_get_audio_frame_rate()
+{
+ const u32 bit_rate = BIT(m_mcp_regs.mccr1, MCCR1_CFS_BIT) ? 9585000 : 11981000;
+ const uint64_t ticks = 32 * ((m_mcp_regs.mccr0 & MCCR0_ASD_MASK) >> MCCR0_ASD_BIT);
+ return attotime::from_ticks(ticks, bit_rate);
+}
+
+attotime sa1110_periphs_device::mcp_get_telecom_frame_rate()
+{
+ const u32 bit_rate = BIT(m_mcp_regs.mccr1, MCCR1_CFS_BIT) ? 9585000 : 11981000;
+ const uint64_t ticks = 32 * ((m_mcp_regs.mccr0 & MCCR0_TSD_MASK) >> MCCR0_TSD_BIT);
+ return attotime::from_ticks(ticks, bit_rate);
+}
+
+void sa1110_periphs_device::mcp_update_sample_rate()
+{
+ const attotime audio_rate = mcp_get_audio_frame_rate();
+ m_mcp_regs.audio_tx_timer->adjust(audio_rate, 0, audio_rate);
+
+ const attotime telecom_rate = mcp_get_telecom_frame_rate();
+ m_mcp_regs.telecom_tx_timer->adjust(telecom_rate, 0, telecom_rate);
+}
+
+void sa1110_periphs_device::mcp_set_enabled(bool enabled)
+{
+ if (enabled)
+ {
+ mcp_update_sample_rate();
+ }
+ else
+ {
+ m_mcp_regs.audio_tx_timer->adjust(attotime::never);
+ m_mcp_regs.telecom_tx_timer->adjust(attotime::never);
+ }
+}
+
+void sa1110_periphs_device::mcp_audio_tx_fifo_push(const u16 value)
+{
+ if (m_mcp_regs.audio_rx_fifo_count == std::size(m_mcp_regs.audio_tx_fifo))
+ return;
+
+ m_mcp_regs.audio_tx_fifo[m_mcp_regs.audio_tx_fifo_write_idx] = value;
+ m_mcp_regs.audio_rx_fifo_write_idx = (m_mcp_regs.audio_tx_fifo_write_idx + 1) % std::size(m_mcp_regs.audio_tx_fifo);
+ m_mcp_regs.audio_rx_fifo_count++;
+
+ if (m_mcp_regs.audio_tx_fifo_count == std::size(m_mcp_regs.audio_tx_fifo))
+ m_mcp_regs.mcsr &= ~(1 << MCSR_ANF_BIT);
+
+ if (m_mcp_regs.audio_tx_fifo_count >= 4)
+ {
+ m_mcp_regs.mcsr &= ~(1 << MCSR_ATS_BIT);
+ if (BIT(m_mcp_regs.mccr0, MCCR0_ATE_BIT))
+ m_mcp_irqs->in_w<MCP_AUDIO_TX>(0);
+ }
+ else
+ {
+ m_mcp_regs.mcsr |= (1 << MCSR_ATS_BIT);
+ if (BIT(m_mcp_regs.mccr0, MCCR0_ATE_BIT))
+ m_mcp_irqs->in_w<MCP_AUDIO_TX>(1);
+ }
+}
+
+void sa1110_periphs_device::mcp_telecom_tx_fifo_push(const u16 value)
+{
+ if (m_mcp_regs.telecom_rx_fifo_count == std::size(m_mcp_regs.telecom_tx_fifo))
+ return;
+
+ m_mcp_regs.telecom_tx_fifo[m_mcp_regs.telecom_tx_fifo_write_idx] = value;
+ m_mcp_regs.telecom_rx_fifo_write_idx = (m_mcp_regs.telecom_tx_fifo_write_idx + 1) % std::size(m_mcp_regs.telecom_tx_fifo);
+ m_mcp_regs.telecom_rx_fifo_count++;
+
+ if (m_mcp_regs.telecom_tx_fifo_count == std::size(m_mcp_regs.telecom_tx_fifo))
+ m_mcp_regs.mcsr &= ~(1 << MCSR_TNF_BIT);
+
+ if (m_mcp_regs.audio_tx_fifo_count >= 4)
+ {
+ m_mcp_regs.mcsr &= ~(1 << MCSR_TTS_BIT);
+ if (BIT(m_mcp_regs.mccr0, MCCR0_TTE_BIT))
+ m_mcp_irqs->in_w<MCP_TELECOM_TX>(0);
+ }
+ else
+ {
+ m_mcp_regs.mcsr |= (1 << MCSR_TTS_BIT);
+ if (BIT(m_mcp_regs.mccr0, MCCR0_TTE_BIT))
+ m_mcp_irqs->in_w<MCP_TELECOM_TX>(1);
+ }
+}
+
+void sa1110_periphs_device::mcp_codec_read(offs_t offset)
+{
+ if (!m_codec)
+ return;
+
+ const u16 data = m_codec->read(offset);
+ m_mcp_regs.mcdr2 &= 0xffff0000;
+ m_mcp_regs.mcdr2 |= data;
+
+ m_mcp_regs.mcsr |= (1 << MCSR_CRC_BIT);
+ m_mcp_regs.mcsr &= ~(1 << MCSR_CWC_BIT);
+}
+
+void sa1110_periphs_device::mcp_codec_write(offs_t offset, u16 data)
+{
+ if (!m_codec)
+ return;
+
+ m_codec->write(offset, data);
+ m_mcp_regs.mcsr |= (1 << MCSR_CWC_BIT);
+ m_mcp_regs.mcsr &= ~(1 << MCSR_CRC_BIT);
+}
+
+u32 sa1110_periphs_device::mcp_mccr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_mcp_regs.mccr0;
+ LOGMASKED(LOG_MCP, "%s: mcp_mccr0_r: MCP Control Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::mcp_mccr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_MCP, "%s: mcp_mccr0_w: MCP Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_MCP, "%s: Audio Sample Rate Divisor: %02x\n", machine().describe_context(), data & MCCR0_ASD_MASK);
+ LOGMASKED(LOG_MCP, "%s: Telecom Sample Rate Divisor: %02x\n", machine().describe_context(), (data & MCCR0_TSD_MASK) >> MCCR0_TSD_BIT);
+ LOGMASKED(LOG_MCP, "%s: MCP Enable: %d\n", machine().describe_context(), BIT(data, MCCR0_MCE_BIT));
+ LOGMASKED(LOG_MCP, "%s: Clock Select: %s\n", machine().describe_context(), BIT(data, MCCR0_ECS_BIT) ? "External" : "Internal");
+ LOGMASKED(LOG_MCP, "%s: A/D Data Sampling Mode: %s Valid\n", machine().describe_context(), BIT(data, MCCR0_ADM_BIT) ? "First" : "Each");
+ LOGMASKED(LOG_MCP, "%s: Telecom Tx FIFO Interrupt Enable: %d\n", machine().describe_context(), BIT(data, MCCR0_TTE_BIT));
+ LOGMASKED(LOG_MCP, "%s: Telecom Rx FIFO Interrupt Enable: %d\n", machine().describe_context(), BIT(data, MCCR0_TRE_BIT));
+ LOGMASKED(LOG_MCP, "%s: Audio Tx FIFO Interrupt Enable: %d\n", machine().describe_context(), BIT(data, MCCR0_ATE_BIT));
+ LOGMASKED(LOG_MCP, "%s: Audio Rx FIFO Interrupt Enable: %d\n", machine().describe_context(), BIT(data, MCCR0_ARE_BIT));
+ LOGMASKED(LOG_MCP, "%s: Loopback Enable: %d\n", machine().describe_context(), BIT(data, MCCR0_LBM_BIT));
+ LOGMASKED(LOG_MCP, "%s: External Clock Prescaler: %d\n", machine().describe_context(), ((data & MCCR0_ECP_MASK) >> MCCR0_ECP_BIT) + 1);
+ const u32 old = m_mcp_regs.mccr0;
+ COMBINE_DATA(&m_mcp_regs.mccr0);
+ const u32 changed = old ^ m_mcp_regs.mccr0;
+ if (BIT(m_mcp_regs.mcsr, MCSR_ATS_BIT) && BIT(changed, MCCR0_ATE_BIT))
+ m_mcp_irqs->in_w<MCP_AUDIO_TX>(BIT(m_mcp_regs.mcsr, MCSR_ATS_BIT));
+ if (BIT(m_mcp_regs.mcsr, MCSR_ARS_BIT) && BIT(changed, MCCR0_ARE_BIT))
+ m_mcp_irqs->in_w<MCP_AUDIO_RX>(BIT(m_mcp_regs.mcsr, MCSR_ARS_BIT));
+ if (BIT(m_mcp_regs.mcsr, MCSR_TTS_BIT) && BIT(changed, MCCR0_TTE_BIT))
+ m_mcp_irqs->in_w<MCP_TELECOM_TX>(BIT(m_mcp_regs.mcsr, MCSR_TTS_BIT));
+ if (BIT(m_mcp_regs.mcsr, MCSR_TRS_BIT) && BIT(changed, MCCR0_TRE_BIT))
+ m_mcp_irqs->in_w<MCP_TELECOM_RX>(BIT(m_mcp_regs.mcsr, MCSR_TRS_BIT));
+ if (BIT(old, MCCR0_MCE_BIT) != BIT(m_mcp_regs.mccr0, MCCR0_MCE_BIT))
+ mcp_set_enabled(BIT(m_mcp_regs.mccr0, MCCR0_MCE_BIT));
+}
+
+u32 sa1110_periphs_device::mcp_mcdr0_r(offs_t offset, u32 mem_mask)
+{
+ const u16 data = mcp_read_audio_fifo() << 4;
+ LOGMASKED(LOG_MCP, "%s: mcp_mcdr0_r: MCP Data Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::mcp_mcdr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_MCP, "%s: mcp_mcdr0_w: MCP Data Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ mcp_audio_tx_fifo_push((u16)data);
+}
+
+u32 sa1110_periphs_device::mcp_mcdr1_r(offs_t offset, u32 mem_mask)
+{
+ const u16 data = mcp_read_telecom_fifo() << 4;
+ LOGMASKED(LOG_MCP, "%s: mcp_mcdr1_r: MCP Data Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::mcp_mcdr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_MCP, "%s: mcp_mcdr1_w: MCP Data Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ mcp_telecom_tx_fifo_push((u16)data);
+}
+
+u32 sa1110_periphs_device::mcp_mcdr2_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_mcp_regs.mcdr2;
+ LOGMASKED(LOG_MCP, "%s: mcp_mcdr2_r: MCP Data Register 2: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_MCP, "%s: Value: %04x\n", machine().describe_context(), (u16)m_mcp_regs.mcdr2);
+ LOGMASKED(LOG_MCP, "%s: Read/Write: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcdr2, 16));
+ LOGMASKED(LOG_MCP, "%s: Address: %01x\n", machine().describe_context(), (m_mcp_regs.mcdr2 >> 17) & 0xf);
+ return data;
+}
+
+void sa1110_periphs_device::mcp_mcdr2_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ const offs_t addr = (data & MCDR2_ADDR_MASK) >> MCDR2_ADDR_BIT;
+ LOGMASKED(LOG_MCP, "%s: mcp_mcdr2_w: MCP Data Register 2 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_mcp_regs.mcdr2);
+ m_mcp_regs.mcdr2 &= ~(1 << MCDR2_RW_BIT);
+
+ if (BIT(data, MCDR2_RW_BIT))
+ mcp_codec_write(addr, (u16)data);
+ else
+ mcp_codec_read(addr);
+}
+
+u32 sa1110_periphs_device::mcp_mcsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_mcp_regs.mcsr;
+ LOGMASKED(LOG_MCP, "%s: mcp_mcsr_r: MCP Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_MCP, "%s: Audio Xmit FIFO Service Request: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 0));
+ LOGMASKED(LOG_MCP, "%s: Audio Recv FIFO Service Request: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 1));
+ LOGMASKED(LOG_MCP, "%s: Telecom Xmit FIFO Service Request: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 2));
+ LOGMASKED(LOG_MCP, "%s: Telecom Recv FIFO Service Request: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 3));
+ LOGMASKED(LOG_MCP, "%s: Audio Xmit FIFO Underrun: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 4));
+ LOGMASKED(LOG_MCP, "%s: Audio Recv FIFO Overrun: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 5));
+ LOGMASKED(LOG_MCP, "%s: Telcom Xmit FIFO Underrun: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 6));
+ LOGMASKED(LOG_MCP, "%s: Telcom Recv FIFO Overrun: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 7));
+ LOGMASKED(LOG_MCP, "%s: Audio Xmit FIFO Not Full: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 8));
+ LOGMASKED(LOG_MCP, "%s: Audio Recv FIFO Not Empty: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 9));
+ LOGMASKED(LOG_MCP, "%s: Telcom Xmit FIFO Not Full: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 10));
+ LOGMASKED(LOG_MCP, "%s: Telcom Recv FIFO Not Empty: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 11));
+ LOGMASKED(LOG_MCP, "%s: Codec Write Complete: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 12));
+ LOGMASKED(LOG_MCP, "%s: Codec Read Complete: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 13));
+ LOGMASKED(LOG_MCP, "%s: Audio Codec Enabled: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 14));
+ LOGMASKED(LOG_MCP, "%s: Telecom Codec Enabled: %d\n", machine().describe_context(), BIT(m_mcp_regs.mcsr, 15));
+ return data;
+}
+
+void sa1110_periphs_device::mcp_mcsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_MCP, "%s: mcp_w: MCP Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_mcp_regs.mcsr;
+ const u32 sticky_mask = (1 << MCSR_ATU_BIT) | (1 << MCSR_ARO_BIT) | (1 << MCSR_TTU_BIT) | (1 << MCSR_TRO_BIT);
+ m_mcp_regs.mcsr &= ~(data & mem_mask & sticky_mask);
+ if (BIT(old, MCSR_ATU_BIT) && !BIT(m_mcp_regs.mcsr, MCSR_ATU_BIT))
+ m_mcp_irqs->in_w<MCP_AUDIO_UNDERRUN>(0);
+ if (BIT(old, MCSR_ARO_BIT) && !BIT(m_mcp_regs.mcsr, MCSR_ARO_BIT))
+ m_mcp_irqs->in_w<MCP_AUDIO_OVERRUN>(0);
+ if (BIT(old, MCSR_TTU_BIT) && !BIT(m_mcp_regs.mcsr, MCSR_TTU_BIT))
+ m_mcp_irqs->in_w<MCP_TELECOM_UNDERRUN>(0);
+ if (BIT(old, MCSR_TRO_BIT) && !BIT(m_mcp_regs.mcsr, MCSR_TRO_BIT))
+ m_mcp_irqs->in_w<MCP_TELECOM_OVERRUN>(0);
+}
+
+
+/*
+
+ Intel SA-1110 SSP - Synchronous Serial Port
+
+ pg. 331 to 347 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::ssp_rx_callback)
+{
+ // TODO: Implement receiving data serially rather than in bulk.
+}
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::ssp_tx_callback)
+{
+ // TODO: Implement transmitting data serially rather than in bulk.
+ if (m_ssp_regs.tx_fifo_count)
+ {
+ const u16 data = m_ssp_regs.tx_fifo[m_ssp_regs.tx_fifo_read_idx];
+ m_ssp_out(data);
+ LOGMASKED(LOG_SSP, "SSP: Transmitting %04x, new Tx FIFO count %d\n", data, m_ssp_regs.tx_fifo_count);
+
+ m_ssp_regs.tx_fifo_read_idx = (m_ssp_regs.tx_fifo_read_idx + 1) % std::size(m_ssp_regs.tx_fifo);
+ m_ssp_regs.tx_fifo_count--;
+
+ m_ssp_regs.sssr |= (1 << SSSR_TNF_BIT);
+
+ if (m_ssp_regs.tx_fifo_count || m_ssp_regs.rx_fifo_count)
+ m_ssp_regs.sssr |= (1 << SSSR_BSY_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_BSY_BIT);
+
+ ssp_update_tx_level();
+ }
+}
+
+void sa1110_periphs_device::ssp_update_enable_state()
+{
+ if (BIT(m_ssp_regs.sscr0, SSCR0_SSE_BIT))
+ {
+ if (m_ssp_regs.tx_fifo_count != std::size(m_ssp_regs.tx_fifo))
+ m_ssp_regs.sssr |= (1 << SSSR_TNF_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_TNF_BIT);
+
+ if (m_ssp_regs.rx_fifo_count != 0)
+ m_ssp_regs.sssr |= (1 << SSSR_RNE_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_RNE_BIT);
+
+ if (m_ssp_regs.tx_fifo_count != 0)
+ m_ssp_regs.sssr |= (1 << SSSR_BSY_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_BSY_BIT);
+
+ if (m_ssp_regs.tx_fifo_count <= 4)
+ m_ssp_regs.sssr |= (1 << SSSR_TFS_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_TFS_BIT);
+
+ if (m_ssp_regs.rx_fifo_count >= 4)
+ m_ssp_regs.sssr |= (1 << SSSR_RFS_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_RFS_BIT);
+
+ uint64_t bit_count = (m_ssp_regs.sscr0 & SSCR0_DSS_MASK) >> SSCR0_DSS_BIT;
+ u32 clock_rate = 2 * (((m_ssp_regs.sscr0 & SSCR0_SCR_MASK) >> SSCR0_SCR_BIT) + 1);
+ attotime packet_rate = attotime::from_ticks(bit_count * clock_rate, 3686400);
+ m_ssp_regs.rx_timer->adjust(packet_rate, 0, packet_rate);
+ m_ssp_regs.tx_timer->adjust(packet_rate, 0, packet_rate);
+ }
+ else
+ {
+ m_ssp_regs.sssr &= ~(1 << SSSR_TFS_BIT);
+ m_ssp_regs.sssr &= ~(1 << SSSR_RFS_BIT);
+
+ m_ssp_regs.rx_fifo_read_idx = 0;
+ m_ssp_regs.rx_fifo_write_idx = 0;
+ m_ssp_regs.rx_fifo_count = 0;
+ m_ssp_regs.tx_fifo_read_idx = 0;
+ m_ssp_regs.tx_fifo_write_idx = 0;
+ m_ssp_regs.tx_fifo_count = 0;
+
+ m_ssp_regs.rx_timer->adjust(attotime::never);
+ m_ssp_regs.tx_timer->adjust(attotime::never);
+ }
+}
+
+void sa1110_periphs_device::ssp_update_rx_level()
+{
+ if (m_ssp_regs.rx_fifo_count >= 4)
+ m_ssp_regs.sssr |= (1 << SSSR_RFS_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_RFS_BIT);
+}
+
+void sa1110_periphs_device::ssp_rx_fifo_push(const u16 data)
+{
+ if (m_ssp_regs.rx_fifo_count < std::size(m_ssp_regs.rx_fifo))
+ {
+ m_ssp_regs.rx_fifo[m_ssp_regs.rx_fifo_write_idx] = data;
+ m_ssp_regs.rx_fifo_write_idx = (m_ssp_regs.rx_fifo_write_idx + 1) % std::size(m_ssp_regs.rx_fifo);
+ m_ssp_regs.rx_fifo_count++;
+
+ m_ssp_regs.sssr |= (1 << SSSR_RNE_BIT);
+
+ ssp_update_rx_level();
+ }
+}
+
+void sa1110_periphs_device::ssp_update_tx_level()
+{
+ if (m_ssp_regs.tx_fifo_count <= 4)
+ m_ssp_regs.sssr |= (1 << SSSR_TFS_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_TFS_BIT);
+}
+
+void sa1110_periphs_device::ssp_tx_fifo_push(const u16 data)
+{
+ if (m_ssp_regs.tx_fifo_count < std::size(m_ssp_regs.tx_fifo))
+ {
+ m_ssp_regs.tx_fifo[m_ssp_regs.tx_fifo_write_idx] = data;
+ m_ssp_regs.tx_fifo_write_idx = (m_ssp_regs.tx_fifo_write_idx + 1) % std::size(m_ssp_regs.tx_fifo);
+ m_ssp_regs.tx_fifo_count++;
+
+ if (m_ssp_regs.tx_fifo_count != std::size(m_ssp_regs.tx_fifo))
+ m_ssp_regs.sssr |= (1 << SSSR_TNF_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_TNF_BIT);
+
+ ssp_update_tx_level();
+ }
+
+ if (m_ssp_regs.tx_fifo_count || m_ssp_regs.rx_fifo_count)
+ m_ssp_regs.sssr |= (1 << SSSR_BSY_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_BSY_BIT);
+}
+
+u16 sa1110_periphs_device::ssp_rx_fifo_pop()
+{
+ u16 data = m_ssp_regs.rx_fifo[m_ssp_regs.rx_fifo_read_idx];
+ if (m_ssp_regs.rx_fifo_count)
+ {
+ m_ssp_regs.rx_fifo_read_idx = (m_ssp_regs.rx_fifo_read_idx + 1) % std::size(m_ssp_regs.rx_fifo);
+ m_ssp_regs.rx_fifo_count--;
+
+ if (m_ssp_regs.rx_fifo_count == 0)
+ m_ssp_regs.sssr &= ~(1 << SSSR_RNE_BIT);
+
+ if (m_ssp_regs.tx_fifo_count || m_ssp_regs.rx_fifo_count)
+ m_ssp_regs.sssr |= (1 << SSSR_BSY_BIT);
+ else
+ m_ssp_regs.sssr &= ~(1 << SSSR_BSY_BIT);
+
+ ssp_update_rx_level();
+ }
+ return data;
+}
+
+u32 sa1110_periphs_device::ssp_sscr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ssp_regs.sscr0;
+ LOGMASKED(LOG_SSP, "%s: ssp_sscr0_r: SSP Control Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::ssp_sscr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ static const char *const s_dss_sizes[16] =
+ {
+ "Invalid [1]", "Invalid [2]", "Invalid [3]", "4-bit",
+ "5-bit", "6-bit", "7-bit", "8-bit",
+ "9-bit", "10-bit", "11-bit", "12-bit",
+ "13-bit", "14-bit", "15-bit", "16-bit"
+ };
+ static const char *const s_frf_formats[4] = { "Motorola SPI", "TI Synchronous Serial", "National Microwire", "Reserved" };
+ LOGMASKED(LOG_SSP, "%s: ssp_sscr0_w: SSP Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP, "%s: Data Size Select: %s\n", machine().describe_context(), s_dss_sizes[(data & SSCR0_DSS_MASK) >> SSCR0_DSS_BIT]);
+ LOGMASKED(LOG_SSP, "%s: Frame Format: %s\n", machine().describe_context(), s_frf_formats[(data & SSCR0_FRF_MASK) >> SSCR0_FRF_BIT]);
+ LOGMASKED(LOG_SSP, "%s: SSP Enable: %d\n", machine().describe_context(), BIT(data, SSCR0_SSE_BIT));
+ LOGMASKED(LOG_SSP, "%s: Serial Clock Rate Divisor: %d\n", machine().describe_context(), 2 * (data & SSCR0_DSS_MASK) >> SSCR0_DSS_BIT);
+ const u32 old = m_ssp_regs.sscr0;
+ COMBINE_DATA(&m_ssp_regs.sscr0);
+ if (BIT(old ^ m_ssp_regs.sscr0, SSCR0_SSE_BIT))
+ ssp_update_enable_state();
+}
+
+u32 sa1110_periphs_device::ssp_sscr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ssp_regs.sscr1;
+ LOGMASKED(LOG_SSP, "%s: ssp_sscr1_r: SSP Control Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::ssp_sscr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: ssp_sscr1_w: SSP Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP, "%s: Receive FIFO Interrupt Enable: %d\n", machine().describe_context(), BIT(data, SSCR1_RIE_BIT));
+ LOGMASKED(LOG_SSP, "%s: Transmit FIFO Interrupt Enable: %d\n", machine().describe_context(), BIT(data, SSCR1_TIE_BIT));
+ LOGMASKED(LOG_SSP, "%s: Loopback Mode Enable: %d\n", machine().describe_context(), BIT(data, SSCR1_LBM_BIT));
+ LOGMASKED(LOG_SSP, "%s: Serial Clock Polarity: %d\n", machine().describe_context(), BIT(data, SSCR1_SPO_BIT));
+ LOGMASKED(LOG_SSP, "%s: Serial Clock Phase: %d\n", machine().describe_context(), BIT(data, SSCR1_SPH_BIT));
+ LOGMASKED(LOG_SSP, "%s: External Clock Select: %d\n", machine().describe_context(), BIT(data, SSCR1_ECS_BIT));
+ COMBINE_DATA(&m_ssp_regs.sscr1);
+}
+
+u32 sa1110_periphs_device::ssp_ssdr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = ssp_rx_fifo_pop();
+ LOGMASKED(LOG_SSP, "%s: ssp_ssdr_r: SSP Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::ssp_ssdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: ssp_ssdr_w: SSP Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ ssp_tx_fifo_push((u16)data);
+}
+
+u32 sa1110_periphs_device::ssp_sssr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ssp_regs.sssr;
+ LOGMASKED(LOG_SSP, "%s: ssp_r: SSP Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(m_ssp_regs.sssr, SSSR_TNF_BIT));
+ LOGMASKED(LOG_SSP, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(m_ssp_regs.sssr, SSSR_RNE_BIT));
+ LOGMASKED(LOG_SSP, "%s: SSP Busy: %d\n", machine().describe_context(), BIT(m_ssp_regs.sssr, SSSR_BSY_BIT));
+ LOGMASKED(LOG_SSP, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(m_ssp_regs.sssr, SSSR_TFS_BIT));
+ LOGMASKED(LOG_SSP, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(m_ssp_regs.sssr, SSSR_RFS_BIT));
+ LOGMASKED(LOG_SSP, "%s: Receive Overrun: %d\n", machine().describe_context(), BIT(m_ssp_regs.sssr, SSSR_ROR_BIT));
+ return data;
+}
+
+void sa1110_periphs_device::ssp_sssr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: ssp_sssr_w: SSP Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP, "%s: Clear Receive Overrun: %d\n", machine().describe_context(), BIT(data, SSSR_ROR_BIT));
+}
+
+
+/*
+
+ Intel SA-1110 Operating System Timer
+
+ pg. 92 to 96 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::ostimer_tick_cb)
+{
+ const int channel = param;
+ if (BIT(m_ostmr_regs.oier, channel))
+ {
+ m_ostmr_regs.ossr |= (1 << channel);
+ set_irq_line(INT_OSTIMER0 + channel, 1);
+ // TODO: Handle Channel 3, watchdog timer mode
+ }
+}
+
+void sa1110_periphs_device::ostimer_update_count()
+{
+ const attotime time_delta = machine().time() - m_ostmr_regs.last_count_sync;
+ const uint64_t ticks_elapsed = time_delta.as_ticks(INTERNAL_OSC);
+ if (ticks_elapsed == 0ULL) // Accrue time until we can tick at least once
+ return;
+
+ const u32 wrapped_ticks = (u32)ticks_elapsed;
+ m_ostmr_regs.oscr += wrapped_ticks;
+ m_ostmr_regs.last_count_sync = machine().time();
+}
+
+void sa1110_periphs_device::ostimer_update_match_timer(int channel)
+{
+ ostimer_update_count();
+ uint64_t ticks_remaining = m_ostmr_regs.osmr[channel] - m_ostmr_regs.oscr;
+ if (m_ostmr_regs.oscr >= m_ostmr_regs.osmr[channel])
+ ticks_remaining += 0x100000000ULL;
+ m_ostmr_regs.timer[channel]->adjust(attotime::from_ticks(ticks_remaining, INTERNAL_OSC), channel);
+ if (channel != 0)
+ LOGMASKED(LOG_OSTIMER, "ostimer_update_match_timer: %d ticks at %dHz (%4.fms)\n", ticks_remaining, INTERNAL_OSC, attotime::from_ticks(ticks_remaining, INTERNAL_OSC).as_double() * 1000.0);
+}
+
+u32 sa1110_periphs_device::tmr_osmr0_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostmr_regs.osmr[0];
+ LOGMASKED(LOG_OSTIMER_HF, "%s: tmr_osmr0_r: OS Timer Match Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_osmr0_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER_HF, "%s: tmr_osmr0_w: OS Timer Match Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ostmr_regs.osmr[0]);
+ ostimer_update_match_timer(0);
+}
+
+u32 sa1110_periphs_device::tmr_osmr1_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostmr_regs.osmr[1];
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_osmr1_r: OS Timer Match Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_osmr1_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_osmr1_w: OS Timer Match Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ostmr_regs.osmr[1]);
+ ostimer_update_match_timer(1);
+}
+
+u32 sa1110_periphs_device::tmr_osmr2_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostmr_regs.osmr[2];
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_osmr2_r: OS Timer Match Register 2: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_osmr2_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_osmr2_w: OS Timer Match Register 2 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ostmr_regs.osmr[2]);
+ ostimer_update_match_timer(2);
+}
+
+u32 sa1110_periphs_device::tmr_osmr3_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostmr_regs.osmr[3];
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_osmr3_r: OS Timer Match Register 3: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_osmr3_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_osmr3_w: OS Timer Match Register 3 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ostmr_regs.osmr[3]);
+ ostimer_update_match_timer(3);
+}
+
+u32 sa1110_periphs_device::tmr_oscr_r(offs_t offset, u32 mem_mask)
+{
+ ostimer_update_count();
+
+ const u32 data = m_ostmr_regs.oscr;
+ LOGMASKED(LOG_OSTIMER_HF, "%s: tmr_oscr_r: OS Timer Counter Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_oscr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_oscr_w: OS Timer Counter Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ostmr_regs.oscr);
+ m_ostmr_regs.last_count_sync = machine().time();
+ for (int channel = 0; channel < 4; channel++)
+ {
+ if (m_ostmr_regs.oscr == m_ostmr_regs.osmr[channel] && BIT(m_ostmr_regs.oier, channel))
+ {
+ if (!BIT(m_ostmr_regs.ossr, channel))
+ {
+ m_ostmr_regs.ossr |= (1 << channel);
+ set_irq_line(INT_OSTIMER0 + channel, 1);
+ }
+ }
+ else
+ {
+ ostimer_update_match_timer(channel);
+ }
+ }
+}
+
+u32 sa1110_periphs_device::tmr_ossr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostmr_regs.ossr;
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ossr_r: OS Timer Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_ossr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ if (data != 1)
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ossr_w: OS Timer Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_ostmr_regs.ossr;
+ m_ostmr_regs.ossr &= ~(data & mem_mask);
+ const u32 cleared = old & ~ m_ostmr_regs.ossr;
+ for (int channel = 0; channel < 4; channel++)
+ {
+ if (BIT(cleared, channel))
+ set_irq_line(INT_OSTIMER0 + channel, 0);
+ }
+}
+
+u32 sa1110_periphs_device::tmr_ower_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostmr_regs.ower;
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ower_r: OS Timer Watchdog Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_ower_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_ower_w: OS Timer Watchdog Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ if (!m_ostmr_regs.ower)
+ {
+ m_ostmr_regs.ower = data & mem_mask & 1;
+ }
+}
+
+u32 sa1110_periphs_device::tmr_oier_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ostmr_regs.oier;
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_oier_r: OS Timer Interrupt Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::tmr_oier_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_OSTIMER, "%s: tmr_oier_w: OS Timer Interrupt Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ostmr_regs.oier);
+}
+
+
+/*
+
+ Intel SA-1110 Real-Time Clock
+
+ pg. 88 to 92 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+TIMER_CALLBACK_MEMBER(sa1110_periphs_device::rtc_tick_cb)
+{
+ m_rtc_regs.rcnr++;
+ m_rtc_regs.rtsr |= (1 << RTSR_HZ_BIT);
+
+ if (m_rtc_regs.rcnr == m_rtc_regs.rtar)
+ {
+ m_rtc_regs.rtsr |= (1 << RTSR_AL_BIT);
+ if (BIT(m_rtc_regs.rtsr, RTSR_ALE_BIT))
+ set_irq_line(INT_RTC_ALARM, 1);
}
+
+ if (BIT(m_rtc_regs.rtsr, RTSR_HZE_BIT))
+ set_irq_line(INT_RTC_TICK, 1);
+}
+
+u32 sa1110_periphs_device::rtc_rtar_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rtc_regs.rtar;
+ LOGMASKED(LOG_RTC, "%s: rtc_rtar_r: RTC Alarm Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::rtc_rtar_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: rtc_rtar_w: RTC Alarm Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_rtc_regs.rtar);
+}
+
+u32 sa1110_periphs_device::rtc_rcnr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rtc_regs.rcnr;
+ LOGMASKED(LOG_RTC_HF, "%s: rtc_rcnr_r: RTC Count Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::rtc_rcnr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: rtc_rcnr_w: RTC Count Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_rtc_regs.rcnr);
+}
+
+u32 sa1110_periphs_device::rtc_rttr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rtc_regs.rttr;
+ LOGMASKED(LOG_RTC, "%s: rtc_rttr_r: RTC Timer Trim Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::rtc_rttr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: rtc_rttr_w: RTC Timer Trim Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_rtc_regs.rttr);
+ // TODO: Implement timer trimming
+}
+
+u32 sa1110_periphs_device::rtc_rtsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rtc_regs.rtsr;
+ LOGMASKED(LOG_RTC, "%s: rtc_rtsr_r: RTC Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::rtc_rtsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RTC, "%s: rtc_w: RTC Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+
+ const u32 old = m_rtc_regs.rtsr;
+ const bool old_alarm_int = BIT(old, RTSR_AL_BIT) && BIT(m_rtc_regs.rtsr, RTSR_ALE_BIT);
+ const bool old_tick_int = BIT(old, RTSR_HZ_BIT) && BIT(m_rtc_regs.rtsr, RTSR_HZE_BIT);
+
+ m_rtc_regs.rtsr &= ~(data & (RTSR_AL_MASK | RTSR_HZ_MASK) & mem_mask);
+ m_rtc_regs.rtsr &= ~(RTSR_ALE_MASK | RTSR_HZE_MASK);
+ m_rtc_regs.rtsr |= (data & (RTSR_ALE_MASK | RTSR_HZE_MASK) & mem_mask);
+
+ const bool new_alarm_int = BIT(m_rtc_regs.rtsr, RTSR_AL_BIT) && BIT(m_rtc_regs.rtsr, RTSR_ALE_BIT);
+ const bool new_tick_int = BIT(m_rtc_regs.rtsr, RTSR_HZ_BIT) && BIT(m_rtc_regs.rtsr, RTSR_HZE_BIT);
+
+ if (old_alarm_int != new_alarm_int)
+ set_irq_line(INT_RTC_ALARM, (int)new_alarm_int);
+ if (old_tick_int != new_tick_int)
+ set_irq_line(INT_RTC_TICK, (int)new_tick_int);
}
+
/*
Intel SA-1110 Power Controller
@@ -116,112 +1898,1115 @@ void sa1110_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_ma
*/
-uint32_t sa1110_periphs_device::power_r(offs_t offset, uint32_t mem_mask)
-{
- switch (offset)
- {
- case REG_PMCR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Control Register: %08x\n", machine().describe_context(), m_power_regs.pmcr);
- return m_power_regs.pmcr;
- case REG_PSSR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Sleep Status Register: %08x\n", machine().describe_context(), m_power_regs.pssr);
- return m_power_regs.pssr;
- case REG_PSPR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Scratch Pad Register: %08x\n", machine().describe_context(), m_power_regs.pspr);
- return m_power_regs.pspr;
- case REG_PWER:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Wake-up Enable Register: %08x\n", machine().describe_context(), m_power_regs.pwer);
- return m_power_regs.pwer;
- case REG_PCFR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager General Configuration Register: %08x\n", machine().describe_context(), m_power_regs.pcfr);
- return m_power_regs.pcfr;
- case REG_PPCR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager PLL Configuration Register: %08x\n", machine().describe_context(), m_power_regs.ppcr);
- return m_power_regs.ppcr;
- case REG_PGSR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Sleep State Register: %08x\n", machine().describe_context(), m_power_regs.pgsr);
- return m_power_regs.pgsr;
- case REG_POSR:
- LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Oscillator Status Register: %08x\n", machine().describe_context(), m_power_regs.posr);
- return m_power_regs.posr;
- default:
- LOGMASKED(LOG_POWER | LOG_UNKNOWN, "%s: power_r: Unknown address: %08x\n", machine().describe_context(), POWER_BASE_ADDR | (offset << 2));
- break;
+u32 sa1110_periphs_device::pwr_pmcr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pmcr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pmcr_r: Power Manager Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_pmcr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pmcr_w: Power Manager Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pmcr);
+}
+
+u32 sa1110_periphs_device::pwr_pssr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pssr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pssr_r: Power Manager Sleep Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_pssr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pssr_w: Power Manager Sleep Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_power_regs.pssr &= ~(data & 0x0000001f);
+}
+
+u32 sa1110_periphs_device::pwr_pspr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pspr;
+ LOGMASKED(LOG_POWER_HF, "%s: pwr_pspr_r: Power Manager Scratch Pad Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_pspr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER_HF, "%s: pwr_pspr_w: Power Manager Scratch Pad Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pspr);
+}
+
+u32 sa1110_periphs_device::pwr_pwer_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pwer;
+ LOGMASKED(LOG_POWER, "%s: pwr_pwer_r: Power Manager Wake-up Enable Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_pwer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pwer_w: Power Manager Wake-Up Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pwer);
+}
+
+u32 sa1110_periphs_device::pwr_pcfr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pcfr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pcfr_r: Power Manager General Configuration Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_pcfr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pcfr_w: Power Manager General Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pcfr);
+}
+
+u32 sa1110_periphs_device::pwr_ppcr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.ppcr;
+ LOGMASKED(LOG_POWER, "%s: pwr_ppcr_r: Power Manager PLL Configuration Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_ppcr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_ppcr_w: Power Manager PLL Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.ppcr);
+}
+
+u32 sa1110_periphs_device::pwr_pgsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.pgsr;
+ LOGMASKED(LOG_POWER, "%s: pwr_pgsr_r: Power Manager GPIO Sleep State Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_pgsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: pwr_pgsr_w: Power Manager GPIO Sleep State Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_power_regs.pgsr);
+}
+
+u32 sa1110_periphs_device::pwr_posr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_power_regs.posr;
+ LOGMASKED(LOG_POWER, "%s: pwr_posr_r: Power Manager Oscillator Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::pwr_posr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Oscillator Status Register (ignored) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+
+/*
+
+ Intel SA-1110 Reset Controller
+
+ pg. 112 to 114 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+u32 sa1110_periphs_device::rst_rsrr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = 0;
+ LOGMASKED(LOG_RESET, "%s: rst_rsrr_r: Reset Controller Software Reset Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::rst_rsrr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RESET, "%s: rst_rsrr_w: Reset Controller Software Reset Register (ignored) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::rst_rcsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_rcsr;
+ LOGMASKED(LOG_RESET, "%s: rst_rcsr_r: Reset Controller Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::rst_rcsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_RESET, "%s: rst_rcsr_w: Reset Controller Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_rcsr &= ~(data & mem_mask);
+}
+
+
+/*
+
+ Intel SA-1110 GPIO Controller
+
+ pg. 71 to 80 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+void sa1110_periphs_device::gpio_in(const u32 line, const int state)
+{
+ const u32 mask = (1 << line);
+ const u32 old_latch = m_gpio_regs.input_latch;
+ m_gpio_regs.input_latch &= ~mask;
+ m_gpio_regs.input_latch |= (state << line);
+
+ LOGMASKED(LOG_GPIO, "gpio_in: Line %d, state %d\n", line, state);
+ if (old_latch != m_gpio_regs.input_latch && !BIT(m_gpio_regs.gafr, line))
+ {
+ // TODO: The manual is unclear if edge detection functions on both inputs and outputs.
+ // If it can also function on outputs, remove the GPDR check below.
+ if (!BIT(m_gpio_regs.gpdr, line) && BIT(m_gpio_regs.any_edge_mask, line))
+ {
+ const u32 old_edge = m_gpio_regs.gedr;
+ if (state && BIT(m_gpio_regs.grer, line))
+ m_gpio_regs.gedr |= mask;
+ if (!state && BIT(m_gpio_regs.gfer, line))
+ m_gpio_regs.gedr |= mask;
+ if (old_edge != m_gpio_regs.gedr)
+ gpio_update_interrupts(mask);
+ }
+
+ m_gpio_regs.gplr = (m_gpio_regs.input_latch & ~m_gpio_regs.gafr) | (m_gpio_regs.alt_input_latch & m_gpio_regs.gafr);
+ LOGMASKED(LOG_GPIO, "gpio_in: New GPLR: %08x\n", m_gpio_regs.gplr);
}
- return 0;
}
-void sa1110_periphs_device::power_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+void sa1110_periphs_device::gpio_update_interrupts(const u32 changed_mask)
{
- switch (offset)
+ u32 remaining_mask = changed_mask;
+ for (u32 line = 0; line < 11; line++)
{
- case REG_PMCR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pmcr);
- break;
- case REG_PSSR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Sleep Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- m_power_regs.pssr &= ~(data & 0x0000001f);
- break;
- case REG_PSPR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Scratch Pad Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pspr);
- break;
- case REG_PWER:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Wake-Up Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pwer);
- break;
- case REG_PCFR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager General Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pcfr);
- break;
- case REG_PPCR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager PLL Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.ppcr);
- break;
- case REG_PGSR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager GPIO Sleep State Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_power_regs.pgsr);
- break;
- case REG_POSR:
- LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Oscillator Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- break;
- default:
- LOGMASKED(LOG_POWER | LOG_UNKNOWN, "%s: power_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), POWER_BASE_ADDR | (offset << 2),
- data, mem_mask);
- break;
+ if (!BIT(remaining_mask, line))
+ continue;
+
+ set_irq_line(INT_GPIO0 + line, BIT(m_gpio_regs.gedr, line));
+ remaining_mask &= ~(1 << line);
}
+
+ if (!remaining_mask)
+ return;
+
+ set_irq_line(INT_GPIOHI, (m_gpio_regs.gedr & 0x0ffff800) ? 1 : 0);
}
-void sa1110_periphs_device::device_start()
+void sa1110_periphs_device::gpio_update_direction(const u32 old_gpdr)
{
- save_item(NAME(m_intc_regs.icip), m_intc_regs.icip);
- save_item(NAME(m_intc_regs.icmr), m_intc_regs.icmr);
- save_item(NAME(m_intc_regs.iclr), m_intc_regs.iclr);
- save_item(NAME(m_intc_regs.iccr), m_intc_regs.iccr);
- save_item(NAME(m_intc_regs.icfp), m_intc_regs.icfp);
- save_item(NAME(m_intc_regs.icpr), m_intc_regs.icpr);
+ const u32 new_outputs = ~old_gpdr & m_gpio_regs.gpdr & ~m_gpio_regs.gafr;
+ if (new_outputs)
+ {
+ for (u32 line = 0; line < 28; line++)
+ {
+ if (BIT(new_outputs, line))
+ {
+ m_gpio_out[line](BIT(m_gpio_regs.gplr, line));
+ }
+ }
+ }
- save_item(NAME(m_power_regs.pmcr), m_power_regs.pmcr);
- save_item(NAME(m_power_regs.pssr), m_power_regs.pssr);
- save_item(NAME(m_power_regs.pspr), m_power_regs.pspr);
- save_item(NAME(m_power_regs.pwer), m_power_regs.pwer);
- save_item(NAME(m_power_regs.pcfr), m_power_regs.pcfr);
- save_item(NAME(m_power_regs.ppcr), m_power_regs.ppcr);
- save_item(NAME(m_power_regs.pgsr), m_power_regs.pgsr);
- save_item(NAME(m_power_regs.posr), m_power_regs.posr);
+ // TODO: Do we need to check rising/falling edges based on the transition from output to input?
}
-void sa1110_periphs_device::device_reset()
+void sa1110_periphs_device::gpio_update_outputs(const u32 old_latch, const u32 changed)
{
- memset(&m_intc_regs, 0, sizeof(m_intc_regs));
- memset(&m_power_regs, 0, sizeof(m_power_regs));
+ u32 remaining_changed = changed;
+
+ for (u32 line = 0; line < 28 && remaining_changed != 0; line++)
+ {
+ if (BIT(remaining_changed, line))
+ {
+ m_gpio_out[line](BIT(m_gpio_regs.output_latch, line));
+ remaining_changed &= ~(1 << line);
+ }
+ }
+}
+
+void sa1110_periphs_device::gpio_update_alternate_pins(const u32 changed_mask)
+{
+ // TODO
+}
+
+u32 sa1110_periphs_device::gpio_gplr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gplr;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gplr_r: GPIO Pin-Level Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_gplr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gplr_w: GPIO Pin-Level Register (ignored) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::gpio_gpdr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gpdr;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpdr_r: GPIO Direction Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_gpdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpdr_w: GPIO Pin Direction Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_gpio_regs.gpdr;
+ COMBINE_DATA(&m_gpio_regs.gpdr);
+ if (old != m_gpio_regs.gpdr)
+ gpio_update_direction(old);
+ }
+
+u32 sa1110_periphs_device::gpio_gpsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = 0;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpsr_r: GPIO Output Set Register (ignored): %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_gpsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpsr_w: GPIO Pin Output Set Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_gpio_regs.output_latch;
+ m_gpio_regs.output_latch |= (data & mem_mask);
+ const u32 changed = ((old ^ m_gpio_regs.output_latch) & m_gpio_regs.gpdr) & ~m_gpio_regs.gafr;
+ if (changed)
+ gpio_update_outputs(old, changed);
+}
+
+u32 sa1110_periphs_device::gpio_gpcr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = 0;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpcr_r: GPIO Output Clear Register (ignored): %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_gpcr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gpcr_w: GPIO Pin Output Clear Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_gpio_regs.output_latch;
+ m_gpio_regs.output_latch &= ~(data & mem_mask);
+ const u32 changed = ((old ^ m_gpio_regs.output_latch) & m_gpio_regs.gpdr) & ~m_gpio_regs.gafr;
+ if (changed)
+ gpio_update_outputs(old, changed);
+}
+
+u32 sa1110_periphs_device::gpio_grer_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.grer;
+ LOGMASKED(LOG_GPIO, "%s: gpio_grer_r: GPIO Rising-Edge Detect Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_grer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_grer_w: GPIO Rising-Edge Detect Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_gpio_regs.grer);
+ m_gpio_regs.any_edge_mask = m_gpio_regs.grer | m_gpio_regs.gfer;
+}
+
+u32 sa1110_periphs_device::gpio_gfer_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gfer;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gfer_r: GPIO Falling-Edge Detect Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_gfer_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gfer_w: GPIO Falling-Edge Detect Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_gpio_regs.gfer);
+ m_gpio_regs.any_edge_mask = m_gpio_regs.grer | m_gpio_regs.gfer;
+}
+
+u32 sa1110_periphs_device::gpio_gedr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gedr;
+ if (data != 0)
+ LOGMASKED(LOG_GPIO, "%s: gpio_gedr_r: GPIO Edge Detect Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_gedr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gedr_w: GPIO Edge Detect Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_gpio_regs.gedr;
+ m_gpio_regs.gedr &= ~(data & mem_mask);
+ if (old != m_gpio_regs.gedr)
+ gpio_update_interrupts(old ^ m_gpio_regs.gedr);
+}
+
+u32 sa1110_periphs_device::gpio_gafr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_gpio_regs.gafr;
+ LOGMASKED(LOG_GPIO, "%s: gpio_gafr_r: GPIO Alternate Function Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::gpio_gafr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: gpio_gafr_w: GPIO Alternate Function Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_gpio_regs.gafr;
+ COMBINE_DATA(&m_gpio_regs.gafr);
+ if (old != m_gpio_regs.gafr)
+ gpio_update_alternate_pins(old ^ m_gpio_regs.gafr);
+}
+
+
+/*
+
+ Intel SA-1110 Interrupt Controller
+
+ pg. 81 to 88 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+void sa1110_periphs_device::set_irq_line(u32 line, int irq_state)
+{
+ if (irq_state == 1 && line != INT_OSTIMER0)
+ {
+ static const char *const INT_NAMES[32] =
+ {
+ "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10", "GPIOHI",
+ "LCD", "UDC", "reserved", "UART1", "UART2", "UART3", "MCP", "SSP", "DMA0", "DMA1", "DMA2", "DMA3", "DMA4", "DMA5",
+ "OSTIMER0", "OSTIMER1", "OSTIMER2", "OSTIMER3", "RTC_TICK", "RTC_ALARM"
+ };
+ LOGMASKED(LOG_INTC, "Setting interrupt line %s\n", INT_NAMES[line]);
+ }
+ const u32 line_mask = (1 << line);
+ const u32 old_status = m_intc_regs.icpr;
+ m_intc_regs.icpr &= ~line_mask;
+ m_intc_regs.icpr |= irq_state ? line_mask : 0;
+
+ if (m_intc_regs.icpr == old_status)
+ return;
+
+ update_interrupts();
+}
+
+void sa1110_periphs_device::update_interrupts()
+{
+ const u32 old_fiq = m_intc_regs.icfp;
+ m_intc_regs.icfp = (m_intc_regs.icpr & m_intc_regs.icmr) & m_intc_regs.iclr;
+ if (old_fiq != m_intc_regs.icfp)
+ {
+ m_maincpu->set_input_line(ARM7_FIRQ_LINE, m_intc_regs.icfp ? ASSERT_LINE : CLEAR_LINE);
+ }
+
+ const u32 old_irq = m_intc_regs.icip;
+ m_intc_regs.icip = (m_intc_regs.icpr & m_intc_regs.icmr) & (~m_intc_regs.iclr);
+ if (old_irq != m_intc_regs.icip)
+ {
+ m_maincpu->set_input_line(ARM7_IRQ_LINE, m_intc_regs.icip ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+u32 sa1110_periphs_device::intc_icip_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.icip;
+ if (data && data != 0x04000000)
+ {
+ LOGMASKED(LOG_INTC, "%s: intc_icip_r: Interrupt Controller IRQ Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ }
+ return data;
+}
+
+void sa1110_periphs_device::intc_icip_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_icip_w: (Invalid Write) Interrupt Controller IRQ Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::intc_icmr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.icmr;
+ LOGMASKED(LOG_INTC, "%s: intc_icmr_r: Interrupt Controller Mask Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::intc_icmr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_icmr_w: Interrupt Controller Mask Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_intc_regs.icmr;
+ COMBINE_DATA(&m_intc_regs.icmr);
+ if (old != m_intc_regs.icmr)
+ update_interrupts();
+}
+
+u32 sa1110_periphs_device::intc_iclr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.iclr;
+ LOGMASKED(LOG_INTC, "%s: intc_iclr_r: Interrupt Controller Level Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::intc_iclr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_iclr_w: Interrupt Controller Level Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ const u32 old = m_intc_regs.iclr;
+ COMBINE_DATA(&m_intc_regs.iclr);
+ if (old != m_intc_regs.iclr)
+ update_interrupts();
+}
+
+u32 sa1110_periphs_device::intc_icfp_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.icfp;
+ LOGMASKED(LOG_INTC, "%s: intc_icfp_r: Interrupt Controller FIQ Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::intc_icfp_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_icfp_w: (Invalid Write) Interrupt Controller FIQ Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::intc_icpr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.icpr;
+ LOGMASKED(LOG_INTC, "%s: intc_icpr_r: Interrupt Controller Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::intc_icpr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_icpr_w: (Invalid Write) Interrupt Controller Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 sa1110_periphs_device::intc_iccr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_intc_regs.iccr;
+ LOGMASKED(LOG_INTC, "%s: intc_iccr_r: Interrupt Controller Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::intc_iccr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_iccr_w: Interrupt Controller Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_intc_regs.iccr = BIT(data, 0);
+}
+
+
+/*
+
+ Intel SA-1110 Peripheral Pin Controller
+
+ pg. 347 to 357 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+u32 sa1110_periphs_device::ppc_ppdr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ppc_regs.ppdr;
+ LOGMASKED(LOG_PPC, "%s: ppc_ppdr_r: PPC Pin Direction Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::ppc_ppdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_PPC, "%s: ppc_ppdr_w: PPC Pin Direction Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ppc_regs.ppdr);
+ //const u32 old_ppsr = m_ppc_regs.ppsr;
+ m_ppc_regs.ppsr = (m_ppc_regs.ppsr_out & m_ppc_regs.ppdr) | (m_ppc_regs.ppsr_in & ~m_ppc_regs.ppdr);
+ //const u32 changed_states = old_ppsr ^ m_ppc_regs.ppsr;
+ //if (changed_states)
+ //{
+ //}
+}
+
+u32 sa1110_periphs_device::ppc_ppsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ppc_regs.ppsr;
+ LOGMASKED(LOG_PPC, "%s: ppc_ppsr_r: PPC Pin State Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ //machine().debug_break();
+ return data;
}
-void sa1110_periphs_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void sa1110_periphs_device::ppc_ppsr_w(offs_t offset, u32 data, u32 mem_mask)
{
+ LOGMASKED(LOG_PPC, "%s: ppc_ppsr_w: PPC Pin State Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ //const u32 old_latch = m_ppc_regs.ppsr_out;
+ COMBINE_DATA(&m_ppc_regs.ppsr_out);
+ m_ppc_regs.ppsr = (m_ppc_regs.ppsr_out & m_ppc_regs.ppdr) | (m_ppc_regs.ppsr_in & ~m_ppc_regs.ppdr);
+ //const u32 changed_outputs = (old ^ m_ppc_regs.ppsr_out) & m_ppc_regs.ppdr;
+ //if (changed_outputs)
+ //{
+ // Do stuff
+ //}
+}
+
+u32 sa1110_periphs_device::ppc_ppar_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ppc_regs.ppar;
+ LOGMASKED(LOG_PPC, "%s: ppc_ppar_r: PPC Pin Assignment Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::ppc_ppar_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_PPC, "%s: ppc_ppar_w: PPC Pin Assignment Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ppc_regs.ppar);
+}
+
+u32 sa1110_periphs_device::ppc_psdr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ppc_regs.psdr;
+ LOGMASKED(LOG_PPC, "%s: ppc_psdr_r: PPC Sleep Mode Direction Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::ppc_psdr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_PPC, "%s: ppc_psdr_w: PPC Sleep Mode Direction Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ppc_regs.psdr);
+}
+
+u32 sa1110_periphs_device::ppc_ppfr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_ppc_regs.ppfr;
+ LOGMASKED(LOG_PPC, "%s: ppc_ppfr_r: PPC Pin Flag Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1110_periphs_device::ppc_ppfr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_PPC, "%s: ppc_ppfr_w: PPC Pin Flag Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ppc_regs.ppfr);
+}
+
+
+/*
+
+ Intel SA-1110 Peripheral Pin Controller
+
+ pg. 186 to 194 Intel StrongARM SA-1110 Microprocessor Developer's Manual
+
+*/
+
+void sa1110_periphs_device::dma_set_control_bits(int channel, u32 bits)
+{
+ dma_regs &regs = m_dma_regs[channel];
+ const u32 old = regs.dsr;
+ regs.dsr |= bits;
+ const u32 newly_set = ~old & bits;
+ if (newly_set == 0)
+ return;
+
+ const u32 irq_mask = (1 << DSR_ERROR_BIT) | (1 << DSR_DONEA_BIT) | (1 << DSR_DONEB_BIT);
+
+ if (BIT(newly_set, DSR_RUN_BIT))
+ regs.dsr &= ~(1 << DSR_ERROR_BIT);
+ if (BIT(newly_set, DSR_DONEA_BIT) || BIT(newly_set, DSR_STRTA_BIT))
+ regs.dsr &= ~(1 << DSR_DONEA_BIT);
+ if (BIT(newly_set, DSR_DONEB_BIT) || BIT(newly_set, DSR_STRTB_BIT))
+ regs.dsr &= ~(1 << DSR_DONEB_BIT);
+
+ if (BIT(regs.dsr, DSR_RUN_BIT))
+ {
+ const u32 buf = BIT(regs.dsr, DSR_BIU_BIT);
+ const u32 start_mask = (buf ? (1 << DSR_STRTB_BIT) : (1 << DSR_STRTA_BIT));
+ const u32 done_mask = (buf ? (1 << DSR_DONEB_BIT) : (1 << DSR_DONEA_BIT));
+ if (regs.dsr & start_mask)
+ {
+ const u32 count = regs.dbt[buf];
+ if (count && regs.ddar == 0x81400580)
+ {
+ const u32 addr = regs.dbs[buf];
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ for (u32 i = 0; i < count; i++)
+ {
+ const u8 value = space.read_byte(addr + i);
+ if (value == 0x0d || value == 0x0a || (value >= 0x20 && value < 0x7f))
+ {
+ osd_printf_debug("%c", (char)value);
+ }
+ }
+ osd_printf_debug("\n");
+ set_irq_line(INT_DMA0 + channel, (BIT(regs.dsr, DSR_IE_BIT) && (regs.dsr & irq_mask)) ? 1 : 0);
+ }
+ regs.dsr &= ~(1 << DSR_RUN_BIT);
+ regs.dsr &= ~start_mask;
+ regs.dsr |= done_mask;
+ regs.dsr ^= (1 << DSR_BIU_BIT);
+ }
+ }
+ //set_irq_line(INT_DMA0 + channel, (BIT(regs.dsr, DSR_IE_BIT) && (regs.dsr & irq_mask)) ? 1 : 0);
+}
+
+void sa1110_periphs_device::dma_clear_control_bits(int channel, u32 bits)
+{
+ dma_regs &regs = m_dma_regs[channel];
+
+ const u32 irq_mask = (1 << DSR_ERROR_BIT) | (1 << DSR_DONEA_BIT) | (1 << DSR_DONEB_BIT);
+
+ regs.dsr &= ~bits;
+ set_irq_line(INT_DMA0 + channel, (BIT(regs.dsr, DSR_IE_BIT) && (regs.dsr & irq_mask)) ? 1 : 0);
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_ddar_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].ddar;
+ LOGMASKED(LOG_DMA, "%s: dma_ddar_r: DMA%d Device Address Register: %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_ddar_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_ddar_w: DMA%d Device Address Register = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ COMBINE_DATA(&m_dma_regs[Channel].ddar);
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_dssr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].dsr;
+ LOGMASKED(LOG_DMA, "%s: dma_dssr_r: DMA%d Control/Status Register (DSSR): %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_dssr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dssr_w: DMA%d Control/Status Register (1S) = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ LOGMASKED(LOG_DMA, "%s: Run Set: %d\n", machine().describe_context(), BIT(data, DSR_RUN_BIT));
+ LOGMASKED(LOG_DMA, "%s: Interrupt Enable Set: %d\n", machine().describe_context(), BIT(data, DSR_IE_BIT));
+ LOGMASKED(LOG_DMA, "%s: Error Set: %d\n", machine().describe_context(), BIT(data, DSR_ERROR_BIT));
+ LOGMASKED(LOG_DMA, "%s: Done A Set: %d\n", machine().describe_context(), BIT(data, DSR_DONEA_BIT));
+ LOGMASKED(LOG_DMA, "%s: Start A Set: %d\n", machine().describe_context(), BIT(data, DSR_STRTA_BIT));
+ LOGMASKED(LOG_DMA, "%s: Done B Set: %d\n", machine().describe_context(), BIT(data, DSR_DONEB_BIT));
+ LOGMASKED(LOG_DMA, "%s: Start B Set: %d\n", machine().describe_context(), BIT(data, DSR_STRTB_BIT));
+ LOGMASKED(LOG_DMA, "%s: Buffer In Use Set: %d\n", machine().describe_context(), BIT(data, DSR_BIU_BIT));
+ dma_set_control_bits(Channel, data & mem_mask);
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_dcsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].dsr;
+ LOGMASKED(LOG_DMA, "%s: dma_dcsr_r: DMA%d Control/Status Register (DCSR): %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_dcsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dcsr_w: DMA%d Control/Status Register (1C) = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ LOGMASKED(LOG_DMA, "%s: Run Clear: %d\n", machine().describe_context(), BIT(data, DSR_RUN_BIT));
+ LOGMASKED(LOG_DMA, "%s: Interrupt Enable Clear: %d\n", machine().describe_context(), BIT(data, DSR_IE_BIT));
+ LOGMASKED(LOG_DMA, "%s: Error Clear: %d\n", machine().describe_context(), BIT(data, DSR_ERROR_BIT));
+ LOGMASKED(LOG_DMA, "%s: Done A Clear: %d\n", machine().describe_context(), BIT(data, DSR_DONEA_BIT));
+ LOGMASKED(LOG_DMA, "%s: Start A Clear: %d\n", machine().describe_context(), BIT(data, DSR_STRTA_BIT));
+ LOGMASKED(LOG_DMA, "%s: Done B Clear: %d\n", machine().describe_context(), BIT(data, DSR_DONEB_BIT));
+ LOGMASKED(LOG_DMA, "%s: Start B Clear: %d\n", machine().describe_context(), BIT(data, DSR_STRTB_BIT));
+ LOGMASKED(LOG_DMA, "%s: Buffer In Use Clear: %d\n", machine().describe_context(), BIT(data, DSR_BIU_BIT));
+ dma_clear_control_bits(Channel, data & mem_mask);
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_dsr_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].dsr;
+ LOGMASKED(LOG_DMA, "%s: dma_dsr_r: DMA%d Control/Status Register (DSR): %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_dsr_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dsr_w: DMA%d Control/Status Register (Read-Only, Ignored) = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_dbsa_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].dbs[0];
+ LOGMASKED(LOG_DMA, "%s: dma_dbsa_r: DMA%d Buffer A Start Address: %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_dbsa_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dbsa_w: DMA%d Buffer A Start Address = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ if (!BIT(m_dma_regs[Channel].dsr, DSR_STRTA_BIT))
+ COMBINE_DATA(&m_dma_regs[Channel].dbs[0]);
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_dbta_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].dbt[0];
+ LOGMASKED(LOG_DMA, "%s: dma_dbta_r: DMA%d Buffer A Transfer Count: %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_dbta_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dbta_w: DMA%d Buffer A Transfer Count = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ if (!BIT(m_dma_regs[Channel].dsr, DSR_STRTA_BIT))
+ {
+ COMBINE_DATA(&m_dma_regs[Channel].dbt[0]);
+ m_dma_regs[Channel].dbt[0] &= DBT_MASK;
+ }
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_dbsb_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].dbs[1];
+ LOGMASKED(LOG_DMA, "%s: dma_dbsb_r: DMA%d Buffer B Start Address: %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_dbsb_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dbsb_w: DMA%d Buffer B Start Address = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ if (!BIT(m_dma_regs[Channel].dsr, DSR_STRTB_BIT))
+ COMBINE_DATA(&m_dma_regs[Channel].dbs[1]);
+}
+
+template <int Channel>
+u32 sa1110_periphs_device::dma_dbtb_r(offs_t offset, u32 mem_mask)
+{
+ const u32 data = m_dma_regs[Channel].dbt[1];
+ LOGMASKED(LOG_DMA, "%s: dma_dbtb_r: DMA%d Buffer B Transfer Count: %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ return data;
+}
+
+template <int Channel>
+void sa1110_periphs_device::dma_dbtb_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ LOGMASKED(LOG_DMA, "%s: dma_dbtb_w: DMA%d Buffer B Transfer Count = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ if (!BIT(m_dma_regs[Channel].dsr, DSR_STRTB_BIT))
+ {
+ COMBINE_DATA(&m_dma_regs[Channel].dbt[1]);
+ m_dma_regs[Channel].dbt[1] &= DBT_MASK;
+ }
+}
+
+void sa1110_periphs_device::device_start()
+{
+ save_item(NAME(m_udc_regs.udccr));
+ save_item(NAME(m_udc_regs.udcar));
+ save_item(NAME(m_udc_regs.udcomp));
+ save_item(NAME(m_udc_regs.udcimp));
+ save_item(NAME(m_udc_regs.udccs0));
+ save_item(NAME(m_udc_regs.udccs1));
+ save_item(NAME(m_udc_regs.udccs2));
+ save_item(NAME(m_udc_regs.udcwc));
+ save_item(NAME(m_udc_regs.udcsr));
+
+ save_item(NAME(m_icp_regs.uart.utcr));
+ save_item(NAME(m_icp_regs.uart.utsr0));
+ save_item(NAME(m_icp_regs.uart.utsr1));
+ save_item(NAME(m_icp_regs.uart.rx_fifo));
+ save_item(NAME(m_icp_regs.uart.rx_fifo_read_idx));
+ save_item(NAME(m_icp_regs.uart.rx_fifo_write_idx));
+ save_item(NAME(m_icp_regs.uart.rx_fifo_count));
+ m_icp_regs.uart_rx_timer = timer_alloc(FUNC(sa1110_periphs_device::icp_rx_callback), this);
+ save_item(NAME(m_icp_regs.uart.tx_fifo));
+ save_item(NAME(m_icp_regs.uart.tx_fifo_read_idx));
+ save_item(NAME(m_icp_regs.uart.tx_fifo_write_idx));
+ save_item(NAME(m_icp_regs.uart.tx_fifo_count));
+ m_icp_regs.uart_tx_timer = timer_alloc(FUNC(sa1110_periphs_device::icp_tx_callback), this);
+ save_item(NAME(m_icp_regs.uart.rx_break_interlock));
+
+ save_item(NAME(m_icp_regs.utcr4));
+ save_item(NAME(m_icp_regs.hssp.hscr0));
+ save_item(NAME(m_icp_regs.hssp.hscr1));
+ save_item(NAME(m_icp_regs.hssp.hssr0));
+ save_item(NAME(m_icp_regs.hssp.hssr1));
+ save_item(NAME(m_icp_regs.hssp.rx_fifo));
+ save_item(NAME(m_icp_regs.hssp.rx_fifo_read_idx));
+ save_item(NAME(m_icp_regs.hssp.rx_fifo_write_idx));
+ save_item(NAME(m_icp_regs.hssp.rx_fifo_count));
+ m_icp_regs.hssp.rx_timer = timer_alloc(FUNC(sa1110_periphs_device::hssp_rx_callback), this);
+ save_item(NAME(m_icp_regs.hssp.tx_fifo));
+ save_item(NAME(m_icp_regs.hssp.tx_fifo_read_idx));
+ save_item(NAME(m_icp_regs.hssp.tx_fifo_write_idx));
+ save_item(NAME(m_icp_regs.hssp.tx_fifo_count));
+ m_icp_regs.hssp.tx_timer = timer_alloc(FUNC(sa1110_periphs_device::hssp_tx_callback), this);
+
+ save_item(NAME(m_uart_regs.utcr));
+ save_item(NAME(m_uart_regs.utsr0));
+ save_item(NAME(m_uart_regs.utsr1));
+ save_item(NAME(m_uart_regs.rx_fifo));
+ save_item(NAME(m_uart_regs.rx_fifo_read_idx));
+ save_item(NAME(m_uart_regs.rx_fifo_write_idx));
+ save_item(NAME(m_uart_regs.rx_fifo_count));
+ save_item(NAME(m_uart_regs.tx_fifo));
+ save_item(NAME(m_uart_regs.tx_fifo_read_idx));
+ save_item(NAME(m_uart_regs.tx_fifo_write_idx));
+ save_item(NAME(m_uart_regs.tx_fifo_count));
+ save_item(NAME(m_uart_regs.rx_break_interlock));
+
+ save_item(NAME(m_mcp_regs.mccr0));
+ save_item(NAME(m_mcp_regs.mccr1));
+ save_item(NAME(m_mcp_regs.mcdr2));
+ save_item(NAME(m_mcp_regs.mcsr));
+ save_item(NAME(m_mcp_regs.audio_rx_fifo));
+ save_item(NAME(m_mcp_regs.audio_rx_fifo_read_idx));
+ save_item(NAME(m_mcp_regs.audio_rx_fifo_write_idx));
+ save_item(NAME(m_mcp_regs.audio_rx_fifo_count));
+ save_item(NAME(m_mcp_regs.audio_tx_fifo));
+ save_item(NAME(m_mcp_regs.audio_tx_fifo_read_idx));
+ save_item(NAME(m_mcp_regs.audio_tx_fifo_write_idx));
+ save_item(NAME(m_mcp_regs.audio_tx_fifo_count));
+ m_mcp_regs.audio_tx_timer = timer_alloc(FUNC(sa1110_periphs_device::mcp_audio_tx_callback), this);
+ save_item(NAME(m_mcp_regs.telecom_rx_fifo));
+ save_item(NAME(m_mcp_regs.telecom_rx_fifo_read_idx));
+ save_item(NAME(m_mcp_regs.telecom_rx_fifo_write_idx));
+ save_item(NAME(m_mcp_regs.telecom_rx_fifo_count));
+ save_item(NAME(m_mcp_regs.telecom_tx_fifo));
+ save_item(NAME(m_mcp_regs.telecom_tx_fifo_read_idx));
+ save_item(NAME(m_mcp_regs.telecom_tx_fifo_write_idx));
+ save_item(NAME(m_mcp_regs.telecom_tx_fifo_count));
+ m_mcp_regs.telecom_tx_timer = timer_alloc(FUNC(sa1110_periphs_device::mcp_telecom_tx_callback), this);
+
+ save_item(NAME(m_ssp_regs.sscr0));
+ save_item(NAME(m_ssp_regs.sscr1));
+ save_item(NAME(m_ssp_regs.sssr));
+ save_item(NAME(m_ssp_regs.rx_fifo));
+ save_item(NAME(m_ssp_regs.rx_fifo_read_idx));
+ save_item(NAME(m_ssp_regs.rx_fifo_write_idx));
+ save_item(NAME(m_ssp_regs.rx_fifo_count));
+ m_ssp_regs.rx_timer = timer_alloc(FUNC(sa1110_periphs_device::ssp_rx_callback), this);
+ save_item(NAME(m_ssp_regs.tx_fifo));
+ save_item(NAME(m_ssp_regs.tx_fifo_read_idx));
+ save_item(NAME(m_ssp_regs.tx_fifo_write_idx));
+ save_item(NAME(m_ssp_regs.tx_fifo_count));
+ m_ssp_regs.tx_timer = timer_alloc(FUNC(sa1110_periphs_device::ssp_tx_callback), this);
+
+ save_item(NAME(m_ostmr_regs.osmr));
+ save_item(NAME(m_ostmr_regs.oscr));
+ save_item(NAME(m_ostmr_regs.ossr));
+ save_item(NAME(m_ostmr_regs.ower));
+ save_item(NAME(m_ostmr_regs.oier));
+ for (int i = 0; i < 4; i++)
+ {
+ m_ostmr_regs.timer[i] = timer_alloc(FUNC(sa1110_periphs_device::ostimer_tick_cb), this);
+ }
+
+ save_item(NAME(m_rtc_regs.rtar));
+ save_item(NAME(m_rtc_regs.rcnr));
+ save_item(NAME(m_rtc_regs.rttr));
+ save_item(NAME(m_rtc_regs.rtsr));
+ m_rtc_regs.tick_timer = timer_alloc(FUNC(sa1110_periphs_device::rtc_tick_cb), this);
+
+ save_item(NAME(m_power_regs.pmcr));
+ save_item(NAME(m_power_regs.pssr));
+ save_item(NAME(m_power_regs.pspr));
+ save_item(NAME(m_power_regs.pwer));
+ save_item(NAME(m_power_regs.pcfr));
+ save_item(NAME(m_power_regs.ppcr));
+ save_item(NAME(m_power_regs.pgsr));
+ save_item(NAME(m_power_regs.posr));
+
+ save_item(NAME(m_rcsr));
+
+ save_item(NAME(m_gpio_regs.gplr));
+ save_item(NAME(m_gpio_regs.gpdr));
+ save_item(NAME(m_gpio_regs.grer));
+ save_item(NAME(m_gpio_regs.gfer));
+ save_item(NAME(m_gpio_regs.gedr));
+ save_item(NAME(m_gpio_regs.gafr));
+ save_item(NAME(m_gpio_regs.any_edge_mask));
+ save_item(NAME(m_gpio_regs.output_latch));
+ save_item(NAME(m_gpio_regs.input_latch));
+ save_item(NAME(m_gpio_regs.alt_output_latch));
+ save_item(NAME(m_gpio_regs.alt_input_latch));
+
+ save_item(NAME(m_intc_regs.icip));
+ save_item(NAME(m_intc_regs.icmr));
+ save_item(NAME(m_intc_regs.iclr));
+ save_item(NAME(m_intc_regs.iccr));
+ save_item(NAME(m_intc_regs.icfp));
+ save_item(NAME(m_intc_regs.icpr));
+
+ save_item(NAME(m_ppc_regs.ppdr));
+ save_item(NAME(m_ppc_regs.ppsr));
+ save_item(NAME(m_ppc_regs.ppar));
+ save_item(NAME(m_ppc_regs.psdr));
+ save_item(NAME(m_ppc_regs.ppfr));
+
+ save_item(STRUCT_MEMBER(m_dma_regs, ddar));
+ save_item(STRUCT_MEMBER(m_dma_regs, dsr));
+ save_item(STRUCT_MEMBER(m_dma_regs, dbs));
+ save_item(STRUCT_MEMBER(m_dma_regs, dbt));
+ save_item(NAME(m_dma_active_mask));
+}
+
+void sa1110_periphs_device::device_reset()
+{
+ m_udc_regs.udccr = (1 << UDCCR_SUSM_BIT) | (1 << UDCCR_UDD_BIT);
+ m_udc_regs.udcar = 0;
+ m_udc_regs.udcomp = 8;
+ m_udc_regs.udcimp = 8;
+ m_udc_regs.udccs0 = 0;
+ m_udc_regs.udccs1 = 0;
+ m_udc_regs.udccs2 = 0;
+ m_udc_regs.udcwc = 0;
+ m_udc_regs.udcsr = 0;
+
+ // init ICP
+ std::fill_n(&m_icp_regs.uart.utcr[0], 4, 0);
+ m_icp_regs.uart.utsr0 = 0;
+ m_icp_regs.uart.utsr1 = 0;
+ std::fill_n(&m_icp_regs.uart.rx_fifo[0], 12, 0);
+ m_icp_regs.uart.rx_fifo_read_idx = 0;
+ m_icp_regs.uart.rx_fifo_write_idx = 0;
+ m_icp_regs.uart.rx_fifo_count = 0;
+ m_icp_regs.uart_rx_timer->adjust(attotime::never);
+ std::fill_n(&m_icp_regs.uart.tx_fifo[0], 8, 0);
+ m_icp_regs.uart.tx_fifo_read_idx = 0;
+ m_icp_regs.uart.tx_fifo_write_idx = 0;
+ m_icp_regs.uart.tx_fifo_count = 0;
+ m_icp_regs.uart_tx_timer->adjust(attotime::never);
+ m_icp_regs.uart.rx_break_interlock = false;
+
+ m_icp_regs.utcr4 = 0;
+ m_icp_regs.hssp.hscr0 = 0;
+ m_icp_regs.hssp.hscr1 = 0;
+ m_icp_regs.hssp.hssr0 = 0;
+ m_icp_regs.hssp.hssr1 = 0;
+ std::fill_n(&m_icp_regs.hssp.rx_fifo[0], 4, 0);
+ m_icp_regs.hssp.rx_fifo_read_idx = 0;
+ m_icp_regs.hssp.rx_fifo_write_idx = 0;
+ m_icp_regs.hssp.rx_fifo_count = 0;
+ m_icp_regs.hssp.rx_timer->adjust(attotime::never);
+ std::fill_n(&m_icp_regs.hssp.tx_fifo[0], 12, 0);
+ m_icp_regs.hssp.tx_fifo_read_idx = 0;
+ m_icp_regs.hssp.tx_fifo_write_idx = 0;
+ m_icp_regs.hssp.tx_fifo_count = 0;
+ m_icp_regs.hssp.tx_timer->adjust(attotime::never);
+
+ // init UART3
+ std::fill_n(&m_uart_regs.utcr[0], 4, 0);
+ m_uart_regs.utsr0 = 0;
+ m_uart_regs.utsr1 = 0;
+ std::fill_n(&m_uart_regs.rx_fifo[0], 12, 0);
+ m_uart_regs.rx_fifo_read_idx = 0;
+ m_uart_regs.rx_fifo_write_idx = 0;
+ m_uart_regs.rx_fifo_count = 0;
+ std::fill_n(&m_uart_regs.tx_fifo[0], 8, 0);
+ m_uart_regs.tx_fifo_read_idx = 0;
+ m_uart_regs.tx_fifo_write_idx = 0;
+ m_uart_regs.tx_fifo_count = 0;
+ m_uart_regs.rx_break_interlock = false;
+
+ transmit_register_reset();
+ receive_register_reset();
+
+ // init MCP regs
+ m_mcp_regs.mccr0 = 0;
+ m_mcp_regs.mccr1 = 0;
+ m_mcp_regs.mcdr2 = 0;
+ m_mcp_regs.mcsr = (1 << MCSR_ANF_BIT) | (1 << MCSR_TNF_BIT);
+ std::fill(std::begin(m_mcp_regs.audio_rx_fifo), std::end(m_mcp_regs.audio_rx_fifo), 0);
+ m_mcp_regs.audio_rx_fifo_read_idx = 0;
+ m_mcp_regs.audio_rx_fifo_write_idx = 0;
+ m_mcp_regs.audio_rx_fifo_count = 0;
+ std::fill(std::begin(m_mcp_regs.audio_tx_fifo), std::end(m_mcp_regs.audio_tx_fifo), 0);
+ m_mcp_regs.audio_tx_fifo_read_idx = 0;
+ m_mcp_regs.audio_tx_fifo_write_idx = 0;
+ m_mcp_regs.audio_tx_fifo_count = 0;
+ m_mcp_regs.audio_tx_timer->adjust(attotime::never);
+ std::fill(std::begin(m_mcp_regs.telecom_rx_fifo), std::end(m_mcp_regs.telecom_rx_fifo), 0);
+ m_mcp_regs.telecom_rx_fifo_read_idx = 0;
+ m_mcp_regs.telecom_rx_fifo_write_idx = 0;
+ m_mcp_regs.telecom_rx_fifo_count = 0;
+ std::fill(std::begin(m_mcp_regs.telecom_tx_fifo), std::end(m_mcp_regs.telecom_tx_fifo), 0);
+ m_mcp_regs.telecom_tx_fifo_read_idx = 0;
+ m_mcp_regs.telecom_tx_fifo_write_idx = 0;
+ m_mcp_regs.telecom_tx_fifo_count = 0;
+ m_mcp_regs.telecom_tx_timer->adjust(attotime::never);
+
+ // init SSP regs
+ m_ssp_regs.sscr0 = 0;
+ m_ssp_regs.sscr1 = 0;
+ m_ssp_regs.sssr = (1 << SSSR_TNF_BIT);
+ std::fill(std::begin(m_ssp_regs.rx_fifo), std::end(m_ssp_regs.rx_fifo), 0);
+ m_ssp_regs.rx_fifo_read_idx = 0;
+ m_ssp_regs.rx_fifo_write_idx = 0;
+ m_ssp_regs.rx_fifo_count = 0;
+ m_ssp_regs.rx_timer->adjust(attotime::never);
+ std::fill(std::begin(m_ssp_regs.tx_fifo), std::end(m_ssp_regs.tx_fifo), 0);
+ m_ssp_regs.tx_fifo_read_idx = 0;
+ m_ssp_regs.tx_fifo_write_idx = 0;
+ m_ssp_regs.tx_fifo_count = 0;
+ m_ssp_regs.tx_timer->adjust(attotime::never);
+
+ // init OS timers
+ std::fill_n(&m_ostmr_regs.osmr[0], 4, 0);
+ m_ostmr_regs.ower = 0;
+ m_ostmr_regs.ossr = 0;
+ m_ostmr_regs.oier = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ m_ostmr_regs.timer[i]->adjust(attotime::never);
+ }
+ m_ostmr_regs.last_count_sync = attotime::zero;
+
+ // init RTC
+ m_rtc_regs.rtar = 0;
+ m_rtc_regs.rcnr = 0;
+ m_rtc_regs.rttr = 0;
+ m_rtc_regs.rtsr = 0;
+ m_rtc_regs.tick_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+
+ // init power regs
+ m_power_regs.pmcr = 0;
+ m_power_regs.pssr = 0;
+ m_power_regs.pspr = 0;
+ m_power_regs.pwer = 0;
+ m_power_regs.pcfr = 0;
+ m_power_regs.ppcr = 0;
+ m_power_regs.pgsr = 0;
+ m_power_regs.posr = 1; // flag oscillator OK
+
+ // init PPC regs
+ m_ppc_regs.ppdr = 0;
+ m_ppc_regs.ppsr = 0;
+ m_ppc_regs.ppar = 0;
+ m_ppc_regs.psdr = 0x003fffff;
+ m_ppc_regs.ppfr = 0x0007f001;
+
+ // init DMA regs
+ for (dma_regs &regs : m_dma_regs)
+ {
+ regs.ddar = 0;
+ regs.dsr = 0;
+ std::fill_n(&regs.dbs[0], 2, 0);
+ std::fill_n(&regs.dbt[0], 2, 0);
+ }
+
+ m_rcsr = 0x00000001; // indicate hardware reset
+
+ m_gpio_regs.gplr = 0;
+ m_gpio_regs.gpdr = 0;
+ m_gpio_regs.grer = 0;
+ m_gpio_regs.gfer = 0;
+ m_gpio_regs.gedr = 0;
+ m_gpio_regs.gafr = 0;
+ m_gpio_regs.any_edge_mask = 0;
+ m_gpio_regs.output_latch = 0;
+ m_gpio_regs.input_latch = 0;
+ m_gpio_regs.alt_output_latch = 0;
+ m_gpio_regs.alt_input_latch = 0;
+
+ m_intc_regs.icip = 0;
+ m_intc_regs.icmr = 0;
+ m_intc_regs.iclr = 0;
+ m_intc_regs.iccr = 0;
+ m_intc_regs.icfp = 0;
+ m_intc_regs.icpr = 0;
+
+ uart_check_rx_fifo_service();
+ uart_check_tx_fifo_service();
}
void sa1110_periphs_device::device_add_mconfig(machine_config &config)
{
+ INPUT_MERGER_ANY_HIGH(config, m_uart3_irqs).output_handler().set(FUNC(sa1110_periphs_device::uart3_irq_callback));
+ INPUT_MERGER_ANY_HIGH(config, m_mcp_irqs).output_handler().set(FUNC(sa1110_periphs_device::mcp_irq_callback));
}
diff --git a/src/devices/machine/sa1110.h b/src/devices/machine/sa1110.h
index 87ea94ffbf0..b39c4f28217 100644
--- a/src/devices/machine/sa1110.h
+++ b/src/devices/machine/sa1110.h
@@ -1,10 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
-/**************************************************************************
- *
- * Intel XScale SA1110 peripheral emulation
- *
- **************************************************************************/
+/***************************************************************************
+
+ Intel XScale SA1110 peripheral emulation
+
+***************************************************************************/
#ifndef MAME_MACHINE_SA1110
#define MAME_MACHINE_SA1110
@@ -13,44 +13,371 @@
#include "cpu/arm7/arm7.h"
#include "cpu/arm7/arm7core.h"
-#include "sound/dmadac.h"
-#include "emupal.h"
-class sa1110_periphs_device : public device_t
+#include "machine/input_merger.h"
+#include "machine/ucb1200.h"
+
+#include "diserial.h"
+
+class sa1110_periphs_device : public device_t, public device_serial_interface
{
public:
template <typename T>
- sa1110_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ sa1110_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&cpu_tag)
: sa1110_periphs_device(mconfig, tag, owner, clock)
{
m_maincpu.set_tag(std::forward<T>(cpu_tag));
}
- sa1110_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ sa1110_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ template <typename T> void set_codec_tag(T &&tag) { m_codec.set_tag(std::forward<T>(tag)); }
- uint32_t intc_r(offs_t offset, uint32_t mem_mask = ~0);
- void intc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
- uint32_t power_r(offs_t offset, uint32_t mem_mask = ~0);
- void power_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ // device_serial overrides
+ virtual void rcv_complete() override; // Rx completed receiving byte
+ virtual void tra_complete() override; // Tx completed sending byte
+ virtual void tra_callback() override; // Tx send bit
+
+ template <unsigned Line> void gpio_in(int state) { gpio_in(Line, state); }
+ template <unsigned Line> auto gpio_out() { return m_gpio_out[Line].bind(); }
+
+ void ssp_in(u16 data) { ssp_rx_fifo_push(data); }
+ auto ssp_out() { return m_ssp_out.bind(); }
+
+ auto uart3_tx_out() { return m_uart3_tx_out.bind(); }
+
+ void map(address_map &map);
protected:
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ static constexpr u32 INTERNAL_OSC = 3686400;
+
+ TIMER_CALLBACK_MEMBER(icp_rx_callback);
+ TIMER_CALLBACK_MEMBER(icp_tx_callback);
+ TIMER_CALLBACK_MEMBER(hssp_rx_callback);
+ TIMER_CALLBACK_MEMBER(hssp_tx_callback);
+ void icp_uart_set_receiver_enabled(bool enabled);
+ void icp_uart_set_transmitter_enabled(bool enabled);
+ void icp_uart_set_receive_irq_enabled(bool enabled);
+ void icp_uart_set_transmit_irq_enabled(bool enabled);
+ u8 icp_uart_read_receive_fifo();
+ void icp_uart_write_transmit_fifo(u8 data);
+ u16 icp_hssp_read_receive_fifo();
+ void icp_hssp_write_transmit_fifo(u8 data);
+ void icp_uart_set_receiver_idle();
+ void icp_uart_begin_of_break();
+ void icp_uart_end_of_break();
+
+ void uart3_irq_callback(int state);
+ void uart_recalculate_divisor();
+ void uart_update_eif_status();
+ void uart_write_receive_fifo(u16 data_and_flags);
+ u8 uart_read_receive_fifo();
+ void uart_write_transmit_fifo(u8 data);
+ void uart_check_rx_fifo_service();
+ void uart_check_tx_fifo_service();
+ void uart_set_receiver_idle();
+ void uart_begin_of_break();
+ void uart_end_of_break();
+ void uart_set_receiver_enabled(bool enabled);
+ void uart_set_transmitter_enabled(bool enabled);
+ void uart_set_receive_irq_enabled(bool enabled);
+ void uart_set_transmit_irq_enabled(bool enabled);
+
+ void mcp_irq_callback(int state);
+ TIMER_CALLBACK_MEMBER(mcp_audio_tx_callback);
+ TIMER_CALLBACK_MEMBER(mcp_telecom_tx_callback);
+ void mcp_update_sample_rate();
+ void mcp_set_enabled(bool enabled);
+ u16 mcp_read_audio_fifo();
+ u16 mcp_read_telecom_fifo();
+ attotime mcp_get_audio_frame_rate();
+ attotime mcp_get_telecom_frame_rate();
+ void mcp_audio_tx_fifo_push(const u16 value);
+ void mcp_telecom_tx_fifo_push(const u16 value);
+ void mcp_codec_read(offs_t offset);
+ void mcp_codec_write(offs_t offset, u16 data);
+
+ TIMER_CALLBACK_MEMBER(ssp_rx_callback);
+ TIMER_CALLBACK_MEMBER(ssp_tx_callback);
+ void ssp_update_enable_state();
+ void ssp_update_rx_level();
+ void ssp_update_tx_level();
+ void ssp_rx_fifo_push(const u16 data);
+ void ssp_tx_fifo_push(const u16 data);
+ u16 ssp_rx_fifo_pop();
+
+ TIMER_CALLBACK_MEMBER(ostimer_tick_cb);
+ void ostimer_update_count();
+ void ostimer_update_match_timer(int channel);
+
+ TIMER_CALLBACK_MEMBER(rtc_tick_cb);
+
+ void gpio_in(const u32 line, const int state);
+ void gpio_update_interrupts(const u32 changed_mask);
+ void gpio_update_direction(const u32 old_gpdr);
+ void gpio_update_outputs(const u32 old_latch, const u32 changed);
+ void gpio_update_alternate_pins(const u32 changed_mask);
+
+ void set_irq_line(u32 line, int state);
void update_interrupts();
- void set_irq_line(uint32_t line, int state);
+ void dma_set_control_bits(int channel, u32 bits);
+ void dma_clear_control_bits(int channel, u32 bits);
+
+ u32 udc_udccr_r(offs_t offset, u32 mem_mask);
+ void udc_udccr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udcar_r(offs_t offset, u32 mem_mask);
+ void udc_udcar_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udcomp_r(offs_t offset, u32 mem_mask);
+ void udc_udcomp_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udcimp_r(offs_t offset, u32 mem_mask);
+ void udc_udcimp_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udccs0_r(offs_t offset, u32 mem_mask);
+ void udc_udccs0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udccs1_r(offs_t offset, u32 mem_mask);
+ void udc_udccs1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udccs2_r(offs_t offset, u32 mem_mask);
+ void udc_udccs2_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udcd0_r(offs_t offset, u32 mem_mask);
+ void udc_udcd0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udcwc_r(offs_t offset, u32 mem_mask);
+ void udc_udcwc_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udcdr_r(offs_t offset, u32 mem_mask);
+ void udc_udcdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 udc_udcsr_r(offs_t offset, u32 mem_mask);
+ void udc_udcsr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 icp_utcr0_r(offs_t offset, u32 mem_mask);
+ void icp_utcr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_utcr1_r(offs_t offset, u32 mem_mask);
+ void icp_utcr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_utcr2_r(offs_t offset, u32 mem_mask);
+ void icp_utcr2_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_utcr3_r(offs_t offset, u32 mem_mask);
+ void icp_utcr3_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_utcr4_r(offs_t offset, u32 mem_mask);
+ void icp_utcr4_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_utdr_r(offs_t offset, u32 mem_mask);
+ void icp_utdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_utsr0_r(offs_t offset, u32 mem_mask);
+ void icp_utsr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_utsr1_r(offs_t offset, u32 mem_mask);
+ u32 icp_hscr0_r(offs_t offset, u32 mem_mask);
+ void icp_hscr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_hscr1_r(offs_t offset, u32 mem_mask);
+ void icp_hscr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_hsdr_r(offs_t offset, u32 mem_mask);
+ void icp_hsdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_hssr0_r(offs_t offset, u32 mem_mask);
+ void icp_hssr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 icp_hssr1_r(offs_t offset, u32 mem_mask);
+ void icp_hssr1_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 uart3_utcr0_r(offs_t offset, u32 mem_mask);
+ void uart3_utcr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 uart3_utcr1_r(offs_t offset, u32 mem_mask);
+ void uart3_utcr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 uart3_utcr2_r(offs_t offset, u32 mem_mask);
+ void uart3_utcr2_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 uart3_utcr3_r(offs_t offset, u32 mem_mask);
+ void uart3_utcr3_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 uart3_utdr_r(offs_t offset, u32 mem_mask);
+ void uart3_utdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 uart3_utsr0_r(offs_t offset, u32 mem_mask);
+ void uart3_utsr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 uart3_utsr1_r(offs_t offset, u32 mem_mask);
+
+ u32 mcp_mccr0_r(offs_t offset, u32 mem_mask);
+ void mcp_mccr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 mcp_mcdr0_r(offs_t offset, u32 mem_mask);
+ void mcp_mcdr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 mcp_mcdr1_r(offs_t offset, u32 mem_mask);
+ void mcp_mcdr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 mcp_mcdr2_r(offs_t offset, u32 mem_mask);
+ void mcp_mcdr2_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 mcp_mcsr_r(offs_t offset, u32 mem_mask);
+ void mcp_mcsr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 ssp_sscr0_r(offs_t offset, u32 mem_mask);
+ void ssp_sscr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 ssp_sscr1_r(offs_t offset, u32 mem_mask);
+ void ssp_sscr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 ssp_ssdr_r(offs_t offset, u32 mem_mask);
+ void ssp_ssdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 ssp_sssr_r(offs_t offset, u32 mem_mask);
+ void ssp_sssr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 tmr_osmr0_r(offs_t offset, u32 mem_mask);
+ void tmr_osmr0_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_osmr1_r(offs_t offset, u32 mem_mask);
+ void tmr_osmr1_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_osmr2_r(offs_t offset, u32 mem_mask);
+ void tmr_osmr2_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_osmr3_r(offs_t offset, u32 mem_mask);
+ void tmr_osmr3_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_oscr_r(offs_t offset, u32 mem_mask);
+ void tmr_oscr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_ossr_r(offs_t offset, u32 mem_mask);
+ void tmr_ossr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_ower_r(offs_t offset, u32 mem_mask);
+ void tmr_ower_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 tmr_oier_r(offs_t offset, u32 mem_mask);
+ void tmr_oier_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 rtc_rtar_r(offs_t offset, u32 mem_mask);
+ void rtc_rtar_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 rtc_rcnr_r(offs_t offset, u32 mem_mask);
+ void rtc_rcnr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 rtc_rttr_r(offs_t offset, u32 mem_mask);
+ void rtc_rttr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 rtc_rtsr_r(offs_t offset, u32 mem_mask);
+ void rtc_rtsr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 pwr_pmcr_r(offs_t offset, u32 mem_mask);
+ void pwr_pmcr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pssr_r(offs_t offset, u32 mem_mask);
+ void pwr_pssr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pspr_r(offs_t offset, u32 mem_mask);
+ void pwr_pspr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pwer_r(offs_t offset, u32 mem_mask);
+ void pwr_pwer_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pcfr_r(offs_t offset, u32 mem_mask);
+ void pwr_pcfr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_ppcr_r(offs_t offset, u32 mem_mask);
+ void pwr_ppcr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_pgsr_r(offs_t offset, u32 mem_mask);
+ void pwr_pgsr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 pwr_posr_r(offs_t offset, u32 mem_mask);
+ void pwr_posr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 rst_rsrr_r(offs_t offset, u32 mem_mask);
+ void rst_rsrr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 rst_rcsr_r(offs_t offset, u32 mem_mask);
+ void rst_rcsr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 gpio_gplr_r(offs_t offset, u32 mem_mask);
+ void gpio_gplr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 gpio_gpdr_r(offs_t offset, u32 mem_mask);
+ void gpio_gpdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 gpio_gpsr_r(offs_t offset, u32 mem_mask);
+ void gpio_gpsr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 gpio_gpcr_r(offs_t offset, u32 mem_mask);
+ void gpio_gpcr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 gpio_grer_r(offs_t offset, u32 mem_mask);
+ void gpio_grer_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 gpio_gfer_r(offs_t offset, u32 mem_mask);
+ void gpio_gfer_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 gpio_gedr_r(offs_t offset, u32 mem_mask);
+ void gpio_gedr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 gpio_gafr_r(offs_t offset, u32 mem_mask);
+ void gpio_gafr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 intc_icip_r(offs_t offset, u32 mem_mask);
+ void intc_icip_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_icmr_r(offs_t offset, u32 mem_mask);
+ void intc_icmr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_iclr_r(offs_t offset, u32 mem_mask);
+ void intc_iclr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_icfp_r(offs_t offset, u32 mem_mask);
+ void intc_icfp_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_icpr_r(offs_t offset, u32 mem_mask);
+ void intc_icpr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 intc_iccr_r(offs_t offset, u32 mem_mask);
+ void intc_iccr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ u32 ppc_ppdr_r(offs_t offset, u32 mem_mask);
+ void ppc_ppdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 ppc_ppsr_r(offs_t offset, u32 mem_mask);
+ void ppc_ppsr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 ppc_ppar_r(offs_t offset, u32 mem_mask);
+ void ppc_ppar_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 ppc_psdr_r(offs_t offset, u32 mem_mask);
+ void ppc_psdr_w(offs_t offset, u32 data, u32 mem_mask);
+ u32 ppc_ppfr_r(offs_t offset, u32 mem_mask);
+ void ppc_ppfr_w(offs_t offset, u32 data, u32 mem_mask);
+
+ template <int Channel> u32 dma_ddar_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_ddar_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Channel> u32 dma_dssr_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_dssr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Channel> u32 dma_dcsr_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_dcsr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Channel> u32 dma_dsr_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_dsr_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Channel> u32 dma_dbsa_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_dbsa_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Channel> u32 dma_dbta_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_dbta_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Channel> u32 dma_dbsb_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_dbsb_w(offs_t offset, u32 data, u32 mem_mask);
+ template <int Channel> u32 dma_dbtb_r(offs_t offset, u32 mem_mask);
+ template <int Channel> void dma_dbtb_w(offs_t offset, u32 data, u32 mem_mask);
+
+ // register offsets
enum
{
- INTC_BASE_ADDR = 0x90050000,
- REG_ICIP = (0x00000000 >> 2),
- REG_ICMR = (0x00000004 >> 2),
- REG_ICLR = (0x00000008 >> 2),
- REG_ICCR = (0x0000000c >> 2),
- REG_ICFP = (0x00000010 >> 2),
- REG_ICPR = (0x00000020 >> 2),
+ UDC_BASE_ADDR = 0x80000000,
+ REG_UDCCR = (0x00000000 >> 2),
+ REG_UDCAR = (0x00000004 >> 2),
+ REG_UDCOMP = (0x00000008 >> 2),
+ REG_UDCIMP = (0x0000000c >> 2),
+ REG_UDCCS0 = (0x00000010 >> 2),
+ REG_UDCCS1 = (0x00000014 >> 2),
+ REG_UDCCS2 = (0x00000018 >> 2),
+ REG_UDCD0 = (0x0000001c >> 2),
+ REG_UDCWC = (0x00000020 >> 2),
+ REG_UDCDR = (0x00000028 >> 2),
+ REG_UDCSR = (0x00000030 >> 2),
+
+ ICP_BASE_ADDR = 0x80030000,
+ REG_UTCR4 = (0x00000010 >> 2),
+ REG_HSCR0 = (0x00000060 >> 2),
+ REG_HSCR1 = (0x00000064 >> 2),
+ REG_HSDR = (0x0000006c >> 2),
+ REG_HSSR0 = (0x00000074 >> 2),
+ REG_HSSR1 = (0x00000078 >> 2),
+
+ UART_BASE_ADDR = 0x80050000,
+ REG_UTCR0 = (0x00000000 >> 2),
+ REG_UTCR1 = (0x00000004 >> 2),
+ REG_UTCR2 = (0x00000008 >> 2),
+ REG_UTCR3 = (0x0000000c >> 2),
+ REG_UTDR = (0x00000014 >> 2),
+ REG_UTSR0 = (0x0000001c >> 2),
+ REG_UTSR1 = (0x00000020 >> 2),
+
+ MCP_BASE_ADDR = 0x80060000,
+ REG_MCCR0 = (0x00000000 >> 2),
+ REG_MCDR0 = (0x00000008 >> 2),
+ REG_MCDR1 = (0x0000000c >> 2),
+ REG_MCDR2 = (0x00000010 >> 2),
+ REG_MCSR = (0x00000018 >> 2),
+
+ SSP_BASE_ADDR = 0x80070000,
+ REG_SSCR0 = (0x00000060 >> 2),
+ REG_SSCR1 = (0x00000064 >> 2),
+ REG_SSDR = (0x0000006c >> 2),
+ REG_SSSR = (0x00000074 >> 2),
+
+ OSTMR_BASE_ADDR = 0x90000000,
+ REG_OSMR0 = (0x00000000 >> 2),
+ REG_OSMR1 = (0x00000004 >> 2),
+ REG_OSMR2 = (0x00000008 >> 2),
+ REG_OSMR3 = (0x0000000c >> 2),
+ REG_OSCR = (0x00000010 >> 2),
+ REG_OSSR = (0x00000014 >> 2),
+ REG_OWER = (0x00000018 >> 2),
+ REG_OIER = (0x0000001c >> 2),
+
+ RTC_BASE_ADDR = 0x90010000,
+ REG_RTAR = (0x00000000 >> 2),
+ REG_RCNR = (0x00000004 >> 2),
+ REG_RTTR = (0x00000008 >> 2),
+ REG_RTSR = (0x00000010 >> 2),
POWER_BASE_ADDR = 0x90020000,
REG_PMCR = (0x00000000 >> 2),
@@ -60,35 +387,521 @@ protected:
REG_PCFR = (0x00000010 >> 2),
REG_PPCR = (0x00000014 >> 2),
REG_PGSR = (0x00000018 >> 2),
- REG_POSR = (0x0000001c >> 2)
+ REG_POSR = (0x0000001c >> 2),
+
+ RESET_BASE_ADDR = 0x90030000,
+ REG_RSRR = (0x00000000 >> 2),
+ REG_RCSR = (0x00000004 >> 2),
+
+ GPIO_BASE_ADDR = 0x90040000,
+ REG_GPLR = (0x00000000 >> 2),
+ REG_GPDR = (0x00000004 >> 2),
+ REG_GPSR = (0x00000008 >> 2),
+ REG_GPCR = (0x0000000c >> 2),
+ REG_GRER = (0x00000010 >> 2),
+ REG_GFER = (0x00000014 >> 2),
+ REG_GEDR = (0x00000018 >> 2),
+ REG_GAFR = (0x0000001c >> 2),
+
+ INTC_BASE_ADDR = 0x90050000,
+ REG_ICIP = (0x00000000 >> 2),
+ REG_ICMR = (0x00000004 >> 2),
+ REG_ICLR = (0x00000008 >> 2),
+ REG_ICCR = (0x0000000c >> 2),
+ REG_ICFP = (0x00000010 >> 2),
+ REG_ICPR = (0x00000020 >> 2),
+
+ PPC_BASE_ADDR = 0x90060000,
+ REG_PPDR = (0x00000000 >> 2),
+ REG_PPSR = (0x00000004 >> 2),
+ REG_PPAR = (0x00000008 >> 2),
+ REG_PSDR = (0x0000000c >> 2),
+ REG_PPFR = (0x00000010 >> 2),
+
+ DMA_BASE_ADDR = 0xb0000000,
+ REG_DDAR = (0x00000000 >> 2),
+ REG_DSSR = (0x00000004 >> 2),
+ REG_DCSR = (0x00000008 >> 2),
+ REG_DSR = (0x0000000c >> 2),
+ REG_DBSA = (0x00000010 >> 2),
+ REG_DBTA = (0x00000014 >> 2),
+ REG_DBSB = (0x00000018 >> 2),
+ REG_DBTB = (0x0000001c >> 2)
};
- struct intc_regs
+ // register contents
+ enum : u32
{
- uint32_t icip;
- uint32_t icmr;
- uint32_t iclr;
- uint32_t iccr;
- uint32_t icfp;
- uint32_t icpr;
+ UDCCR_UDD_BIT = 0,
+ UDCCR_UDA_BIT = 1,
+ UDCCR_RESM_BIT = 2,
+ UDCCR_EIM_BIT = 3,
+ UDCCR_RIM_BIT = 4,
+ UDCCR_TIM_BIT = 5,
+ UDCCR_SUSM_BIT = 6,
+ UDCCR_WRITE_MASK = 0x7d,
+
+ UDCAR_WRITE_MASK = 0x7f,
+
+ UDCOMP_WRITE_MASK = 0xff,
+
+ UDCIMP_WRITE_MASK = 0xff,
+
+ UDCCS0_OPR_BIT = 0,
+ UDCCS0_IPR_BIT = 1,
+ UDCCS0_SST_BIT = 2,
+ UDCCS0_FST_BIT = 3,
+ UDCCS0_DE_BIT = 4,
+ UDCCS0_SE_BIT = 5,
+ UDCCS0_SO_BIT = 6,
+ UDCCS0_SSE_BIT = 7,
+
+ UDCCS1_RFS_BIT = 0,
+ UDCCS1_RPC_BIT = 1,
+ UDCCS1_RPE_BIT = 2,
+ UDCCS1_SST_BIT = 3,
+ UDCCS1_FST_BIT = 4,
+ UDCCS1_RNE_BIT = 5,
+
+ UDCCS2_TFS_BIT = 0,
+ UDCCS2_TPC_BIT = 1,
+ UDCCS2_TPE_BIT = 2,
+ UDCCS2_TUR_BIT = 3,
+ UDCCS2_SST_BIT = 4,
+ UDCCS2_FST_BIT = 5,
+
+ UDCWC_WRITE_MASK = 0x0f,
+
+ UDCSR_EIR_BIT = 0,
+ UDCSR_RIR_BIT = 1,
+ UDCSR_TIR_BIT = 2,
+ UDCSR_SUSIR_BIT = 3,
+ UDCSR_RESIR_BIT = 4,
+ UDCSR_RSTIR_BIT = 5,
+
+ UART3_FIFO_PRE = 8,
+ UART3_FIFO_FRE = 9,
+ UART3_FIFO_ROR = 10,
+
+ UTCR3_RXE_BIT = 0,
+ UTCR3_TXE_BIT = 1,
+ UTCR3_BRK_BIT = 2,
+ UTCR3_RIE_BIT = 3,
+ UTCR3_TIE_BIT = 4,
+ UTCR3_LBM_BIT = 5,
+
+ UTCR4_HSE_BIT = 0,
+ UTCR4_LPM_BIT = 1,
+
+ UTSR0_TFS_BIT = 0,
+ UTSR0_RFS_BIT = 1,
+ UTSR0_RID_BIT = 2,
+ UTSR0_RBB_BIT = 3,
+ UTSR0_REB_BIT = 4,
+ UTSR0_EIF_BIT = 5,
+
+ UTSR1_TBY_BIT = 0,
+ UTSR1_RNE_BIT = 1,
+ UTSR1_TNF_BIT = 2,
+ UTSR1_PRE_BIT = 3,
+ UTSR1_FRE_BIT = 4,
+ UTSR1_ROR_BIT = 5,
+
+ HSCR0_ITR_BIT = 0,
+ HSCR0_LBM_BIT = 1,
+ HSCR0_TUS_BIT = 2,
+ HSCR0_TXE_BIT = 3,
+ HSCR0_RXE_BIT = 4,
+ HSCR0_RIE_BIT = 5,
+ HSCR0_TIE_BIT = 6,
+ HSCR0_AME_BIT = 7,
+
+ HSCR2_TXP_BIT = 18,
+ HSCR2_RXP_BIT = 19,
+
+ HSDR_EOF_BIT = 8,
+ HSDR_CRE_BIT = 9,
+ HSDR_ROR_BIT = 10,
+
+ HSSR0_EIF_BIT = 0,
+ HSSR0_TUR_BIT = 1,
+ HSSR0_RAB_BIT = 2,
+ HSSR0_TFS_BIT = 3,
+ HSSR0_RFS_BIT = 4,
+ HSSR0_FRE_BIT = 5,
+
+ HSSR1_RSY_BIT = 0,
+ HSSR1_TBY_BIT = 1,
+ HSSR1_RNE_BIT = 2,
+ HSSR1_TNF_BIT = 3,
+ HSSR1_EOF_BIT = 4,
+ HSSR1_CRE_BIT = 5,
+ HSSR1_ROR_BIT = 6,
+
+ MCCR0_ASD_BIT = 0,
+ MCCR0_ASD_MASK = 0x0000007f,
+ MCCR0_TSD_BIT = 8,
+ MCCR0_TSD_MASK = 0x00007f00,
+ MCCR0_MCE_BIT = 16,
+ MCCR0_ECS_BIT = 17,
+ MCCR0_ADM_BIT = 18,
+ MCCR0_TTE_BIT = 19,
+ MCCR0_TRE_BIT = 20,
+ MCCR0_ATE_BIT = 21,
+ MCCR0_ARE_BIT = 22,
+ MCCR0_LBM_BIT = 23,
+ MCCR0_ECP_BIT = 24,
+ MCCR0_ECP_MASK = 0x03000000,
+
+ MCCR1_CFS_BIT = 20,
+
+ MCDR2_RW_BIT = 16,
+ MCDR2_ADDR_BIT = 17,
+ MCDR2_ADDR_MASK = 0x001e0000,
+
+ MCSR_ATS_BIT = 0,
+ MCSR_ARS_BIT = 1,
+ MCSR_TTS_BIT = 2,
+ MCSR_TRS_BIT = 3,
+ MCSR_ATU_BIT = 4,
+ MCSR_ARO_BIT = 5,
+ MCSR_TTU_BIT = 6,
+ MCSR_TRO_BIT = 7,
+ MCSR_ANF_BIT = 8,
+ MCSR_ANE_BIT = 9,
+ MCSR_TNF_BIT = 10,
+ MCSR_TNE_BIT = 11,
+ MCSR_CWC_BIT = 12,
+ MCSR_CRC_BIT = 13,
+ MCSR_ACE_BIT = 14,
+ MCSR_TCE_BIT = 15,
+
+ SSCR0_DSS_BIT = 0,
+ SSCR0_DSS_MASK = 0x0000000f,
+ SSCR0_FRF_BIT = 4,
+ SSCR0_FRF_MASK = 0x00000030,
+ SSCR0_SSE_BIT = 7,
+ SSCR0_SCR_BIT = 8,
+ SSCR0_SCR_MASK = 0x0000ff00,
+
+ SSCR1_RIE_BIT = 0,
+ SSCR1_TIE_BIT = 1,
+ SSCR1_LBM_BIT = 2,
+ SSCR1_SPO_BIT = 3,
+ SSCR1_SPH_BIT = 4,
+ SSCR1_ECS_BIT = 5,
+
+ SSSR_TNF_BIT = 1,
+ SSSR_RNE_BIT = 2,
+ SSSR_BSY_BIT = 3,
+ SSSR_TFS_BIT = 4,
+ SSSR_RFS_BIT = 5,
+ SSSR_ROR_BIT = 6,
+
+ RTSR_AL_BIT = 0,
+ RTSR_AL_MASK = (1 << RTSR_AL_BIT),
+ RTSR_HZ_BIT = 1,
+ RTSR_HZ_MASK = (1 << RTSR_HZ_BIT),
+ RTSR_ALE_BIT = 2,
+ RTSR_ALE_MASK = (1 << RTSR_ALE_BIT),
+ RTSR_HZE_BIT = 3,
+ RTSR_HZE_MASK = (1 << RTSR_HZE_BIT),
+
+ DDAR_RW_BIT = 0,
+ DDAR_E_BIT = 1,
+ DDAR_BS_BIT = 2,
+ DDAR_DW_BIT = 3,
+ DDAR_DA0_BIT = 4,
+ DDAR_DA0_MASK = 0x000000f0,
+ DDAR_DA8_BIT = 8,
+ DDAR_DA8_MASK = 0xffffff00,
+
+ DSR_RUN_BIT = 0,
+ DSR_IE_BIT = 1,
+ DSR_ERROR_BIT = 2,
+ DSR_DONEA_BIT = 3,
+ DSR_STRTA_BIT = 4,
+ DSR_DONEB_BIT = 5,
+ DSR_STRTB_BIT = 6,
+ DSR_BIU_BIT = 7,
+
+ DBT_MASK = 0x00001fff
+ };
+
+ // interrupt bits
+ enum : u32
+ {
+ INT_GPIO0 = 0,
+ INT_GPIO1 = 1,
+ INT_GPIO2 = 2,
+ INT_GPIO3 = 3,
+ INT_GPIO4 = 4,
+ INT_GPIO5 = 5,
+ INT_GPIO6 = 6,
+ INT_GPIO7 = 7,
+ INT_GPIO8 = 8,
+ INT_GPIO9 = 9,
+ INT_GPIO10 = 10,
+ INT_GPIOHI = 11,
+ INT_LCD = 12,
+ INT_UDC = 13,
+ INT_UART1 = 15,
+ INT_UART2 = 16,
+ INT_UART3 = 17,
+ INT_MCP = 18,
+ INT_SSP = 19,
+ INT_DMA0 = 20,
+ INT_DMA1 = 21,
+ INT_DMA2 = 22,
+ INT_DMA3 = 23,
+ INT_DMA4 = 24,
+ INT_DMA5 = 25,
+ INT_OSTIMER0 = 26,
+ INT_OSTIMER1 = 27,
+ INT_OSTIMER2 = 28,
+ INT_OSTIMER3 = 29,
+ INT_RTC_TICK = 30,
+ INT_RTC_ALARM = 31
+ };
+
+ // UART3 interrupt sources
+ enum : unsigned
+ {
+ UART3_TFS = 0,
+ UART3_RFS = 1,
+ UART3_RID = 2,
+ UART3_RBB = 3,
+ UART3_REB = 4,
+ UART3_EIF = 5,
+ };
+
+ // MCP interrupt sources
+ enum : unsigned
+ {
+ MCP_AUDIO_TX = 0,
+ MCP_AUDIO_RX = 1,
+ MCP_TELECOM_TX = 2,
+ MCP_TELECOM_RX = 3,
+ MCP_AUDIO_UNDERRUN = 4,
+ MCP_AUDIO_OVERRUN = 5,
+ MCP_TELECOM_UNDERRUN = 6,
+ MCP_TELECOM_OVERRUN = 7
+ };
+
+ struct udc_regs
+ {
+ u32 udccr;
+ u32 udcar;
+ u32 udcomp;
+ u32 udcimp;
+ u32 udccs0;
+ u32 udccs1;
+ u32 udccs2;
+ u32 udcwc;
+ u32 udcsr;
+ };
+
+ struct uart_regs
+ {
+ u32 utcr[4];
+ u32 utsr0;
+ u32 utsr1;
+
+ u16 rx_fifo[12];
+ int rx_fifo_read_idx;
+ int rx_fifo_write_idx;
+ int rx_fifo_count;
+
+ u8 tx_fifo[8];
+ int tx_fifo_read_idx;
+ int tx_fifo_write_idx;
+ int tx_fifo_count;
+
+ bool rx_break_interlock;
+ };
+
+ struct hssp_regs
+ {
+ u32 hscr0;
+ u32 hscr1;
+ u32 hssr0;
+ u32 hssr1;
+
+ u16 rx_fifo[8];
+ int rx_fifo_read_idx;
+ int rx_fifo_write_idx;
+ int rx_fifo_count;
+ emu_timer *rx_timer;
+
+ u16 tx_fifo[8];
+ int tx_fifo_read_idx;
+ int tx_fifo_write_idx;
+ int tx_fifo_count;
+ emu_timer *tx_timer;
+ };
+
+ struct icp_regs
+ {
+ uart_regs uart;
+ u32 utcr4;
+ emu_timer *uart_rx_timer;
+ emu_timer *uart_tx_timer;
+
+ hssp_regs hssp;
+ };
+
+ struct mcp_regs
+ {
+ u32 mccr0;
+ u32 mccr1;
+ u32 mcdr2;
+ u32 mcsr;
+
+ u16 audio_rx_fifo[8];
+ int audio_rx_fifo_read_idx;
+ int audio_rx_fifo_write_idx;
+ int audio_rx_fifo_count;
+
+ u16 audio_tx_fifo[8];
+ int audio_tx_fifo_read_idx;
+ int audio_tx_fifo_write_idx;
+ int audio_tx_fifo_count;
+ emu_timer *audio_tx_timer;
+
+ u16 telecom_rx_fifo[8];
+ int telecom_rx_fifo_read_idx;
+ int telecom_rx_fifo_write_idx;
+ int telecom_rx_fifo_count;
+
+ u16 telecom_tx_fifo[8];
+ int telecom_tx_fifo_read_idx;
+ int telecom_tx_fifo_write_idx;
+ int telecom_tx_fifo_count;
+ emu_timer *telecom_tx_timer;
+ };
+
+ struct ssp_regs
+ {
+ u32 sscr0;
+ u32 sscr1;
+ u32 sssr;
+
+ u16 rx_fifo[8];
+ int rx_fifo_read_idx;
+ int rx_fifo_write_idx;
+ int rx_fifo_count;
+ emu_timer *rx_timer;
+
+ u16 tx_fifo[8];
+ int tx_fifo_read_idx;
+ int tx_fifo_write_idx;
+ int tx_fifo_count;
+ emu_timer *tx_timer;
+ };
+
+ struct ostimer_regs
+ {
+ u32 osmr[4];
+ u32 oscr;
+ u32 ossr;
+ u32 ower;
+ u32 oier;
+
+ emu_timer *timer[4];
+ attotime last_count_sync;
+ };
+
+ struct rtc_regs
+ {
+ u32 rtar;
+ u32 rcnr;
+ u32 rttr;
+ u32 rtsr;
+
+ emu_timer *tick_timer;
};
struct power_regs
{
- uint32_t pmcr;
- uint32_t pssr;
- uint32_t pspr;
- uint32_t pwer;
- uint32_t pcfr;
- uint32_t ppcr;
- uint32_t pgsr;
- uint32_t posr;
+ u32 pmcr;
+ u32 pssr;
+ u32 pspr;
+ u32 pwer;
+ u32 pcfr;
+ u32 ppcr;
+ u32 pgsr;
+ u32 posr;
+ };
+
+ struct gpio_regs
+ {
+ u32 gplr;
+ u32 gpdr;
+ u32 grer;
+ u32 gfer;
+ u32 gedr;
+ u32 gafr;
+
+ u32 any_edge_mask;
+
+ u32 output_latch;
+ u32 input_latch;
+ u32 alt_output_latch;
+ u32 alt_input_latch;
+ };
+
+ struct intc_regs
+ {
+ u32 icip;
+ u32 icmr;
+ u32 iclr;
+ u32 iccr;
+ u32 icfp;
+ u32 icpr;
+ };
+
+ struct ppc_regs
+ {
+ u32 ppdr;
+ u32 ppsr_out;
+ u32 ppsr_in;
+ u32 ppsr;
+ u32 ppar;
+ u32 psdr;
+ u32 ppfr;
};
- intc_regs m_intc_regs;
- power_regs m_power_regs;
+ struct dma_regs
+ {
+ u32 ddar;
+ u32 dsr;
+ u32 dbs[2];
+ u32 dbt[2];
+ };
+
+ udc_regs m_udc_regs;
+ uart_regs m_uart_regs;
+ icp_regs m_icp_regs;
+ mcp_regs m_mcp_regs;
+ ssp_regs m_ssp_regs;
+ ostimer_regs m_ostmr_regs;
+ rtc_regs m_rtc_regs;
+ power_regs m_power_regs;
+ u32 m_rcsr;
+ gpio_regs m_gpio_regs;
+ intc_regs m_intc_regs;
+ ppc_regs m_ppc_regs;
+ dma_regs m_dma_regs[6];
+ u8 m_dma_active_mask;
+
+ required_device<sa1110_cpu_device> m_maincpu;
+ required_device<input_merger_device> m_uart3_irqs;
+ required_device<input_merger_device> m_mcp_irqs;
+ optional_device<ucb1200_device> m_codec;
- required_device<cpu_device> m_maincpu;
+ devcb_write_line::array<28> m_gpio_out;
+ devcb_write16 m_ssp_out;
+ devcb_write_line m_uart3_tx_out;
};
DECLARE_DEVICE_TYPE(SA1110_PERIPHERALS, sa1110_periphs_device)
diff --git a/src/devices/machine/sa1111.cpp b/src/devices/machine/sa1111.cpp
new file mode 100644
index 00000000000..cc33ccd6892
--- /dev/null
+++ b/src/devices/machine/sa1111.cpp
@@ -0,0 +1,2194 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Intel SA1111 Microprocessor Companion Chip skeleton
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sa1111.h"
+
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_SBI (1U << 2)
+#define LOG_SK (1U << 3)
+#define LOG_USB (1U << 4)
+#define LOG_AUDIO (1U << 5)
+#define LOG_SSP (1U << 6)
+#define LOG_SSP_HF (1U << 7)
+#define LOG_TRACK (1U << 8)
+#define LOG_MOUSE (1U << 9)
+#define LOG_GPIO (1U << 10)
+#define LOG_INTC (1U << 11)
+#define LOG_CARD (1U << 12)
+#define LOG_AUDIO_DMA (1U << 13)
+#define LOG_ALL (LOG_UNKNOWN | LOG_SBI | LOG_SK | LOG_USB | LOG_AUDIO | LOG_SSP | LOG_TRACK | LOG_MOUSE | LOG_GPIO | LOG_INTC | LOG_CARD)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SA1111, sa1111_device, "sa1111", "Intel SA1111 Microprocessor Companion Chip")
+
+sa1111_device::sa1111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SA1111, tag, owner, clock)
+ , m_maincpu(*this, finder_base::DUMMY_TAG)
+ , m_audio_codec(*this, finder_base::DUMMY_TAG)
+ , m_irq_out(*this)
+ , m_gpio_out(*this)
+ , m_ssp_out(*this)
+ , m_l3_addr_out(*this)
+ , m_l3_data_out(*this)
+ , m_i2s_out(*this)
+{
+}
+
+void sa1111_device::map(address_map &map)
+{
+ map(0x0000, 0x1fff).rw(FUNC(sa1111_device::unknown_r), FUNC(sa1111_device::unknown_w));
+
+ map(0x0000, 0x0003).rw(FUNC(sa1111_device::skcr_r), FUNC(sa1111_device::skcr_w));
+ map(0x0004, 0x0007).rw(FUNC(sa1111_device::smcr_r), FUNC(sa1111_device::smcr_w));
+ map(0x0008, 0x000b).r(FUNC(sa1111_device::skid_r));
+
+ map(0x0200, 0x0203).rw(FUNC(sa1111_device::skpcr_r), FUNC(sa1111_device::skpcr_w));
+ map(0x0204, 0x0207).rw(FUNC(sa1111_device::skcdr_r), FUNC(sa1111_device::skcdr_w));
+ map(0x0208, 0x020b).rw(FUNC(sa1111_device::skaud_r), FUNC(sa1111_device::skaud_w));
+ map(0x020c, 0x020f).rw(FUNC(sa1111_device::skpmc_r), FUNC(sa1111_device::skpmc_w));
+ map(0x0210, 0x0213).rw(FUNC(sa1111_device::skptc_r), FUNC(sa1111_device::skptc_w));
+ map(0x0214, 0x0217).rw(FUNC(sa1111_device::skpen0_r), FUNC(sa1111_device::skpen0_w));
+ map(0x0218, 0x021b).rw(FUNC(sa1111_device::skpwm0_r), FUNC(sa1111_device::skpwm0_w));
+ map(0x021c, 0x021f).rw(FUNC(sa1111_device::skpen1_r), FUNC(sa1111_device::skpen1_w));
+ map(0x0220, 0x0223).rw(FUNC(sa1111_device::skpwm1_r), FUNC(sa1111_device::skpwm1_w));
+
+ map(0x0400, 0x0457).rw(FUNC(sa1111_device::ohci_r), FUNC(sa1111_device::ohci_w));
+ map(0x0518, 0x051b).r(FUNC(sa1111_device::usb_status_r));
+ map(0x051c, 0x051f).rw(FUNC(sa1111_device::usb_reset_r), FUNC(sa1111_device::usb_reset_w));
+ map(0x0520, 0x0523).w(FUNC(sa1111_device::usb_int_test_w));
+ map(0x0530, 0x055f).r(FUNC(sa1111_device::usb_fifo_r));
+
+ map(0x0600, 0x0603).rw(FUNC(sa1111_device::sacr0_r), FUNC(sa1111_device::sacr0_w));
+ map(0x0604, 0x0607).rw(FUNC(sa1111_device::sacr1_r), FUNC(sa1111_device::sacr1_w));
+ map(0x0608, 0x060b).rw(FUNC(sa1111_device::sacr2_r), FUNC(sa1111_device::sacr2_w));
+ map(0x060c, 0x060f).r(FUNC(sa1111_device::sasr0_r));
+ map(0x0610, 0x0613).r(FUNC(sa1111_device::sasr1_r));
+ map(0x0618, 0x061b).w(FUNC(sa1111_device::sascr_w));
+ map(0x061c, 0x061f).rw(FUNC(sa1111_device::l3car_r), FUNC(sa1111_device::l3car_w));
+ map(0x0620, 0x0623).rw(FUNC(sa1111_device::l3cdr_r), FUNC(sa1111_device::l3cdr_w));
+ map(0x0624, 0x0627).rw(FUNC(sa1111_device::accar_r), FUNC(sa1111_device::accar_w));
+ map(0x0628, 0x062b).rw(FUNC(sa1111_device::accdr_r), FUNC(sa1111_device::accdr_w));
+ map(0x062c, 0x062f).rw(FUNC(sa1111_device::acsar_r), FUNC(sa1111_device::acsar_w));
+ map(0x0630, 0x0633).rw(FUNC(sa1111_device::acsdr_r), FUNC(sa1111_device::acsdr_w));
+ map(0x0634, 0x0637).rw(FUNC(sa1111_device::sadtcs_r), FUNC(sa1111_device::sadtcs_w));
+ map(0x0638, 0x063b).rw(FUNC(sa1111_device::sadtsa_r), FUNC(sa1111_device::sadtsa_w));
+ map(0x063c, 0x063f).rw(FUNC(sa1111_device::sadtca_r), FUNC(sa1111_device::sadtca_w));
+ map(0x0640, 0x0643).rw(FUNC(sa1111_device::sadtsb_r), FUNC(sa1111_device::sadtsb_w));
+ map(0x0644, 0x0647).rw(FUNC(sa1111_device::sadtcb_r), FUNC(sa1111_device::sadtcb_w));
+ map(0x0648, 0x064b).rw(FUNC(sa1111_device::sadrcs_r), FUNC(sa1111_device::sadrcs_w));
+ map(0x064c, 0x064f).rw(FUNC(sa1111_device::sadrsa_r), FUNC(sa1111_device::sadrsa_w));
+ map(0x0650, 0x0653).rw(FUNC(sa1111_device::sadrca_r), FUNC(sa1111_device::sadrca_w));
+ map(0x0654, 0x0657).rw(FUNC(sa1111_device::sadrsb_r), FUNC(sa1111_device::sadrsb_w));
+ map(0x0658, 0x065b).rw(FUNC(sa1111_device::sadrcb_r), FUNC(sa1111_device::sadrcb_w));
+ map(0x065c, 0x065f).w(FUNC(sa1111_device::saitr_w));
+ map(0x0680, 0x06bf).rw(FUNC(sa1111_device::sadr_r), FUNC(sa1111_device::sadr_w));
+
+ map(0x0800, 0x0803).rw(FUNC(sa1111_device::sspcr0_r), FUNC(sa1111_device::sspcr0_w));
+ map(0x0804, 0x0807).rw(FUNC(sa1111_device::sspcr1_r), FUNC(sa1111_device::sspcr1_w));
+ map(0x0810, 0x0813).rw(FUNC(sa1111_device::sspsr_r), FUNC(sa1111_device::sspsr_w));
+ map(0x0814, 0x0817).w(FUNC(sa1111_device::sspitr_w));
+ map(0x0840, 0x087f).rw(FUNC(sa1111_device::sspdr_r), FUNC(sa1111_device::sspdr_w));
+
+ map(0x0a00, 0x0a03).rw(FUNC(sa1111_device::track_kbdcr_r), FUNC(sa1111_device::track_kbdcr_w));
+ map(0x0a04, 0x0a07).rw(FUNC(sa1111_device::track_kbdstat_r), FUNC(sa1111_device::track_kbdstat_w));
+ map(0x0a08, 0x0a0b).rw(FUNC(sa1111_device::track_kbddata_r), FUNC(sa1111_device::track_kbddata_w));
+ map(0x0a0c, 0x0a0f).rw(FUNC(sa1111_device::track_kbdclkdiv_r), FUNC(sa1111_device::track_kbdclkdiv_w));
+ map(0x0a10, 0x0a13).rw(FUNC(sa1111_device::track_kbdprecnt_r), FUNC(sa1111_device::track_kbdprecnt_w));
+ map(0x0a14, 0x0a17).w(FUNC(sa1111_device::track_kbditr_w));
+
+ map(0x0c00, 0x0c03).rw(FUNC(sa1111_device::mouse_kbdcr_r), FUNC(sa1111_device::mouse_kbdcr_w));
+ map(0x0c04, 0x0c07).rw(FUNC(sa1111_device::mouse_kbdstat_r), FUNC(sa1111_device::mouse_kbdstat_w));
+ map(0x0c08, 0x0c0b).rw(FUNC(sa1111_device::mouse_kbddata_r), FUNC(sa1111_device::mouse_kbddata_w));
+ map(0x0c0c, 0x0c0f).rw(FUNC(sa1111_device::mouse_kbdclkdiv_r), FUNC(sa1111_device::mouse_kbdclkdiv_w));
+ map(0x0c10, 0x0c13).rw(FUNC(sa1111_device::mouse_kbdprecnt_r), FUNC(sa1111_device::mouse_kbdprecnt_w));
+ map(0x0c14, 0x0c17).w(FUNC(sa1111_device::mouse_kbditr_w));
+
+ map(0x1000, 0x1003).rw(FUNC(sa1111_device::ddr_r<0>), FUNC(sa1111_device::ddr_w<0>));
+ map(0x1004, 0x1007).rw(FUNC(sa1111_device::drr_r<0>), FUNC(sa1111_device::dwr_w<0>));
+ map(0x1008, 0x100b).rw(FUNC(sa1111_device::sdr_r<0>), FUNC(sa1111_device::sdr_w<0>));
+ map(0x100c, 0x100f).rw(FUNC(sa1111_device::ssr_r<0>), FUNC(sa1111_device::ssr_w<0>));
+ map(0x1010, 0x1013).rw(FUNC(sa1111_device::ddr_r<1>), FUNC(sa1111_device::ddr_w<1>));
+ map(0x1014, 0x1017).rw(FUNC(sa1111_device::drr_r<1>), FUNC(sa1111_device::dwr_w<1>));
+ map(0x1018, 0x101b).rw(FUNC(sa1111_device::sdr_r<1>), FUNC(sa1111_device::sdr_w<1>));
+ map(0x101c, 0x101f).rw(FUNC(sa1111_device::ssr_r<1>), FUNC(sa1111_device::ssr_w<1>));
+ map(0x1020, 0x1023).rw(FUNC(sa1111_device::ddr_r<2>), FUNC(sa1111_device::ddr_w<2>));
+ map(0x1024, 0x1027).rw(FUNC(sa1111_device::drr_r<2>), FUNC(sa1111_device::dwr_w<2>));
+ map(0x1028, 0x102b).rw(FUNC(sa1111_device::sdr_r<2>), FUNC(sa1111_device::sdr_w<2>));
+ map(0x102c, 0x102f).rw(FUNC(sa1111_device::ssr_r<2>), FUNC(sa1111_device::ssr_w<2>));
+
+ map(0x1600, 0x1603).rw(FUNC(sa1111_device::inttest_r<0>), FUNC(sa1111_device::inttest_w<0>));
+ map(0x1604, 0x1607).rw(FUNC(sa1111_device::inttest_r<1>), FUNC(sa1111_device::inttest_w<1>));
+ map(0x1608, 0x160b).rw(FUNC(sa1111_device::inten_r<0>), FUNC(sa1111_device::inten_w<0>));
+ map(0x160c, 0x160f).rw(FUNC(sa1111_device::inten_r<1>), FUNC(sa1111_device::inten_w<1>));
+ map(0x1610, 0x1613).rw(FUNC(sa1111_device::intpol_r<0>), FUNC(sa1111_device::intpol_w<0>));
+ map(0x1614, 0x1617).rw(FUNC(sa1111_device::intpol_r<1>), FUNC(sa1111_device::intpol_w<1>));
+ map(0x1618, 0x161b).rw(FUNC(sa1111_device::inttstsel_r), FUNC(sa1111_device::inttstsel_w));
+ map(0x161c, 0x161f).rw(FUNC(sa1111_device::intstat_r<0>), FUNC(sa1111_device::intclr_w<0>));
+ map(0x1620, 0x1623).rw(FUNC(sa1111_device::intstat_r<1>), FUNC(sa1111_device::intclr_w<1>));
+ map(0x1624, 0x1627).w(FUNC(sa1111_device::intset_w<0>));
+ map(0x1628, 0x162b).w(FUNC(sa1111_device::intset_w<1>));
+ map(0x162c, 0x162f).rw(FUNC(sa1111_device::wake_en_r<0>), FUNC(sa1111_device::wake_en_w<0>));
+ map(0x1630, 0x1633).rw(FUNC(sa1111_device::wake_en_r<1>), FUNC(sa1111_device::wake_en_w<1>));
+ map(0x1634, 0x1637).rw(FUNC(sa1111_device::wake_pol_r<0>), FUNC(sa1111_device::wake_pol_w<0>));
+ map(0x1638, 0x163b).rw(FUNC(sa1111_device::wake_pol_r<1>), FUNC(sa1111_device::wake_pol_w<1>));
+
+ map(0x1800, 0x1803).rw(FUNC(sa1111_device::pccr_r), FUNC(sa1111_device::pccr_w));
+ map(0x1804, 0x1807).rw(FUNC(sa1111_device::pcssr_r), FUNC(sa1111_device::pcssr_w));
+ map(0x1808, 0x180b).r(FUNC(sa1111_device::pcsr_r));
+}
+
+uint32_t sa1111_device::unknown_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_UNKNOWN, "%s: unknown_r: Unknown Register: %08x & %08x\n", machine().describe_context(), offset << 2, mem_mask);
+ return 0;
+}
+
+void sa1111_device::unknown_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_UNKNOWN, "%s: unknown_w: Unknown Register: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+}
+
+/*
+
+ Intel SA-1111 System Bus Interface
+
+ pg. 33 to 50 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+uint32_t sa1111_device::skcr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SBI, "%s: skcr_r: Control Register: %08x & %08x\n", machine().describe_context(), m_sbi_regs.skcr, mem_mask);
+ return m_sbi_regs.skcr;
+}
+
+uint32_t sa1111_device::smcr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SBI, "%s: smcr_r: Shared Memory Controller Register: %08x & %08x\n", machine().describe_context(), m_sbi_regs.smcr, mem_mask);
+ return m_sbi_regs.smcr;
+}
+
+uint32_t sa1111_device::skid_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SBI, "%s: skid_r: ID Register: %08x & %08x\n", machine().describe_context(), m_sbi_regs.skid, mem_mask);
+ return m_sbi_regs.skid;
+}
+
+void sa1111_device::skcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SBI, "%s: skcr_w: Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SBI, "%s: Use External Clock: %d\n", machine().describe_context(), BIT(data, SKCR_PLLB_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enable System Bus Clocks: %d\n", machine().describe_context(), BIT(data, SKCR_RCLK_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enter Sleep Mode: %d\n", machine().describe_context(), BIT(data, SKCR_SLEEP_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enter Doze Mode: %d\n", machine().describe_context(), BIT(data, SKCR_DOZE_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enable System PLL: %d\n", machine().describe_context(), BIT(data, SKCR_VCO_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enable Scan Test: %d\n", machine().describe_context(), BIT(data, SKCR_SCANTST_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enable Clock Test: %d\n", machine().describe_context(), BIT(data, SKCR_CLKTST_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enable RDY Response: %d\n", machine().describe_context(), BIT(data, SKCR_RDY_BIT));
+ LOGMASKED(LOG_SBI, "%s: Audio Feature Select: %s\n", machine().describe_context(), BIT(data, SKCR_SACMDSL_BIT) ? "AC Link" : "I2S");
+ LOGMASKED(LOG_SBI, "%s: Out-Only Pad Control: %d\n", machine().describe_context(), BIT(data, SKCR_OPPC_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enable PII Test: %d\n", machine().describe_context(), BIT(data, SKCR_PII_BIT));
+ LOGMASKED(LOG_SBI, "%s: USB IO Cell Test: %d\n", machine().describe_context(), BIT(data, SKCR_UIOTEN_BIT));
+ LOGMASKED(LOG_SBI, "%s: Enable /OE on SDRAM DMA Read Cycles: %d\n", machine().describe_context(), 1 - BIT(data, SKCR_OEEN_BIT));
+ const bool audio_mode_changed = BIT(m_sbi_regs.skcr ^ ((m_sbi_regs.skcr & ~mem_mask) | (data & mem_mask)), SKCR_SACMDSL_BIT);
+ const bool audio_enabled = BIT(m_audio_regs.sacr0, SACR0_ENB_BIT);
+ if (audio_mode_changed && audio_enabled)
+ {
+ // If we're changing audio output modes while the audio interface is active, bring it down in the old mode,
+ // then bring it back up in the new mode.
+ audio_set_enabled(false);
+ COMBINE_DATA(&m_sbi_regs.skcr);
+ audio_set_enabled(true);
+ }
+ else
+ {
+ COMBINE_DATA(&m_sbi_regs.skcr);
+ }
+}
+
+void sa1111_device::smcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SBI, "%s: smcr_w: Shared Memory Controller Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SBI, "%s: DRAM Type: %s\n", machine().describe_context(), BIT(data, SMCR_DTIM_BIT) ? "SDRAM" : "Unknown");
+ LOGMASKED(LOG_SBI, "%s: Shared-Memory Grant Enable: %d\n", machine().describe_context(), BIT(data, SMCR_MBGE_BIT));
+ LOGMASKED(LOG_SBI, "%s: DRAM Row Address Bits: %d\n", machine().describe_context(), 9 + ((data & SMCR_DRAC_MASK) >> SMCR_DRAC_BIT));
+ LOGMASKED(LOG_SBI, "%s: CAS Latency: %d\n", machine().describe_context(), 2 + BIT(data, SMCR_CLAT_BIT));
+ COMBINE_DATA(&m_sbi_regs.smcr);
+}
+
+/*
+
+ Intel SA-1111 System Controller
+
+ pg. 59 to 66 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+uint32_t sa1111_device::skpcr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpcr_r: Power Control Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skpcr, mem_mask);
+ return m_sk_regs.skpcr;
+}
+
+uint32_t sa1111_device::skcdr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skcdr_r: Clock Divider Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skcdr, mem_mask);
+ return m_sk_regs.skcdr;
+}
+
+uint32_t sa1111_device::skaud_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skaud_r: Audio Clock Divider Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skaud, mem_mask);
+ return m_sk_regs.skaud;
+}
+
+uint32_t sa1111_device::skpmc_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpmc_r: PS/2 Mouse Clock Divider Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skpmc, mem_mask);
+ return m_sk_regs.skpmc;
+}
+
+uint32_t sa1111_device::skptc_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skptc_r: PS/2 Track Pad Clock Divider Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skptc, mem_mask);
+ return m_sk_regs.skptc;
+}
+
+uint32_t sa1111_device::skpen0_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpen0_r: PWM0 Enable Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skpen0, mem_mask);
+ return m_sk_regs.skpen0;
+}
+
+uint32_t sa1111_device::skpwm0_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpwm0_r: PWM0 Clock Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skpwm0, mem_mask);
+ return m_sk_regs.skpwm0;
+}
+
+uint32_t sa1111_device::skpen1_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpen1_r: PWM1 Enable Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skpen1, mem_mask);
+ return m_sk_regs.skpen1;
+}
+
+uint32_t sa1111_device::skpwm1_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpwm1_r: PWM1 Clock Register: %08x & %08x\n", machine().describe_context(), m_sk_regs.skpwm1, mem_mask);
+ return m_sk_regs.skpwm1;
+}
+
+void sa1111_device::skpcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpcr_w: Power Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SK, "%s: USB Host Controller Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_UCLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: Audio Controller AC Link Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_ACCLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: Audio Controller I2S Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_ISCLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: Audio Controller L3 Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_L3CLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: SSP Controller Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_SCLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: PS/2 Mouse Port Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_PMCLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: PS/2 Track Pad Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_PTCLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: Shared Memory Controller Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_DCLKE_BIT));
+ LOGMASKED(LOG_SK, "%s: PWM Clock Enable: %d\n", machine().describe_context(), BIT(data, SKPCR_PWMCLKE_BIT));
+ COMBINE_DATA(&m_sk_regs.skpcr);
+}
+
+void sa1111_device::skcdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ static const int s_opd_values[4] = { 1, 4, 2, 8 };
+ LOGMASKED(LOG_SK, "%s: skcdr_w: Clock Divider Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SK, "%s: Feedback Divider: %02x\n", machine().describe_context(), (data & SKCDR_FBD_MASK) >> SKCDR_FBD_BIT);
+ LOGMASKED(LOG_SK, "%s: Input Divider: %02x\n", machine().describe_context(), (data & SKCDR_IPD_MASK) >> SKCDR_IPD_BIT);
+ LOGMASKED(LOG_SK, "%s: Output Divider: %d\n", machine().describe_context(), s_opd_values[(data & SKCDR_OPD_MASK) >> SKCDR_OPD_BIT]);
+ LOGMASKED(LOG_SK, "%s: PLL-Bypass Output Phase: %s\n", machine().describe_context(), BIT(data, SKCDR_OPS_BIT) ? "Inverted" : "In-Phase");
+ COMBINE_DATA(&m_sk_regs.skcdr);
+}
+
+void sa1111_device::skaud_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ const uint32_t audio_divider = ((data & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
+ LOGMASKED(LOG_SK, "%s: skaud_w: Audio Clock Divider Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SK, "%s: Audio Clock Divider: %02x\n", machine().describe_context(), audio_divider);
+ COMBINE_DATA(&m_sk_regs.skaud);
+ const uint32_t pll_clock = clock() * 39;
+ if (m_audio_codec)
+ m_audio_codec->set_unscaled_clock(pll_clock / audio_divider);
+}
+
+void sa1111_device::skpmc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpmc_w: PS/2 Mouse Clock Divider Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SK, "%s: PS/2 Clock Divider: %02x\n", machine().describe_context(), ((data & SKPMC_PMCD_MASK) >> SKPMC_PMCD_BIT) + 1);
+ COMBINE_DATA(&m_sk_regs.skpmc);
+}
+
+void sa1111_device::skptc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skptc_w: PS/2 Track Pad Clock Divider Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SK, "%s: PS/2 Clock Divider: %02x\n", machine().describe_context(), ((data & SKPTC_PTCD_MASK) >> SKPTC_PTCD_BIT) + 1);
+ COMBINE_DATA(&m_sk_regs.skptc);
+}
+
+void sa1111_device::skpen0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpen0_w: PWM0 Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_sk_regs.skpen0);
+}
+
+void sa1111_device::skpwm0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpwm0_w: PWM0 Clock Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SK, "%s: PWM0 Duty Cycle: %02x\n", machine().describe_context(), (data & SKPWM0_PWM0CK_MASK) >> SKPWM0_PWM0CK_BIT);
+ COMBINE_DATA(&m_sk_regs.skpwm0);
+}
+
+void sa1111_device::skpen1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpen1_w: PWM1 Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_sk_regs.skpen1);
+}
+
+void sa1111_device::skpwm1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SK, "%s: skpwm1_w: PWM1 Clock Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SK, "%s: PWM1 Duty Cycle: %02x\n", machine().describe_context(), (data & SKPWM1_PWM1CK_MASK) >> SKPWM1_PWM1CK_BIT);
+ COMBINE_DATA(&m_sk_regs.skpwm1);
+}
+
+/*
+
+ Intel SA-1111 USB Host Interface Controller
+
+ pg. 67 to 77 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+uint32_t sa1111_device::ohci_r(offs_t offset, uint32_t mem_mask)
+{
+ static const char *const s_ohci_names[22] =
+ {
+ "Revision", "Control", "Command Status", "Interrupt Status",
+ "Interrupt Enable", "Interrupt Disable", "HCCA", "Period Current ED",
+ "Control Head ED", "Control Current ED", "Bulk Head ED", "Bulk Current ED",
+ "Done Head", "Fm Interval", "Fm Remaining", "Fm Number",
+ "Periodic Start", "LS Threshold", "Rh Descriptor A", "Rh Descriptor B",
+ "Rh Status", "Rh Port Status<1>"
+ };
+ LOGMASKED(LOG_USB, "%s: ohci_r: %s: %08x & %08x\n", machine().describe_context(), s_ohci_names[offset], m_usb_regs.ohci[offset], mem_mask);
+ return m_usb_regs.ohci[offset];
+}
+
+uint32_t sa1111_device::usb_status_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_usb_regs.status;
+ LOGMASKED(LOG_USB, "%s: usb_status_r: Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_USB, "%s: HCI Remote Wake-Up Event: %d\n", machine().describe_context(), BIT(data, USBSTAT_IHRW_BIT));
+ LOGMASKED(LOG_USB, "%s: HCI Buffer Active: %d\n", machine().describe_context(), BIT(data, USBSTAT_IHBA_BIT));
+ LOGMASKED(LOG_USB, "%s: Normal HCI Interrupt Active: %d\n", machine().describe_context(), BIT(data, USBSTAT_NHT_BIT));
+ LOGMASKED(LOG_USB, "%s: HCI Interface Clear Signals Active: %d\n", machine().describe_context(), BIT(data, USBSTAT_NHFCT_BIT));
+ LOGMASKED(LOG_USB, "%s: Port Over-Current: %d\n", machine().describe_context(), BIT(data, USBSTAT_UPRT_BIT));
+ return data;
+}
+
+uint32_t sa1111_device::usb_reset_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_USB, "%s: usb_reset_r: Reset Register: %08x & %08x\n", machine().describe_context(), m_usb_regs.reset, mem_mask);
+ return m_usb_regs.reset;
+}
+
+uint32_t sa1111_device::usb_fifo_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_USB, "%s: usb_fifo_r: Data FIFO RAM %02x: %08x & %08x\n", machine().describe_context(), offset, m_usb_regs.fifo[offset], mem_mask);
+ return m_usb_regs.fifo[offset];
+}
+
+void sa1111_device::ohci_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ static const char *const s_ohci_names[22] =
+ {
+ "Revision", "Control", "Command Status", "Interrupt Status",
+ "Interrupt Enable", "Interrupt Disable", "HCCA", "Period Current ED",
+ "Control Head ED", "Control Current ED", "Bulk Head ED", "Bulk Current ED",
+ "Done Head", "Fm Interval", "Fm Remaining", "Fm Number",
+ "Periodic Start", "LS Threshold", "Rh Descriptor A", "Rh Descriptor B",
+ "Rh Status", "Rh Port Status<1>"
+ };
+ LOGMASKED(LOG_USB, "%s: ohci_w: %s = %08x & %08x\n", machine().describe_context(), s_ohci_names[offset], data, mem_mask);
+ COMBINE_DATA(&m_usb_regs.ohci[offset]);
+}
+
+void sa1111_device::usb_reset_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_USB, "%s: usb_reset_w: Reset Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_USB, "%s: Reset ASB Master Interface: %d\n", machine().describe_context(), BIT(data, USBRST_FIR_BIT));
+ LOGMASKED(LOG_USB, "%s: Reset USB Host Controller: %d\n", machine().describe_context(), BIT(data, USBRST_FHR_BIT));
+ LOGMASKED(LOG_USB, "%s: Reset Host Controller Clock-Gen Block: %d\n", machine().describe_context(), BIT(data, USBRST_CGR_BIT));
+ LOGMASKED(LOG_USB, "%s: Scale-down 1ms Clock: %d\n", machine().describe_context(), BIT(data, USBRST_SSDC_BIT));
+ LOGMASKED(LOG_USB, "%s: Interrupt Test Enable: %d\n", machine().describe_context(), BIT(data, USBRST_UIT_BIT));
+ LOGMASKED(LOG_USB, "%s: Enable Sleep Standby: %d\n", machine().describe_context(), BIT(data, USBRST_SSE_BIT));
+ LOGMASKED(LOG_USB, "%s: USB Power Sense Polarity: %s\n", machine().describe_context(), BIT(data, USBRST_PSPL_BIT) ? "Active-Low" : "Active-High");
+ LOGMASKED(LOG_USB, "%s: PwrCtrlPolLow Polarity: %s\n", machine().describe_context(), BIT(data, USBRST_PCPL_BIT) ? "Active-Low" : "Active-High");
+ COMBINE_DATA(&m_usb_regs.reset);
+}
+
+void sa1111_device::usb_int_test_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_USB, "%s: usb_int_test_w: Interrupt Test Register = %08x & %08x\n", machine().describe_context(), m_usb_regs.int_test, mem_mask);
+ LOGMASKED(LOG_USB, "%s: Force HCI Remote Wake-Up Interrupt: %d\n", machine().describe_context(), BIT(data, USBINT_IHRWT_BIT));
+ LOGMASKED(LOG_USB, "%s: Force HCI Buffer Active Interrupt: %d\n", machine().describe_context(), BIT(data, USBINT_IHBAT_BIT));
+ LOGMASKED(LOG_USB, "%s: Force Normal HC Interrupt: %d\n", machine().describe_context(), BIT(data, USBINT_NHT_BIT));
+ LOGMASKED(LOG_USB, "%s: Force HCI Interface Transfer Abort Interrupt: %d\n", machine().describe_context(), BIT(data, USBINT_NHFCT_BIT));
+ LOGMASKED(LOG_USB, "%s: Force USB Port Resume Interrupt: %d\n", machine().describe_context(), BIT(data, USBINT_UPRT_BIT));
+ COMBINE_DATA(&m_usb_regs.int_test);
+}
+
+/*
+
+ Intel SA-1111 Serial Audio Controller
+
+ pg. 79 to 108 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+void sa1111_device::l3wd_in(int state)
+{
+ if (state)
+ m_audio_regs.sasr0 |= (1 << SASR0_L3WD_BIT);
+}
+
+TIMER_CALLBACK_MEMBER(sa1111_device::audio_rx_dma_callback)
+{
+ // TODO: Audio input
+}
+
+TIMER_CALLBACK_MEMBER(sa1111_device::audio_rx_callback)
+{
+ // TODO: Audio input
+}
+
+TIMER_CALLBACK_MEMBER(sa1111_device::audio_tx_dma_callback)
+{
+ const uint32_t buf = BIT(m_audio_regs.sadtcs, SADTCS_TBIU_BIT);
+ const uint32_t remaining = m_audio_regs.sadtcc >> 2;
+ const uint32_t avail = std::size(m_audio_regs.tx_fifo) - m_audio_regs.tx_fifo_count;
+ if (remaining == 0 || avail == 0)
+ return;
+
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ const uint32_t data = space.read_dword(m_audio_regs.sadta);
+ LOGMASKED(LOG_AUDIO_DMA, "audio_tx_dma_callback: read data %08x from %08x, pushing to FIFO\n", data, m_audio_regs.sadta);
+ audio_tx_fifo_push(data);
+ m_audio_regs.sadta += 4;
+
+ m_audio_regs.sadtcc = (remaining - 1) << 2;
+ if (!m_audio_regs.sadtcc)
+ {
+ static constexpr uint32_t s_start_masks[2] = { (1 << SADTCS_TDSTA_BIT), (1 << SADTCS_TDSTB_BIT) };
+ static constexpr uint32_t s_done_masks[2] = { (1 << SADTCS_TDBDA_BIT), (1 << SADTCS_TDBDB_BIT) };
+ static constexpr uint32_t s_done_ints[2] = { INT_AUDTXA, INT_AUDTXB };
+ m_audio_regs.sadtcs &= ~s_start_masks[buf];
+ m_audio_regs.sadtcs |= s_done_masks[buf];
+ set_irq_line(s_done_ints[buf], 1);
+ m_audio_regs.sadtcs ^= (1 << SADTCS_TBIU_BIT);
+ m_audio_regs.sadta = m_audio_regs.sadts[1 - buf];
+ m_audio_regs.sadtcc = m_audio_regs.sadtc[1 - buf];
+ if (!BIT(m_audio_regs.sadtcs, s_start_masks[1 - buf]))
+ {
+ m_audio_regs.tx_dma_timer->adjust(attotime::never);
+ }
+ }
+}
+
+TIMER_CALLBACK_MEMBER(sa1111_device::audio_tx_callback)
+{
+ m_i2s_out(audio_tx_fifo_pop());
+}
+
+void sa1111_device::audio_update_mode()
+{
+ audio_set_enabled(BIT(m_audio_regs.sacr0, SACR0_ENB_BIT));
+}
+
+void sa1111_device::audio_clear_interrupts()
+{
+ set_irq_line(INT_AUDTXA, 0);
+ set_irq_line(INT_AUDRXA, 0);
+ set_irq_line(INT_AUDTXB, 0);
+ set_irq_line(INT_AUDRXB, 0);
+ set_irq_line(INT_AUDTFS, 0);
+ set_irq_line(INT_AUDRFS, 0);
+ set_irq_line(INT_AUDTUR, 0);
+ set_irq_line(INT_AUDROR, 0);
+ set_irq_line(INT_AUDDTS, 0);
+ set_irq_line(INT_AUDRDD, 0);
+ set_irq_line(INT_AUDSTO, 0);
+}
+
+void sa1111_device::audio_controller_reset()
+{
+ m_audio_regs.rx_fifo_read_idx = 0;
+ m_audio_regs.rx_fifo_write_idx = 0;
+ m_audio_regs.rx_fifo_count = 0;
+ m_audio_regs.tx_fifo_read_idx = 0;
+ m_audio_regs.tx_fifo_write_idx = 0;
+ m_audio_regs.tx_fifo_count = 0;
+}
+
+void sa1111_device::audio_set_enabled(bool enabled)
+{
+ if (enabled)
+ {
+ audio_set_tx_dma_enabled(BIT(m_audio_regs.sadtcs, SADTCS_TDEN_BIT));
+ audio_set_rx_dma_enabled(BIT(m_audio_regs.sadrcs, SADRCS_RDEN_BIT));
+ audio_update_tx_fifo_levels();
+ audio_update_rx_fifo_levels();
+ audio_update_busy_flag();
+
+ uint32_t &status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? m_audio_regs.sasr1 : m_audio_regs.sasr0;
+ set_irq_line(INT_AUDTUR, BIT(status, SASR_TUR_BIT));
+ set_irq_line(INT_AUDROR, BIT(status, SASR_ROR_BIT));
+ set_irq_line(INT_AUDDTS, BIT(status, SASR_SEND_BIT));
+ set_irq_line(INT_AUDRDD, BIT(status, SASR_RECV_BIT));
+ set_irq_line(INT_AUDSTO, BIT(m_audio_regs.sasr1, SASR1_RSTO_BIT));
+ }
+ else
+ {
+ audio_set_tx_dma_enabled(false);
+ audio_set_rx_dma_enabled(false);
+ audio_clear_interrupts();
+ }
+}
+
+void sa1111_device::audio_set_tx_dma_enabled(bool enabled)
+{
+ LOGMASKED(LOG_AUDIO_DMA, "audio_set_tx_dma_enabled: %d\n", enabled);
+ if (enabled)
+ {
+ if (m_audio_regs.tx_dma_timer->remaining() == attotime::never)
+ {
+ const uint32_t buf = BIT(m_audio_regs.sadtcs, SADTCS_TBIU_BIT);
+ if ((buf == 0 && BIT(m_audio_regs.sadtcs, SADTCS_TDSTA_BIT)) || (buf == 1 && BIT(m_audio_regs.sadtcs, SADTCS_TDSTB_BIT)))
+ {
+ LOGMASKED(LOG_AUDIO_DMA, "audio_set_tx_dma_enabled, starting Tx DMA from buffer %d\n", buf);
+ audio_start_tx_dma(buf);
+ }
+ }
+ }
+ else
+ {
+ m_audio_regs.tx_timer->adjust(attotime::never);
+ m_audio_regs.tx_dma_timer->adjust(attotime::never);
+
+ set_irq_line(INT_AUDTXA, 0);
+ set_irq_line(INT_AUDTXB, 0);
+ set_irq_line(INT_AUDTFS, 0);
+ set_irq_line(INT_AUDTUR, 0);
+ }
+}
+
+void sa1111_device::audio_set_rx_dma_enabled(bool enabled)
+{
+ if (enabled)
+ {
+ if (m_audio_regs.rx_dma_timer->remaining() == attotime::never)
+ {
+ const uint32_t buf = BIT(m_audio_regs.sadrcs, SADRCS_RBIU_BIT);
+ if ((buf == 0 && BIT(m_audio_regs.sadrcs, SADRCS_RDSTA_BIT)) || (buf == 1 && BIT(m_audio_regs.sadrcs, SADRCS_RDSTB_BIT)))
+ {
+ audio_start_rx_dma(buf);
+ }
+ }
+ }
+ else
+ {
+ m_audio_regs.rx_timer->adjust(attotime::never);
+ m_audio_regs.rx_dma_timer->adjust(attotime::never);
+
+ set_irq_line(INT_AUDRXA, 0);
+ set_irq_line(INT_AUDRXB, 0);
+ set_irq_line(INT_AUDRFS, 0);
+ set_irq_line(INT_AUDROR, 0);
+ }
+}
+
+void sa1111_device::audio_start_tx_dma(const uint32_t buf)
+{
+ if (!m_audio_codec)
+ return;
+
+ m_audio_regs.sadta = m_audio_regs.sadts[buf];
+ m_audio_regs.sadtcc = m_audio_regs.sadtc[buf];
+
+ const uint32_t divisor = ((m_sk_regs.skaud & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
+ const uint32_t pll_clock = clock() * 39;
+ attotime clock_period = attotime::from_ticks(divisor * 128, pll_clock);
+ m_audio_regs.tx_dma_timer->adjust(clock_period, 0, clock_period);
+
+ LOGMASKED(LOG_AUDIO_DMA, "audio_start_tx_dma, setting start address to %08x, Tx clock to %d / %d\n", m_audio_regs.sadta, pll_clock, divisor);
+}
+
+void sa1111_device::audio_start_rx_dma(const uint32_t buf)
+{
+ if (!m_audio_codec)
+ return;
+
+ m_audio_regs.sadra = m_audio_regs.sadrs[buf];
+
+ const uint32_t divisor = ((m_sk_regs.skaud & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
+ const uint32_t pll_clock = clock() * 39;
+ attotime clock_period = attotime::from_ticks(divisor * 256, pll_clock);
+ m_audio_regs.rx_dma_timer->adjust(clock_period, 0, clock_period);
+}
+
+void sa1111_device::audio_update_tx_fifo_levels()
+{
+ uint32_t &status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? m_audio_regs.sasr1 : m_audio_regs.sasr0;
+ if (m_audio_regs.tx_fifo_count < std::size(m_audio_regs.tx_fifo))
+ status |= (1 << SASR_TNF_BIT);
+ else
+ status &= ~(1 << SASR_TNF_BIT);
+
+ const uint32_t tfl = ((m_audio_regs.tx_fifo_count == std::size(m_audio_regs.tx_fifo)) ? (m_audio_regs.tx_fifo_count - 1) : m_audio_regs.tx_fifo_count);
+ status &= ~SASR_TFL_MASK;
+ status |= (tfl << SASR_TFL_BIT);
+
+ const uint32_t tfth = ((m_audio_regs.sacr0 & SACR0_TFTH_MASK) >> SACR0_TFTH_BIT) + 1;
+ if (tfl <= tfth)
+ {
+ status |= (1 << SASR_TFS_BIT);
+ set_irq_line(INT_AUDTFS, 1);
+ }
+ else
+ {
+ status &= ~(1 << SASR_TFS_BIT);
+ set_irq_line(INT_AUDTFS, 0);
+ }
+}
+
+void sa1111_device::audio_update_rx_fifo_levels()
+{
+ uint32_t &status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? m_audio_regs.sasr1 : m_audio_regs.sasr0;
+ if (m_audio_regs.rx_fifo_count != 0)
+ status |= (1 << SASR_RNE_BIT);
+ else
+ status &= ~(1 << SASR_RNE_BIT);
+
+ const uint32_t rfl = ((m_audio_regs.rx_fifo_count == std::size(m_audio_regs.rx_fifo)) ? (m_audio_regs.rx_fifo_count - 1) : m_audio_regs.rx_fifo_count);
+ status &= ~SASR_RFL_MASK;
+ status |= (rfl << SASR_RFL_BIT);
+
+ const uint32_t rfth = ((m_audio_regs.sacr0 & SACR0_RFTH_MASK) >> SACR0_RFTH_BIT) + 1;
+ if (rfl >= rfth)
+ {
+ status |= (1 << SASR_RFS_BIT);
+ set_irq_line(INT_AUDRFS, 1);
+ }
+ else
+ {
+ status &= ~(1 << SASR_RFS_BIT);
+ set_irq_line(INT_AUDRFS, 0);
+ }
+}
+
+void sa1111_device::audio_update_busy_flag()
+{
+ uint32_t &status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? m_audio_regs.sasr1 : m_audio_regs.sasr0;
+ if (m_audio_regs.rx_fifo_count > 0 || m_audio_regs.tx_fifo_count > 0)
+ status |= (1 << SASR_BSY_BIT);
+ else
+ status &= ~(1 << SASR_BSY_BIT);
+}
+
+void sa1111_device::audio_tx_fifo_push(uint32_t data)
+{
+ if (m_audio_regs.tx_fifo_count < std::size(m_audio_regs.tx_fifo))
+ {
+ m_audio_regs.tx_fifo[m_audio_regs.tx_fifo_write_idx] = data;
+ m_audio_regs.tx_fifo_write_idx = (m_audio_regs.tx_fifo_write_idx + 1) % std::size(m_audio_regs.tx_fifo);
+ m_audio_regs.tx_fifo_count++;
+ audio_update_tx_fifo_levels();
+ if (m_audio_regs.tx_timer->remaining() == attotime::never)
+ {
+ const uint32_t divisor = ((m_sk_regs.skaud & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
+ const uint32_t pll_clock = clock() * 39;
+ attotime clock_period = attotime::from_ticks(divisor * 96, pll_clock);
+ m_audio_regs.tx_timer->adjust(clock_period, 0, clock_period);
+ }
+ }
+}
+
+uint32_t sa1111_device::audio_tx_fifo_pop()
+{
+ if (m_audio_regs.tx_fifo_count > 0)
+ {
+ const uint32_t data = m_audio_regs.tx_fifo[m_audio_regs.tx_fifo_read_idx];
+ m_audio_regs.tx_fifo_read_idx = (m_audio_regs.tx_fifo_read_idx + 1) % std::size(m_audio_regs.tx_fifo);
+ m_audio_regs.tx_fifo_count--;
+ audio_update_tx_fifo_levels();
+ if (m_audio_regs.tx_fifo_count == 0)
+ {
+ m_audio_regs.tx_timer->adjust(attotime::never);
+ }
+ return data;
+ }
+ else
+ {
+ uint32_t &status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? m_audio_regs.sasr1 : m_audio_regs.sasr0;
+ status |= (1 << SASR_TUR_BIT);
+ set_irq_line(INT_AUDTUR, 1);
+ return m_audio_regs.tx_fifo[m_audio_regs.tx_fifo_read_idx];
+ }
+}
+
+void sa1111_device::audio_rx_fifo_push(uint32_t data)
+{
+ if (m_audio_regs.rx_fifo_count < std::size(m_audio_regs.rx_fifo))
+ {
+ m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_write_idx] = data;
+ m_audio_regs.rx_fifo_write_idx = (m_audio_regs.rx_fifo_write_idx + 1) % std::size(m_audio_regs.rx_fifo);
+ m_audio_regs.rx_fifo_count++;
+ audio_update_rx_fifo_levels();
+ }
+ else
+ {
+ uint32_t &status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? m_audio_regs.sasr1 : m_audio_regs.sasr0;
+ status |= (1 << SASR_ROR_BIT);
+ set_irq_line(INT_AUDROR, 1);
+ }
+}
+
+uint32_t sa1111_device::audio_rx_fifo_pop()
+{
+ if (m_audio_regs.rx_fifo_count > 0)
+ {
+ const uint32_t data = m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_read_idx];
+ m_audio_regs.rx_fifo_read_idx = (m_audio_regs.rx_fifo_read_idx + 1) % std::size(m_audio_regs.rx_fifo);
+ m_audio_regs.rx_fifo_count--;
+ audio_update_rx_fifo_levels();
+ return data;
+ }
+ return m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_read_idx];
+}
+
+uint32_t sa1111_device::sacr0_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sacr0_r: Serial Audio Common Control Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.sacr0, mem_mask);
+ return m_audio_regs.sacr0;
+}
+
+uint32_t sa1111_device::sacr1_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sacr1_r: Serial Audio Alternate Mode Control Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.sacr1, mem_mask);
+ return m_audio_regs.sacr1;
+}
+
+uint32_t sa1111_device::sacr2_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sacr2_r: Serial Audio AC-Link Control Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.sacr2, mem_mask);
+ return m_audio_regs.sacr2;
+}
+
+uint32_t sa1111_device::sasr0_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_audio_regs.sasr0;
+ LOGMASKED(LOG_AUDIO, "%s: sasr0_r: Serial Audio Status Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(data, SASR_TNF_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(data, SASR_RNE_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio Controller Busy: %d\n", machine().describe_context(), BIT(data, SASR_BSY_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_TFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_RFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SASR_TUR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SASR_ROR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Level: %02x\n", machine().describe_context(), (data & SASR_TFL_MASK) >> SASR_TFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Level: %02x\n", machine().describe_context(), (data & SASR_RFL_MASK) >> SASR_RFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: L3 Control Bus Data Write Done: %d\n", machine().describe_context(), BIT(data, SASR0_L3WD_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: L3 Control Bus Data Read Done: %d\n", machine().describe_context(), BIT(data, SASR0_L3RD_BIT));
+ return data;
+}
+
+uint32_t sa1111_device::sasr1_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_audio_regs.sasr1;
+ LOGMASKED(LOG_AUDIO, "%s: sasr1_r: Serial Audio Status Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(data, SASR_TNF_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(data, SASR_RNE_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio Controller Busy: %d\n", machine().describe_context(), BIT(data, SASR_BSY_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_TFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_RFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SASR_TUR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SASR_ROR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Level: %02x\n", machine().describe_context(), (data & SASR_TFL_MASK) >> SASR_TFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Level: %02x\n", machine().describe_context(), (data & SASR_RFL_MASK) >> SASR_RFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: AC-Link Command Address and Data Transmitted: %d\n", machine().describe_context(), BIT(data, SASR1_CADT_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: AC-Link Status Address and Data Received: %d\n", machine().describe_context(), BIT(data, SASR1_SADR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Read Status Time-Out: %d\n", machine().describe_context(), BIT(data, SASR1_RSTO_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: AC'97 Codec BIT_CLK in Low-Power Mode: %d\n", machine().describe_context(), BIT(data, SASR1_CLPM_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: AC'97 Codec Ready: %d\n", machine().describe_context(), BIT(data, SASR1_CRDY_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Received Slot 3 Valid (Left Channel Valid): %d\n", machine().describe_context(), BIT(data, SASR1_RS3V_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Received Slot 4 Valid (Right Channel Valid): %d\n", machine().describe_context(), BIT(data, SASR1_RS4V_BIT));
+ return data;
+}
+
+uint32_t sa1111_device::l3car_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: l3car_r: L3 Control Bus Address Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.l3car, mem_mask);
+ return m_audio_regs.l3car;
+}
+
+uint32_t sa1111_device::l3cdr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: l3car_r: L3 Control Bus Data Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.l3cdr, mem_mask);
+ return m_audio_regs.l3cdr;
+}
+
+uint32_t sa1111_device::accar_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: accar_r: AC-Link Command Address Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.accar, mem_mask);
+ return m_audio_regs.accar;
+}
+
+uint32_t sa1111_device::accdr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: accdr_r: AC-Link Command Data Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.accdr, mem_mask);
+ return m_audio_regs.accdr;
+}
+
+uint32_t sa1111_device::acsar_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: acsar_r: AC-Link Status Address Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.acsar, mem_mask);
+ return m_audio_regs.acsar;
+}
+
+uint32_t sa1111_device::acsdr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: acsdr_r: AC-Link Status Data Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.acsdr, mem_mask);
+ return m_audio_regs.acsdr;
+}
+
+uint32_t sa1111_device::sadtcs_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtcs_r: Serial Audio DMA Transmit Control/Status Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtcs, mem_mask);
+ return m_audio_regs.sadtcs;
+}
+
+uint32_t sa1111_device::sadtsa_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtsa_r: Serial Audio DMA Transmit Buffer Start Address Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadts[0], mem_mask);
+ return m_audio_regs.sadts[0];
+}
+
+uint32_t sa1111_device::sadtca_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtca_r: Serial Audio DMA Transmit Buffer Count Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtc[0], mem_mask);
+ return m_audio_regs.sadtc[0];
+}
+
+uint32_t sa1111_device::sadtsb_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtsb_r: Serial Audio DMA Transmit Buffer Start Address Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadts[1], mem_mask);
+ return m_audio_regs.sadts[1];
+}
+
+uint32_t sa1111_device::sadtcb_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtcb_r: Serial Audio DMA Transmit Buffer Count Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtc[1], mem_mask);
+ return m_audio_regs.sadtc[1];
+}
+
+uint32_t sa1111_device::sadrcs_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrcs_r: Serial Audio DMA Receive Control/Status Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrcs, mem_mask);
+ return m_audio_regs.sadrcs;
+}
+
+uint32_t sa1111_device::sadrsa_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrsa_r: Serial Audio DMA Receive Buffer Start Address Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrs[0], mem_mask);
+ return m_audio_regs.sadrs[0];
+}
+
+uint32_t sa1111_device::sadrca_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrca_r: Serial Audio DMA Receive Buffer Count Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrc[0], mem_mask);
+ return m_audio_regs.sadrc[0];
+}
+
+uint32_t sa1111_device::sadrsb_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrsb_r: Serial Audio DMA Receive Buffer Start Address Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrs[1], mem_mask);
+ return m_audio_regs.sadrs[1];
+}
+
+uint32_t sa1111_device::sadrcb_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrcb_r: Serial Audio DMA Receive Buffer Count Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrc[1], mem_mask);
+ return m_audio_regs.sadrc[1];
+}
+
+uint32_t sa1111_device::sadr_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = audio_rx_fifo_pop();
+ LOGMASKED(LOG_AUDIO, "%s: sadr_r: Serial Audio Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1111_device::sacr0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sacr0_w: Serial Audio Common Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Enable Serial Audio Controller: %d\n", machine().describe_context(), BIT(data, SACR0_ENB_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: BIT_CLK Pin Direction: %s\n", machine().describe_context(), BIT(data, SACR0_BCKD_BIT) ? "Input" : "Output");
+ LOGMASKED(LOG_AUDIO, "%s: Reset SAC Control and FIFOs: %d\n", machine().describe_context(), BIT(data, SACR0_RST_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Threshold: %02x\n", machine().describe_context(), (data & SACR0_TFTH_MASK) >> SACR0_TFTH_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Threshold: %02x\n", machine().describe_context(), (data & SACR0_RFTH_MASK) >> SACR0_RFTH_BIT);
+
+ const uint32_t old = m_audio_regs.sacr0;
+ COMBINE_DATA(&m_audio_regs.sacr0);
+ const uint32_t changed = old ^ m_audio_regs.sacr0;
+
+ if (BIT(m_audio_regs.sacr0, SACR0_RST_BIT))
+ audio_controller_reset();
+
+ if (BIT(changed, SACR0_ENB_BIT))
+ {
+ audio_set_enabled(BIT(m_audio_regs.sacr0, SACR0_ENB_BIT));
+ }
+ else
+ {
+ if (changed & SACR0_TFTH_MASK)
+ audio_update_tx_fifo_levels();
+ if (changed & SACR0_RFTH_MASK)
+ audio_update_rx_fifo_levels();
+ }
+}
+
+void sa1111_device::sacr1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sacr1_w: Serial Audio Alternate Mode Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Alternate Mode Operation: %s\n", machine().describe_context(), BIT(data, SACR1_AMSL_BIT) ? "MSB-Justified" : "I2S");
+ LOGMASKED(LOG_AUDIO, "%s: Enable L3 Control Bus: %d\n", machine().describe_context(), BIT(data, SACR1_L3EN_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: L3 Control Bus Data Multi-Byte Transfer: %s\n", machine().describe_context(), BIT(data, SACR1_L3MB_BIT) ? "Multiple-Byte" : "Last Byte");
+ LOGMASKED(LOG_AUDIO, "%s: Disable Recording Function: %d\n", machine().describe_context(), BIT(data, SACR1_DREC_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Disable Replaying Function: %d\n", machine().describe_context(), BIT(data, SACR1_DRPL_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Enable L3 and I2S/MSB-Justified Loopback: %d\n", machine().describe_context(), BIT(data, SACR1_ENLBF_BIT));
+ COMBINE_DATA(&m_audio_regs.sacr1);
+}
+
+void sa1111_device::sacr2_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sacr2_w: Serial Audio AC-Link Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Transmit Slot 3 Valid (Left Out Valid): %d\n", machine().describe_context(), BIT(data, SACR2_TS3V_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit Slot 4 Valid (Right Out Valid): %d\n", machine().describe_context(), BIT(data, SACR2_TS4V_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Wake Up AC'97 Codec: %d\n", machine().describe_context(), BIT(data, SACR2_WKUP_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Disable Recording of AC-Link Interface: %d\n", machine().describe_context(), BIT(data, SACR2_DREC_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Disable Replaying of AC-Link Interface: %d\n", machine().describe_context(), BIT(data, SACR2_DRPL_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Enable AC-Link Loopback: %d\n", machine().describe_context(), BIT(data, SACR2_ENLBF_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Specify Reset# Signal to SYS_CLK Output: %s\n", machine().describe_context(), BIT(data, SACR2_RESET_BIT) ? "Inactive" : "Active-Low");
+ COMBINE_DATA(&m_audio_regs.sacr2);
+}
+
+void sa1111_device::sascr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sascr_w: Serial Audio Status Clear Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Clear Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SASCR_TUR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SASCR_ROR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear L3C/AC-Link Data Sent Status Bit: %d\n", machine().describe_context(), BIT(data, SASCR_DTS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear L3C/AC-Link Data Read Done Status Bit: %d\n", machine().describe_context(), BIT(data, SASCR_RDD_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear AC-Link Read Status Time-Out Bit: %d\n", machine().describe_context(), BIT(data, SASCR_STO_BIT));
+
+ if (BIT(data, SASCR_TUR_BIT))
+ {
+ m_audio_regs.sasr0 &= ~(1 << SASR_TUR_BIT);
+ m_audio_regs.sasr1 &= ~(1 << SASR_TUR_BIT);
+ set_irq_line(INT_AUDTUR, 0);
+ }
+ if (BIT(data, SASCR_ROR_BIT))
+ {
+ m_audio_regs.sasr0 &= ~(1 << SASR_ROR_BIT);
+ m_audio_regs.sasr1 &= ~(1 << SASR_ROR_BIT);
+ set_irq_line(INT_AUDROR, 0);
+ }
+ if (BIT(data, SASCR_DTS_BIT))
+ {
+ m_audio_regs.sasr0 &= ~(1 << SASR0_L3WD_BIT);
+ m_audio_regs.sasr1 &= ~(1 << SASR1_CADT_BIT);
+ set_irq_line(INT_AUDDTS, 0);
+ }
+ if (BIT(data, SASCR_RDD_BIT))
+ {
+ m_audio_regs.sasr0 &= ~(1 << SASR0_L3RD_BIT);
+ m_audio_regs.sasr1 &= ~(1 << SASR1_SADR_BIT);
+ set_irq_line(INT_AUDRDD, 0);
+ }
+ if (BIT(data, SASCR_STO_BIT))
+ {
+ m_audio_regs.sasr1 &= ~(1 << SASR1_RSTO_BIT);
+ set_irq_line(INT_AUDSTO, 0);
+ }
+}
+
+void sa1111_device::l3car_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: l3car_w: L3 Control Bus Address Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.l3car);
+ m_l3_addr_out((uint8_t)data);
+}
+
+void sa1111_device::l3cdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: l3cdr_w: L3 Control Bus Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.l3cdr);
+ m_l3_data_out((uint8_t)data);
+}
+
+void sa1111_device::accar_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: accar_w: AC-Link Command Address Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.accar);
+}
+
+void sa1111_device::accdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: accdr_w: AC-Link Command Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.accdr);
+}
+
+void sa1111_device::acsar_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: acsar_w: AC-Link Status Address Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.acsar);
+}
+
+void sa1111_device::acsdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: acsdr_w: AC-Link Status Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.acsdr);
+}
+
+void sa1111_device::sadtcs_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtcs_w: Serial Audio DMA Transmit Control/Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Transmit Enable: %d\n", machine().describe_context(), BIT(data, SADTCS_TDEN_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear Serial Audio DMA Transmit Buffer Done A: %d\n", machine().describe_context(), BIT(data, SADTCS_TDBDA_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Transmit Buffer Start Transfer A: %d\n", machine().describe_context(), BIT(data, SADTCS_TDSTA_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear Serial Audio DMA Transmit Buffer Done B: %d\n", machine().describe_context(), BIT(data, SADTCS_TDBDB_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Transmit Buffer Start Transfer B: %d\n", machine().describe_context(), BIT(data, SADTCS_TDSTB_BIT));
+
+ const uint32_t old = m_audio_regs.sadtcs;
+
+ static constexpr uint32_t start_mask = (1 << SADTCS_TDSTA_BIT) | (1 << SADTCS_TDSTB_BIT);
+ static constexpr uint32_t write_mask = (1 << SADTCS_TDEN_BIT) | start_mask;
+ m_audio_regs.sadtcs &= ~write_mask;
+ m_audio_regs.sadtcs |= data & write_mask & mem_mask;
+
+ if (BIT(data, SADTCS_TDBDA_BIT) || BIT(data, SADTCS_TDSTA_BIT))
+ {
+ LOGMASKED(LOG_AUDIO_DMA, "%s: sadtcs_w: Clearing done A bit, lowering AUDTXA IRQ\n", machine().describe_context());
+ m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDA_BIT);
+ set_irq_line(INT_AUDTXA, 0);
+ }
+ if (BIT(data, SADTCS_TDBDB_BIT) || BIT(data, SADTCS_TDSTB_BIT))
+ {
+ LOGMASKED(LOG_AUDIO_DMA, "%s: sadtcs_w: Clearing done B bit, lowering AUDTXB IRQ\n", machine().describe_context());
+ m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDB_BIT);
+ set_irq_line(INT_AUDTXB, 0);
+ }
+
+ const uint32_t changed = old ^ m_audio_regs.sadtcs;
+
+ if (BIT(changed, SADTCS_TDEN_BIT))
+ {
+ audio_set_tx_dma_enabled(BIT(changed, SADTCS_TDEN_BIT));
+ }
+ else if (BIT(m_audio_regs.sadtcs, SADTCS_TDEN_BIT) && (changed & start_mask))
+ {
+ audio_set_tx_dma_enabled(true);
+ }
+}
+
+void sa1111_device::sadtsa_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtsa_w: Serial Audio DMA Transmit Buffer Start Address Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadts[0]);
+}
+
+void sa1111_device::sadtca_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtca_w: Serial Audio DMA Transmit Buffer Count Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadtc[0]);
+}
+
+void sa1111_device::sadtsb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtsb_w: Serial Audio DMA Transmit Buffer Start Address Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadts[1]);
+}
+
+void sa1111_device::sadtcb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadtcb_w: Serial Audio DMA Transmit Buffer Count Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadtc[1]);
+}
+
+void sa1111_device::sadrcs_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrcs_w: Serial Audio DMA Receive Control/Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Receive Enable: %d\n", machine().describe_context(), BIT(data, SADRCS_RDEN_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear Serial Audio DMA Receive Buffer Done A: %d\n", machine().describe_context(), BIT(data, SADRCS_RDBDA_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Receive Buffer Start Transfer A: %d\n", machine().describe_context(), BIT(data, SADRCS_RDSTA_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Clear Serial Audio DMA Receive Buffer Done B: %d\n", machine().describe_context(), BIT(data, SADRCS_RDBDB_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Receive Buffer Start Transfer B: %d\n", machine().describe_context(), BIT(data, SADRCS_RDSTB_BIT));
+
+ const uint32_t old = m_audio_regs.sadrcs;
+
+ static constexpr uint32_t start_mask = (1 << SADRCS_RDSTA_BIT) | (1 << SADRCS_RDSTB_BIT);
+ static constexpr uint32_t write_mask = (1 << SADRCS_RDEN_BIT) | start_mask;
+ m_audio_regs.sadrcs &= ~write_mask;
+ m_audio_regs.sadrcs |= data & write_mask & mem_mask;
+
+ if (BIT(data, SADRCS_RDBDA_BIT))
+ {
+ m_audio_regs.sadrcs &= ~(1 << SADRCS_RDBDA_BIT);
+ set_irq_line(INT_AUDRXA, 0);
+ }
+ if (BIT(data, SADRCS_RDBDB_BIT))
+ {
+ m_audio_regs.sadrcs &= ~(1 << SADRCS_RDBDB_BIT);
+ set_irq_line(INT_AUDRXB, 0);
+ }
+
+ const uint32_t changed = old ^ m_audio_regs.sadrcs;
+
+ if (BIT(changed, SADRCS_RDEN_BIT))
+ {
+ audio_set_rx_dma_enabled(BIT(changed, SADRCS_RDEN_BIT));
+ }
+ else if (BIT(m_audio_regs.sadrcs, SADRCS_RDEN_BIT) && (changed & start_mask))
+ {
+ audio_set_rx_dma_enabled(true);
+ }
+}
+
+void sa1111_device::sadrsa_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrsa_w: Serial Audio DMA Receive Buffer Start Address Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadrs[0]);
+}
+
+void sa1111_device::sadrca_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrca_w: Serial Audio DMA Receive Buffer Count Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadrc[0]);
+}
+
+void sa1111_device::sadrsb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrsb_w: Serial Audio DMA Receive Buffer Start Address Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadrs[1]);
+}
+
+void sa1111_device::sadrcb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadrcb_w: Serial Audio DMA Receive Buffer Count Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_audio_regs.sadrc[1]);
+}
+
+void sa1111_device::saitr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: saitr_w: Serial Audio Interrupt Test Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SAITR_TFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SAITR_RFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SAITR_TUR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SAITR_ROR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Command Address/Data Transfer Done: %d\n", machine().describe_context(), BIT(data, SAITR_CADT_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Status Address/Data Receive Done: %d\n", machine().describe_context(), BIT(data, SAITR_SADR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Read Status Time-Out: %d\n", machine().describe_context(), BIT(data, SAITR_RSTO_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: DMA Transmit Buffer Done A: %d\n", machine().describe_context(), BIT(data, SAITR_TDBDA_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: DMA Transmit Buffer Done B: %d\n", machine().describe_context(), BIT(data, SAITR_TDBDB_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: DMA Receive Buffer Done A: %d\n", machine().describe_context(), BIT(data, SAITR_RDBDA_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: DMA Receive Buffer Done B: %d\n", machine().describe_context(), BIT(data, SAITR_RDBDB_BIT));
+}
+
+void sa1111_device::sadr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_AUDIO, "%s: sadr_w: Serial Audio Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ audio_tx_fifo_push(data);
+}
+
+/*
+
+ Intel SA-1111 SSP Serial Port
+
+ pg. 109 to 124 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+TIMER_CALLBACK_MEMBER(sa1111_device::ssp_rx_callback)
+{
+ // TODO: Implement receiving serial data rather than in bulk.
+}
+
+TIMER_CALLBACK_MEMBER(sa1111_device::ssp_tx_callback)
+{
+ // TODO: Implement transmitting data serially rather than in bulk.
+ if (m_ssp_regs.tx_fifo_count)
+ {
+ const uint16_t data = m_ssp_regs.tx_fifo[m_ssp_regs.tx_fifo_read_idx];
+ m_ssp_out(data);
+
+ m_ssp_regs.tx_fifo_read_idx = (m_ssp_regs.tx_fifo_read_idx + 1) % std::size(m_ssp_regs.tx_fifo);
+ m_ssp_regs.tx_fifo_count--;
+
+ m_ssp_regs.sspsr |= (1 << SSPSR_TNF_BIT);
+
+ ssp_update_tx_level();
+ }
+}
+
+void sa1111_device::ssp_update_enable_state()
+{
+ if (BIT(m_ssp_regs.sspcr0, SSPCR0_SSPEN_BIT))
+ {
+ const uint32_t tfl = (m_ssp_regs.sspsr & SSPSR_TFL_MASK) >> SSPSR_TFL_BIT;
+ const uint32_t rfl = (m_ssp_regs.sspsr & SSPSR_RFL_MASK) >> SSPSR_RFL_BIT;
+ const uint32_t tft = (m_ssp_regs.sspsr & SSPCR1_TFT_MASK) >> SSPCR1_TFT_BIT;
+ const uint32_t rft = (m_ssp_regs.sspsr & SSPCR1_RFT_MASK) >> SSPCR1_RFT_BIT;
+
+ if (tfl != (std::size(m_ssp_regs.tx_fifo) - 1))
+ m_ssp_regs.sspsr |= (1 << SSPSR_TNF_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_TNF_BIT);
+
+ if (rfl != 0)
+ m_ssp_regs.sspsr |= (1 << SSPSR_RNE_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_RNE_BIT);
+
+ if (tfl != 0 || rfl != 0)
+ m_ssp_regs.sspsr |= (1 << SSPSR_BSY_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_BSY_BIT);
+
+ if (tfl <= tft)
+ m_ssp_regs.sspsr |= (1 << SSPSR_TFS_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_TFS_BIT);
+
+ if (rfl <= rft)
+ m_ssp_regs.sspsr |= (1 << SSPSR_RFS_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_RFS_BIT);
+
+ uint64_t bit_count = (m_ssp_regs.sspcr0 & SSPCR0_DSS_MASK) >> SSPCR0_DSS_BIT;
+ uint32_t clock_rate = 2 * (((m_ssp_regs.sspcr0 & SSPCR0_SCR_MASK) >> SSPCR0_SCR_BIT) + 1);
+ attotime packet_rate = attotime::from_ticks(bit_count * clock_rate, 3686400);
+ m_ssp_regs.rx_timer->adjust(packet_rate, 0, packet_rate);
+ m_ssp_regs.tx_timer->adjust(packet_rate, 0, packet_rate);
+ }
+ else
+ {
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_TFS_BIT);
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_RFS_BIT);
+
+ m_ssp_regs.rx_fifo_read_idx = 0;
+ m_ssp_regs.rx_fifo_write_idx = 0;
+ m_ssp_regs.rx_fifo_count = 0;
+ m_ssp_regs.tx_fifo_read_idx = 0;
+ m_ssp_regs.tx_fifo_write_idx = 0;
+ m_ssp_regs.tx_fifo_count = 0;
+
+ m_ssp_regs.rx_timer->adjust(attotime::never);
+ m_ssp_regs.tx_timer->adjust(attotime::never);
+ }
+}
+
+void sa1111_device::ssp_update_rx_level()
+{
+ const uint32_t rfl = m_ssp_regs.rx_fifo_count;
+ m_ssp_regs.sspsr &= ~SSPSR_RFL_MASK;
+ m_ssp_regs.sspsr |= (rfl << SSPSR_RFL_BIT);
+
+ const uint32_t rft = (m_ssp_regs.sspcr1 & SSPCR1_RFT_MASK) >> SSPCR1_RFT_BIT;
+ if (rfl >= rft)
+ m_ssp_regs.sspsr |= (1 << SSPSR_RFS_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_RFS_BIT);
+}
+
+void sa1111_device::ssp_rx_fifo_push(const uint16_t data)
+{
+ if (m_ssp_regs.rx_fifo_count < std::size(m_ssp_regs.rx_fifo))
+ {
+ m_ssp_regs.rx_fifo[m_ssp_regs.rx_fifo_write_idx] = data;
+ m_ssp_regs.rx_fifo_write_idx = (m_ssp_regs.rx_fifo_write_idx + 1) % std::size(m_ssp_regs.rx_fifo);
+ m_ssp_regs.rx_fifo_count++;
+
+ m_ssp_regs.sspsr |= (1 << SSPSR_RNE_BIT);
+
+ ssp_update_rx_level();
+ }
+}
+
+void sa1111_device::ssp_update_tx_level()
+{
+ const uint32_t tfl = m_ssp_regs.tx_fifo_count;
+ m_ssp_regs.sspsr &= ~SSPSR_TFL_MASK;
+ m_ssp_regs.sspsr |= (tfl << SSPSR_TFL_BIT);
+
+ const uint32_t tft = (m_ssp_regs.sspcr1 & SSPCR1_TFT_MASK) >> SSPCR1_TFT_BIT;
+ if (tfl >= tft)
+ m_ssp_regs.sspsr |= (1 << SSPSR_TFS_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_TFS_BIT);
+}
+
+void sa1111_device::ssp_tx_fifo_push(const uint16_t data)
+{
+ if (m_ssp_regs.tx_fifo_count < std::size(m_ssp_regs.tx_fifo))
+ {
+ m_ssp_regs.tx_fifo[m_ssp_regs.tx_fifo_write_idx] = data;
+ m_ssp_regs.tx_fifo_write_idx = (m_ssp_regs.tx_fifo_write_idx + 1) % std::size(m_ssp_regs.tx_fifo);
+ m_ssp_regs.tx_fifo_count++;
+
+ if (m_ssp_regs.tx_fifo_count != std::size(m_ssp_regs.tx_fifo))
+ m_ssp_regs.sspsr |= (1 << SSPSR_TNF_BIT);
+ else
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_TNF_BIT);
+
+ ssp_update_tx_level();
+ }
+}
+
+uint16_t sa1111_device::ssp_rx_fifo_pop()
+{
+ uint16_t data = m_ssp_regs.rx_fifo[m_ssp_regs.rx_fifo_read_idx];
+ if (m_ssp_regs.rx_fifo_count)
+ {
+ m_ssp_regs.rx_fifo_read_idx = (m_ssp_regs.rx_fifo_read_idx + 1) % std::size(m_ssp_regs.rx_fifo);
+ m_ssp_regs.rx_fifo_count--;
+
+ if (m_ssp_regs.rx_fifo_count == 0)
+ m_ssp_regs.sspsr &= ~(1 << SSPSR_RNE_BIT);
+
+ ssp_update_rx_level();
+ }
+ return data;
+}
+
+uint32_t sa1111_device::sspcr0_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: sspcr0_r: SSP Control Register 0: %08x & %08x\n", machine().describe_context(), m_ssp_regs.sspcr0, mem_mask);
+ return m_ssp_regs.sspcr0;
+}
+
+uint32_t sa1111_device::sspcr1_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: sspcr1_r: SSP Control Register 1: %08x & %08x\n", machine().describe_context(), m_ssp_regs.sspcr1, mem_mask);
+ return m_ssp_regs.sspcr1;
+}
+
+uint32_t sa1111_device::sspsr_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_ssp_regs.sspsr;
+ LOGMASKED(LOG_SSP_HF, "%s: sspsr_r: SSP Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP_HF, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(data, SSPSR_TNF_BIT));
+ LOGMASKED(LOG_SSP_HF, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(data, SSPSR_RNE_BIT));
+ LOGMASKED(LOG_SSP_HF, "%s: Transmit/Receive In Progress: %d\n", machine().describe_context(), BIT(data, SSPSR_BSY_BIT));
+ LOGMASKED(LOG_SSP_HF, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SSPSR_TFS_BIT));
+ LOGMASKED(LOG_SSP_HF, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SSPSR_RFS_BIT));
+ LOGMASKED(LOG_SSP_HF, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SSPSR_ROR_BIT));
+ LOGMASKED(LOG_SSP_HF, "%s: Transmit FIFO Level: %02x\n", machine().describe_context(), (data & SSPSR_TFL_MASK) >> SSPSR_TFL_BIT);
+ LOGMASKED(LOG_SSP_HF, "%s: Receive FIFO Level: %02x\n", machine().describe_context(), (data & SSPSR_RFL_MASK) >> SSPSR_RFL_BIT);
+ return data;
+}
+
+uint32_t sa1111_device::sspdr_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = ssp_rx_fifo_pop();
+ LOGMASKED(LOG_SSP, "%s: sspdr_r: SSP Data Read Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
+}
+
+void sa1111_device::sspcr0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ static const char *const s_dss_sizes[16] =
+ {
+ "Invalid [1]", "Invalid [2]", "Invalid [3]", "4-bit",
+ "5-bit", "6-bit", "7-bit", "8-bit",
+ "9-bit", "10-bit", "11-bit", "12-bit",
+ "13-bit", "14-bit", "15-bit", "16-bit"
+ };
+ static const char *const s_frf_formats[4] = { "Motorola SPI", "TI Synchronous Serial", "National Microwire", "Reserved" };
+ LOGMASKED(LOG_SSP, "%s: sspcr0_w: SSP Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP, "%s: Data Size Select: %s\n", machine().describe_context(), s_dss_sizes[(data & SSPCR0_DSS_MASK) >> SSPCR0_DSS_BIT]);
+ LOGMASKED(LOG_SSP, "%s: Frame Format: %s\n", machine().describe_context(), s_frf_formats[(data & SSPCR0_FRF_MASK) >> SSPCR0_FRF_BIT]);
+ LOGMASKED(LOG_SSP, "%s: SSP Enable: %d\n", machine().describe_context(), BIT(data, SSPCR0_SSPEN_BIT));
+ LOGMASKED(LOG_SSP, "%s: Serial Clock Rate Divisor: %03x\n", machine().describe_context(), (data & SSPCR0_SCR_MASK) >> SSPCR0_SCR_BIT);
+ const uint32_t old = m_ssp_regs.sspcr0;
+ COMBINE_DATA(&m_ssp_regs.sspcr0);
+ const uint32_t changed = old ^ m_ssp_regs.sspcr0;
+ if (BIT(changed, SSPCR0_SSPEN_BIT))
+ ssp_update_enable_state();
+}
+
+void sa1111_device::sspcr1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: sspcr1_w: SSP Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP, "%s: Loopback Mode: %d\n", machine().describe_context(), BIT(data, SSPCR1_LBM_BIT));
+ LOGMASKED(LOG_SSP, "%s: Clock Polarity, Idle State: %s\n", machine().describe_context(), BIT(data, SSPCR1_SPO_BIT) ? "High" : "Low");
+ LOGMASKED(LOG_SSP, "%s: Clock Phase: %d\n", machine().describe_context(), BIT(data, SSPCR1_SPH_BIT));
+ LOGMASKED(LOG_SSP, "%s: Transmit FIFO Threshold: %02x\n", machine().describe_context(), (data & SSPCR1_TFT_MASK) >> SSPCR1_TFT_BIT);
+ LOGMASKED(LOG_SSP, "%s: Receive FIFO Threshold: %02x\n", machine().describe_context(), (data & SSPCR1_RFT_MASK) >> SSPCR1_RFT_BIT);
+ COMBINE_DATA(&m_ssp_regs.sspcr1);
+}
+
+void sa1111_device::sspsr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: sspsr_w: SSP Status Register (ignored, all read-only flags) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+void sa1111_device::sspitr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: sspitr_w: SSP Interrupt Test Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_SSP, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SSPITR_TFS_BIT));
+ LOGMASKED(LOG_SSP, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SSPITR_RFS_BIT));
+ LOGMASKED(LOG_SSP, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SSPITR_ROR_BIT));
+ COMBINE_DATA(&m_ssp_regs.sspitr);
+}
+
+void sa1111_device::sspdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SSP, "%s: sspdr_w: SSP Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ ssp_tx_fifo_push((uint16_t)data);
+}
+
+/*
+
+ Intel SA-1111 PS/2 Trackpad and Mouse Interfaces
+
+ pg. 125 to 131 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+uint32_t sa1111_device::track_kbdcr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbdcr_r: Track Pad Control Register: %08x & %08x\n", machine().describe_context(), m_track_regs.kbdcr, mem_mask);
+ return m_track_regs.kbdcr;
+}
+
+uint32_t sa1111_device::track_kbdstat_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_track_regs.kbdstat;
+ LOGMASKED(LOG_TRACK, "%s: track_kbdstat_r: Track Pad Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_TRACK, "%s: KBCLK Pin State: %d\n", machine().describe_context(), BIT(data, KBDSTAT_KBC_BIT));
+ LOGMASKED(LOG_TRACK, "%s: KBDATA Pin State: %d\n", machine().describe_context(), BIT(data, KBDSTAT_KBD_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Data Byte Parity Bit: %d\n", machine().describe_context(), BIT(data, KBDSTAT_RXP_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Track Pad Enabled: %d\n", machine().describe_context(), BIT(data, KBDSTAT_ENA_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Receiver Busy: %d\n", machine().describe_context(), BIT(data, KBDSTAT_RXB_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Receiver Full: %d\n", machine().describe_context(), BIT(data, KBDSTAT_RXF_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Transmitter Busy: %d\n", machine().describe_context(), BIT(data, KBDSTAT_TXB_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Transmitter Empty: %d\n", machine().describe_context(), BIT(data, KBDSTAT_TXE_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Stop Bit Error: %d\n", machine().describe_context(), BIT(data, KBDSTAT_STP_BIT));
+ return data;
+}
+
+uint32_t sa1111_device::track_kbddata_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbddata_r: Track Pad Received Data Byte: %08x & %08x\n", machine().describe_context(), m_track_regs.kbddata_rx, mem_mask);
+ return m_track_regs.kbddata_rx;
+}
+
+uint32_t sa1111_device::track_kbdclkdiv_r(offs_t offset, uint32_t mem_mask)
+{
+ static const char *const s_clkdiv_values[4] = { "8MHz", "4MHz", "2MHz", "Reserved" };
+ LOGMASKED(LOG_TRACK, "%s: track_kbdclkdiv_r: Track Pad Clock Division Register: %08x & %08x\n", machine().describe_context(), m_track_regs.kbdclkdiv, mem_mask);
+ LOGMASKED(LOG_TRACK, "%s: Incoming KbdClk: %s\n", machine().describe_context(), s_clkdiv_values[(m_track_regs.kbdclkdiv & KBDCLKDIV_DV_MASK) >> KBDCLKDIV_DV_BIT]);
+ return m_track_regs.kbdclkdiv;
+}
+
+uint32_t sa1111_device::track_kbdprecnt_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbdprecnt_r: Track Pad Clock Precount Register: %08x & %08x\n", machine().describe_context(), m_track_regs.kbdprecnt, mem_mask);
+ return m_track_regs.kbdprecnt;
+}
+
+uint32_t sa1111_device::mouse_kbdcr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdcr_r: Mouse Control Register: %08x & %08x\n", machine().describe_context(), m_mouse_regs.kbdcr, mem_mask);
+ return m_mouse_regs.kbdcr;
+}
+
+uint32_t sa1111_device::mouse_kbdstat_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_mouse_regs.kbdstat;
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdstat_r: Mouse Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_MOUSE, "%s: KBCLK Pin State: %d\n", machine().describe_context(), BIT(data, KBDSTAT_KBC_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: KBDATA Pin State: %d\n", machine().describe_context(), BIT(data, KBDSTAT_KBD_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Data Byte Parity Bit: %d\n", machine().describe_context(), BIT(data, KBDSTAT_RXP_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Mouse Enabled: %d\n", machine().describe_context(), BIT(data, KBDSTAT_ENA_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Receiver Busy: %d\n", machine().describe_context(), BIT(data, KBDSTAT_RXB_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Receiver Full: %d\n", machine().describe_context(), BIT(data, KBDSTAT_RXF_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Transmitter Busy: %d\n", machine().describe_context(), BIT(data, KBDSTAT_TXB_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Transmitter Empty: %d\n", machine().describe_context(), BIT(data, KBDSTAT_TXE_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Stop Bit Error: %d\n", machine().describe_context(), BIT(data, KBDSTAT_STP_BIT));
+ return data;
+}
+
+uint32_t sa1111_device::mouse_kbddata_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbddata_r: Mouse Received Data Byte: %08x & %08x\n", machine().describe_context(), m_mouse_regs.kbddata_rx, mem_mask);
+ return m_mouse_regs.kbddata_rx;
+}
+
+uint32_t sa1111_device::mouse_kbdclkdiv_r(offs_t offset, uint32_t mem_mask)
+{
+ static const char *const s_clkdiv_values[4] = { "8MHz", "4MHz", "2MHz", "Reserved" };
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdclkdiv_r: Mouse Clock Division Register: %08x & %08x\n", machine().describe_context(), m_mouse_regs.kbdclkdiv, mem_mask);
+ LOGMASKED(LOG_MOUSE, "%s: Incoming KbdClk: %s\n", machine().describe_context(), s_clkdiv_values[(m_mouse_regs.kbdclkdiv & KBDCLKDIV_DV_MASK) >> KBDCLKDIV_DV_BIT]);
+ return m_mouse_regs.kbdclkdiv;
+}
+
+uint32_t sa1111_device::mouse_kbdprecnt_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdprecnt_r: Mouse Clock Precount Register: %08x & %08x\n", machine().describe_context(), m_mouse_regs.kbdprecnt, mem_mask);
+ return m_mouse_regs.kbdprecnt;
+}
+
+void sa1111_device::track_kbdcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbdcr_w: Track Pad Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_TRACK, "%s: Force TPCLK Low: %d\n", machine().describe_context(), BIT(data, KBDCR_FKC_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Force TPDATA Low: %d\n", machine().describe_context(), BIT(data, KBDCR_FKD_BIT));
+ LOGMASKED(LOG_TRACK, "%s: Enable Track Pad: %d\n", machine().describe_context(), BIT(data, KBDCR_ENA_BIT));
+ COMBINE_DATA(&m_track_regs.kbdcr);
+}
+
+void sa1111_device::track_kbdstat_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbdstat_w: Track Pad Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_track_regs.kbdstat &= ~(data & mem_mask & (1 << KBDSTAT_STP_BIT));
+}
+
+void sa1111_device::track_kbddata_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbddata_w: Track Pad Transmit Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_track_regs.kbddata_tx);
+}
+
+void sa1111_device::track_kbdclkdiv_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbdclkdiv_w: Track Pad Clock Division Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_track_regs.kbdclkdiv);
+}
+
+void sa1111_device::track_kbdprecnt_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbdprecnt_w: Track Pad Clock Precount Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_track_regs.kbdprecnt);
+}
+
+void sa1111_device::track_kbditr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_TRACK, "%s: track_kbditr_w: Track Pad Interrupt Test Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_track_regs.kbditr);
+}
+
+void sa1111_device::mouse_kbdcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdcr_w: Mouse Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_MOUSE, "%s: Force TPCLK Low: %d\n", machine().describe_context(), BIT(data, KBDCR_FKC_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Force TPDATA Low: %d\n", machine().describe_context(), BIT(data, KBDCR_FKD_BIT));
+ LOGMASKED(LOG_MOUSE, "%s: Enable Mouse: %d\n", machine().describe_context(), BIT(data, KBDCR_ENA_BIT));
+ COMBINE_DATA(&m_mouse_regs.kbdcr);
+}
+
+void sa1111_device::mouse_kbdstat_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdstat_w: Mouse Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ m_mouse_regs.kbdstat &= ~(data & mem_mask & (1 << KBDSTAT_STP_BIT));
+}
+
+void sa1111_device::mouse_kbddata_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbddata_w: Mouse Transmit Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_mouse_regs.kbddata_tx);
+}
+
+void sa1111_device::mouse_kbdclkdiv_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdclkdiv_w: Mouse Clock Division Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_mouse_regs.kbdclkdiv);
+}
+
+void sa1111_device::mouse_kbdprecnt_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbdprecnt_w: Mouse Clock Precount Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_mouse_regs.kbdprecnt);
+}
+
+void sa1111_device::mouse_kbditr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_MOUSE, "%s: mouse_kbditr_w: Mouse Interrupt Test Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_mouse_regs.kbditr);
+}
+
+/*
+
+ Intel SA-1111 General-Purpose I/O Interface
+
+ pg. 133 to 138 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+void sa1111_device::gpio_in(const uint32_t line, const int state)
+{
+}
+
+void sa1111_device::gpio_update_direction(const uint32_t block, const uint32_t old_dir)
+{
+ const uint32_t new_outputs = old_dir & ~m_gpio_regs.ddr[block];
+ if (new_outputs)
+ {
+ for (uint32_t line = 0; line < 8; line++)
+ {
+ if (BIT(new_outputs, line))
+ {
+ m_gpio_out[block * 8 + line](BIT(m_gpio_regs.out_latch[block], line));
+ }
+ }
+ }
+}
+
+void sa1111_device::gpio_update_outputs(const uint32_t block, const uint32_t changed)
+{
+ uint32_t remaining_changed = changed;
+
+ for (uint32_t line = 0; line < 8 && remaining_changed != 0; line++)
+ {
+ if (BIT(remaining_changed, line))
+ {
+ m_gpio_out[block * 8 + line](BIT(m_gpio_regs.level[block], line));
+ remaining_changed &= ~(1 << line);
+ }
+ }
+}
+
+template <int Block>
+uint32_t sa1111_device::ddr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: ddr_r: GPIO Block %c Data Direction: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.ddr[Block], mem_mask);
+ return m_gpio_regs.ddr[Block];
+}
+
+template <int Block>
+uint32_t sa1111_device::drr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: drr_r: GPIO Block %c Data Value Register: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.level[Block], mem_mask);
+ return m_gpio_regs.level[Block];
+}
+
+template <int Block>
+uint32_t sa1111_device::sdr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: sdr_r: GPIO Block %c Sleep Direction: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.sdr[Block], mem_mask);
+ return m_gpio_regs.sdr[Block];
+}
+
+template <int Block>
+uint32_t sa1111_device::ssr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: ssr_r: GPIO Block %c Sleep State: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.ssr[Block], mem_mask);
+ return m_gpio_regs.ssr[Block];
+}
+
+template <int Block>
+void sa1111_device::ddr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: ddr_w: GPIO Block %c Data Direction = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
+ const uint32_t old = m_gpio_regs.ddr[Block];
+ COMBINE_DATA(&m_gpio_regs.ddr[Block]);
+ if (old != m_gpio_regs.ddr[Block])
+ gpio_update_direction(Block, old);
+}
+
+template <int Block>
+void sa1111_device::dwr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: dwr_w: GPIO Block %c Data Value Register = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
+ const uint32_t old = m_gpio_regs.level[Block];
+ COMBINE_DATA(&m_gpio_regs.out_latch[Block]);
+ m_gpio_regs.level[Block] = (m_gpio_regs.ddr[Block] & m_gpio_regs.in_latch[Block]) | (~m_gpio_regs.ddr[Block] & m_gpio_regs.out_latch[Block]);
+ if (old != m_gpio_regs.level[Block])
+ gpio_update_outputs(Block, old ^ m_gpio_regs.level[Block]);
+}
+
+template <int Block>
+void sa1111_device::sdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: sdr_w: GPIO Block %c Sleep Direction = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
+ COMBINE_DATA(&m_gpio_regs.sdr[Block]);
+}
+
+template <int Block>
+void sa1111_device::ssr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_GPIO, "%s: ssr_w: GPIO Block %c Sleep State = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
+ COMBINE_DATA(&m_gpio_regs.ssr[0]);
+}
+
+/*
+
+ Intel SA-1111 Interrupt Controller
+
+ pg. 139 to 146 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+void sa1111_device::set_irq_line(uint32_t line, int state)
+{
+ const uint32_t set = BIT(line, 5);
+ const uint32_t local_bit = line & 0x1f;
+ const uint32_t mask = (1 << local_bit);
+ const uint32_t old_raw = BIT(m_intc_regs.intraw[set], local_bit);
+ //LOGMASKED(LOG_INTC, "Setting IRQ line %d to state %d. Current intraw[%d] state %08x, bit state %d\n", line, state, set, m_intc_regs.intraw[set], old_raw);
+ if (old_raw == state)
+ return;
+
+ m_intc_regs.intraw[set] &= ~mask;
+ m_intc_regs.intraw[set] |= (state << local_bit);
+
+ const uint32_t falling_edge = BIT(m_intc_regs.intpol[set], local_bit);
+ const bool new_rising = (!old_raw && state && !falling_edge);
+ const bool new_falling = (old_raw && !state && falling_edge);
+
+ if (new_rising || new_falling)
+ m_intc_regs.intstat[set] |= mask;
+
+ if (BIT(m_intc_regs.inten[set], local_bit))
+ {
+ LOGMASKED(LOG_INTC, "IRQ line %d is enabled, updating interrupts\n", line);
+ update_interrupts();
+ }
+}
+
+void sa1111_device::update_interrupts()
+{
+ const bool any_interrupt = (m_intc_regs.intstat[0] & m_intc_regs.inten[0]) || (m_intc_regs.intstat[1] & m_intc_regs.inten[1]);
+ m_irq_out(any_interrupt);
+}
+
+template <int Set>
+uint32_t sa1111_device::inttest_r(offs_t offset, uint32_t mem_mask)
+{
+ if (Set == 0)
+ {
+ const uint32_t any_interrupts = ((m_intc_regs.inttest[0] | m_intc_regs.inttest[1]) != 0) ? 1 : 0;
+ LOGMASKED(LOG_INTC, "%s: inttest_r: Interrupt Test Register %d: %08x & %08x\n", machine().describe_context(), Set, any_interrupts, mem_mask);
+ return any_interrupts;
+ }
+ else
+ {
+ LOGMASKED(LOG_INTC, "%s: inttest_r: Interrupt Test Register %d: %08x & %08x\n", machine().describe_context(), Set, 0, mem_mask);
+ return 0;
+ }
+}
+
+template <int Set>
+uint32_t sa1111_device::inten_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: inten_r: Interrupt Enable Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.inten[Set], mem_mask);
+ return m_intc_regs.inten[Set];
+}
+
+template <int Set>
+uint32_t sa1111_device::intpol_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intpol_r: Interrupt Polarity Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.intpol[Set], mem_mask);
+ return m_intc_regs.intpol[Set];
+}
+
+uint32_t sa1111_device::inttstsel_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: inttstsel_r: Interrupt Test Mode Select Register: %08x & %08x\n", machine().describe_context(), m_intc_regs.inttstsel, mem_mask);
+ return m_intc_regs.inttstsel;
+}
+
+template <int Set>
+uint32_t sa1111_device::intstat_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intstat_r: Interrupt Status Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.intstat[Set], mem_mask);
+ return m_intc_regs.intstat[Set];
+}
+
+template <int Set>
+uint32_t sa1111_device::wake_en_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: wake_en_r: Interrupt Wake-Up Enable Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.wake_en[Set], mem_mask);
+ return m_intc_regs.wake_en[Set];
+}
+
+template <int Set>
+uint32_t sa1111_device::wake_pol_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: wake_pol_r: Interrupt Wake-Up Polarity Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.wake_pol[Set], mem_mask);
+ return m_intc_regs.wake_pol[Set];
+}
+
+template <int Set>
+void sa1111_device::inttest_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: inttest_w: Interrupt Test Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ COMBINE_DATA(&m_intc_regs.inttest[Set]);
+}
+
+template <int Set>
+void sa1111_device::inten_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: inten_w: Interrupt Enable Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ const uint32_t old = m_intc_regs.inten[Set];
+ COMBINE_DATA(&m_intc_regs.inten[Set]);
+ if (old != m_intc_regs.inten[Set] && (m_intc_regs.intstat[Set] & old) != 0)
+ {
+ update_interrupts();
+ }
+}
+
+template <int Set>
+void sa1111_device::intpol_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Polarity Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ COMBINE_DATA(&m_intc_regs.intpol[Set]);
+}
+
+void sa1111_device::inttstsel_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: inttestsel_w: Interrupt Test Mode Select Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_intc_regs.inttstsel);
+}
+
+template <int Set>
+void sa1111_device::intclr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Clear Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ const uint32_t old = m_intc_regs.intstat[Set];
+ m_intc_regs.intstat[Set] &= ~(data & mem_mask);
+ if (old != m_intc_regs.intstat[Set] && (old & m_intc_regs.inten[Set]) != 0)
+ {
+ update_interrupts();
+ }
+}
+
+template <int Set>
+void sa1111_device::intset_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: intset_w: Interrupt Set Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ const uint32_t old = m_intc_regs.intstat[Set];
+ m_intc_regs.intstat[Set] |= (data & mem_mask);
+ if (old != m_intc_regs.intstat[Set] && (m_intc_regs.intstat[Set] & m_intc_regs.inten[Set]) != 0)
+ {
+ update_interrupts();
+ }
+}
+
+template <int Set>
+void sa1111_device::wake_en_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: wake_en_w: Interrupt Wake-Up Enable Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ COMBINE_DATA(&m_intc_regs.wake_en[Set]);
+}
+
+template <int Set>
+void sa1111_device::wake_pol_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_INTC, "%s: wake_pol_w: Interrupt Wake-Up Polarity Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ COMBINE_DATA(&m_intc_regs.wake_pol[Set]);
+}
+
+/*
+
+ Intel SA-1111 PCMCIA Interface
+
+ pg. 147 to 160 Intel StrongARM SA-1111 Microprocessor Companion Chip Developer's Manual
+
+*/
+
+uint32_t sa1111_device::pccr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_CARD, "%s: pccr_r: PCMCIA Control Register: %08x & %08x\n", machine().describe_context(), m_card_regs.pccr, mem_mask);
+ return m_card_regs.pccr;
+}
+
+uint32_t sa1111_device::pcssr_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_CARD, "%s: pcssr_r: PCMCIA Sleep State Register: %08x & %08x\n", machine().describe_context(), m_card_regs.pcssr, mem_mask);
+ return m_card_regs.pcssr;
+}
+
+uint32_t sa1111_device::pcsr_r(offs_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_card_regs.pcsr;
+ LOGMASKED(LOG_CARD, "%s: pcsr_r: PCMCIA Status Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Ready: %d\n", machine().describe_context(), BIT(data, PCSR_S0R_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Ready: %d\n", machine().describe_context(), BIT(data, PCSR_S1R_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Card Detect: %d\n", machine().describe_context(), BIT(data, PCSR_S0CD_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Card Detect: %d\n", machine().describe_context(), BIT(data, PCSR_S1CD_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Voltage Sense 1: %d\n", machine().describe_context(), BIT(data, PCSR_S0VS1_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Voltage Sense 2: %d\n", machine().describe_context(), BIT(data, PCSR_S0VS2_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Voltage Sense 1: %d\n", machine().describe_context(), BIT(data, PCSR_S1VS1_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Voltage Sense 2: %d\n", machine().describe_context(), BIT(data, PCSR_S1VS2_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Write Protect: %d\n", machine().describe_context(), BIT(data, PCSR_S0WP_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Write Protect: %d\n", machine().describe_context(), BIT(data, PCSR_S1WP_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 BVD1: %d\n", machine().describe_context(), BIT(data, PCSR_S0BVD1_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 BVD2: %d\n", machine().describe_context(), BIT(data, PCSR_S0BVD2_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 BVD1: %d\n", machine().describe_context(), BIT(data, PCSR_S1BVD1_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 BVD2: %d\n", machine().describe_context(), BIT(data, PCSR_S1BVD2_BIT));
+ return data;
+}
+
+void sa1111_device::pccr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_CARD, "%s: pccr_w: PCMCIA Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Reset: %d\n", machine().describe_context(), BIT(data, PCCR_S0RST_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Reset: %d\n", machine().describe_context(), BIT(data, PCCR_S1RST_BIT));
+ LOGMASKED(LOG_CARD, "%s: Set Socket 0 Floating: %d\n", machine().describe_context(), BIT(data, PCCR_S0FLT_BIT));
+ LOGMASKED(LOG_CARD, "%s: Set Socket 1 Floating: %d\n", machine().describe_context(), BIT(data, PCCR_S1FLT_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 PWAIT Enable: %d\n", machine().describe_context(), BIT(data, PCCR_S0PWEN_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 PWAIT Enable: %d\n", machine().describe_context(), BIT(data, PCCR_S1PWEN_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Power Mode: %s\n", machine().describe_context(), BIT(data, PCCR_S0PSE_BIT) ? "5V" : "3V");
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Power Mode: %s\n", machine().describe_context(), BIT(data, PCCR_S1PSE_BIT) ? "5V" : "3V");
+ COMBINE_DATA(&m_card_regs.pccr);
+}
+
+void sa1111_device::pcssr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_CARD, "%s: pcssr_w: PCMCIA Sleep State Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_CARD, "%s: Socket 0 Sleep Mode: %d\n", machine().describe_context(), BIT(data, PCSSR_S0SLP_BIT));
+ LOGMASKED(LOG_CARD, "%s: Socket 1 Sleep Mode: %d\n", machine().describe_context(), BIT(data, PCSSR_S1SLP_BIT));
+ COMBINE_DATA(&m_card_regs.pcssr);
+}
+
+void sa1111_device::device_start()
+{
+ save_item(NAME(m_sbi_regs.skcr));
+ save_item(NAME(m_sbi_regs.smcr));
+ save_item(NAME(m_sbi_regs.skid));
+
+ save_item(NAME(m_sk_regs.skpcr));
+ save_item(NAME(m_sk_regs.skcdr));
+ save_item(NAME(m_sk_regs.skaud));
+ save_item(NAME(m_sk_regs.skpmc));
+ save_item(NAME(m_sk_regs.skptc));
+ save_item(NAME(m_sk_regs.skpen0));
+ save_item(NAME(m_sk_regs.skpwm0));
+ save_item(NAME(m_sk_regs.skpen1));
+ save_item(NAME(m_sk_regs.skpwm1));
+
+ save_item(NAME(m_usb_regs.ohci));
+ save_item(NAME(m_usb_regs.status));
+ save_item(NAME(m_usb_regs.reset));
+ save_item(NAME(m_usb_regs.int_test));
+ save_item(NAME(m_usb_regs.fifo));
+
+ save_item(NAME(m_audio_regs.sacr0));
+ save_item(NAME(m_audio_regs.sacr1));
+ save_item(NAME(m_audio_regs.sacr2));
+ save_item(NAME(m_audio_regs.sasr0));
+ save_item(NAME(m_audio_regs.sasr1));
+ save_item(NAME(m_audio_regs.l3car));
+ save_item(NAME(m_audio_regs.l3cdr));
+ save_item(NAME(m_audio_regs.accar));
+ save_item(NAME(m_audio_regs.accdr));
+ save_item(NAME(m_audio_regs.acsar));
+ save_item(NAME(m_audio_regs.acsdr));
+ save_item(NAME(m_audio_regs.sadtcs));
+ save_item(NAME(m_audio_regs.sadts));
+ save_item(NAME(m_audio_regs.sadtc));
+ save_item(NAME(m_audio_regs.sadta));
+ save_item(NAME(m_audio_regs.sadtcc));
+ save_item(NAME(m_audio_regs.sadrcs));
+ save_item(NAME(m_audio_regs.sadrs));
+ save_item(NAME(m_audio_regs.sadrc));
+ save_item(NAME(m_audio_regs.sadra));
+ save_item(NAME(m_audio_regs.sadrcc));
+ save_item(NAME(m_audio_regs.saitr));
+ save_item(NAME(m_audio_regs.rx_fifo));
+ save_item(NAME(m_audio_regs.rx_fifo_read_idx));
+ save_item(NAME(m_audio_regs.rx_fifo_write_idx));
+ save_item(NAME(m_audio_regs.rx_fifo_count));
+ save_item(NAME(m_audio_regs.tx_fifo));
+ save_item(NAME(m_audio_regs.tx_fifo_read_idx));
+ save_item(NAME(m_audio_regs.tx_fifo_write_idx));
+ save_item(NAME(m_audio_regs.tx_fifo_count));
+
+ save_item(NAME(m_ssp_regs.sspcr0));
+ save_item(NAME(m_ssp_regs.sspcr1));
+ save_item(NAME(m_ssp_regs.sspsr));
+ save_item(NAME(m_ssp_regs.sspitr));
+ save_item(NAME(m_ssp_regs.rx_fifo));
+ save_item(NAME(m_ssp_regs.rx_fifo_read_idx));
+ save_item(NAME(m_ssp_regs.rx_fifo_write_idx));
+ save_item(NAME(m_ssp_regs.rx_fifo_count));
+ save_item(NAME(m_ssp_regs.tx_fifo));
+ save_item(NAME(m_ssp_regs.tx_fifo_read_idx));
+ save_item(NAME(m_ssp_regs.tx_fifo_write_idx));
+ save_item(NAME(m_ssp_regs.tx_fifo_count));
+
+ save_item(NAME(m_track_regs.kbdcr));
+ save_item(NAME(m_track_regs.kbdstat));
+ save_item(NAME(m_track_regs.kbddata_tx));
+ save_item(NAME(m_track_regs.kbddata_rx));
+ save_item(NAME(m_track_regs.kbdclkdiv));
+ save_item(NAME(m_track_regs.kbdprecnt));
+ save_item(NAME(m_track_regs.kbditr));
+
+ save_item(NAME(m_mouse_regs.kbdcr));
+ save_item(NAME(m_mouse_regs.kbdstat));
+ save_item(NAME(m_mouse_regs.kbddata_tx));
+ save_item(NAME(m_mouse_regs.kbddata_rx));
+ save_item(NAME(m_mouse_regs.kbdclkdiv));
+ save_item(NAME(m_mouse_regs.kbdprecnt));
+ save_item(NAME(m_mouse_regs.kbditr));
+
+ save_item(NAME(m_gpio_regs.ddr));
+ save_item(NAME(m_gpio_regs.level));
+ save_item(NAME(m_gpio_regs.sdr));
+ save_item(NAME(m_gpio_regs.ssr));
+ save_item(NAME(m_gpio_regs.out_latch));
+ save_item(NAME(m_gpio_regs.in_latch));
+
+ save_item(NAME(m_intc_regs.inttest));
+ save_item(NAME(m_intc_regs.inten));
+ save_item(NAME(m_intc_regs.intpol));
+ save_item(NAME(m_intc_regs.inttstsel));
+ save_item(NAME(m_intc_regs.intstat));
+ save_item(NAME(m_intc_regs.wake_en));
+ save_item(NAME(m_intc_regs.wake_pol));
+ save_item(NAME(m_intc_regs.intraw));
+
+ save_item(NAME(m_card_regs.pccr));
+ save_item(NAME(m_card_regs.pcssr));
+ save_item(NAME(m_card_regs.pcsr));
+
+ m_audio_regs.rx_timer = timer_alloc(FUNC(sa1111_device::audio_rx_callback), this);
+ m_audio_regs.rx_dma_timer = timer_alloc(FUNC(sa1111_device::audio_rx_dma_callback), this);
+ m_audio_regs.tx_timer = timer_alloc(FUNC(sa1111_device::audio_tx_callback), this);
+ m_audio_regs.tx_dma_timer = timer_alloc(FUNC(sa1111_device::audio_tx_dma_callback), this);
+
+ m_ssp_regs.rx_timer = timer_alloc(FUNC(sa1111_device::ssp_rx_callback), this);
+ m_ssp_regs.tx_timer = timer_alloc(FUNC(sa1111_device::ssp_tx_callback), this);
+}
+
+void sa1111_device::device_reset()
+{
+ m_sbi_regs.skcr = (1 << SKCR_RDY_BIT);
+ m_sbi_regs.smcr = (1 << SMCR_CLAT_BIT) | (5 << SMCR_DRAC_BIT) | (1 << SMCR_DTIM_BIT);
+ m_sbi_regs.skid = 0x690cc211;
+
+ m_sk_regs.skpcr = 0;
+ m_sk_regs.skcdr = (0x4c << SKCDR_FBD_BIT);
+ m_sk_regs.skaud = (0x18 << SKAUD_ACD_BIT);
+ m_sk_regs.skpmc = (0x11 << SKPMC_PMCD_BIT);
+ m_sk_regs.skptc = (0x11 << SKPTC_PTCD_BIT);
+ m_sk_regs.skpen0 = 0;
+ m_sk_regs.skpwm0 = 0;
+ m_sk_regs.skpen1 = 0;
+ m_sk_regs.skpwm1 = 0;
+
+ std::fill(std::begin(m_usb_regs.ohci), std::end(m_usb_regs.ohci), 0);
+ m_usb_regs.status = 0;
+ m_usb_regs.reset = (1 << USBRST_FHR_BIT) | (1 << USBRST_FIR_BIT);
+ m_usb_regs.int_test = 0;
+ std::fill(std::begin(m_usb_regs.fifo), std::end(m_usb_regs.fifo), 0);
+
+ m_audio_regs.sacr0 = (0x7 << SACR0_RFTH_BIT) | (0x7 << SACR0_TFTH_BIT);
+ m_audio_regs.sacr1 = 0;
+ m_audio_regs.sacr2 = 0;
+ m_audio_regs.sasr0 = 0;
+ m_audio_regs.sasr1 = 0;
+ m_audio_regs.l3car = 0;
+ m_audio_regs.l3cdr = 0;
+ m_audio_regs.accar = 0;
+ m_audio_regs.accdr = 0;
+ m_audio_regs.acsar = 0;
+ m_audio_regs.acsdr = 0;
+ m_audio_regs.sadtcs = 0;
+ std::fill_n(&m_audio_regs.sadts[0], 2, 0);
+ std::fill_n(&m_audio_regs.sadtc[0], 2, 0);
+ m_audio_regs.sadta = 0;
+ m_audio_regs.sadtcc = 0;
+ m_audio_regs.sadrcs = 0;
+ std::fill_n(&m_audio_regs.sadrs[0], 2, 0);
+ std::fill_n(&m_audio_regs.sadrc[0], 2, 0);
+ m_audio_regs.sadra = 0;
+ m_audio_regs.sadrcc = 0;
+ m_audio_regs.saitr = 0;
+ std::fill(std::begin(m_audio_regs.rx_fifo), std::end(m_audio_regs.rx_fifo), 0);
+ m_audio_regs.rx_fifo_read_idx = 0;
+ m_audio_regs.rx_fifo_write_idx = 0;
+ m_audio_regs.rx_fifo_count = 0;
+ m_audio_regs.rx_timer->adjust(attotime::never);
+ m_audio_regs.rx_dma_timer->adjust(attotime::never);
+ std::fill(std::begin(m_audio_regs.tx_fifo), std::end(m_audio_regs.tx_fifo), 0);
+ m_audio_regs.tx_fifo_read_idx = 0;
+ m_audio_regs.tx_fifo_write_idx = 0;
+ m_audio_regs.tx_fifo_count = 0;
+ m_audio_regs.tx_timer->adjust(attotime::never);
+ m_audio_regs.tx_dma_timer->adjust(attotime::never);
+
+ m_ssp_regs.sspcr0 = 0;
+ m_ssp_regs.sspcr1 = (0x7 << SSPCR1_RFT_BIT) | (0x7 << SSPCR1_TFT_BIT);
+ m_ssp_regs.sspsr = 0;
+ m_ssp_regs.sspitr = 0;
+ std::fill(std::begin(m_ssp_regs.rx_fifo), std::end(m_ssp_regs.rx_fifo), 0);
+ m_ssp_regs.rx_fifo_read_idx = 0;
+ m_ssp_regs.rx_fifo_write_idx = 0;
+ m_ssp_regs.rx_fifo_count = 0;
+ m_ssp_regs.rx_timer->adjust(attotime::never);
+ std::fill(std::begin(m_ssp_regs.tx_fifo), std::end(m_ssp_regs.tx_fifo), 0);
+ m_ssp_regs.tx_fifo_read_idx = 0;
+ m_ssp_regs.tx_fifo_write_idx = 0;
+ m_ssp_regs.tx_fifo_count = 0;
+ m_ssp_regs.tx_timer->adjust(attotime::never);
+
+ for (ps2_regs &regs : { std::ref(m_track_regs), std::ref(m_mouse_regs) })
+ {
+ regs.kbdcr = 0;
+ regs.kbdstat = 0;
+ regs.kbddata_tx = 0;
+ regs.kbddata_rx = 0;
+ regs.kbdclkdiv = 0;
+ regs.kbdprecnt = 0;
+ regs.kbditr = 0;
+ }
+
+ std::fill(std::begin(m_gpio_regs.ddr), std::end(m_gpio_regs.ddr), 0);
+ std::fill(std::begin(m_gpio_regs.level), std::end(m_gpio_regs.level), 0);
+ std::fill(std::begin(m_gpio_regs.sdr), std::end(m_gpio_regs.sdr), 0);
+ std::fill(std::begin(m_gpio_regs.ssr), std::end(m_gpio_regs.ssr), 0);
+ std::fill(std::begin(m_gpio_regs.out_latch), std::end(m_gpio_regs.out_latch), 0);
+ std::fill(std::begin(m_gpio_regs.in_latch), std::end(m_gpio_regs.in_latch), 0);
+
+ std::fill(std::begin(m_intc_regs.inttest), std::end(m_intc_regs.inttest), 0);
+ std::fill(std::begin(m_intc_regs.inten), std::end(m_intc_regs.inten), 0);
+ std::fill(std::begin(m_intc_regs.intpol), std::end(m_intc_regs.intpol), 0);
+ m_intc_regs.inttstsel = 0;
+ std::fill(std::begin(m_intc_regs.intstat), std::end(m_intc_regs.intstat), 0);
+ std::fill(std::begin(m_intc_regs.wake_en), std::end(m_intc_regs.wake_en), 0);
+ std::fill(std::begin(m_intc_regs.wake_pol), std::end(m_intc_regs.wake_pol), 0);
+ std::fill(std::begin(m_intc_regs.intraw), std::end(m_intc_regs.intraw), 0);
+
+ m_card_regs.pccr = 0;
+ m_card_regs.pcssr = 0;
+ m_card_regs.pcsr = 0x000000fc;
+}
+
+void sa1111_device::device_add_mconfig(machine_config &config)
+{
+}
diff --git a/src/devices/machine/sa1111.h b/src/devices/machine/sa1111.h
new file mode 100644
index 00000000000..46cf6779179
--- /dev/null
+++ b/src/devices/machine/sa1111.h
@@ -0,0 +1,689 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Intel SA1111 Microprocessor Companion Chip skeleton
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_SA1111
+#define MAME_MACHINE_SA1111
+
+#pragma once
+
+#include "cpu/arm7/arm7.h"
+#include "cpu/arm7/arm7core.h"
+
+class sa1111_device : public device_t
+{
+public:
+ template <typename T>
+ sa1111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag)
+ : sa1111_device(mconfig, tag, owner, clock)
+ {
+ m_maincpu.set_tag(std::forward<T>(cpu_tag));
+ }
+
+ sa1111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T> void set_audio_codec_tag(T &&tag) { m_audio_codec.set_tag(std::forward<T>(tag)); }
+
+ auto irq_out() { return m_irq_out.bind(); }
+
+ template <int Line> void pa_in(int state) { gpio_in(0 + Line, state); }
+ template <int Line> void pb_in(int state) { gpio_in(8 + Line, state); }
+ template <int Line> void pc_in(int state) { gpio_in(16 + Line, state); }
+ template <int Line> auto pa_out() { return m_gpio_out[0 + Line].bind(); }
+ template <int Line> auto pb_out() { return m_gpio_out[8 + Line].bind(); }
+ template <int Line> auto pc_out() { return m_gpio_out[16 + Line].bind(); }
+
+ void ssp_in(uint16_t data) { ssp_rx_fifo_push(data); }
+ auto ssp_out() { return m_ssp_out.bind(); }
+
+ auto l3_addr_out() { return m_l3_addr_out.bind(); }
+ auto l3_data_out() { return m_l3_data_out.bind(); }
+ auto i2s_out() { return m_i2s_out.bind(); }
+
+ void l3wd_in(int state);
+
+ void map(address_map &map);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ void set_irq_line(uint32_t line, int state);
+ void update_interrupts();
+
+ TIMER_CALLBACK_MEMBER(ssp_rx_callback);
+ TIMER_CALLBACK_MEMBER(ssp_tx_callback);
+
+ TIMER_CALLBACK_MEMBER(audio_rx_dma_callback);
+ TIMER_CALLBACK_MEMBER(audio_rx_callback);
+ TIMER_CALLBACK_MEMBER(audio_tx_dma_callback);
+ TIMER_CALLBACK_MEMBER(audio_tx_callback);
+ void audio_update_mode();
+ void audio_clear_interrupts();
+ void audio_set_enabled(bool enabled);
+ void audio_controller_reset();
+ void audio_set_tx_dma_enabled(bool enabled);
+ void audio_set_rx_dma_enabled(bool enabled);
+ void audio_start_tx_dma(const uint32_t buf);
+ void audio_start_rx_dma(const uint32_t buf);
+ void audio_update_tx_fifo_levels();
+ void audio_update_rx_fifo_levels();
+ void audio_update_busy_flag();
+ void audio_tx_fifo_push(uint32_t data);
+ uint32_t audio_tx_fifo_pop();
+ void audio_rx_fifo_push(uint32_t data);
+ uint32_t audio_rx_fifo_pop();
+
+ uint32_t unknown_r(offs_t offset, uint32_t mem_mask);
+ void unknown_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t skcr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t smcr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skid_r(offs_t offset, uint32_t mem_mask);
+ void skcr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void smcr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t skpcr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skcdr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skaud_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skpmc_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skptc_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skpen0_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skpwm0_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skpen1_r(offs_t offset, uint32_t mem_mask);
+ uint32_t skpwm1_r(offs_t offset, uint32_t mem_mask);
+ void skpcr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skcdr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skaud_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skpmc_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skptc_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skpen0_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skpwm0_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skpen1_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void skpwm1_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t ohci_r(offs_t offset, uint32_t mem_mask);
+ uint32_t usb_status_r(offs_t offset, uint32_t mem_mask);
+ uint32_t usb_reset_r(offs_t offset, uint32_t mem_mask);
+ uint32_t usb_fifo_r(offs_t offset, uint32_t mem_mask);
+ void ohci_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void usb_reset_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void usb_int_test_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t sacr0_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sacr1_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sacr2_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sasr0_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sasr1_r(offs_t offset, uint32_t mem_mask);
+ uint32_t l3car_r(offs_t offset, uint32_t mem_mask);
+ uint32_t l3cdr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t accar_r(offs_t offset, uint32_t mem_mask);
+ uint32_t accdr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t acsar_r(offs_t offset, uint32_t mem_mask);
+ uint32_t acsdr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadtcs_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadtsa_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadtca_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadtsb_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadtcb_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadrcs_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadrsa_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadrca_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadrsb_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadrcb_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sadr_r(offs_t offset, uint32_t mem_mask);
+ void sacr0_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sacr1_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sacr2_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sascr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void l3car_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void l3cdr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void accar_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void accdr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void acsar_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void acsdr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadtcs_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadtsa_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadtca_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadtsb_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadtcb_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadrcs_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadrsa_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadrca_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadrsb_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadrcb_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void saitr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sadr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t sspcr0_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sspcr1_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sspsr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t sspdr_r(offs_t offset, uint32_t mem_mask);
+ void sspcr0_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sspcr1_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sspsr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sspitr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void sspdr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t track_kbdcr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t track_kbdstat_r(offs_t offset, uint32_t mem_mask);
+ uint32_t track_kbddata_r(offs_t offset, uint32_t mem_mask);
+ uint32_t track_kbdclkdiv_r(offs_t offset, uint32_t mem_mask);
+ uint32_t track_kbdprecnt_r(offs_t offset, uint32_t mem_mask);
+ void track_kbdcr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void track_kbdstat_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void track_kbddata_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void track_kbdclkdiv_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void track_kbdprecnt_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void track_kbditr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t mouse_kbdcr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t mouse_kbdstat_r(offs_t offset, uint32_t mem_mask);
+ uint32_t mouse_kbddata_r(offs_t offset, uint32_t mem_mask);
+ uint32_t mouse_kbdclkdiv_r(offs_t offset, uint32_t mem_mask);
+ uint32_t mouse_kbdprecnt_r(offs_t offset, uint32_t mem_mask);
+ void mouse_kbdcr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void mouse_kbdstat_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void mouse_kbddata_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void mouse_kbdclkdiv_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void mouse_kbdprecnt_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void mouse_kbditr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ template <int Block> uint32_t ddr_r(offs_t offset, uint32_t mem_mask);
+ template <int Block> uint32_t drr_r(offs_t offset, uint32_t mem_mask);
+ template <int Block> uint32_t sdr_r(offs_t offset, uint32_t mem_mask);
+ template <int Block> uint32_t ssr_r(offs_t offset, uint32_t mem_mask);
+ template <int Block> void ddr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Block> void dwr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Block> void sdr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Block> void ssr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ template <int Set> uint32_t inttest_r(offs_t offset, uint32_t mem_mask);
+ template <int Set> uint32_t inten_r(offs_t offset, uint32_t mem_mask);
+ template <int Set> uint32_t intpol_r(offs_t offset, uint32_t mem_mask);
+ uint32_t inttstsel_r(offs_t offset, uint32_t mem_mask);
+ template <int Set> uint32_t intstat_r(offs_t offset, uint32_t mem_mask);
+ template <int Set> uint32_t wake_en_r(offs_t offset, uint32_t mem_mask);
+ template <int Set> uint32_t wake_pol_r(offs_t offset, uint32_t mem_mask);
+ template <int Set> void inttest_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Set> void inten_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Set> void intpol_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void inttstsel_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Set> void intclr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Set> void intset_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Set> void wake_en_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ template <int Set> void wake_pol_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ uint32_t pccr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t pcssr_r(offs_t offset, uint32_t mem_mask);
+ uint32_t pcsr_r(offs_t offset, uint32_t mem_mask);
+ void pccr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+ void pcssr_w(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+ void ssp_update_enable_state();
+ void ssp_update_rx_level();
+ void ssp_update_tx_level();
+ void ssp_rx_fifo_push(const uint16_t data);
+ void ssp_tx_fifo_push(const uint16_t data);
+ uint16_t ssp_rx_fifo_pop();
+
+ void gpio_in(const uint32_t line, const int state);
+ void gpio_update_direction(const uint32_t block, const uint32_t old_dir);
+ void gpio_update_outputs(const uint32_t block, const uint32_t changed);
+
+ // register contents
+ enum : uint32_t
+ {
+ SKCR_PLLB_BIT = 0,
+ SKCR_RCLK_BIT = 1,
+ SKCR_SLEEP_BIT = 2,
+ SKCR_DOZE_BIT = 3,
+ SKCR_VCO_BIT = 4,
+ SKCR_SCANTST_BIT = 5,
+ SKCR_CLKTST_BIT = 6,
+ SKCR_RDY_BIT = 7,
+ SKCR_SACMDSL_BIT = 8,
+ SKCR_OPPC_BIT = 9,
+ SKCR_PII_BIT = 10,
+ SKCR_UIOTEN_BIT = 11,
+ SKCR_OEEN_BIT = 12,
+
+ SMCR_DTIM_BIT = 0,
+ SMCR_MBGE_BIT = 1,
+ SMCR_DRAC_BIT = 2,
+ SMCR_DRAC_MASK = 0x0000001c,
+ SMCR_CLAT_BIT = 5,
+
+ SKPCR_UCLKE_BIT = 0,
+ SKPCR_ACCLKE_BIT = 1,
+ SKPCR_ISCLKE_BIT = 2,
+ SKPCR_L3CLKE_BIT = 3,
+ SKPCR_SCLKE_BIT = 4,
+ SKPCR_PMCLKE_BIT = 5,
+ SKPCR_PTCLKE_BIT = 6,
+ SKPCR_DCLKE_BIT = 7,
+ SKPCR_PWMCLKE_BIT = 8,
+
+ SKCDR_FBD_BIT = 0,
+ SKCDR_FBD_MASK = 0x0000007f,
+ SKCDR_IPD_BIT = 7,
+ SKCDR_IPD_MASK = 0x00000f80,
+ SKCDR_OPD_BIT = 12,
+ SKCDR_OPD_MASK = 0x00003000,
+ SKCDR_OPS_BIT = 14,
+
+ SKAUD_ACD_BIT = 0,
+ SKAUD_ACD_MASK = 0x0000007f,
+
+ SKPMC_PMCD_BIT = 0,
+ SKPMC_PMCD_MASK = 0x000000ff,
+
+ SKPTC_PTCD_BIT = 0,
+ SKPTC_PTCD_MASK = 0x000000ff,
+
+ SKPEN0_PWM0EN_BIT = 0,
+
+ SKPWM0_PWM0CK_BIT = 0,
+ SKPWM0_PWM0CK_MASK = 0x000000ff,
+
+ SKPEN1_PWM1EN_BIT = 0,
+
+ SKPWM1_PWM1CK_BIT = 0,
+ SKPWM1_PWM1CK_MASK = 0x000000ff,
+
+ USBSTAT_IHRW_BIT = 7,
+ USBSTAT_IHBA_BIT = 8,
+ USBSTAT_NHT_BIT = 9,
+ USBSTAT_NHFCT_BIT = 10,
+ USBSTAT_UPRT_BIT = 11,
+
+ USBRST_FIR_BIT = 0,
+ USBRST_FHR_BIT = 1,
+ USBRST_CGR_BIT = 2,
+ USBRST_SSDC_BIT = 3,
+ USBRST_UIT_BIT = 4,
+ USBRST_SSE_BIT = 5,
+ USBRST_PSPL_BIT = 6,
+ USBRST_PCPL_BIT = 7,
+
+ USBINT_IHRWT_BIT = 7,
+ USBINT_IHBAT_BIT = 8,
+ USBINT_NHT_BIT = 9,
+ USBINT_NHFCT_BIT = 10,
+ USBINT_UPRT_BIT = 11,
+
+ SACR0_ENB_BIT = 0,
+ SACR0_BCKD_BIT = 2,
+ SACR0_RST_BIT = 3,
+ SACR0_TFTH_BIT = 8,
+ SACR0_TFTH_MASK = 0x00000f00,
+ SACR0_RFTH_BIT = 12,
+ SACR0_RFTH_MASK = 0x0000f000,
+
+ SACR1_AMSL_BIT = 0,
+ SACR1_L3EN_BIT = 1,
+ SACR1_L3MB_BIT = 2,
+ SACR1_DREC_BIT = 3,
+ SACR1_DRPL_BIT = 4,
+ SACR1_ENLBF_BIT = 5,
+
+ SACR2_TS3V_BIT = 0,
+ SACR2_TS4V_BIT = 1,
+ SACR2_WKUP_BIT = 2,
+ SACR2_DREC_BIT = 3,
+ SACR2_DRPL_BIT = 4,
+ SACR2_ENLBF_BIT = 5,
+ SACR2_RESET_BIT = 6,
+
+ SASCR_TUR_BIT = 5,
+ SASCR_ROR_BIT = 6,
+ SASCR_DTS_BIT = 16,
+ SASCR_RDD_BIT = 17,
+ SASCR_STO_BIT = 18,
+
+ SASR_TNF_BIT = 0,
+ SASR_RNE_BIT = 1,
+ SASR_BSY_BIT = 2,
+ SASR_TFS_BIT = 3,
+ SASR_RFS_BIT = 4,
+ SASR_TUR_BIT = 5,
+ SASR_ROR_BIT = 6,
+ SASR_TFL_BIT = 8,
+ SASR_TFL_MASK = 0x00000f00,
+ SASR_RFL_BIT = 12,
+ SASR_RFL_MASK = 0x0000f000,
+ SASR_SEND_BIT = 16,
+ SASR_RECV_BIT = 17,
+
+ SASR0_L3WD_BIT = 16,
+ SASR0_L3RD_BIT = 17,
+
+ SASR1_CADT_BIT = 16,
+ SASR1_SADR_BIT = 17,
+ SASR1_RSTO_BIT = 18,
+ SASR1_CLPM_BIT = 19,
+ SASR1_CRDY_BIT = 20,
+ SASR1_RS3V_BIT = 21,
+ SASR1_RS4V_BIT = 22,
+
+ SADTCS_TDEN_BIT = 0,
+ SADTCS_TDBDA_BIT = 3,
+ SADTCS_TDSTA_BIT = 4,
+ SADTCS_TDBDB_BIT = 5,
+ SADTCS_TDSTB_BIT = 6,
+ SADTCS_TBIU_BIT = 7,
+
+ SADRCS_RDEN_BIT = 0,
+ SADRCS_RDBDA_BIT = 3,
+ SADRCS_RDSTA_BIT = 4,
+ SADRCS_RDBDB_BIT = 5,
+ SADRCS_RDSTB_BIT = 6,
+ SADRCS_RBIU_BIT = 7,
+
+ SAITR_TFS_BIT = 0,
+ SAITR_RFS_BIT = 1,
+ SAITR_TUR_BIT = 2,
+ SAITR_ROR_BIT = 3,
+ SAITR_CADT_BIT = 4,
+ SAITR_SADR_BIT = 5,
+ SAITR_RSTO_BIT = 6,
+ SAITR_TDBDA_BIT = 8,
+ SAITR_TDBDB_BIT = 9,
+ SAITR_RDBDA_BIT = 10,
+ SAITR_RDBDB_BIT = 11,
+
+ SSPCR0_DSS_BIT = 0,
+ SSPCR0_DSS_MASK = 0x0000000f,
+ SSPCR0_FRF_BIT = 4,
+ SSPCR0_FRF_MASK = 0x00000030,
+ SSPCR0_FRF_SPI = 0,
+ SSPCR0_FRF_SSP = 1,
+ SSPCR0_FRF_MWIRE = 2,
+ SSPCR0_FRF_RESV = 3,
+ SSPCR0_SSPEN_BIT = 7,
+ SSPCR0_SCR_BIT = 8,
+ SSPCR0_SCR_MASK = 0x0000ff00,
+
+ SSPCR1_LBM_BIT = 2,
+ SSPCR1_SPO_BIT = 3,
+ SSPCR1_SPH_BIT = 4,
+ SSPCR1_TFT_BIT = 7,
+ SSPCR1_TFT_MASK = 0x00000780,
+ SSPCR1_RFT_BIT = 11,
+ SSPCR1_RFT_MASK = 0x00007800,
+
+ SSPSR_TNF_BIT = 2,
+ SSPSR_RNE_BIT = 3,
+ SSPSR_BSY_BIT = 4,
+ SSPSR_TFS_BIT = 5,
+ SSPSR_RFS_BIT = 6,
+ SSPSR_ROR_BIT = 7,
+ SSPSR_TFL_BIT = 8,
+ SSPSR_TFL_MASK = 0x00000f00,
+ SSPSR_RFL_BIT = 12,
+ SSPSR_RFL_MASK = 0x0000f000,
+
+ SSPITR_TFS_BIT = 2,
+ SSPITR_RFS_BIT = 3,
+ SSPITR_ROR_BIT = 4,
+
+ KBDCR_FKC_BIT = 0,
+ KBDCR_FKD_BIT = 1,
+ KBDCR_ENA_BIT = 3,
+
+ KBDSTAT_KBC_BIT = 0,
+ KBDSTAT_KBD_BIT = 1,
+ KBDSTAT_RXP_BIT = 2,
+ KBDSTAT_ENA_BIT = 3,
+ KBDSTAT_RXB_BIT = 4,
+ KBDSTAT_RXF_BIT = 5,
+ KBDSTAT_TXB_BIT = 6,
+ KBDSTAT_TXE_BIT = 7,
+ KBDSTAT_STP_BIT = 8,
+
+ KBDCLKDIV_DV_BIT = 0,
+ KBDCLKDIV_DV_MASK = 0x00000003,
+
+ PCSR_S0R_BIT = 0,
+ PCSR_S1R_BIT = 1,
+ PCSR_S0CD_BIT = 2,
+ PCSR_S1CD_BIT = 3,
+ PCSR_S0VS1_BIT = 4,
+ PCSR_S0VS2_BIT = 5,
+ PCSR_S1VS1_BIT = 6,
+ PCSR_S1VS2_BIT = 7,
+ PCSR_S0WP_BIT = 8,
+ PCSR_S1WP_BIT = 9,
+ PCSR_S0BVD1_BIT = 10,
+ PCSR_S0BVD2_BIT = 11,
+ PCSR_S1BVD1_BIT = 12,
+ PCSR_S1BVD2_BIT = 13,
+
+ PCCR_S0RST_BIT = 0,
+ PCCR_S1RST_BIT = 1,
+ PCCR_S0FLT_BIT = 2,
+ PCCR_S1FLT_BIT = 3,
+ PCCR_S0PWEN_BIT = 4,
+ PCCR_S1PWEN_BIT = 5,
+ PCCR_S0PSE_BIT = 6,
+ PCCR_S1PSE_BIT = 7,
+
+ PCSSR_S0SLP_BIT = 0,
+ PCSSR_S1SLP_BIT = 1
+ };
+
+ // interrupt lines
+ enum : uint32_t
+ {
+ INT_GPA0 = 0,
+ INT_GPA1 = 1,
+ INT_GPA2 = 2,
+ INT_GPA3 = 3,
+ INT_GPB0 = 4,
+ INT_GPB1 = 5,
+ INT_GPB2 = 6,
+ INT_GPB3 = 7,
+ INT_GPB4 = 8,
+ INT_GPB5 = 9,
+ INT_GPC0 = 10,
+ INT_GPC1 = 11,
+ INT_GPC2 = 12,
+ INT_GPC3 = 13,
+ INT_GPC4 = 14,
+ INT_GPC5 = 15,
+ INT_GPC6 = 16,
+ INT_GPC7 = 17,
+ INT_MSTX = 18,
+ INT_MSRX = 19,
+ INT_MSERR = 20,
+ INT_TPTX = 21,
+ INT_TPRX = 22,
+ INT_TPERR = 23,
+ INT_SSPTX = 24,
+ INT_SSPRX = 25,
+ INT_SSPROR = 26,
+ INT_AUDTXA = 32,
+ INT_AUDRXA = 33,
+ INT_AUDTXB = 34,
+ INT_AUDRXB = 35,
+ INT_AUDTFS = 36,
+ INT_AUDRFS = 37,
+ INT_AUDTUR = 38,
+ INT_AUDROR = 39,
+ INT_AUDDTS = 40,
+ INT_AUDRDD = 41,
+ INT_AUDSTO = 42,
+ INT_USBPWR = 43,
+ INT_USBHCIM = 44,
+ INT_USBHCIBUF = 45,
+ INT_USBHCIWAKE = 46,
+ INT_USBHCIMFC = 47,
+ INT_USBRESUME = 48,
+ INT_S0RDY = 49,
+ INT_S1RDY = 50,
+ INT_S0CD = 51,
+ INT_S1CD = 52,
+ INT_S0BVD = 53,
+ INT_S1BVD = 54
+ };
+
+ struct sbi_regs
+ {
+ uint32_t skcr;
+ uint32_t smcr;
+ uint32_t skid;
+ };
+
+ struct sysctrl_regs
+ {
+ uint32_t skpcr;
+ uint32_t skcdr;
+ uint32_t skaud;
+ uint32_t skpmc;
+ uint32_t skptc;
+ uint32_t skpen0;
+ uint32_t skpwm0;
+ uint32_t skpen1;
+ uint32_t skpwm1;
+ };
+
+ struct usb_regs
+ {
+ uint32_t ohci[22];
+ uint32_t status;
+ uint32_t reset;
+ uint32_t int_test;
+ uint32_t fifo[12];
+ };
+
+ struct audio_regs
+ {
+ uint32_t sacr0;
+ uint32_t sacr1;
+ uint32_t sacr2;
+ uint32_t sasr0;
+ uint32_t sasr1;
+ uint32_t l3car;
+ uint32_t l3cdr;
+ uint32_t accar;
+ uint32_t accdr;
+ uint32_t acsar;
+ uint32_t acsdr;
+ uint32_t sadtcs;
+ uint32_t sadts[2];
+ uint32_t sadtc[2];
+ uint32_t sadta;
+ uint32_t sadtcc;
+ uint32_t sadrcs;
+ uint32_t sadrs[2];
+ uint32_t sadrc[2];
+ uint32_t sadra;
+ uint32_t sadrcc;
+ uint32_t saitr;
+
+ uint32_t rx_fifo[16];
+ int rx_fifo_read_idx;
+ int rx_fifo_write_idx;
+ int rx_fifo_count;
+ emu_timer *rx_timer;
+ emu_timer *rx_dma_timer;
+
+ uint32_t tx_fifo[16];
+ int tx_fifo_read_idx;
+ int tx_fifo_write_idx;
+ int tx_fifo_count;
+ emu_timer *tx_timer;
+ emu_timer *tx_dma_timer;
+ };
+
+ struct ssp_regs
+ {
+ uint32_t sspcr0;
+ uint32_t sspcr1;
+ uint32_t sspsr;
+ uint32_t sspitr;
+
+ uint16_t rx_fifo[16];
+ int rx_fifo_read_idx;
+ int rx_fifo_write_idx;
+ int rx_fifo_count;
+ emu_timer *rx_timer;
+
+ uint16_t tx_fifo[16];
+ int tx_fifo_read_idx;
+ int tx_fifo_write_idx;
+ int tx_fifo_count;
+ emu_timer *tx_timer;
+ };
+
+ struct ps2_regs
+ {
+ uint32_t kbdcr;
+ uint32_t kbdstat;
+ uint32_t kbddata_tx;
+ uint32_t kbddata_rx;
+ uint32_t kbdclkdiv;
+ uint32_t kbdprecnt;
+ uint32_t kbditr;
+ };
+
+ struct gpio_regs
+ {
+ uint32_t ddr[3];
+ uint32_t level[3];
+ uint32_t sdr[3];
+ uint32_t ssr[3];
+ uint32_t out_latch[3];
+ uint32_t in_latch[3];
+ };
+
+ struct intc_regs
+ {
+ uint32_t inttest[2];
+ uint32_t inten[2];
+ uint32_t intpol[2];
+ uint32_t inttstsel;
+ uint32_t intstat[2];
+ uint32_t wake_en[2];
+ uint32_t wake_pol[2];
+
+ uint32_t intraw[2];
+ };
+
+ struct card_regs
+ {
+ uint32_t pccr;
+ uint32_t pcssr;
+ uint32_t pcsr;
+ };
+
+ sbi_regs m_sbi_regs;
+ sysctrl_regs m_sk_regs;
+ usb_regs m_usb_regs;
+ audio_regs m_audio_regs;
+ ssp_regs m_ssp_regs;
+ ps2_regs m_track_regs;
+ ps2_regs m_mouse_regs;
+ gpio_regs m_gpio_regs;
+ intc_regs m_intc_regs;
+ card_regs m_card_regs;
+
+ required_device<sa1110_cpu_device> m_maincpu;
+ optional_device<device_t> m_audio_codec;
+
+ devcb_write_line m_irq_out;
+ devcb_write_line::array<24> m_gpio_out;
+ devcb_write16 m_ssp_out;
+ devcb_write8 m_l3_addr_out;
+ devcb_write8 m_l3_data_out;
+ devcb_write32 m_i2s_out;
+};
+
+DECLARE_DEVICE_TYPE(SA1111, sa1111_device)
+
+#endif // MAME_MACHINE_SA1111
diff --git a/src/devices/machine/saa1043.cpp b/src/devices/machine/saa1043.cpp
index c6766cf5b7e..099041209a8 100644
--- a/src/devices/machine/saa1043.cpp
+++ b/src/devices/machine/saa1043.cpp
@@ -24,7 +24,6 @@ saa1043_device::saa1043_device(const machine_config &mconfig, const char *tag, d
, m_outputs(*this)
, m_type(PAL)
{
- std::fill(std::begin(m_outputs_hooked), std::end(m_outputs_hooked), false);
}
void saa1043_device::device_start()
@@ -32,50 +31,24 @@ void saa1043_device::device_start()
m_h = attotime::from_ticks(320, clock() * 2);
m_line_count = s_line_counts[m_type];
- // resolve callbacks
- for (uint32_t i = 0; i < OUT_COUNT; i++)
- {
- m_outputs[i].resolve_safe();
- if (m_outputs_hooked[i])
- {
- m_timers[i] = timer_alloc(i);
- switch(i)
- {
- case V2:
- m_timers[V2]->adjust(m_h * 6, 1);
- break;
- default:
- // Not yet implemented
- break;
- }
- }
- }
+ m_timers[OUT_V2] = timer_alloc(FUNC(saa1043_device::toggle_v2), this);
+ m_timers[OUT_V2]->adjust(m_h * 6, 1);
}
void saa1043_device::device_reset()
{
- // Clear any existing clock states
for (uint32_t i = 0; i < OUT_COUNT; i++)
{
m_outputs[i](CLEAR_LINE);
}
- m_outputs[V2](ASSERT_LINE);
+ m_outputs[OUT_V2](ASSERT_LINE);
}
-void saa1043_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(saa1043_device::toggle_v2)
{
- switch (id)
- {
- case V2:
- m_outputs[V2](1 - param);
- if (param)
- m_timers[V2]->adjust(m_h * (m_line_count - 9), 0);
- else
- m_timers[V2]->adjust(m_h * 9, 1);
- break;
-
- default:
- // Not yet implemented
- break;
- }
+ m_outputs[OUT_V2](1 - param);
+ if (param)
+ m_timers[OUT_V2]->adjust(m_h * (m_line_count - 9), 0);
+ else
+ m_timers[OUT_V2]->adjust(m_h * 9, 1);
}
diff --git a/src/devices/machine/saa1043.h b/src/devices/machine/saa1043.h
index 32591d58300..3a5851d0f42 100644
--- a/src/devices/machine/saa1043.h
+++ b/src/devices/machine/saa1043.h
@@ -46,24 +46,24 @@ public:
enum outputs : uint32_t
{
- BC,
- FH2,
- FH3,
- FH80,
- PH,
- NS,
- RI,
- WMP,
- RR,
- V1,
- V2,
- CLP,
- DL,
- H1,
- H2,
- CB,
- CS,
- ID,
+ OUT_BC,
+ OUT_FH2,
+ OUT_FH3,
+ OUT_FH80,
+ OUT_PH,
+ OUT_NS,
+ OUT_RI,
+ OUT_WMP,
+ OUT_RR,
+ OUT_V1,
+ OUT_V2,
+ OUT_CLP,
+ OUT_DL,
+ OUT_H1,
+ OUT_H2,
+ OUT_CB,
+ OUT_CS,
+ OUT_ID,
OUT_COUNT
};
@@ -78,34 +78,34 @@ public:
void set_type(signal_type type) { m_type = type; }
- auto bc_callback() { m_outputs_hooked[BC] = true; return m_outputs[BC].bind(); }
- auto fh2_callback() { m_outputs_hooked[FH2] = true; return m_outputs[FH2].bind(); }
- auto fh3_callback() { m_outputs_hooked[FH3] = true; return m_outputs[FH3].bind(); }
- auto fh80_callback() { m_outputs_hooked[FH80] = true; return m_outputs[FH80].bind(); }
- auto ph_callback() { m_outputs_hooked[PH] = true; return m_outputs[PH].bind(); }
- auto ns_callback() { m_outputs_hooked[NS] = true; return m_outputs[NS].bind(); }
- auto ri_callback() { m_outputs_hooked[RI] = true; return m_outputs[RI].bind(); }
- auto wmp_callback() { m_outputs_hooked[WMP] = true; return m_outputs[WMP].bind(); }
- auto rr_callback() { m_outputs_hooked[RR] = true; return m_outputs[RR].bind(); }
- auto v1_callback() { m_outputs_hooked[V1] = true; return m_outputs[V1].bind(); }
- auto v2_callback() { m_outputs_hooked[V2] = true; return m_outputs[V2].bind(); }
- auto clp_callback() { m_outputs_hooked[CLP] = true; return m_outputs[CLP].bind(); }
- auto dl_callback() { m_outputs_hooked[DL] = true; return m_outputs[DL].bind(); }
- auto h1_callback() { m_outputs_hooked[H1] = true; return m_outputs[H1].bind(); }
- auto h2_callback() { m_outputs_hooked[H2] = true; return m_outputs[H2].bind(); }
- auto cb_callback() { m_outputs_hooked[CB] = true; return m_outputs[CB].bind(); }
- auto cs_callback() { m_outputs_hooked[CS] = true; return m_outputs[CS].bind(); }
- auto id_callback() { m_outputs_hooked[ID] = true; return m_outputs[ID].bind(); }
+ auto bc_callback() { return m_outputs[OUT_BC].bind(); }
+ auto fh2_callback() { return m_outputs[OUT_FH2].bind(); }
+ auto fh3_callback() { return m_outputs[OUT_FH3].bind(); }
+ auto fh80_callback() { return m_outputs[OUT_FH80].bind(); }
+ auto ph_callback() { return m_outputs[OUT_PH].bind(); }
+ auto ns_callback() { return m_outputs[OUT_NS].bind(); }
+ auto ri_callback() { return m_outputs[OUT_RI].bind(); }
+ auto wmp_callback() { return m_outputs[OUT_WMP].bind(); }
+ auto rr_callback() { return m_outputs[OUT_RR].bind(); }
+ auto v1_callback() { return m_outputs[OUT_V1].bind(); }
+ auto v2_callback() { return m_outputs[OUT_V2].bind(); }
+ auto clp_callback() { return m_outputs[OUT_CLP].bind(); }
+ auto dl_callback() { return m_outputs[OUT_DL].bind(); }
+ auto h1_callback() { return m_outputs[OUT_H1].bind(); }
+ auto h2_callback() { return m_outputs[OUT_H2].bind(); }
+ auto cb_callback() { return m_outputs[OUT_CB].bind(); }
+ auto cs_callback() { return m_outputs[OUT_CS].bind(); }
+ auto id_callback() { return m_outputs[OUT_ID].bind(); }
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(toggle_v2);
private:
devcb_write_line::array<OUT_COUNT> m_outputs;
- bool m_outputs_hooked[OUT_COUNT];
emu_timer *m_timers[OUT_COUNT];
signal_type m_type;
diff --git a/src/devices/machine/saa5070.cpp b/src/devices/machine/saa5070.cpp
new file mode 100644
index 00000000000..21331917644
--- /dev/null
+++ b/src/devices/machine/saa5070.cpp
@@ -0,0 +1,350 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ SAA5070 Viewdata Input/Output Peripheral (VIOP)
+
+ https://bitsavers.org/components/philips/_dataBooks/1985_IC02Na_Philips_Bipolar_MOS_Video_and_Associated_Systems.pdf
+
+ TODO:
+ - tape UART
+ - IBUS receiver/transmitter
+
+*********************************************************************/
+
+#include "emu.h"
+#include "saa5070.h"
+
+
+DEFINE_DEVICE_TYPE(SAA5070, saa5070_device, "saa5070", "SAA5070 Viewdata Input/Output Peripheral")
+DEFINE_DEVICE_TYPE(SAA5070_UART, saa5070_uart_device, "saa5070_uart", "SAA5070 UART")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+saa5070_uart_device::saa5070_uart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SAA5070_UART, tag, owner, clock)
+ , device_serial_interface(mconfig, *this)
+ , m_txd_handler(*this)
+ , m_rx_enabled(0)
+ , m_tx_enabled(0)
+ , m_rxd(1)
+{
+}
+
+
+void saa5070_uart_device::device_start()
+{
+ receive_register_reset();
+ transmit_register_reset();
+
+ save_item(NAME(m_status));
+}
+
+void saa5070_uart_device::device_reset()
+{
+ m_status = 0x80; // TXRDY
+}
+
+
+void saa5070_uart_device::set_baud_rate(int rxbaud, int txbaud, int parity)
+{
+ if (parity)
+ set_data_frame(1, 7, (parity == 1) ? PARITY_ODD : PARITY_EVEN, STOP_BITS_1);
+ else
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
+
+ set_rcv_rate(rxbaud);
+ set_tra_rate(txbaud);
+
+ receive_register_reset();
+ transmit_register_reset();
+}
+
+void saa5070_uart_device::rcv_callback()
+{
+ if (m_rx_enabled) // UART enabled
+ receive_register_update_bit(m_rxd);
+}
+
+void saa5070_uart_device::rcv_complete()
+{
+ receive_register_extract();
+
+ m_status |= 0x40; // RXRDY
+
+ if (is_receive_framing_error())
+ m_status |= 0x10; // FERR
+ else
+ m_status &= ~0x10;
+
+ if (is_receive_parity_error())
+ m_status |= 0x08; // PERR
+ else
+ m_status &= ~0x08;
+}
+
+void saa5070_uart_device::tra_callback()
+{
+ if (m_tx_enabled) // UART enabled
+ m_txd_handler(transmit_register_get_data_bit());
+}
+
+void saa5070_uart_device::tra_complete()
+{
+ m_status |= 0x80; // TXRDY
+}
+
+
+void saa5070_uart_device::write_rxd(int state)
+{
+ m_rxd = state;
+ device_serial_interface::rx_w(state);
+}
+
+void saa5070_uart_device::write_dcd(int state)
+{
+ if (state)
+ m_status |= 0x24; // DCD/IDCD
+ else
+ m_status &= ~0x24;
+}
+
+void saa5070_uart_device::tx_byte(uint8_t data)
+{
+ m_status &= ~0x80; // TXRDY
+
+ transmit_register_setup(data);
+}
+
+uint8_t saa5070_uart_device::rx_byte()
+{
+ m_status &= ~0x40; // RXRDY
+
+ return get_received_char();
+}
+
+
+saa5070_device::saa5070_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SAA5070, tag, owner, clock)
+ , m_line_uart(*this, "line_uart")
+ , m_tape_uart(*this, "tape_uart")
+ , m_in_a_handler(*this, 0x00)
+ , m_in_b_handler(*this, 0x00)
+ , m_out_a_handler(*this)
+ , m_out_b_handler(*this)
+ , m_imp_handler(*this)
+ , m_txdata_handler(*this)
+ , m_timeout_timer(nullptr)
+ , m_dial_timer(nullptr)
+{
+}
+
+
+void saa5070_device::device_start()
+{
+ memset(m_sr, 0, sizeof(m_sr));
+
+ m_timeout_timer = timer_alloc(FUNC(saa5070_device::timeout), this);
+ m_dial_timer = timer_alloc(FUNC(saa5070_device::dial), this);
+
+ save_item(NAME(m_index));
+ save_item(NAME(m_sr));
+}
+
+void saa5070_device::device_reset()
+{
+ write_direct(0, 0x81); // Status 0: LTXRDY, IBTXRDY
+ write_direct(1, 0x80); // Status 1: TTXRDY
+ write_direct(2, 0x00); // Mode
+ write_direct(3, 0x00); // Command
+ write_direct(6, 0x00); // Port A
+ write_direct(7, 0x00); // Port B
+ write_direct(8, 0x00); // Dial Control and Timing
+}
+
+
+void saa5070_device::device_add_mconfig(machine_config &config)
+{
+ SAA5070_UART(config, m_line_uart, DERIVED_CLOCK(1, 1));
+ m_line_uart->txd_handler().set(FUNC(saa5070_device::write_txdata));
+ SAA5070_UART(config, m_tape_uart, DERIVED_CLOCK(1, 1));
+}
+
+
+TIMER_CALLBACK_MEMBER(saa5070_device::timeout)
+{
+ m_sr[8] &= ~0x10; // 1.5s TIMER
+ m_sr[8] &= ~0x40; // 60s TIMER
+}
+
+TIMER_CALLBACK_MEMBER(saa5070_device::dial)
+{
+ m_sr[8] &= ~0x20; // DIAL GO
+}
+
+
+void saa5070_device::address_w(uint8_t data)
+{
+ m_index = data & 0x0f;
+}
+
+uint8_t saa5070_device::data_r()
+{
+ switch (m_index)
+ {
+ case 0x0: // Status Register 0
+ // b0 IBTXRDY - IBUS B transmitter ready - previous transmission complete
+ // b1 IBRXRDY - IBUS B receiver ready - data available
+ // b2 LIDCD - line instantaneous data carrier detect
+ // b3 LPERR - line receiver parity error flag
+ // b4 LFERR - line receiver framing error - received stop bit not HIGH
+ // b5 LDCD - line data carrier detected
+ // b6 LRXRDY - line receiver ready - data available
+ // b7 LTXRDY - line transmitter ready - transmit holding register empty
+ m_sr[0] = (m_sr[0] & 0x27) | m_line_uart->status();
+ break;
+ case 0x1: // Status Register 1
+ // b0
+ // b1 IARXRDY - IBUS A receiver ready - data available
+ // b2
+ // b3 TPERR - tape receiver parity error flag
+ // b4 TFERR - tape receiver framing error - received stop nit not HIGH
+ // b5 TDCD - tape data carrier detected
+ // b6 TRXRDY - tape receiver ready - data available
+ // b7 TTXRDY - tape transmitter ready - transmit holding register empty
+ m_sr[1] = (m_sr[1] & 0x27) | m_tape_uart->status();
+ break;
+ case 0x2: // Mode Register
+ break;
+ case 0x3: // Command Register
+ break;
+ case 0x4: // Line Receive Holding Register
+ m_sr[4] = m_line_uart->rx_byte();
+ break;
+ case 0x5: // Tape Receive Holding Register
+ m_sr[5] = m_tape_uart->rx_byte();
+ break;
+ case 0x6: // Port A
+ m_sr[6] = m_in_a_handler() & 0x1f;
+ break;
+ case 0x7: // Port B
+ m_sr[7] = m_in_b_handler() & 0x0f;
+ break;
+ case 0x8: // Dial Control and Timing Register
+ break;
+ case 0xa: // IBUS A Registers
+ logerror("IBUS Receiver A not implemented %02x\n", m_sr[m_index]);
+ break;
+ case 0xb: // IBUS B Registers
+ logerror("IBUS Receiver B not implemented %02x\n", m_sr[m_index]);
+ break;
+ }
+
+ return m_sr[m_index];
+}
+
+void saa5070_device::data_w(uint8_t data)
+{
+ m_sr[m_index] = data;
+
+ switch (m_index)
+ {
+ case 0x2: // Mode Register
+ {
+ // b0
+ // b1
+ // b2 nTPEN - tape parity enable command
+ // b3 TPO/nE - tape parity odd/even command
+ // b4
+ // b5 n75/1200 - baud rate selection command for line modulator and line transmit shift register
+ // b6 nLPEN - line parity enable command
+ // b7 LPO/nE - line parity odd/even command
+ int tape_parity = device_serial_interface::PARITY_NONE;
+ if (BIT(data, 2))
+ tape_parity = BIT(data, 3) ? device_serial_interface::PARITY_ODD : device_serial_interface::PARITY_EVEN;
+ m_tape_uart->set_baud_rate(1300, 1300, tape_parity);
+ int line_parity = device_serial_interface::PARITY_NONE;
+ if (BIT(data, 6))
+ line_parity = BIT(data, 7) ? device_serial_interface::PARITY_ODD : device_serial_interface::PARITY_EVEN;
+ m_line_uart->set_baud_rate(1200, BIT(data, 5) ? 1200 : 75, line_parity); // V23 Modem (1200/75 baud)
+ break;
+ }
+ case 0x3: // Command Register
+ // b0 nDLEN A/nDLIM A - three line/two line control for IBUS A receiver
+ // b1 CLCK IN/nOUT - input/output control for 62.5 kHz clock pin
+ // b2 TTXEN - tape transmitter enable
+ // b3 TRXEN - tape receiver enable
+ // b4 LDBEN - line demodulator output buffer enable
+ // b5 RESET
+ // b6 LTXEN - line transmitter and modulator enable
+ // b7 LRXEN - line receiver enable
+ m_tape_uart->tx_enable(BIT(data, 2));
+ m_tape_uart->rx_enable(BIT(data, 3));
+
+ if (BIT(data, 5))
+ {
+ reset();
+ }
+
+ m_line_uart->tx_enable(BIT(data, 6));
+ m_line_uart->rx_enable(BIT(data, 7));
+ break;
+ case 0x4: // Line Transmit Holding Register
+ m_line_uart->tx_byte(data);
+ break;
+ case 0x5: // Tape Transmit Holding Register
+ m_tape_uart->tx_byte(data);
+ break;
+ case 0x6: // Port A
+ m_out_a_handler(data & 0x1f);
+ break;
+ case 0x7: // Port B
+ m_out_b_handler(data & 0x0f);
+ break;
+ case 0x8: // Dial Control and Timing Register
+ // b0 D10
+ // b1 D11
+ // b2 D12
+ // b3 D13
+ // b4 1.5s TIMER
+ // b5 DIAL GO
+ // b6 60s TIMER
+ // b7 UK/nEUR - impulsing ratio control for UK and European standards
+ if (BIT(data, 4))
+ {
+ m_timeout_timer->adjust(attotime::from_msec(1'500));
+ }
+ if (BIT(data, 5))
+ {
+ m_sr[0] &= ~0x24; // LIDCD/LDCD
+ int digit_counter = (data & 0x0f) == 0 ? 10 : (data & 0x0f);
+ // each digit impulse = 100ms, inter digit pause = 800ms
+ m_dial_timer->adjust(attotime::from_msec((100 * digit_counter) + 800)); // TODO: digit impulse generator output on IMP line
+ }
+ if (BIT(data, 6))
+ {
+ m_timeout_timer->adjust(attotime::from_msec(60'000));
+ }
+ break;
+ case 0xb: // IBUS B Registers
+ logerror("IBUS Transmitter B not implemented %02x\n", m_sr[m_index]);
+ break;
+ }
+}
+
+uint8_t saa5070_device::read_direct(offs_t offset)
+{
+ m_index = offset & 0x0f;
+
+ return data_r();
+}
+
+void saa5070_device::write_direct(offs_t offset, uint8_t data)
+{
+ m_index = offset & 0x0f;
+
+ data_w(data);
+}
diff --git a/src/devices/machine/saa5070.h b/src/devices/machine/saa5070.h
new file mode 100644
index 00000000000..5561e596517
--- /dev/null
+++ b/src/devices/machine/saa5070.h
@@ -0,0 +1,151 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/*********************************************************************
+
+ SAA5070 Viewdata Input/Output Peripheral (VIOP)
+
+**********************************************************************
+
+ Pinning: ____ ____
+ | \/ |
+ Vss 1 | | 40 DON
+ IMP 2 | | 39 CARDET
+ TFSKIN 3 | | 38 FSKIN
+ TFSKOUT 4 | | 37 DOCDI
+ FSKOUT 5 | | 36 CS
+ TXDATA 6 | | 35 nWR
+ RXDATA 7 | | 34 nRD
+ F1 8 | | 33 D7
+ DLIM B 9 | | 32 D6
+ nDATA B 10 | SAA5070 | 31 D5
+ nDLEN B 11 | | 30 D4
+ nDATA A 12 | | 29 D3
+ DLIM A/nDLEN A 13 | | 28 D2
+ IBCLK 14 | | 27 D1
+ PA4 15 | | 26 D0
+ PA3 16 | | 25 ALE
+ PA2 17 | | 24 PB0
+ PA1 18 | | 23 PB1
+ PA0 19 | | 22 PB2
+ Vdd 20 | | 21 PB3
+ |__________|
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_SAA5070_H
+#define MAME_MACHINE_SAA5070_H
+
+#pragma once
+
+#include "diserial.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> saa5070_uart_device
+
+class saa5070_uart_device : public device_t, public device_serial_interface
+{
+public:
+ saa5070_uart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto txd_handler() { return m_txd_handler.bind(); }
+
+ void set_baud_rate(int rxbaud, int txbaud, int parity);
+ uint8_t status() { return m_status; }
+
+ void tx_byte(uint8_t data);
+ uint8_t rx_byte();
+
+ void rx_enable(int state) { m_rx_enabled = state; }
+ void tx_enable(int state) { m_tx_enabled = state; }
+
+ void write_rxd(int state);
+ void write_dcd(int state);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void rcv_callback() override;
+ virtual void rcv_complete() override;
+ virtual void tra_callback() override;
+ virtual void tra_complete() override;
+
+private:
+ devcb_write_line m_txd_handler;
+
+ uint8_t m_status;
+ int m_rx_enabled;
+ int m_tx_enabled;
+ int m_rxd;
+};
+
+
+// ======================> saa5070_device
+
+class saa5070_device : public device_t
+{
+public:
+ saa5070_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // port handlers
+ auto readpa_handler() { return m_in_a_handler.bind(); }
+ auto readpb_handler() { return m_in_b_handler.bind(); }
+ auto writepa_handler() { return m_out_a_handler.bind(); }
+ auto writepb_handler() { return m_out_b_handler.bind(); }
+
+ // autodial handler
+ auto imp_handler() { return m_imp_handler.bind(); }
+
+ // uart handlers
+ auto txdata_handler() { return m_txdata_handler.bind(); }
+
+ void write_rxdata(int state) { m_line_uart->write_rxd(state); }
+ void write_cardet(int state) { m_line_uart->write_dcd(state); }
+
+ // read/write access
+ void address_w(uint8_t data);
+ uint8_t data_r();
+ void data_w(uint8_t data);
+
+ // direct-mapped read/write access
+ uint8_t read_direct(offs_t offset);
+ void write_direct(offs_t offset, uint8_t data);
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ required_device<saa5070_uart_device> m_line_uart;
+ required_device<saa5070_uart_device> m_tape_uart;
+
+ devcb_read8 m_in_a_handler;
+ devcb_read8 m_in_b_handler;
+ devcb_write8 m_out_a_handler;
+ devcb_write8 m_out_b_handler;
+ devcb_write_line m_imp_handler;
+ devcb_write_line m_txdata_handler;
+
+ emu_timer *m_timeout_timer;
+ emu_timer *m_dial_timer;
+
+ void write_txdata(int state) { m_txdata_handler(state); }
+
+ TIMER_CALLBACK_MEMBER(timeout);
+ TIMER_CALLBACK_MEMBER(dial);
+
+ uint8_t m_index = 0;
+ uint8_t m_sr[16];
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(SAA5070, saa5070_device)
+
+
+#endif // MAME_MACHINE_SAA5070_H
diff --git a/src/devices/machine/saa7191.cpp b/src/devices/machine/saa7191.cpp
new file mode 100644
index 00000000000..61c16feba67
--- /dev/null
+++ b/src/devices/machine/saa7191.cpp
@@ -0,0 +1,214 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*********************************************************************
+
+ saa7191.cpp
+
+ Philips SAA7191B Digital Multistandard Colour Decoder (DMSD)
+
+ TODO:
+ - Actual functionality
+
+*********************************************************************/
+
+#include "emu.h"
+#include "saa7191.h"
+
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_READS (1U << 2)
+#define LOG_WRITES (1U << 3)
+#define LOG_ERRORS (1U << 4)
+#define LOG_I2C_IGNORES (1U << 5)
+#define LOG_DEFAULT (LOG_READS | LOG_WRITES | LOG_ERRORS | LOG_I2C_IGNORES | LOG_UNKNOWN)
+
+#define VERBOSE (LOG_DEFAULT)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SAA7191, saa7191_device, "saa7191", "Philips SAA7191 DMSD")
+
+saa7191_device::saa7191_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SAA7191, tag, owner, clock)
+ , m_chr_in(*this, 0)
+ , m_cvbs_in(*this, 0)
+ , m_y_out(*this)
+ , m_uv_out(*this)
+ , m_hs_out(*this)
+ , m_vs_out(*this)
+{
+}
+
+void saa7191_device::device_start()
+{
+ save_item(NAME(m_status));
+ save_item(NAME(m_regs));
+ save_item(NAME(m_i2c_write_addr));
+ save_item(NAME(m_i2c_read_addr));
+ save_item(NAME(m_i2c_subaddr));
+ save_item(NAME(m_i2c_state));
+}
+
+void saa7191_device::device_reset()
+{
+ m_status = 0;
+ memset(m_regs, 0, sizeof(uint8_t) * REG_COUNT);
+
+ m_i2c_write_addr = 0x8a;
+ m_i2c_read_addr = 0x8b;
+ m_i2c_subaddr = 0x00;
+ m_i2c_state = I2C_STATE_IDLE;
+}
+
+void saa7191_device::i2c_data_w(uint8_t data)
+{
+ switch (m_i2c_state)
+ {
+ case I2C_STATE_IDLE:
+ if (data == m_i2c_write_addr)
+ m_i2c_state = I2C_STATE_SUBADDR_WRITE;
+ else if (data == m_i2c_read_addr)
+ m_i2c_state = I2C_STATE_SUBADDR_READ;
+ else
+ LOGMASKED(LOG_I2C_IGNORES, "I2C idle, address %02x ignored (mine are R:%02x/W:%02x)\n", data, m_i2c_read_addr, m_i2c_write_addr);
+ break;
+ case I2C_STATE_SUBADDR_WRITE:
+ m_i2c_subaddr = data;
+ m_i2c_state = I2C_STATE_DATA_WRITE;
+ break;
+ case I2C_STATE_SUBADDR_READ:
+ m_i2c_subaddr = data;
+ m_i2c_state = I2C_STATE_DATA_READ;
+ break;
+ case I2C_STATE_DATA_WRITE:
+ reg_w(data);
+ m_i2c_subaddr = (m_i2c_subaddr + 1) % REG_COUNT;
+ break;
+ case I2C_STATE_DATA_READ:
+ LOGMASKED(LOG_ERRORS, "I2C is expecting a data read, but data was written, returning to idle\n");
+ m_i2c_state = I2C_STATE_IDLE;
+ break;
+ default:
+ LOGMASKED(LOG_ERRORS, "Unknown I2C state %d, returning to idle\n", m_i2c_state);
+ m_i2c_state = I2C_STATE_IDLE;
+ break;
+ }
+}
+
+uint8_t saa7191_device::i2c_data_r()
+{
+ if (m_i2c_state != I2C_STATE_DATA_READ)
+ {
+ LOGMASKED(LOG_ERRORS, "i2c_data_r called, but we are in state %d and not expecting a data read, returning to idle\n", m_i2c_state);
+ m_i2c_state = I2C_STATE_IDLE;
+ return 0;
+ }
+ if (m_i2c_subaddr == 0x01)
+ {
+ LOGMASKED(LOG_READS, "i2c_data_r: Status = %02x\n", m_status);
+ m_i2c_subaddr = (m_i2c_subaddr + 1) % REG_COUNT;
+ return m_status;
+ }
+ LOGMASKED(LOG_UNKNOWN, "i2c_data_r: Unknown Sub-Address %02x, returning 0\n", m_i2c_subaddr);
+ m_i2c_subaddr = (m_i2c_subaddr + 1) % REG_COUNT;
+ return 0;
+}
+
+void saa7191_device::i2c_stop_w(int state)
+{
+ if (state)
+ m_i2c_state = I2C_STATE_IDLE;
+}
+
+void saa7191_device::iicsa_w(int state)
+{
+ m_i2c_write_addr = state ? 0x8e : 0x8a;
+ m_i2c_read_addr = m_i2c_write_addr | 1;
+}
+
+void saa7191_device::reg_w(uint8_t data)
+{
+ if (m_i2c_subaddr < REG_COUNT)
+ {
+ m_regs[m_i2c_subaddr] = data;
+ }
+
+ switch (m_i2c_subaddr)
+ {
+ case REG_IDEL:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Increment delay = %02x\n", data);
+ break;
+ case REG_HSYB:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync begin, 50Hz = %02x\n", data);
+ break;
+ case REG_HSYS:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync stop, 50Hz = %02x\n", data);
+ break;
+ case REG_HCLB:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp begin, 50Hz = %02x\n", data);
+ break;
+ case REG_HCLS:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp stop, 50Hz = %02x\n", data);
+ break;
+ case REG_HPHI:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync after PHI1, 50Hz = %02x\n", data);
+ break;
+ case REG_LUMC:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Luminance control = %02x\n", data);
+ break;
+ case REG_HUEC:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Hue control = %02x\n", data);
+ break;
+ case REG_CKTQ:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Colour killer threshold QAM = %02x\n", data);
+ break;
+ case REG_CKTS:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Colour killer threshold SECAM = %02x\n", data);
+ break;
+ case REG_PLSE:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: PAL switch sensitivity = %02x\n", data);
+ break;
+ case REG_SESE:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: SECAM switch sensitivity = %02x\n", data);
+ break;
+ case REG_GAIN:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Chroma gain control settings = %02x\n", data);
+ break;
+ case REG_STDC:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Standard/mode control = %02x\n", data);
+ break;
+ case REG_IOCK:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: I/O and clock control = %02x\n", data);
+ break;
+ case REG_CTL1:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Control #1 = %02x\n", data);
+ break;
+ case REG_CTL2:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Control #2 = %02x\n", data);
+ break;
+ case REG_CHCV:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Chroma gain reference = %02x\n", data);
+ break;
+ case REG_HS6B:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync begin, 60Hz = %02x\n", data);
+ break;
+ case REG_HS6S:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync stop, 60Hz = %02x\n", data);
+ break;
+ case REG_HC6B:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp begin, 60Hz = %02x\n", data);
+ break;
+ case REG_HC6S:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp stop, 60Hz = %02x\n", data);
+ break;
+ case REG_HP6I:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync after PHI1, 60Hz = %02x\n", data);
+ break;
+ default:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Unknown Register %02x = %02x (ignored)\n", m_i2c_subaddr, data);
+ if (m_i2c_subaddr < REG_COUNT)
+ {
+ m_regs[m_i2c_subaddr] = 0;
+ }
+ break;
+ }
+}
+
diff --git a/src/devices/machine/saa7191.h b/src/devices/machine/saa7191.h
new file mode 100644
index 00000000000..42c1182e1f2
--- /dev/null
+++ b/src/devices/machine/saa7191.h
@@ -0,0 +1,172 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*********************************************************************
+
+ saa7191.h
+
+ Philips SAA7191B Digital Multistandard Colour Decoder (DMSD)
+
+ TODO:
+ - Actual functionality
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_SAA7191_H
+#define MAME_MACHINE_SAA7191_H
+
+#pragma once
+
+class saa7191_device : public device_t
+{
+public:
+ saa7191_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U);
+
+ void i2c_data_w(uint8_t data);
+ uint8_t i2c_data_r();
+ void i2c_stop_w(int state);
+
+ void iicsa_w(int state);
+
+ auto chr_in() { return m_chr_in.bind(); }
+ auto cvbs_in() { return m_cvbs_in.bind(); }
+
+ auto y_out() { return m_y_out.bind(); }
+ auto uv_out() { return m_uv_out.bind(); }
+ auto hs_out() { return m_hs_out.bind(); }
+ auto vs_out() { return m_vs_out.bind(); }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ void reg_w(uint8_t data);
+
+ enum
+ {
+ REG_IDEL = 0x00,
+ REG_HSYB = 0x01,
+ REG_HSYS = 0x02,
+ REG_HCLB = 0x03,
+ REG_HCLS = 0x04,
+ REG_HPHI = 0x05,
+ REG_LUMC = 0x06,
+ REG_HUEC = 0x07,
+ REG_CKTQ = 0x08,
+ REG_CKTS = 0x09,
+ REG_PLSE = 0x0a,
+ REG_SESE = 0x0b,
+ REG_GAIN = 0x0c,
+ REG_STDC = 0x0d,
+ REG_IOCK = 0x0e,
+ REG_CTL1 = 0x0f,
+ REG_CTL2 = 0x10,
+ REG_CHCV = 0x11,
+ REG_HS6B = 0x14,
+ REG_HS6S = 0x15,
+ REG_HC6B = 0x16,
+ REG_HC6S = 0x17,
+ REG_HP6I = 0x18,
+ REG_COUNT,
+
+ LUMC_APER_SHIFT = 0,
+ LUMC_APER_MASK = (3 << LUMC_APER_SHIFT),
+ LUMC_CORI_SHIFT = 2,
+ LUMC_CORI_MASK = (3 << LUMC_CORI_SHIFT),
+ LUMC_BPSS_SHIFT = 4,
+ LUMC_BPSS_MASK = (3 << LUMC_BPSS_SHIFT),
+ LUMC_PREF_BIT = 6,
+ LUMC_PREF_MASK = (1 << LUMC_PREF_BIT),
+ LUMC_BYPS_BIT = 7,
+ LUMC_BYPS_MASK = (1 << LUMC_BYPS_BIT),
+
+ CKTQ_SHIFT = 3,
+ CKTQ_MASK = (0x1f << CKTQ_SHIFT),
+ CKTS_SHIFT = 3,
+ CKTS_MASK = (0x1f << CKTS_SHIFT),
+
+ GAIN_LFIS_SHIFT = 5,
+ GAIN_LFIS_MASK = (3 << GAIN_LFIS_SHIFT),
+ GAIN_COLO_BIT = 7,
+ GAIN_COLO_MASK = (1 << GAIN_COLO_BIT),
+ GAIN_MASK = GAIN_LFIS_MASK | GAIN_COLO_MASK,
+
+ STDC_SECS_BIT = 0,
+ STDC_SECS_MASK = (1 << STDC_SECS_BIT),
+ STDC_GPSW0_BIT = 1,
+ STDC_GPSW0_MASK = (1 << STDC_GPSW0_BIT),
+ STDC_HRMV_BIT = 2,
+ STDC_HRMV_MASK = (1 << STDC_HRMV_BIT),
+ STDC_NFEN_BIT = 3,
+ STDC_NFEN_MASK = (1 << STDC_NFEN_BIT),
+ STDC_VTRC_BIT = 7,
+ STDC_VTRC_MASK = (1 << STDC_VTRC_BIT),
+ STDC_MASK = STDC_SECS_MASK | STDC_GPSW0_MASK | STDC_HRMV_MASK | STDC_NFEN_MASK | STDC_VTRC_MASK,
+
+ IOCK_GPSW1_BIT = 0,
+ IOCK_GPSW1_MASK = (1 << IOCK_GPSW1_BIT),
+ IOCK_GPSW2_BIT = 1,
+ IOCK_GPSW2_MASK = (1 << IOCK_GPSW2_BIT),
+ IOCK_CHRS_BIT = 2,
+ IOCK_CHRS_MASK = (1 << IOCK_CHRS_BIT),
+ IOCK_OEDY_BIT = 3,
+ IOCK_OEDY_MASK = (1 << IOCK_OEDY_BIT),
+ IOCK_OEVS_BIT = 4,
+ IOCK_OEVS_MASK = (1 << IOCK_OEVS_BIT),
+ IOCK_OEHS_BIT = 5,
+ IOCK_OEHS_MASK = (1 << IOCK_OEHS_BIT),
+ IOCK_OEDC_BIT = 6,
+ IOCK_OEDC_MASK = (1 << IOCK_OEDC_BIT),
+ IOCK_HPLL_BIT = 7,
+ IOCK_HPLL_MASK = (1 << IOCK_HPLL_BIT),
+
+ CTL1_YDEL_SHIFT = 0,
+ CTL1_YDEL_MASK = (7 << CTL1_YDEL_SHIFT),
+ CTL1_OFTS_BIT = 3,
+ CTL1_OFTS_MASK = (1 << CTL1_OFTS_BIT),
+ CTL1_SCEN_BIT = 4,
+ CTL1_SCEN_MASK = (1 << CTL1_SCEN_BIT),
+ CTL1_SXCR_BIT = 5,
+ CTL1_SXCR_MASK = (1 << CTL1_SXCR_BIT),
+ CTL1_FSEL_BIT = 6,
+ CTL1_FSEL_MASK = (1 << CTL1_FSEL_BIT),
+ CTL1_AUFD_BIT = 7,
+ CTL1_AUFD_MASK = (1 << CTL1_AUFD_BIT),
+
+ CTL2_VNOI_SHIFT = 0,
+ CTL2_VNOI_MASK = (3 << CTL2_VNOI_SHIFT),
+ CTL2_HRFS_SHIFT = 2,
+ CTL2_HRFS_MASK = (1 << CTL2_HRFS_SHIFT),
+ CTL2_MASK = CTL2_VNOI_MASK | CTL2_HRFS_MASK
+ };
+
+ enum
+ {
+ I2C_STATE_IDLE,
+ I2C_STATE_SUBADDR_READ,
+ I2C_STATE_SUBADDR_WRITE,
+ I2C_STATE_DATA_READ,
+ I2C_STATE_DATA_WRITE
+ };
+
+ uint8_t m_status;
+ uint8_t m_regs[REG_COUNT];
+
+ uint8_t m_i2c_write_addr;
+ uint8_t m_i2c_read_addr;
+ uint8_t m_i2c_subaddr;
+ int m_i2c_state;
+
+ devcb_read8 m_chr_in;
+ devcb_read8 m_cvbs_in;
+
+ devcb_write8 m_y_out;
+ devcb_write8 m_uv_out;
+ devcb_write_line m_hs_out;
+ devcb_write_line m_vs_out;
+};
+
+DECLARE_DEVICE_TYPE(SAA7191, saa7191_device)
+
+#endif // MAME_MACHINE_SAA7191_H
diff --git a/src/devices/machine/scc2698b.cpp b/src/devices/machine/scc2698b.cpp
index 9dcc280fb20..4fb7b2b3a3f 100644
--- a/src/devices/machine/scc2698b.cpp
+++ b/src/devices/machine/scc2698b.cpp
@@ -7,10 +7,10 @@
Enhanced Octal Universal Asynchronous Receiver/Transmitter
Notes:
- This device is similiar to four 2681 DUART chips tied together
+ This device is similar to four 2681 DUART chips tied together
in a single package, with some shared resources.
The 2681 DUART is implemented in scn2681_device - but this
- chip is being independently emulated seperately for mainly
+ chip is being independently emulated separately for mainly
educational purposes. When functionality for this device is
completed we will consider merging the devices if it's
practical.
@@ -26,7 +26,6 @@ Quirks:
#include "emu.h"
#include "scc2698b.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_CONFIG_CHANGE (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_CONFIG_CHANGE)
@@ -364,29 +363,12 @@ scc2698b_device::scc2698b_device(const machine_config &mconfig, const char *tag,
write_mpp2(*this),
write_mpo(*this)
{
-
}
-void scc2698b_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
-
-}
-
-
void scc2698b_device::device_start()
{
- write_intr_A.resolve_safe();
- write_intr_B.resolve_safe();
- write_intr_C.resolve_safe();
- write_intr_D.resolve_safe();
-
- write_tx.resolve_all_safe();
- write_mpp1.resolve_all_safe();
- write_mpp2.resolve_all_safe();
- write_mpo.resolve_all_safe();
-
for (int i = 0; i < 8; i++)
{
m_channel[i]->channel_port = i;
@@ -398,13 +380,12 @@ void scc2698b_device::device_start()
void scc2698b_device::device_reset()
{
-
}
void scc2698b_device::write_line_tx(int port, int value)
{
- if ((0 <= port) && (ARRAY_LENGTH(write_tx) > port))
+ if ((0 <= port) && (std::size(write_tx) > port))
write_tx[port](value);
else
logerror("Unsupported port %d in write_line_tx\n", port);
@@ -412,7 +393,7 @@ void scc2698b_device::write_line_tx(int port, int value)
void scc2698b_device::write_line_mpp1(int port, int value)
{
- if ((0 <= port) && (ARRAY_LENGTH(write_mpp1) > port))
+ if ((0 <= port) && (std::size(write_mpp1) > port))
write_mpp1[port](value);
else
logerror("Unsupported port %d in write_line_mpp1\n", port);
@@ -420,7 +401,7 @@ void scc2698b_device::write_line_mpp1(int port, int value)
void scc2698b_device::write_line_mpp2(int port, int value)
{
- if ((0 <= port) && (ARRAY_LENGTH(write_mpp2) > port))
+ if ((0 <= port) && (std::size(write_mpp2) > port))
write_mpp2[port](value);
else
logerror("Unsupported port %d in write_line_mpp2\n", port);
@@ -428,7 +409,7 @@ void scc2698b_device::write_line_mpp2(int port, int value)
void scc2698b_device::write_line_mpo(int port, int value)
{
- if ((0 <= port) && (ARRAY_LENGTH(write_mpo) > port))
+ if ((0 <= port) && (std::size(write_mpo) > port))
write_mpo[port](value);
else
logerror("Unsupported port %d in write_line_mpo\n", port);
diff --git a/src/devices/machine/scc2698b.h b/src/devices/machine/scc2698b.h
index 84da53998c5..d883b45d0b9 100644
--- a/src/devices/machine/scc2698b.h
+++ b/src/devices/machine/scc2698b.h
@@ -114,7 +114,6 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_add_mconfig(machine_config &config) override;
devcb_write_line write_intr_A, write_intr_B, write_intr_C, write_intr_D;
diff --git a/src/devices/machine/scc66470.cpp b/src/devices/machine/scc66470.cpp
new file mode 100644
index 00000000000..7538cf88e3a
--- /dev/null
+++ b/src/devices/machine/scc66470.cpp
@@ -0,0 +1,890 @@
+// license:BSD-3-Clause
+// copyright-holders:Paul Arnold
+/***************************************************************************
+ Philips SCC66470 Video and System controller.
+
+ This does not render the image to the display. It is up to the user
+ to provide their own screen_update function. Pixel (palette offset) data
+ can be obtained by calling line( line number ) for each line.
+ Some boards have multiple video sources, the source being displayed being
+ selected based on pixel value...is there a nice way of doing this other
+ than leaving it to the board driver ?
+
+ Todo:
+ Add support for mosaic and RLE screens.
+ Add remaining pixac operations. Only BCOLOUR1/BCOLOUR2 are supported.
+ Add interlaced support.
+ Add bep ?
+ Verify number of cycles for each access.
+***************************************************************************/
+
+#include "emu.h"
+#include "scc66470.h"
+
+#include "screen.h"
+
+#define CSR_REG (m_csr)
+#define DCR_REG (m_dcr)
+#define DCR2_REG (m_dcr2)
+
+#define DCR_DE 15
+#define DCR_CF1 14
+#define DCR_CF2 13
+#define DCR_FD 12
+#define DCR_SM 11
+#define DCR_SS 10
+#define DCR_LS 9
+#define DCR_CM 8
+#define DCR_FG 7
+#define DCR_DF 6
+#define DCR_IC 5
+#define DCR_DC 4
+
+#define CSR_DI1 15
+#define CSR_DI2 14
+#define CSR_EW 10
+#define CSR_DD1 9
+#define CSR_DD2 8
+#define CSR_DM1 7
+#define CSR_DM2 6
+#define CSR_TD 5
+#define CSR_CG 4
+#define CSR_DD 3
+#define CSR_ED 2
+#define CSR_ST 1
+#define CSR_BE 0
+
+#define DCR2_OM1 14
+#define DCR2_OM2 13
+#define DCR2_ID 12
+#define DCR2_MF1 11
+#define DCR2_MF2 10
+#define DCR2_FT1 9
+#define DCR2_FT2 8
+
+#define CSR_R_DA 0x80
+#define CSR_R_PA 0x20
+#define CSR_R_IT2 0x04
+#define CSR_R_IT1 0x02
+
+#define SCC_INS_STOP ( 0 << 12 )
+#define SCC_INS_NOP ( 1 << 12 )
+#define SCC_INS_LOAD_DCP ( 2 << 12 )
+#define SCC_INS_LOAD_DCP_STOP ( 3 << 12 )
+#define SCC_INS_LOAD_VSR ( 4 << 12 )
+#define SCC_INS_LOAD_VSR_STOP ( 5 << 12 )
+#define SCC_INS_INTERRUPT ( 6 << 12 )
+#define SCC_INS_LOAD_BORDER ( 14 << 11 )
+#define SCC_INS_LOAD_BORDER_DSP ( 15 << 11 )
+#define SCC_INS_BEP_CONTROL ( 1 << 15 )
+
+#define PIXAC_4N 15
+#define PIXAC_COL 14
+#define PIXAC_EXC 13
+#define PIXAC_CPY 12
+#define PIXAC_CMP 11
+#define PIXAC_RTL 10
+#define PIXAC_SHK 9
+#define PIXAC_ZOM 8
+#define PIXAC_INV 3
+#define PIXAC_BIT 2
+#define PIXAC_TT 1
+#define PIXAC_NI 0
+
+struct horizontal_settings
+{
+ uint32_t pixels;
+ uint32_t border;
+};
+
+static const horizontal_settings h_table[] =
+{
+ //cf1 cf2 ss st
+ { 512, 64 }, // 0 0 0 0
+ { 512, 64 }, // 0 0 0 1
+ { 512, 0 }, // 0 0 1 0
+ { 512, 0 }, // 0 0 1 1
+
+ { 640, 128 }, // 0 1 0 0
+ { 640, 128 }, // 0 1 0 1
+ { 640, 0 }, // 0 1 1 0
+ { 640, 0 }, // 0 1 1 1
+
+ { 720, 80 }, // 1 0 0 0
+ { 720, 80 }, // 1 0 0 1
+
+ { 720, 0 }, // 1 0 1 0
+ { 720, 0 }, // 1 0 1 1
+
+ { 768, 128 }, // 1 1 0 0
+ { 720, 80 }, // 1 1 0 1
+
+ { 768, 0 }, // 1 1 1 0
+
+ { 768, 48 }, // 1 1 1 1
+};
+
+// device type definition
+DEFINE_DEVICE_TYPE(SCC66470, scc66470_device, "scc66470", "Philips SCC66470")
+
+//-------------------------------------------------
+// scc66470_device - constructor
+//-------------------------------------------------
+
+scc66470_device::scc66470_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, SCC66470, tag, owner, clock),
+ device_memory_interface(mconfig, *this),
+ device_video_interface(mconfig, *this),
+ m_irqcallback(*this),
+ m_space_config("videoram", ENDIANNESS_BIG, 16, 21, 0, address_map_constructor(FUNC(scc66470_device::scc66470_vram), this))
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void scc66470_device::device_start()
+{
+ m_ica_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc66470_device::process_ica), this));
+
+ m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc66470_device::process_dca), this));
+
+ save_item(NAME(m_csr));
+ save_item(NAME(m_dcr));
+ save_item(NAME(m_vsr));
+ save_item(NAME(m_bcr));
+ save_item(NAME(m_dcr2));
+ save_item(NAME(m_dcp));
+ save_item(NAME(m_swm));
+ save_item(NAME(m_stm));
+ save_item(NAME(m_reg_a));
+ save_item(NAME(m_reg_b));
+ save_item(NAME(m_pcr));
+ save_item(NAME(m_mask));
+ save_item(NAME(m_shift));
+ save_item(NAME(m_index));
+ save_item(NAME(m_fc));
+ save_item(NAME(m_bc));
+ save_item(NAME(m_tc));
+ save_item(NAME(m_csr_r));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void scc66470_device::device_reset()
+{
+ m_working_dcp = 0;
+
+ m_csr = 0;
+ m_dcr = 0;
+ m_vsr = 0;
+ m_bcr = 0;
+ m_dcr2 = 0;
+ m_dcp = 0;
+ m_swm = 0;
+ m_stm = 0;
+ m_reg_a = 0;
+ m_reg_b = 0;
+ m_pcr = 0;
+ m_mask = 0;
+ m_shift = 0;
+ m_index = 0;
+ m_fc = 0;
+ m_bc = 0;
+ m_tc = 0;
+ m_csr_r = 0;
+
+ m_ica_timer->adjust(screen().time_until_pos(0, 0));
+ m_dca_timer->adjust(screen().time_until_pos(32, 784));
+}
+
+// default address map
+void scc66470_device::scc66470_vram(address_map &map)
+{
+ if(!has_configured_map(0))
+ {
+ map(0x00000000, 0x0017ffff).ram();
+ }
+}
+
+device_memory_interface::space_config_vector scc66470_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+
+void scc66470_device::set_vectors(uint16_t *src)
+{
+ for(int i = 0 ; i < 4 ; i++)
+ {
+ dram_w(i, *src++, 0xffff);
+ }
+}
+
+
+void scc66470_device::dram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ space().write_word(offset<<1, data, mem_mask);
+}
+
+uint16_t scc66470_device::dram_r(offs_t offset, uint16_t mem_mask)
+{
+ return space().read_word(offset<<1, mem_mask);
+}
+
+inline uint8_t scc66470_device::dram_byte_r(offs_t offset)
+{
+ return space().read_byte(offset);
+}
+
+void scc66470_device::csr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_csr);
+}
+
+void scc66470_device::dcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_dcr);
+}
+
+void scc66470_device::vsr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_vsr);
+}
+
+void scc66470_device::bcr_w(offs_t offset, uint8_t data)
+{
+ m_bcr = data;
+}
+
+void scc66470_device::dcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_dcr2);
+}
+
+void scc66470_device::dcp_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_dcp);
+}
+
+void scc66470_device::swm_w(offs_t offset, uint8_t data)
+{
+ m_swm = data | data << 8;
+}
+
+void scc66470_device::stm_w(offs_t offset, uint8_t data)
+{
+ m_stm = data;
+}
+
+void scc66470_device::reg_a_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_reg_a);
+}
+
+void scc66470_device::reg_b_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_reg_b);
+ perform_pixac_op();
+}
+
+void scc66470_device::pcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_pcr);
+
+ if(!BIT(m_pcr, PIXAC_COL) || !BIT(m_pcr, PIXAC_4N) || !BIT(m_pcr, PIXAC_BIT))
+ {
+ logerror("unsuppported pixac %x\n", m_pcr);
+ }
+}
+
+void scc66470_device::mask_w(offs_t offset, uint8_t data)
+{
+ m_mask = data;
+}
+
+void scc66470_device::shift_w(offs_t offset, uint8_t data)
+{
+ m_shift = data;
+}
+
+void scc66470_device::index_w(offs_t offset, uint8_t data)
+{
+ m_index = data;
+}
+
+void scc66470_device::fc_w(offs_t offset, uint8_t data)
+{
+ m_fc = data;
+}
+
+void scc66470_device::bc_w(offs_t offset, uint8_t data)
+{
+ m_bc = data;
+}
+
+void scc66470_device::tc_w(offs_t offset, uint8_t data)
+{
+ m_tc = data;
+}
+
+uint8_t scc66470_device::csr_r(offs_t offset)
+{
+ uint8_t val = m_csr_r;
+
+ if(!machine().side_effects_disabled())
+ {
+ m_csr_r &= ~(CSR_R_IT1 | CSR_R_IT2);
+ m_irqcallback(CLEAR_LINE);
+ }
+
+ int scanline = screen().vpos();
+
+ if(scanline >= total_height() - height())
+ {
+ val |= CSR_R_DA;
+ }
+
+ return val;
+}
+
+uint16_t scc66470_device::reg_b_r(offs_t offset, uint16_t mem_mask)
+{
+ return m_reg_b & mem_mask;
+}
+
+int scc66470_device::dram_dtack_cycles()
+{
+ const int slot_cycle = (int)(machine().time().as_ticks(clock()) & 0xf);
+
+ if(slot_cycle == 9)
+ {
+ return 2;
+ }
+ else if(slot_cycle < 9)
+ {
+ return 2 + 9 - slot_cycle;
+ }
+ else
+ {
+ return 2 + 9 + 16 - slot_cycle;
+ }
+}
+
+void scc66470_device::map(address_map &map)
+{
+ map(0x000000, 0x17ffff).rw(FUNC(scc66470_device::dram_r), FUNC(scc66470_device::dram_w));
+ map(0x1fffe0, 0x1fffe1).w(FUNC(scc66470_device::csr_w));
+ map(0x1fffe1, 0x1fffe1).r(FUNC(scc66470_device::csr_r));
+ map(0x1fffe2, 0x1fffe3).w(FUNC(scc66470_device::dcr_w));
+ map(0x1fffe4, 0x1fffe5).w(FUNC(scc66470_device::vsr_w));
+ map(0x1fffe7, 0x1fffe7).w(FUNC(scc66470_device::bcr_w));
+ map(0x1fffe8, 0x1fffe9).w(FUNC(scc66470_device::dcr2_w));
+ map(0x1fffea, 0x1fffeb).w(FUNC(scc66470_device::dcp_w));
+ map(0x1fffec, 0x1fffec).w(FUNC(scc66470_device::swm_w));
+ map(0x1fffef, 0x1fffef).w(FUNC(scc66470_device::stm_w));
+ map(0x1ffff0, 0x1ffff1).w(FUNC(scc66470_device::reg_a_w));
+ map(0x1ffff2, 0x1ffff3).rw(FUNC(scc66470_device::reg_b_r), FUNC(scc66470_device::reg_b_w));
+ map(0x1ffff4, 0x1ffff5).w(FUNC(scc66470_device::pcr_w));
+ map(0x1ffff7, 0x1ffff7).w(FUNC(scc66470_device::mask_w));
+ map(0x1ffff8, 0x1ffff8).w(FUNC(scc66470_device::shift_w));
+ map(0x1ffffb, 0x1ffffb).w(FUNC(scc66470_device::index_w));
+ map(0x1ffffc, 0x1ffffc).w(FUNC(scc66470_device::fc_w));
+ map(0x1ffffd, 0x1ffffd).w(FUNC(scc66470_device::bc_w));
+ map(0x1ffffe, 0x1ffffe).w(FUNC(scc66470_device::tc_w));
+}
+
+int scc66470_device::pixac_trigger()
+{
+ if(BIT(m_pcr, PIXAC_COL))
+ {
+ return 1;
+ }
+ else if(BIT(m_pcr, PIXAC_CPY) && !BIT(m_pcr, PIXAC_TT))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void scc66470_device::perform_pixac_op()
+{
+ if(BIT(m_pcr, PIXAC_COL) && BIT(m_pcr, PIXAC_BIT))
+ {
+ if(BIT(m_pcr, PIXAC_4N))
+ {
+ uint16_t result = m_reg_b;
+ m_index &= 0xf;
+
+ if(BIT(m_reg_a, 15 - m_index))
+ {
+ result = (result & 0xff) | m_fc << 8;
+ }
+ else if(!BIT(m_pcr, PIXAC_TT))
+ {
+ result = (result & 0xff) | m_bc << 8;
+ }
+
+ m_index++;
+
+ m_index &= 0xf;
+
+ if(BIT(m_reg_a, 15 - m_index))
+ {
+ result = (result & 0xff00) | m_fc;
+ }
+ else if(!BIT(m_pcr, PIXAC_TT))
+ {
+ result = (result & 0xff00) | m_bc;
+ }
+
+ m_index++;
+
+ m_reg_b = (m_reg_b & ~m_swm) | (result & m_swm);
+ }
+ }
+}
+
+
+uint16_t scc66470_device::ipa_r(offs_t offset, uint16_t mem_mask)
+{
+ if(offset < 0x180000 / 2)
+ {
+ if(pixac_trigger())
+ {
+ reg_b_w(0, dram_r(offset, 0xffff), 0xffff);
+ }
+ }
+
+ return 0;
+}
+
+void scc66470_device::ipa_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ if(offset < 0x180000 / 2)
+ {
+ if(pixac_trigger())
+ {
+ dram_w(offset, m_reg_b, 0xffff);
+ }
+ }
+}
+
+bool scc66470_device::display_enabled()
+{
+ if(BIT(DCR_REG, DCR_DE))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void scc66470_device::set_vsr(uint32_t vsr)
+{
+ m_dcr = (m_dcr & 0xfff0) | ((vsr >> 16) & 0x0f);
+ m_vsr = vsr;
+}
+
+uint32_t scc66470_device::get_vsr()
+{
+ return ((m_dcr & 0xf) << 16) | m_vsr;
+}
+
+uint32_t scc66470_device::get_dcp()
+{
+ return ((m_dcr2 & 0x0f) << 16) | m_dcp;
+}
+
+void scc66470_device::set_dcp(uint32_t dcp)
+{
+ m_dcr2 = (m_dcr2 & 0xfff0) | (dcp & 0x0f);
+ m_dcp = dcp;
+}
+
+void scc66470_device::line(int line, uint8_t *line_buffer, unsigned line_buffer_size)
+{
+ if(line_buffer_size == width())
+ {
+ if(display_enabled() && line >= (total_height() - height()))
+ {
+ uint8_t bc = m_bcr;
+
+ if(BIT(DCR_REG, DCR_CM)) //4 bits/pixel
+ {
+ bc = bc >> 4;
+ }
+
+ line -= total_height() - height();
+
+ if(line < border_height() || line >= (height() - border_height()))
+ {
+ std::fill_n(line_buffer, width(), bc);
+
+ if(line == height() - 1)
+ {
+ set_vsr(0);
+ }
+ }
+ else
+ {
+ unsigned vsr = get_vsr() & 0xfffff;
+
+ if(vsr)
+ {
+ line_buffer = std::fill_n(line_buffer, border_width(), bc);
+
+ if(BIT(DCR_REG, DCR_CM)) //4 bits/pixel
+ {
+ if(!BIT(DCR2_REG, DCR2_FT1))
+ {
+ for(int i = 0 ; i < width() - (border_width() * 2) ; i += 2)
+ {
+ uint8_t pixels = dram_byte_r(vsr++);
+ *line_buffer++ = (pixels >> 4) & 0x0f;
+ *line_buffer++ = (pixels) & 0x0f;
+ vsr &= 0xfffff;
+ }
+ }
+ }
+ else
+ {
+ if(!BIT(DCR2_REG, DCR2_FT1))
+ {
+ for(int i = 0 ; i < width() - (border_width() * 2) ; i += 2)
+ {
+ const uint8_t pixel = dram_byte_r(vsr++);
+ *line_buffer++ = pixel;
+ *line_buffer++ = pixel;
+ vsr &= 0xfffff;
+ }
+ }
+ }
+
+ std::fill_n(line_buffer, border_width(), bc);
+
+ if(BIT(DCR_REG, DCR_LS))
+ {
+ vsr = get_vsr() + 512;
+
+ if(BIT(DCR_REG, DCR_IC))
+ {
+ m_working_dcp = vsr - 64;
+ }
+ else
+ {
+ m_working_dcp = vsr - 16;
+ }
+ }
+ else
+ {
+ if(!BIT(DCR2_REG, DCR2_ID))
+ {
+ if(BIT(DCR_REG, DCR_DC))
+ {
+ m_working_dcp = vsr;
+
+ if(BIT(DCR_REG, DCR_IC))
+ {
+ vsr += 64;
+ }
+ else
+ {
+ vsr += 16;
+ }
+ }
+ }
+ }
+
+ set_vsr(vsr);
+ }
+ else
+ {
+ std::fill_n(line_buffer, line_buffer_size, 0);
+ }
+ }
+ }
+ else
+ {
+ std::fill_n(line_buffer, line_buffer_size, 0);
+ }
+ }
+ else
+ {
+ std::fill_n(line_buffer, line_buffer_size, 0);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(scc66470_device::process_ica)
+{
+ uint32_t ctrl = 0x400 / 2;
+
+ if((BIT(DCR_REG, DCR_IC) || BIT(DCR_REG, DCR_DC)) && dram_r(ctrl, 0xffff) != 0)
+ {
+ bool stop = false;
+ while(!stop)
+ {
+ uint16_t cmd = dram_r(ctrl++, 0xffff);
+ uint16_t data = dram_r(ctrl++, 0xffff);
+
+ ctrl &= 0xffffe;
+
+ switch(cmd & 0xff00)
+ {
+ case SCC_INS_STOP:
+ set_vsr((ctrl - 2) * 2);
+ stop = true;
+ break;
+
+ case SCC_INS_NOP:
+ break;
+
+ case SCC_INS_LOAD_DCP:
+ set_dcp(((cmd & 0xf) << 16) | (data & 0xfc));
+ break;
+
+ case SCC_INS_LOAD_DCP_STOP:
+ set_dcp(((cmd & 0xf) << 16) | (data & 0xfc));
+ stop = true;
+ break;
+
+ case SCC_INS_LOAD_VSR:
+ ctrl = (((cmd & 0xf) << 16) | data) / 2;
+ ctrl &= 0xffffe;
+ break;
+
+ case SCC_INS_LOAD_VSR_STOP:
+ ctrl = ((cmd & 0xf) << 16) | data;
+ ctrl &= 0xffffe;
+ set_vsr(ctrl);
+ stop = true;
+ break;
+
+ case SCC_INS_INTERRUPT:
+ m_csr_r |= CSR_R_IT1;
+
+ if(!BIT(CSR_REG, CSR_DI1))
+ {
+ m_irqcallback(ASSERT_LINE);
+ }
+
+ break;
+
+ default:
+ if((cmd & 0xf800) == SCC_INS_LOAD_BORDER)
+ {
+ m_bcr = cmd & 0xff;
+ }
+ else if((cmd & 0xf800) == SCC_INS_LOAD_BORDER_DSP)
+ {
+ m_bcr = cmd & 0xff;
+ m_dcr2 = (m_dcr2 & 0x90ff) | (data & 0x6f) << 8;
+ m_dcr = (m_dcr & 0xfaff) | (data & 0x0500);
+ }
+ else if(cmd & SCC_INS_BEP_CONTROL)
+ {
+ //need to implement ?
+ }
+ else
+ {
+ logerror("Unknown ica/dca instruction %x %x %x\n",cmd,data,ctrl);
+ }
+ }
+ }
+ }
+
+ m_working_dcp = 0;
+
+ if(BIT(DCR_REG, DCR_DC) && BIT(DCR2_REG, DCR2_ID))
+ {
+ m_working_dcp = get_dcp();
+ }
+
+ m_ica_timer->adjust(screen().time_until_pos(0, 0));
+}
+
+TIMER_CALLBACK_MEMBER(scc66470_device::process_dca)
+{
+ uint32_t ctrl = (m_working_dcp / 2) & 0xffffe;
+
+ if(BIT(DCR_REG, DCR_DC) && ctrl)
+ {
+ bool stop = false;
+ bool new_dcp = false;
+ uint32_t count;
+
+ if(!BIT(DCR_REG, DCR_IC))
+ {
+ count = 16;
+ }
+ else
+ {
+ count = 64;
+ }
+
+ while(!stop && count)
+ {
+ uint16_t cmd = dram_r(ctrl++, 0xffff);
+ uint16_t data = dram_r(ctrl++, 0xffff);
+
+ ctrl &= 0xffffe;
+
+ count -= 4;
+
+ switch(cmd & 0xff00)
+ {
+ case SCC_INS_STOP:
+ stop = true;
+ break;
+
+ case SCC_INS_NOP:
+ break;
+
+ case SCC_INS_LOAD_DCP:
+ m_working_dcp = ((cmd & 0xf) << 16) | (data & 0xfc);
+ set_dcp(m_working_dcp);
+ ctrl = m_working_dcp / 2;
+ ctrl &= 0xffffe;
+ break;
+
+ case SCC_INS_LOAD_DCP_STOP:
+ m_working_dcp = ((cmd & 0xf) << 16) | (data & 0xfc);
+ set_dcp(m_working_dcp);
+ stop = true;
+ new_dcp = true;
+ break;
+
+ case SCC_INS_LOAD_VSR:
+ set_vsr(((cmd & 0xf) << 16) | data);
+ break;
+
+ case SCC_INS_LOAD_VSR_STOP:
+ set_vsr(((cmd & 0xf) << 16) | data);
+ stop = true;
+ break;
+
+ case SCC_INS_INTERRUPT:
+ m_csr_r |= CSR_R_IT1;
+
+ if(!BIT(CSR_REG, CSR_DI1))
+ {
+ m_irqcallback(ASSERT_LINE);
+ }
+
+ break;
+
+ default:
+ if((cmd & 0xf800) == SCC_INS_LOAD_BORDER)
+ {
+ m_bcr = cmd & 0xff;
+ }
+ else if((cmd & 0xf800) == SCC_INS_LOAD_BORDER_DSP)
+ {
+ m_bcr = cmd & 0xff;
+ m_dcr2 = (m_dcr2 & 0x90ff) | (data & 0x6f) << 8;
+ m_dcr = (m_dcr & 0xfaff) | (data & 0x0500);
+ }
+ else if(cmd & SCC_INS_BEP_CONTROL)
+ {
+ //need to implement ?
+ }
+ else
+ {
+ logerror("Unknown ica instruction %x %x %x\n",cmd,data,ctrl);
+ }
+ }
+ }
+
+ ctrl *= 2;
+
+ if(!new_dcp)
+ {
+ ctrl += count;
+ }
+
+ if(BIT(DCR_REG, DCR_DC) && BIT(DCR2_REG, DCR2_ID))
+ {
+ m_working_dcp = ctrl;
+ }
+ else
+ {
+ m_working_dcp = 0;
+ }
+ }
+
+ int scanline = screen().vpos();
+
+ if(scanline == total_height() - border_height() - 1)
+ {
+ m_csr_r ^= CSR_R_PA;
+
+ m_dca_timer->adjust(screen().time_until_pos(total_height() - height() + border_height(), 784));
+ }
+ else
+ {
+ m_dca_timer->adjust(screen().time_until_pos(scanline + 1, 784));
+ }
+}
+
+unsigned scc66470_device::border_width()
+{
+ const unsigned hoffset = (BIT(DCR_REG, DCR_CF1) << 3) | (BIT(DCR_REG, DCR_CF2) << 2) | (BIT(DCR_REG, DCR_SS) << 1) | BIT(CSR_REG, CSR_ST);
+ return h_table[ hoffset ].border / 2;
+}
+
+int scc66470_device::border_height()
+{
+ int height = 0;
+
+ if(!BIT(DCR_REG, DCR_FD) && BIT(CSR_REG, CSR_ST))
+ {
+ height = 20;
+ }
+
+ if(!BIT(DCR_REG, DCR_SS))
+ {
+ height += 15;
+ }
+
+ return height;
+}
+
+unsigned scc66470_device::width()
+{
+ const unsigned hoffset = (BIT(DCR_REG, DCR_CF1) << 3) | (BIT(DCR_REG, DCR_CF2) << 2) | (BIT(DCR_REG, DCR_SS) << 1) | BIT(CSR_REG, CSR_ST);
+ return h_table[ hoffset ].pixels;
+}
+
+unsigned scc66470_device::height()
+{
+ if(BIT(DCR_REG, DCR_FD))
+ {
+ return 240;
+ }
+ else
+ {
+ return 280;
+ }
+}
+
+unsigned scc66470_device::total_height()
+{
+ if(BIT(DCR_REG, DCR_FD))
+ {
+ return 262;
+ }
+ else
+ {
+ return 312;
+ }
+}
diff --git a/src/devices/machine/scc66470.h b/src/devices/machine/scc66470.h
new file mode 100644
index 00000000000..d5a5700b304
--- /dev/null
+++ b/src/devices/machine/scc66470.h
@@ -0,0 +1,115 @@
+// license:BSD-3-Clause
+// copyright-holders:Paul Arnold
+/***************************************************************************
+
+ scc66470.h
+
+***************************************************************************/
+
+#ifndef MAME_VIDEO_SCC66470_H
+#define MAME_VIDEO_SCC66470_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> scc66470_device
+
+class scc66470_device : public device_t, public device_memory_interface, public device_video_interface
+{
+public:
+ auto irq()
+ {
+ return m_irqcallback.bind();
+ }
+
+ // construction/destruction
+ scc66470_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ uint16_t ipa_r(offs_t offset, uint16_t mem_mask = ~0);
+ void ipa_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ bool display_enabled();
+ void line(int line, uint8_t *line_buffer, unsigned line_buffer_size);
+ unsigned width();
+ unsigned height();
+ unsigned total_height();
+ int dram_dtack_cycles();
+ void dram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t dram_r(offs_t offset, uint16_t mem_mask = ~0);
+ void map(address_map &map);
+ void set_vectors(uint16_t *src);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual space_config_vector memory_space_config() const override;
+
+ devcb_write_line m_irqcallback;
+
+ uint32_t m_working_dcp;
+
+ uint16_t m_csr;
+ uint16_t m_dcr;
+ uint16_t m_vsr;
+ uint8_t m_bcr;
+ uint16_t m_dcr2;
+ uint16_t m_dcp;
+ uint16_t m_swm;
+ uint8_t m_stm;
+ uint16_t m_reg_a;
+ uint16_t m_reg_b;
+ uint16_t m_pcr;
+ uint8_t m_mask;
+ uint8_t m_shift;
+ uint8_t m_index;
+ uint8_t m_fc;
+ uint8_t m_bc;
+ uint8_t m_tc;
+ uint8_t m_csr_r;
+
+private:
+ void scc66470_vram(address_map &map);
+ void set_vsr(uint32_t vsr);
+ void set_dcp(uint32_t dcp);
+ uint32_t get_vsr();
+ uint32_t get_dcp();
+ unsigned border_width();
+ int border_height();
+ void csr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void dcr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void vsr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void bcr_w(offs_t offset, uint8_t data);
+ void dcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void dcp_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void swm_w(offs_t offset, uint8_t data);
+ void stm_w(offs_t offset, uint8_t data);
+ void reg_a_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void reg_b_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void pcr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void mask_w(offs_t offset, uint8_t data);
+ void shift_w(offs_t offset, uint8_t data);
+ void index_w(offs_t offset, uint8_t data);
+ void fc_w(offs_t offset, uint8_t data);
+ void bc_w(offs_t offset, uint8_t data);
+ void tc_w(offs_t offset, uint8_t data);
+ uint8_t csr_r(offs_t offset);
+ uint16_t reg_b_r(offs_t offset, uint16_t mem_mask = ~0);
+ int pixac_trigger();
+ void perform_pixac_op();
+ inline uint8_t dram_byte_r(offs_t offset);
+
+ TIMER_CALLBACK_MEMBER(process_ica);
+ TIMER_CALLBACK_MEMBER(process_dca);
+ emu_timer *m_ica_timer;
+ emu_timer *m_dca_timer;
+
+ const address_space_config m_space_config;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(SCC66470, scc66470_device)
+
+#endif // MAME_VIDEO_SCC66470_H
diff --git a/src/devices/machine/scc68070.cpp b/src/devices/machine/scc68070.cpp
index 84debddc48d..57238532f41 100644
--- a/src/devices/machine/scc68070.cpp
+++ b/src/devices/machine/scc68070.cpp
@@ -13,26 +13,27 @@
STATUS:
-- Skeleton. Just enough for the CD-i to run.
+- Skeleton. Just enough for the CD-i and Magicard to run.
TODO:
- Proper handling of the 68070's internal devices (UART, DMA, Timers, etc.)
+- I2C could do with re-visiting.
*******************************************************************************/
#include "emu.h"
-#include "machine/scc68070.h"
-
-#define LOG_I2C (1 << 0)
-#define LOG_UART (1 << 1)
-#define LOG_TIMERS (1 << 2)
-#define LOG_TIMERS_HF (1 << 3)
-#define LOG_DMA (1 << 4)
-#define LOG_MMU (1 << 5)
-#define LOG_IRQS (1 << 6)
-#define LOG_UNKNOWN (1 << 7)
-#define LOG_MORE_UART (1 << 8)
+#include "scc68070.h"
+
+#define LOG_I2C (1U << 1)
+#define LOG_UART (1U << 2)
+#define LOG_TIMERS (1U << 3)
+#define LOG_TIMERS_HF (1U << 4)
+#define LOG_DMA (1U << 5)
+#define LOG_MMU (1U << 6)
+#define LOG_IRQS (1U << 7)
+#define LOG_UNKNOWN (1U << 8)
+#define LOG_MORE_UART (1U << 9)
#define LOG_ALL (LOG_I2C | LOG_UART | LOG_TIMERS | LOG_DMA | LOG_MMU | LOG_IRQS | LOG_UNKNOWN)
#define VERBOSE (0)
@@ -41,6 +42,165 @@ TODO:
#define ENABLE_UART_PRINTING (0)
+//**************************************************************************
+// Register defines
+//**************************************************************************
+enum isr_bits
+{
+ ISR_MST = 0x80, // Master
+ ISR_TRX = 0x40, // Transmitter
+ ISR_BB = 0x20, // Busy
+ ISR_PIN = 0x10, // No Pending Interrupt
+ ISR_AL = 0x08, // Arbitration Lost
+ ISR_AAS = 0x04, // Addressed As Slave
+ ISR_AD0 = 0x02, // Address Zero
+ ISR_LRB = 0x01, // Last Received Bit
+ ISR_SSR_MASK = (ISR_MST | ISR_TRX | ISR_BB),// Mask for detecting start/stop/restart
+ ISR_START = (ISR_MST | ISR_TRX | ISR_BB),// Start bit request
+ ISR_STOP = (ISR_MST | ISR_TRX) // Stop bit request
+};
+
+enum umr_bits
+{
+ UMR_OM = 0xc0,
+ UMR_OM_NORMAL = 0x00,
+ UMR_OM_ECHO = 0x40,
+ UMR_OM_LOOPBACK = 0x80,
+ UMR_OM_RLOOP = 0xc0,
+ UMR_TXC = 0x10,
+ UMR_PC = 0x08,
+ UMR_P = 0x04,
+ UMR_SB = 0x02,
+ UMR_CL = 0x01
+};
+
+enum usr_bits
+{
+ USR_RB = 0x80,
+ USR_FE = 0x40,
+ USR_PE = 0x20,
+ USR_OE = 0x10,
+ USR_TXEMT = 0x08,
+ USR_TXRDY = 0x04,
+ USR_RXRDY = 0x01
+};
+
+enum tsr_bits
+{
+ TSR_OV0 = 0x80,
+ TSR_MA1 = 0x40,
+ TSR_CAP1 = 0x20,
+ TSR_OV1 = 0x10,
+ TSR_MA2 = 0x08,
+ TSR_CAP2 = 0x04,
+ TSR_OV2 = 0x02
+};
+
+enum tcr_bits
+{
+ TCR_E1 = 0xc0,
+ TCR_E1_NONE = 0x00,
+ TCR_E1_RISING = 0x40,
+ TCR_E1_FALLING = 0x80,
+ TCR_E1_BOTH = 0xc0,
+ TCR_M1 = 0x30,
+ TCR_M1_NONE = 0x00,
+ TCR_M1_MATCH = 0x10,
+ TCR_M1_CAPTURE = 0x20,
+ TCR_M1_COUNT = 0x30,
+ TCR_E2 = 0x0c,
+ TCR_E2_NONE = 0x00,
+ TCR_E2_RISING = 0x04,
+ TCR_E2_FALLING = 0x08,
+ TCR_E2_BOTH = 0x0c,
+ TCR_M2 = 0x03,
+ TCR_M2_NONE = 0x00,
+ TCR_M2_MATCH = 0x01,
+ TCR_M2_CAPTURE = 0x02,
+ TCR_M2_COUNT = 0x03
+};
+
+enum csr_bits
+{
+ CSR_COC = 0x80,
+ CSR_NDT = 0x20,
+ CSR_ERR = 0x10,
+ CSR_CA = 0x08
+};
+
+enum cer_bits
+{
+ CER_EC = 0x1f,
+ CER_NONE = 0x00,
+ CER_TIMING = 0x02,
+ CER_BUSERR_MEM = 0x09,
+ CER_BUSERR_DEV = 0x0a,
+ CER_SOFT_ABORT = 0x11
+};
+
+enum dcr1_bits
+{
+ DCR1_ERM = 0x80,
+ DCR1_DT = 0x30
+};
+
+enum dcr2_bits
+{
+ DCR2_ERM = 0x80,
+ DCR2_DT = 0x30,
+ DCR2_DS = 0x08
+};
+
+
+enum scr2_bits
+{
+ SCR2_MAC = 0x0c,
+ SCR2_MAC_NONE = 0x00,
+ SCR2_MAC_INC = 0x04,
+ SCR2_DAC = 0x03,
+ SCR2_DAC_NONE = 0x00,
+ SCR2_DAC_INC = 0x01
+};
+
+enum ccr_bits
+{
+ CCR_SO = 0x80,
+ CCR_SA = 0x10,
+ CCR_INE = 0x08,
+ CCR_IPL = 0x07
+};
+
+enum icr_bits
+{
+ ICR_SEL = 0x40,
+ ICR_ESO = 0x08,
+ ICR_ACK = 0x04
+};
+
+enum i2c_states
+{
+ I2C_IDLE = 0,
+ I2C_TX_IN_PROGRESS,
+ I2C_RX_IN_PROGRESS,
+ I2C_RX_COMPLETE,
+ I2C_GET_ACK,
+ I2C_SEND_ACK,
+ I2C_SEND_ACK_AND_RX,
+ I2C_SEND_ACK_AND_STOP,
+ I2C_SEND_STOP,
+ I2C_CHANGED_TO_RX,
+ I2C_SEND_RESTART
+};
+
+enum i2c_clock_states
+{
+ I2C_SCL_IDLE = 0,
+ I2C_SCL_SET_0,
+ I2C_SCL_SET_1,
+ I2C_SCL_WAIT_1,
+};
+
+
// device type definition
DEFINE_DEVICE_TYPE(SCC68070, scc68070_device, "scc68070", "Philips SCC68070")
@@ -80,12 +240,15 @@ void scc68070_device::cpu_space_map(address_map &map)
scc68070_device::scc68070_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: scc68070_base_device(mconfig, tag, owner, clock, SCC68070, address_map_constructor(FUNC(scc68070_device::internal_map), this))
- , m_iack2_callback(*this)
- , m_iack4_callback(*this)
- , m_iack5_callback(*this)
- , m_iack7_callback(*this)
+ , m_iack2_callback(*this, autovector(2))
+ , m_iack4_callback(*this, autovector(4))
+ , m_iack5_callback(*this, autovector(5))
+ , m_iack7_callback(*this, autovector(7))
, m_uart_tx_callback(*this)
, m_uart_rtsn_callback(*this)
+ , m_i2c_scl_callback(*this)
+ , m_i2c_sdaw_callback(*this)
+ , m_i2c_sdar_callback(*this, 0)
, m_ipl(0)
, m_in2_line(CLEAR_LINE)
, m_in4_line(CLEAR_LINE)
@@ -98,24 +261,6 @@ scc68070_device::scc68070_device(const machine_config &mconfig, const char *tag,
}
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void scc68070_device::device_resolve_objects()
-{
- scc68070_base_device::device_resolve_objects();
-
- m_iack2_callback.resolve_safe(autovector(2));
- m_iack4_callback.resolve_safe(autovector(4));
- m_iack5_callback.resolve_safe(autovector(5));
- m_iack7_callback.resolve_safe(autovector(7));
- m_uart_tx_callback.resolve_safe();
- m_uart_rtsn_callback.resolve_safe();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -146,6 +291,16 @@ void scc68070_device::device_start()
save_item(NAME(m_i2c.status_register));
save_item(NAME(m_i2c.control_register));
save_item(NAME(m_i2c.clock_control_register));
+ save_item(NAME(m_i2c.scl_out_state));
+ save_item(NAME(m_i2c.scl_in_state));
+ save_item(NAME(m_i2c.sda_out_state));
+ save_item(NAME(m_i2c.sda_in_state));
+ save_item(NAME(m_i2c.state));
+ save_item(NAME(m_i2c.counter));
+ save_item(NAME(m_i2c.clock_change_state));
+ save_item(NAME(m_i2c.clocks));
+ save_item(NAME(m_i2c.first_byte));
+ save_item(NAME(m_i2c.ack_or_nak_sent));
save_item(NAME(m_uart.mode_register));
save_item(NAME(m_uart.status_register));
@@ -183,14 +338,17 @@ void scc68070_device::device_start()
save_item(STRUCT_MEMBER(m_mmu.desc, segment));
save_item(STRUCT_MEMBER(m_mmu.desc, base));
- m_timers.timer0_timer = timer_alloc(TIMER_TMR0);
+ m_timers.timer0_timer = timer_alloc(FUNC(scc68070_device::timer0_callback), this);
m_timers.timer0_timer->adjust(attotime::never);
- m_uart.rx_timer = timer_alloc(TIMER_UART_RX);
+ m_uart.rx_timer = timer_alloc(FUNC(scc68070_device::rx_callback), this);
m_uart.rx_timer->adjust(attotime::never);
- m_uart.tx_timer = timer_alloc(TIMER_UART_TX);
+ m_uart.tx_timer = timer_alloc(FUNC(scc68070_device::tx_callback), this);
m_uart.tx_timer->adjust(attotime::never);
+
+ m_i2c.timer = timer_alloc(FUNC(scc68070_device::i2c_callback), this);
+ m_i2c.timer->adjust(attotime::never);
}
//-------------------------------------------------
@@ -212,9 +370,15 @@ void scc68070_device::device_reset()
m_i2c.data_register = 0;
m_i2c.address_register = 0;
- m_i2c.status_register = 0;
+ m_i2c.status_register = ISR_PIN;
m_i2c.control_register = 0;
m_i2c.clock_control_register = 0;
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ m_i2c.clocks = 0;
m_uart.mode_register = 0;
m_uart.status_register = USR_TXRDY;
@@ -260,53 +424,58 @@ void scc68070_device::device_reset()
m_uart.rx_timer->adjust(attotime::never);
m_uart.tx_timer->adjust(attotime::never);
- m_timers.timer0_timer->adjust(attotime::never);
+ set_timer_callback(0);
}
-//-------------------------------------------------
-// device_timer - device-specific timer callback
-//-------------------------------------------------
-void scc68070_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void scc68070_device::device_config_complete()
{
- if (id == TIMER_TMR0)
- timer0_callback();
- else if (id == TIMER_UART_RX)
- rx_callback();
- else if (id == TIMER_UART_TX)
- tx_callback();
+ scc68070_base_device::device_config_complete();
+
+ reset_cb().append(*this, FUNC(scc68070_device::reset_peripherals));
}
-void scc68070_device::m68k_reset_peripherals()
-{
- m_lir = 0;
- m_picr1 = 0;
- m_picr2 = 0;
- m_timer_int = false;
- m_i2c_int = false;
- m_uart_rx_int = false;
- m_uart_tx_int = false;
-
- m_i2c.status_register = 0;
- m_i2c.control_register = 0;
- m_i2c.clock_control_register = 0;
- m_uart.command_register = 0;
- m_uart.receive_pointer = -1;
- m_uart.transmit_pointer = -1;
+void scc68070_device::reset_peripherals(int state)
+{
+ if (state)
+ {
+ m_lir = 0;
+
+ m_picr1 = 0;
+ m_picr2 = 0;
+ m_timer_int = false;
+ m_i2c_int = false;
+ m_uart_rx_int = false;
+ m_uart_tx_int = false;
+
+ m_i2c.status_register = ISR_PIN;
+ m_i2c.control_register = 0;
+ m_i2c.clock_control_register = 0;
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ m_i2c.clocks = 0;
+ m_uart.command_register = 0;
+ m_uart.receive_pointer = -1;
+ m_uart.transmit_pointer = -1;
- m_uart.mode_register = 0;
- m_uart.status_register = USR_TXRDY;
- m_uart.clock_select = 0;
+ m_uart.mode_register = 0;
+ m_uart.status_register = USR_TXRDY;
+ m_uart.clock_select = 0;
- m_timers.timer_status_register = 0;
- m_timers.timer_control_register = 0;
+ m_timers.timer_status_register = 0;
+ m_timers.timer_control_register = 0;
- m_uart.rx_timer->adjust(attotime::never);
- m_uart.tx_timer->adjust(attotime::never);
- m_timers.timer0_timer->adjust(attotime::never);
+ m_uart.rx_timer->adjust(attotime::never);
+ m_uart.tx_timer->adjust(attotime::never);
+ m_timers.timer0_timer->adjust(attotime::never);
+ m_i2c.timer->adjust(attotime::never);
- update_ipl();
+ update_ipl();
+ }
}
void scc68070_device::update_ipl()
@@ -336,31 +505,31 @@ void scc68070_device::update_ipl()
}
}
-WRITE_LINE_MEMBER(scc68070_device::in2_w)
+void scc68070_device::in2_w(int state)
{
m_in2_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::in4_w)
+void scc68070_device::in4_w(int state)
{
m_in4_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::in5_w)
+void scc68070_device::in5_w(int state)
{
m_in5_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::nmi_w)
+void scc68070_device::nmi_w(int state)
{
m_nmi_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::int1_w)
+void scc68070_device::int1_w(int state)
{
if (m_int1_line != state)
{
@@ -374,7 +543,7 @@ WRITE_LINE_MEMBER(scc68070_device::int1_w)
}
}
-WRITE_LINE_MEMBER(scc68070_device::int2_w)
+void scc68070_device::int2_w(int state)
{
if (m_int2_line != state)
{
@@ -384,7 +553,7 @@ WRITE_LINE_MEMBER(scc68070_device::int2_w)
update_ipl();
}
- m_int1_line = state;
+ m_int2_line = state;
}
}
@@ -469,7 +638,7 @@ void scc68070_device::set_timer_callback(int channel)
}
}
-void scc68070_device::timer0_callback()
+TIMER_CALLBACK_MEMBER(scc68070_device::timer0_callback)
{
m_timers.timer0 = m_timers.reload_register;
m_timers.timer_status_register |= TSR_OV0;
@@ -500,7 +669,7 @@ void scc68070_device::uart_tx(uint8_t data)
m_uart.status_register &= ~USR_TXEMT;
}
-void scc68070_device::rx_callback()
+TIMER_CALLBACK_MEMBER(scc68070_device::rx_callback)
{
if ((m_uart.command_register & 3) == 1)
{
@@ -535,7 +704,7 @@ void scc68070_device::rx_callback()
}
}
-void scc68070_device::tx_callback()
+TIMER_CALLBACK_MEMBER(scc68070_device::tx_callback)
{
if (((m_uart.command_register >> 2) & 3) == 1)
{
@@ -572,13 +741,41 @@ void scc68070_device::tx_callback()
uint8_t scc68070_device::lir_r()
{
// LIR priority level: 80001001
- return m_lir;
+ return m_lir & 0x77;
}
void scc68070_device::lir_w(uint8_t data)
{
LOGMASKED(LOG_IRQS, "%s: LIR Write: %02x\n", machine().describe_context(), data);
- m_lir = data;
+
+ switch (data & 0x88)
+ {
+ case 0x08:
+ if (m_lir & 0x08)
+ {
+ m_lir &= 0xf7;
+ update_ipl();
+ }
+ break;
+
+ case 0x80:
+ if (data & 0x80)
+ {
+ m_lir &= 0x7f;
+ update_ipl();
+ }
+ break;
+
+ case 0x88:
+ if (data & 0x88)
+ {
+ m_lir &= 0x77;
+ update_ipl();
+ }
+ break;
+ }
+
+ m_lir = (m_lir & 0x88) | (data & 0x77);
}
uint8_t scc68070_device::picr1_r()
@@ -668,6 +865,35 @@ uint8_t scc68070_device::idr_r()
// I2C data register: 80002001
if (!machine().side_effects_disabled())
LOGMASKED(LOG_I2C, "%s: I2C Data Register Read: %02x\n", machine().describe_context(), m_i2c.data_register);
+
+ m_i2c.counter = 0;
+ m_i2c.status_register |= ISR_PIN;
+ m_i2c_int = false;
+ update_ipl();
+
+ if (m_i2c.state != I2C_RX_COMPLETE)
+ {
+ }
+ else
+ {
+ m_i2c.sda_out_state = (m_i2c.control_register & ICR_ACK) ? false : true;
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+
+ if (m_i2c.control_register & ICR_ACK)
+ {
+ m_i2c.state = I2C_SEND_ACK_AND_RX;
+ m_i2c.clocks = 9;
+ }
+ else
+ {
+ m_i2c.state = I2C_SEND_ACK;
+ m_i2c.clocks = 1;
+ }
+ m_i2c.ack_or_nak_sent = true;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ set_i2c_timer();
+
+ }
return m_i2c.data_register;
}
@@ -675,6 +901,18 @@ void scc68070_device::idr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Data Register Write: %02x\n", machine().describe_context(), data);
m_i2c.data_register = data;
+ if (m_i2c.status_register & ISR_MST && m_i2c.status_register & ISR_TRX && m_i2c.status_register & ISR_BB)
+ {
+ m_i2c.status_register |= ISR_PIN;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.counter = 0;
+ m_i2c.state = I2C_TX_IN_PROGRESS;
+ m_i2c.clocks = 9;
+ i2c_process_falling_scl();
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ set_i2c_timer();
+ }
}
uint8_t scc68070_device::iar_r()
@@ -696,13 +934,154 @@ uint8_t scc68070_device::isr_r()
// I2C status register: 80002005
if (!machine().side_effects_disabled())
LOGMASKED(LOG_I2C, "%s: I2C Status Register Read: %02x\n", machine().describe_context(), m_i2c.status_register);
- return m_i2c.status_register & 0xef; // hack for magicard
+ return m_i2c.status_register;
}
void scc68070_device::isr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Status Register Write: %02x\n", machine().describe_context(), data);
- m_i2c.status_register = data;
+ if (data & ISR_MST)
+ {
+ if ((data & ISR_SSR_MASK) == ISR_START)
+ {
+ if ((m_i2c.status_register & ISR_SSR_MASK) == ISR_STOP || (m_i2c.status_register & ISR_SSR_MASK) == 0)
+ {
+ if (m_i2c_sdar_callback() && m_i2c.state == I2C_IDLE)
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ m_i2c.clock_change_state = I2C_SCL_SET_0;
+ m_i2c.clocks = 10;
+ m_i2c.state = I2C_TX_IN_PROGRESS;
+ m_i2c.first_byte = true;
+ m_i2c.ack_or_nak_sent = false;
+ set_i2c_timer();
+ m_i2c.counter = 0;
+ }
+ else
+ {
+ m_i2c.status_register |= ISR_AL;
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ }
+ }
+ else if ((m_i2c.status_register & ISR_SSR_MASK) == ISR_MST)
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ m_i2c.clocks = 10;
+ m_i2c.state = I2C_SEND_RESTART;
+ m_i2c.first_byte = true;
+ m_i2c.ack_or_nak_sent = false;
+ set_i2c_timer();
+ m_i2c.counter = 0;
+ }
+ }
+ else if ((data & ISR_SSR_MASK) == ISR_STOP && m_i2c.status_register & ISR_BB)
+ {
+ // we should send STOP here, however, unkte06 in magicard appears to expect
+ // NAK followed by STOP when in read mode.
+
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+
+ if (m_i2c.ack_or_nak_sent || (m_i2c.status_register & ISR_TRX))
+ {
+ m_i2c.state = I2C_SEND_STOP;
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ }
+ else
+ {
+ m_i2c.ack_or_nak_sent = true;
+ m_i2c.sda_out_state = (m_i2c.control_register&ICR_ACK) ? false : true;
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+ m_i2c.state = I2C_SEND_ACK_AND_STOP;
+ m_i2c.clocks = 2;
+ }
+ m_i2c.status_register = data | ISR_BB;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ set_i2c_timer();
+ }
+ else if ((data & ISR_SSR_MASK) == ISR_MST)
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ }
+ else
+ {
+ if (data & ISR_PIN && !(m_i2c.status_register & ISR_PIN))
+ {
+ if (m_i2c.state == I2C_CHANGED_TO_RX)
+ {
+ m_i2c.state = I2C_RX_IN_PROGRESS;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ m_i2c.status_register = data;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.counter = 0;
+ m_i2c.clocks = 8;
+ set_i2c_timer();
+ }
+ else
+ {
+ m_i2c.ack_or_nak_sent = true;
+ m_i2c.sda_out_state = (m_i2c.control_register&ICR_ACK) ? false : true;
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+ m_i2c.status_register = data;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.state = I2C_SEND_ACK;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ m_i2c.clocks = 1;
+ set_i2c_timer();
+ }
+ }
+ else
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ }
+ }
+ }
+ else
+ {
+ m_i2c.status_register = data;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.timer->adjust(attotime::never);
+ m_i2c_scl_callback(1);
+ m_i2c_sdaw_callback(1);
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ }
}
uint8_t scc68070_device::icr_r()
@@ -717,6 +1096,17 @@ void scc68070_device::icr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Control Register Write: %02x\n", machine().describe_context(), data);
m_i2c.control_register = data;
+
+ if (!(data & ICR_ESO))
+ {
+ m_i2c.timer->adjust(attotime::never);
+ m_i2c_scl_callback(1);
+ m_i2c_sdaw_callback(1);
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ }
}
uint8_t scc68070_device::iccr_r()
@@ -733,6 +1123,200 @@ void scc68070_device::iccr_w(uint8_t data)
m_i2c.clock_control_register = data & 0x1f;
}
+
+void scc68070_device::i2c_process_falling_scl()
+{
+ switch (m_i2c.state)
+ {
+ case I2C_TX_IN_PROGRESS:
+ if (m_i2c.counter<8)
+ {
+ m_i2c.sda_out_state = BIT(m_i2c.data_register, 7 - m_i2c.counter);
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+ m_i2c.counter++;
+ }
+ else
+ {
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ m_i2c.state = I2C_GET_ACK;
+ }
+ break;
+
+ case I2C_GET_ACK:
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ m_i2c.state = I2C_IDLE;
+ if (m_i2c.first_byte)
+ {
+ m_i2c.first_byte = false;
+ if (BIT(m_i2c.data_register, 0))
+ {
+ m_i2c.status_register &= ~ISR_TRX;
+ if (!(m_i2c.status_register & ISR_LRB))
+ {
+ m_i2c.state = I2C_CHANGED_TO_RX;
+ }
+ }
+ }
+ break;
+
+ case I2C_RX_IN_PROGRESS:
+ if (m_i2c.counter >= 8)
+ {
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ m_i2c.state = I2C_RX_COMPLETE;
+ }
+ break;
+
+ case I2C_SEND_ACK_AND_RX:
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ m_i2c.state = I2C_RX_IN_PROGRESS;
+ m_i2c.counter = 0;
+ break;
+
+ case I2C_SEND_ACK_AND_STOP:
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ m_i2c.state = I2C_SEND_STOP;
+ break;
+
+ case I2C_SEND_ACK:
+ m_i2c.state = I2C_IDLE;
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ break;
+ }
+}
+
+void scc68070_device::i2c_process_rising_scl()
+{
+ switch (m_i2c.state)
+ {
+ case I2C_GET_ACK:
+ if (m_i2c_sdar_callback())
+ {
+ m_i2c.status_register |= ISR_LRB;
+ }
+ else
+ {
+ m_i2c.status_register &= ~ISR_LRB;
+ }
+ break;
+
+ case I2C_SEND_STOP:
+ case I2C_SEND_RESTART:
+ m_i2c.timer->adjust(attotime::from_nsec(5000));
+ break;
+
+ case I2C_RX_IN_PROGRESS:
+ if (m_i2c.counter < 8)
+ {
+ m_i2c.data_register <<= 1;
+ m_i2c.data_register |= m_i2c_sdar_callback();
+ m_i2c.counter++;
+ }
+ break;
+ }
+}
+
+void scc68070_device::write_scl(int state)
+{
+ if (m_i2c.status_register & ISR_MST)
+ {
+ if (m_i2c.scl_in_state != state && state)
+ {
+ i2c_process_rising_scl();
+ i2c_next_state();
+ }
+ }
+ m_i2c.scl_in_state = state;
+}
+
+TIMER_CALLBACK_MEMBER(scc68070_device::i2c_callback)
+{
+ i2c_next_state();
+}
+
+void scc68070_device::i2c_next_state()
+{
+ switch (m_i2c.clock_change_state)
+ {
+ case I2C_SCL_SET_0:
+ if (m_i2c.state == I2C_SEND_STOP)
+ {
+ if (!m_i2c.sda_out_state)
+ {
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ set_i2c_timer();
+ }
+ else
+ {
+ m_i2c.state = I2C_IDLE;
+ m_i2c.status_register &= ~(ISR_PIN | ISR_BB);
+ m_i2c_int = true;
+ update_ipl();
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ }
+ }
+ else if (m_i2c.state == I2C_SEND_RESTART)
+ {
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ set_i2c_timer();
+ m_i2c.clock_change_state = I2C_SCL_SET_0;
+ m_i2c.state = I2C_TX_IN_PROGRESS;
+ }
+ else
+ {
+ m_i2c.scl_out_state = false;
+ m_i2c_scl_callback(false);
+ if (m_i2c.clocks)
+ {
+ m_i2c.clocks--;
+ }
+ if (m_i2c.clocks == 0)
+ {
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ }
+ else
+ {
+ set_i2c_timer();
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ }
+ i2c_process_falling_scl();
+ }
+ break;
+
+ case I2C_SCL_SET_1:
+ m_i2c.clock_change_state = I2C_SCL_WAIT_1;
+ m_i2c.scl_out_state = true;
+ m_i2c_scl_callback(true);
+ break;
+
+ case I2C_SCL_WAIT_1:
+ set_i2c_timer();
+ m_i2c.clock_change_state = I2C_SCL_SET_0;
+ break;
+ }
+}
+
+void scc68070_device::set_i2c_timer()
+{
+ // divider offset 0 entry is illegal
+ static constexpr int divider[]={ 1, 78, 90, 102, 126, 150, 174, 198,
+ 246, 294, 342, 390, 486, 582, 678, 774,
+ 996, 1158, 1350, 1542, 1926, 2310, 2694, 3078,
+ 3846, 4614, 5382, 6150, 7686, 9222, 10758, 12294 };
+ m_i2c.timer->adjust(cycles_to_attotime(divider[m_i2c.clock_control_register]));
+}
+
uint8_t scc68070_device::umr_r()
{
// UART mode register: 80002011
@@ -884,7 +1468,8 @@ uint16_t scc68070_device::timer_r(offs_t offset, uint16_t mem_mask)
case 0x4/2:
if (!machine().side_effects_disabled())
LOGMASKED(LOG_TIMERS, "%s: Timer 0 Read: %04x & %04x\n", machine().describe_context(), m_timers.timer0, mem_mask);
- return m_timers.timer0;
+ return 0x10000 - (attotime_to_cycles(m_timers.timer0_timer->remaining()) / 96);
+
case 0x6/2:
if (!machine().side_effects_disabled())
LOGMASKED(LOG_TIMERS, "%s: Timer 1 Read: %04x & %04x\n", machine().describe_context(), m_timers.timer1, mem_mask);
@@ -922,6 +1507,7 @@ void scc68070_device::timer_w(offs_t offset, uint16_t data, uint16_t mem_mask)
case 0x2/2:
LOGMASKED(LOG_TIMERS, "%s: Timer Reload Register Write: %04x & %04x\n", machine().describe_context(), data, mem_mask);
COMBINE_DATA(&m_timers.reload_register);
+ set_timer_callback(0);
break;
case 0x4/2:
LOGMASKED(LOG_TIMERS, "%s: Timer 0 Write: %04x & %04x\n", machine().describe_context(), data, mem_mask);
diff --git a/src/devices/machine/scc68070.h b/src/devices/machine/scc68070.h
index 2bae392ab63..c0240163e55 100644
--- a/src/devices/machine/scc68070.h
+++ b/src/devices/machine/scc68070.h
@@ -26,107 +26,20 @@ TODO:
#pragma once
-#include "cpu/m68000/m68000.h"
-
-
-#define ISR_MST 0x80 // Master
-#define ISR_TRX 0x40 // Transmitter
-#define ISR_BB 0x20 // Busy
-#define ISR_PIN 0x10 // No Pending Interrupt
-#define ISR_AL 0x08 // Arbitration Lost
-#define ISR_AAS 0x04 // Addressed As Slave
-#define ISR_AD0 0x02 // Address Zero
-#define ISR_LRB 0x01 // Last Received Bit
-
-#define UMR_OM 0xc0
-#define UMR_OM_NORMAL 0x00
-#define UMR_OM_ECHO 0x40
-#define UMR_OM_LOOPBACK 0x80
-#define UMR_OM_RLOOP 0xc0
-#define UMR_TXC 0x10
-#define UMR_PC 0x08
-#define UMR_P 0x04
-#define UMR_SB 0x02
-#define UMR_CL 0x01
-
-#define USR_RB 0x80
-#define USR_FE 0x40
-#define USR_PE 0x20
-#define USR_OE 0x10
-#define USR_TXEMT 0x08
-#define USR_TXRDY 0x04
-#define USR_RXRDY 0x01
-
-#define TSR_OV0 0x80
-#define TSR_MA1 0x40
-#define TSR_CAP1 0x20
-#define TSR_OV1 0x10
-#define TSR_MA2 0x08
-#define TSR_CAP2 0x04
-#define TSR_OV2 0x02
-
-#define TCR_E1 0xc0
-#define TCR_E1_NONE 0x00
-#define TCR_E1_RISING 0x40
-#define TCR_E1_FALLING 0x80
-#define TCR_E1_BOTH 0xc0
-#define TCR_M1 0x30
-#define TCR_M1_NONE 0x00
-#define TCR_M1_MATCH 0x10
-#define TCR_M1_CAPTURE 0x20
-#define TCR_M1_COUNT 0x30
-#define TCR_E2 0x0c
-#define TCR_E2_NONE 0x00
-#define TCR_E2_RISING 0x04
-#define TCR_E2_FALLING 0x08
-#define TCR_E2_BOTH 0x0c
-#define TCR_M2 0x03
-#define TCR_M2_NONE 0x00
-#define TCR_M2_MATCH 0x01
-#define TCR_M2_CAPTURE 0x02
-#define TCR_M2_COUNT 0x03
-
-#define CSR_COC 0x80
-#define CSR_NDT 0x20
-#define CSR_ERR 0x10
-#define CSR_CA 0x08
-
-#define CER_EC 0x1f
-#define CER_NONE 0x00
-#define CER_TIMING 0x02
-#define CER_BUSERR_MEM 0x09
-#define CER_BUSERR_DEV 0x0a
-#define CER_SOFT_ABORT 0x11
-
-#define DCR1_ERM 0x80
-#define DCR1_DT 0x30
-
-#define DCR2_ERM 0x80
-#define DCR2_DT 0x30
-#define DCR2_DS 0x08
-
-#define OCR_D 0x80
-#define OCR_D_M2D 0x00
-#define OCR_D_D2M 0x80
-#define OCR_OS 0x30
-#define OCR_OS_BYTE 0x00
-#define OCR_OS_WORD 0x10
-
-#define SCR2_MAC 0x0c
-#define SCR2_MAC_NONE 0x00
-#define SCR2_MAC_INC 0x04
-#define SCR2_DAC 0x03
-#define SCR2_DAC_NONE 0x00
-#define SCR2_DAC_INC 0x01
-
-#define CCR_SO 0x80
-#define CCR_SA 0x10
-#define CCR_INE 0x08
-#define CCR_IPL 0x07
+#include "cpu/m68000/scc68070.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
+enum scc68070_ocr_bits
+{
+ SCC68070_OCR_D = 0x80,
+ SCC68070_OCR_D_M2D = 0x00,
+ SCC68070_OCR_D_D2M = 0x80,
+ SCC68070_OCR_OS = 0x30,
+ SCC68070_OCR_OS_BYTE = 0x00,
+ SCC68070_OCR_OS_WORD = 0x10
+};
// ======================> scc68070_device
@@ -141,22 +54,28 @@ public:
auto iack7_callback() { return m_iack7_callback.bind(); }
auto uart_tx_callback() { return m_uart_tx_callback.bind(); }
auto uart_rtsn_callback() { return m_uart_rtsn_callback.bind(); }
+ auto i2c_scl_w() { return m_i2c_scl_callback.bind(); }
+ auto i2c_sda_w() { return m_i2c_sdaw_callback.bind(); }
+ auto i2c_sda_r() { return m_i2c_sdar_callback.bind(); }
+
+ void in2_w(int state);
+ void in4_w(int state);
+ void in5_w(int state);
+ void nmi_w(int state);
+ void int1_w(int state);
+ void int2_w(int state);
- DECLARE_WRITE_LINE_MEMBER(in2_w);
- DECLARE_WRITE_LINE_MEMBER(in4_w);
- DECLARE_WRITE_LINE_MEMBER(in5_w);
- DECLARE_WRITE_LINE_MEMBER(nmi_w);
- DECLARE_WRITE_LINE_MEMBER(int1_w);
- DECLARE_WRITE_LINE_MEMBER(int2_w);
+ void write_scl(int state);
+
+ TIMER_CALLBACK_MEMBER(timer0_callback);
+ TIMER_CALLBACK_MEMBER(rx_callback);
+ TIMER_CALLBACK_MEMBER(tx_callback);
+ TIMER_CALLBACK_MEMBER(i2c_callback);
// external callbacks
void uart_rx(uint8_t data);
void uart_ctsn(int state);
- void timer0_callback();
- void rx_callback();
- void tx_callback();
-
// register structures
struct i2c_regs_t
{
@@ -170,6 +89,17 @@ public:
uint8_t control_register;
uint8_t reserved;
uint8_t clock_control_register;
+ emu_timer* timer;
+ bool scl_out_state;
+ bool scl_in_state;
+ bool sda_out_state;
+ bool sda_in_state;
+ uint8_t clock_change_state;
+ uint8_t clocks;
+ uint8_t state;
+ uint8_t counter;
+ bool first_byte;
+ bool ack_or_nak_sent;
};
struct uart_regs_t
@@ -260,26 +190,20 @@ public:
dma_regs_t& dma() { return m_dma; }
protected:
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ virtual void device_config_complete() override;
- // device_execute_interface overrides
+ // device_execute_interface implementation
virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 2 - 1) / 2; }
virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 2); }
- // m68000_base_device overrides
- virtual void m68k_reset_peripherals() override;
-
private:
void internal_map(address_map &map);
void cpu_space_map(address_map &map);
- static constexpr device_timer_id TIMER_TMR0 = 0;
- static constexpr device_timer_id TIMER_UART_RX = 1;
- static constexpr device_timer_id TIMER_UART_TX = 2;
+ void reset_peripherals(int state);
void update_ipl();
uint8_t iack_r(offs_t offset);
@@ -303,6 +227,10 @@ private:
void icr_w(uint8_t data);
uint8_t iccr_r();
void iccr_w(uint8_t data);
+ void set_i2c_timer();
+ void i2c_process_falling_scl();
+ void i2c_process_rising_scl();
+ void i2c_next_state();
// UART interface
uint8_t umr_r();
@@ -341,6 +269,9 @@ private:
devcb_read8 m_iack7_callback;
devcb_write8 m_uart_tx_callback;
devcb_write_line m_uart_rtsn_callback;
+ devcb_write_line m_i2c_scl_callback;
+ devcb_write_line m_i2c_sdaw_callback;
+ devcb_read8 m_i2c_sdar_callback;
// internal state
uint8_t m_ipl;
diff --git a/src/devices/machine/scn_pci.cpp b/src/devices/machine/scn_pci.cpp
index 73ef2590e66..8a4b1fec9fd 100644
--- a/src/devices/machine/scn_pci.cpp
+++ b/src/devices/machine/scn_pci.cpp
@@ -49,10 +49,10 @@
#include "emu.h"
#include "scn_pci.h"
-#define LOG_INIT (1 << 1U)
-#define LOG_COMMAND (1 << 2U)
-#define LOG_RCVR (1 << 3U)
-#define LOG_XMTR (1 << 4U)
+#define LOG_INIT (1U << 1)
+#define LOG_COMMAND (1U << 2)
+#define LOG_RCVR (1U << 3)
+#define LOG_XMTR (1U << 4)
//#define VERBOSE (LOG_INIT | LOG_COMMAND | LOG_RCVR | LOG_XMTR)
#include "logmacro.h"
@@ -260,50 +260,25 @@ scn2641_device::scn2641_device(const machine_config &mconfig, const char *tag, d
void scn2641_device::device_validity_check(validity_checker &valid) const
{
- if (!m_dtr_callback.isnull())
+ if (!m_dtr_callback.isunset())
osd_printf_error("Nonexistent DTR output configured on SCN2641\n");
- if (!m_txemt_dschg_callback.isnull())
+ if (!m_txemt_dschg_callback.isunset())
osd_printf_error("Nonexistent TxEMT/DSCHG output configured on SCN2641 (use INTR instead)\n");
- if (!m_txrdy_callback.isnull())
+ if (!m_txrdy_callback.isunset())
osd_printf_error("Nonexistent TxRDY output configured on SCN2641 (use INTR instead)\n");
- if (!m_rxrdy_callback.isnull())
+ if (!m_rxrdy_callback.isunset())
osd_printf_error("Nonexistent RxRDY output configured on SCN2641 (use INTR instead)\n");
}
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void scn_pci_device::device_resolve_objects()
-{
- m_dtr_callback.resolve_safe();
- m_rts_callback.resolve_safe();
- m_txemt_dschg_callback.resolve_safe();
- m_txc_callback.resolve_safe();
- m_rxc_callback.resolve_safe();
- m_txd_callback.resolve_safe();
- m_txrdy_callback.resolve_safe();
- m_rxrdy_callback.resolve_safe();
-}
-
-void scn2641_device::device_resolve_objects()
-{
- scn_pci_device::device_resolve_objects();
- m_intr_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void scn_pci_device::device_start()
{
// Create timer for baud rate generator
- m_brg_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scn_pci_device::brg_tick), this));
+ m_brg_timer = timer_alloc(FUNC(scn_pci_device::brg_tick), this);
// Save state
save_item(NAME(m_rhr));
@@ -551,7 +526,7 @@ void scn_pci_device::rx_load_sync(u8 data, bool pe)
// rxd_w - set serial data input for receiver
//-------------------------------------------------
-WRITE_LINE_MEMBER(scn_pci_device::rxd_w)
+void scn_pci_device::rxd_w(int state)
{
m_rxd = state;
}
@@ -1096,7 +1071,7 @@ void scn_pci_device::set_rts(bool state)
// or ring indicator input (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(scn_pci_device::dsr_w)
+void scn_pci_device::dsr_w(int state)
{
assert(!m_is_aci);
@@ -1118,7 +1093,7 @@ WRITE_LINE_MEMBER(scn_pci_device::dsr_w)
// enable receiver (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(scn_pci_device::dcd_w)
+void scn_pci_device::dcd_w(int state)
{
if (BIT(m_status, 6) == !state)
return;
@@ -1145,7 +1120,7 @@ WRITE_LINE_MEMBER(scn_pci_device::dcd_w)
// transmitter (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(scn_pci_device::cts_w)
+void scn_pci_device::cts_w(int state)
{
m_cts = !state;
}
@@ -1477,7 +1452,7 @@ void scn_pci_device::write(offs_t offset, u8 data)
// (or jam sync for EPCI receiver)
//-------------------------------------------------
-WRITE_LINE_MEMBER(scn_pci_device::txc_w)
+void scn_pci_device::txc_w(int state)
{
if (state == m_txc_input)
return;
@@ -1512,7 +1487,7 @@ WRITE_LINE_MEMBER(scn_pci_device::txc_w)
// rxc_w - external clock input for receiver
//-------------------------------------------------
-WRITE_LINE_MEMBER(scn_pci_device::rxc_w)
+void scn_pci_device::rxc_w(int state)
{
if (state == m_rxc_input)
return;
diff --git a/src/devices/machine/scn_pci.h b/src/devices/machine/scn_pci.h
index acb16e90f72..de3a5c712b6 100644
--- a/src/devices/machine/scn_pci.h
+++ b/src/devices/machine/scn_pci.h
@@ -68,17 +68,17 @@ public:
void write(offs_t offset, u8 data);
// line write handlers
- DECLARE_WRITE_LINE_MEMBER(rxd_w);
- DECLARE_WRITE_LINE_MEMBER(dsr_w);
- DECLARE_WRITE_LINE_MEMBER(dcd_w);
- DECLARE_WRITE_LINE_MEMBER(cts_w);
- DECLARE_WRITE_LINE_MEMBER(txc_w);
- DECLARE_WRITE_LINE_MEMBER(rxc_w);
+ void rxd_w(int state);
+ void dsr_w(int state);
+ void dcd_w(int state);
+ void cts_w(int state);
+ void txc_w(int state);
+ void rxc_w(int state);
// output polling
- DECLARE_READ_LINE_MEMBER(txrdy_r) { assert(!m_is_aci); return BIT(m_status, 0) ? 0 : 1; }
- DECLARE_READ_LINE_MEMBER(rxrdy_r) { assert(!m_is_aci); return BIT(m_status, 1) ? 0 : 1; }
- DECLARE_READ_LINE_MEMBER(txemt_dschg_r) { assert(!m_is_aci); return BIT(m_status, 2) != 0 ? 0 : 1; }
+ int txrdy_r() { assert(!m_is_aci); return BIT(m_status, 0) ? 0 : 1; }
+ int rxrdy_r() { assert(!m_is_aci); return BIT(m_status, 1) ? 0 : 1; }
+ int txemt_dschg_r() { assert(!m_is_aci); return BIT(m_status, 2) != 0 ? 0 : 1; }
protected:
enum class rcvr_state : u8 {
@@ -102,8 +102,7 @@ protected:
// construction/destruction
scn_pci_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const u16 *br_div, bool is_enhanced, bool is_aci);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
@@ -257,12 +256,11 @@ public:
auto intr_handler() { return m_intr_callback.bind(); }
// output polling
- DECLARE_READ_LINE_MEMBER(intr_r) { return (m_status & 0x07) != 0 ? 0 : 1; }
+ int intr_r() { return (m_status & 0x07) != 0 ? 0 : 1; }
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_validity_check(validity_checker &valid) const override;
- virtual void device_resolve_objects() override;
// scn_pci_device overrides
virtual void set_rxrdy(bool state) override;
diff --git a/src/devices/machine/scnxx562.cpp b/src/devices/machine/scnxx562.cpp
index df6754c8f24..e49c586d00c 100644
--- a/src/devices/machine/scnxx562.cpp
+++ b/src/devices/machine/scnxx562.cpp
@@ -1,4 +1,5 @@
-// license:BSD-3-Clause copyright-holders: Joakim Larsson Edstrom
+// license:BSD-3-Clause
+// copyright-holders: Joakim Larsson Edstrom
/***************************************************************************
DUSCC Dual Serial Communications Controller emulation
@@ -17,8 +18,8 @@
CMOS 26C562 68C562
----------------------------------
For more info see:
- page 511: http://bitsavers.informatik.uni-stuttgart.de/pdf/signetics/_dataBooks/1986_Signetics_Microprocessor.pdf
- page 514: http://bitsavers.informatik.uni-stuttgart.de/pdf/signetics/_dataBooks/1994_Signetics_Data_Communications.pdf
+ page 511: http://bitsavers.informatik.uni-stuttgart.de/components/signetics/_dataBooks/1986_Signetics_Microprocessor.pdf
+ page 514: http://bitsavers.informatik.uni-stuttgart.de/components/signetics/_dataBooks/1994_Signetics_Data_Communications.pdf
Designs known of including one or more DUSCCs
------------------------------------------------
@@ -86,7 +87,6 @@ DONE (x) (p=partly) NMOS CMOS
/* Useful temporary debug printout format */
// printf("TAG %s%s Data:%d\n", __PRETTY_FUNCTION__, owner()->tag(), data);
-#define LOG_GENERAL (1U << 0)
#define LOG_R (1U << 1)
#define LOG_TX (1U << 2)
#define LOG_RX (1U << 3)
@@ -206,23 +206,6 @@ void duscc_device::device_start()
{
LOG("%s\n", FUNCNAME);
- // resolve callbacks
- m_out_txda_cb.resolve_safe();
- m_out_dtra_cb.resolve_safe();
- m_out_rtsa_cb.resolve_safe();
- m_out_synca_cb.resolve_safe();
- m_out_rtxca_cb.resolve_safe();
- m_out_trxca_cb.resolve_safe();
-
- m_out_txdb_cb.resolve_safe();
- m_out_dtrb_cb.resolve_safe();
- m_out_rtsb_cb.resolve_safe();
- m_out_syncb_cb.resolve_safe();
- m_out_rtxcb_cb.resolve_safe();
- m_out_trxcb_cb.resolve_safe();
-
- m_out_int_cb.resolve_safe();
-
// state saving - stuff with runtime values
save_item(NAME(m_int_state));
save_item(NAME(m_gsr));
@@ -241,7 +224,7 @@ void duscc_device::device_start()
void duscc_device::device_reset()
{
- LOG("%s %s \n",tag(), FUNCNAME);
+ LOG("%s\n", FUNCNAME);
m_chanA->reset();
m_chanB->reset();
@@ -268,9 +251,9 @@ void duscc_device::device_reset()
into three bits which are inserted into bits [2:0] or [4:2] of the interrupt vector register. This forms the content of the IVRM during
an interrupt acknowledge cycle. Unmodified and modified vectors can read directly through specified registers. Two of the conditions
are the inclusive OR of several other maskable conditions:
- - Extemal or CIT special condition: Delta DCD, Delta CTS or CIT zero count (ICTSR[6:4j).
- - Rxrrx error or special condition: any condition in the Receiver Status Register (RSR[7:0J) or a transmitter or DPLL condition in
- the Transmitter and Receiver Status Register (TRSR[7:3J).
+ - External or CIT special condition: Delta DCD, Delta CTS or CIT zero count (ICTSR[6:4]).
+ - Rxrrx error or special condition: any condition in the Receiver Status Register (RSR[7:0]) or a transmitter or DPLL condition in
+ the Transmitter and Receiver Status Register (TRSR[7:3]).
The TxRDY and RxRDY conditions are defined by OMR[4] and OMR[3], respectively. Also associated with the interrupt system are
the Interrupt Enable Register (IER), one bit in the Countermmer Control Register (CTCR), and the Interrupt Control Register (lCR).
@@ -296,7 +279,7 @@ int duscc_device::z80daisy_irq_state()
{
int state = 0;
- LOGINT("%s %s A:[%02x][%02x][%02x][%02x] B:[%02x][%02x][%02x][%02x] ",tag(), FUNCNAME,
+ LOGINT("%s A:[%02x][%02x][%02x][%02x] B:[%02x][%02x][%02x][%02x] ", FUNCNAME,
m_int_state[0], m_int_state[1], m_int_state[2], m_int_state[3],
m_int_state[4], m_int_state[5], m_int_state[6], m_int_state[7]);
@@ -324,7 +307,7 @@ int duscc_device::z80daisy_irq_state()
int duscc_device::z80daisy_irq_ack()
{
- LOGINT("%s %s()\n",tag(), FUNCNAME);
+ LOGINT("%s()\n", FUNCNAME);
// loop over all interrupt sources
for (auto & elem : m_int_state)
@@ -359,7 +342,7 @@ int duscc_device::z80daisy_irq_ack()
void duscc_device::z80daisy_irq_reti()
{
- LOGINT("%s %s \n",tag(), FUNCNAME);
+ LOGINT("%s\n", FUNCNAME);
// loop over all interrupt sources
for (auto & elem : m_int_state)
@@ -378,7 +361,7 @@ void duscc_device::z80daisy_irq_reti()
uint8_t duscc_device::iack()
{
- LOGINT("%s %s - returning vector:%02x\n",tag(), FUNCNAME, m_ivrm);
+ LOGINT("%s - returning vector:%02x\n", FUNCNAME, m_ivrm);
int vec = z80daisy_irq_ack();
z80daisy_irq_reti();
return vec;
@@ -386,8 +369,8 @@ uint8_t duscc_device::iack()
void duscc_device::check_interrupts()
{
- LOGINT("%s %s()\n",tag(), FUNCNAME);
int state = (z80daisy_irq_state() & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE;
+ LOGINT("%s(icr %02x ierA %02x ierB %02x state %d)\n", FUNCNAME, m_icr, m_chanA->m_ier, m_chanB->m_ier, state);
// "If no interrupt is pending, an H'FF' is output when reading the IVRM."
if (state == CLEAR_LINE)
@@ -405,7 +388,7 @@ void duscc_device::check_interrupts()
void duscc_device::reset_interrupts()
{
- LOGINT("%s %s\n",tag(), FUNCNAME);
+ LOGINT("%s\n", FUNCNAME);
// reset internal interrupt sources
for (auto & elem : m_int_state)
@@ -434,7 +417,7 @@ uint8_t duscc_device::modify_vector(uint8_t vec, int index, uint8_t src)
1 1 1 Ch B external or C/T status
--------------------------------------------------
*/
- LOGINT("%s %c %s, vec:%02x src=%02x\n",tag(), 'A' + index, FUNCNAME, vec, src);
+ LOGINT("%c %s, vec:%02x src=%02x\n", 'A' + index, FUNCNAME, vec, src);
// TODO: Prevent modification if no vector has been programmed, even if it is the default vector.
if ((m_icr & REG_ICR_VEC_MOD) != 0) // Affect vector?
@@ -465,12 +448,41 @@ uint8_t duscc_device::modify_vector(uint8_t vec, int index, uint8_t src)
1. Interrupt Enable Register (IERA/B). - checked by trigger_interrupt
2. Receiver Status Register (RSRA/B).
3. Transmitter and Receiver Status Register (TRSRA/B).
- 4. Input and Counter/timer Status Register (ICTSRA/B).
- 5. interrupt Vector Register (IVR) and Modified Interrupt Vector Register (IVRM).
- 6. Interrupt control register (lCR).
+ 4. Input and Counter/Timer Status Register (ICTSRA/B).
+ 5. Interrupt Vector Register (IVR) and Modified Interrupt Vector Register (IVRM).
+ 6. Interrupt control register (ICR).
7. General status register (GSR)
*/
+int duscc_device::interrupt_priority(int index, int state)
+{
+ int priority_level = 0;
+
+ switch (m_icr & REG_ICR_PRIO_MASK)
+ {
+ case REG_ICR_PRIO_AHI: priority_level = state + (index == CHANNEL_A ? 0 : 4); break;
+ case REG_ICR_PRIO_BHI: priority_level = state + (index == CHANNEL_A ? 4 : 0); break;
+ case REG_ICR_PRIO_AINT: priority_level = state * 2 + (index == CHANNEL_A ? 0 : 1); break;
+ case REG_ICR_PRIO_BINT: priority_level = state * 2 + (index == CHANNEL_A ? 1 : 0); break;
+ default: logerror("DUSCC Programming error, please report/fix\n"); // Will not happen
+ }
+
+ return priority_level;
+}
+
+void duscc_device::clear_interrupt(int index, int state)
+{
+ LOGINT("%s:%c %02x\n", FUNCNAME, 'A' + index, state);
+
+ m_int_state[interrupt_priority(index, state)] &= ~Z80_DAISY_INT;
+ if ((m_icr & (index == CHANNEL_A ? REG_ICR_CHA : REG_ICR_CHB)) == 0)
+ {
+ LOGINT("The Interrupt Control Register [%02x] bit for this channel is not set, blocking attempt to interrupt\n", m_icr);
+ return;
+ }
+ check_interrupts();
+}
+
//-----------------------------------------------------------------------
// trigger_interrupt - called when a potential interrupt condition occurs and will only issue an interrupt if the DUSCC is
// programmed to do so.
@@ -481,9 +493,9 @@ void duscc_device::trigger_interrupt(int index, int state)
uint8_t source = 0;
int priority_level = 0;
- LOGINT("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, state);
+ LOGINT("%s:%c %02x \n",FUNCNAME, 'A' + index, state);
- /* The Interrup Controll Register (ICR) bits, must be set for the correspondning channel */
+ // The Interrupt Control Register (ICR) bits, must be set for the corresponding channel
// ICR Check is probably by the caller but we check again to be sure
if ((m_icr & (index == CHANNEL_A ? REG_ICR_CHA : REG_ICR_CHB)) == 0)
{
@@ -492,14 +504,7 @@ void duscc_device::trigger_interrupt(int index, int state)
}
// Modify priority level
- switch (m_icr & REG_ICR_PRIO_MASK)
- {
- case REG_ICR_PRIO_AHI: priority_level = state + (index == CHANNEL_A ? 0 : 4); break;
- case REG_ICR_PRIO_BHI: priority_level = state + (index == CHANNEL_A ? 4 : 0); break;
- case REG_ICR_PRIO_AINT: priority_level = state * 2 + (index == CHANNEL_A ? 0 : 1); break;
- case REG_ICR_PRIO_BINT: priority_level = state * 2 + (index == CHANNEL_A ? 1 : 0); break;
- default: logerror("DUSCC Programming error, please report/fix\n"); // Will not happen
- }
+ priority_level = interrupt_priority(index, state);
// Vector modification requested?
source = state + (index == CHANNEL_A ? 0 : 4); // bit in interrupt queue register of a certain priotiry level
@@ -595,9 +600,9 @@ void duscc_channel::device_start()
m_cid = (m_uart->m_variant & duscc_device::SET_CMOS) ? 0x7f : 0xff; // TODO: support CMOS rev A = 0xbf
// Timers
- duscc_timer = timer_alloc(TIMER_ID);
- rtxc_timer = timer_alloc(TIMER_ID_RTXC);
- trxc_timer = timer_alloc(TIMER_ID_TRXC);
+ duscc_timer = timer_alloc(FUNC(duscc_channel::check_zero_detect), this);
+ rtxc_timer = timer_alloc(FUNC(duscc_channel::rtxc_tick), this);
+ trxc_timer = timer_alloc(FUNC(duscc_channel::trxc_tick), this);
// state saving
save_item(NAME(m_cmr1));
@@ -722,113 +727,111 @@ void duscc_channel::device_reset()
m_a7 = 0;
}
-void duscc_channel::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(duscc_channel::check_zero_detect)
{
- switch(id)
+ if (m_ct-- == 0) // Zero detect
{
- case TIMER_ID:
- if (m_ct-- == 0) // Zero detect
+ m_ictsr |= REG_ICTSR_ZERO_DET; // set zero detection bit
+
+ // Generate interrupt?
+ if ( ( (m_ctcr & REG_CTCR_ZERO_DET_INT) == REG_CTCR_ZERO_DET_INT ) &&
+ ( (m_uart->m_icr & (m_index == duscc_device::CHANNEL_A ? duscc_device::REG_ICR_CHA : duscc_device::REG_ICR_CHB) ) != 0) )
{
- m_ictsr |= REG_ICTSR_ZERO_DET; // set zero detection bit
+ LOG("Zero Detect Interrupt pending\n");
+ m_uart->trigger_interrupt(m_index, INT_EXTCTSTAT);
+ }
- // Generate interrupt?
- if ( ( (m_ctcr & REG_CTCR_ZERO_DET_INT) == REG_CTCR_ZERO_DET_INT ) &&
- ( (m_uart->m_icr & (m_index == duscc_device::CHANNEL_A ? duscc_device::REG_ICR_CHA : duscc_device::REG_ICR_CHB) ) != 0) )
- {
- LOG("Zero Detect Interrupt pending\n");
- m_uart->trigger_interrupt(m_index, INT_EXTCTSTAT);
- }
+ // Preload or rollover?
+ if (( m_ctcr & REG_CTCR_ZERO_DET_CTL) == 0)
+ {
+ m_ct = m_ctpr;
+ }
+ else
+ {
+ m_ct = 0xffff;
+ }
- // Preload or rollover?
- if (( m_ctcr & REG_CTCR_ZERO_DET_CTL) == 0)
+ // Is Counter/Timer output on the RTxC pin?
+ if (( m_pcr & REG_PCR_RTXC_MASK) == REG_PCR_RTXC_CNTR_OUT)
+ {
+ if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
{
- m_ct = m_ctpr;
+ m_rtxc = (~m_rtxc) & 1;
}
- else
+ else // Pulse!
{
- m_ct = 0xffff;
+ m_rtxc = 1;
+ rtxc_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
}
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_rtxca_cb(m_rtxc);
+ else
+ m_uart->m_out_rtxcb_cb(m_rtxc);
+ }
- // Is Counter/Timer output on the RTxC pin?
- if (( m_pcr & REG_PCR_RTXC_MASK) == REG_PCR_RTXC_CNTR_OUT)
+ // Is Counter/Timer output on the TRXC pin?
+ if (( m_pcr & REG_PCR_TRXC_MASK) == REG_PCR_TRXC_CNTR_OUT)
+ {
+ if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
{
- if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
- {
- m_rtxc = (~m_rtxc) & 1;
- }
- else // Pulse!
- {
- m_rtxc = 1;
- rtxc_timer->adjust(attotime::from_hz(clock()), TIMER_ID_RTXC, attotime::from_hz(clock()));
- }
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_rtxca_cb(m_rtxc);
- else
- m_uart->m_out_rtxcb_cb(m_rtxc);
+ m_trxc = (~m_trxc) & 1;
}
-
- // Is Counter/Timer output on the TRXC pin?
- if (( m_pcr & REG_PCR_TRXC_MASK) == REG_PCR_TRXC_CNTR_OUT)
+ else // Pulse!
{
- if ((m_ctcr & REG_CTCR_TIM_OC) == 0) // Toggle?
- {
- m_trxc = (~m_trxc) & 1;
- }
- else // Pulse!
- {
- m_trxc = 1;
- trxc_timer->adjust(attotime::from_hz(clock()), TIMER_ID_TRXC, attotime::from_hz(clock()));
- }
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_trxca_cb(m_trxc);
- else
- m_uart->m_out_trxcb_cb(m_trxc);
+ m_trxc = 1;
+ trxc_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
}
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_trxca_cb(m_trxc);
+ else
+ m_uart->m_out_trxcb_cb(m_trxc);
}
- else
- { // clear zero detection bit
- m_ictsr &= ~REG_ICTSR_ZERO_DET;
- }
- break;
- case TIMER_ID_RTXC: // Terminate zero detection pulse
- m_rtxc = 0;
- rtxc_timer->adjust(attotime::never);
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_rtxca_cb(m_rtxc);
- else
- m_uart->m_out_rtxcb_cb(m_rtxc);
- break;
- case TIMER_ID_TRXC: // Terminate zero detection pulse
- m_trxc = 0;
- trxc_timer->adjust(attotime::never);
- if (m_index == duscc_device::CHANNEL_A)
- m_uart->m_out_trxca_cb(m_trxc);
- else
- m_uart->m_out_trxcb_cb(m_trxc);
- break;
- default:
- LOGR("Unhandled Timer ID %d\n", id);
- break;
}
- // LOG("%s %d\n", FUNCNAME, id);
+ else
+ { // clear zero detection bit
+ m_ictsr &= ~REG_ICTSR_ZERO_DET;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(duscc_channel::rtxc_tick)
+{
+ m_rtxc = 0;
+ rtxc_timer->adjust(attotime::never);
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_rtxca_cb(m_rtxc);
+ else
+ m_uart->m_out_rtxcb_cb(m_rtxc);
+}
+
+TIMER_CALLBACK_MEMBER(duscc_channel::trxc_tick)
+{
+ m_trxc = 0;
+ trxc_timer->adjust(attotime::never);
+ if (m_index == duscc_device::CHANNEL_A)
+ m_uart->m_out_trxca_cb(m_trxc);
+ else
+ m_uart->m_out_trxcb_cb(m_trxc);
}
/* The DUSCC 16 bit Timer
+
Counter/Timer Control and Value Registers
+
There are five registers in this set consisting of the following:
- 1. Counterltimer control register (CTCRAlB).
- 2. Counterltimer preset Highland Low registers (CTPRHAlB, CTPRLAlB).
- 3. Counter/bmer (current value) High and Low registers (CTHAlB, CTLAlB)
- The control register contains the operational information for the counterltimer. The preset registers contain the count which is
- loaded into the counterltimer circuits. The third group contains the current value of the counterltimer as it operates.
-*/
-/* Counter/Timer Control Register (CTCRA/CTCRB)
+ 1. Counter/Timer control register (CTCRA/B).
+ 2. Counter/Timer preset Highland Low registers (CTPRHA/B, CTPRLA/B).
+ 3. Counter/Timer (current value) High and Low registers (CTHA/B, CTLA/B)
+ The control register contains the operational information for the counter/timer. The preset registers contain the count which is
+ loaded into the counter/timer circuits. The third group contains the current value of the counterltimer as it operates.
+
+ Counter/Timer Control Register (CTCRA/CTCRB)
+
[7] Zero Detect Interrupt - This bit determines whether the assertion of the CIT ZERO COUNT status bit (ICTSR[6)) causes an
interrupt to be generated if set to 1 and the Master interrupt control bit (ICR[0:1]) is set
[6] Zero Detect Control - his bit determines the action of the counter upon reaching zero count
- 0 - The counter/timer is preset to the value contained in the counterltimer preset registers (CTPRL, CTPRH) at the next clock edge.
- 1 - The counterltimer continues counting without preset. The value at the next clock edge will be H'FFFF'.
- [5] CounterlTimer Output Control - This bit selects the output waveform when the counterltimer is selected to be output on TRxC or RTxC.
+ 0 - The counter/timer is preset to the value contained in the counter/timer preset registers (CTPRL, CTPRH) at the next clock edge.
+ 1 - The counter/timer continues counting without preset. The value at the next clock edge will be H'FFFF'.
+ [5] Counter/Timer Output Control - This bit selects the output waveform when the counter/timer is selected to be output on TRxC or RTxC.
0 - The output toggles each time the CIT reaches zero count. The output is cleared to Low by either of the preset counterltimer commands.
1 - The output is a single clock positive width pulse each time the CIT reaches zero count. (The duration of this pulse is one clock period.)
[4:3] Clock Select - This field selects whether the clock selected by [2:0J is prescaled prior to being applied to the input of the CIT.
@@ -844,8 +847,8 @@ void duscc_channel::device_timer(emu_timer &timer, device_timer_id id, int param
start of counting until the RxD input goes Low. It continues counting until the RxD input goes High, then stops and sets
the CIT zero count status bit. The CPU can use the value in the CIT to determine the bit rate of the incoming data.
The clock is the crystal oscillator or system clock input divided by four.
- 100 Source is the 32X BRG output selected by RTR[3:0J of own channel.
- 101 Source is the 32X BRG output selected by TTR[3:0J of own channel.
+ 100 Source is the 32X BRG output selected by RTR[3:0] of own channel.
+ 101 Source is the 32X BRG output selected by TTR[3:0] of own channel.
110 Source is the internal signal which loads received characters from the receive shift register into the receiver
FIFO. When operating in this mode, the FIFOed EOM status bit (RSR[7)) shall be set when the character which
causes the count to go to zero is loaded into the receive FIFO.
@@ -1284,7 +1287,7 @@ uint8_t duscc_channel::do_dusccreg_gsr_r()
uint8_t duscc_channel::do_dusccreg_ier_r()
{
- LOGINT("%s <- %02x\n", FUNCNAME, m_ier);
+ LOGINT("%s(%02x)\n", FUNCNAME, m_ier);
return (uint8_t) m_ier;
}
@@ -1818,7 +1821,7 @@ void duscc_channel::do_dusccreg_rtr_w(uint8_t data)
to the transmit shift register. If not reset by the CPU, TxRDY remains asserted until the FIFO is full, at which time
it is automatically negated.
1 FIFO empty. The channel's TxRDY status bit is asserted when a character transfer from the transmit FIFO to the
- transmit shift register causes the FI FO to become empty. If not reset by the CPU, TxRDY remains asserted until the
+ transmit shift register causes the FIFO to become empty. If not reset by the CPU, TxRDY remains asserted until the
FIFO is full, at which time it is negated.
If the TxRDY status bit is reset by the CPU, it will remain negated regardless of the current state of the transmit
FIFO, until it is asserted again due to the occurrence of one of the above conditions.
@@ -1951,6 +1954,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
m_tx_fifo_wp = m_tx_fifo_rp = 0;
m_trsr &= 0x0f;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->clear_interrupt(m_index, INT_TXREADY);
break;
/* Enable transmitter. Enables transmitter operation, conditioned by the state of
@@ -1971,6 +1975,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
set_tra_rate(0);
m_tra = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->clear_interrupt(m_index, INT_TXREADY);
break;
// RECEIVER COMMANDS
@@ -1985,6 +1990,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
m_trsr &= 0xf0;
m_rsr = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
+ m_uart->clear_interrupt(m_index, INT_RXREADY);
break;
/* Enable receiver. Causes receiver operation to begin, conditioned by the state of the DCD
@@ -2000,6 +2006,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
case REG_CCR_DISABLE_RX: LOGINT("- Disable Rx\n");
m_rcv = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
+ m_uart->clear_interrupt(m_index, INT_RXREADY);
break;
// COUNTER/TIMER COMMANDS
@@ -2007,7 +2014,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
/* Start. Starts the counteritimer and prescaler. */
case REG_CCR_START_TIMER: LOG("- Start Counter/Timer\n");
rate = 100; // TODO: calculate correct rate
- duscc_timer->adjust(attotime::from_hz(rate), TIMER_ID_RTXC, attotime::from_hz(rate));
+ duscc_timer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate));
break;
/* Stop. Stops the counter/timer and prescaler. Since the command may be asynchronous with the selected clock source,
@@ -2035,7 +2042,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data)
void duscc_channel::do_dusccreg_txfifo_w(uint8_t data)
{
- LOGTX(" - TX %s(%02x)'%c'\n", FUNCNAME,data, isalnum(data) ? data : ' ');
+ LOGTX(" - TX %s(%02x)'%c' wp %d rp %d\n", FUNCNAME,data, isprint(data) ? data : ' ', m_tx_fifo_wp, m_tx_fifo_rp);
/* Tx FIFO is full or...? */
if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) ))
@@ -2066,6 +2073,7 @@ void duscc_channel::do_dusccreg_txfifo_w(uint8_t data)
if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) ))
{
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->clear_interrupt(m_index, INT_TXREADY);
}
else
{
@@ -2082,9 +2090,9 @@ void duscc_channel::do_dusccreg_txfifo_w(uint8_t data)
}
/* Receiver Status Register (RSRA, RSRB)
- This register informs the CPU of receiver status. Bits indicated as 'not used';n a particular mode will read as zero. The logical OR of
+ This register informs the CPU of receiver status. Bits indicated as 'not used' in a particular mode will read as zero. The logical OR of
these bits is presented in GSR[2] or GSR[6] (ORed with the bits of TRSR) for Channels A and B, respectively. Unless otherwise
- indicated, asserted status bits are reset only be performing a write operation to the status register with the bits to be reset being ones in
+ indicated, asserted status bits are reset only by performing a write operation to the status register with the bits to be reset being ones in
the accompanying data word, or when the RESETN input is asserted, or when a 'reset receiver' command is issued.
Certain status bits are specified as being FIFOed. This means that they occupy positions in a status FIFO that correspond to the data
FIFO. As the data is brought to the top of the FIFO (the position read when the RxFIFO is read), the FIFOed status bits are logically
@@ -2116,15 +2124,15 @@ void duscc_channel::do_dusccreg_ictsr_w(uint8_t data)
/* The GSR register provides a 'quick look' at the overall status of both channels of the DUSCC. A write to this register with ls at the
corresponding bit pOSitions causes TxRDY (bits 5 and 1) and/or RxRDY (bits 4 and 0) to be reset. The other status bits can be reset
only by resetting the individual status bits that they point to.
- [7] Channel 8 External or Coutnerrrimer Status - This bit indicates that one of the following status bits is asserted: ICTSRB[6:4].
+ [7] Channel 8 External or Counter/Timer Status - This bit indicates that one of the following status bits is asserted: ICTSRB[6:4].
[6] Channel B Receiver or Transmitter Status - This bit indicates that one of the following status bits is asserted: RSRB[7:0], TRSRB[7:3].
[5] Channel 8 Transmitter Ready - The assertion of this bit indicates that one or more characters may be loaded into the Channel B
transmitter FIFO to be serialized by the transmit shift register. See description of OMR[4j. This bit can be asserted only
when the transmitter is enabled. Reselling the transmitter negates TxRDY.
[4] Channel 8 Receiver Ready - The assertion of this bit indicates that one or more characters are available in the Channel B receiver
- FIFO to be read by the CPU. See deSCription of OMR[3]. RxRDY is initially reset (negated) by a chip reset or when a 'reset Channel B
+ FIFO to be read by the CPU. See description of OMR[3]. RxRDY is initially reset (negated) by a chip reset or when a 'reset Channel B
receiver' command is invoked.
- [3] Channel A External or Countermmer Status - This bit indicates that one of the following status bits is asserted: ICTSRA[6:4].
+ [3] Channel A External or Counter/Timer Status - This bit indicates that one of the following status bits is asserted: ICTSRA[6:4].
[2] Channel A Receiver or Transmitter Status - This bit indicates that one of the following status bits is asserted: RSRA(7:0], TRSRA(7:3].
[1) Channel A Transmitter Ready - The assertion of this bit indicates that one or more characters may be loaded into the Channel A
transmitter FIFO to be serialized by the transmit shift register. See description of OMR[4]. This bit can be asserted only
@@ -2209,7 +2217,7 @@ uint8_t duscc_channel::read(offs_t &offset)
{
uint8_t data = 0;
int reg = (offset | m_a7) & ~0x20; // Add extended rgisters and remove the channel B bit from offset
- LOG("\"%s\" %s: %c : Register read '%02x' <- [%02x]", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
+ LOGR("\"%s\" %s: %c : Register read '%02x' <- [%02x]", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
LOGR(" * %c Reg %02x -> %02x \n", 'A' + m_index, reg, data);
switch (reg)
{
@@ -2260,7 +2268,7 @@ void duscc_channel::write(uint8_t data, offs_t &offset)
int reg = (offset | m_a7) & ~0x20; // Add extended rgisters and remove the channel B bit from offset
LOGSETUP(" * %s%c Reg %02x <- %02x \n", owner()->tag(), 'A' + m_index, reg, data);
- LOG("\"%s\" %s: %c : Register write '%02x' -> [%02x]", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
+ LOG("\"%s\" %s: %c : Register write '%02x' -> [%02x]\n", owner()->tag(), FUNCNAME, 'A' + m_index, data, reg );
switch (reg)
{
case REG_CMR1: do_dusccreg_cmr1_w(data); break;
@@ -2333,6 +2341,7 @@ void duscc_channel::m_rx_fifo_rp_step()
// no more characters available in the FIFO
LOGINT("Clear RXRDY in GSR because FIFO is emptied\n");
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
+ m_uart->clear_interrupt(m_index, INT_RXREADY);
}
}
@@ -2414,6 +2423,7 @@ void duscc_channel::cts_w(int state)
if (m_tpr & REG_TPR_CTS && m_tra)
{
m_uart->m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
+ m_uart->trigger_interrupt(m_index, INT_TXREADY);
}
// set clear to send
diff --git a/src/devices/machine/scnxx562.h b/src/devices/machine/scnxx562.h
index 72f3322a2e5..c9ac458b44c 100644
--- a/src/devices/machine/scnxx562.h
+++ b/src/devices/machine/scnxx562.h
@@ -152,7 +152,6 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_serial_interface overrides
virtual void tra_callback() override;
@@ -160,6 +159,10 @@ protected:
virtual void rcv_callback() override;
virtual void rcv_complete() override;
+ TIMER_CALLBACK_MEMBER(check_zero_detect);
+ TIMER_CALLBACK_MEMBER(rtxc_tick);
+ TIMER_CALLBACK_MEMBER(trxc_tick);
+
int m_rxc;
int m_txc;
int m_tra;
@@ -435,13 +438,6 @@ protected:
REG_CTCR_TIM_OC = 0x20,
};
- enum
- {
- TIMER_ID,
- TIMER_ID_RTXC,
- TIMER_ID_TRXC
- };
-
uint16_t m_brg_rx_rate;
uint16_t m_brg_tx_rate;
uint16_t m_brg_const;
@@ -602,7 +598,9 @@ protected:
void check_interrupts();
void reset_interrupts();
uint8_t modify_vector(uint8_t vect, int i, uint8_t src);
+ int interrupt_priority(int index, int state);
void trigger_interrupt(int index, int state);
+ void clear_interrupt(int index, int state);
int get_channel_index(duscc_channel *ch) const { return (ch == m_chanA) ? 0 : 1; }
// Variants in the DUSCC family
diff --git a/src/devices/machine/scoop.cpp b/src/devices/machine/scoop.cpp
new file mode 100644
index 00000000000..6f2151cb19a
--- /dev/null
+++ b/src/devices/machine/scoop.cpp
@@ -0,0 +1,176 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Sharp Scoop peripheral chip emulation skeleton
+
+***************************************************************************/
+
+#include "emu.h"
+#include "scoop.h"
+
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_READS (1U << 2)
+#define LOG_WRITES (1U << 3)
+#define LOG_ALL (LOG_UNKNOWN | LOG_READS | LOG_WRITES)
+
+#define VERBOSE (LOG_ALL)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SCOOP, scoop_device, "scoop", "Sharp SCOOP peripheral interface")
+
+scoop_device::scoop_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SCOOP, tag, owner, clock)
+ , m_gpio_out(*this)
+{
+}
+
+void scoop_device::device_start()
+{
+ save_item(NAME(m_gpwr));
+ save_item(NAME(m_gpio_in_latch));
+ save_item(NAME(m_gpcr));
+}
+
+void scoop_device::device_reset()
+{
+ m_gpwr = 0;
+ m_gpio_in_latch = 0;
+ m_gpcr = 0;
+}
+
+void scoop_device::gpio_in(const uint16_t line, const int state)
+{
+ m_gpio_in_latch &= ~(1 << line);
+ m_gpio_in_latch |= (state << line);
+}
+
+void scoop_device::update_gpio_direction(const uint16_t old_dir)
+{
+ const uint16_t new_outputs = ~old_dir & m_gpcr;
+ if (new_outputs)
+ {
+ for (uint32_t line = 0; line < 13; line++)
+ {
+ if (BIT(new_outputs, line))
+ {
+ m_gpio_out[line](BIT(m_gpwr, line));
+ }
+ }
+ }
+}
+
+void scoop_device::update_gpio_outputs(const uint16_t old_latch, const uint16_t changed)
+{
+ uint16_t remaining_changed = changed;
+
+ for (uint32_t line = 0; line < 13 && remaining_changed != 0; line++)
+ {
+ if (BIT(remaining_changed, line))
+ {
+ m_gpio_out[line](BIT(m_gpwr, line));
+ remaining_changed &= ~(1 << line);
+ }
+ }
+}
+
+uint32_t scoop_device::read(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0x00/4:
+ LOGMASKED(LOG_READS, "%s: read: MCR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x04/4:
+ LOGMASKED(LOG_READS, "%s: read: CDR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x08/4:
+ LOGMASKED(LOG_READS, "%s: read: CSR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x0c/4:
+ LOGMASKED(LOG_READS, "%s: read: CPR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x10/4:
+ LOGMASKED(LOG_READS, "%s: read: CCR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x14/4:
+ LOGMASKED(LOG_READS, "%s: read: IRR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x18/4:
+ LOGMASKED(LOG_READS, "%s: read: IMR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x1c/4:
+ LOGMASKED(LOG_READS, "%s: read: ISR: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 0x20/4:
+ LOGMASKED(LOG_READS, "%s: read: GPCR: %04x\n", machine().describe_context(), m_gpcr);
+ return m_gpcr;
+ case 0x24/4:
+ LOGMASKED(LOG_READS, "%s: read: GPWR: %04x\n", machine().describe_context(), m_gpwr);
+ return m_gpwr;
+ case 0x28/4:
+ {
+ const uint16_t combined = (m_gpwr & m_gpcr) | (m_gpio_in_latch & ~m_gpcr);
+ LOGMASKED(LOG_READS, "%s: read: GPRR: %04x\n", machine().describe_context(), combined);
+ return combined;
+ }
+ default:
+ LOGMASKED(LOG_READS | LOG_UNKNOWN, "%s: read: Unknown Register: %04x\n", machine().describe_context(), offset << 2);
+ return 0;
+ }
+}
+
+void scoop_device::write(offs_t offset, uint32_t data)
+{
+ switch (offset)
+ {
+ case 0x00/4:
+ LOGMASKED(LOG_WRITES, "%s: write: MCR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x04/4:
+ LOGMASKED(LOG_WRITES, "%s: write: CDR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x08/4:
+ LOGMASKED(LOG_WRITES, "%s: write: CSR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x0c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: CPR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x10/4:
+ LOGMASKED(LOG_WRITES, "%s: write: CCR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x14/4:
+ LOGMASKED(LOG_WRITES, "%s: write: IRR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x18/4:
+ LOGMASKED(LOG_WRITES, "%s: write: IMR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x1c/4:
+ LOGMASKED(LOG_WRITES, "%s: write: ISR: %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ case 0x20/4:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: GPCR: %04x\n", machine().describe_context(), (uint16_t)data);
+ const uint16_t old = m_gpcr;
+ m_gpcr = data;
+ if (old != m_gpcr)
+ update_gpio_direction(old);
+ break;
+ }
+ case 0x24/4:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: GPWR: %04x\n", machine().describe_context(), (uint16_t)data);
+ const uint16_t old = m_gpwr;
+ m_gpwr = data;
+ if (old != m_gpwr)
+ update_gpio_outputs(old, old ^ m_gpwr);
+ break;
+ }
+ case 0x28/4:
+ LOGMASKED(LOG_WRITES, "%s: write: GPRR (ignored): %04x\n", machine().describe_context(), (uint16_t)data);
+ break;
+ default:
+ LOGMASKED(LOG_WRITES | LOG_UNKNOWN, "%s: write: Unknown Register: %04x = %04x\n", machine().describe_context(), offset << 2, (uint16_t)data);
+ break;
+ }
+}
diff --git a/src/devices/machine/scoop.h b/src/devices/machine/scoop.h
new file mode 100644
index 00000000000..1fb0edaae66
--- /dev/null
+++ b/src/devices/machine/scoop.h
@@ -0,0 +1,42 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Sharp Scoop peripheral chip emulation skeleton
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_SCOOP
+#define MAME_MACHINE_SCOOP
+
+#pragma once
+
+class scoop_device : public device_t
+{
+public:
+ scoop_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ template <unsigned Line> auto gpio_out() { return m_gpio_out[Line].bind(); }
+ template <unsigned Line> void gpio_in(int state) { gpio_in((uint16_t)Line, state); }
+
+ uint32_t read(offs_t offset);
+ void write(offs_t offset, uint32_t data);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void gpio_in(const uint16_t line, const int state);
+ void update_gpio_direction(const uint16_t old_dir);
+ void update_gpio_outputs(const uint16_t old_latch, const uint16_t changed);
+
+ uint16_t m_gpwr;
+ uint16_t m_gpio_in_latch;
+ uint16_t m_gpcr;
+
+ devcb_write_line::array<13> m_gpio_out;
+};
+
+DECLARE_DEVICE_TYPE(SCOOP, scoop_device)
+
+#endif // MAME_MACHINE_SCOOP
diff --git a/src/devices/machine/sda2006.cpp b/src/devices/machine/sda2006.cpp
index 853e5cf871d..99b4a41d9f7 100644
--- a/src/devices/machine/sda2006.cpp
+++ b/src/devices/machine/sda2006.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Tomasz Slanina
#include "emu.h"
-#include "machine/sda2006.h"
+#include "sda2006.h"
//-------------------------------------------------
//
@@ -114,9 +114,10 @@ void sda2006_device::nvram_default()
// .nv file
//-------------------------------------------------
-void sda2006_device::nvram_read(emu_file &file)
+bool sda2006_device::nvram_read(util::read_stream &file)
{
- file.read(m_eeprom_data, EEPROM_CAPACITY);
+ auto const [err, actual] = read(file, m_eeprom_data, EEPROM_CAPACITY);
+ return !err && (actual == EEPROM_CAPACITY);
}
//-------------------------------------------------
@@ -124,22 +125,23 @@ void sda2006_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void sda2006_device::nvram_write(emu_file &file)
+bool sda2006_device::nvram_write(util::write_stream &file)
{
- file.write(m_eeprom_data, EEPROM_CAPACITY);
+ auto const [err, actual] = write(file, m_eeprom_data, EEPROM_CAPACITY);
+ return !err;
}
-READ_LINE_MEMBER( sda2006_device::read_data )
+int sda2006_device::read_data()
{
return m_latch^1;
}
-WRITE_LINE_MEMBER( sda2006_device::write_data )
+void sda2006_device::write_data(int state)
{
m_latch = state;
}
-WRITE_LINE_MEMBER( sda2006_device::write_enable )
+void sda2006_device::write_enable(int state)
{
if( (m_write_state ^ state) && (!state)){ //falling edge
m_is_end_o_stream = true;
@@ -148,7 +150,7 @@ WRITE_LINE_MEMBER( sda2006_device::write_enable )
m_write_state = state;
}
-WRITE_LINE_MEMBER( sda2006_device::write_clock )
+void sda2006_device::write_clock(int state)
{
if( (m_clock_state ^ state) && (!state)) { // falling edge
diff --git a/src/devices/machine/sda2006.h b/src/devices/machine/sda2006.h
index 31657be6344..4d3ee1b98a0 100644
--- a/src/devices/machine/sda2006.h
+++ b/src/devices/machine/sda2006.h
@@ -17,10 +17,10 @@ public:
sda2006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
// I/O operations
- DECLARE_READ_LINE_MEMBER(read_data);
- DECLARE_WRITE_LINE_MEMBER(write_data);
- DECLARE_WRITE_LINE_MEMBER(write_clock);
- DECLARE_WRITE_LINE_MEMBER(write_enable);
+ int read_data();
+ void write_data(int state);
+ void write_clock(int state);
+ void write_enable(int state);
protected:
// device-level overrides
@@ -29,8 +29,8 @@ protected:
virtual void device_reset() override;
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
enum {
diff --git a/src/devices/machine/sdlc.cpp b/src/devices/machine/sdlc.cpp
index 7a7303b9e73..a6d727f2e5f 100644
--- a/src/devices/machine/sdlc.cpp
+++ b/src/devices/machine/sdlc.cpp
@@ -7,7 +7,6 @@
#include <sstream>
-#define LOG_GENERAL (1U << 0)
#define LOG_RXBIT (1U << 1)
#define LOG_RXFLAG (1U << 2)
#define LOG_LINESTATE (1U << 3)
@@ -140,7 +139,7 @@ sdlc_logger_device::sdlc_logger_device(machine_config const &mconfig, char const
{
}
-WRITE_LINE_MEMBER(sdlc_logger_device::clock_w)
+void sdlc_logger_device::clock_w(int state)
{
if (bool(state) != bool(m_current_clock))
{
diff --git a/src/devices/machine/sdlc.h b/src/devices/machine/sdlc.h
index 5dd7b177c3e..126dfed766e 100644
--- a/src/devices/machine/sdlc.h
+++ b/src/devices/machine/sdlc.h
@@ -57,12 +57,12 @@ public:
sdlc_logger_device(machine_config const &mconfig, char const *tag, device_t *owner, std::uint32_t clock);
// input signals
- DECLARE_WRITE_LINE_MEMBER(data_w) { m_current_data = state ? 1U : 0U; }
- DECLARE_WRITE_LINE_MEMBER(clock_w);
+ void data_w(int state) { m_current_data = state ? 1U : 0U; }
+ void clock_w(int state);
// input format configuration
- DECLARE_WRITE_LINE_MEMBER(data_nrzi) { m_data_nrzi = state ? 1U : 0U; }
- DECLARE_WRITE_LINE_MEMBER(clock_active) { m_clock_active = state ? 1U : 0U; }
+ void data_nrzi(int state) { m_data_nrzi = state ? 1U : 0U; }
+ void clock_active(int state) { m_clock_active = state ? 1U : 0U; }
protected:
virtual void device_start() override;
diff --git a/src/devices/machine/sega_scu.cpp b/src/devices/machine/sega_scu.cpp
index d7a0bf521cb..57214053b36 100644
--- a/src/devices/machine/sega_scu.cpp
+++ b/src/devices/machine/sega_scu.cpp
@@ -235,9 +235,9 @@ void sega_scu_device::device_start()
m_hostspace = &m_hostcpu->space(AS_PROGRAM);
- m_dma_timer[0] = timer_alloc(DMALV0_ID);
- m_dma_timer[1] = timer_alloc(DMALV1_ID);
- m_dma_timer[2] = timer_alloc(DMALV2_ID);
+ m_dma_timer[0] = timer_alloc(FUNC(sega_scu_device::dma_tick<DMALV0_ID>), this);
+ m_dma_timer[1] = timer_alloc(FUNC(sega_scu_device::dma_tick<DMALV1_ID>), this);
+ m_dma_timer[2] = timer_alloc(FUNC(sega_scu_device::dma_tick<DMALV2_ID>), this);
}
@@ -269,32 +269,20 @@ void sega_scu_device::device_reset_after_children()
m_scudsp->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
}
-
-void sega_scu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+template <int Level>
+TIMER_CALLBACK_MEMBER(sega_scu_device::dma_tick)
{
+ const int irqlevel = Level == 0 ? 5 : 6;
+ const int irqvector = 0x4b - Level;
+ const uint16_t irqmask = 1 << (11 - Level);
- switch(id)
- {
- case DMALV0_ID:
- case DMALV1_ID:
- case DMALV2_ID:
- {
- const int irqlevel = id == 0 ? 5 : 6;
- const int irqvector = 0x4b - id;
- const uint16_t irqmask = 1 << (11-id);
-
- if(!(m_ism & irqmask))
- m_hostcpu->set_input_line_and_vector(irqlevel, HOLD_LINE, irqvector); // SH2
- else
- m_ist |= (irqmask);
+ if(!(m_ism & irqmask))
+ m_hostcpu->set_input_line_and_vector(irqlevel, HOLD_LINE, irqvector); // SH2
+ else
+ m_ist |= (irqmask);
- update_dma_status(id,false);
- machine().scheduler().synchronize(); // force resync
- break;
- }
- default:
- break;
- }
+ update_dma_status((uint8_t)Level,false);
+ machine().scheduler().synchronize(); // force resync
}
//**************************************************************************
@@ -700,7 +688,7 @@ void sega_scu_device::test_pending_irqs()
}
}
-WRITE_LINE_MEMBER(sega_scu_device::vblank_out_w)
+void sega_scu_device::vblank_out_w(int state)
{
if(!state)
return;
@@ -714,7 +702,7 @@ WRITE_LINE_MEMBER(sega_scu_device::vblank_out_w)
m_ist |= (IRQ_VBLANK_OUT);
}
-WRITE_LINE_MEMBER(sega_scu_device::vblank_in_w)
+void sega_scu_device::vblank_in_w(int state)
{
if(!state)
return;
@@ -728,7 +716,7 @@ WRITE_LINE_MEMBER(sega_scu_device::vblank_in_w)
m_ist |= (IRQ_VBLANK_IN);
}
-WRITE_LINE_MEMBER(sega_scu_device::hblank_in_w)
+void sega_scu_device::hblank_in_w(int state)
{
if(!state)
return;
@@ -742,7 +730,7 @@ WRITE_LINE_MEMBER(sega_scu_device::hblank_in_w)
m_ist |= (IRQ_HBLANK_IN);
}
-WRITE_LINE_MEMBER(sega_scu_device::vdp1_end_w)
+void sega_scu_device::vdp1_end_w(int state)
{
if(!state)
return;
@@ -756,7 +744,7 @@ WRITE_LINE_MEMBER(sega_scu_device::vdp1_end_w)
m_ist |= (IRQ_VDP1_END);
}
-WRITE_LINE_MEMBER(sega_scu_device::sound_req_w)
+void sega_scu_device::sound_req_w(int state)
{
if(!state)
return;
@@ -770,7 +758,7 @@ WRITE_LINE_MEMBER(sega_scu_device::sound_req_w)
m_ist |= (IRQ_SOUND_REQ);
}
-WRITE_LINE_MEMBER(sega_scu_device::smpc_irq_w)
+void sega_scu_device::smpc_irq_w(int state)
{
if(!state)
return;
@@ -781,7 +769,7 @@ WRITE_LINE_MEMBER(sega_scu_device::smpc_irq_w)
m_ist |= (IRQ_SMPC);
}
-WRITE_LINE_MEMBER(sega_scu_device::scudsp_end_w)
+void sega_scu_device::scudsp_end_w(int state)
{
if(!state)
return;
diff --git a/src/devices/machine/sega_scu.h b/src/devices/machine/sega_scu.h
index ae751b09d2f..f66f65df0d4 100644
--- a/src/devices/machine/sega_scu.h
+++ b/src/devices/machine/sega_scu.h
@@ -11,7 +11,7 @@
#pragma once
-#include "cpu/sh/sh2.h"
+#include "cpu/sh/sh7604.h"
#include "cpu/scudsp/scudsp.h"
#define IRQ_VBLANK_IN 1 << 0
@@ -46,13 +46,13 @@ public:
// I/O operations
void regs_map(address_map &map);
- DECLARE_WRITE_LINE_MEMBER(vblank_out_w);
- DECLARE_WRITE_LINE_MEMBER(vblank_in_w);
- DECLARE_WRITE_LINE_MEMBER(hblank_in_w);
- DECLARE_WRITE_LINE_MEMBER(vdp1_end_w);
+ void vblank_out_w(int state);
+ void vblank_in_w(int state);
+ void hblank_in_w(int state);
+ void vdp1_end_w(int state);
void check_scanline_timers(int scanline,int y_step);
- DECLARE_WRITE_LINE_MEMBER(sound_req_w);
- DECLARE_WRITE_LINE_MEMBER(smpc_irq_w);
+ void sound_req_w(int state);
+ void smpc_irq_w(int state);
template <typename T> void set_hostcpu(T &&tag) { m_hostcpu.set_tag(std::forward<T>(tag)); }
@@ -63,12 +63,13 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_reset_after_children() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ template <int Level> TIMER_CALLBACK_MEMBER(dma_tick);
private:
required_device<scudsp_cpu_device> m_scudsp;
- enum {
+ enum dma_id : int {
DMALV0_ID = 0,
DMALV1_ID,
DMALV2_ID
@@ -83,7 +84,7 @@ private:
bool m_t1md;
bool m_tenb;
- required_device<sh2_device> m_hostcpu;
+ required_device<sh7604_device> m_hostcpu;
address_space *m_hostspace;
void test_pending_irqs();
@@ -109,7 +110,7 @@ private:
void dma_single_transfer(uint32_t src, uint32_t dst,uint8_t *src_shift);
void dma_start_factor_ack(uint8_t event);
- DECLARE_WRITE_LINE_MEMBER(scudsp_end_w);
+ void scudsp_end_w(int state);
uint16_t scudsp_dma_r(offs_t offset, uint16_t mem_mask = ~0);
void scudsp_dma_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
diff --git a/src/devices/machine/segacrp2_device.cpp b/src/devices/machine/segacrp2_device.cpp
new file mode 100644
index 00000000000..1a2676bd631
--- /dev/null
+++ b/src/devices/machine/segacrp2_device.cpp
@@ -0,0 +1,451 @@
+// license:BSD-3-Clause
+// copyright-holders:Nicola Salmoria, David Haywood
+/******************************************************************************
+
+ Sega encryption emulation by Nicola Salmoria
+
+
+ This encryption is an evolution of the one implemented in segacrpt.cpp.
+ It works on more data and address bits but apart from that it's essentially
+ the same.
+
+ The encryption affects D0, D2, D4, and D6, and depends on M1, A0, A3, A6, A9,
+ A12, and A14.
+
+ The encryption consists of a permutation of the four data bits, which can also
+ be inverted. Therefore there are 4! * 2^4 = 384 different possible encryptions.
+
+ An interesting peculiarity is that four games in the list below use an almost
+ identical key, just offset by one or more bytes. This leads to believe that
+ keys were generated using a PRNG like in other Sega encryptions (MC8123 etc.)
+ and the CPU part# used to skip the first N bytes.
+
+
+ List of encrypted games currently known:
+
+ CPU Part # Game Comments
+ 315-5136 New Lucky 8 Lines (set 7, W-4, encrypted)
+ 315-5162 4D Warriors & used I'm Sorry for k.p.a.
+ Rafflesia &
+ Wonder Boy (set 4)
+ 315-5176 Wonder Boy (system 2 hardware, set 2)
+ 315-5177 Astro Flash &
+ Wonder Boy (set 1)
+ 315-5178 Wonder Boy (set 2) unencrypted version available
+ 315-5179 Robo-Wrestle 2001
+ 317-5000 Fantasy Zone (Sound CPU) same key as 315-5177
+
+ The following games seem to use the same algorithm as the above ones, but
+ using a key which almost doesn't change
+
+ 317-0004 Calorie Kun unencrypted bootleg available
+ 317-0005 Space Position
+ 317-0006 Gardia (set 1)
+ 317-0007 Gardia (set 2)
+
+******************************************************************************/
+
+#include "emu.h"
+#include "segacrp2_device.h"
+
+
+static void decode(uint8_t *rom, uint8_t *decrypted, const uint8_t xor_table[128], const int swap_table[128])
+{
+ static const uint8_t swaptable[24][4] = {
+ { 6,4,2,0 }, { 4,6,2,0 }, { 2,4,6,0 }, { 0,4,2,6 },
+ { 6,2,4,0 }, { 6,0,2,4 }, { 6,4,0,2 }, { 2,6,4,0 },
+ { 4,2,6,0 }, { 4,6,0,2 }, { 6,0,4,2 }, { 0,6,4,2 },
+ { 4,0,6,2 }, { 0,4,6,2 }, { 6,2,0,4 }, { 2,6,0,4 },
+ { 0,6,2,4 }, { 2,0,6,4 }, { 0,2,6,4 }, { 4,2,0,6 },
+ { 2,4,0,6 }, { 4,0,2,6 }, { 2,0,4,6 }, { 0,2,4,6 } };
+
+ for (int a = 0x0000; a < 0x8000; a++)
+ {
+ const uint8_t *tbl;
+
+ const uint8_t src = rom[a];
+
+ // pick the translation table from bits 0, 3, 6, 9, 12 and 14 of the address
+ const int row = bitswap<6>(a, 14, 12, 9, 6, 3, 0);
+
+ // decode the opcodes
+ tbl = swaptable[swap_table[2 * row]];
+ decrypted[a] = bitswap<8>(src, 7, tbl[0], 5, tbl[1], 3, tbl[2], 1, tbl[3]) ^ xor_table[2 * row];
+
+ // decode the data
+ tbl = swaptable[swap_table[2 * row + 1]];
+ rom[a] = bitswap<8>(src, 7, tbl[0], 5, tbl[1], 3, tbl[2], 1, tbl[3]) ^ xor_table[2 * row + 1];
+ }
+}
+
+
+DEFINE_DEVICE_TYPE(NEC_315_5136, nec_315_5136_device, "nec_315_5136", "Nec 315-5136")
+DEFINE_DEVICE_TYPE(SEGA_315_5179, sega_315_5179_device, "sega_315_5179", "Sega 315-5179")
+DEFINE_DEVICE_TYPE(SEGA_315_5178, sega_315_5178_device, "sega_315_5178", "Sega 315-5178")
+DEFINE_DEVICE_TYPE(SEGA_315_5177, sega_315_5177_device, "sega_315_5177", "Sega 315-5177") // also seen as 317-5000
+DEFINE_DEVICE_TYPE(SEGA_315_5176, sega_315_5176_device, "sega_315_5176", "Sega 315-5176")
+DEFINE_DEVICE_TYPE(SEGA_315_5162, sega_315_5162_device, "sega_315_5162", "Sega 315-5162")
+
+DEFINE_DEVICE_TYPE(SEGA_317_0004, sega_317_0004_device, "sega_317_0004", "Sega 317-0004")
+DEFINE_DEVICE_TYPE(SEGA_317_0005, sega_317_0005_device, "sega_317_0005", "Sega 317-0005")
+DEFINE_DEVICE_TYPE(SEGA_317_0006, sega_317_0006_device, "sega_317_0006", "Sega 317-0006")
+DEFINE_DEVICE_TYPE(SEGA_317_0007, sega_317_0007_device, "sega_317_0007", "Sega 317-0007")
+
+
+segacrp2_z80_device::segacrp2_z80_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ z80_device(mconfig, type, tag, owner, clock),
+ m_decrypted(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void segacrp2_z80_device::device_start()
+{
+ z80_device::device_start();
+ decrypt();
+}
+
+nec_315_5136_device::nec_315_5136_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, NEC_315_5136, tag, owner, clock)
+{
+}
+
+void nec_315_5136_device::decrypt()
+{
+ // 315-5136
+ static const uint8_t xor_table[128] = {
+ 0x00,0x40, 0x10,0x50, 0x04,0x44, 0x14,0x54, 0x01,0x41, 0x11,0x51, 0x05,0x45, 0x15,0x55,
+ 0x00,0x40, 0x10,0x50, 0x04,0x44, 0x14,0x54, 0x01,0x41, 0x11,0x51, 0x05,0x45, 0x15,0x55,
+ 0x00,0x40, 0x10,0x50, 0x04,0x44, 0x14,0x54, 0x01,0x41, 0x11,0x51, 0x05,0x45, 0x15,0x55,
+ 0x00,0x40, 0x10,0x50, 0x04,0x44, 0x14,0x54, 0x01,0x41, 0x11,0x51, 0x05,0x45, 0x15,0x55,
+
+ 0x50,0x10, 0x44,0x04, 0x54,0x14, 0x41,0x01, 0x51,0x11, 0x45,0x05, 0x55,0x15, 0x40,0x00,
+ 0x50,0x10, 0x44,0x04, 0x54,0x14, 0x41,0x01, 0x51,0x11, 0x45,0x05, 0x55,0x15, 0x40,0x00,
+ 0x50,0x10, 0x44,0x04, 0x54,0x14, 0x41,0x01, 0x51,0x11, 0x45,0x05, 0x55,0x15, 0x40,0x00,
+ 0x50,0x10, 0x44,0x04, 0x54,0x14, 0x41,0x01, 0x51,0x11, 0x45,0x05, 0x55,0x15, 0x40,0x00 };
+
+ static const int swap_table[128] = {
+ 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,
+ 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,
+ 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,
+ 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+ 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,
+ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
+ 0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,
+ 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
+ 0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x04 };
+
+ decode(memregion(tag())->base(), m_decrypted, xor_table, swap_table);
+}
+
+
+sega_315_5177_device::sega_315_5177_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_315_5177, tag, owner, clock)
+{
+}
+
+void sega_315_5177_device::decrypt()
+{
+ // 315-5177
+ static const uint8_t xor_table[128] = {
+ 0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
+ 0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
+ 0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
+ 0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
+ 0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
+ 0x05,0x55,0x50,0x14,
+
+ 0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
+ 0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
+ 0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
+ 0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
+ 0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
+ 0x05,0x55,0x50,0x14 };
+
+ static const int swap_table[128] = {
+ 0,0,0,0,
+ 1,1,1,1,1,
+ 2,2,2,2,2,
+ 3,3,3,3,
+ 4,4,4,4,4,
+ 5,5,5,5,5,
+ 6,6,6,6,6,
+ 7,7,7,7,7,
+ 8,8,8,8,
+ 9,9,9,9,9,
+ 10,10,10,10,10,
+ 11,11,11,11,11,
+ 12,12,12,12,12,
+ 13,13,
+
+ 8,8,8,8,
+ 9,9,9,9,9,
+ 10,10,10,10,10,
+ 11,11,11,11,
+ 12,12,12,12,12,
+ 13,13,13,13,13,
+ 14,14,14,14,14,
+ 15,15,15,15,15,
+ 16,16,16,16,
+ 17,17,17,17,17,
+ 18,18,18,18,18,
+ 19,19,19,19,19,
+ 20,20,20,20,20,
+ 21,21 };
+ decode(memregion(tag())->base(), m_decrypted, xor_table, swap_table);
+}
+
+
+sega_315_5176_device::sega_315_5176_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_315_5176, tag, owner, clock)
+{
+}
+
+void sega_315_5176_device::decrypt()
+{
+ static const uint8_t xor_table[128] = {
+ 0x44, 0x01, 0x51, 0x15, 0x40, 0x04, 0x54, 0x11, 0x45, 0x00, 0x50, 0x14,
+ 0x41, 0x05, 0x55, 0x10, 0x44, 0x01, 0x51, 0x15, 0x40, 0x04, 0x54, 0x11,
+ 0x45, 0x00, 0x50, 0x14, 0x41, 0x05, 0x55, 0x10, 0x44, 0x01, 0x51, 0x15,
+ 0x40, 0x04, 0x54, 0x11, 0x45, 0x00, 0x50, 0x14, 0x41, 0x05, 0x55, 0x10,
+ 0x44, 0x01, 0x51, 0x15, 0x40, 0x04, 0x54, 0x11, 0x45, 0x00, 0x50, 0x14,
+ 0x41, 0x05, 0x55, 0x10,
+
+ 0x44, 0x01, 0x51, 0x15, 0x40, 0x04, 0x54, 0x11, 0x45, 0x00, 0x50, 0x14,
+ 0x41, 0x05, 0x55, 0x10, 0x44, 0x01, 0x51, 0x15, 0x40, 0x04, 0x54, 0x11,
+ 0x45, 0x00, 0x50, 0x14, 0x41, 0x05, 0x55, 0x10, 0x44, 0x01, 0x51, 0x15,
+ 0x40, 0x04, 0x54, 0x11, 0x45, 0x00, 0x50, 0x14, 0x41, 0x05, 0x55, 0x10,
+ 0x44, 0x01, 0x51, 0x15, 0x40, 0x04, 0x54, 0x11, 0x45, 0x00, 0x50, 0x14,
+ 0x41, 0x05, 0x55, 0x10 };
+
+ static const int swap_table[128] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09,
+ 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c,
+
+ 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+ 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e,
+ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12,
+ 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14 };
+
+ decode(memregion(tag())->base(), m_decrypted, xor_table, swap_table);
+}
+
+
+sega_315_5162_device::sega_315_5162_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_315_5162, tag, owner, clock)
+{
+}
+
+void sega_315_5162_device::decrypt()
+{
+ // 315-5162
+ static const uint8_t xor_table[128] = {
+ 0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00,0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00,0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00,0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00,0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00,0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00,0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00,0x40,0x10,0x50,0x04,0x44,0x14,0x54,0x01,0x41,0x11,0x51,0x05,0x45,0x15,0x55,
+ 0x00 };
+
+ static const int swap_table[128] = {
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+ 12 };
+
+ decode(memregion(tag())->base(), m_decrypted, xor_table, swap_table);
+}
+
+
+
+sega_315_5178_device::sega_315_5178_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_315_5178, tag, owner, clock)
+{
+}
+
+void sega_315_5178_device::decrypt()
+{ // 315-5178
+ static const uint8_t xor_table[128] = {
+ 0x00,0x55,0x45,0x05,0x11,0x41,0x01,0x14,0x44,0x50,0x10,
+ 0x00,0x55,0x15,0x05,0x51,0x41,0x01,0x14,0x44,0x04,0x10,
+ 0x40,0x55,0x15,0x05,0x51,0x11,
+ 0x01,0x54,0x44,0x04,0x10,0x40,0x00,0x15,0x45,0x51,0x11,
+ 0x01,0x54,0x14,0x04,0x50,0x40,0x00,0x15,0x45,0x05,0x11,
+ 0x41,0x54,0x14,0x04,0x50,0x10,
+ 0x00,0x55,0x45,0x05,0x11,0x41,0x01,0x14,
+
+ 0x00,0x55,0x45,0x05,0x11,0x41,0x01,0x14,0x44,0x50,0x10,
+ 0x00,0x55,0x15,0x05,0x51,0x41,0x01,0x14,0x44,0x04,0x10,
+ 0x40,0x55,0x15,0x05,0x51,0x11,
+ 0x01,0x54,0x44,0x04,0x10,0x40,0x00,0x15,0x45,0x51,0x11,
+ 0x01,0x54,0x14,0x04,0x50,0x40,0x00,0x15,0x45,0x05,0x11,
+ 0x41,0x54,0x14,0x04,0x50,0x10,
+ 0x00,0x55,0x45,0x05,0x11,0x41,0x01,0x14 };
+
+ static const int swap_table[128] = {
+ 2,
+ 3, 5, 7, 1, 3, 5, 7, 1, 3, 5, 7,
+ 0, 2, 4, 6, 0, 2, 4, 6, 0, 2, 4,
+ 5, 7, 1, 3, 5, 7, 1, 3, 5, 7, 1, 3,
+ 4, 6, 0, 2, 4, 6, 0, 2, 4, 6,
+ 8,
+ 1, 3, 5, 7, 1, 3, 5, 7, 1, 3, 5,
+ 6, 0, 2, 4, 6, 0, 2,
+
+ 10,
+ 11,13,15, 9,11,13,15, 9,11,13,15,
+ 8,10,12,14, 8,10,12,14, 8,10,12,
+ 13,15, 9,11,13,15, 9,11,13,15, 9,11,
+ 12,14, 8,10,12,14, 8,10,12,14,
+ 16,
+ 9,11,13,15, 9,11,13,15, 9,11,13,
+ 14, 8,10,12,14, 8,10 };
+
+ decode(memregion(tag())->base(), m_decrypted, xor_table, swap_table);
+}
+
+
+sega_315_5179_device::sega_315_5179_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_315_5179, tag, owner, clock)
+{
+}
+
+void sega_315_5179_device::decrypt()
+{ // 315-5179
+ static const uint8_t xor_table[128] = {
+ 0x00,0x45,0x41,0x14,0x10,0x55,0x51,0x01,0x04,0x40,0x45,0x11,0x14,0x50,
+ 0x00,0x05,0x41,0x44,0x10,0x15,0x51,0x54,0x04,
+ 0x00,0x45,0x41,0x14,0x10,0x55,0x05,0x01,0x44,0x40,0x15,0x11,0x54,0x50,
+ 0x00,0x05,0x41,0x44,0x10,0x15,0x51,0x01,0x04,
+ 0x40,0x45,0x11,0x14,0x50,0x55,0x05,0x01,0x44,0x40,0x15,0x11,0x54,0x04,
+ 0x00,0x45,0x41,0x14,0x50,
+ 0x00,0x05,0x41,0x44,0x10,0x15,0x51,0x54,0x04,
+ 0x00,0x45,0x41,0x14,0x50,0x55,0x05,0x01,0x44,0x40,0x15,0x11,0x54,0x50,
+ 0x00,0x05,0x41,0x44,0x10,0x55,0x51,0x01,0x04,
+ 0x40,0x45,0x11,0x14,0x50,0x55,0x05,0x01,0x44,0x40,0x15,0x51,0x54,0x04,
+ 0x00,0x45,0x41,0x14,0x10,0x55,0x51,0x01,0x04,
+ 0x40,0x45,0x11,0x54,0x50,0x00,0x05,0x41 };
+
+ static const int swap_table[128] = {
+ 8, 9,11,13,15, 0, 2, 4, 6,
+ 8, 9,11,13,15, 1, 2, 4, 6,
+ 8, 9,11,13,15, 1, 2, 4, 6,
+ 8, 9,11,13,15, 1, 2, 4, 6,
+ 8,10,11,13,15, 1, 2, 4, 6,
+ 8,10,11,13,15, 1, 2, 4, 6,
+ 8,10,11,13,15, 1, 3, 4, 6,
+ 8,
+ 7, 1, 2, 4, 6, 0, 1, 3, 5,
+ 7, 1, 2, 4, 6, 0, 1, 3, 5,
+ 7, 1, 2, 4, 6, 0, 2, 3, 5,
+ 7, 1, 2, 4, 6, 0, 2, 3, 5,
+ 7, 1, 2, 4, 6, 0, 2, 3, 5,
+ 7, 1, 3, 4, 6, 0, 2, 3, 5,
+ 7, 1, 3, 4, 6, 0, 2, 4, 5,
+ 7 };
+
+ decode(memregion(tag())->base(), m_decrypted, xor_table, swap_table);
+}
+
+
+/******************************************************************************
+
+ These games (all 317-000x CPUs) use the same algorithm, but the key doesn't
+ change much - just a shift in the table.
+
+******************************************************************************/
+
+static void sega_decode_317(uint8_t *rom, uint8_t *decrypted, int shift)
+{
+ static const uint8_t xor_table[128 + 3] = {
+ 0x04,0x54,0x44,0x14,0x15,0x15,0x51,0x41,0x41,0x14,0x10,0x50,0x15,0x55,0x54,0x05,
+ 0x04,0x41,0x51,0x01,0x05,0x10,0x55,0x51,0x05,0x05,0x54,0x11,0x45,0x05,0x04,0x14,
+ 0x10,0x55,0x01,0x41,0x51,0x05,0x55,0x04,0x45,0x41,0x55,0x14,0x45,0x10,0x04,0x45,
+ 0x55,0x50,0x40,0x00,0x11,0x45,0x15,0x00,0x01,0x00,0x40,0x00,0x01,0x45,0x11,0x00,
+ 0x45,0x00,0x44,0x54,0x40,0x04,0x05,0x15,0x15,0x10,0x15,0x04,0x01,0x05,0x50,0x11,
+ 0x00,0x44,0x44,0x04,0x04,0x01,0x50,0x05,0x51,0x00,0x45,0x44,0x50,0x15,0x54,0x40,
+ 0x41,0x45,0x40,0x10,0x14,0x15,0x40,0x51,0x50,0x50,0x45,0x00,0x10,0x15,0x05,0x51,
+ 0x50,0x44,0x01,0x15,0x40,0x04,0x01,0x44,0x50,0x44,0x50,0x50,0x50,0x10,0x44,0x04,
+ 0x40,0x04,0x10 };
+
+ static const int swap_table[128 + 3] = {
+ 7, 7,12, 1,18,11, 8,23,21,17, 0,23,22, 0,21,15,
+ 13,19,21,20,20,12,13,10,20, 0,14,18, 6,18, 3, 5,
+ 5,20,20,13, 8, 0,20,18, 4,14, 8, 5,17, 6,22,10,
+ 0,21, 0, 1, 6,11,17, 9,17, 3, 9,21, 0, 4,16, 1,
+ 13,17,21, 5, 3, 7, 2,16,18,13, 6,19,11,23, 3,20,
+ 3, 2,18,10,18,23,19,23, 3,15, 0,10, 5,12, 0, 0,
+ 11,22, 8,14, 8, 6, 1,15, 7,11, 2,17,10,15, 8,21,
+ 10, 0, 2, 6, 1, 1, 3, 1,12,18,16, 5, 0,15,17,15,
+ 10,20, 1 };
+
+ decode(rom, decrypted, xor_table + shift, swap_table + shift);
+}
+
+
+sega_317_0004_device::sega_317_0004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_317_0004, tag, owner, clock)
+{
+}
+
+void sega_317_0004_device::decrypt()
+{ // 317-0004
+ sega_decode_317(memregion(tag())->base(), m_decrypted, 0);
+}
+
+
+sega_317_0005_device::sega_317_0005_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_317_0005, tag, owner, clock)
+{
+}
+
+void sega_317_0005_device::decrypt()
+{ // 317-0005
+ sega_decode_317(memregion(tag())->base(), m_decrypted, 1);
+}
+
+
+sega_317_0006_device::sega_317_0006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_317_0006, tag, owner, clock)
+{
+}
+
+void sega_317_0006_device::decrypt()
+{ // 317-0006
+ sega_decode_317(memregion(tag())->base(), m_decrypted, 2);
+}
+
+
+sega_317_0007_device::sega_317_0007_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ segacrp2_z80_device(mconfig, SEGA_317_0007, tag, owner, clock)
+{
+}
+
+void sega_317_0007_device::decrypt()
+{ // 317-0006
+ sega_decode_317(memregion(tag())->base(), m_decrypted, 3);
+}
diff --git a/src/devices/machine/segacrp2_device.h b/src/devices/machine/segacrp2_device.h
new file mode 100644
index 00000000000..a64f3fa5fe0
--- /dev/null
+++ b/src/devices/machine/segacrp2_device.h
@@ -0,0 +1,126 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+#ifndef MAME_MACHINE_SEGACRP2_DEVICE_H
+#define MAME_MACHINE_SEGACRP2_DEVICE_H
+
+#pragma once
+
+
+#include "cpu/z80/z80.h"
+
+// base class
+class segacrp2_z80_device : public z80_device
+{
+public:
+ template <typename T> void set_decrypted_tag(T &&decrypted_tag) { m_decrypted.set_tag(std::forward<T>(decrypted_tag)); }
+
+protected:
+ segacrp2_z80_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void decrypt() = 0;
+
+ required_shared_ptr<uint8_t> m_decrypted;
+};
+
+
+
+// actual encrypted CPUs
+class nec_315_5136_device : public segacrp2_z80_device
+{
+public:
+ nec_315_5136_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5179_device : public segacrp2_z80_device
+{
+public:
+ sega_315_5179_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+class sega_315_5178_device : public segacrp2_z80_device
+{
+public:
+ sega_315_5178_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5177_device : public segacrp2_z80_device
+{
+public:
+ sega_315_5177_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5176_device : public segacrp2_z80_device
+{
+public:
+ sega_315_5176_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5162_device : public segacrp2_z80_device
+{
+public:
+ sega_315_5162_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_317_0004_device : public segacrp2_z80_device
+{
+public:
+ sega_317_0004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+class sega_317_0005_device : public segacrp2_z80_device
+{
+public:
+ sega_317_0005_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+class sega_317_0006_device : public segacrp2_z80_device
+{
+public:
+ sega_317_0006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_317_0007_device : public segacrp2_z80_device
+{
+public:
+ sega_317_0007_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+DECLARE_DEVICE_TYPE(NEC_315_5136, nec_315_5136_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5179, sega_315_5179_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5178, sega_315_5178_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5177, sega_315_5177_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5176, sega_315_5176_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5162, sega_315_5162_device)
+
+DECLARE_DEVICE_TYPE(SEGA_317_0004, sega_317_0004_device)
+DECLARE_DEVICE_TYPE(SEGA_317_0005, sega_317_0005_device)
+DECLARE_DEVICE_TYPE(SEGA_317_0006, sega_317_0006_device)
+DECLARE_DEVICE_TYPE(SEGA_317_0007, sega_317_0007_device)
+
+
+#endif // MAME_MACHINE_SEGACRP2_DEVICE_H
diff --git a/src/devices/machine/segacrpt_device.cpp b/src/devices/machine/segacrpt_device.cpp
new file mode 100644
index 00000000000..b7ab782499f
--- /dev/null
+++ b/src/devices/machine/segacrpt_device.cpp
@@ -0,0 +1,1068 @@
+// license:BSD-3-Clause
+// copyright-holders:Nicola Salmoria, David Haywood
+/******************************************************************************
+
+ Sega encryption emulation by Nicola Salmoria
+
+
+ Several Sega Z80 games have program ROMs encrypted using a common algorithm
+ (but with a different key).
+ The hardware used to implement this encryption is either a custom CPU, or an
+ epoxy block which probably contains a standard Z80 + PALs.
+
+ The encryption affects D3, D5, and D7, and depends on M1, A0, A4, A8 and A12.
+ D0, D1, D2, D4 and D6 are always unaffected.
+
+ The encryption consists of a permutation of the three bits, which can also be
+ inverted. Therefore there are 3! * 2^3 = 48 different possible encryptions.
+
+ For simplicity, the decryption is implemented using conversion tables.
+ We need 32 of these tables, one for every possible combination of M1, A0, A4,
+ A8 and A12. However, all the games currently known are full of repetitions
+ and only use 6 different tables, the only exceptions being Pengo, Yamato and
+ Spatter which have 7 (but one of them is the identity: { 0x00, 0x08, 0x20, 0x28 } ).
+ This is most likely a limitation of the hardware.
+ Some of the early games are even weaker: of the 6 different tables, they use
+ 3 for opcodes and 3 for data, and always coupled in the same way.
+
+ In all games currently known, only bytes in the memory range 0x0000-0x7fff
+ (A15 = 0) are encrypted. My guess is that this was done to allow games to
+ copy code to RAM (in the memory range 0x8000-0xffff) and execute it from
+ there without the CPU trying to decrypt it and messing everything up.
+ However Zaxxon has RAM at 0x6000, and the CPU doesn't seem to interfere with
+ it; but it doesn't execute code from there, so it's possible that the CPU is
+ encrypting the data while writing it and decrypting it while reading (that
+ would seem kind of strange though). Video and sprite RAM and memory mapped
+ ports are all placed above 0x8000.
+
+ Given its strict limitations, this encryption is reasonably easy to break,
+ and very vulnerable to known plaintext attacks.
+
+
+
+ Ninja Princess:
+
+ there is a (bootleg?) board which has a standard Z80 + 2 bipolar PROMs
+ instead of the custom CPU. The encryption table is different from the
+ original Ninja Princess; it is actually the same as Flicky.
+
+ The first PROM is 32x8 and contains the number (0..5) of the table to
+ use depending on M1, A0, A4, A8, A12:
+
+ 00: 11 00 33 22 00 44 44 00 11 33 33 22 44 44 44 22
+ 10: 11 55 55 33 44 22 55 22 11 33 55 33 44 44 11 22
+
+ The second PROM is 256x4 and contains the 6 different XOR tables:
+
+ A D B C C B D A
+ 00: 09 09 0A 0A 0A 0A 09 09
+ 08: 0E 08 0B 0D 0D 0B 08 0E
+ 10: 0A 0C 0A 0C 0C 0A 0C 0A
+ 18: 0B 0E 0E 0B 0B 0E 0E 0B
+ 20: 0C 0C 0F 0F 0F 0F 0C 0C
+ 28: 08 0D 0B 0E 0E 0B 0D 08
+ [the remaining bytes are all 0F]
+ bit 3 is not used.
+ bits 0-2 is the XOR code inverted (0 = 0xa8, 1 = 0xa0 ... 6 = 0x08 7 = 0x00)
+
+ Here is a diagram showing how it works:
+
+ data to XOR
+ decode value
+ A ---
+ D7 --------------- 0| |
+ D3 --------------- 1| |
+ D5 --------------- 2| P |D
+ A --- D | R |0 ---|>--- D3
+ M1 --- 0| P |0 --- 3| O |1 ---|>--- D5
+ A0 --- 1| R |1 --- 4| M |2 ---|>--- D7
+ A4 --- 2| O |2 --- 5| 2 |3 ---
+ A8 --- 3| M |3 --- 6| |
+ A12 --- 4| 1 |4 --- 7| |
+ --- ---
+
+
+ My Hero:
+
+ the bootleg does the decryption using a single 256x4 PROM, mapped in the
+ obvious way:
+
+ data to XOR
+ decode value
+ A ---
+ D3 --- 0| |
+ D5 --- 1| |D
+ D7 --- 2| P |0 --- D3
+ A0 --- 3| R |1 --- D5
+ A4 --- 4| O |2 --- D7
+ A8 --- 5| M |3 ---
+ A12 --- 6| |
+ M1 --- 7| |
+ ---
+
+
+
+ List of encrypted games currently known:
+
+ CPU Part # Game Comments
+ 315-5006 Monster Bash same encryption scheme as 315-5096 - Spatter
+ 315-5010 Pengo unencrypted version available
+ 315-5013 Super Zaxxon used Zaxxon for known plaintext attack
+ 315-5014 Buck Rogers / Zoom 909 unencrypted version available
+ 315-5015 Super Locomotive
+ 315-5018 Yamato seems to have been copied by Falcon for Falcons Wild - World Wide Poker
+ ???-???? Top Roller same key as Yamato
+ 315-5028 Sindbad Mystery
+ 315-5030 Up'n Down unencrypted version available
+ ???-???? M120 Razzmatazz same key as Up'n Down
+ 315-5033 Regulus unencrypted version available
+ 315-5041 M140 Mister Viking
+ 315-5048 SWAT used Bull Fight for k.p.a.
+ 315-5051 Flicky &
+ Ninja Princess (bootleg)
+ 315-5061 Future Spy
+ 315-5064 Water Match used Mister Viking for k.p.a.
+ 315-5065 Bull Fight
+ 315-5069 Star Force game by Tehkan; same key as Super Locomotive
+ 315-5084 Jongkyo TABLE INCOMPLETE game by Kiwako; also has a simple bitswap on top
+ 315-5093 Pitfall II
+ 315-5096 Spatter same encryption scheme is used by the Falcon 03155096 CPU (Z80)
+ 315-5098 Ninja Princess unencrypted version available; same key as Up'n Down
+ 315-5099 Spatter
+ 315-5102 Sega Ninja unencrypted version available
+ 315-5110 I'm Sorry used My Hero for k.p.a.
+ 315-5111 TeddyBoy Blues same as 315-5006
+ 315-5114 Champion Pro Wrestling same key as Regulus
+ 315-5115 TeddyBoy Blues
+ 315-5128 Pinball Action game by Tehkan; also has a simple bitswap on top
+ 315-5132 My Hero
+ 315-5133 Ninja Princess exactly the same as Sega 315-5048?
+ 315-5135 Heavy Metal &
+ Wonder Boy (set 1a & 3; bootlegs?)
+ 315-5155 TeddyBoy Blues
+
+
+ Some text found in the ROMs:
+
+ Buck Rogers SECULITY BY MASATOSHI,MIZUNAGA
+ Super Locomotive SEGA FUKUMURA MIZUNAGA
+ Yamato SECULITY BY M,MIZUNAGA
+ Regulus SECULITY BY SYUICHI,KATAGI
+ Up'n Down 19/SEP 1983 MASATOSHI,MIZUNAGA
+ Mister Viking SECURITY BY S.KATAGI CONTROL CHIP M140
+ SWAT SECURITY BY S.KATAGI
+ Flicky SECURITY BY S.KATAGI
+ Water Match PROGRAMED BY KAWAHARA&NAKAGAWA
+ Star Force STAR FORCE TEHKAN. SECURITY BY SEGA ENTERPRISESE
+
+******************************************************************************/
+
+#include "emu.h"
+#include "segacrpt_device.h"
+
+
+#if 0
+static void lfkp(int mask)
+{
+ int A;
+ uint8_t *RAM = machine.root_device().memregion("maincpu")->base();
+
+
+ for (A = 0x0000;A < 0x8000-14;A++)
+ {
+ static const char text[] = "INSERT COIN";
+ int i;
+
+
+ if ( (RAM[A+0] & mask) == (0x21 & mask) && /* LD HL,$xxxx */
+ (RAM[A+3] & mask) == (0x11 & mask) && /* LD DE,$xxxx */
+ (RAM[A+6] & mask) == (0x01 & mask)) /* LD BC,$xxxx */
+ {
+ if ( (RAM[A+ 9] & mask) == (0x36 & mask) && /* LD (HL),$xx */
+ (RAM[A+11] & mask) == (0xed & mask) &&
+ (RAM[A+12] & mask) == (0xb0 & mask)) /* LDIR */
+ logerror("%04x: hl de bc (hl),xx ldir\n",A);
+
+ if ( (RAM[A+ 9] & mask) == (0x77 & mask) && /* LD (HL),A */
+ (RAM[A+10] & mask) == (0xed & mask) &&
+ (RAM[A+11] & mask) == (0xb0 & mask)) /* LDIR */
+ logerror("%04x: hl de bc (hl),a ldir\n",A);
+
+ if ( (RAM[A+ 9] & mask) == (0xed & mask) &&
+ (RAM[A+10] & mask) == (0xb0 & mask)) /* LDIR */
+ logerror("%04x: hl de bc ldir\n",A);
+ }
+
+ /* the following can also be PUSH IX, PUSH IY - need better checking */
+ if ( (RAM[A+0] & mask) == (0xf5 & mask) && /* PUSH AF */
+ (RAM[A+1] & mask) == (0xc5 & mask) && /* PUSH BC */
+ (RAM[A+2] & mask) == (0xd5 & mask) && /* PUSH DE */
+ (RAM[A+3] & mask) == (0xe5 & mask)) /* PUSH HL */
+ logerror("%04x: push af bc de hl\n",A);
+
+ if ( (RAM[A+0] & mask) == (0xe1 & mask) && /* POP HL */
+ (RAM[A+1] & mask) == (0xd1 & mask) && /* POP DE */
+ (RAM[A+2] & mask) == (0xc1 & mask) && /* POP BC */
+ (RAM[A+3] & mask) == (0xf1 & mask)) /* POP AF */
+ logerror("%04x: pop hl de bc af\n",A);
+
+ for (i = 0;i < strlen(text);i++)
+ if ((RAM[A+i] & mask) != (text[i] & mask)) break;
+ if (i == strlen(text))
+ logerror("%04x: INSERT COIN\n",A);
+ }
+}
+
+static void look_for_known_plaintext(void)
+{
+ lfkp(0x57);
+}
+#endif
+
+static void decode(uint8_t *data, uint8_t *opcodes, int size, const uint8_t convtable[32][4], int bank_count, int bank_size)
+{
+ for (int A = 0x0000;A < size + bank_count*bank_size;A++)
+ {
+ int xorval = 0;
+
+ uint8_t src = data[A];
+ int adr;
+ if(A < size || !bank_count)
+ adr = A;
+ else
+ adr = size + ((A - size) % bank_size);
+
+ /* pick the translation table from bits 0, 4, 8 and 12 of the address */
+ int row = (adr & 1) + (((adr >> 4) & 1) << 1) + (((adr >> 8) & 1) << 2) + (((adr >> 12) & 1) << 3);
+
+ /* pick the offset in the table from bits 3 and 5 of the source data */
+ int col = ((src >> 3) & 1) + (((src >> 5) & 1) << 1);
+ /* the bottom half of the translation table is the mirror image of the top */
+ if (src & 0x80)
+ {
+ col = 3 - col;
+ xorval = 0xa8;
+ }
+
+ /* decode the opcodes */
+ opcodes[A] = (src & ~0xa8) | (convtable[2*row][col] ^ xorval);
+
+ /* decode the data */
+ data[A] = (src & ~0xa8) | (convtable[2*row+1][col] ^ xorval);
+
+ if (convtable[2*row][col] == 0xff) /* table incomplete! (for development) */
+ opcodes[A] = 0xee;
+ if (convtable[2*row+1][col] == 0xff) /* table incomplete! (for development) */
+ data[A] = 0xee;
+ }
+}
+
+
+
+DEFINE_DEVICE_TYPE(SEGA_315_5006, sega_315_5006_device, "sega_315_5006", "Sega 315-5006")
+DEFINE_DEVICE_TYPE(SEGA_315_5010, sega_315_5010_device, "sega_315_5010", "Sega 315-5010")
+DEFINE_DEVICE_TYPE(SEGA_315_5013, sega_315_5013_device, "sega_315_5013", "Sega 315-5013")
+DEFINE_DEVICE_TYPE(SEGA_315_5014, sega_315_5014_device, "sega_315_5014", "Sega 315-5014")
+DEFINE_DEVICE_TYPE(SEGA_315_5015, sega_315_5015_device, "sega_315_5015", "Sega 315-5015")
+DEFINE_DEVICE_TYPE(SEGA_315_5018, sega_315_5018_device, "sega_315_5018", "Sega 315-5018")
+DEFINE_DEVICE_TYPE(SEGA_315_5028, sega_315_5028_device, "sega_315_5028", "Sega 315-5028")
+DEFINE_DEVICE_TYPE(SEGA_315_5033, sega_315_5033_device, "sega_315_5033", "Sega 315-5033")
+DEFINE_DEVICE_TYPE(SEGA_315_5041, sega_315_5041_device, "sega_315_5041", "Sega 315-5041")
+DEFINE_DEVICE_TYPE(SEGA_315_5048, sega_315_5048_device, "sega_315_5048", "Sega 315-5048")
+DEFINE_DEVICE_TYPE(SEGA_315_5051, sega_315_5051_device, "sega_315_5051", "Sega 315-5051")
+DEFINE_DEVICE_TYPE(SEGA_315_5061, sega_315_5061_device, "sega_315_5061", "Sega 315-5061")
+DEFINE_DEVICE_TYPE(SEGA_315_5064, sega_315_5064_device, "sega_315_5064", "Sega 315-5064")
+DEFINE_DEVICE_TYPE(SEGA_315_5065, sega_315_5065_device, "sega_315_5065", "Sega 315-5065")
+DEFINE_DEVICE_TYPE(SEGA_315_5084, sega_315_5084_device, "sega_315_5084", "Sega 315-5084")
+DEFINE_DEVICE_TYPE(SEGA_315_5093, sega_315_5093_device, "sega_315_5093", "Sega 315-5093")
+DEFINE_DEVICE_TYPE(SEGA_315_5096, sega_315_5096_device, "sega_315_5096", "Sega 315-5096") // exactly the same as Sega 315-5006?
+DEFINE_DEVICE_TYPE(SEGA_315_5098, sega_315_5098_device, "sega_315_5098", "Sega 315-5098") // also 315-5030 ?
+DEFINE_DEVICE_TYPE(SEGA_315_5099, sega_315_5099_device, "sega_315_5099", "Sega 315-5099")
+DEFINE_DEVICE_TYPE(SEGA_315_5102, sega_315_5102_device, "sega_315_5102", "Sega 315-5102")
+DEFINE_DEVICE_TYPE(SEGA_315_5110, sega_315_5110_device, "sega_315_5110", "Sega 315-5110")
+DEFINE_DEVICE_TYPE(SEGA_315_5111, sega_315_5111_device, "sega_315_5111", "Sega 315-5111") // exactly the same as Sega 315-5006?
+DEFINE_DEVICE_TYPE(SEGA_315_5128, sega_315_5128_device, "sega_315_5128", "Sega 315-5128")
+DEFINE_DEVICE_TYPE(SEGA_315_5132, sega_315_5132_device, "sega_315_5132", "Sega 315-5132")
+DEFINE_DEVICE_TYPE(SEGA_315_5133, sega_315_5133_device, "sega_315_5133", "Sega 315-5133") // exactly the same as Sega 315-5048?
+DEFINE_DEVICE_TYPE(SEGA_315_5135, sega_315_5135_device, "sega_315_5135", "Sega 315-5135")
+DEFINE_DEVICE_TYPE(SEGA_315_5155, sega_315_5155_device, "sega_315_5155", "Sega 315-5155")
+
+
+
+
+segacrpt_z80_device::segacrpt_z80_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ z80_device(mconfig, type, tag, owner, clock),
+ m_decrypted_ptr(nullptr),
+ m_region_ptr(nullptr),
+ m_decode_size(0x8000),
+ m_numbanks(0),
+ m_banksize(0),
+ m_decryption_done(false)
+{
+}
+
+void segacrpt_z80_device::device_start()
+{
+ z80_device::device_start();
+}
+
+void segacrpt_z80_device::device_reset()
+{
+ // decrypt on reset, makes sure DRIVER_INIT stuff happens first (for myherok)
+ // actual CPU would be decrypting in realtime anyway
+ if (m_decrypted_ptr == nullptr)
+ {
+ m_decrypted_ptr = (uint8_t*)memshare(m_decrypted_tag)->ptr();
+ }
+
+ if (m_region_ptr == nullptr)
+ {
+ m_region_ptr = (uint8_t*)memregion(tag())->base();
+ }
+
+ if (m_decryption_done == false)
+ {
+ decrypt();
+ m_decryption_done = true;
+ }
+ z80_device::device_reset();
+}
+
+void segacrpt_z80_device::set_region_p(uint8_t* ptr)
+{
+ m_region_ptr = ptr;
+}
+
+void segacrpt_z80_device::set_decrypted_p(uint8_t* ptr)
+{
+ m_decrypted_ptr = ptr;
+}
+
+
+
+
+sega_315_5132_device::sega_315_5132_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5132, tag, owner, clock) {}
+void sega_315_5132_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x20,0x00,0xa0,0x80 }, { 0x80,0xa0,0x88,0xa8 }, /* ...0...0...0...0 */
+ { 0x20,0x00,0xa0,0x80 }, { 0x80,0xa0,0x88,0xa8 }, /* ...0...0...0...1 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...0...1...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0x80,0xa0,0x88,0xa8 }, /* ...0...0...1...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...1...0...0 */
+ { 0x20,0x00,0xa0,0x80 }, { 0x08,0x88,0x00,0x80 }, /* ...0...1...0...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...1...1...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...1...1...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x20,0x00,0xa0,0x80 }, /* ...1...0...0...0 */
+ { 0x80,0xa0,0x88,0xa8 }, { 0x20,0x00,0xa0,0x80 }, /* ...1...0...0...1 */
+ { 0x80,0xa0,0x88,0xa8 }, { 0x80,0xa0,0x88,0xa8 }, /* ...1...0...1...0 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x80,0xa0,0x88,0xa8 }, /* ...1...0...1...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...0...0 */
+ { 0x88,0x80,0x08,0x00 }, { 0x08,0x88,0x00,0x80 }, /* ...1...1...0...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...1...1...0 */
+ { 0x88,0x80,0x08,0x00 }, { 0xa8,0xa0,0x88,0x80 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+
+sega_315_5155_device::sega_315_5155_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5155, tag, owner, clock) {}
+void sega_315_5155_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x20,0x28,0x00,0x08 }, { 0x80,0x00,0xa0,0x20 }, /* ...0...0...0...0 */
+ { 0x20,0x28,0x00,0x08 }, { 0xa0,0xa8,0x20,0x28 }, /* ...0...0...0...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...1...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...1...1 */
+ { 0x20,0x28,0x00,0x08 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...1...0...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0xa8,0x20,0x28 }, /* ...0...1...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...1...1...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...1...1...1 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x80,0x00,0xa0,0x20 }, /* ...1...0...0...0 */
+ { 0xa0,0x20,0xa8,0x28 }, { 0xa0,0xa8,0x20,0x28 }, /* ...1...0...0...1 */
+ { 0xa0,0x20,0xa8,0x28 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...0...1...0 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...0...1...1 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x20,0x28,0x00,0x08 }, /* ...1...1...0...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0x20,0xa8,0x28 }, /* ...1...1...0...1 */
+ { 0x80,0x00,0xa0,0x20 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...1...1...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0x20,0xa8,0x28 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+
+sega_315_5110_device::sega_315_5110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5110, tag, owner, clock) {}
+void sega_315_5110_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0x08,0x80,0x00 }, { 0x00,0x20,0x80,0xa0 }, /* ...0...0...0...0 */
+ { 0x00,0x20,0x80,0xa0 }, { 0x88,0x08,0x80,0x00 }, /* ...0...0...0...1 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x00,0x20,0x80,0xa0 }, /* ...0...0...1...0 */
+ { 0x00,0x20,0x80,0xa0 }, { 0x88,0x08,0xa8,0x28 }, /* ...0...0...1...1 */
+ { 0x00,0x20,0x80,0xa0 }, { 0x08,0x00,0x88,0x80 }, /* ...0...1...0...0 */
+ { 0x00,0x20,0x80,0xa0 }, { 0x20,0x28,0xa0,0xa8 }, /* ...0...1...0...1 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x00,0x20,0x80,0xa0 }, /* ...0...1...1...0 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x88,0x08,0xa8,0x28 }, /* ...0...1...1...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0x08,0x00,0x88,0x80 }, /* ...1...0...0...0 */
+ { 0x08,0x00,0x88,0x80 }, { 0x88,0x08,0x80,0x00 }, /* ...1...0...0...1 */
+ { 0x08,0x28,0x00,0x20 }, { 0x08,0x28,0x00,0x20 }, /* ...1...0...1...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x08,0x28,0x00,0x20 }, /* ...1...0...1...1 */
+ { 0x08,0x28,0x00,0x20 }, { 0x08,0x00,0x88,0x80 }, /* ...1...1...0...0 */
+ { 0x08,0x28,0x00,0x20 }, { 0x20,0x28,0xa0,0xa8 }, /* ...1...1...0...1 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x08,0x28,0x00,0x20 }, /* ...1...1...1...0 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x08,0x28,0x00,0x20 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+sega_315_5135_device::sega_315_5135_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5135, tag, owner, clock) {}
+void sega_315_5135_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...0...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...1...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...0 */
+ { 0x88,0x80,0x08,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...1...0 */
+ { 0x88,0x80,0x08,0x00 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...1...1...1 */
+ { 0xa0,0x20,0xa8,0x28 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...0...0...0 */
+ { 0xa0,0x20,0xa8,0x28 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...0...0...1 */
+ { 0xa0,0x20,0xa8,0x28 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...0...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...0...1...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa0,0x20,0xa8,0x28 }, /* ...1...1...0...0 */
+ { 0xa0,0x20,0xa8,0x28 }, { 0x28,0xa8,0x08,0x88 }, /* ...1...1...0...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa0,0x20,0xa8,0x28 }, /* ...1...1...1...0 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0xa8,0x08,0x88 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+
+sega_315_5051_device::sega_315_5051_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5051, tag, owner, clock) {}
+void sega_315_5051_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x08,0x88,0x00,0x80 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...0...0 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x28,0x08,0x20,0x00 }, /* ...0...0...1...0 */
+ { 0x28,0x08,0x20,0x00 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...1...1 */
+ { 0x08,0x88,0x00,0x80 }, { 0x80,0x00,0xa0,0x20 }, /* ...0...1...0...0 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...1 */
+ { 0x28,0x08,0x20,0x00 }, { 0x28,0x08,0x20,0x00 }, /* ...0...1...1...0 */
+ { 0x28,0x08,0x20,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...1...1 */
+ { 0x08,0x88,0x00,0x80 }, { 0xa8,0x88,0x28,0x08 }, /* ...1...0...0...0 */
+ { 0xa8,0x88,0x28,0x08 }, { 0x80,0x00,0xa0,0x20 }, /* ...1...0...0...1 */
+ { 0x28,0x08,0x20,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...1...0 */
+ { 0xa8,0x88,0x28,0x08 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...1...1 */
+ { 0x08,0x88,0x00,0x80 }, { 0x80,0x00,0xa0,0x20 }, /* ...1...1...0...0 */
+ { 0xa8,0x88,0x28,0x08 }, { 0x80,0x00,0xa0,0x20 }, /* ...1...1...0...1 */
+ { 0x28,0x08,0x20,0x00 }, { 0x28,0x08,0x20,0x00 }, /* ...1...1...1...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0x88,0x80,0x08,0x00 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+sega_315_5098_device::sega_315_5098_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5098, tag, owner, clock) {}
+void sega_315_5098_device::decrypt()
+{
+ // also 315-5030 ?
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x08,0x88,0x00,0x80 }, { 0xa0,0x20,0x80,0x00 }, /* ...0...0...0...0 */
+ { 0xa8,0xa0,0x28,0x20 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...0...0...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...0...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...0...1...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x20,0x80,0x00 }, /* ...0...1...0...0 */
+ { 0xa8,0xa0,0x28,0x20 }, { 0xa8,0xa0,0x28,0x20 }, /* ...0...1...0...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...1...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...1...1...1 */
+ { 0xa0,0x20,0x80,0x00 }, { 0xa0,0x20,0x80,0x00 }, /* ...1...0...0...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...0...0...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...0...1...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...1...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...1...0...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...1...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0x28,0x08,0xa8,0x88 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+
+sega_315_5102_device::sega_315_5102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5102, tag, owner, clock) {}
+void sega_315_5102_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0x08,0x80,0x00 }, /* ...0...0...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa0,0xa8,0x80,0x88 }, /* ...0...0...0...1 */
+ { 0xa8,0xa0,0x28,0x20 }, { 0xa8,0xa0,0x28,0x20 }, /* ...0...0...1...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa0,0xa8,0x80,0x88 }, /* ...0...0...1...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...1...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x08,0x80,0x00 }, /* ...0...1...0...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...1...1...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa8,0xa0,0x28,0x20 }, /* ...0...1...1...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...0...0...0 */
+ { 0xa0,0xa8,0x80,0x88 }, { 0x28,0xa8,0x08,0x88 }, /* ...1...0...0...1 */
+ { 0xa8,0xa0,0x28,0x20 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...0...1...0 */
+ { 0xa8,0xa0,0x28,0x20 }, { 0x28,0xa8,0x08,0x88 }, /* ...1...0...1...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...1...0...0 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...1...0...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...1...1...0 */
+ { 0xa8,0xa0,0x28,0x20 }, { 0x28,0x08,0xa8,0x88 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5065_device::sega_315_5065_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5065, tag, owner, clock) {}
+void sega_315_5065_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x80,0xa0,0x00,0x20 }, /* ...0...0...0...0 */
+ { 0x20,0x28,0x00,0x08 }, { 0x20,0x28,0x00,0x08 }, /* ...0...0...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x08,0x28,0x00,0x20 }, /* ...0...0...1...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x88,0x08,0xa8,0x28 }, /* ...0...0...1...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x20,0x28,0x00,0x08 }, /* ...0...1...0...0 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0x20,0x28,0x00,0x08 }, /* ...0...1...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x08,0x28,0x00,0x20 }, /* ...0...1...1...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x88,0x08,0xa8,0x28 }, /* ...0...1...1...1 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0xa0,0xa8,0x20,0x28 }, /* ...1...0...0...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...0...0...1 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0x08,0x28,0x00,0x20 }, /* ...1...0...1...0 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...0...1...1 */
+ { 0x20,0x28,0x00,0x08 }, { 0x20,0x28,0x00,0x08 }, /* ...1...1...0...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x20,0x28,0x00,0x08 }, /* ...1...1...0...1 */
+ { 0x08,0x28,0x00,0x20 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...1...1...0 */
+ { 0x08,0x28,0x00,0x20 }, { 0x88,0x08,0xa8,0x28 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5064_device::sega_315_5064_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5064, tag, owner, clock) {}
+void sega_315_5064_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...0...0...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...0...0...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0x20,0x28,0xa0,0xa8 }, /* ...0...0...1...0 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...0...1...1 */
+ { 0xa8,0x28,0x88,0x08 }, { 0xa8,0x28,0x88,0x08 }, /* ...0...1...0...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0xa8,0x28,0x88,0x08 }, /* ...0...1...0...1 */
+ { 0xa8,0x28,0x88,0x08 }, { 0x20,0x28,0xa0,0xa8 }, /* ...0...1...1...0 */
+ { 0xa8,0x28,0x88,0x08 }, { 0xa8,0x28,0x88,0x08 }, /* ...0...1...1...1 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...0...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x20,0x28,0xa0,0xa8 }, /* ...1...0...0...1 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...0...1...0 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x20,0x28,0xa0,0xa8 }, /* ...1...0...1...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0x20,0x28,0xa0,0xa8 }, /* ...1...1...0...0 */
+ { 0xa8,0x28,0x88,0x08 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...0...1 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x20,0x28,0xa0,0xa8 }, /* ...1...1...1...0 */
+ { 0xa8,0x28,0x88,0x08 }, { 0xa8,0x28,0x88,0x08 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+sega_315_5033_device::sega_315_5033_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5033, tag, owner, clock) {}
+void sega_315_5033_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x28,0x08,0xa8,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...0...0 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...0...0...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0x88,0x08,0x80,0x00 }, /* ...0...0...1...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...0...1...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...0 */
+ { 0x88,0x80,0x08,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0x88,0x08,0x80,0x00 }, /* ...0...1...1...0 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...1...1...1 */
+ { 0x80,0xa0,0x00,0x20 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...0...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...0...0...1 */
+ { 0x80,0xa0,0x00,0x20 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...0...1...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...0...1...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...1...0...0 */
+ { 0x80,0xa0,0x00,0x20 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...1...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...1...1...0 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa0,0x80,0xa8,0x88 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5041_device::sega_315_5041_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5041, tag, owner, clock) {}
+void sega_315_5041_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...0...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...0...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...0...1...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x88,0x08,0x80,0x00 }, /* ...0...0...1...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...0 */
+ { 0x88,0x80,0x08,0x00 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...1...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...0...1...1...0 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...1...1...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...0...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...0...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...0...1...0 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x88,0x08,0x80,0x00 }, /* ...1...0...1...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...0...0 */
+ { 0xa0,0x80,0x20,0x00 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...1...1...0 */
+ { 0xa0,0x80,0x20,0x00 }, { 0xa0,0x80,0xa8,0x88 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+sega_315_5048_device::sega_315_5048_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5048, tag, owner, clock) {}
+sega_315_5048_device::sega_315_5048_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, type, tag, owner, clock) {}
+void sega_315_5048_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0xa8,0x80,0x88 }, /* ...0...0...0...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...0...0...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x88,0x08,0x80,0x00 }, /* ...0...0...1...0 */
+ { 0xa0,0xa8,0x80,0x88 }, { 0x88,0x08,0x80,0x00 }, /* ...0...0...1...1 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0xa0,0xa8,0x80,0x88 }, /* ...0...1...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...1...0...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0xa0,0xa8,0x80,0x88 }, /* ...0...1...1...0 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0xa0,0xa8,0x80,0x88 }, /* ...0...1...1...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...0...0...0 */
+ { 0xa0,0x20,0x80,0x00 }, { 0x88,0xa8,0x80,0xa0 }, /* ...1...0...0...1 */
+ { 0xa0,0x20,0x80,0x00 }, { 0xa0,0x20,0x80,0x00 }, /* ...1...0...1...0 */
+ { 0xa0,0x20,0x80,0x00 }, { 0xa0,0x20,0x80,0x00 }, /* ...1...0...1...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...1...0...1 */
+ { 0xa0,0xa8,0x80,0x88 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...1...0 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0xa0,0xa8,0x80,0x88 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5093_device::sega_315_5093_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5093, tag, owner, clock) {}
+void sega_315_5093_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...0...0 */
+ { 0x08,0x88,0x28,0xa8 }, { 0x28,0xa8,0x20,0xa0 }, /* ...0...0...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...1...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0xa8,0x20,0x28 }, /* ...0...0...1...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x20,0x00,0xa0,0x80 }, /* ...0...1...0...0 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0x20,0x00,0xa0,0x80 }, /* ...0...1...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0xa8,0x20,0x28 }, /* ...0...1...1...0 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0xa0,0xa8,0x20,0x28 }, /* ...0...1...1...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0x80,0x88,0xa0,0xa8 }, /* ...1...0...0...0 */
+ { 0x80,0x88,0xa0,0xa8 }, { 0x80,0x88,0xa0,0xa8 }, /* ...1...0...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...0...1...0 */
+ { 0x80,0x88,0xa0,0xa8 }, { 0x28,0xa8,0x20,0xa0 }, /* ...1...0...1...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0x80,0x88,0xa0,0xa8 }, /* ...1...1...0...0 */
+ { 0x80,0x88,0xa0,0xa8 }, { 0x20,0x00,0xa0,0x80 }, /* ...1...1...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...1...1...0 */
+ { 0x80,0x88,0xa0,0xa8 }, { 0x28,0xa8,0x20,0xa0 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+sega_315_5099_device::sega_315_5099_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5099, tag, owner, clock) {}
+void sega_315_5099_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x80,0xa0,0x00,0x20 }, /* ...0...0...0...0 */
+ { 0x20,0x28,0x00,0x08 }, { 0x20,0x28,0x00,0x08 }, /* ...0...0...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x08,0x28,0x00,0x20 }, /* ...0...0...1...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x88,0x08,0xa8,0x28 }, /* ...0...0...1...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x20,0x28,0x00,0x08 }, /* ...0...1...0...0 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0x20,0x28,0x00,0x08 }, /* ...0...1...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x08,0x28,0x00,0x20 }, /* ...0...1...1...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x88,0x08,0xa8,0x28 }, /* ...0...1...1...1 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0xa0,0xa8,0x20,0x28 }, /* ...1...0...0...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...0...0...1 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0x08,0x28,0x00,0x20 }, /* ...1...0...1...0 */
+ { 0x28,0xa8,0x20,0xa0 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...0...1...1 */
+ { 0x20,0x28,0x00,0x08 }, { 0x20,0x28,0x00,0x08 }, /* ...1...1...0...0 */
+ { 0x88,0x08,0xa8,0x28 }, { 0x20,0x28,0x00,0x08 }, /* ...1...1...0...1 */
+ { 0x08,0x28,0x00,0x20 }, { 0x80,0xa0,0x00,0x20 }, /* ...1...1...1...0 */
+ { 0x08,0x28,0x00,0x20 }, { 0x88,0x08,0xa8,0x28 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+
+sega_315_5006_device::sega_315_5006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5006, tag, owner, clock) {}
+sega_315_5006_device::sega_315_5006_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, type, tag, owner, clock) {}
+void sega_315_5006_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0x08,0x80,0x00 }, { 0x00,0x08,0x20,0x28 }, /* ...0...0...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...0...0...1 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...0...1...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x88,0x08,0x80,0x00 }, /* ...0...0...1...1 */
+ { 0x00,0x08,0x20,0x28 }, { 0x88,0x08,0x80,0x00 }, /* ...0...1...0...0 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x80,0x88,0x00,0x08 }, /* ...0...1...0...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...1...1...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...1...1...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x80,0x88,0x00,0x08 }, /* ...1...0...0...0 */
+ { 0x80,0x88,0x00,0x08 }, { 0x00,0x08,0x20,0x28 }, /* ...1...0...0...1 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0x28,0xa8,0x08,0x88 }, /* ...1...0...1...0 */
+ { 0x00,0x08,0x20,0x28 }, { 0x80,0xa0,0x88,0xa8 }, /* ...1...0...1...1 */
+ { 0x80,0x88,0x00,0x08 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...0...0 */
+ { 0x80,0xa0,0x88,0xa8 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...0...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x80,0xa0,0x88,0xa8 }, /* ...1...1...1...0 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0x00,0x08,0x20,0x28 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+sega_315_5096_device::sega_315_5096_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : sega_315_5006_device(mconfig, SEGA_315_5096, tag, owner, clock) {}
+// == sega_315_5006_device
+
+sega_315_5111_device::sega_315_5111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : sega_315_5006_device(mconfig, SEGA_315_5111, tag, owner, clock) {}
+// == sega_315_5006_device
+
+sega_315_5015_device::sega_315_5015_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5015, tag, owner, clock) {}
+void sega_315_5015_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x20,0x00,0xa0,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...0...0...0 */
+ { 0x20,0x00,0xa0,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...0...0...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...0...1...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...1...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...1...0...0 */
+ { 0x20,0x00,0xa0,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...1...0...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...1...1...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...1...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...0...0...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...0...0...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...0...1...0 */
+ { 0x20,0x00,0xa0,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...0...1...1 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...1...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...0...1 */
+ { 0x20,0x00,0xa0,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...1...1...0 */
+ { 0x88,0x08,0x80,0x00 }, { 0xa0,0x80,0xa8,0x88 } /* ...1...1...1...1 */
+ };
+
+ /* decrypt program ROMs */
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5133_device::sega_315_5133_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : sega_315_5048_device(mconfig, SEGA_315_5133, tag, owner, clock) {}
+// == sega_315_5048_device
+
+
+sega_315_5014_device::sega_315_5014_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5014, tag, owner, clock) {}
+void sega_315_5014_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x80,0x00,0x88,0x08 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...0...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...0...0...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...0...1...0 */
+ { 0x80,0x00,0x88,0x08 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...0...1...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...1...0...0 */
+ { 0x80,0x00,0x88,0x08 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...1...0...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...1...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...1...1...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...0...0...0 */
+ { 0x80,0x00,0x88,0x08 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...0...0...1 */
+ { 0x80,0x00,0x88,0x08 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...0...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...0...1...1 */
+ { 0x80,0x00,0x88,0x08 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...1...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...0...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...1...1...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa8,0xa0,0x88,0x80 } /* ...1...1...1...1 */
+ };
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+sega_315_5013_device::sega_315_5013_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5013, tag, owner, clock) {}
+void sega_315_5013_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...0...0...0 */
+ { 0x08,0x28,0x88,0xa8 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...0...1 */
+ { 0xa8,0x28,0xa0,0x20 }, { 0x20,0xa0,0x00,0x80 }, /* ...0...0...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...0...1...1 */
+ { 0x08,0x28,0x88,0xa8 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...1...0...1 */
+ { 0xa8,0x28,0xa0,0x20 }, { 0x20,0xa0,0x00,0x80 }, /* ...0...1...1...0 */
+ { 0x08,0x28,0x88,0xa8 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...1...1 */
+ { 0x08,0x28,0x88,0xa8 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...0...0...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...0...1...0 */
+ { 0xa8,0x28,0xa0,0x20 }, { 0x20,0xa0,0x00,0x80 }, /* ...1...0...1...1 */
+ { 0xa8,0x28,0xa0,0x20 }, { 0x20,0xa0,0x00,0x80 }, /* ...1...1...0...0 */
+ { 0xa8,0x28,0xa0,0x20 }, { 0x20,0xa0,0x00,0x80 }, /* ...1...1...0...1 */
+ { 0x08,0x28,0x88,0xa8 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x28,0x20,0xa8,0xa0 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5061_device::sega_315_5061_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5061, tag, owner, clock) {}
+void sega_315_5061_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x28,0x08,0x20,0x00 }, { 0x28,0x08,0x20,0x00 }, /* ...0...0...0...0 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x08,0x88,0x00,0x80 }, /* ...0...0...0...1 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x08,0x88,0x00,0x80 }, /* ...0...0...1...0 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x20,0x28,0xa0,0xa8 }, /* ...0...0...1...1 */
+ { 0x28,0x08,0x20,0x00 }, { 0x88,0x80,0xa8,0xa0 }, /* ...0...1...0...0 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x08,0x88,0x00,0x80 }, /* ...0...1...0...1 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x20,0x28,0xa0,0xa8 }, /* ...0...1...1...0 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x08,0x88,0x00,0x80 }, /* ...0...1...1...1 */
+ { 0x88,0x80,0xa8,0xa0 }, { 0x28,0x08,0x20,0x00 }, /* ...1...0...0...0 */
+ { 0x80,0x00,0xa0,0x20 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...0...0...1 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0x08,0x88,0x00,0x80 }, /* ...1...0...1...0 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x20,0x28,0xa0,0xa8 }, /* ...1...0...1...1 */
+ { 0x88,0x80,0xa8,0xa0 }, { 0x88,0x80,0xa8,0xa0 }, /* ...1...1...0...0 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x08,0x88,0x00,0x80 }, /* ...1...1...0...1 */
+ { 0x80,0x00,0xa0,0x20 }, { 0x28,0x08,0x20,0x00 }, /* ...1...1...1...0 */
+ { 0x20,0x28,0xa0,0xa8 }, { 0xa0,0x80,0x20,0x00 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+sega_315_5018_device::sega_315_5018_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5018, tag, owner, clock) {}
+void sega_315_5018_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x88,0xa8,0x08,0x28 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...0...0...0 */
+ { 0x20,0xa0,0x28,0xa8 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...0...0...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...0...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x20,0xa0,0x28,0xa8 }, /* ...0...0...1...1 */
+ { 0x88,0xa8,0x08,0x28 }, { 0x88,0xa8,0x08,0x28 }, /* ...0...1...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...1...0...1 */
+ { 0x20,0xa0,0x28,0xa8 }, { 0x20,0xa0,0x28,0xa8 }, /* ...0...1...1...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x88,0xa8,0x80,0xa0 }, /* ...0...1...1...1 */
+ { 0x20,0xa0,0x28,0xa8 }, { 0x88,0xa8,0x08,0x28 }, /* ...1...0...0...0 */
+ { 0x20,0xa0,0x28,0xa8 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...0...0...1 */
+ { 0xa0,0x20,0x80,0x00 }, { 0x20,0xa0,0x28,0xa8 }, /* ...1...0...1...0 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0x20,0xa0,0x28,0xa8 }, /* ...1...0...1...1 */
+ { 0x20,0xa0,0x28,0xa8 }, { 0x88,0xa8,0x08,0x28 }, /* ...1...1...0...0 */
+ { 0x88,0xa8,0x08,0x28 }, { 0x88,0xa8,0x08,0x28 }, /* ...1...1...0...1 */
+ { 0xa0,0x20,0x80,0x00 }, { 0x88,0x08,0x80,0x00 }, /* ...1...1...1...0 */
+ { 0x20,0xa0,0x28,0xa8 }, { 0x00,0x08,0x20,0x28 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+
+}
+
+
+sega_315_5010_device::sega_315_5010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5010, tag, owner, clock) {}
+void sega_315_5010_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0xa0,0x80,0xa8,0x88 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...0...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...0...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...0...1...0 */
+ { 0x08,0x28,0x88,0xa8 }, { 0xa0,0x80,0xa8,0x88 }, /* ...0...0...1...1 */
+ { 0x08,0x00,0x88,0x80 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...1...0...0 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x08,0x00,0x88,0x80 }, /* ...0...1...0...1 */
+ { 0xa0,0x80,0x20,0x00 }, { 0xa0,0x80,0x20,0x00 }, /* ...0...1...1...0 */
+ { 0xa0,0x80,0x20,0x00 }, { 0x00,0x08,0x20,0x28 }, /* ...0...1...1...1 */
+ { 0x88,0x80,0x08,0x00 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...0...0...0 */
+ { 0x88,0x80,0x08,0x00 }, { 0x00,0x08,0x20,0x28 }, /* ...1...0...0...1 */
+ { 0x08,0x28,0x88,0xa8 }, { 0x08,0x28,0x88,0xa8 }, /* ...1...0...1...0 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa0,0x80,0x20,0x00 }, /* ...1...0...1...1 */
+ { 0x08,0x00,0x88,0x80 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...0...0 */
+ { 0x00,0x08,0x20,0x28 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...0...1 */
+ { 0x08,0x28,0x88,0xa8 }, { 0x08,0x28,0x88,0xa8 }, /* ...1...1...1...0 */
+ { 0x08,0x00,0x88,0x80 }, { 0xa0,0x80,0x20,0x00 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+
+
+sega_315_5128_device::sega_315_5128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5128, tag, owner, clock) {}
+void sega_315_5128_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...0...0...0 */
+ { 0x28,0x08,0xa8,0x88 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...0...0...1 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0x28,0xa8,0x08,0x88 }, /* ...0...0...1...0 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...0...1...1 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0xa8,0xa0,0x88,0x80 }, /* ...0...1...0...0 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...1...0...1 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...1...1...0 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x28,0x20,0xa8,0xa0 }, /* ...0...1...1...1 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x28,0x20,0xa8,0xa0 }, /* ...1...0...0...0 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...0...0...1 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0xa0,0x80,0xa8,0x88 }, /* ...1...0...1...0 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...0...1...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...1...0...0 */
+ { 0x28,0x20,0xa8,0xa0 }, { 0xa8,0x28,0xa0,0x20 }, /* ...1...1...0...1 */
+ { 0xa0,0x80,0xa8,0x88 }, { 0xa8,0xa0,0x88,0x80 }, /* ...1...1...1...0 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0xa8,0x28,0xa0,0x20 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5028_device::sega_315_5028_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5028, tag, owner, clock) {}
+void sega_315_5028_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...0...0 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x00,0x20,0x80,0xa0 }, /* ...0...0...0...1 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x00,0x20,0x80,0xa0 }, /* ...0...0...1...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...0...1...1 */
+ { 0xa8,0x88,0xa0,0x80 }, { 0xa0,0x20,0xa8,0x28 }, /* ...0...1...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...0...1...0...1 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x00,0x20,0x80,0xa0 }, /* ...0...1...1...0 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x00,0x20,0x80,0xa0 }, /* ...0...1...1...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...0...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...1...0...0...1 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x00,0x20,0x80,0xa0 }, /* ...1...0...1...0 */
+ { 0xa8,0xa0,0x88,0x80 }, { 0x00,0x20,0x80,0xa0 }, /* ...1...0...1...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...0...0 */
+ { 0xa8,0x88,0xa0,0x80 }, { 0xa0,0x20,0xa8,0x28 }, /* ...1...1...0...1 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 }, /* ...1...1...1...0 */
+ { 0x28,0xa8,0x08,0x88 }, { 0x88,0x80,0x08,0x00 } /* ...1...1...1...1 */
+ };
+
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
+
+
+sega_315_5084_device::sega_315_5084_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : segacrpt_z80_device(mconfig, SEGA_315_5084, tag, owner, clock) {}
+void sega_315_5084_device::decrypt()
+{
+ static const uint8_t convtable[32][4] =
+ {
+ /* opcode data address */
+ /* A B C D A B C D */
+ { 0x28,0x08,0xa8,0x88 }, { 0xa0,0xa8,0x20,0x28 }, /* ...0...0...0...0 */
+ { 0x80,0x88,0xa0,0xa8 }, { 0xa0,0xa8,0x20,0x28 }, /* ...0...0...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x20,0xa0,0x00,0x80 }, /* ...0...0...1...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x80,0x88,0xa0,0xa8 }, /* ...0...0...1...1 */
+ { 0x08,0x88,0x00,0x80 }, { 0x08,0x88,0x00,0x80 }, /* ...0...1...0...0 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0x08,0x88,0x00,0x80 }, /* ...0...1...0...1 */
+ { 0x20,0xa0,0x00,0x80 }, { 0x20,0xa0,0x00,0x80 }, /* ...0...1...1...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0x08,0x88,0x00,0x80 }, /* ...0...1...1...1 */
+ { 0x88,0xa8,0x80,0xa0 }, { 0xa0,0xa8,0x20,0x28 }, /* ...1...0...0...0 */
+ { 0x80,0x88,0xa0,0xa8 }, { 0x80,0x88,0xa0,0xa8 }, /* ...1...0...0...1 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x20,0xa0,0x00,0x80 }, /* ...1...0...1...0 */
+ { 0xa0,0xa8,0x20,0x28 }, { 0x80,0x88,0xa0,0xa8 }, /* ...1...0...1...1 */
+ { 0x08,0x88,0x00,0x80 }, { 0x28,0x08,0xa8,0x88 }, /* ...1...1...0...0 */
+ { 0x08,0x88,0x00,0x80 }, { 0x80,0x88,0xa0,0xa8 }, /* ...1...1...0...1 */
+ { 0x28,0x08,0xa8,0x88 }, { 0x20,0xa0,0x00,0x80 }, /* ...1...1...1...0 */
+ { 0x80,0x88,0xa0,0xa8 }, { 0x08,0x88,0x00,0x80 } /* ...1...1...1...1 */
+ };
+ decode(m_region_ptr, m_decrypted_ptr, m_decode_size, convtable, m_numbanks, m_banksize);
+}
diff --git a/src/devices/machine/segacrpt_device.h b/src/devices/machine/segacrpt_device.h
new file mode 100644
index 00000000000..f47f4d3d3ca
--- /dev/null
+++ b/src/devices/machine/segacrpt_device.h
@@ -0,0 +1,294 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_MACHINE_SEGACRYPT_DEVICE_H
+#define MAME_MACHINE_SEGACRYPT_DEVICE_H
+
+#pragma once
+
+#include "cpu/z80/z80.h"
+
+
+// base class
+class segacrpt_z80_device : public z80_device
+{
+public:
+ void set_decrypted_tag(const char* decrypted_tag) { m_decrypted_tag = decrypted_tag; }
+ void set_size(int size) { m_decode_size = size; }
+ void set_numbanks(int numbanks) { m_numbanks = numbanks; }
+ void set_banksize(int banksize) { m_banksize = banksize; }
+
+ void set_decrypted_p(uint8_t* ptr);
+ void set_region_p(uint8_t* ptr);
+
+protected:
+ segacrpt_z80_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void decrypt() = 0;
+
+ const char* m_decrypted_tag = nullptr;
+ uint8_t* m_decrypted_ptr;
+ uint8_t* m_region_ptr;
+ int m_decode_size;
+ int m_numbanks;
+ int m_banksize;
+
+private:
+ bool m_decryption_done;
+};
+
+
+// actual encrypted CPUs
+class sega_315_5132_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5132_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5155_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5155_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5110_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5135_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5135_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5051_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5051_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5098_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5098_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5102_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5065_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5065_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+class sega_315_5064_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5064_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+class sega_315_5033_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5033_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5041_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5041_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5048_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5048_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+ sega_315_5048_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5093_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5093_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5099_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5099_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5006_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ sega_315_5006_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+ virtual void decrypt() override;
+};
+
+class sega_315_5096_device : public sega_315_5006_device
+{
+public:
+ sega_315_5096_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+};
+
+class sega_315_5111_device : public sega_315_5006_device
+{
+public:
+ sega_315_5111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+};
+
+class sega_315_5015_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5015_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+class sega_315_5133_device : public sega_315_5048_device
+{
+public:
+ sega_315_5133_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+};
+
+class sega_315_5014_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5014_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5013_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5013_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5061_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5061_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+
+class sega_315_5018_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5018_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5010_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+
+class sega_315_5128_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5128_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5028_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5028_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+class sega_315_5084_device : public segacrpt_z80_device
+{
+public:
+ sega_315_5084_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t);
+protected:
+ virtual void decrypt() override;
+};
+
+
+DECLARE_DEVICE_TYPE(SEGA_315_5132, sega_315_5132_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5155, sega_315_5155_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5110, sega_315_5110_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5135, sega_315_5135_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5051, sega_315_5051_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5098, sega_315_5098_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5102, sega_315_5102_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5065, sega_315_5065_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5064, sega_315_5064_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5033, sega_315_5033_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5041, sega_315_5041_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5048, sega_315_5048_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5093, sega_315_5093_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5099, sega_315_5099_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5006, sega_315_5006_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5096, sega_315_5096_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5111, sega_315_5111_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5015, sega_315_5015_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5133, sega_315_5133_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5014, sega_315_5014_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5013, sega_315_5013_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5061, sega_315_5061_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5018, sega_315_5018_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5010, sega_315_5010_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5128, sega_315_5128_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5028, sega_315_5028_device)
+DECLARE_DEVICE_TYPE(SEGA_315_5084, sega_315_5084_device)
+
+
+#endif // MAME_MACHINE_SEGACRYPT_DEVICE_H
diff --git a/src/devices/machine/sensorboard.cpp b/src/devices/machine/sensorboard.cpp
index 0a5767aef3e..5fa63885f1f 100644
--- a/src/devices/machine/sensorboard.cpp
+++ b/src/devices/machine/sensorboard.cpp
@@ -57,7 +57,7 @@ sensor state instead.
*/
#include "emu.h"
-#include "machine/sensorboard.h"
+#include "sensorboard.h"
DEFINE_DEVICE_TYPE(SENSORBOARD, sensorboard_device, "sensorboard", "Sensorboard")
@@ -69,17 +69,19 @@ DEFINE_DEVICE_TYPE(SENSORBOARD, sensorboard_device, "sensorboard", "Sensorboard"
sensorboard_device::sensorboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SENSORBOARD, tag, owner, clock),
device_nvram_interface(mconfig, *this),
- m_out_piece(*this, "piece_%c%u", 0U + 'a', 1U),
+ m_out_piece(*this, "piece_%c%u", unsigned('a'), 1U),
m_out_pui(*this, "piece_ui%u", 0U),
m_out_count(*this, "count_ui%u", 0U),
m_inp_rank(*this, "RANK.%u", 1),
m_inp_spawn(*this, "SPAWN"),
m_inp_ui(*this, "UI"),
m_inp_conf(*this, "CONF"),
- m_custom_init_cb(*this),
- m_custom_sensor_cb(*this),
- m_custom_spawn_cb(*this),
- m_custom_output_cb(*this)
+ m_clear_cb(*this),
+ m_init_cb(*this),
+ m_remove_cb(*this, 0),
+ m_sensor_cb(*this, 0),
+ m_spawn_cb(*this, 0),
+ m_output_cb(*this)
{
m_nvram_auto = false;
m_nosensors = false;
@@ -87,6 +89,7 @@ sensorboard_device::sensorboard_device(const machine_config &mconfig, const char
m_inductive = false;
m_ui_enabled = 7;
set_delay(attotime::never);
+ clear_cb().set(*this, FUNC(sensorboard_device::clear_board));
// set defaults for most common use case (aka chess)
set_size(8, 8);
@@ -101,21 +104,15 @@ sensorboard_device::sensorboard_device(const machine_config &mconfig, const char
void sensorboard_device::device_start()
{
- // resolve handlers
- m_custom_init_cb.resolve_safe();
- m_custom_sensor_cb.resolve_safe(0);
- m_custom_spawn_cb.resolve();
- m_custom_output_cb.resolve();
-
- if (m_custom_output_cb.isnull())
+ if (m_output_cb.isunset())
{
m_out_piece.resolve();
m_out_pui.resolve();
m_out_count.resolve();
}
- m_undotimer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sensorboard_device::undo_tick),this));
- m_sensortimer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sensorboard_device::sensor_off),this));
+ m_undotimer = timer_alloc(FUNC(sensorboard_device::undo_tick), this);
+ m_sensortimer = timer_alloc(FUNC(sensorboard_device::sensor_off), this);
cancel_sensor();
u16 wmask = ~((1 << m_width) - 1);
@@ -127,7 +124,7 @@ void sensorboard_device::device_start()
m_upointer = 0;
m_ufirst = 0;
m_ulast = 0;
- m_usize = ARRAY_LENGTH(m_history);
+ m_usize = std::size(m_history);
// register for savestates
save_item(NAME(m_nosensors));
@@ -157,7 +154,7 @@ void sensorboard_device::device_start()
save_item(NAME(m_sensordelay));
}
-void sensorboard_device::preset_chess(int state)
+void sensorboard_device::preset_chess(u8 data)
{
// set chessboard start position
@@ -196,8 +193,8 @@ void sensorboard_device::device_reset()
if (!nvram_on())
{
- clear_board();
- m_custom_init_cb(0);
+ m_clear_cb(0);
+ m_init_cb(0);
}
undo_reset();
refresh();
@@ -211,27 +208,29 @@ void sensorboard_device::device_reset()
void sensorboard_device::nvram_default()
{
- clear_board();
- m_custom_init_cb(1);
+ m_clear_cb(0);
+ m_init_cb(0);
}
-void sensorboard_device::nvram_read(emu_file &file)
+bool sensorboard_device::nvram_read(util::read_stream &file)
{
- file.read(m_curstate, sizeof(m_curstate));
+ auto const [err, actual] = read(file, m_curstate, sizeof(m_curstate));
+ return !err && (sizeof(m_curstate) == actual);
}
-void sensorboard_device::nvram_write(emu_file &file)
+bool sensorboard_device::nvram_write(util::write_stream &file)
{
// save last board position
- file.write(m_curstate, sizeof(m_curstate));
+ auto const [err, actual] = write(file, m_curstate, sizeof(m_curstate));
+ return !err;
}
-bool sensorboard_device::nvram_can_write()
+bool sensorboard_device::nvram_can_write() const
{
return nvram_on();
}
-bool sensorboard_device::nvram_on()
+bool sensorboard_device::nvram_on() const
{
return (m_inp_conf->read() & 3) ? bool(m_inp_conf->read() & 2) : m_nvram_auto;
}
@@ -317,20 +316,23 @@ u16 sensorboard_device::read_rank(u8 y, bool reverse)
void sensorboard_device::refresh()
{
- bool custom_out = !m_custom_output_cb.isnull();
+ if (machine().phase() < machine_phase::RESET)
+ return;
+
+ bool custom_out = !m_output_cb.isunset();
// output spawn icons
for (int i = 0; i < m_maxspawn; i++)
{
if (custom_out)
- m_custom_output_cb(i + 0x101, i + 1);
+ m_output_cb(i + 0x101, i + 1);
else
m_out_pui[i + 1] = i + 1;
}
// output hand piece
if (custom_out)
- m_custom_output_cb(0x100, m_hand);
+ m_output_cb(0x100, m_hand);
else
m_out_pui[0] = m_hand;
@@ -346,7 +348,7 @@ void sensorboard_device::refresh()
piece += m_maxid;
if (custom_out)
- m_custom_output_cb(pos, piece);
+ m_output_cb(pos, piece);
else
m_out_piece[x][y] = piece;
}
@@ -377,8 +379,8 @@ void sensorboard_device::refresh()
if (custom_out)
{
- m_custom_output_cb(0x200, c0);
- m_custom_output_cb(0x201, c1);
+ m_output_cb(0x200, c0);
+ m_output_cb(0x201, c1);
}
else
{
@@ -476,13 +478,15 @@ INPUT_CHANGED_MEMBER(sensorboard_device::sensor)
m_sensortimer->adjust(m_sensordelay);
}
+ bool drop = m_hand != 0;
+
// optional custom handling:
// return d0 = block drop piece
// return d1 = block pick up piece
- u8 custom = m_custom_sensor_cb(pos);
+ u8 custom = m_sensor_cb(pos);
// drop piece
- if (m_hand != 0)
+ if (drop)
{
if (~custom & 1)
drop_piece(x, y);
@@ -497,7 +501,7 @@ INPUT_CHANGED_MEMBER(sensorboard_device::sensor)
INPUT_CHANGED_MEMBER(sensorboard_device::ui_spawn)
{
- u8 pos = (newval) ? (u8)param : 32 - count_leading_zeros(m_inp_spawn->read());
+ u8 pos = (newval) ? (u8)param : 32 - count_leading_zeros_32(m_inp_spawn->read());
if (pos == 0 || pos > m_maxspawn)
return;
@@ -506,8 +510,8 @@ INPUT_CHANGED_MEMBER(sensorboard_device::ui_spawn)
m_handpos = -1;
// optional callback to change piece id
- if (!m_custom_spawn_cb.isnull())
- m_hand = m_custom_spawn_cb(pos);
+ if (!m_spawn_cb.isunset())
+ m_hand = m_spawn_cb(pos);
refresh();
}
@@ -518,7 +522,12 @@ INPUT_CHANGED_MEMBER(sensorboard_device::ui_hand)
return;
cancel_sensor();
- remove_hand();
+
+ // optional custom handling:
+ // return d0: block remove hand
+ if (~m_remove_cb() & 1)
+ remove_hand();
+
refresh();
}
@@ -597,17 +606,18 @@ INPUT_CHANGED_MEMBER(sensorboard_device::ui_init)
if (!newval)
return;
- u8 init = (u8)param;
+ u8 init = param ? 1 : 0;
cancel_sensor();
cancel_hand();
- clear_board();
+ u8 rotate = m_inp_ui->read() & 2;
+ m_clear_cb((init ^ 1) | rotate);
if (init)
- m_custom_init_cb(0);
+ m_init_cb(init | rotate);
// rotate pieces
- if (m_inp_ui->read() & 2)
+ if (rotate)
{
u8 tempstate[0x100];
for (int y = 0; y < m_height; y++)
@@ -644,6 +654,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<16 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x09) PORT_NAME("Sensor J1")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<16 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x0a) PORT_NAME("Sensor K1")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<16 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x0b) PORT_NAME("Sensor L1")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<16 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x0c) PORT_NAME("Sensor M1")
PORT_START("RANK.2")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<17 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x10) PORT_NAME("Sensor A2")
@@ -658,6 +669,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<17 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x19) PORT_NAME("Sensor J2")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<17 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x1a) PORT_NAME("Sensor K2")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<17 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x1b) PORT_NAME("Sensor L2")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<17 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x1c) PORT_NAME("Sensor M2")
PORT_START("RANK.3")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<18 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x20) PORT_NAME("Sensor A3")
@@ -672,6 +684,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<18 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x29) PORT_NAME("Sensor J3")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<18 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x2a) PORT_NAME("Sensor K3")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<18 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x2b) PORT_NAME("Sensor L3")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<18 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x2c) PORT_NAME("Sensor M3")
PORT_START("RANK.4")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<19 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x30) PORT_NAME("Sensor A4")
@@ -686,6 +699,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<19 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x39) PORT_NAME("Sensor J4")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<19 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x3a) PORT_NAME("Sensor K4")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<19 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x3b) PORT_NAME("Sensor L4")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<19 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x3c) PORT_NAME("Sensor M4")
PORT_START("RANK.5")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<20 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x40) PORT_NAME("Sensor A5")
@@ -700,6 +714,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<20 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x49) PORT_NAME("Sensor J5")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<20 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x4a) PORT_NAME("Sensor K5")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<20 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x4b) PORT_NAME("Sensor L5")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<20 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x4c) PORT_NAME("Sensor M5")
PORT_START("RANK.6")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<21 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x50) PORT_NAME("Sensor A6")
@@ -714,6 +729,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<21 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x59) PORT_NAME("Sensor J6")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<21 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x5a) PORT_NAME("Sensor K6")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<21 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x5b) PORT_NAME("Sensor L6")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<21 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x5c) PORT_NAME("Sensor M6")
PORT_START("RANK.7")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<22 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x60) PORT_NAME("Sensor A7")
@@ -728,6 +744,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<22 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x69) PORT_NAME("Sensor J7")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<22 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x6a) PORT_NAME("Sensor K7")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<22 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x6b) PORT_NAME("Sensor L7")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<22 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x6c) PORT_NAME("Sensor M7")
PORT_START("RANK.8")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<23 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x70) PORT_NAME("Sensor A8")
@@ -742,6 +759,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<23 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x79) PORT_NAME("Sensor J8")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<23 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x7a) PORT_NAME("Sensor K8")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<23 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x7b) PORT_NAME("Sensor L8")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<23 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x7c) PORT_NAME("Sensor M8")
PORT_START("RANK.9")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<24 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x80) PORT_NAME("Sensor A9")
@@ -756,6 +774,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<24 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x89) PORT_NAME("Sensor J9")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<24 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x8a) PORT_NAME("Sensor K9")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<24 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x8b) PORT_NAME("Sensor L9")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<24 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x8c) PORT_NAME("Sensor M9")
PORT_START("RANK.10")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<25 | 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x90) PORT_NAME("Sensor A10")
@@ -770,6 +789,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<25 | 1<<9, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x99) PORT_NAME("Sensor J10")
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<25 | 1<<10, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x9a) PORT_NAME("Sensor K10")
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<25 | 1<<11, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x9b) PORT_NAME("Sensor L10")
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("BS_CHECK", 1<<25 | 1<<12, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, sensor, 0x9c) PORT_NAME("Sensor M10")
PORT_START("SPAWN")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("SS_CHECK", 1<<0, EQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, ui_spawn, 1) PORT_NAME("Spawn Piece 1")
@@ -792,7 +812,7 @@ static INPUT_PORTS_START( sensorboard )
PORT_START("UI")
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("UI_CHECK", 1<<0, NOTEQUALS, 0) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_NAME("Modifier 2 / Force Sensor") // hold while clicking to force sensor (ignore piece)
PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("UI_CHECK", 1<<0, NOTEQUALS, 0) PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_NAME("Modifier 1 / Force Piece") // hold while clicking to force piece (ignore sensor)
- PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(sensorboard_device, check_sensor_busy) // check if any sensor is busy / pressed (read-only)
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_CUSTOM) PORT_CUSTOM_MEMBER(sensorboard_device, check_sensor_busy) // check if any sensor is busy / pressed (read-only)
PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("UI_CHECK", 1<<1, NOTEQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, ui_hand, 0) PORT_NAME("Remove Piece")
PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("UI_CHECK", 1<<1, NOTEQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, ui_undo, 0) PORT_NAME("Undo Buffer First")
PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CONDITION("UI_CHECK", 1<<1, NOTEQUALS, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, sensorboard_device, ui_undo, 1) PORT_NAME("Undo Buffer Previous")
diff --git a/src/devices/machine/sensorboard.h b/src/devices/machine/sensorboard.h
index 50b428c04b4..3d5596f0f82 100644
--- a/src/devices/machine/sensorboard.h
+++ b/src/devices/machine/sensorboard.h
@@ -16,7 +16,7 @@ class sensorboard_device : public device_t, public device_nvram_interface
public:
sensorboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
- enum sb_type
+ enum sb_type : u8
{
NOSENSORS = 0,
BUTTONS,
@@ -26,7 +26,7 @@ public:
// configuration helpers
sensorboard_device &set_type(sb_type type); // sensor type
- sensorboard_device &set_size(u8 width, u8 height) { m_width = width; m_height = height; return *this; } // board dimensions, max 12 * 10
+ sensorboard_device &set_size(u8 width, u8 height) { m_width = width; m_height = height; return *this; } // board dimensions, max 13 * 10
sensorboard_device &set_spawnpoints(u8 i) { m_maxspawn = i; m_maxid = i; return *this; } // number of piece spawnpoints, max 16
sensorboard_device &set_max_id(u8 i) { m_maxid = i; return *this; } // maximum piece id (if larger than set_spawnpoints)
sensorboard_device &set_delay(attotime delay) { m_sensordelay = delay; return *this; } // delay when activating a sensor (like PORT_IMPULSE), set to attotime::never to disable
@@ -34,12 +34,14 @@ public:
sensorboard_device &set_ui_enable(bool b) { if (!b) m_maxspawn = 0; m_ui_enabled = (b) ? 7 : 0; return *this; } // enable UI inputs
sensorboard_device &set_mod_enable(bool b) { if (b) m_ui_enabled |= 1; else m_ui_enabled &= ~1; return *this; } // enable modifier keys
- auto init_cb() { return m_custom_init_cb.bind(); } // for setting pieces starting position
- auto sensor_cb() { return m_custom_sensor_cb.bind(); } // x = offset & 0xf, y = offset >> 4 & 0xf
- auto spawn_cb() { return m_custom_spawn_cb.bind(); } // spawnpoint/piece = offset, retval = new piece id
- auto output_cb() { return m_custom_output_cb.bind(); } // pos = offset(A8 for ui/board, A9 for count), id = data
+ auto clear_cb() { return m_clear_cb.bind(); } // d0: 0 = internal clear, 1 = user presses clear, d1: rotate
+ auto init_cb() { return m_init_cb.bind(); } // for setting pieces starting position
+ auto remove_cb() { return m_remove_cb.bind(); } // user removes piece from hand
+ auto sensor_cb() { return m_sensor_cb.bind(); } // x = offset & 0xf, y = offset >> 4 & 0xf
+ auto spawn_cb() { return m_spawn_cb.bind(); } // spawnpoint/piece = offset, retval = new piece id
+ auto output_cb() { return m_output_cb.bind(); } // pos = offset(A8 for ui/board, A9 for count), id = data
- void preset_chess(int state); // init_cb() preset for chessboards
+ void preset_chess(u8 data = 0); // init_cb() preset for chessboards
// read sensors
u8 read_sensor(u8 x, u8 y);
@@ -51,7 +53,7 @@ public:
// handle board state
u8 read_piece(u8 x, u8 y) { return m_curstate[y * m_width + x]; }
void write_piece(u8 x, u8 y, u8 id) { m_curstate[y * m_width + x] = id; }
- void clear_board() { memset(m_curstate, 0, sizeof(m_curstate)); }
+ void clear_board(u8 data = 0) { memset(m_curstate, 0, sizeof(m_curstate)); } // default clear_cb()
void refresh();
void cancel_sensor();
@@ -59,6 +61,10 @@ public:
// handle pieces
void cancel_hand();
void remove_hand();
+ u8 get_hand() { return m_hand; }
+ void set_hand(u8 hand) { m_hand = hand; }
+ int get_handpos() { return m_handpos; }
+ void set_handpos(int pos) { m_handpos = pos; }
bool drop_piece(u8 x, u8 y);
bool pickup_piece(u8 x, u8 y);
@@ -85,9 +91,9 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
- virtual bool nvram_can_write() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+ virtual bool nvram_can_write() const override;
private:
output_finder<0x10, 0x10> m_out_piece;
@@ -98,10 +104,12 @@ private:
required_ioport m_inp_ui;
required_ioport m_inp_conf;
- devcb_write_line m_custom_init_cb;
- devcb_read8 m_custom_sensor_cb;
- devcb_read8 m_custom_spawn_cb;
- devcb_write16 m_custom_output_cb;
+ devcb_write8 m_clear_cb;
+ devcb_write8 m_init_cb;
+ devcb_read8 m_remove_cb;
+ devcb_read8 m_sensor_cb;
+ devcb_read8 m_spawn_cb;
+ devcb_write16 m_output_cb;
bool m_nosensors;
bool m_magnets;
@@ -128,7 +136,7 @@ private:
u32 m_usize;
bool m_nvram_auto;
- bool nvram_on();
+ bool nvram_on() const;
emu_timer *m_undotimer;
TIMER_CALLBACK_MEMBER(undo_tick);
diff --git a/src/devices/machine/serflash.cpp b/src/devices/machine/serflash.cpp
deleted file mode 100644
index c616b4d34a7..00000000000
--- a/src/devices/machine/serflash.cpp
+++ /dev/null
@@ -1,473 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:David Haywood, Luca Elia
-/* Serial Flash Device */
-
-/* todo: cleanup, refactor etc. */
-/* ghosteo.c is similar? */
-
-#include "emu.h"
-#include "machine/serflash.h"
-
-#include <algorithm>
-
-ALLOW_SAVE_TYPE(serflash_device::flash_state_t);
-
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
-
-// device type definition
-DEFINE_DEVICE_TYPE(SERFLASH, serflash_device, "serflash", "Serial Flash")
-
-//-------------------------------------------------
-// serflash_device - constructor
-//-------------------------------------------------
-
-serflash_device::serflash_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, SERFLASH, tag, owner, clock)
- , device_nvram_interface(mconfig, *this)
- , m_length(0)
- , m_region(nullptr)
- , m_row_num(0)
- , m_flash_page_size(2048+64)
- , m_flash_state()
- , m_flash_enab(0)
- , m_flash_cmd_seq(0), m_flash_cmd_prev(0), m_flash_addr_seq(0), m_flash_read_seq(0)
- , m_flash_row(0), m_flash_col(0), m_flash_page_addr(0), m_flash_page_index(0), m_last_flash_cmd(0), m_flash_addr(0)
-{
-}
-
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void serflash_device::device_start()
-{
- m_length = machine().root_device().memregion(tag())->bytes();
- m_region = machine().root_device().memregion(tag())->base();
-
- m_row_num = m_length / m_flash_page_size;
-
- m_flashwritemap.resize(m_row_num);
- std::fill(m_flashwritemap.begin(), m_flashwritemap.end(), 0);
-
- m_flash_page_data.resize(m_flash_page_size);
-
- save_item(NAME(m_flash_state));
- save_item(NAME(m_flash_enab));
- save_item(NAME(m_flash_cmd_seq));
- save_item(NAME(m_flash_cmd_prev));
- save_item(NAME(m_flash_addr_seq));
- save_item(NAME(m_flash_read_seq));
- save_item(NAME(m_flash_row));
- save_item(NAME(m_flash_col));
- save_item(NAME(m_flash_page_addr));
- save_item(NAME(m_flash_page_index));
- save_item(NAME(m_flashwritemap));
- save_item(NAME(m_last_flash_cmd));
- save_item(NAME(m_flash_addr));
- save_item(NAME(m_flash_page_data));
-}
-
-void serflash_device::device_reset()
-{
- m_flash_enab = 0;
- flash_hard_reset();
-
- m_last_flash_cmd = 0x00;
- m_flash_addr_seq = 0;
- m_flash_addr = 0;
-
- m_flash_page_addr = 0;
-}
-
-//-------------------------------------------------
-// serflash_default - called to initialize SERFLASH to
-// its default state
-//-------------------------------------------------
-
-void serflash_device::nvram_default()
-{
-}
-
-
-//-------------------------------------------------
-// nvram_read - called to read SERFLASH from the
-// .nv file
-//-------------------------------------------------
-
-void serflash_device::nvram_read(emu_file &file)
-{
- if (m_length % m_flash_page_size) return; // region size must be multiple of flash page size
- int size = m_length / m_flash_page_size;
-
-
- if (file.is_open())
- {
- uint32_t page;
- file.read(&page, 4);
- while (page < size)
- {
- m_flashwritemap[page] = 1;
- file.read(m_region + page * m_flash_page_size, m_flash_page_size);
- file.read(&page, 4);
- }
- }
-
-}
-
-
-//-------------------------------------------------
-// nvram_write - called to write SERFLASH to the
-// .nv file
-//-------------------------------------------------
-
-void serflash_device::nvram_write(emu_file &file)
-{
- if (m_length % m_flash_page_size) return; // region size must be multiple of flash page size
- int size = m_length / m_flash_page_size;
-
- uint32_t page = 0;
- while (page < size)
- {
- if (m_flashwritemap[page])
- {
- file.write(&page, 4);
- file.write(m_region + page * m_flash_page_size, m_flash_page_size);
- }
- page++;
- }
- file.write(&page, 4);
-}
-
-void serflash_device::flash_hard_reset()
-{
-// logerror("%08x FLASH: RESET\n", cpuexec_describe_context(machine));
-
- m_flash_state = flash_state_t::READ;
-
- m_flash_cmd_prev = -1;
- m_flash_cmd_seq = 0;
-
- m_flash_addr_seq = 0;
- m_flash_read_seq = 0;
-
- m_flash_row = 0;
- m_flash_col = 0;
-
- std::fill(m_flash_page_data.begin(), m_flash_page_data.end(), 0);
- m_flash_page_addr = 0;
- m_flash_page_index = 0;
-}
-
-void serflash_device::flash_enab_w(uint8_t data)
-{
- //logerror("%08x FLASH: enab = %02X\n", m_maincpu->pc(), data);
- m_flash_enab = data;
-}
-
-void serflash_device::flash_change_state(flash_state_t state)
-{
- m_flash_state = state;
-
- m_flash_cmd_prev = -1;
- m_flash_cmd_seq = 0;
-
- m_flash_read_seq = 0;
- m_flash_addr_seq = 0;
-
- //logerror("flash_change_state - FLASH: state = %s\n", m_flash_state_name[state]);
-}
-
-void serflash_device::flash_cmd_w(uint8_t data)
-{
- if (!m_flash_enab)
- return;
-
- //logerror("%08x FLASH: cmd = %02X (prev = %02X)\n", m_maincpu->pc(), data, m_flash_cmd_prev);
-
- if (m_flash_cmd_prev == -1)
- {
- m_flash_cmd_prev = data;
-
- switch (data)
- {
- case 0x00: // READ
- m_flash_addr_seq = 0;
- break;
-
- case 0x60: // BLOCK ERASE
- m_flash_addr_seq = 2; // row address only
- break;
-
- case 0x70: // READ STATUS
- flash_change_state( flash_state_t::READ_STATUS );
- break;
-
- case 0x80: // PAGE / CACHE PROGRAM
- m_flash_addr_seq = 0;
- // this actually seems to be set with the next 2 writes?
- m_flash_page_addr = 0;
- break;
-
- case 0x90: // READ ID
- flash_change_state( flash_state_t::READ_ID );
- break;
-
- case 0xff: // RESET
- flash_change_state( flash_state_t::IDLE );
- break;
-
- default:
- {
- //logerror("%s FLASH: unknown cmd1 = %02X\n", machine().describe_context(), data);
- }
- }
- }
- else
- {
- switch (m_flash_cmd_prev)
- {
- case 0x00: // READ
- if (data == 0x30)
- {
- if (m_flash_row < m_row_num)
- {
- std::copy_n(&m_region[m_flash_row * m_flash_page_size], m_flash_page_size, m_flash_page_data.begin());
- m_flash_page_addr = m_flash_col;
- m_flash_page_index = m_flash_row;
- }
- flash_change_state( flash_state_t::READ );
-
- //logerror("%08x FLASH: caching page = %04X\n", m_maincpu->pc(), m_flash_row);
- }
- break;
-
- case 0x60: // BLOCK ERASE
- if (data==0xd0)
- {
- flash_change_state( flash_state_t::BLOCK_ERASE );
- if (m_flash_row < m_row_num)
- {
- m_flashwritemap[m_flash_row] |= 1;
- std::fill_n(&m_region[m_flash_row * m_flash_page_size], m_flash_page_size, 0xff);
- }
- //logerror("erased block %04x (%08x - %08x)\n", m_flash_col, m_flash_col * m_flash_page_size, ((m_flash_col+1) * m_flash_page_size)-1);
- }
- else
- {
- //logerror("unexpected 2nd command after BLOCK ERASE\n");
- }
- break;
- case 0x80:
- if (data==0x10)
- {
- flash_change_state( flash_state_t::PAGE_PROGRAM );
- if (m_flash_row < m_row_num)
- {
- m_flashwritemap[m_flash_row] |= (memcmp(m_region + m_flash_row * m_flash_page_size, &m_flash_page_data[0], m_flash_page_size) != 0);
- std::copy_n(m_flash_page_data.begin(), m_flash_page_size, &m_region[m_flash_row * m_flash_page_size]);
- }
- //logerror("re-written block %04x (%08x - %08x)\n", m_flash_row, m_flash_row * m_flash_page_size, ((m_flash_row+1) * m_flash_page_size)-1);
- }
- else
- {
- //logerror("unexpected 2nd command after SPAGE PROGRAM\n");
- }
- break;
-
-
- default:
- {
- //logerror("%08x FLASH: unknown cmd2 = %02X (cmd1 = %02X)\n", m_maincpu->pc(), data, m_flash_cmd_prev);
- }
- }
- }
-}
-
-void serflash_device::flash_data_w(uint8_t data)
-{
- if (!m_flash_enab)
- return;
-
- //logerror("flash data write %04x\n", m_flash_page_addr);
- if (m_flash_page_addr < m_flash_page_size)
- {
- m_flash_page_data[m_flash_page_addr] = data;
- }
- m_flash_page_addr++;
-}
-
-void serflash_device::flash_addr_w(uint8_t data)
-{
- if (!m_flash_enab)
- return;
-
- //logerror("%08x FLASH: addr = %02X (seq = %02X)\n", m_maincpu->pc(), data, m_flash_addr_seq);
-
- switch( m_flash_addr_seq++ )
- {
- case 0:
- m_flash_col = (m_flash_col & 0xff00) | data;
- break;
- case 1:
- m_flash_col = (m_flash_col & 0x00ff) | (data << 8);
- break;
- case 2:
- m_flash_row = (m_flash_row & 0xffff00) | data;
- if (m_row_num <= 256)
- {
- m_flash_addr_seq = 0;
- }
- break;
- case 3:
- m_flash_row = (m_flash_row & 0xff00ff) | (data << 8);
- if (m_row_num <= 65536)
- {
- m_flash_addr_seq = 0;
- }
- break;
- case 4:
- m_flash_row = (m_flash_row & 0x00ffff) | (data << 16);
- m_flash_addr_seq = 0;
- break;
- }
-}
-
-uint8_t serflash_device::flash_io_r()
-{
- uint8_t data = 0x00;
-// uint32_t old;
-
- if (!m_flash_enab)
- return 0xff;
-
- switch (m_flash_state)
- {
- case flash_state_t::READ_ID:
- //old = m_flash_read_seq;
-
- switch( m_flash_read_seq++ )
- {
- case 0:
- data = 0xEC; // Manufacturer
- break;
- case 1:
- data = 0xF1; // Device
- break;
- case 2:
- data = 0x00; // XX
- break;
- case 3:
- data = 0x15; // Flags
- m_flash_read_seq = 0;
- break;
- }
-
- //logerror("%08x FLASH: read %02X from id(%02X)\n", m_maincpu->pc(), data, old);
- break;
-
- case flash_state_t::READ:
- if (m_flash_page_addr > m_flash_page_size-1)
- m_flash_page_addr = m_flash_page_size-1;
-
- //old = m_flash_page_addr;
-
- data = m_flash_page_data[m_flash_page_addr++];
-
- //logerror("%08x FLASH: read data %02X from addr %03X (page %04X)\n", m_maincpu->pc(), data, old, m_flash_page_index);
- break;
-
- case flash_state_t::READ_STATUS:
- // bit 7 = writeable, bit 6 = ready, bit 5 = ready/true ready, bit 1 = fail(N-1), bit 0 = fail
- data = 0xe0;
- //logerror("%08x FLASH: read status %02X\n", m_maincpu->pc(), data);
- break;
-
- default:
- {
- // logerror("%08x FLASH: unknown read in state %s\n",0x00/*m_maincpu->pc()*/, m_flash_state_name[m_flash_state]);
- }
- }
-
- return data;
-}
-
-uint8_t serflash_device::flash_ready_r()
-{
- return 1;
-}
-
-
-
-uint8_t serflash_device::n3d_flash_r(offs_t offset)
-{
- if (m_last_flash_cmd==0x70) return 0xe0;
-
- if (m_last_flash_cmd==0x00)
- {
- uint8_t retdat = m_flash_page_data[m_flash_page_addr];
-
- //logerror("n3d_flash_r %02x %04x\n", offset, m_flash_page_addr);
-
- m_flash_page_addr++;
- return retdat;
- }
-
-
- logerror("n3d_flash_r %02x\n", offset);
- return 0x00;
-
-}
-
-
-void serflash_device::n3d_flash_cmd_w(offs_t offset, uint8_t data)
-{
- logerror("n3d_flash_cmd_w %02x %02x\n", offset, data);
- m_last_flash_cmd = data;
-
- if (data==0x00)
- {
- if (m_flash_addr < m_row_num)
- {
- std::copy_n(&m_region[m_flash_addr * m_flash_page_size], m_flash_page_size, m_flash_page_data.begin());
- }
- }
-}
-
-void serflash_device::n3d_flash_addr_w(offs_t offset, uint8_t data)
-{
-// logerror("n3d_flash_addr_w %02x %02x\n", offset, data);
-
- m_flash_addr_seq++;
-
- if (m_flash_addr_seq==3)
- {
- m_flash_addr = (m_flash_addr & 0xffff00) | data;
- if (m_row_num <= 256)
- {
- m_flash_addr_seq = 0;
- m_flash_page_addr = 0;
- logerror("set flash block to %08x\n", m_flash_addr);
- }
- }
- if (m_flash_addr_seq==4)
- {
- m_flash_addr = (m_flash_addr & 0xff00ff) | data << 8;
- if (m_row_num <= 65536)
- {
- m_flash_addr_seq = 0;
- m_flash_page_addr = 0;
- logerror("set flash block to %08x\n", m_flash_addr);
- }
- }
- if (m_flash_addr_seq==5)
- {
- m_flash_addr = (m_flash_addr & 0x00ffff) | data << 16;
- m_flash_addr_seq = 0;
- m_flash_page_addr = 0;
- logerror("set flash block to %08x\n", m_flash_addr);
- }
-}
diff --git a/src/devices/machine/serflash.h b/src/devices/machine/serflash.h
deleted file mode 100644
index 03181dec73a..00000000000
--- a/src/devices/machine/serflash.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:David Haywood, Luca Elia
-/* Serial Flash */
-
-#ifndef MAME_MACHINE_SERFLASH_H
-#define MAME_MACHINE_SERFLASH_H
-
-#pragma once
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-
-// ======================> serflash_device
-
-class serflash_device : public device_t, public device_nvram_interface
-{
-public:
- // custom initialization for default state
- typedef device_delegate<void (serflash_device &, void *, size_t)> init_delegate;
-
- // construction/destruction
- serflash_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- // configuration
- void set_flash_page_size(uint16_t size) { m_flash_page_size = size; }
-
- uint8_t flash_ready_r();
- uint8_t flash_io_r();
- void flash_addr_w(uint8_t data);
- void flash_data_w(uint8_t data);
- void flash_cmd_w(uint8_t data);
- void flash_enab_w(uint8_t data);
- void flash_hard_reset();
-
- uint8_t n3d_flash_r(offs_t offset);
- void n3d_flash_cmd_w(offs_t offset, uint8_t data);
- void n3d_flash_addr_w(offs_t offset, uint8_t data);
-
-protected:
- enum class flash_state_t : u8 { IDLE = 0, READ, READ_ID, READ_STATUS, BLOCK_ERASE, PAGE_PROGRAM };
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
- // device_nvram_interface overrides
- virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
-
- void flash_change_state(flash_state_t state);
-
- // runtime state
- size_t m_length;
- uint8_t* m_region;
-
- uint32_t m_row_num;
- uint16_t m_flash_page_size;
-
- flash_state_t m_flash_state;
-
- uint8_t m_flash_enab;
-
- uint8_t m_flash_cmd_seq;
- uint32_t m_flash_cmd_prev;
-
- uint8_t m_flash_addr_seq;
- uint8_t m_flash_read_seq;
-
- uint32_t m_flash_row;
- uint16_t m_flash_col;
- int m_flash_page_addr;
- uint32_t m_flash_page_index;
-
-
- std::vector<uint8_t> m_flashwritemap;
-
- uint8_t m_last_flash_cmd;
-
- uint32_t m_flash_addr;
-
- std::vector<uint8_t> m_flash_page_data;
-};
-
-
-// device type definition
-DECLARE_DEVICE_TYPE(SERFLASH, serflash_device)
-
-#endif // MAME_MACHINE_SERFLASH_H
diff --git a/src/devices/machine/sis5513_ide.cpp b/src/devices/machine/sis5513_ide.cpp
new file mode 100644
index 00000000000..f29c91fecf0
--- /dev/null
+++ b/src/devices/machine/sis5513_ide.cpp
@@ -0,0 +1,363 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ SiS 5513 IDE controller
+
+ TODO:
+ - Derive from common pci-ide.cpp interface
+ (what flavour that emulates tho? PCI regs 0x40-0x52 don't match)
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis5513_ide.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SIS5513_IDE, sis5513_ide_device, "sis5513_ide", "SiS 5513 IDE Controller")
+
+sis5513_ide_device::sis5513_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, SIS5513_IDE, tag, owner, clock)
+ , m_ide1(*this, "ide1")
+ , m_ide2(*this, "ide2")
+ , m_irq_pri_callback(*this)
+ , m_irq_sec_callback(*this)
+ , m_bus_master_space(*this, finder_base::DUMMY_TAG, AS_PROGRAM)
+{
+}
+
+void sis5513_ide_device::device_add_mconfig(machine_config &config)
+{
+ BUS_MASTER_IDE_CONTROLLER(config, m_ide1).options(ata_devices, "hdd", nullptr, false);
+ m_ide1->irq_handler().set([this](int state) { m_irq_pri_callback(state); });
+ m_ide1->set_bus_master_space(m_bus_master_space);
+
+ BUS_MASTER_IDE_CONTROLLER(config, m_ide2).options(ata_devices, "cdrom", nullptr, false);
+ m_ide2->irq_handler().set([this](int state) { m_irq_sec_callback(state); });
+ m_ide2->set_bus_master_space(m_bus_master_space);
+}
+
+void sis5513_ide_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+// map(0x10, 0x4f).unmaprw();
+ map(0x09, 0x09).w(FUNC(sis5513_ide_device::prog_if_w));
+ // base I/O relocation (effective only when native mode is on)
+// map(0x10, 0x13) Primary channel command base
+// map(0x14, 0x17) Primary channel control base
+// map(0x18, 0x1b) Secondary channel command base
+// map(0x1c, 0x1f) Secondary channel control base
+
+// map(0x20, 0x23) Bus master IDE control register base (0x10 I/O regs)
+ map(0x10, 0x23).rw(FUNC(sis5513_ide_device::bar_r), FUNC(sis5513_ide_device::bar_w));
+ map(0x24, 0x27).unmaprw();
+ map(0x40, 0x52).rw(FUNC(sis5513_ide_device::unmap_log_r), FUNC(sis5513_ide_device::unmap_log_w));
+ map(0x4a, 0x4a).rw(FUNC(sis5513_ide_device::ide_ctrl_0_r), FUNC(sis5513_ide_device::ide_ctrl_0_w));
+ map(0x52, 0x52).rw(FUNC(sis5513_ide_device::ide_misc_ctrl_r), FUNC(sis5513_ide_device::ide_misc_ctrl_w));
+
+
+// map(0x2c, 0x2f) subsystem ID (written once)
+
+// map(0x3c, 0x3d) interrupt line/pin
+
+// map(0x40, 0x40) IDE Primary channel master data recovery time
+// map(0x41, 0x41) IDE Primary channel master data active time (Ultra DMA)
+// map(0x42, 0x42) IDE Primary channel slave data recovery time
+// map(0x43, 0x43) IDE Primary channel slave data active time (Ultra DMA)
+// map(0x44, 0x47) ^ Same for IDE Secondary
+
+// map(0x48, 0x48) IDE status
+// map(0x4a, 0x4b) IDE general control regs
+
+// map(0x4c, 0x4d) prefetch count of primary channel
+// map(0x4e, 0x4f) prefetch count of secondary channel
+
+// map(0x52, 0x52) IDE misc control regs
+}
+
+#if 0
+void sis5513_ide_device::compatible_io_map(address_map &map)
+{
+ map(0x0170, 0x0177).rw(FUNC(sis5513_ide_device::ide2_read32_cs0_r), FUNC(sis5513_ide_device::ide2_write32_cs0_w));
+ map(0x01f0, 0x01f7).rw(FUNC(sis5513_ide_device::ide1_read32_cs0_r), FUNC(sis5513_ide_device::ide1_write32_cs0_w));
+ map(0x0376, 0x0376).rw(FUNC(sis5513_ide_device::ide2_read_cs1_r), FUNC(sis5513_ide_device::ide2_write_cs1_w));
+ map(0x03f6, 0x03f6).rw(FUNC(sis5513_ide_device::ide1_read_cs1_r), FUNC(sis5513_ide_device::ide1_write_cs1_w));
+}
+#endif
+
+// $1f0
+void sis5513_ide_device::ide1_command_map(address_map &map)
+{
+ map(0, 7).rw(FUNC(sis5513_ide_device::ide1_read32_cs0_r), FUNC(sis5513_ide_device::ide1_write32_cs0_w));
+}
+
+// $3f4
+void sis5513_ide_device::ide1_control_map(address_map &map)
+{
+ map(2, 2).rw(FUNC(sis5513_ide_device::ide1_read_cs1_r), FUNC(sis5513_ide_device::ide1_write_cs1_w));
+}
+
+// $170
+void sis5513_ide_device::ide2_command_map(address_map &map)
+{
+ map(0, 7).rw(FUNC(sis5513_ide_device::ide2_read32_cs0_r), FUNC(sis5513_ide_device::ide2_write32_cs0_w));
+}
+
+// $374
+void sis5513_ide_device::ide2_control_map(address_map &map)
+{
+ map(2, 2).rw(FUNC(sis5513_ide_device::ide2_read_cs1_r), FUNC(sis5513_ide_device::ide2_write_cs1_w));
+}
+
+void sis5513_ide_device::bus_master_ide_control_map(address_map &map)
+{
+ map(0x0, 0x7).rw(m_ide1, FUNC(bus_master_ide_controller_device::bmdma_r), FUNC(bus_master_ide_controller_device::bmdma_w));
+ map(0x8, 0xf).rw(m_ide2, FUNC(bus_master_ide_controller_device::bmdma_r), FUNC(bus_master_ide_controller_device::bmdma_w));
+}
+
+void sis5513_ide_device::device_start()
+{
+ pci_device::device_start();
+
+ add_map(8, M_IO, FUNC(sis5513_ide_device::ide1_command_map));
+ add_map(4, M_IO, FUNC(sis5513_ide_device::ide1_control_map));
+ add_map(8, M_IO, FUNC(sis5513_ide_device::ide2_command_map));
+ add_map(4, M_IO, FUNC(sis5513_ide_device::ide2_control_map));
+ add_map(16, M_IO, FUNC(sis5513_ide_device::bus_master_ide_control_map));
+}
+
+
+void sis5513_ide_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ command_mask = 5;
+ status = 0x0000;
+ pclass = 0x01018a;
+ m_ide_ctrl0 = 0;
+ m_ide_misc = 0;
+ m_bar[0] = 0x1f0;
+ m_bar[1] = 0x3f4;
+ m_bar[2] = 0x170;
+ m_bar[3] = 0x374;
+ m_bar[4] = 0xf00;
+ for (int i = 0; i < 5; i++)
+ bank_infos[i].adr = m_bar[i];
+ remap_cb();
+}
+
+inline bool sis5513_ide_device::ide1_mode()
+{
+ return (pclass & 0x3) == 3;
+}
+
+inline bool sis5513_ide_device::ide2_mode()
+{
+ return (pclass & 0xc) == 0xc;
+}
+
+// In compatible mode BARs with legacy addresses but can values written can still be readout.
+// In practice we need to override writes and make sure we flush remapping accordingly
+inline void sis5513_ide_device::flush_ide_mode()
+{
+ // Map Primary IDE Channel
+ if (ide1_mode())
+ {
+ // PCI Mode
+ pci_device::address_base_w(0, m_bar[0]);
+ pci_device::address_base_w(1, m_bar[1]);
+ }
+ else
+ {
+ // Legacy Mode
+ pci_device::address_base_w(0, 0x1f0);
+ pci_device::address_base_w(1, 0x3f4);
+ }
+
+ // Map Secondary IDE Channel
+ if (ide2_mode())
+ {
+ // PCI Mode
+ pci_device::address_base_w(2, m_bar[2]);
+ pci_device::address_base_w(3, m_bar[3]);
+ }
+ else
+ {
+ // Legacy Mode
+ pci_device::address_base_w(2, 0x170);
+ pci_device::address_base_w(3, 0x374);
+ }
+}
+
+void sis5513_ide_device::prog_if_w(u8 data)
+{
+ uint32_t oldVal = pclass;
+ pclass = (pclass & ~(0xff)) | (data & 0xff);
+ // Check for switch to/from compatibility (legacy) mode from/to pci mode
+ if ((oldVal ^ pclass) & 0xf)
+ flush_ide_mode();
+}
+
+u32 sis5513_ide_device::bar_r(offs_t offset)
+{
+ if (bank_reg_infos[offset].bank == -1)
+ return 0;
+ int bid = bank_reg_infos[offset].bank;
+ if (bank_reg_infos[offset].hi)
+ return bank_infos[bid].adr >> 32;
+ int flags = bank_infos[bid].flags;
+ return (m_bar[offset] & ~(bank_infos[bid].size - 1)) | (flags & M_IO ? 1 : 0) | (flags & M_64A ? 4 : 0) | (flags & M_PREF ? 8 : 0);
+}
+
+void sis5513_ide_device::bar_w(offs_t offset, u32 data)
+{
+ m_bar[offset] = data;
+ // Bits 0 (primary) and 2 (secondary) control if the mapping is legacy or BAR
+ switch (offset) {
+ case 0:
+ case 1:
+ if (ide1_mode())
+ pci_device::address_base_w(offset, data);
+ break;
+ case 2:
+ case 3:
+ if (ide2_mode())
+ pci_device::address_base_w(offset, data);
+ break;
+ default:
+ // Only the first 4 bars are controlled by pif
+ pci_device::address_base_w(offset, data);
+ }
+ logerror("Mapping bar[%i] = %08x\n", offset, data);
+}
+
+u8 sis5513_ide_device::ide_ctrl_0_r()
+{
+ LOGIO("IDE ctrl 0 read [$4a] %02x\n", m_ide_ctrl0);
+ return m_ide_ctrl0;
+}
+
+void sis5513_ide_device::ide_ctrl_0_w(u8 data)
+{
+ LOGIO("IDE ctrl 0 write [$4a] %02x\n", data);
+ m_ide_ctrl0 = data;
+ // TODO: bit 1 disables IDE ch. 0, bit 2 ch. 1
+// remap_cb();
+}
+
+u8 sis5513_ide_device::ide_misc_ctrl_r()
+{
+ LOGIO("IDE misc ctrl read [$52] %02x\n", m_ide_misc);
+ return m_ide_misc;
+}
+
+void sis5513_ide_device::ide_misc_ctrl_w(u8 data)
+{
+ LOGIO("IDE misc ctrl write [$52] %02x\n", data);
+ m_ide_misc = data;
+
+ const bool compatible_mode = BIT(m_ide_misc, 2);
+ pclass &= 0xffff85;
+
+ if (compatible_mode)
+ {
+ //LOGMAP("- Compatible Mode\n");
+ intr_pin = 0;
+ }
+ else
+ {
+ // Native Mode
+ pclass |= 0xa;
+ intr_pin = 1;
+ }
+
+ flush_ide_mode();
+}
+
+/*
+ * Debugging
+ */
+
+u8 sis5513_ide_device::unmap_log_r(offs_t offset)
+{
+ LOGTODO("IDE Unemulated [%02x] R\n", offset + 0x40);
+ return 0;
+}
+
+void sis5513_ide_device::unmap_log_w(offs_t offset, u8 data)
+{
+ LOGTODO("IDE Unemulated [%02x] %02x W\n", offset + 0x40, data);
+}
+
+/*
+ * Start of legacy handling, to be moved out
+ */
+
+uint32_t sis5513_ide_device::ide1_read32_cs0_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return 0xffffffff;
+ return m_ide1->read_cs0(offset, mem_mask);
+}
+
+void sis5513_ide_device::ide1_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return;
+ m_ide1->write_cs0(offset, data, mem_mask);
+}
+
+uint32_t sis5513_ide_device::ide2_read32_cs0_r(offs_t offset, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return 0xffffffff;
+ return m_ide2->read_cs0(offset, mem_mask);
+}
+
+void sis5513_ide_device::ide2_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ if (!(command & 1))
+ return;
+ m_ide2->write_cs0(offset, data, mem_mask);
+}
+
+uint8_t sis5513_ide_device::ide1_read_cs1_r()
+{
+ if (!(command & 1))
+ return 0xff;
+ return m_ide1->read_cs1(1, 0xff0000) >> 16;
+}
+
+void sis5513_ide_device::ide1_write_cs1_w(uint8_t data)
+{
+ if (!(command & 1))
+ return;
+ m_ide1->write_cs1(1, data << 16, 0xff0000);
+}
+
+uint8_t sis5513_ide_device::ide2_read_cs1_r()
+{
+ if (!(command & 1))
+ return 0xff;
+ return m_ide2->read_cs1(1, 0xff0000) >> 16;
+}
+
+void sis5513_ide_device::ide2_write_cs1_w(uint8_t data)
+{
+ if (!(command & 1))
+ return;
+ m_ide2->write_cs1(1, data << 16, 0xff0000);
+}
diff --git a/src/devices/machine/sis5513_ide.h b/src/devices/machine/sis5513_ide.h
new file mode 100644
index 00000000000..58a1ef0beb6
--- /dev/null
+++ b/src/devices/machine/sis5513_ide.h
@@ -0,0 +1,90 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS5513_IDE_H
+#define MAME_MACHINE_SIS5513_IDE_H
+
+#pragma once
+
+#include "pci.h"
+#include "idectrl.h"
+
+class sis5513_ide_device : public pci_device
+{
+public:
+ template <typename T> sis5513_ide_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&host_tag, uint32_t bmspace = AS_PROGRAM
+ ) : sis5513_ide_device(mconfig, tag, owner, clock)
+ {
+ // IDE controller with 0xd0 as programming i/f "ATA Host Adapters standard"
+ // pclass bits 1-3 are actually 1 when controller is in native mode
+ // pclass bits 0-2 can be r/w from $09
+ set_ids(0x10395513, 0xd0, 0x010180, 0x00);
+ m_bus_master_space.set_tag(host_tag, bmspace);
+ }
+ sis5513_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto irq_pri() { return m_irq_pri_callback.bind(); }
+ auto irq_sec() { return m_irq_sec_callback.bind(); }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+// virtual void reset_all_mappings() override;
+
+// virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+// uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+private:
+ required_device<bus_master_ide_controller_device> m_ide1;
+ required_device<bus_master_ide_controller_device> m_ide2;
+ devcb_write_line m_irq_pri_callback;
+ devcb_write_line m_irq_sec_callback;
+ required_address_space m_bus_master_space;
+
+ void ide1_command_map(address_map &map);
+ void ide1_control_map(address_map &map);
+ void ide2_command_map(address_map &map);
+ void ide2_control_map(address_map &map);
+ void bus_master_ide_control_map(address_map &map);
+
+ bool ide1_mode();
+ bool ide2_mode();
+
+ u32 bar_r(offs_t offset);
+ void bar_w(offs_t offset, u32 data);
+ u32 m_bar[5]{};
+
+ void prog_if_w(u8 data);
+ u8 ide_ctrl_0_r();
+ void ide_ctrl_0_w(u8 data);
+ u8 ide_misc_ctrl_r();
+ void ide_misc_ctrl_w(u8 data);
+
+ u8 m_ide_ctrl0 = 0;
+ u8 m_ide_misc = 0;
+
+ uint32_t ide1_read32_cs0_r(offs_t offset, uint32_t mem_mask = ~0);
+ void ide1_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint32_t ide2_read32_cs0_r(offs_t offset, uint32_t mem_mask = ~0);
+ void ide2_write32_cs0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint8_t ide1_read_cs1_r();
+ void ide1_write_cs1_w(uint8_t data);
+ uint8_t ide2_read_cs1_r();
+ void ide2_write_cs1_w(uint8_t data);
+
+// void compatible_io_map(address_map &map);
+ void flush_ide_mode();
+
+ u8 unmap_log_r(offs_t offset);
+ void unmap_log_w(offs_t offset, u8 data);
+};
+
+DECLARE_DEVICE_TYPE(SIS5513_IDE, sis5513_ide_device)
+
+#endif
diff --git a/src/devices/machine/sis630_gui.cpp b/src/devices/machine/sis630_gui.cpp
new file mode 100644
index 00000000000..e7696b54dd4
--- /dev/null
+++ b/src/devices/machine/sis630_gui.cpp
@@ -0,0 +1,327 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ SiS 630 Video GUI portion (SVGA-based) & 301 video bridge
+
+ - 630 core is SVGA based:
+ \- has two sets of extended CRTC ($3c4) regs;
+ \- a dedicated MPEG-2 video playback interface;
+ \- a digital video interface to 301;
+ - 301 draws to a separate monitor, and it was originally tied to a SiS300 AGP card,
+ (which we don't have a dump of at the time of this writing):
+ \- can select VGA, NTSC, PAL or LCD sources;
+ \- Has separate set of VGA and RAMDAC regs;
+ \- Has TV encoder;
+ \- Has macrovision regs;
+ - GUI is the 630 PCI/AGP i/f
+ \- it's actually internal to the rest of 630;
+ \- 301 is external but closely tied to it: the digital i/f ports (RIO+$4) selects where it
+ should start drawing/sync etc. while the "VGA2 regs" (RIO+$14) seems to be a custom set
+ rather than be related at all (i.e. it most likely be just capable to have VGA-like
+ resolutions).
+ - sis_main.c portions refers to the correlated Linux driver at
+ https://github.com/torvalds/linux/blob/master/drivers/video/fbdev/sis/sis_main.c
+
+ TODO:
+ - Backward port '630 GUI/PCI implementation to '300 and other flavours
+ (needs VGA mods to do this properly);
+ - 2d acceleration;
+ - Turbo queue stuff;
+ - AGP;
+ - xubuntu 6.10 splash screen is decentered (zooming?)
+ - xubuntu 6.10 splash screen text is unreadable or not visible depending on res selected;
+ - Interface with '301 bridge (a lovely can of worms);
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis630_gui.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+#define LOG_AGP (1U << 4) // log AGP
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_AGP)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+#define LOGAGP(...) LOGMASKED(LOG_AGP, __VA_ARGS__)
+
+/*****************************
+ *
+ * 630 GUI PCI implementation
+ *
+ ****************************/
+
+DEFINE_DEVICE_TYPE(SIS630_GUI, sis630_gui_device, "sis630_gui", "SiS 630 GUI")
+
+sis630_gui_device::sis630_gui_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, SIS630_GUI, tag, owner, clock)
+ , m_vga(*this, "svga")
+ , m_gui_rom(*this, "gui_rom")
+{
+ set_ids(0x10396300, 0x00, 0x030000, 0x00);
+}
+
+ROM_START( sis630gui )
+ ROM_REGION32_LE( 0xc000, "gui_rom", ROMREGION_ERASEFF )
+ // TODO: why the OEM ROM is 0xc000 in size?
+ // 0x8000-0xbfff mostly contains a charset, may be either programmable via a dedicated interface
+ // or the dump above is half size.
+ // gamecstl dump ver. 2.06.50
+ // (which actually writes to VRAM with the actual expansion ROM enabled, uh?)
+ ROM_SYSTEM_BIOS( 0, "2.06.50", "Ver. 2.06.50 OEM" )
+ ROMX_LOAD( "oemrom.bin", 0x0000, 0xc000, BAD_DUMP CRC(03d8df9d) SHA1(8fb80a2bf4067d9bebc90fb498448869ae795b2b), ROM_BIOS(0) )
+
+ // "SiS 630 (Ver. 2.02.1c) [AGP VGA] (Silicon Integrated Systems Corp.).bin"
+ ROM_SYSTEM_BIOS( 1, "2.02.1c", "Ver. 2.02.1c" )
+ ROMX_LOAD( "sis630.bin", 0x0000, 0x8000, BAD_DUMP CRC(f04ef9b0) SHA1(2396a79cd4045362bfc511090b146daa85902b4d), ROM_BIOS(1) )
+ROM_END
+
+const tiny_rom_entry *sis630_gui_device::device_rom_region() const
+{
+ return ROM_NAME(sis630gui);
+}
+
+void sis630_gui_device::device_add_mconfig(machine_config &config)
+{
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_raw(XTAL(25'174'800), 900, 0, 640, 526, 0, 480);
+ screen.set_screen_update(m_vga, FUNC(sis630_vga_device::screen_update));
+
+ SIS630_VGA(config, m_vga, 0);
+ m_vga->set_screen("screen");
+ // 64MB according to POST
+ // documentation claims 128MB, assume being wrong
+ m_vga->set_vram_size(64*1024*1024);
+}
+
+void sis630_gui_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+ map(0x2c, 0x2d).r(FUNC(sis630_gui_device::subvendor_r));
+ map(0x2e, 0x2f).r(FUNC(sis630_gui_device::subsystem_r));
+ map(0x2c, 0x2f).w(FUNC(sis630_gui_device::subvendor_w));
+
+// map(0x3c, 0x3d) irq line/pin
+
+ map(0x34, 0x34).r(FUNC(sis630_gui_device::capptr_r));
+
+ map(0x50, 0x53).r(FUNC(sis630_gui_device::agp_id_r));
+ map(0x54, 0x57).r(FUNC(sis630_gui_device::agp_status_r));
+ map(0x58, 0x5b).rw(FUNC(sis630_gui_device::agp_command_r), FUNC(sis630_gui_device::agp_command_w));
+ map(0x5c, 0x5c).lr8(NAME([] () { return 0; })); // NULL terminator
+}
+
+u8 sis630_gui_device::capptr_r()
+{
+ return 0x50;
+}
+
+// TODO: move to specific interface
+u32 sis630_gui_device::agp_id_r()
+{
+ LOGAGP("Read AGP ID [$50]\n");
+ // bits 23-16 AGP v1.0
+ // bits 15-8 0x5c NEXT_PTR (which goes to NULL terminator)
+ // bits 7-0 CAP_ID (0x02 for AGP)
+ return 0x00105c02;
+}
+
+u32 sis630_gui_device::agp_status_r()
+{
+ LOGAGP("Read AGP status [$54]\n");
+ // RQ (1 + 1), 2X and 1X capable
+ return 0x01000003;
+}
+
+u32 sis630_gui_device::agp_command_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGAGP("Read AGP command [$58] %d %d %08x\n", m_agp.enable, m_agp.data_rate, mem_mask);
+ // TODO: enable gets cleared by AGP_RESET, or even from PCI RST#
+ return m_agp.enable << 8 | (m_agp.data_rate & 7);
+}
+
+void sis630_gui_device::agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGAGP("Write AGP command [$c8] %08x & %08x\n", data, mem_mask);
+
+ if (ACCESSING_BITS_8_15)
+ {
+ m_agp.enable = bool(BIT(m_agp.enable, 8));
+ LOGAGP("- AGP_ENABLE = %d\n", m_agp.enable);
+ }
+
+ if (ACCESSING_BITS_0_7)
+ {
+ // quick checker, to be translated into an AGP interface
+ std::map<u8, std::string> agp_transfer_rates = {
+ { 0, "(illegal 0)" },
+ { 1, "1X" },
+ { 2, "2X" },
+ { 3, "(illegal 3)" }
+ };
+
+ // make sure the AGP DATA_RATE specs are honored
+ const u8 data_rate = data & 3;
+ LOGAGP("- DATA_RATE = %s enabled=%d\n", agp_transfer_rates.at(data_rate), m_agp.enable);
+ m_agp.data_rate = data_rate;
+ }
+}
+
+// TODO: may be common to PCI base interface, verify
+void sis630_gui_device::subvendor_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ // write once
+ if (m_subsystem_logger_mask & mem_mask)
+ {
+ LOG("Warning: subvendor ID possible rewrite! old=%08x & %08x data=%08x & %08x\n"
+ , subsystem_id
+ , m_subsystem_logger_mask
+ , data
+ , mem_mask
+ );
+ }
+ m_subsystem_logger_mask |= mem_mask;
+
+ COMBINE_DATA(&subsystem_id);
+ LOGIO("subsystem ID write [$2c] %08x & %08x (%08x)\n", data, mem_mask, subsystem_id);
+}
+
+void sis630_gui_device::memory_map(address_map &map)
+{
+ map(0x0000000, 0x3ffffff).rw(m_vga, FUNC(sis630_vga_device::mem_linear_r), FUNC(sis630_vga_device::mem_linear_w));
+}
+
+void sis630_gui_device::io_map(address_map &map)
+{
+
+}
+
+// "Relocate I/O" -> RIO
+void sis630_gui_device::space_io_map(address_map &map)
+{
+ // RIO + 0x00: video capture regs on '300, omitted or missing on '630
+ // RIO + 0x02: MPEG-2 video playback
+ // RIO + 0x04: digital video interface (to '301 only?)
+ // RIO + 0x10: 301 TV encoder
+ // RIO + 0x12: 301 macrovision regs
+ // RIO + 0x14: 301 VGA2 regs
+ // RIO + 0x16: 301 RAMDAC
+ // RIO + 0x30/+0x40/+0x50: omitted, legacy '300/'630 VGA regs?
+ // (gamecstl definitely tries to access 0x44 index 5 for readback extension ID)
+ map(0x30, 0x5f).m(m_vga, FUNC(sis630_vga_device::io_map));
+}
+
+void sis630_gui_device::legacy_memory_map(address_map &map)
+{
+ map(0xa0000, 0xbffff).rw(FUNC(sis630_gui_device::vram_r), FUNC(sis630_gui_device::vram_w));
+}
+
+void sis630_gui_device::legacy_io_map(address_map &map)
+{
+ map(0x03b0, 0x03df).m(m_vga, FUNC(sis630_vga_device::io_map));
+}
+
+void sis630_gui_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+
+}
+
+void sis630_gui_device::device_start()
+{
+ pci_device::device_start();
+
+ add_map(64*1024*1024, M_MEM, FUNC(sis630_gui_device::memory_map));
+ // claims 128KB, which goes outside the pentium range.
+ // Assume memory mapped, given the size should be yet another VGA memory compatible window.
+ add_map(128*1024, M_MEM, FUNC(sis630_gui_device::io_map));
+ add_map(128, M_IO, FUNC(sis630_gui_device::space_io_map));
+
+ add_rom((u8 *)m_gui_rom->base(), m_gui_rom->bytes());
+
+ // INTA#
+ intr_pin = 1;
+}
+
+void sis630_gui_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0004;
+ status = 0x0220;
+
+ m_subsystem_logger_mask = 0;
+}
+
+// TODO: remove these trampolines
+uint8_t sis630_gui_device::vram_r(offs_t offset)
+{
+ return downcast<sis630_vga_device *>(m_vga.target())->mem_r(offset);
+}
+
+void sis630_gui_device::vram_w(offs_t offset, uint8_t data)
+{
+ downcast<sis630_vga_device *>(m_vga.target())->mem_w(offset, data);
+}
+
+/*****************************
+ *
+ * 630 bridge PCI implementation
+ *
+ ****************************/
+
+DEFINE_DEVICE_TYPE(SIS630_BRIDGE, sis630_bridge_device, "sis630_bridge", "SiS 630 Virtual PCI-to-PCI bridge")
+
+sis630_bridge_device::sis630_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_bridge_device(mconfig, SIS630_BRIDGE, tag, owner, clock)
+ , m_vga(*this, finder_base::DUMMY_TAG)
+{
+
+}
+
+void sis630_bridge_device::map_extra(
+ uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space
+)
+{
+ // command extensions
+ // VGA control - forward legacy VGA addresses to AGP
+ // TODO: doc implies that is unaffected by base and limit?
+ if (BIT(bridge_control, 3))
+ {
+ memory_space->install_device(0, 0xfffff, *m_vga, &sis630_gui_device::legacy_memory_map);
+ io_space->install_device(0, 0x0fff, *m_vga, &sis630_gui_device::legacy_io_map);
+ }
+
+ // TODO: ISA control
+ // forward to "primary PCI" (host & LPC?) for A8 or A9 blocks for each 1KB blocks in I/O spaces,
+ // (i.e. $100-$3ff, $500-$7ff, $900-$bff etc.)
+ // even if I/O range is inside base and limits
+// if (BIT(bridge_control, 2))
+ // ...
+}
+
+void sis630_bridge_device::bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ pci_bridge_device::bridge_control_w(offset, data, mem_mask);
+ LOGMAP("- %s VGA control\n", bridge_control & 8 ? "Enable" : "Disable");
+ remap_cb();
+}
+
+void sis630_bridge_device::device_start()
+{
+ pci_bridge_device::device_start();
+}
+
+void sis630_bridge_device::device_reset()
+{
+ pci_bridge_device::device_reset();
+}
diff --git a/src/devices/machine/sis630_gui.h b/src/devices/machine/sis630_gui.h
new file mode 100644
index 00000000000..c8c9d5dde5e
--- /dev/null
+++ b/src/devices/machine/sis630_gui.h
@@ -0,0 +1,98 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS630_VGA_H
+#define MAME_MACHINE_SIS630_VGA_H
+
+#pragma once
+
+#include "pci.h"
+#include "video/pc_vga_sis.h"
+
+class sis630_gui_device : public pci_device
+{
+public:
+ sis630_gui_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void legacy_memory_map(address_map &map);
+ void legacy_io_map(address_map &map);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ virtual const tiny_rom_entry *device_rom_region() const override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void memory_map(address_map &map);
+ void io_map(address_map &map);
+ void space_io_map(address_map &map);
+
+private:
+ required_device<sis630_vga_device> m_vga;
+ required_memory_region m_gui_rom;
+
+ u8 vram_r(offs_t offset);
+ void vram_w(offs_t offset, uint8_t data);
+
+ void subvendor_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+
+ virtual u8 capptr_r() override;
+ u32 agp_id_r();
+ u32 agp_status_r();
+ u32 agp_command_r(offs_t offset, uint32_t mem_mask);
+ void agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+
+ struct {
+ bool enable = false;
+ u8 data_rate = 0;
+ } m_agp;
+
+ u32 m_subsystem_logger_mask = 0;
+
+ u8 unmap_log_r(offs_t offset);
+ void unmap_log_w(offs_t offset, u8 data);
+};
+
+DECLARE_DEVICE_TYPE(SIS630_GUI, sis630_gui_device)
+
+class sis630_bridge_device : public pci_bridge_device
+{
+public:
+ template <typename T> sis630_bridge_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&gui_tag
+ ) : sis630_bridge_device(mconfig, tag, owner, clock)
+ {
+ // either 0001 or 6001 as device ID
+ set_ids_bridge(0x10396001, 0x00);
+ //set_multifunction_device(true);
+ m_vga.set_tag(std::forward<T>(gui_tag));
+ }
+
+ sis630_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+private:
+ required_device<sis630_gui_device> m_vga;
+
+ virtual void bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) override;
+};
+
+DECLARE_DEVICE_TYPE(SIS630_BRIDGE, sis630_bridge_device)
+
+
+#endif
diff --git a/src/devices/machine/sis630_host.cpp b/src/devices/machine/sis630_host.cpp
new file mode 100644
index 00000000000..e5c9f897cde
--- /dev/null
+++ b/src/devices/machine/sis630_host.cpp
@@ -0,0 +1,440 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ SiS630 host implementation (northbridge)
+
+ TODO:
+ - AGP and VGA interfaces;
+ - Is ACPI declared here shared with LPC or a different one?
+ \- shutms11 maps it to the exact same place (I/O $5000), may be interleaved?
+ - HW trap control;
+ - PCI-Hole;
+ - Convert RAM to device;
+ - Integrated VGA control;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis630_host.h"
+
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+#define LOG_AGP (1U << 4) // log AGP
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_AGP)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+#define LOGAGP(...) LOGMASKED(LOG_AGP, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SIS630_HOST, sis630_host_device, "sis630_host", "SiS 630 Host-to-PCI Bridge")
+
+sis630_host_device::sis630_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_host_device(mconfig, SIS630_HOST, tag, owner, clock)
+ , m_host_cpu(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void sis630_host_device::device_start()
+{
+ pci_host_device::device_start();
+
+ memory_window_start = 0;
+ memory_window_end = 0xffffffff;
+ memory_offset = 0;
+ io_window_start = 0;
+ io_window_end = 0xffff;
+ io_offset = 0;
+
+ set_spaces(&m_host_cpu->space(AS_PROGRAM), &m_host_cpu->space(AS_IO));
+ add_map(8*1024*1024, M_MEM, FUNC(sis630_host_device::memory_map));
+
+ m_ram.resize(m_ram_size/4);
+}
+
+void sis630_host_device::device_reset()
+{
+ pci_host_device::device_reset();
+
+ command = 0x0005;
+ status = 0x0210;
+
+ m_shadow_ram_ctrl = 0;
+ m_vga_control = 0;
+ std::fill(std::begin(m_agp_mailbox), std::end(m_agp_mailbox), 0);
+
+ remap_cb();
+}
+
+void sis630_host_device::device_add_mconfig(machine_config &config)
+{
+
+}
+
+void sis630_host_device::config_map(address_map &map)
+{
+ pci_host_device::config_map(map);
+ // override header type, needed for actual IDE detection
+ map(0x0e, 0x0e).lr8(NAME([] () { return 0x80; }));
+
+ // override first BAR slot for gfx window base address
+ map(0x10, 0x13).rw(FUNC(pci_device::address_base_r), FUNC(pci_device::address_base_w));
+
+ map(0x34, 0x34).r(FUNC(sis630_host_device::capptr_r));
+
+ // host & DRAM regs
+// map(0x50, 0x51) host interface control
+// map(0x52, 0x53) DRAM misc control 1 & 2
+// map(0x54, 0x55) DRAM timing control 1 & 2
+// map(0x56, 0x56) DRAM misc control 3
+// map(0x57, 0x57) SDRAM/VCM init control
+// map(0x58, 0x58) DRAM buffer slew rating
+// map(0x59, 0x5a) DRAM buffer strength and current rating
+// map(0x5b, 0x5b) PCI buffer strength and current rating
+// map(0x60, 0x62) DRAMx type register (x = 0, 1 or 2)
+ map(0x63, 0x63).rw(FUNC(sis630_host_device::dram_status_r), FUNC(sis630_host_device::dram_status_w));
+// map(0x64, 0x64) FBC control register
+// map(0x65, 0x65) DIMM switch control
+// map(0x68, 0x69) ACPI I/O base
+ map(0x6a, 0x6a).rw(FUNC(sis630_host_device::smram_r), FUNC(sis630_host_device::smram_w));
+// map(0x6b, 0x6b) self refresh command output timing control
+// map(0x6c, 0x6c) power management DRAM self refresh control
+
+// Shadow RAM & PCI-Hole area
+ map(0x70, 0x73).rw(FUNC(sis630_host_device::shadow_ram_ctrl_r), FUNC(sis630_host_device::shadow_ram_ctrl_w));
+ map(0x77, 0x77).rw(FUNC(sis630_host_device::pci_hole_r), FUNC(sis630_host_device::pci_hole_w));
+// map(0x78, 0x79) PCI-Hole #1 allocation
+// map(0x7a, 0x7b) PCI-Hole #2 allocation
+
+// HW Trap control
+// map(0x7c, 0x7c) VGA
+// map(0x7d, 0x7d) Southbridge
+// map(0x7e, 0x7f) Northbridge
+
+// Host Bridge & PCI arbiter characteristics
+// map(0x80, 0x80) Target bridge DRAM characteristics
+// map(0x81, 0x81) PCI discard timer for delay transaction
+// map(0x82, 0x82) PCI target bridge bus characteristics
+// map(0x83, 0x83) CPU to PCI characteristics
+// map(0x84, 0x85) PCI grant timer
+// map(0x86, 0x86) CPU idle timer for PCI
+// map(0x87, 0x87) Host bridge & PCI master priority timer
+// map(0x88, 0x89) PCI discard timer for PCI hold
+
+// Clock Control
+// map(0x8c, 0x8c) SDRCLK/SDWCLK
+// map(0x8d, 0x8d) SDWCLK
+// map(0x8e, 0x8e) CPU & SDRAM clock relationship
+// map(0x8f, 0x8f) FBCRCLK/FBCWCLK control
+
+// GART and page table regs
+// map(0x90, 0x93) GART base address
+// map(0x94, 0x94) Graphic window control
+// map(0x97, 0x97) Page table cache control
+// map(0x98, 0x98) Page table cache invalidation control
+
+ // Integrated VGA control
+ map(0x9c, 0x9c).rw(FUNC(sis630_host_device::vga_control_r), FUNC(sis630_host_device::vga_control_w));
+
+// AGP
+// map(0xa0, 0xa3) DRAM priority timer control
+ map(0xa0, 0xa3).rw(FUNC(sis630_host_device::agp_priority_timer_r), FUNC(sis630_host_device::agp_priority_timer_w));
+// map(0xa4, 0xaf) General purpose register (generic mailboxes?)
+ map(0xa4, 0xaf).rw(FUNC(sis630_host_device::agp_mailbox_r), FUNC(sis630_host_device::agp_mailbox_w));
+// map(0xc0, 0xc3) AGP capability identifier
+ map(0xc0, 0xc3).r(FUNC(sis630_host_device::agp_id_r));
+ map(0xc4, 0xc7).r(FUNC(sis630_host_device::agp_status_r));
+ map(0xc8, 0xcb).rw(FUNC(sis630_host_device::agp_command_r), FUNC(sis630_host_device::agp_command_w));
+}
+
+// TODO: verify if we need these trampolines
+void sis630_host_device::memory_map(address_map &map)
+{
+}
+
+void sis630_host_device::map_shadowram(address_space *memory_space, uint32_t start_offs, uint32_t end_offs, bool read_enable, bool write_enable)
+{
+ LOGMAP("- 0x%08x-0x%08x ", start_offs, end_offs);
+
+ switch(write_enable << 1 | read_enable)
+ {
+ case 0:
+ LOGMAP("shadow RAM off\n");
+ //memory_space->unmap_write(start_offs, end_offs);
+ break;
+ case 1:
+ LOGMAP("shadow RAM r/o\n");
+ memory_space->install_rom(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ case 2:
+ LOGMAP("shadow RAM w/o\n");
+ //memory_space->install_rom(start_offs, end_offs, m_region->base() + bios_rom_offset);
+ memory_space->install_writeonly(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ case 3:
+ LOGMAP("shadow RAM r/w\n");
+ memory_space->install_ram(start_offs, end_offs, &m_ram[start_offs/4]);
+ break;
+ }
+}
+
+
+void sis630_host_device::map_extra(
+ uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space
+) {
+ io_space->install_device(0, 0xffff, *static_cast<pci_host_device *>(this), &pci_host_device::io_configuration_access_map);
+
+ regenerate_config_mapping();
+
+ memory_space->install_ram(0x00000000, 0x0009ffff, &m_ram[0x00000000/4]);
+// memory_space->install_ram(0x000a0000, 0x000bffff, &m_ram[0x000a0000/4]);
+
+ LOGMAP("Host Remapping table (shadow: %08x smram: %02x):\n", m_shadow_ram_ctrl, m_smram);
+
+ for (int i = 0; i < 12; i ++)
+ {
+ u32 start_offs = 0x000c0000 + i * 0x4000;
+ u32 end_offs = start_offs + 0x3fff;
+
+ map_shadowram(
+ memory_space,
+ start_offs, end_offs,
+ bool(BIT(m_shadow_ram_ctrl, i)), bool(BIT(m_shadow_ram_ctrl, i + 16))
+ );
+ }
+
+ map_shadowram(
+ memory_space,
+ 0xf0000, 0xfffff,
+ bool(BIT(m_shadow_ram_ctrl, 12)), bool(BIT(m_shadow_ram_ctrl, 28))
+ );
+
+ // System Management Memory Region handling
+ // Potentially overrides VGA VRAM if on
+ if (BIT(m_smram, 4))
+ {
+ u8 smram_config = m_smram >> 5;
+
+ // POST checks for config 6 only, other settings aren't tested
+ // TODO: setting 3 and 5 are undocumented, verify if mirror logic is correct
+ if (smram_config == 3 || smram_config == 5)
+ throw emu_fatalerror("SMRAM config = %d!", smram_config);
+
+ const u32 host_addresses[8] = {
+ 0xe0000, 0xb0000, 0xe0000, 0xb0000,
+ 0xe0000, 0xe0000, 0xa0000, 0xa0000
+ };
+ const u32 smram_sizes[8] = {
+ 0x07fff, 0xffff, 0x7fff, 0xffff,
+ 0x07fff, 0x7fff, 0xffff, 0x1ffff
+ };
+ const u32 system_memory_addresses[8] = {
+ 0xe0000, 0xb0000, 0xa0000, 0xb0000,
+ 0xb0000, 0xb0000, 0xa0000, 0xa0000
+ };
+ const u32 host_address_start = host_addresses[smram_config];
+ const u32 host_address_end = host_address_start + smram_sizes[smram_config];
+ const u32 system_memory_address = system_memory_addresses[smram_config];
+ LOGMAP("- SMRAM %02x relocation %08x-%08x to %08x\n"
+ , m_smram
+ , host_address_start
+ , host_address_end
+ , system_memory_address
+ );
+ memory_space->install_ram(host_address_start, host_address_end, &m_ram[system_memory_address/4]);
+ }
+
+ // TODO: shadow RAM bit 15?
+ // Always on after POST, should give shared access to PCI cards on the bus,
+ // BIOS mentions 8M of "shared memory", unknown how this works out.
+ // TODO: undocumented shadow RAM configs bits 7 and 23 after POST IDE check on shutms11 (programmer errors?)
+
+ memory_space->install_ram(0x00100000, m_ram_size - 1, &m_ram[0x00100000/4]);
+}
+
+
+
+
+
+/*
+ *
+ * I/O implemtation
+ *
+ */
+
+u8 sis630_host_device::capptr_r()
+{
+ LOGIO("Read capptr_r [$34]\n");
+ return 0xc0;
+}
+
+u8 sis630_host_device::dram_status_r()
+{
+ LOGIO("Read DRAM status [$63] (%02x)\n", m_dram_status);
+ return m_dram_status;
+}
+
+void sis630_host_device::dram_status_w(u8 data)
+{
+ LOGIO("Write DRAM status [$63] %02x\n", data);
+
+ m_dram_status = data;
+ // TODO: bit 7 is shared memory control
+}
+
+
+u8 sis630_host_device::smram_r()
+{
+ LOGIO("Read SMRAM [$6a] (%02x)\n", m_smram);
+ return m_smram;
+}
+
+void sis630_host_device::smram_w(u8 data)
+{
+ LOGIO("Write SMRAM [$6a] %02x\n", data);
+ m_smram = data;
+ remap_cb();
+}
+
+u32 sis630_host_device::shadow_ram_ctrl_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGIO("Read shadow RAM setting [$70] %08x (%08x)\n", mem_mask, m_shadow_ram_ctrl);
+ return m_shadow_ram_ctrl;
+}
+
+void sis630_host_device::shadow_ram_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_shadow_ram_ctrl);
+ LOGMAP("Write shadow RAM setting [$70] %08x & %08x (%08x)\n", data, mem_mask, m_shadow_ram_ctrl);
+ remap_cb();
+}
+
+u8 sis630_host_device::pci_hole_r()
+{
+ LOGIO("Read PCI hole [$77]\n");
+ return 0;
+}
+
+void sis630_host_device::pci_hole_w(u8 data)
+{
+ LOGIO("Write PCI hole [$77] %02x\n", data);
+ if (data)
+ LOG("Warning: PCI hole area enabled! %02x\n", data);
+}
+
+u8 sis630_host_device::vga_control_r()
+{
+ LOGIO("Read integrated VGA control data [$9c] %02x\n", m_vga_control);
+ return m_vga_control;
+}
+
+void sis630_host_device::vga_control_w(u8 data)
+{
+ LOGIO("Write integrated VGA control data [$9c] %02x\n", data);
+ // TODO: "integrated VGA control" (?)
+ m_vga_control = data;
+// remap_cb();
+}
+
+u32 sis630_host_device::agp_priority_timer_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGIO("Read AGP priority timer [$a0] %08x (%08x)\n", mem_mask, m_agp_priority_timer);
+ return m_agp_priority_timer;
+}
+
+void sis630_host_device::agp_priority_timer_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ COMBINE_DATA(&m_agp_priority_timer);
+ LOGIO("Write AGP priority timer [$a0] %08x & %08x (%08x)\n", data, mem_mask, m_agp_priority_timer);
+}
+
+u8 sis630_host_device::agp_mailbox_r(offs_t offset)
+{
+ LOGIO("Read AGP mailbox [$%02x] (%02x)\n", offset + 0xa4, m_agp_mailbox[offset]);
+ return m_agp_mailbox[offset];
+}
+
+void sis630_host_device::agp_mailbox_w(offs_t offset, u8 data)
+{
+ LOGIO("Write AGP mailbox [$%02x] %02x\n", offset + 0xa4, data);
+ m_agp_mailbox[offset] = data;
+}
+
+// TODO: move to generic interface
+u32 sis630_host_device::agp_id_r()
+{
+ LOGAGP("Read AGP ID [$c0]\n");
+ // bits 23-16 AGP v2.0
+ // bits 15-8 0x00 no NEXT_PTR (NULL terminates here)
+ // bits 7-0 CAP_ID (0x02 for AGP)
+ return 0x00200002;
+}
+
+u32 sis630_host_device::agp_status_r()
+{
+ LOGAGP("Read AGP status [$c4]\n");
+ // bits 31-24 RQ max number of AGP command requests (0x1f + 1 = 32)
+ // bit 9: SBA, side band addressing enabled
+ // ---- -xxx RATE
+ // ---- -1-- 4X transfer capable
+ // ---- --1- 2X transfer capable
+ // ---- ---1 1X transfer capable
+ // NB: documentation claims a RATE of 0x03 then contradicts with "111b" value, do the math
+ // It gets setup with a 4X at POST, assume 0x07 is right
+
+ // Stuff that isn't enabled here:
+ // bit 5: 4G support address greater than 4 GB
+ // bit 4: FW transfer support
+
+ return 0x1f000207;
+}
+
+u32 sis630_host_device::agp_command_r(offs_t offset, uint32_t mem_mask)
+{
+ LOGAGP("Read AGP command [$c8] %d %d %02x\n", m_agp.sba_enable, m_agp.enable, m_agp.data_rate);
+ // TODO: enable gets cleared by AGP_RESET, or even from PCI RST#
+ return m_agp.sba_enable << 9 | m_agp.enable << 8 | (m_agp.data_rate & 7);
+}
+
+void sis630_host_device::agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGAGP("Write AGP command [$c8] %08x & %08x\n", data, mem_mask);
+ if (ACCESSING_BITS_8_15)
+ {
+ m_agp.sba_enable = bool(BIT(m_agp.sba_enable, 9));
+ m_agp.enable = bool(BIT(m_agp.enable, 8));
+ LOGAGP("- SBA_ENABLE = %d AGP_ENABLE = %d\n", m_agp.sba_enable, m_agp.enable);
+ }
+
+ if (ACCESSING_BITS_0_7)
+ {
+ // quick checker, to be translated into an AGP interface
+ std::map<u8, std::string> agp_transfer_rates = {
+ { 0, "(illegal 0)" },
+ { 1, "1X" },
+ { 2, "2X" },
+ { 3, "(illegal 3)" },
+ { 4, "4X" },
+ { 5, "(illegal 5)" },
+ { 6, "(illegal 6)" },
+ { 7, "(illegal 7)" }
+ };
+
+ // make sure the AGP DATA_RATE specs are honored
+ const u8 data_rate = data & 7;
+ LOGAGP("- DATA_RATE = %s enabled=%d\n", agp_transfer_rates.at(data_rate), m_agp.enable);
+ m_agp.data_rate = data_rate;
+
+ // should probably never be enabled since it reads out from the ID
+ if (data & 0x30)
+ LOG("Warning: AGP unsupported i/f set 4G=%d FW_Enable=%d\n", bool(BIT(data, 5)), bool(BIT(data, 4)));
+ }
+}
diff --git a/src/devices/machine/sis630_host.h b/src/devices/machine/sis630_host.h
new file mode 100644
index 00000000000..46efc0ed803
--- /dev/null
+++ b/src/devices/machine/sis630_host.h
@@ -0,0 +1,98 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS630_HOST_H
+#define MAME_MACHINE_SIS630_HOST_H
+
+#pragma once
+
+#include "pci.h"
+#include "sis630_gui.h"
+
+class sis630_host_device : public pci_host_device
+{
+public:
+ template <typename T> sis630_host_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&cpu_tag, int ram_size
+ ) : sis630_host_device(mconfig, tag, owner, clock)
+ {
+ // Revision 1 -> A1
+ set_ids(0x10390630, 0x01, 0x060000, 0x00);
+ set_multifunction_device(true);
+ m_host_cpu.set_tag(std::forward<T>(cpu_tag));
+ set_ram_size(ram_size);
+ }
+
+ sis630_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ void set_ram_size(int ram_size) { m_ram_size = ram_size; }
+
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ virtual bool map_first() const override { return true; }
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void memory_map(address_map &map);
+
+private:
+ required_device<cpu_device> m_host_cpu;
+ std::vector<uint32_t> m_ram;
+
+ void map_shadowram(address_space *memory_space, offs_t start_offs, offs_t end_offs, bool read_enable, bool write_enable);
+
+ int m_ram_size = 0;
+ u8 m_dram_status = 0;
+ u32 m_shadow_ram_ctrl = 0;
+ u8 m_vga_control = 0;
+ u8 m_agp_mailbox[12]{};
+ u8 m_smram = 0;
+ u32 m_agp_priority_timer = 0;
+
+ u8 dram_status_r();
+ void dram_status_w(u8 data);
+
+ u8 pci_hole_r();
+ void pci_hole_w(u8 data);
+
+ u8 vga_control_r();
+ void vga_control_w(u8 data);
+
+ u32 shadow_ram_ctrl_r(offs_t offset, uint32_t mem_mask = ~0);
+ void shadow_ram_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+
+ u8 smram_r();
+ void smram_w(u8 data);
+
+ u32 agp_priority_timer_r(offs_t offset, uint32_t mem_mask = ~0);
+ void agp_priority_timer_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+
+ u8 agp_mailbox_r(offs_t offset);
+ void agp_mailbox_w(offs_t offset, u8 data);
+
+ virtual uint8_t capptr_r() override;
+ u32 agp_id_r();
+ u32 agp_status_r();
+ u32 agp_command_r(offs_t offset, uint32_t mem_mask);
+ void agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+
+ struct {
+ bool sba_enable = false;
+ bool enable = false;
+ u8 data_rate = 0;
+ } m_agp;
+};
+
+DECLARE_DEVICE_TYPE(SIS630_HOST, sis630_host_device)
+
+
+#endif
diff --git a/src/devices/machine/sis7001_usb.cpp b/src/devices/machine/sis7001_usb.cpp
new file mode 100644
index 00000000000..d1a81f205e1
--- /dev/null
+++ b/src/devices/machine/sis7001_usb.cpp
@@ -0,0 +1,93 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ SiS 7001 USB Host controller
+
+ TODO:
+ - Stub interface, to be merged with pci-usb;
+ - PCI values omitted from docs, assumes same as OpenHCI;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis7001_usb.h"
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SIS7001_USB, sis7001_usb_device, "sis7001_usb", "SiS 7001 USB Host Controller")
+
+sis7001_usb_device::sis7001_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, SIS7001_USB, tag, owner, clock)
+{
+
+}
+
+void sis7001_usb_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+ // no vendor regs?
+}
+
+void sis7001_usb_device::map(address_map &map)
+{
+ // HcRevision: operational mode
+ // 1 ---- ---- Legacy PS/2 present
+ // - 0001 0000 OpenHCI v1.0
+ map(0x000, 0x003).lr32(NAME([]() { return 0x00000110; }));
+ // ...
+ // HcFmInterval (Windows OSes fails if this isn't r/w)
+ map(0x034, 0x037).lrw32(
+ NAME([this]() { return m_HcFmInterval; } ),
+ NAME([this](offs_t offset, u32 data, u32 mem_mask) {
+ COMBINE_DATA(&m_HcFmInterval);
+ LOG("Write HcFmInterval %08x & %08x\n", data, mem_mask);
+ })
+ );
+ // ...
+ // HcRhDescriptorA
+ // 0000 0001 ---- ---- ---- ---- ---- ---- POTPGT 2 ms
+ // ---- ---- xxxx xxxx xxxx x-xx ---- ---- (writeable bits by host controller driver)
+ // ---- ---- ---- ---- ---- -0-- ---- ---- DT DeviceType (0) not a compound device
+ // ---- ---- ---- ---- ---- ---- xxxx xxxx NDP NumberDownstreamPorts (15 max)
+ map(0x048, 0x04b).lr32(NAME([this]() { return 0x01000000 | m_downstream_ports; }));
+ // ...
+// map(0x05c, 0x05f) HcRhPortStatus[3] last item for function 2 (3 ports), missing on function 3 (2)
+
+ // legacy support mode (8-bit each)
+// map(0x100, 0x100) [Hce]Control, bit 0 enables emulation mode
+// map(0x104, 0x104) [Hce]Input
+// map(0x108, 0x108) [Hce]Output
+// map(0x10c, 0x10f) [Hce]Status
+}
+
+void sis7001_usb_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+ // TODO: overrides I/O ports $0060-$0064 (emulation mode)
+}
+
+void sis7001_usb_device::device_start()
+{
+ pci_device::device_start();
+
+ // Docs don't mention it, should be 4KB
+ add_map(4096, M_MEM, FUNC(sis7001_usb_device::map));
+
+ // INTD#
+ intr_pin = 4;
+}
+
+
+void sis7001_usb_device::device_reset()
+{
+ pci_device::device_reset();
+
+ // TODO: unverified
+ command = 0x0000;
+ status = 0x0000;
+ m_HcFmInterval = 0x2edf;
+}
diff --git a/src/devices/machine/sis7001_usb.h b/src/devices/machine/sis7001_usb.h
new file mode 100644
index 00000000000..7dc1b97e123
--- /dev/null
+++ b/src/devices/machine/sis7001_usb.h
@@ -0,0 +1,50 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS7001_USB_H
+#define MAME_MACHINE_SIS7001_USB_H
+
+#pragma once
+
+#include "pci.h"
+
+class sis7001_usb_device : public pci_device
+{
+public:
+ sis7001_usb_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ int num_ports
+ ) : sis7001_usb_device(mconfig, tag, owner, clock)
+ {
+ // 0x0c0310 - Serial Bus Controller, USB, OpenHCI Host
+ // Assume no rev.
+ set_ids(0x10397001, 0x00, 0x0c0310, 0x00);
+ // TODO: should really read from a std::list interface
+ m_downstream_ports = num_ports;
+ }
+ sis7001_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ static constexpr feature_type unemulated_features() { return feature::MEDIA; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+// virtual void device_add_mconfig(machine_config &config) override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void map(address_map &map);
+
+private:
+ u8 m_downstream_ports;
+ u32 m_HcFmInterval = 0;
+};
+
+DECLARE_DEVICE_TYPE(SIS7001_USB, sis7001_usb_device)
+
+#endif
diff --git a/src/devices/machine/sis7018_audio.cpp b/src/devices/machine/sis7018_audio.cpp
new file mode 100644
index 00000000000..afcbfb13efd
--- /dev/null
+++ b/src/devices/machine/sis7018_audio.cpp
@@ -0,0 +1,163 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+SiS 7018 Audio device (AC97 complaint)
+
+TODO:
+- Stub interface, to be improved;
+- Reportedly based off Trident 4DWave technology, some registers effectively matches up;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis7018_audio.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+#define LOG_PMC (1U << 4) // log PMC access
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_PMC)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+#define LOGPMC(...) LOGMASKED(LOG_PMC, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SIS7018_AUDIO, sis7018_audio_device, "sis7018_audio", "SiS 7018 Audio AC97")
+
+sis7018_audio_device::sis7018_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, SIS7018_AUDIO, tag, owner, clock)
+ , m_joy(*this, "pc_joy")
+{
+ // 0x040100 - Multimedia device, audio device (vendor specific i/f)
+ // 0x01 - Rev 1
+ set_ids(0x10397018, 0x01, 0x040100, 0x00);
+}
+
+void sis7018_audio_device::device_add_mconfig(machine_config &config)
+{
+ PC_JOY(config, m_joy);
+ // ...
+}
+
+// NOTE: prefer using Trident naming if a register is there too.
+void sis7018_audio_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+
+ map(0x48, 0xe3).rw(FUNC(sis7018_audio_device::unmap_log_r), FUNC(sis7018_audio_device::unmap_log_w));
+
+ map(0x44, 0x44).lrw8(
+ NAME([this] (offs_t offset) {
+ return m_legacy_io_base;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ LOGIO("PCI $44: Legacy I/O base %02x\n", data);
+ m_legacy_io_base = data;
+ remap_cb();
+ })
+ );
+ // 0x45 Legacy DMA Decoding
+ // 0x46 PM_CFG Power Management Config (Legacy Control on Trident)
+
+ // PMC capability identifier
+ map(0xdc, 0xdf).r(FUNC(sis7018_audio_device::pmc_id_r));
+// map(0xe0, 0xe3).r(FUNC(sis7018_audio_device::pmc_status_r), FUNC(sis7018_audio_device::pmc_control_w));
+}
+
+u8 sis7018_audio_device::capptr_r()
+{
+ LOGIO("AUDIO Read capptr_r [$34]\n");
+ return 0xdc;
+}
+
+// TODO: move to specific interface
+u32 sis7018_audio_device::pmc_id_r()
+{
+ LOGPMC("Read PMC ID [$dc]\n");
+ // bits 31-16 PPMI v1.0, D1 / D2 supported, no PCI clock for PME#
+ // bits 15-8 0x00 no NEXT_PTR (NULL terminates here)
+ // bits 7-0 PM_CAP_ID (0x01 for PMC)
+ return 0xe6110001;
+}
+
+void sis7018_audio_device::memory_map(address_map &map)
+{
+
+}
+
+void sis7018_audio_device::io_map(address_map &map)
+{
+
+}
+
+void sis7018_audio_device::device_start()
+{
+ pci_device::device_start();
+ add_map(256, M_IO, FUNC(sis7018_audio_device::io_map));
+ // not explicitly stated, assume 4096 size from the MEM decoding
+ add_map(4096, M_MEM, FUNC(sis7018_audio_device::memory_map));
+
+ // TODO: PCI regs 0x3e/0x3f max_lat = 0x18, min_gnt = 0x02
+}
+
+
+void sis7018_audio_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ status = 0x0000;
+ // INTA#
+ intr_pin = 1;
+ // TODO: can be written to with $46=1
+ subsystem_id = 0x10397018;
+
+ m_legacy_io_base = 0xe2; // 0xf0 on Trident
+ remap_cb();
+}
+
+void sis7018_audio_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+ // if(BIT(m_legacy_io_base, 7))
+ // const u16 mpu401base_io_addr = 0x300 | (BIT(m_legacy_io_base, 6) ? 0x00 : 0x30);
+
+ if (BIT(m_legacy_io_base, 5))
+ {
+ const u16 gamebase_io_addr = 0x200 | (BIT(m_legacy_io_base, 4) << 3);
+ io_space->install_device(gamebase_io_addr, gamebase_io_addr | 0x7, *this, &sis7018_audio_device::gameport_map);
+ }
+
+ // if(BIT(m_legacy_io_base, 3))
+ // const u16 adlibbase_io_addr = 0x388 | (BIT(m_legacy_io_base, 2) << 2);
+
+ // if(BIT(m_legacy_io_base, 1))
+ // const u16 sbbase_io_addr = 0x200 | (BIT(m_legacy_io_base, 0) ? 0x20 : 0x40);
+}
+
+// 200h / 208h
+void sis7018_audio_device::gameport_map(address_map &map)
+{
+ map(0x00, 0x07).rw(m_joy, FUNC(pc_joy_device::joy_port_r), FUNC(pc_joy_device::joy_port_w));
+}
+
+/*
+ * Debugging
+ */
+
+u8 sis7018_audio_device::unmap_log_r(offs_t offset)
+{
+ LOGTODO("AUDIO Unemulated [%02x] R\n", offset + 0x48);
+ return 0;
+}
+
+void sis7018_audio_device::unmap_log_w(offs_t offset, u8 data)
+{
+ LOGTODO("AUDIO Unemulated [%02x] %02x W\n", offset + 0x48, data);
+}
diff --git a/src/devices/machine/sis7018_audio.h b/src/devices/machine/sis7018_audio.h
new file mode 100644
index 00000000000..5f50316015f
--- /dev/null
+++ b/src/devices/machine/sis7018_audio.h
@@ -0,0 +1,54 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS7018_AUDIO_H
+#define MAME_MACHINE_SIS7018_AUDIO_H
+
+#pragma once
+
+#include "pci.h"
+
+#include "bus/pc_joy/pc_joy.h"
+
+class sis7018_audio_device : public pci_device
+{
+public:
+ sis7018_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ static constexpr feature_type unemulated_features() { return feature::SOUND; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void memory_map(address_map &map);
+ void io_map(address_map &map);
+
+private:
+ required_device<pc_joy_device> m_joy;
+
+ virtual u8 capptr_r() override;
+
+ void gameport_map(address_map &map);
+
+ u32 pmc_id_r();
+// void pmc_status_r();
+// u32 pmc_control(offs_t offset, u32 data, u32 mem_mask = ~0);
+
+ u8 unmap_log_r(offs_t offset);
+ void unmap_log_w(offs_t offset, u8 data);
+
+ u8 m_legacy_io_base = 0;
+};
+
+DECLARE_DEVICE_TYPE(SIS7018_AUDIO, sis7018_audio_device)
+
+#endif
diff --git a/src/devices/machine/sis85c496.cpp b/src/devices/machine/sis85c496.cpp
index 1af083c24d9..572a003740e 100644
--- a/src/devices/machine/sis85c496.cpp
+++ b/src/devices/machine/sis85c496.cpp
@@ -14,17 +14,27 @@
#include "emu.h"
#include "sis85c496.h"
+
#include "bus/pc_kbd/keyboards.h"
#include "speaker.h"
-DEFINE_DEVICE_TYPE(SIS85C496, sis85c496_host_device, "sis85c496", "SiS 85C496/497 chipset")
+DEFINE_DEVICE_TYPE(SIS85C496_HOST, sis85c496_host_device, "sis85c496_host", "SiS 85C496/497 chipset")
void sis85c496_host_device::config_map(address_map &map)
{
pci_host_device::config_map(map);
map(0x40, 0x40).rw(FUNC(sis85c496_host_device::dram_config_r), FUNC(sis85c496_host_device::dram_config_w));
map(0x44, 0x45).rw(FUNC(sis85c496_host_device::shadow_config_r), FUNC(sis85c496_host_device::shadow_config_w));
+ map(0x48, 0x4f).lrw8(
+ NAME([this] (offs_t offset) { return m_dram_boundary[offset]; }),
+ NAME([this] (offs_t offset, u8 data) {
+ logerror("SiS496: DRAM boundary [%02x] set %02x\n", offset, data);
+ m_dram_boundary[offset] = data;
+ })
+ );
+ map(0x58, 0x59).rw(FUNC(sis85c496_host_device::ide_vesa_config_r), FUNC(sis85c496_host_device::ide_vesa_config_w));
map(0x5a, 0x5a).rw(FUNC(sis85c496_host_device::smram_ctrl_r), FUNC(sis85c496_host_device::smram_ctrl_w));
+ map(0xc0, 0xc3).rw(FUNC(sis85c496_host_device::pirqrc_r), FUNC(sis85c496_host_device::pirqrc_w));
map(0xc8, 0xcb).rw(FUNC(sis85c496_host_device::mailbox_r), FUNC(sis85c496_host_device::mailbox_w));
map(0xd0, 0xd0).rw(FUNC(sis85c496_host_device::bios_config_r), FUNC(sis85c496_host_device::bios_config_w));
map(0xd1, 0xd1).rw(FUNC(sis85c496_host_device::isa_decoder_r), FUNC(sis85c496_host_device::isa_decoder_w));
@@ -34,27 +44,21 @@ void sis85c496_host_device::internal_io_map(address_map &map)
{
pci_host_device::io_configuration_access_map(map);
map(0x0000, 0x001f).rw("dma8237_1", FUNC(am9517a_device::read), FUNC(am9517a_device::write));
- map(0x0020, 0x003f).rw("pic8259_master", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ map(0x0020, 0x0021).rw("pic8259_master", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+// map(0x0022, 0x0023) 85C497 super I/O
map(0x0040, 0x005f).rw("pit8254", FUNC(pit8254_device::read), FUNC(pit8254_device::write));
map(0x0060, 0x0063).rw(FUNC(sis85c496_host_device::at_keybc_r), FUNC(sis85c496_host_device::at_keybc_w));
map(0x0064, 0x0067).rw("keybc", FUNC(at_keyboard_controller_device::status_r), FUNC(at_keyboard_controller_device::command_w));
- map(0x0070, 0x007f).rw("rtc", FUNC(ds12885_device::read), FUNC(ds12885_device::write));
+ map(0x0070, 0x0070).lr8(NAME([this] () { return m_ds12885->get_address(); })).w(FUNC(sis85c496_host_device::rtc_address_nmi_w));
+ map(0x0071, 0x0071).rw("rtc", FUNC(ds12885_device::data_r), FUNC(ds12885_device::data_w));
map(0x0080, 0x009f).rw(FUNC(sis85c496_host_device::at_page8_r), FUNC(sis85c496_host_device::at_page8_w));
- map(0x00a0, 0x00bf).rw("pic8259_slave", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ map(0x00a0, 0x00a1).rw("pic8259_slave", FUNC(pic8259_device::read), FUNC(pic8259_device::write));
map(0x00c0, 0x00df).rw(FUNC(sis85c496_host_device::at_dma8237_2_r), FUNC(sis85c496_host_device::at_dma8237_2_w));
map(0x00e0, 0x00ef).noprw();
}
void sis85c496_host_device::device_add_mconfig(machine_config &config)
{
- PIT8254(config, m_pit8254, 0);
- m_pit8254->set_clk<0>(4772720/4); // heartbeat IRQ
- m_pit8254->out_handler<0>().set(FUNC(sis85c496_host_device::at_pit8254_out0_changed));
- m_pit8254->set_clk<1>(4772720/4); // DRAM refresh
- m_pit8254->out_handler<1>().set(FUNC(sis85c496_host_device::at_pit8254_out1_changed));
- m_pit8254->set_clk<2>(4772720/4); // PIO port C pin 4, and speaker polling enough
- m_pit8254->out_handler<2>().set(FUNC(sis85c496_host_device::at_pit8254_out2_changed));
-
AM9517A(config, m_dma8237_1, XTAL(14'318'181)/3);
m_dma8237_1->out_hreq_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq0_w));
m_dma8237_1->out_eop_callback().set(FUNC(sis85c496_host_device::at_dma8237_out_eop));
@@ -89,7 +93,7 @@ void sis85c496_host_device::device_add_mconfig(machine_config &config)
m_dma8237_2->out_dack_callback<3>().set(FUNC(sis85c496_host_device::pc_dack7_w));
PIC8259(config, m_pic8259_master, 0);
- m_pic8259_master->out_int_callback().set(FUNC(sis85c496_host_device::cpu_int_w));
+ m_pic8259_master->out_int_callback().set_inputline(m_maincpu, 0);
m_pic8259_master->in_sp_callback().set_constant(1);
m_pic8259_master->read_slave_ack_callback().set(FUNC(sis85c496_host_device::get_slave_ack));
@@ -97,22 +101,60 @@ void sis85c496_host_device::device_add_mconfig(machine_config &config)
m_pic8259_slave->out_int_callback().set(m_pic8259_master, FUNC(pic8259_device::ir2_w));
m_pic8259_slave->in_sp_callback().set_constant(0);
+ PIT8254(config, m_pit8254, 0);
+ m_pit8254->set_clk<0>(4772720/4); // heartbeat IRQ
+ m_pit8254->out_handler<0>().set(m_pic8259_master, FUNC(pic8259_device::ir0_w));
+ m_pit8254->set_clk<1>(4772720/4); // DRAM refresh
+ m_pit8254->out_handler<1>().set(FUNC(sis85c496_host_device::at_pit8254_out1_changed));
+ m_pit8254->set_clk<2>(4772720/4); // PIO port C pin 4, and speaker polling enough
+ m_pit8254->out_handler<2>().set(FUNC(sis85c496_host_device::at_pit8254_out2_changed));
+
+ // TODO: PS/2
AT_KEYBOARD_CONTROLLER(config, m_keybc, XTAL(12'000'000));
m_keybc->hot_res().set(FUNC(sis85c496_host_device::cpu_reset_w));
m_keybc->gate_a20().set(FUNC(sis85c496_host_device::cpu_a20_w));
- m_keybc->kbd_irq().set("pic8259_master", FUNC(pic8259_device::ir1_w));
- m_keybc->kbd_clk().set("pc_kbdc", FUNC(pc_kbdc_device::clock_write_from_mb));
- m_keybc->kbd_data().set("pc_kbdc", FUNC(pc_kbdc_device::data_write_from_mb));
+ m_keybc->kbd_irq().set(m_pic8259_master, FUNC(pic8259_device::ir1_w));
+ m_keybc->kbd_clk().set(m_pc_kbdc, FUNC(pc_kbdc_device::clock_write_from_mb));
+ m_keybc->kbd_data().set(m_pc_kbdc, FUNC(pc_kbdc_device::data_write_from_mb));
- PC_KBDC(config, m_pc_kbdc, 0);
+ PC_KBDC(config, m_pc_kbdc, pc_at_keyboards, STR_KBD_MICROSOFT_NATURAL);
m_pc_kbdc->out_clock_cb().set("keybc", FUNC(at_keyboard_controller_device::kbd_clk_w));
m_pc_kbdc->out_data_cb().set("keybc", FUNC(at_keyboard_controller_device::kbd_data_w));
- PC_KBDC_SLOT(config, "kbd", pc_at_keyboards, STR_KBD_MICROSOFT_NATURAL).set_pc_kbdc_slot(subdevice("pc_kbdc"));
DS12885(config, m_ds12885);
m_ds12885->irq().set(m_pic8259_slave, FUNC(pic8259_device::ir0_w));
m_ds12885->set_century_index(0x32);
+ // TODO: ISA bus clock, irqs
+ ISA16(config, m_isabus, 0);
+ m_isabus->set_memspace(m_maincpu, AS_PROGRAM);
+ m_isabus->set_iospace(m_maincpu, AS_IO);
+ m_isabus->irq3_callback().set(FUNC(sis85c496_host_device::pc_irq3_w));
+ m_isabus->irq4_callback().set(FUNC(sis85c496_host_device::pc_irq4_w));
+ m_isabus->irq5_callback().set(FUNC(sis85c496_host_device::pc_irq5_w));
+ m_isabus->irq6_callback().set(FUNC(sis85c496_host_device::pc_irq6_w));
+ m_isabus->irq7_callback().set(FUNC(sis85c496_host_device::pc_irq7_w));
+ m_isabus->irq2_callback().set(FUNC(sis85c496_host_device::pc_irq9_w));
+ m_isabus->irq10_callback().set(FUNC(sis85c496_host_device::pc_irq10_w));
+ m_isabus->irq11_callback().set(FUNC(sis85c496_host_device::pc_irq11_w));
+ m_isabus->irq12_callback().set(FUNC(sis85c496_host_device::pc_irq12m_w));
+ m_isabus->irq14_callback().set(FUNC(sis85c496_host_device::pc_irq14_w));
+ m_isabus->irq15_callback().set(FUNC(sis85c496_host_device::pc_irq15_w));
+ m_isabus->drq0_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq0_w));
+ m_isabus->drq1_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq1_w));
+ m_isabus->drq2_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq2_w));
+ m_isabus->drq3_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq3_w));
+ m_isabus->drq5_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq1_w));
+ m_isabus->drq6_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq2_w));
+ m_isabus->drq7_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq3_w));
+ m_isabus->iochck_callback().set(FUNC(sis85c496_host_device::iochck_w));
+
+ IDE_CONTROLLER_32(config, m_ide[0]).options(ata_devices, "hdd", nullptr, false);
+ m_ide[0]->irq_handler().set(m_pic8259_slave, FUNC(pic8259_device::ir6_w));
+
+ IDE_CONTROLLER_32(config, m_ide[1]).options(ata_devices, "cdrom", nullptr, false);
+ m_ide[1]->irq_handler().set(m_pic8259_slave, FUNC(pic8259_device::ir7_w));
+
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
@@ -120,7 +162,7 @@ void sis85c496_host_device::device_add_mconfig(machine_config &config)
sis85c496_host_device::sis85c496_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : pci_host_device(mconfig, SIS85C496, tag, owner, clock),
+ : pci_host_device(mconfig, SIS85C496_HOST, tag, owner, clock),
m_maincpu(*this, finder_base::DUMMY_TAG),
m_pic8259_master(*this, "pic8259_master"),
m_pic8259_slave(*this, "pic8259_slave"),
@@ -130,7 +172,9 @@ sis85c496_host_device::sis85c496_host_device(const machine_config &mconfig, cons
m_keybc(*this, "keybc"),
m_speaker(*this, "speaker"),
m_ds12885(*this, "rtc"),
- m_pc_kbdc(*this, "pc_kbdc"),
+ m_pc_kbdc(*this, "kbd"),
+ m_isabus(*this, "isabus"),
+ m_ide(*this, "ide%u", 1U),
m_at_spkrdata(0), m_pit_out2(0), m_dma_channel(0), m_cur_eop(false), m_dma_high_byte(0), m_at_speaker(0), m_refresh(false), m_channel_check(0), m_nmi_enabled(0)
{
}
@@ -149,8 +193,10 @@ void sis85c496_host_device::device_start()
{
pci_host_device::device_start();
- memory_space = &m_maincpu->space(AS_PROGRAM);
- io_space = &m_maincpu->space(AS_IO);
+ set_spaces(&m_maincpu->space(AS_PROGRAM), &m_maincpu->space(AS_IO));
+
+ m_pci_root->set_pin_mapper(pci_pin_mapper(*this, FUNC(sis85c496_host_device::pin_mapper)));
+ m_pci_root->set_irq_handler(pci_irq_handler(*this, FUNC(sis85c496_host_device::irq_handler)));
memory_window_start = 0;
memory_window_end = 0xffffffff;
@@ -167,6 +213,8 @@ void sis85c496_host_device::device_start()
m_smramctrl = 0;
ram.resize(ram_size/4);
+
+ save_item(NAME(m_shadctrl));
}
void sis85c496_host_device::reset_all_mappings()
@@ -190,6 +238,18 @@ void sis85c496_host_device::device_reset()
m_isa_decoder = 0xff;
m_shadctrl = 0;
m_smramctrl = 0;
+ m_ide_vesa_ctrl = 0;
+
+ memset(m_pirqrc, 0x80, sizeof(m_pirqrc));
+}
+
+void sis85c496_host_device::device_config_complete()
+{
+ auto isabus = m_isabus.finder_target();
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_memspace(m_maincpu, AS_PROGRAM);
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_iospace(m_maincpu, AS_IO);
+
+ pci_device::device_config_complete();
}
void sis85c496_host_device::map_bios(address_space *memory_space, uint32_t start, uint32_t end)
@@ -222,12 +282,12 @@ void sis85c496_host_device::map_extra(uint64_t memory_window_start, uint64_t mem
if (m_smramctrl & 0x08)
{
memory_space->install_ram(0x000e0000, 0x000effff, &ram[0x000b0000/4]);
- logerror("Sis496: SMRAM at Exxxx, phys Bxxxx\n");
+ logerror("SiS496: SMRAM at Exxxx, phys Bxxxx\n");
}
else
{
memory_space->install_ram(0x000e0000, 0x000effff, &ram[0x000a0000/4]);
- logerror("Sis496: SMRAM at Exxxx, phys Axxxx\n");
+ logerror("SiS496: SMRAM at Exxxx, phys Axxxx\n");
}
// map the high BIOS at FFFExxxx if enabled
@@ -313,15 +373,34 @@ void sis85c496_host_device::map_extra(uint64_t memory_window_start, uint64_t mem
// is SMRAM enabled at 6xxxx?
if ((m_smramctrl & 0x12) == 0x02)
{
- fatalerror("Sis486: SMRAM enabled at 6xxxx, not yet supported!\n");
+ throw emu_fatalerror("SiS496: SMRAM enabled at 6xxxx, not yet supported!\n");
}
+ // TODO: determined by ISA decoder
+ m_isabus->remap(AS_PROGRAM, 0, 1 << 24);
+ m_isabus->remap(AS_IO, 0, 0xffff);
+
if (m_isa_decoder & 0x01)
{
logerror("SiS496: ISA base 640K enabled\n");
memory_space->install_ram(0x00000000, 0x0009ffff, &ram[0x00000000/4]);
}
+ if (BIT(m_ide_vesa_ctrl, 8))
+ {
+ // TODO: doesn't seem to work right for anything after IDE[0] primary
+ // bit 9: swaps IDE channels
+ io_space->install_readwrite_handler(0x170, 0x177, read32s_delegate(*m_ide[1], FUNC(ide_controller_32_device::cs0_r)), write32s_delegate(*m_ide[1], FUNC(ide_controller_32_device::cs0_w)));
+
+ io_space->install_readwrite_handler(0x1f0, 0x1f7, read32s_delegate(*m_ide[0], FUNC(ide_controller_32_device::cs0_r)), write32s_delegate(*m_ide[0], FUNC(ide_controller_32_device::cs0_w)));
+
+ //if (!BIT(m_ide_vesa_ctrl, 6))
+ io_space->install_readwrite_handler(0x370, 0x377, read32s_delegate(*m_ide[1], FUNC(ide_controller_32_device::cs1_r)), write32s_delegate(*m_ide[1], FUNC(ide_controller_32_device::cs1_w)));
+
+ //if (!BIT(m_ide_vesa_ctrl, 7))
+ io_space->install_readwrite_handler(0x3f0, 0x3f7, read32s_delegate(*m_ide[0], FUNC(ide_controller_32_device::cs1_r)), write32s_delegate(*m_ide[0], FUNC(ide_controller_32_device::cs1_w)));
+ }
+
// 32 megs of RAM (todo: don't hardcode)
memory_space->install_ram(0x00100000, 0x01ffffff, &ram[0x00100000/4]);
}
@@ -341,21 +420,13 @@ void sis85c496_host_device::at_speaker_set_spkrdata(uint8_t data)
m_speaker->level_w(m_at_spkrdata & m_pit_out2);
}
-
-
-WRITE_LINE_MEMBER( sis85c496_host_device::at_pit8254_out0_changed )
-{
- if (m_pic8259_master)
- m_pic8259_master->ir0_w(state);
-}
-
-WRITE_LINE_MEMBER( sis85c496_host_device::at_pit8254_out1_changed )
+void sis85c496_host_device::at_pit8254_out1_changed(int state)
{
if(state)
m_refresh = !m_refresh;
}
-WRITE_LINE_MEMBER( sis85c496_host_device::at_pit8254_out2_changed )
+void sis85c496_host_device::at_pit8254_out2_changed(int state)
{
m_pit_out2 = state ? 1 : 0;
m_speaker->level_w(m_at_spkrdata & m_pit_out2);
@@ -409,7 +480,7 @@ void sis85c496_host_device::at_page8_w(offs_t offset, uint8_t data)
}
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dma_hrq_changed )
+void sis85c496_host_device::pc_dma_hrq_changed(int state)
{
m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
@@ -484,7 +555,7 @@ void sis85c496_host_device::pc_dma8237_5_dack_w(uint8_t data) { } //m_isabus->da
void sis85c496_host_device::pc_dma8237_6_dack_w(uint8_t data) { } //m_isabus->dack_w(6, data); }
void sis85c496_host_device::pc_dma8237_7_dack_w(uint8_t data) { } //m_isabus->dack_w(7, data); }
-WRITE_LINE_MEMBER( sis85c496_host_device::at_dma8237_out_eop )
+void sis85c496_host_device::at_dma8237_out_eop(int state)
{
m_cur_eop = state == ASSERT_LINE;
//if(m_dma_channel != -1)
@@ -508,14 +579,137 @@ void sis85c496_host_device::pc_select_dma_channel(int channel, bool state)
}
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack0_w ) { pc_select_dma_channel(0, state); }
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack1_w ) { pc_select_dma_channel(1, state); }
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack2_w ) { pc_select_dma_channel(2, state); }
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack3_w ) { pc_select_dma_channel(3, state); }
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack4_w ) { m_dma8237_1->hack_w( state ? 0 : 1); } // it's inverted
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack5_w ) { pc_select_dma_channel(5, state); }
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack6_w ) { pc_select_dma_channel(6, state); }
-WRITE_LINE_MEMBER( sis85c496_host_device::pc_dack7_w ) { pc_select_dma_channel(7, state); }
+void sis85c496_host_device::pc_dack0_w(int state) { pc_select_dma_channel(0, state); }
+void sis85c496_host_device::pc_dack1_w(int state) { pc_select_dma_channel(1, state); }
+void sis85c496_host_device::pc_dack2_w(int state) { pc_select_dma_channel(2, state); }
+void sis85c496_host_device::pc_dack3_w(int state) { pc_select_dma_channel(3, state); }
+void sis85c496_host_device::pc_dack4_w(int state) { m_dma8237_1->hack_w( state ? 0 : 1); } // it's inverted
+void sis85c496_host_device::pc_dack5_w(int state) { pc_select_dma_channel(5, state); }
+void sis85c496_host_device::pc_dack6_w(int state) { pc_select_dma_channel(6, state); }
+void sis85c496_host_device::pc_dack7_w(int state) { pc_select_dma_channel(7, state); }
+
+void sis85c496_host_device::pc_irq1_w(int state) { m_pic8259_master->ir1_w(state); }
+void sis85c496_host_device::pc_irq3_w(int state) { m_pic8259_master->ir3_w(state); }
+void sis85c496_host_device::pc_irq4_w(int state) { m_pic8259_master->ir4_w(state); }
+void sis85c496_host_device::pc_irq5_w(int state) { m_pic8259_master->ir5_w(state); }
+void sis85c496_host_device::pc_irq6_w(int state) { m_pic8259_master->ir6_w(state); }
+void sis85c496_host_device::pc_irq7_w(int state) { m_pic8259_master->ir7_w(state); }
+void sis85c496_host_device::pc_irq8n_w(int state) { m_pic8259_slave->ir0_w(state); }
+void sis85c496_host_device::pc_irq9_w(int state) { m_pic8259_slave->ir1_w(state); }
+void sis85c496_host_device::pc_irq10_w(int state) { m_pic8259_slave->ir2_w(state); }
+void sis85c496_host_device::pc_irq11_w(int state) { m_pic8259_slave->ir3_w(state); }
+void sis85c496_host_device::pc_irq12m_w(int state) { m_pic8259_slave->ir4_w(state); }
+void sis85c496_host_device::pc_irq14_w(int state) { m_pic8259_slave->ir6_w(state); }
+void sis85c496_host_device::pc_irq15_w(int state) { m_pic8259_slave->ir7_w(state); }
+
+uint8_t sis85c496_host_device::pirqrc_r(offs_t offset)
+{
+ return m_pirqrc[offset];
+}
+
+void sis85c496_host_device::pirqrc_w(offs_t offset, uint8_t data)
+{
+ m_pirqrc[offset] = data;
+ logerror("pirqrc[%d] = %02x\n", offset, m_pirqrc[offset]);
+}
+
+int sis85c496_host_device::pin_mapper(int pin)
+{
+ if(pin < 0 || pin >= 4 || (m_pirqrc[pin] & 0x80))
+ return -1;
+ return m_pirqrc[pin];
+}
+
+void sis85c496_host_device::irq_handler(int line, int state)
+{
+ if(line < 0 && line >= 16)
+ return;
+
+ logerror("irq_handler %d %d\n", line, state);
+ redirect_irq(line, state);
+}
+
+void sis85c496_host_device::pc_pirqa_w(int state)
+{
+ int irq = m_pirqrc[0] & 15;
+
+ if (!(BIT(m_pirqrc[0], 7)))
+ return;
+ redirect_irq(irq, state);
+}
+
+void sis85c496_host_device::pc_pirqb_w(int state)
+{
+ int irq = m_pirqrc[1] & 15;
+
+ if (!(BIT(m_pirqrc[1], 7)))
+ return;
+ redirect_irq(irq, state);
+}
+
+void sis85c496_host_device::pc_pirqc_w(int state)
+{
+ int irq = m_pirqrc[2] & 15;
+
+ if (!(BIT(m_pirqrc[2], 7)))
+ return;
+ redirect_irq(irq, state);
+}
+
+void sis85c496_host_device::pc_pirqd_w(int state)
+{
+ int irq = m_pirqrc[3] & 15;
+
+ if (!(BIT(m_pirqrc[3], 7)))
+ return;
+ redirect_irq(irq, state);
+}
+
+void sis85c496_host_device::redirect_irq(int irq, int state)
+{
+ switch (irq)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 8:
+ case 13:
+ break;
+ case 3:
+ m_pic8259_master->ir3_w(state);
+ break;
+ case 4:
+ m_pic8259_master->ir4_w(state);
+ break;
+ case 5:
+ m_pic8259_master->ir5_w(state);
+ break;
+ case 6:
+ m_pic8259_master->ir6_w(state);
+ break;
+ case 7:
+ m_pic8259_master->ir7_w(state);
+ break;
+ case 9:
+ m_pic8259_slave->ir1_w(state);
+ break;
+ case 10:
+ m_pic8259_slave->ir2_w(state);
+ break;
+ case 11:
+ m_pic8259_slave->ir3_w(state);
+ break;
+ case 12:
+ m_pic8259_slave->ir4_w(state);
+ break;
+ case 14:
+ m_pic8259_slave->ir6_w(state);
+ break;
+ case 15:
+ m_pic8259_slave->ir7_w(state);
+ break;
+ }
+}
uint8_t sis85c496_host_device::at_portb_r()
{
@@ -539,17 +733,24 @@ void sis85c496_host_device::at_portb_w(uint8_t data)
m_pit8254->write_gate2(BIT(data, 0));
at_speaker_set_spkrdata( BIT(data, 1));
m_channel_check = BIT(data, 3);
- //m_isabus->set_nmi_state((m_nmi_enabled==0) && (m_channel_check==0));
+ if (m_channel_check)
+ m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+}
+
+void sis85c496_host_device::iochck_w(int state)
+{
+ if (!state && !m_channel_check && m_nmi_enabled)
+ m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
}
uint8_t sis85c496_host_device::at_dma8237_2_r(offs_t offset)
{
- return m_dma8237_2->read( offset / 2);
+ return m_dma8237_2->read(offset / 2);
}
void sis85c496_host_device::at_dma8237_2_w(offs_t offset, uint8_t data)
{
- m_dma8237_2->write( offset / 2, data);
+ m_dma8237_2->write(offset / 2, data);
}
uint8_t sis85c496_host_device::at_keybc_r(offs_t offset)
@@ -572,30 +773,19 @@ void sis85c496_host_device::at_keybc_w(offs_t offset, uint8_t data)
}
}
-
-void sis85c496_host_device::write_rtc(offs_t offset, uint8_t data)
-{
- if (offset==0) {
- m_nmi_enabled = BIT(data,7);
- //m_isabus->set_nmi_state((m_nmi_enabled==0) && (m_channel_check==0));
- m_ds12885->write(0,data);
- }
- else {
- m_ds12885->write(offset,data);
- }
-}
-
-WRITE_LINE_MEMBER(sis85c496_host_device::cpu_int_w)
+void sis85c496_host_device::rtc_address_nmi_w(uint8_t data)
{
- m_maincpu->set_input_line(0, state);
+ m_nmi_enabled = BIT(data, 7);
+ //m_isabus->set_nmi_state((m_nmi_enabled==0) && (m_channel_check==0));
+ m_ds12885->address_w(data);
}
-WRITE_LINE_MEMBER(sis85c496_host_device::cpu_a20_w)
+void sis85c496_host_device::cpu_a20_w(int state)
{
m_maincpu->set_input_line(INPUT_LINE_A20, state);
}
-WRITE_LINE_MEMBER(sis85c496_host_device::cpu_reset_w)
+void sis85c496_host_device::cpu_reset_w(int state)
{
m_maincpu->set_input_line(INPUT_LINE_RESET, state);
}
diff --git a/src/devices/machine/sis85c496.h b/src/devices/machine/sis85c496.h
index 05bd11d5d56..47cb0729655 100644
--- a/src/devices/machine/sis85c496.h
+++ b/src/devices/machine/sis85c496.h
@@ -6,12 +6,14 @@
#define SIS85C496_H
#include "pci.h"
-#include "machine/ins8250.h"
#include "machine/ds128x.h"
+#include "machine/idectrl.h"
+#include "machine/ins8250.h"
#include "machine/pic8259.h"
#include "machine/pit8253.h"
#include "bus/ata/ataintf.h"
+#include "bus/isa/isa.h"
#include "machine/at_keybc.h"
#include "sound/spkrdev.h"
@@ -25,22 +27,49 @@
#include "cpu/i386/i386.h"
#include "machine/at.h"
-#define SIS85C496_HOST(_config, _tag, _cpu_tag, _ram_size) \
- pci_host_device &pcihost(PCI_HOST(_config, _tag, SIS85C496, 0x10390496, 0x03, 0x00000000)); \
- pcihost.set_cpu_tag(_cpu_tag); \
- pcihost.set_ram_size(_ram_size);
-
class sis85c496_host_device : public pci_host_device {
public:
sis85c496_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ template <typename T> sis85c496_host_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&cpu_tag, int ram_size
+ ) : sis85c496_host_device(mconfig, tag, owner, clock)
+ {
+ // Revision 3
+ set_ids(0x10390496, 0x03, 0x060000, 0x00);
+ //set_multifunction_device(true);
+ set_cpu_tag(std::forward<T>(cpu_tag));
+ set_ram_size(ram_size);
+ }
+
void set_cpu_tag(const char *tag);
void set_ram_size(int ram_size);
+ void pc_pirqa_w(int state);
+ void pc_pirqb_w(int state);
+ void pc_pirqc_w(int state);
+ void pc_pirqd_w(int state);
+
+ void pc_irq1_w(int state);
+ void pc_irq3_w(int state);
+ void pc_irq4_w(int state);
+ void pc_irq5_w(int state);
+ void pc_irq6_w(int state);
+ void pc_irq7_w(int state);
+ void pc_irq8n_w(int state);
+ void pc_irq9_w(int state);
+ void pc_irq10_w(int state);
+ void pc_irq11_w(int state);
+ void pc_irq12m_w(int state);
+ void pc_irq14_w(int state);
+ void pc_irq15_w(int state);
+
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_config_complete() override;
void map_bios(address_space *memory_space, uint32_t start, uint32_t end);
void map_shadowram(address_space *memory_space, offs_t addrstart, offs_t addrend, void *baseptr);
@@ -63,6 +92,8 @@ private:
required_device<speaker_sound_device> m_speaker;
required_device<ds12885_device> m_ds12885;
required_device<pc_kbdc_device> m_pc_kbdc;
+ required_device<isa16_device> m_isabus;
+ required_device_array<ide_controller_32_device, 2> m_ide;
uint8_t m_at_spkrdata;
uint8_t m_pit_out2;
@@ -78,12 +109,16 @@ private:
uint8_t m_channel_check;
uint8_t m_nmi_enabled;
+ uint8_t m_pirqrc[4];
+
int ram_size;
std::vector<uint32_t> ram;
uint32_t m_mailbox;
uint8_t m_bios_config, m_dram_config, m_isa_decoder;
uint16_t m_shadctrl;
uint8_t m_smramctrl;
+ uint16_t m_ide_vesa_ctrl;
+ u8 m_dram_boundary[8]{};
void internal_io_map(address_map &map);
@@ -99,6 +134,8 @@ private:
void shadow_config_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { COMBINE_DATA(&m_shadctrl); logerror("SiS496: %04x to shadow control\n", m_shadctrl); remap_cb(); }
uint8_t smram_ctrl_r() { return m_smramctrl; }
void smram_ctrl_w(uint8_t data) { m_smramctrl = data; remap_cb(); }
+ uint16_t ide_vesa_config_r() { return m_ide_vesa_ctrl; }
+ void ide_vesa_config_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { COMBINE_DATA(&m_ide_vesa_ctrl); logerror("SiS496: %04x to IDE/VESA Bus configuration\n", m_ide_vesa_ctrl); remap_cb(); }
// southbridge
uint8_t at_page8_r(offs_t offset);
@@ -106,10 +143,9 @@ private:
uint8_t at_portb_r();
void at_portb_w(uint8_t data);
uint8_t get_slave_ack(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER(at_pit8254_out0_changed);
- DECLARE_WRITE_LINE_MEMBER(at_pit8254_out1_changed);
- DECLARE_WRITE_LINE_MEMBER(at_pit8254_out2_changed);
- DECLARE_WRITE_LINE_MEMBER(pc_dma_hrq_changed);
+ void at_pit8254_out1_changed(int state);
+ void at_pit8254_out2_changed(int state);
+ void pc_dma_hrq_changed(int state);
uint8_t pc_dma8237_0_dack_r();
uint8_t pc_dma8237_1_dack_r();
uint8_t pc_dma8237_2_dack_r();
@@ -124,29 +160,37 @@ private:
void pc_dma8237_5_dack_w(uint8_t data);
void pc_dma8237_6_dack_w(uint8_t data);
void pc_dma8237_7_dack_w(uint8_t data);
- 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);
+ void at_dma8237_out_eop(int state);
+ void pc_dack0_w(int state);
+ void pc_dack1_w(int state);
+ void pc_dack2_w(int state);
+ void pc_dack3_w(int state);
+ void pc_dack4_w(int state);
+ void pc_dack5_w(int state);
+ void pc_dack6_w(int state);
+ void pc_dack7_w(int state);
uint8_t at_dma8237_2_r(offs_t offset);
void at_dma8237_2_w(offs_t offset, uint8_t data);
+ void iochck_w(int state);
uint8_t at_keybc_r(offs_t offset);
void at_keybc_w(offs_t offset, uint8_t data);
- void write_rtc(offs_t offset, uint8_t data);
+ u8 rtc_address_r();
+ void rtc_address_nmi_w(uint8_t data);
uint8_t pc_dma_read_byte(offs_t offset);
void pc_dma_write_byte(offs_t offset, uint8_t data);
uint8_t pc_dma_read_word(offs_t offset);
void pc_dma_write_word(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(cpu_int_w);
- DECLARE_WRITE_LINE_MEMBER(cpu_a20_w);
- DECLARE_WRITE_LINE_MEMBER(cpu_reset_w);
+ void cpu_a20_w(int state);
+ void cpu_reset_w(int state);
+
+ uint8_t pirqrc_r(offs_t offset);
+ void pirqrc_w(offs_t offset, uint8_t data);
+ void redirect_irq(int irq, int state);
+
+ int pin_mapper(int pin);
+ void irq_handler(int line, int state);
};
-DECLARE_DEVICE_TYPE(SIS85C496, sis85c496_host_device)
+DECLARE_DEVICE_TYPE(SIS85C496_HOST, sis85c496_host_device)
#endif
diff --git a/src/devices/machine/sis900_eth.cpp b/src/devices/machine/sis900_eth.cpp
new file mode 100644
index 00000000000..d960c4b0293
--- /dev/null
+++ b/src/devices/machine/sis900_eth.cpp
@@ -0,0 +1,161 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ SiS 900 Fast Ethernet Controller / Adapter
+
+ TODO:
+ - Stub interface, to be improved;
+ - Sensible defaults for EEPROM;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis900_eth.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+#define LOG_PMC (1U << 4) // log PMC access
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_PMC)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+#define LOGPMC(...) LOGMASKED(LOG_PMC, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SIS900_ETH, sis900_eth_device, "sis900_eth", "SiS 900 Fast Ethernet Adapter")
+
+sis900_eth_device::sis900_eth_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, SIS900_ETH, tag, owner, clock)
+ , m_eeprom(*this, "eeprom")
+ , m_eth_rom(*this, "eth_rom")
+{
+ // 0x020000 - Network Ethernet controller
+ // 0x80 - "Silicon revision" (sic)
+ set_ids(0x10390900, 0x80, 0x020000, 0x00);
+}
+
+void sis900_eth_device::device_add_mconfig(machine_config &config)
+{
+ EEPROM_93C66_16BIT(config, m_eeprom); // NM93Cxx
+}
+
+void sis900_eth_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+ map(0x40, 0x43).r(FUNC(sis900_eth_device::pmc_id_r));
+// map(0x44, 0x47).r(FUNC(sis900_eth_device::pmc_status_r), FUNC(sis900_eth_device::pmc_control_w));
+}
+
+void sis900_eth_device::memory_map(address_map &map)
+{
+
+}
+
+void sis900_eth_device::io_map(address_map &map)
+{
+ map(0x08, 0x08).rw(FUNC(sis900_eth_device::eromar_r), FUNC(sis900_eth_device::eromar_w));
+}
+
+void sis900_eth_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+// io_space->install_device(0, 0x03ff, *this, &sis900_eth_device::io_map);
+}
+
+ROM_START( sis900eth )
+ ROM_REGION32_LE( 0x10000, "eth_rom", ROMREGION_ERASEFF )
+ ROM_LOAD( "pxe_m.19", 0x0000, 0xa000, BAD_DUMP CRC(c8da34a6) SHA1(f11b4f5398176b7d924c63c77a1951cb83020e48) )
+ // structure:
+ // [0x00] signature -> 0x55aa
+ // [0x08] MAC address
+ // [0x0b] checksum
+ // PCIR signature+[0x00] vendor ID -> 0x1039
+ // PCIR signature+[0x02] device ID -> 0x0900
+ROM_END
+
+const tiny_rom_entry *sis900_eth_device::device_rom_region() const
+{
+ return ROM_NAME(sis900eth);
+}
+
+void sis900_eth_device::device_start()
+{
+ pci_device::device_start();
+
+ add_map(256, M_IO, FUNC(sis900_eth_device::io_map));
+ add_map(4096, M_MEM, FUNC(sis900_eth_device::memory_map));
+ add_rom((u8 *)m_eth_rom->base(), m_eth_rom->bytes());
+
+ // INTC#
+ intr_pin = 3;
+ // TODO: "if auto load is enabled it is set by subvendor ID stored in EEPROM" (?)
+ subsystem_id = 0x10390900;
+}
+
+void sis900_eth_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ status = 0x0290;
+
+ m_eromar_mode = false;
+}
+
+uint8_t sis900_eth_device::capptr_r()
+{
+ return 0x40;
+}
+
+// TODO: move to specific interface
+u32 sis900_eth_device::pmc_id_r()
+{
+ LOGPMC("Read PMC ID [$40]\n");
+ // bits 31-16 PPMI v1.0 / v1.0a, D1 / D2 supported, PME# D0/D1/D2/D3hot & optional D3cold
+ // bits 15-8 0x00 no NEXT_PTR (NULL terminates here)
+ // bits 7-0 PM_CAP_ID (0x01 for PMC)
+ // TODO: versioning may depend on ROM installed
+ return 0xfe010001;
+}
+
+/*
+ * I/O space
+ */
+
+u8 sis900_eth_device::eromar_r()
+{
+ // TODO: doc claims all bits are readable, looks unlikely?
+ u8 res = m_eromar_mode << 7;
+ if (m_eromar_mode)
+ {
+ // ...
+ }
+ else
+ res |= m_eeprom->do_read() << 1;
+
+ return res;
+}
+
+void sis900_eth_device::eromar_w(u8 data)
+{
+ m_eromar_mode = bool(BIT(data, 7));
+
+ LOGIO("eromar_w %s selected %02x\n", m_eromar_mode ? "HomePHY" : "eeprom", data);
+
+ if (m_eromar_mode)
+ {
+ // ...
+ }
+ else
+ {
+ m_eeprom->cs_write(BIT(data, 3));
+ m_eeprom->clk_write(BIT(data, 2));
+ m_eeprom->di_write(BIT(data, 0));
+ }
+}
diff --git a/src/devices/machine/sis900_eth.h b/src/devices/machine/sis900_eth.h
new file mode 100644
index 00000000000..4d5fb46f2bd
--- /dev/null
+++ b/src/devices/machine/sis900_eth.h
@@ -0,0 +1,53 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS900_ETH_H
+#define MAME_MACHINE_SIS900_ETH_H
+
+#pragma once
+
+#include "pci.h"
+#include "machine/eepromser.h"
+
+class sis900_eth_device : public pci_device
+{
+public:
+ sis900_eth_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ static constexpr feature_type unemulated_features() { return feature::LAN; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ virtual const tiny_rom_entry *device_rom_region() const override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void memory_map(address_map &map);
+ void io_map(address_map &map);
+
+private:
+ required_device<eeprom_serial_93cxx_device> m_eeprom;
+ required_memory_region m_eth_rom;
+
+ bool m_eromar_mode;
+
+ virtual uint8_t capptr_r() override;
+ u32 pmc_id_r();
+// void pmc_status_r();
+// u32 pmc_control(offs_t offset, u32 data, u32 mem_mask = ~0);
+
+ u8 eromar_r();
+ void eromar_w(u8 data);
+};
+
+DECLARE_DEVICE_TYPE(SIS900_ETH, sis900_eth_device)
+
+#endif
diff --git a/src/devices/machine/sis950_lpc.cpp b/src/devices/machine/sis950_lpc.cpp
new file mode 100644
index 00000000000..2cac38194fa
--- /dev/null
+++ b/src/devices/machine/sis950_lpc.cpp
@@ -0,0 +1,786 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+SiS950 LPC implementation (Super I/O & southbridge)
+
+TODO:
+- Convert most stuff declared here to generic interfaces;
+ \- Despite what the datasheet claims it really looks like that a separate Super I/O provides
+ the usual x86 resources;
+- Flash ROM handling
+ \- Doesn't survive a soft reset;
+- Fix EISA;
+- INIT register (reset & A20 control + fast gates + fast reset timing control);
+- Override PS/2 ports if USB legacy mode is enabled;
+- NMI & SMI handling;
+- SMBus handling;
+- RTC extended bank enable;
+ \- Doesn't survive a CMOS write after fast reset;
+- Shadow registers for PIC and PIT;
+- IRQ remaps for PCI_SLOT
+ \- INTA GUI
+ \- INTB AUDIO and MODEM
+ \- INTC ethernet
+ \- INTD USB
+- IRQ software traps ($6e-$6f);
+ \- Documentation mentions that those can be read-back too, huh?
+- Understand what's the catch of "changing device ID number" via BIOS control $40 bit 6;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "sis950_lpc.h"
+
+#include "bus/pc_kbd/keyboards.h"
+#include "machine/pckeybrd.h"
+#include "speaker.h"
+
+#define LOG_IO (1U << 1) // log PCI register accesses
+#define LOG_TODO (1U << 2) // log unimplemented registers
+#define LOG_MAP (1U << 3) // log full remaps
+#define LOG_LPC (1U << 4) // log LPC legacy regs
+#define LOG_IRQ (1U << 5) // log IRQ remaps
+
+#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_IRQ)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__)
+#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__)
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+#define LOGLPC(...) LOGMASKED(LOG_LPC, __VA_ARGS__)
+#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SIS950_LPC, sis950_lpc_device, "sis950_lpc", "SiS 950 LPC Super-South Bridge")
+
+sis950_lpc_device::sis950_lpc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, SIS950_LPC, tag, owner, clock)
+ , m_host_cpu(*this, finder_base::DUMMY_TAG)
+ , m_flash_rom(*this, finder_base::DUMMY_TAG)
+ , m_pic_master(*this, "pic_master")
+ , m_pic_slave(*this, "pic_slave")
+ , m_dmac_master(*this, "dmac_master")
+ , m_dmac_slave(*this, "dmac_slave")
+ , m_pit(*this, "pit")
+ , m_keybc(*this, "keybc")
+ , m_isabus(*this, "isabus")
+ , m_speaker(*this, "speaker")
+ , m_rtc(*this, "rtc")
+ , m_ps2_con(*this, "ps2_con")
+ , m_aux_con(*this, "aux_con")
+ , m_acpi(*this, "acpi")
+ , m_smbus(*this, "smbus")
+ , m_fast_reset_cb(*this)
+{
+}
+
+void sis950_lpc_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x000c;
+ status = 0x0200;
+
+ m_bios_control = 1;
+ m_acpi_base = 0;
+ m_flash_control = 0x40;
+ m_keybc_reg = 0x51;
+ m_dma_channel = -1;
+// m_cur_eop = false;
+ m_dma_high_byte = 0;
+ m_init_reg = 0;
+ m_rtc_reg = 0x10;
+ // remapping is disabled for all as default
+ std::fill(std::begin(m_irq_remap), std::end(m_irq_remap), 0x80);
+
+ m_lpc_legacy.fast_init = 0;
+ remap_cb();
+}
+
+void sis950_lpc_device::cpu_a20_w(int state)
+{
+ // TODO: confirm "A20M# being always high"
+// if (BIT(m_init_reg, 1))
+// state = ASSERT_LINE;
+ m_host_cpu->set_input_line(INPUT_LINE_A20, state);
+}
+
+void sis950_lpc_device::cpu_reset_w(int state)
+{
+ // TODO: masked via INIT $46 bit 0
+ m_host_cpu->set_input_line(INPUT_LINE_RESET, state);
+}
+
+void sis950_lpc_device::device_add_mconfig(machine_config &config)
+{
+ constexpr XTAL lpc_pit_clock = XTAL(14'318'181);
+
+ // confirmed 82C54
+ PIT8254(config, m_pit, 0);
+ // heartbeat IRQ
+ m_pit->set_clk<0>(lpc_pit_clock / 12);
+ m_pit->out_handler<0>().set(FUNC(sis950_lpc_device::pit_out0));
+ // DRAM refresh
+ m_pit->set_clk<1>(lpc_pit_clock / 12);
+ m_pit->out_handler<1>().set(FUNC(sis950_lpc_device::pit_out1));
+ // PIO port C pin 4, and speaker polling enough
+ m_pit->set_clk<2>(lpc_pit_clock / 12);
+ m_pit->out_handler<2>().set(FUNC(sis950_lpc_device::pit_out2));
+
+ // TODO: unknown part #
+ AM9517A(config, m_dmac_master, lpc_pit_clock / 3);
+ m_dmac_master->out_hreq_callback().set(m_dmac_slave, FUNC(am9517a_device::dreq0_w));
+// m_dmac_master->out_eop_callback().set(FUNC(sis950_lpc_device::at_dma8237_out_eop));
+ m_dmac_master->in_memr_callback().set(FUNC(sis950_lpc_device::pc_dma_read_byte));
+ m_dmac_master->out_memw_callback().set(FUNC(sis950_lpc_device::pc_dma_write_byte));
+ // TODO: ior/iow/dack/eop callbacks
+
+ AM9517A(config, m_dmac_slave, lpc_pit_clock / 3);
+ m_dmac_slave->out_hreq_callback().set(FUNC(sis950_lpc_device::pc_dma_hrq_changed));
+ m_dmac_slave->in_memr_callback().set(FUNC(sis950_lpc_device::pc_dma_read_word));
+ m_dmac_slave->out_memw_callback().set(FUNC(sis950_lpc_device::pc_dma_write_word));
+ // TODO: ior/iow/dack callbacks
+
+ // Confirmed 82C59s
+ PIC8259(config, m_pic_master, 0);
+ m_pic_master->out_int_callback().set_inputline(m_host_cpu, 0);
+ m_pic_master->in_sp_callback().set_constant(1);
+ m_pic_master->read_slave_ack_callback().set(
+ [this](offs_t offset) -> u8
+ {
+ if (offset == 2)
+ return m_pic_slave->acknowledge();
+
+ return 0;
+ });
+
+ PIC8259(config, m_pic_slave, 0);
+ m_pic_slave->out_int_callback().set(m_pic_master, FUNC(pic8259_device::ir2_w));
+ m_pic_slave->in_sp_callback().set_constant(0);
+
+ // TODO: EISA, from virtual bridge
+
+ // TODO: selectable between PCI clock / 4 or 7.159 MHz, via reg $47 bit 5
+ PS2_KEYBOARD_CONTROLLER(config, m_keybc, DERIVED_CLOCK(1, 4));
+ m_keybc->set_default_bios_tag("compaq");
+ m_keybc->hot_res().set(FUNC(sis950_lpc_device::cpu_reset_w));
+ m_keybc->gate_a20().set(FUNC(sis950_lpc_device::cpu_a20_w));
+ m_keybc->kbd_irq().set(m_pic_master, FUNC(pic8259_device::ir1_w));
+ m_keybc->kbd_clk().set(m_ps2_con, FUNC(pc_kbdc_device::clock_write_from_mb));
+ m_keybc->kbd_data().set(m_ps2_con, FUNC(pc_kbdc_device::data_write_from_mb));
+ m_keybc->aux_irq().set(m_pic_slave, FUNC(pic8259_device::ir4_w));
+ m_keybc->aux_clk().set(m_aux_con, FUNC(pc_kbdc_device::clock_write_from_mb));
+ m_keybc->aux_data().set(m_aux_con, FUNC(pc_kbdc_device::data_write_from_mb));
+
+ PC_KBDC(config, m_ps2_con, pc_at_keyboards, STR_KBD_MICROSOFT_NATURAL);
+ m_ps2_con->out_clock_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::kbd_clk_w));
+ m_ps2_con->out_data_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::kbd_data_w));
+
+ // TODO: doesn't work (wrong PS/2 BIOS?), worked around by disabling for now
+ PC_KBDC(config, m_aux_con, ps2_mice, nullptr);
+ m_aux_con->out_clock_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::aux_clk_w));
+ m_aux_con->out_data_cb().set(m_keybc, FUNC(ps2_keyboard_controller_device::aux_data_w));
+
+ // TODO: unknown RTC type
+ // Has external RTC bank select at $48, using this one as convenience
+ DS12885EXT(config, m_rtc, XTAL(32'768));
+ m_rtc->irq().set(m_pic_slave, FUNC(pic8259_device::ir0_w));
+ m_rtc->set_century_index(0x32);
+
+ // TODO: left/right speaker connection
+ SPEAKER(config, "mono").front_center();
+ SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
+
+ ISA16(config, m_isabus, 0);
+ m_isabus->irq3_callback().set(FUNC(sis950_lpc_device::pc_irq3_w));
+ m_isabus->irq4_callback().set(FUNC(sis950_lpc_device::pc_irq4_w));
+ m_isabus->irq6_callback().set(FUNC(sis950_lpc_device::pc_irq6_w));
+ m_isabus->irq5_callback().set(FUNC(sis950_lpc_device::pc_irq5_w));
+ m_isabus->irq7_callback().set(FUNC(sis950_lpc_device::pc_irq7_w));
+ m_isabus->irq2_callback().set(FUNC(sis950_lpc_device::pc_irq9_w));
+ m_isabus->irq10_callback().set(FUNC(sis950_lpc_device::pc_irq10_w));
+ m_isabus->irq11_callback().set(FUNC(sis950_lpc_device::pc_irq11_w));
+ m_isabus->irq12_callback().set(FUNC(sis950_lpc_device::pc_irq12m_w));
+ m_isabus->irq14_callback().set(FUNC(sis950_lpc_device::pc_irq14_w));
+ m_isabus->irq15_callback().set(FUNC(sis950_lpc_device::pc_irq15_w));
+ m_isabus->iochck_callback().set(FUNC(sis950_lpc_device::iochck_w));
+}
+
+void sis950_lpc_device::device_config_complete()
+{
+ auto isabus = m_isabus.finder_target();
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_memspace(m_host_cpu, AS_PROGRAM);
+ isabus.first.subdevice<isa16_device>(isabus.second)->set_iospace(m_host_cpu, AS_IO);
+
+ pci_device::device_config_complete();
+}
+
+void sis950_lpc_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+ map(0x10, 0x4f).unmaprw();
+ map(0x10, 0x75).rw(FUNC(sis950_lpc_device::unmap_log_r), FUNC(sis950_lpc_device::unmap_log_w));
+
+ // LPC control regs
+ map(0x40, 0x40).rw(FUNC(sis950_lpc_device::bios_control_r), FUNC(sis950_lpc_device::bios_control_w));
+ map(0x41, 0x41).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_INTA>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTA>));
+ map(0x42, 0x42).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_INTB>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTB>));
+ map(0x43, 0x43).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_INTC>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTC>));
+ map(0x44, 0x44).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_INTD>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_INTD>));
+
+ map(0x45, 0x45).rw(FUNC(sis950_lpc_device::flash_ctrl_r), FUNC(sis950_lpc_device::flash_ctrl_w));
+ map(0x46, 0x46).rw(FUNC(sis950_lpc_device::init_enable_r), FUNC(sis950_lpc_device::init_enable_w));
+ map(0x47, 0x47).rw(FUNC(sis950_lpc_device::keybc_reg_r), FUNC(sis950_lpc_device::keybc_reg_w));
+ map(0x48, 0x48).rw(FUNC(sis950_lpc_device::rtc_reg_r), FUNC(sis950_lpc_device::rtc_reg_w));
+
+ // DMA control regs
+// map(0x49, 0x49) Distributed DMA channel enable
+// map(0x4a, 0x4b) Distributed DMA Master config
+
+ // Shadow regs (r/o)
+// map(0x4c, 0x4f) PIC master ICW*
+// map(0x50, 0x53) PIC slave ICW*
+// map(0x54, 0x55) PIC master OCW2-3
+// map(0x56, 0x57) PIC slave OCW2-3 (NB: assume documentation 0x54-0x55 to be a typo)
+// map(0x58, 0x5f) PIT counters 0-1-2 low/high, $5e -> control 43h, $5f -> read count pointer statuses
+// map(0x60, 0x60) EISA port $70
+
+ map(0x61, 0x61).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_IDE>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_IDE>));
+// map(0x62, 0x62) <reserved>, hardwired to 0x80 (PIT irq remap?)
+ map(0x62, 0x62).lr8(NAME([] () { return 0x80; }));
+ map(0x63, 0x63).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_GPE>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_GPE>));
+
+// map(0x64, 0x64) PCI bus priority timer
+// map(0x65, 0x65) PHOLD# timer
+
+// map(0x66, 0x66) <reserved>
+// map(0x67, 0x67) Serial IRQ 1 & 12 latch control (FDC super I/O)
+// map(0x68, 0x69) <reserved>
+
+ map(0x63, 0x63).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_ACPI>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_ACPI>));
+// map(0x6b, 0x6b) <reserved>
+ map(0x6c, 0x6c).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_SMBUS>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_SMBUS>));
+ map(0x6d, 0x6d).rw(FUNC(sis950_lpc_device::irq_remap_r<IRQ_SWDOG>), FUNC(sis950_lpc_device::irq_remap_w<IRQ_SWDOG>));
+
+// map(0x6e, 0x6f) SW irq triggers
+// map(0x70, 0x70) Serial irq control
+// map(0x71, 0x73) Serial irq enable
+
+ // $74 should be ACPI lower base bank, but marked as <reserved> regardless
+ // (by logic that should go to NOP too)
+ map(0x74, 0x74).lr8(NAME([] () { return 0; }));
+ map(0x75, 0x75).rw(FUNC(sis950_lpc_device::acpi_base_r), FUNC(sis950_lpc_device::acpi_base_w));
+}
+
+u8 sis950_lpc_device::bios_control_r()
+{
+ LOGIO("Read BIOS control [$40] %02x\n", m_bios_control);
+ return m_bios_control;
+}
+
+void sis950_lpc_device::bios_control_w(u8 data)
+{
+ // Mostly 0x9a or 0x9b
+ LOGIO("Write BIOS control [$40] %02x\n", data);
+ m_bios_control = data;
+ remap_cb();
+}
+
+template <unsigned N> u8 sis950_lpc_device::irq_remap_r()
+{
+ return m_irq_remap[N];
+}
+
+template <unsigned N> void sis950_lpc_device::irq_remap_w(u8 data)
+{
+ m_irq_remap[N] = data;
+ LOGIRQ("%s IRQ remap write %02x (%s)\n", std::array<char const *, 9> {{
+ "INTA",
+ "INTB",
+ "INTC",
+ "INTD",
+ "IDEIRQ",
+ "GPEIRQ",
+ "ACPI/SCI",
+ "SMBus",
+ "Software Watchdog"
+ }}[N], data, BIT(data, 7) ? "disable" : "enable");
+}
+
+u8 sis950_lpc_device::flash_ctrl_r()
+{
+ LOGIO("Read Flash control [$45] %02x\n", m_flash_control);
+ return m_flash_control;
+}
+
+void sis950_lpc_device::flash_ctrl_w(u8 data)
+{
+ LOGIO("Write Flash control [$45] %02x\n", data);
+ m_flash_control = data;
+ remap_cb();
+}
+
+u8 sis950_lpc_device::init_enable_r()
+{
+ LOGIO("Read INIT enable [$46] %02x\n", m_init_reg);
+ return m_init_reg;
+}
+
+/*
+ * 11-- ---- HW (fast?) reset
+ * --x- ---- INIT enable
+ * ---x ---- Fast Gate A20 emulation
+ * ---- x--- Fast Reset latency control
+ * ---- -x-- Fast Reset emulation
+ * ---- --x- (0) enable A20M# (1) A20M# always high (?)
+ * ---- ---x Keyboard HW reset
+ */
+void sis950_lpc_device::init_enable_w(u8 data)
+{
+ LOGIO("Write INIT enable [$46] %02x\n", data);
+ // HW fast reset
+ // TODO: is 0->1 implementation correct?
+ // it will otherwise keep resetting itself, which may be a side effect of something else
+ // (perhaps PS/2 controller can intercept this? Or it's a full on LPC reset like using an actual MAME soft reset implies?)
+ if ((data & 0xc0) == 0xc0)// && (m_init_reg & 0xc0) == 0)
+ {
+ //const int fast_reset_time = BIT(data, 3) ? 6 : 2;
+ LOGIO("Fast reset issued\n");
+ //m_host_cpu->pulse_input_line(INPUT_LINE_RESET, attotime::from_usec(fast_reset_time));
+ m_fast_reset_cb(1);
+ }
+
+ m_init_reg = data;
+}
+
+u8 sis950_lpc_device::keybc_reg_r()
+{
+ LOGIO("Read keyboard register [$47] %02x\n", m_keybc_reg);
+ return m_keybc_reg;
+}
+
+/*
+ * x--- ---- legacy USB (ports $60-$64 overrides)
+ * -x-- ---- PS/2 mouse lock enable
+ * --x- ---- Keyboard controller clock select (0) PCI Clock / 4 (1) 7.159 MHz
+ * ---x ---- Keyboard lock enable
+ * ---- x--- Integrated keyboard controller enable
+ * ---- -x-- Integrated PS/2 mouse enable (needs bit 3 enabled)
+ * ---- --x- Keyboard hot key status (needs bit 3 enabled, ctrl+alt+backspace)
+ * ---- ---x Keyboard hot key control
+ */
+void sis950_lpc_device::keybc_reg_w(u8 data)
+{
+ LOGIO("Write keyboard register [$47] %02x\n", data);
+ m_keybc_reg = data;
+}
+
+u8 sis950_lpc_device::rtc_reg_r()
+{
+ LOGIO("Read RTC register [$48] %02x\n", m_keybc_reg);
+ return m_rtc_reg | 0x10;
+}
+
+/*
+ * x--- ---- RTC extended bank enable
+ * -x-- ---- APC enable
+ * --x- ---- Instant Power-Off enable (thru APC)
+ * ---x ---- Internal RTC status (r/o, always on?)
+ * ---- xxxx <reserved>
+ */
+void sis950_lpc_device::rtc_reg_w(u8 data)
+{
+ LOGIO("Write RTC register [$48] %02x\n", data);
+ m_rtc_reg = data;
+}
+
+u8 sis950_lpc_device::acpi_base_r()
+{
+ LOGIO("Read ACPI base [$75] %04x\n", m_acpi_base);
+ return m_acpi_base >> 8;
+}
+
+void sis950_lpc_device::acpi_base_w(u8 data)
+{
+ u16 new_value = data << 8;
+ LOGIO("Write ACPI base [$75] %04x\n", new_value);
+ m_acpi_base = new_value;
+ remap_cb();
+}
+
+template <unsigned N> void sis950_lpc_device::memory_map(address_map &map)
+{
+ map(0x00000000, 0x0001ffff).lrw8(
+ NAME([this] (offs_t offset) { return m_flash_rom->read(offset | N * 0x20000); }),
+ NAME([this] (offs_t offset, u8 data) { m_flash_rom->write(offset | N * 0x20000, data); })
+ );
+}
+
+void sis950_lpc_device::io_map(address_map &map)
+{
+ // Legacy ISA (page 177)
+ // map(0x0000, 0x000f) DMA1
+ map(0x0000, 0x001f).rw(m_dmac_master, FUNC(am9517a_device::read), FUNC(am9517a_device::write));
+ // map(0x0020, 0x0021) INT1
+ map(0x0020, 0x0021).rw(m_pic_master, FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ // map(0x0040, 0x0043) PIT
+ map(0x0040, 0x0043).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write));
+ map(0x0060, 0x0060).rw(m_keybc, FUNC(ps2_keyboard_controller_device::data_r), FUNC(ps2_keyboard_controller_device::data_w));
+ // map(0x0061, 0x0061) NMI Status Register
+ map(0x0061, 0x0061).rw(FUNC(sis950_lpc_device::nmi_status_r), FUNC(sis950_lpc_device::nmi_control_w));
+ // undocumented but read, assume LPC complaint
+ map(0x0064, 0x0064).rw(m_keybc, FUNC(ps2_keyboard_controller_device::status_r), FUNC(ps2_keyboard_controller_device::command_w));
+ // map(0x0070, 0x0070) CMOS and NMI Mask
+ map(0x0070, 0x0070).w(FUNC(sis950_lpc_device::rtc_index_w));
+ map(0x0071, 0x0071).rw(FUNC(sis950_lpc_device::rtc_data_r), FUNC(sis950_lpc_device::rtc_data_w));
+ // map(0x0080, 0x008f) DMA low page registers
+ map(0x0080, 0x008f).rw(FUNC(sis950_lpc_device::at_page8_r), FUNC(sis950_lpc_device::at_page8_w));
+ // map(0x0092, 0x0092) INIT and A20
+ map(0x0092, 0x0092).rw(FUNC(sis950_lpc_device::lpc_fast_init_r), FUNC(sis950_lpc_device::lpc_fast_init_w));
+ // map(0x00a0, 0x00a1) INT2
+ map(0x00a0, 0x00a1).rw(m_pic_slave, FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ // map(0x00c0, 0x00df) DMA2
+ map(0x00c0, 0x00df).lrw8(
+ NAME([this] (offs_t offset) { return m_dmac_slave->read( offset / 2 ); }),
+ NAME([this] (offs_t offset, u8 data) { m_dmac_slave->write( offset / 2, data ); })
+ );
+
+ map(0x00e0, 0x00ef).noprw();
+ // map(0x00f0, 0x00f0) COPRO error
+ // map(0x0480, 0x048f) DMA high page registers
+ // map(0x04d0, 0x04d1) IRQ edge/level control registers
+
+ // http://bxr.su/DragonFly/share/man/man4/it.4
+ // 0x0290, 0xc00, 0xd00, 0x228: Motherboard Super I/O HW monitoring
+
+ // map(0x0295, 0x0295) - index register, $d-$e lower/upper RPM readback for fans (alternating on read)
+ // map(0x0296, 0x0296) - data ^
+
+ // Intel LPC interface specs (legacy host decode ranges, not necessarily present on '950)
+
+ // map(0x002e, 0x002f) Super I/O config (config-index & data ports)
+ // map(0x004e, 0x004f) alt Super I/O config (ISA converter index-data ports)
+ // map(0x0062, 0x0062) - ACPI embedded controller
+ // map(0x0066, 0x0066) /
+
+ // map(0x0200, 0x020f) game ports ($201 as shutms11 default)
+
+ // map(0x0220, 0x0227) serial 2
+ // map(0x0228, 0x022f) serial 2
+ // map(0x0220, 0x0233) sb compatible i/f 1
+ // map(0x0240, 0x0253) sb compatible i/f 2
+ // map(0x0260, 0x0273) sb compatible i/f 3
+ // map(0x0280, 0x0293) sb compatible i/f 4
+
+ // map(0x0238, 0x023f) serial 3
+
+ // map(0x0278, 0x027f) parallel port 2 & PnP
+ // map(0x02e8, 0x02ef) serial 3
+ // map(0x02f8, 0x02ff) serial 1
+
+ // map(0x0300, 0x0301) - MIDI ($330 as shutms11 default)
+ // map(0x0310, 0x0311) /
+ // map(0x0320, 0x0321) /
+ // map(0x0330, 0x0331) /
+
+ // map(0x0338, 0x033f) serial 4
+ // map(0x0370, 0x0377) FDC 2
+
+ // map(0x0378, 0x037f) parallel port 1
+ // map(0x0388, 0x0389) ADLIB
+ // map(0x03bc, 0x03bf) parallel port 3
+ // map(0x03e8, 0x03ef) serial 4
+ // map(0x03f0, 0x03f7) FDC 1
+ // map(0x03f8, 0x03ff).rw(m_uart, FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w)); // COM1
+
+ // map(0x0530, 0x0537) - MSS (TCP Maximum Segment Size?)
+ // map(0x0604, 0x060b) /
+ // map(0x0e80, 0x0e87) /
+ // map(0x0f40, 0x0f47) /
+
+ // map(0x0678, 0x067f) ECP parallel port 1
+ // map(0x0778, 0x0779) ECP parallel port 2 & PnP
+ // map(0x07bc, 0x07bf) ECP parallel port 3
+}
+
+void sis950_lpc_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+ m_isabus->remap(AS_PROGRAM, 0, 1 << 24);
+ m_isabus->remap(AS_IO, 0, 0xffff);
+ io_space->install_device(0, 0x07ff, *this, &sis950_lpc_device::io_map);
+
+ LOGMAP("LPC Remapping table (BIOS: %02x, flash: %02x)\n", m_bios_control, m_flash_control);
+
+ // ACPI enable
+ if (BIT(m_bios_control, 7))
+ {
+ LOGMAP("- ACPI enable (%02x) %04x-%04x\n", m_bios_control, m_acpi_base, m_acpi_base + 0xff);
+ // shutms11 BIOS POST maps this at $5000
+ m_acpi->map_device(memory_window_start, memory_window_end, 0, memory_space, io_window_start, io_window_end, m_acpi_base, io_space);
+ io_space->install_device(m_acpi_base | 0x80, m_acpi_base | 0xff, *m_smbus, &sis950_smbus_device::map);
+ }
+
+ // TODO: disable flash access write thru reg $45
+ // TODO: BIOS positive decode
+ // (bios_control bit 1), which should disable BIOS mapping to E and F segment
+
+ memory_space->install_device(0x000e0000, 0x000fffff, *this, &sis950_lpc_device::memory_map<3>);
+ // extended BIOS enable
+ if (m_bios_control & 1)
+ {
+ LOGMAP("- Extend BIOS on\n");
+ memory_space->install_device(0xfff80000, 0xfff9ffff, *this, &sis950_lpc_device::memory_map<0>);
+ memory_space->install_device(0xfffa0000, 0xfffbffff, *this, &sis950_lpc_device::memory_map<1>);
+ memory_space->install_device(0xfffc0000, 0xfffdffff, *this, &sis950_lpc_device::memory_map<2>);
+ }
+ memory_space->install_device(0xfffe0000, 0xffffffff, *this, &sis950_lpc_device::memory_map<3>);
+}
+
+u8 sis950_lpc_device::lpc_fast_init_r()
+{
+ LOGLPC("LPC fast init read [$92]\n");
+ return m_lpc_legacy.fast_init;
+}
+
+void sis950_lpc_device::lpc_fast_init_w(offs_t offset, u8 data)
+{
+ LOGLPC("LPC fast init write [$92] %02x\n", data);
+ if (data & 0xfd)
+ LOG("Warning: unemulated LPC fast init type %02x", data);
+
+ // TODO: pinpoint exact disable INIT condition and if that will be reflected on reading reg too
+ m_host_cpu->set_input_line(INPUT_LINE_A20, BIT(data, 1));
+
+ m_lpc_legacy.fast_init = data;
+}
+
+/*
+ * Debugging
+ */
+u8 sis950_lpc_device::unmap_log_r(offs_t offset)
+{
+ LOGTODO("LPC Unemulated [%02x] R\n", offset + 0x10);
+ return 0;
+}
+
+void sis950_lpc_device::unmap_log_w(offs_t offset, u8 data)
+{
+ LOGTODO("LPC Unemulated [%02x] %02x W\n", offset + 0x10, data);
+}
+
+/*
+ * IRQ sharing
+ */
+
+void sis950_lpc_device::pc_irq1_w(int state) { m_pic_master->ir1_w(state); }
+void sis950_lpc_device::pc_irq3_w(int state) { m_pic_master->ir3_w(state); }
+void sis950_lpc_device::pc_irq4_w(int state) { m_pic_master->ir4_w(state); }
+void sis950_lpc_device::pc_irq5_w(int state) { m_pic_master->ir5_w(state); }
+void sis950_lpc_device::pc_irq6_w(int state) { m_pic_master->ir6_w(state); }
+void sis950_lpc_device::pc_irq7_w(int state) { m_pic_master->ir7_w(state); }
+void sis950_lpc_device::pc_irq8n_w(int state) { m_pic_slave->ir0_w(state); }
+void sis950_lpc_device::pc_irq9_w(int state) { m_pic_slave->ir1_w(state); }
+void sis950_lpc_device::pc_irq10_w(int state) { m_pic_slave->ir2_w(state); }
+void sis950_lpc_device::pc_irq11_w(int state) { m_pic_slave->ir3_w(state); }
+void sis950_lpc_device::pc_irq12m_w(int state) { m_pic_slave->ir4_w(state); }
+void sis950_lpc_device::pc_irq14_w(int state) { m_pic_slave->ir6_w(state); }
+void sis950_lpc_device::pc_irq15_w(int state) { m_pic_slave->ir7_w(state); }
+
+/*
+ * Start of legacy handling, to be moved out
+ */
+
+void sis950_lpc_device::pit_out0(int state)
+{
+ m_pic_master->ir0_w(state);
+}
+
+void sis950_lpc_device::pit_out1(int state)
+{
+ if(state)
+ m_refresh = !m_refresh;
+}
+
+void sis950_lpc_device::pit_out2(int state)
+{
+ m_pit_out2 = state ? 1 : 0;
+ m_speaker->level_w(m_at_spkrdata & m_pit_out2);
+}
+
+/*
+ * x--- ---- Set if a PCI device or main memory module asserts PERR#/SERR# line
+ * -x-- ---- Set when IOCHK# is asserted on ISA bus
+ * --x- ---- Counter 2 out signal state (PIT ch. 2)
+ * ---x ---- Refresh bit toggle (PIT ch. 1)
+ * ---- xxxx <reads back NMI control enable>
+ */
+uint8_t sis950_lpc_device::nmi_status_r()
+{
+ uint8_t data = m_at_speaker;
+ data &= ~0xd0; // AT BIOS don't likes this being set
+
+ data |= m_refresh ? 0x10 : 0;
+
+ if (m_pit_out2)
+ data |= 0x20;
+ else
+ data &= ~0x20; // ps2m30 wants this
+
+ return data;
+}
+
+void sis950_lpc_device::at_speaker_set_spkrdata(uint8_t data)
+{
+ m_at_spkrdata = data ? 1 : 0;
+ m_speaker->level_w(m_at_spkrdata & m_pit_out2);
+}
+
+/*
+ * xxxx ---- <must be zero when writing to this port>
+ * ---- x--- (0) enable IOCHK# NMI (1) clear and disable IOCHK# NMI
+ * ---- -x-- (0) enable PCI SERR# (1) clear and disable PCI SERR#
+ * ---- --x- Speaker output enable
+ * ---- ---x Timer counter 2 enable
+ */
+void sis950_lpc_device::nmi_control_w(uint8_t data)
+{
+ m_at_speaker = data;
+ m_pit->write_gate2(BIT(data, 0));
+ at_speaker_set_spkrdata(BIT(data, 1));
+ m_channel_check = BIT(data, 3);
+ if (m_channel_check)
+ m_host_cpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+}
+
+void sis950_lpc_device::rtc_index_w(uint8_t data)
+{
+ m_rtc_index = data & 0x7f;
+ // bit 7: NMI enable
+}
+
+u8 sis950_lpc_device::rtc_data_r()
+{
+ const u8 rtc_address = m_rtc_index | (m_rtc_reg & 0x80);
+ return m_rtc->read_direct(rtc_address);
+}
+
+void sis950_lpc_device::rtc_data_w(u8 data)
+{
+ const u8 rtc_address = m_rtc_index | (m_rtc_reg & 0x80);
+ m_rtc->write_direct(rtc_address, data);
+}
+
+uint8_t sis950_lpc_device::at_page8_r(offs_t offset)
+{
+ uint8_t 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;
+}
+
+
+void sis950_lpc_device::at_page8_w(offs_t offset, uint8_t data)
+{
+ m_at_pages[offset % 0x10] = data;
+
+ switch(offset % 8)
+ {
+ case 0:
+ // matches boot_state_infos_phoenix
+ //m_boot_state_hook((offs_t)0, data);
+ break;
+ 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;
+ }
+}
+
+void sis950_lpc_device::pc_dma_hrq_changed(int state)
+{
+ m_host_cpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ // Assert HLDA
+ m_dmac_slave->hack_w( state );
+}
+
+void sis950_lpc_device::iochck_w(int state)
+{
+// if (!state && !m_channel_check && m_nmi_enabled)
+ if (!state && !m_channel_check)
+ m_host_cpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
+}
+
+uint8_t sis950_lpc_device::pc_dma_read_byte(offs_t offset)
+{
+ address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return 0xff;
+ uint8_t result;
+ offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;
+
+ result = prog_space.read_byte(page_offset + offset);
+ return result;
+}
+
+
+void sis950_lpc_device::pc_dma_write_byte(offs_t offset, uint8_t data)
+{
+ address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return;
+ offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;
+
+ prog_space.write_byte(page_offset + offset, data);
+}
+
+
+uint8_t sis950_lpc_device::pc_dma_read_word(offs_t offset)
+{
+ address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return 0xff;
+ uint16_t result;
+ offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;
+
+ result = prog_space.read_word((page_offset & 0xfe0000) | (offset << 1));
+ m_dma_high_byte = result & 0xFF00;
+
+ return result & 0xFF;
+}
+
+
+void sis950_lpc_device::pc_dma_write_word(offs_t offset, uint8_t data)
+{
+ address_space& prog_space = m_host_cpu->space(AS_PROGRAM); // get the right address space
+ if(m_dma_channel == -1)
+ return;
+ offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;
+
+ prog_space.write_word((page_offset & 0xfe0000) | (offset << 1), m_dma_high_byte | data);
+}
diff --git a/src/devices/machine/sis950_lpc.h b/src/devices/machine/sis950_lpc.h
new file mode 100644
index 00000000000..286241a8c25
--- /dev/null
+++ b/src/devices/machine/sis950_lpc.h
@@ -0,0 +1,189 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_SIS950_LPC_H
+#define MAME_MACHINE_SIS950_LPC_H
+
+#pragma once
+
+#include "pci.h"
+
+#include "bus/ata/ataintf.h"
+#include "bus/isa/isa.h"
+#include "lpc-acpi.h"
+#include "sis950_smbus.h"
+
+#include "cpu/i386/i386.h"
+
+#include "bus/pc_kbd/pc_kbdc.h"
+#include "machine/at_keybc.h"
+#include "machine/am9517a.h"
+#include "machine/ds128x.h"
+#include "machine/intelfsh.h"
+#include "machine/pc_lpt.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "machine/ram.h"
+#include "machine/nvram.h"
+
+#include "sound/spkrdev.h"
+
+
+class sis950_lpc_device : public pci_device
+{
+public:
+ template <typename T, typename U> sis950_lpc_device(
+ const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
+ T &&cpu_tag, U &&flash_tag
+ ) : sis950_lpc_device(mconfig, tag, owner, clock)
+ {
+ // Revision 0 -> A0
+ set_ids(0x10390008, 0x00, 0x060100, 0x00);
+ //set_multifunction_device(true);
+ m_host_cpu.set_tag(std::forward<T>(cpu_tag));
+ m_flash_rom.set_tag(std::forward<U>(flash_tag));
+ }
+
+ sis950_lpc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ static constexpr feature_type unemulated_features() { return feature::MOUSE; }
+
+ auto fast_reset_cb() { return m_fast_reset_cb.bind(); }
+
+ void pc_irq1_w(int state);
+ void pc_irq3_w(int state);
+ void pc_irq4_w(int state);
+ void pc_irq5_w(int state);
+ void pc_irq6_w(int state);
+ void pc_irq7_w(int state);
+ void pc_irq8n_w(int state);
+ void pc_irq9_w(int state);
+ void pc_irq10_w(int state);
+ void pc_irq11_w(int state);
+ void pc_irq12m_w(int state);
+ void pc_irq14_w(int state);
+ void pc_irq15_w(int state);
+
+protected:
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_config_complete() override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ template <unsigned N> void memory_map(address_map &map);
+ void io_map(address_map &map);
+
+ virtual bool map_first() const override { return true; }
+
+private:
+ required_device<cpu_device> m_host_cpu;
+ required_device<intelfsh8_device> m_flash_rom;
+ required_device<pic8259_device> m_pic_master;
+ required_device<pic8259_device> m_pic_slave;
+ required_device<am9517a_device> m_dmac_master;
+ required_device<am9517a_device> m_dmac_slave;
+ required_device<pit8254_device> m_pit;
+ required_device<ps2_keyboard_controller_device> m_keybc;
+ required_device<isa16_device> m_isabus;
+ required_device<speaker_sound_device> m_speaker;
+ required_device<ds12885ext_device> m_rtc;
+ required_device<pc_kbdc_device> m_ps2_con;
+ required_device<pc_kbdc_device> m_aux_con;
+ required_device<lpc_acpi_device> m_acpi;
+ required_device<sis950_smbus_device> m_smbus;
+
+ devcb_write_line m_fast_reset_cb;
+
+ // PCI interface
+ u8 bios_control_r();
+ void bios_control_w(u8 data);
+ u8 flash_ctrl_r();
+ void flash_ctrl_w(u8 data);
+ u8 acpi_base_r();
+ void acpi_base_w(u8 data);
+ u8 init_enable_r();
+ void init_enable_w(u8 data);
+ u8 keybc_reg_r();
+ void keybc_reg_w(u8 data);
+ u8 rtc_reg_r();
+ void rtc_reg_w(u8 data);
+ void rtc_index_w(u8 data);
+ u8 rtc_data_r();
+ void rtc_data_w(u8 data);
+ template <unsigned N> u8 irq_remap_r();
+ template <unsigned N> void irq_remap_w(u8 data);
+ u8 unmap_log_r(offs_t offset);
+ void unmap_log_w(offs_t offset, u8 data);
+
+ u8 m_bios_control = 0;
+ u8 m_flash_control = 0;
+ u16 m_acpi_base = 0x0000;
+ u8 m_init_reg = 0;
+ u8 m_keybc_reg = 0;
+ u8 m_rtc_reg = 0;
+ u8 m_rtc_index = 0;
+
+ enum {
+ IRQ_INTA = 0,
+ IRQ_INTB,
+ IRQ_INTC,
+ IRQ_INTD,
+ IRQ_IDE,
+ IRQ_GPE,
+ // or SCI
+ IRQ_ACPI,
+ IRQ_SMBUS,
+ IRQ_SWDOG
+ };
+ u8 m_irq_remap[9]{};
+
+ // LPC vendor specific, verify if it's common for all
+ u8 lpc_fast_init_r();
+ void lpc_fast_init_w(offs_t offset, u8 data);
+ struct {
+ u8 fast_init;
+ } m_lpc_legacy;
+
+ // southbridge implementation
+ void pit_out0(int state);
+ void pit_out1(int state);
+ void pit_out2(int state);
+ uint8_t pc_dma_read_byte(offs_t offset);
+ void pc_dma_write_byte(offs_t offset, uint8_t data);
+ uint8_t pc_dma_read_word(offs_t offset);
+ void pc_dma_write_word(offs_t offset, uint8_t data);
+ void pc_dma_hrq_changed(int state);
+ void pc_select_dma_channel(int channel, bool state);
+
+ uint8_t m_at_pages[0x10]{};
+ uint8_t m_dma_offset[2][4]{};
+ uint8_t m_at_speaker = 0;
+ uint8_t m_refresh = 0;
+ bool m_pit_out2 = 0;
+ bool m_at_spkrdata = 0;
+ uint8_t m_channel_check = 0;
+ int m_dma_channel = -1;
+// bool m_cur_eop = false;
+ uint16_t m_dma_high_byte = 0;
+
+ void cpu_a20_w(int state);
+ void cpu_reset_w(int state);
+
+ uint8_t at_page8_r(offs_t offset);
+ void at_page8_w(offs_t offset, uint8_t data);
+ u8 nmi_status_r();
+ void nmi_control_w(uint8_t data);
+ void at_speaker_set_spkrdata(uint8_t data);
+ void iochck_w(int state);
+};
+
+DECLARE_DEVICE_TYPE(SIS950_LPC, sis950_lpc_device)
+
+
+#endif
diff --git a/src/devices/machine/sis950_smbus.cpp b/src/devices/machine/sis950_smbus.cpp
new file mode 100644
index 00000000000..b96898cbbe0
--- /dev/null
+++ b/src/devices/machine/sis950_smbus.cpp
@@ -0,0 +1,108 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/**************************************************************************************************
+
+ SiS 950 SMBus implementation
+
+ TODO:
+ - Stub, needs an smbus_interface, bare minimum to make shutms11 happy;
+
+**************************************************************************************************/
+#include "emu.h"
+#include "sis950_smbus.h"
+
+#define LOG_CMD (1U << 1) // log commands
+
+#define VERBOSE (LOG_GENERAL | LOG_CMD)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(SIS950_SMBUS, sis950_smbus_device, "sis950_smbus", "SiS950 SMBus interface")
+
+void sis950_smbus_device::map(address_map &map)
+{
+ map(0x00, 0x00).rw(FUNC(sis950_smbus_device::smb_sts_r), FUNC(sis950_smbus_device::smb_sts_w));
+
+ map(0x03, 0x03).rw(FUNC(sis950_smbus_device::smbhost_cnt_r), FUNC(sis950_smbus_device::smbhost_cnt_w));
+
+#if 0
+ map(0x02, 0x02).rw(FUNC(sis950_smbus_device::hst_cnt_r), FUNC(sis950_smbus_device::hst_cnt_w));
+ map(0x03, 0x03).rw(FUNC(sis950_smbus_device::hst_cmd_r), FUNC(sis950_smbus_device::hst_cmd_w));
+ map(0x04, 0x04).rw(FUNC(sis950_smbus_device::xmit_slva_r), FUNC(sis950_smbus_device::xmit_slva_w));
+ map(0x05, 0x05).rw(FUNC(sis950_smbus_device::hst_d0_r), FUNC(sis950_smbus_device::hst_d0_w));
+ map(0x06, 0x06).rw(FUNC(sis950_smbus_device::hst_d1_r), FUNC(sis950_smbus_device::hst_d1_w));
+ map(0x07, 0x07).rw(FUNC(sis950_smbus_device::host_block_db_r), FUNC(sis950_smbus_device::host_block_db_w));
+ map(0x08, 0x08).rw(FUNC(sis950_smbus_device::pec_r), FUNC(sis950_smbus_device::pec_w));
+ map(0x09, 0x09).rw(FUNC(sis950_smbus_device::rcv_slva_r), FUNC(sis950_smbus_device::rcv_slva_w));
+ map(0x0a, 0x0b).rw(FUNC(sis950_smbus_device::slv_data_r), FUNC(sis950_smbus_device::slv_data_w));
+ map(0x0c, 0x0c).rw(FUNC(sis950_smbus_device::aux_sts_r), FUNC(sis950_smbus_device::aux_sts_w));
+ map(0x0d, 0x0d).rw(FUNC(sis950_smbus_device::aux_ctl_r), FUNC(sis950_smbus_device::aux_ctl_w));
+ map(0x0e, 0x0e).rw(FUNC(sis950_smbus_device::smlink_pin_ctl_r), FUNC(sis950_smbus_device::smlink_pin_ctl_w));
+ map(0x0f, 0x0f).rw(FUNC(sis950_smbus_device::smbus_pin_ctl_r), FUNC(sis950_smbus_device::smbus_pin_ctl_w));
+ map(0x10, 0x10).rw(FUNC(sis950_smbus_device::slv_sts_r), FUNC(sis950_smbus_device::slv_sts_w));
+ map(0x11, 0x11).rw(FUNC(sis950_smbus_device::slv_cmd_r), FUNC(sis950_smbus_device::slv_cmd_w));
+ map(0x14, 0x14).r(FUNC(sis950_smbus_device::notify_daddr_r));
+ map(0x16, 0x16).r(FUNC(sis950_smbus_device::notify_dlow_r));
+ map(0x17, 0x17).r(FUNC(sis950_smbus_device::notify_dhigh_r));
+#endif
+}
+
+sis950_smbus_device::sis950_smbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SIS950_SMBUS, tag, owner, clock)
+{
+}
+
+void sis950_smbus_device::device_start()
+{
+
+}
+
+void sis950_smbus_device::device_reset()
+{
+
+}
+
+u8 sis950_smbus_device::smb_sts_r()
+{
+ LOGCMD("%s: smb_sts_r (%02x)\n", tag(), m_status);
+
+ return m_status;
+}
+
+void sis950_smbus_device::smb_sts_w(u8 data)
+{
+ m_status &= ~data;
+ LOGCMD("%s: smb_sts_w = %02x\n", tag(), data);
+}
+
+// reads back bits 0-2 only
+u8 sis950_smbus_device::smbhost_cnt_r()
+{
+ return m_cmd;
+}
+
+/*
+ * --x- ---- kill (reset state, TODO)
+ * ---x ---- start transaction
+ * ---- -xxx command protocol
+ * ---- -000 quick command
+ * ---- -001 send/receive byte
+ * ---- -010 read/write byte data
+ * ---- -011 read/write word data
+ * ---- -100 process call
+ * ---- -101 read/write block data
+ * ---- -11x <reserved>
+ */
+void sis950_smbus_device::smbhost_cnt_w(u8 data)
+{
+ m_cmd = data & 7;
+ LOGCMD("%s: smbhost_cnt_w = %02x\n", tag(), data);
+
+ // TODO: process commands properly
+ // For now we just reflect shutms11 wanting bit 3 on after each transaction
+ if (BIT(data, 4))
+ m_status |= 8;
+}
diff --git a/src/devices/machine/sis950_smbus.h b/src/devices/machine/sis950_smbus.h
new file mode 100644
index 00000000000..a474fe10914
--- /dev/null
+++ b/src/devices/machine/sis950_smbus.h
@@ -0,0 +1,32 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+
+#ifndef MAME_MACHINE_SIS950_SMBUS_H
+#define MAME_MACHINE_SIS950_SMBUS_H
+
+#include "emu.h"
+
+class sis950_smbus_device : public device_t {
+public:
+
+ sis950_smbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void map(address_map &map);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ u8 smb_sts_r();
+ void smb_sts_w(u8 data);
+ u8 smbhost_cnt_r();
+ void smbhost_cnt_w(u8 data);
+
+ u8 m_status = 0;
+ u8 m_cmd = 0;
+};
+
+DECLARE_DEVICE_TYPE(SIS950_SMBUS, sis950_smbus_device)
+
+#endif // MAME_MACHINE_PCI_SMBUS_H
diff --git a/src/devices/machine/smartboard.cpp b/src/devices/machine/smartboard.cpp
new file mode 100644
index 00000000000..d699b1306df
--- /dev/null
+++ b/src/devices/machine/smartboard.cpp
@@ -0,0 +1,336 @@
+// license:BSD-3-Clause
+// copyright-holders:Sandro Ronco, hap
+/******************************************************************************
+
+Tasc SmartBoard SB30 (analog)
+
+Chessboard controller for use with Tasc R30 chesscomputer, or as PC peripheral.
+
+The SmartBoard can detect which piece is present on a specific square, more
+info on the technology used in the piece recognition system can be found in
+the US patent 5,129,654
+
+SmartBoard I is SB30 (81 LEDs, analog chesspieces)
+SmartBoard II is SB20 (64 LEDs, digital chesspieces)
+SmartBoard III is SB30 again, but digital
+
+SB20 and the newer SB30 are not emulated. They're on different hardware, with
+embedded CPU to reduce I/O overhead. Note, those are not compatible with old
+versions of Tasc R30.
+
+******************************************************************************/
+
+#include "emu.h"
+#include "smartboard.h"
+
+// SB30 chesspiece IDs: 0-31 (+1 for MAME sensorboard_device)
+enum
+{
+ SB30_WHITE_KNIGHT1 = 1,
+ SB30_WHITE_KNIGHT2,
+ SB30_BLACK_KING,
+ SB30_WHITE_KING,
+ SB30_BLACK_QUEEN,
+ SB30_WHITE_QUEEN,
+ SB30_BLACK_ROOK1,
+ SB30_BLACK_ROOK2,
+ SB30_WHITE_ROOK1,
+ SB30_WHITE_ROOK2,
+ SB30_BLACK_BISHOP1,
+ SB30_BLACK_BISHOP2,
+ SB30_WHITE_BISHOP1,
+ SB30_WHITE_BISHOP2,
+ SB30_BLACK_KNIGHT1,
+ SB30_BLACK_KNIGHT2,
+ SB30_WHITE_PAWN1,
+ SB30_WHITE_PAWN2,
+ SB30_WHITE_PAWN3,
+ SB30_WHITE_PAWN4,
+ SB30_WHITE_PAWN5,
+ SB30_WHITE_PAWN6,
+ SB30_WHITE_PAWN7,
+ SB30_WHITE_PAWN8,
+ SB30_BLACK_PAWN1,
+ SB30_BLACK_PAWN2,
+ SB30_BLACK_PAWN3,
+ SB30_BLACK_PAWN4,
+ SB30_BLACK_PAWN5,
+ SB30_BLACK_PAWN6,
+ SB30_BLACK_PAWN7,
+ SB30_BLACK_PAWN8
+};
+
+
+DEFINE_DEVICE_TYPE(TASC_SB30, tasc_sb30_device, "tasc_sb30", "Tasc SmartBoard SB30")
+
+//-------------------------------------------------
+// tasc_sb30_device - constructor
+//-------------------------------------------------
+
+tasc_sb30_device::tasc_sb30_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, TASC_SB30, tag, owner, clock)
+ , m_board(*this, "board")
+ , m_out_leds(*this, "sb30_led_%u.%u", 0U, 0U)
+ , m_conf(*this, "CONF")
+ , m_data_out(*this)
+ , m_led_out(*this)
+{ }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tasc_sb30_device::device_start()
+{
+ if (m_led_out.isunset())
+ m_out_leds.resolve();
+
+ // zerofill
+ m_data0 = 0;
+ m_data1 = 0;
+ m_output = 0;
+ m_scan_pending = false;
+ m_pos = 0;
+ std::fill_n(m_squares, std::size(m_squares), 0);
+
+ // register for savestates
+ save_item(NAME(m_data0));
+ save_item(NAME(m_data1));
+ save_item(NAME(m_output));
+ save_item(NAME(m_scan_pending));
+ save_item(NAME(m_pos));
+ save_item(NAME(m_squares));
+}
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( smartboard )
+ PORT_START("CONF")
+ PORT_CONFNAME( 0x01, 0x00, "Duplicate Piece IDs" )
+ PORT_CONFSETTING( 0x00, DEF_STR( No ) )
+ PORT_CONFSETTING( 0x01, DEF_STR( Yes ) )
+INPUT_PORTS_END
+
+ioport_constructor tasc_sb30_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(smartboard);
+}
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device-specific
+// machine configuration
+//-------------------------------------------------
+
+void tasc_sb30_device::device_add_mconfig(machine_config &config)
+{
+ SENSORBOARD(config, m_board);
+ m_board->set_type(sensorboard_device::INDUCTIVE);
+ m_board->set_max_id(32);
+ m_board->init_cb().set(FUNC(tasc_sb30_device::init_cb));
+ m_board->spawn_cb().set(FUNC(tasc_sb30_device::spawn_cb));
+}
+
+
+//-------------------------------------------------
+// sensorboard_device interface
+//-------------------------------------------------
+
+void tasc_sb30_device::init_cb(u8 data)
+{
+ m_board->clear_board();
+ m_board->write_piece(0, 0, SB30_WHITE_ROOK1);
+ m_board->write_piece(7, 0, SB30_WHITE_ROOK2);
+ m_board->write_piece(1, 0, SB30_WHITE_KNIGHT1);
+ m_board->write_piece(6, 0, SB30_WHITE_KNIGHT2);
+ m_board->write_piece(2, 0, SB30_WHITE_BISHOP1);
+ m_board->write_piece(5, 0, SB30_WHITE_BISHOP2);
+ m_board->write_piece(3, 0, SB30_WHITE_QUEEN);
+ m_board->write_piece(4, 0, SB30_WHITE_KING);
+ m_board->write_piece(0, 7, SB30_BLACK_ROOK1);
+ m_board->write_piece(7, 7, SB30_BLACK_ROOK2);
+ m_board->write_piece(1, 7, SB30_BLACK_KNIGHT1);
+ m_board->write_piece(6, 7, SB30_BLACK_KNIGHT2);
+ m_board->write_piece(2, 7, SB30_BLACK_BISHOP1);
+ m_board->write_piece(5, 7, SB30_BLACK_BISHOP2);
+ m_board->write_piece(3, 7, SB30_BLACK_QUEEN);
+ m_board->write_piece(4, 7, SB30_BLACK_KING);
+
+ for (int x = 0; x < 8; x++)
+ {
+ m_board->write_piece(x, 1, SB30_WHITE_PAWN1 + x);
+ m_board->write_piece(x, 6, SB30_BLACK_PAWN1 + x);
+ }
+}
+
+bool tasc_sb30_device::piece_available(u8 id)
+{
+ for (int y = 0; y < 8; y++)
+ for (int x = 0; x < 8; x++)
+ {
+ if (m_board->read_piece(x, y) == id)
+ return bool(m_conf->read() & 1);
+ }
+
+ return true;
+}
+
+u8 tasc_sb30_device::spawn_cb(offs_t offset)
+{
+ int piece_id = 0;
+
+ // While most software works fine as long as color and piece type can be distinguished,
+ // each individual chesspiece is expected to have a unique id.
+ switch (offset)
+ {
+ case 1+0:
+ for (int p = 0; p < 8; p++)
+ if (piece_available(SB30_WHITE_PAWN1 + p))
+ {
+ piece_id = SB30_WHITE_PAWN1 + p;
+ break;
+ }
+ break;
+
+ case 1+6:
+ for (int p = 0; p < 8; p++)
+ if (piece_available(SB30_BLACK_PAWN1 + p))
+ {
+ piece_id = SB30_BLACK_PAWN1 + p;
+ break;
+ }
+ break;
+
+ case 2+0:
+ if (piece_available(SB30_WHITE_KNIGHT1))
+ piece_id = SB30_WHITE_KNIGHT1;
+ else if (piece_available(SB30_WHITE_KNIGHT2))
+ piece_id = SB30_WHITE_KNIGHT2;
+ break;
+
+ case 2+6:
+ if (piece_available(SB30_BLACK_KNIGHT1))
+ piece_id = SB30_BLACK_KNIGHT1;
+ else if (piece_available(SB30_BLACK_KNIGHT2))
+ piece_id = SB30_BLACK_KNIGHT2;
+ break;
+
+ case 3+0:
+ if (piece_available(SB30_WHITE_BISHOP1))
+ piece_id = SB30_WHITE_BISHOP1;
+ else if (piece_available(SB30_WHITE_BISHOP2))
+ piece_id = SB30_WHITE_BISHOP2;
+ break;
+
+ case 3+6:
+ if (piece_available(SB30_BLACK_BISHOP1))
+ piece_id = SB30_BLACK_BISHOP1;
+ else if (piece_available(SB30_BLACK_BISHOP2))
+ piece_id = SB30_BLACK_BISHOP2;
+ break;
+
+ case 4+0:
+ if (piece_available(SB30_WHITE_ROOK1))
+ piece_id = SB30_WHITE_ROOK1;
+ else if (piece_available(SB30_WHITE_ROOK2))
+ piece_id = SB30_WHITE_ROOK2;
+ break;
+
+ case 4+6:
+ if (piece_available(SB30_BLACK_ROOK1))
+ piece_id = SB30_BLACK_ROOK1;
+ else if (piece_available(SB30_BLACK_ROOK2))
+ piece_id = SB30_BLACK_ROOK2;
+ break;
+
+ case 5+0:
+ if (piece_available(SB30_WHITE_QUEEN))
+ piece_id = SB30_WHITE_QUEEN;
+ break;
+
+ case 5+6:
+ if (piece_available(SB30_BLACK_QUEEN))
+ piece_id = SB30_BLACK_QUEEN;
+ break;
+
+ case 6+0:
+ if (piece_available(SB30_WHITE_KING))
+ piece_id = SB30_WHITE_KING;
+ break;
+
+ case 6+6:
+ if (piece_available(SB30_BLACK_KING))
+ piece_id = SB30_BLACK_KING;
+ break;
+
+ default:
+ break;
+ }
+
+ return piece_id;
+}
+
+
+//-------------------------------------------------
+// I/O handlers
+//-------------------------------------------------
+
+void tasc_sb30_device::data0_w(int state)
+{
+ state = state ? 1 : 0;
+
+ if (!state && m_data0)
+ {
+ if (m_scan_pending)
+ {
+ for (int i = 0; i < 64; i++)
+ {
+ // each piece is identified by a single bit in a 32-bit sequence
+ int piece_id = m_board->read_sensor(i >> 3 ^ 7, ~i & 7);
+ m_squares[i] = piece_id ? (1 << (piece_id - 1)) : 0;
+ }
+
+ m_scan_pending = false;
+ m_pos = 0;
+ update_output();
+ }
+ else
+ {
+ // output board led(s)
+ if (m_led_out.isunset())
+ m_out_leds[m_pos & 7][m_pos >> 3 & 7] = m_data1;
+ else
+ m_led_out(m_pos & 0x3f, m_data1);
+ }
+ }
+
+ m_data0 = state;
+}
+
+void tasc_sb30_device::data1_w(int state)
+{
+ state = state ? 1 : 0;
+
+ // clock position counter
+ if (!state && m_data1)
+ {
+ m_pos++;
+
+ if (m_data0)
+ m_scan_pending = true;
+
+ update_output();
+ }
+
+ m_data1 = state;
+}
+
+void tasc_sb30_device::update_output()
+{
+ m_output = BIT(m_squares[m_pos & 0x3f], m_pos >> 6 & 0x1f);
+ m_data_out(m_output);
+}
diff --git a/src/devices/machine/smartboard.h b/src/devices/machine/smartboard.h
new file mode 100644
index 00000000000..5258b154cc2
--- /dev/null
+++ b/src/devices/machine/smartboard.h
@@ -0,0 +1,63 @@
+// license:BSD-3-Clause
+// copyright-holders:Sandro Ronco, hap
+/*
+
+ Tasc SmartBoard SB30
+
+*/
+
+#ifndef MAME_MACHINE_SMARTBOARD_H
+#define MAME_MACHINE_SMARTBOARD_H
+
+#pragma once
+
+#include "machine/sensorboard.h"
+
+class tasc_sb30_device : public device_t
+{
+public:
+ tasc_sb30_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ // configuration helpers
+ auto data_out() { return m_data_out.bind(); } // data_r
+ auto led_out() { return m_led_out.bind(); } // optional, outputs to sb30_ledy.x when not used
+
+ // external read/write lines
+ void data0_w(int state);
+ void data1_w(int state);
+ int data_r() { return m_output; }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+
+private:
+ required_device<sensorboard_device> m_board;
+ output_finder<8, 8> m_out_leds;
+ required_ioport m_conf;
+
+ devcb_write_line m_data_out;
+ devcb_write8 m_led_out;
+
+ void update_output();
+ bool piece_available(u8 id);
+ void init_cb(u8 data);
+ u8 spawn_cb(offs_t offset);
+
+ // i/o lines
+ int m_data0;
+ int m_data1;
+ int m_output;
+
+ // internal use
+ bool m_scan_pending;
+ u32 m_pos;
+ u32 m_squares[64]; // board state
+};
+
+
+DECLARE_DEVICE_TYPE(TASC_SB30, tasc_sb30_device)
+
+#endif // MAME_MACHINE_SMARTBOARD_H
diff --git a/src/devices/machine/smartmed.cpp b/src/devices/machine/smartmed.cpp
index 7e4153797f6..75473c8922d 100644
--- a/src/devices/machine/smartmed.cpp
+++ b/src/devices/machine/smartmed.cpp
@@ -14,6 +14,7 @@
TODO:
* support multi-plane mode?
* use HD-format images instead of our experimental custom format?
+ * better separation of SmartMedia image and NAND flash device
Raphael Nabet 2004
*/
@@ -21,6 +22,10 @@
#include "emu.h"
#include "smartmed.h"
+#include "softlist_dev.h"
+
+#include <tuple>
+
namespace {
@@ -35,16 +40,6 @@ inline uint32_t 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_t 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 */
struct SM_disk_image_header
{
@@ -71,77 +66,28 @@ enum
} // anonymous namespace
-
-DEFINE_DEVICE_TYPE(NAND, nand_device, "nand", "NAND Flash Memory")
-
-nand_device::nand_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nand_device(mconfig, NAND, tag, owner, clock)
-{
-}
-
-nand_device::nand_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock)
- , m_page_data_size(0)
- , m_page_total_size(0)
- , m_num_pages(0)
- , m_log2_pages_per_block(0)
- , m_pagereg(nullptr)
- , m_id_len(0)
- , m_col_address_cycles(0)
- , m_row_address_cycles(0)
- , m_sequential_row_read(0)
- , m_write_rnb(*this)
-{
- memset(m_id, 0, sizeof(m_id));
-}
-
-/*
- Init a SmartMedia image
-*/
-void nand_device::device_start()
-{
- m_data_ptr = nullptr;
- m_data_uid_ptr = nullptr;
- 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 = std::make_unique<uint8_t[]>(m_page_total_size);
-
-#ifdef SMARTMEDIA_IMAGE_SAVE
- m_image_format = 0;
-#endif
- m_write_rnb.resolve_safe();
-}
-
/*
Load a SmartMedia image
*/
-image_init_result smartmedia_image_device::smartmedia_format_1()
+std::error_condition smartmedia_image_device::smartmedia_format_1()
{
+ std::error_condition err;
+ size_t bytes_read;
+
SM_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_result::FAIL;
- }
+ std::tie(err, bytes_read) = read(image_core_file(), &custom_header, sizeof(custom_header));
+ if (err || (bytes_read != sizeof(custom_header)))
+ return err ? err : std::errc::io_error;
if (custom_header.version > 1)
- {
- return image_init_result::FAIL;
- }
+ return image_error::INVALIDIMAGE;
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_t, m_page_total_size*m_num_pages);
+ m_feeprom_data = std::make_unique<uint8_t[]>(m_page_total_size*m_num_pages);
m_data_uid_ptr = std::make_unique<uint8_t[]>(256 + 16);
m_mode = SM_M_INIT;
m_pointer_mode = SM_PM_A;
@@ -171,13 +117,16 @@ image_init_result smartmedia_image_device::smartmedia_format_1()
fread(&m_mp_opcode, 1);
fread(m_data_uid_ptr.get(), 256 + 16);
}
- fread(m_data_ptr, m_page_total_size*m_num_pages);
+
+ std::tie(err, m_feeprom_data, bytes_read) = read(image_core_file(), m_page_total_size * m_num_pages);
+ if (err || (bytes_read != (m_page_total_size * m_num_pages)))
+ return err ? err : std::errc::io_error;
#ifdef SMARTMEDIA_IMAGE_SAVE
m_image_format = 1;
#endif
- return image_init_result::PASS;
+ return std::error_condition();
}
int smartmedia_image_device::detect_geometry( uint8_t id1, uint8_t id2)
@@ -206,6 +155,7 @@ int smartmedia_image_device::detect_geometry( uint8_t id1, uint8_t id2)
{
switch (id2)
{
+ 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;
}
}
@@ -215,28 +165,24 @@ int smartmedia_image_device::detect_geometry( uint8_t id1, uint8_t id2)
return result;
}
-image_init_result smartmedia_image_device::smartmedia_format_2()
+std::error_condition smartmedia_image_device::smartmedia_format_2()
{
+ std::error_condition err;
+ size_t bytes_read;
+
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_result::FAIL;
- }
+ std::tie(err, bytes_read) = read(image_core_file(), &custom_header, sizeof(custom_header));
+ if (err || (bytes_read != sizeof(custom_header)))
+ return err ? err : std::errc::io_error;
if ((custom_header.data1[0] != 0xEC) && (custom_header.data1[0] != 0x98))
- {
- return image_init_result::FAIL;
- }
+ return image_error::INVALIDIMAGE;
if (!detect_geometry(custom_header.data1[0], custom_header.data1[1]))
- {
- return image_init_result::FAIL;
- }
+ return image_error::INVALIDIMAGE;
- m_data_ptr = auto_alloc_array(machine(), uint8_t, m_page_total_size*m_num_pages);
+ m_feeprom_data = std::make_unique<uint8_t[]>(m_page_total_size*m_num_pages);
m_data_uid_ptr = std::make_unique<uint8_t[]>(256 + 16);
m_mode = SM_M_INIT;
m_pointer_mode = SM_PM_A;
@@ -248,42 +194,44 @@ image_init_result smartmedia_image_device::smartmedia_format_2()
m_accumulated_status = 0;
m_pagereg = std::make_unique<uint8_t[]>(m_page_total_size);
m_id_len = 3;
- memcpy( m_id, custom_header.data1, m_id_len);
+ 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++)
+ for (int i = 0; i < 8; i++)
{
- memcpy( m_data_uid_ptr.get() + 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.get() + i * 32, custom_header.data2, 16);
+ for (int j = 0; j < 16; j++)
+ m_data_uid_ptr[i * 32 + 16 + j] = custom_header.data2[j] ^ 0xFF;
}
- memcpy( m_data_uid_ptr.get() + 256, custom_header.data3, 16);
+ memcpy(m_data_uid_ptr.get() + 256, custom_header.data3, 16);
- fread(m_data_ptr, m_page_total_size*m_num_pages);
+ std::tie(err, m_feeprom_data, bytes_read) = read(image_core_file(), m_page_total_size * m_num_pages);
+ if (err || (bytes_read != (m_page_total_size * m_num_pages)))
+ return err ? err : std::errc::io_error;
#ifdef SMARTMEDIA_IMAGE_SAVE
m_image_format = 2;
#endif
- return image_init_result::PASS;
+ return std::error_condition();
}
-image_init_result smartmedia_image_device::call_load()
+std::pair<std::error_condition, std::string> smartmedia_image_device::call_load()
{
- image_init_result result;
- uint64_t position;
+ std::error_condition result;
// try format 1
- position = ftell();
+ uint64_t const position = ftell();
result = smartmedia_format_1();
- if (result != image_init_result::PASS)
+ if (result)
{
- // try format 2
- fseek( position, SEEK_SET);
- result = smartmedia_format_2();
+ // try format 2
+ fseek(position, SEEK_SET);
+ result = smartmedia_format_2();
}
- return result;
+ return std::make_pair(result, std::string());
}
/*
@@ -297,27 +245,26 @@ void smartmedia_image_device::call_unload()
if (m_image_format == 1)
{
SM_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))
+ fseek(0, SEEK_SET);
+ const int 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);
+ fseek(2 + 1, SEEK_CUR);
+ fwrite(m_feeprom_data, 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);
+ fseek(3 + 1 + 256 + 16, SEEK_CUR);
+ fwrite(m_feeprom_data, 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);
+ fseek(sizeof(disk_image_format_2_header), SEEK_SET);
+ fwrite(m_feeprom_data, m_page_total_size * m_num_pages);
}
}
#endif
@@ -326,7 +273,7 @@ void smartmedia_image_device::call_unload()
m_page_total_size = 0;
m_num_pages = 0;
m_log2_pages_per_block = 0;
- m_data_ptr = nullptr;
+ m_feeprom_data = nullptr;
m_data_uid_ptr = nullptr;
m_mode = SM_M_INIT;
m_pointer_mode = SM_PM_A;
@@ -335,7 +282,7 @@ void smartmedia_image_device::call_unload()
m_status = 0xC0;
m_accumulated_status = 0;
m_pagereg = std::make_unique<uint8_t[]>(m_page_total_size);
- memset( m_id, 0, sizeof( m_id));
+ memset(m_id, 0, sizeof(m_id));
m_id_len = 0;
m_mp_opcode = 0;
m_mode_3065 = 0;
@@ -350,428 +297,17 @@ void smartmedia_image_device::call_unload()
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_t *)ptr;
-}
-
-/*
- write a byte to SmartMedia command port
-*/
-void nand_device::command_w(uint8_t 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_write_rnb.isnull())
- {
- m_write_rnb( 0);
- m_write_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.get(), 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_write_rnb.isnull())
- {
- m_write_rnb( 0);
- m_write_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_write_rnb.isnull())
- {
- m_write_rnb( 0);
- m_write_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_write_rnb.isnull())
- {
- m_write_rnb( 0);
- m_write_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_t 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_t nand_device::data_r()
-{
- uint8_t 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_t 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;
-}
-
-
DEFINE_DEVICE_TYPE(SMARTMEDIA, smartmedia_image_device, "smartmedia", "SmartMedia Flash card")
smartmedia_image_device::smartmedia_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: nand_device(mconfig, SMARTMEDIA, tag, owner, clock)
- , device_image_interface(mconfig, *this)
+ , device_memcard_image_interface(mconfig, *this)
+{
+ // SmartMedia images have been read only so keep it that way until someone puts more thought into this device
+ nvram_enable_backup(false);
+}
+
+const software_list_loader &smartmedia_image_device::get_software_list_loader() const
{
+ return image_software_list_loader::instance();
}
diff --git a/src/devices/machine/smartmed.h b/src/devices/machine/smartmed.h
index 708449cd36a..0799f8c1063 100644
--- a/src/devices/machine/smartmed.h
+++ b/src/devices/machine/smartmed.h
@@ -10,7 +10,8 @@
#pragma once
#include "formats/imageutl.h"
-#include "softlist_dev.h"
+#include "imagedev/memcard.h"
+#include "machine/nandflash.h"
//#define SMARTMEDIA_IMAGE_SAVE
@@ -19,212 +20,38 @@
TYPE DEFINITIONS
***************************************************************************/
-// ======================> nand_device
-class nand_device : public device_t
-{
-public:
- // "Sequential Row Read is available only on K9F5608U0D_Y,P,V,F or K9F5608D0D_Y,P"
- enum class chip
- {
- K9F5608U0D = 0, // K9F5608U0D
- K9F5608U0D_J, // K9F5608U0D-Jxxx
- K9F5608U0B, // K9F5608U0B
- K9F1G08U0B, // K9F1G08U0B
- K9LAG08U0M // K9LAG08U0M
- };
-
- // construction/destruction
- nand_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto rnb_wr_callback() { return m_write_rnb.bind(); }
-
- void set_nand_type(chip type)
- {
- switch (type)
- {
- case chip::K9F5608U0D:
- m_id_len = 2;
- m_id[0] = 0xec;
- m_id[1] = 0x75;
- m_page_data_size = 512;
- m_page_total_size = 512 + 16;
- m_log2_pages_per_block = compute_log2(32);
- m_num_pages = 32 * 2048;
- m_col_address_cycles = 1;
- m_row_address_cycles = 2;
- m_sequential_row_read = 1;
- break;
- case chip::K9F5608U0D_J:
- case chip::K9F5608U0B:
- m_id_len = 2;
- m_id[0] = 0xec;
- m_id[1] = 0x75;
- m_page_data_size = 512;
- m_page_total_size = 512 + 16;
- m_log2_pages_per_block = compute_log2(32);
- m_num_pages = 32 * 2048;
- m_col_address_cycles = 1;
- m_row_address_cycles = 2;
- m_sequential_row_read = 0;
- break;
- case chip::K9F1G08U0B:
- m_id_len = 5;
- m_id[0] = 0xec;
- m_id[1] = 0xf1;
- m_id[2] = 0x00;
- m_id[3] = 0x95;
- m_id[4] = 0x40;
- m_page_data_size = 2048;
- m_page_total_size = 2048 + 64;
- m_log2_pages_per_block = compute_log2(64);
- m_num_pages = 64 * 1024;
- m_col_address_cycles = 2;
- m_row_address_cycles = 2;
- m_sequential_row_read = 0;
- break;
- case chip::K9LAG08U0M:
- m_id_len = 5;
- m_id[0] = 0xec;
- m_id[1] = 0xd5;
- m_id[2] = 0x55;
- m_id[3] = 0x25;
- m_id[4] = 0x68;
- m_page_data_size = 2048;
- m_page_total_size = 2048 + 64;
- m_log2_pages_per_block = compute_log2(128);
- m_num_pages = 128 * 8192;
- m_col_address_cycles = 2;
- m_row_address_cycles = 3;
- m_sequential_row_read = 0;
- break;
- default:
- printf("Unknown NAND type!\n");
- 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_col_address_cycles = 0;
- m_row_address_cycles = 0;
- m_sequential_row_read = 0;
- break;
- }
- }
-
- int is_present();
- int is_protected();
- int is_busy();
-
- uint8_t data_r();
- void command_w(uint8_t data);
- void address_w(uint8_t data);
- void data_w(uint8_t data);
-
- void set_data_ptr(void *ptr);
-
-protected:
- 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
- };
-
- nand_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
-
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
- 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_t* m_data_ptr; // FEEPROM data area
- std::unique_ptr<uint8_t[]> 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
-
- std::unique_ptr<uint8_t[]> m_pagereg; // page register used by program command
- uint8_t m_id[5]; // chip ID
- uint8_t 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_write_line m_write_rnb;
-
-#ifdef SMARTMEDIA_IMAGE_SAVE
- int m_image_format;
-#endif
-};
-
-
-
-class smartmedia_image_device : public nand_device, public device_image_interface
+class smartmedia_image_device : public nand_device, public device_memcard_image_interface
{
public:
// construction/destruction
smartmedia_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- // image-level overrides
- virtual iodevice_t image_type() const noexcept override { return IO_MEMCARD; }
-
- virtual bool is_readable() const noexcept override { return true; }
- virtual bool is_writeable() const noexcept override { return true; }
+ // device_image_interface implementation
virtual bool is_creatable() const noexcept override { return false; }
- virtual bool must_be_loaded() const noexcept override { return false; }
virtual bool is_reset_on_load() const noexcept override { return false; }
virtual const char *image_interface() const noexcept override { return "sm_memc"; }
virtual const char *file_extensions() const noexcept override { return "smc"; }
- virtual image_init_result call_load() override;
+ virtual std::pair<std::error_condition, std::string> call_load() override;
virtual void call_unload() override;
+ // Because nand_device is a NVRAM device now, stub these to make it not do anything (read only)
+ virtual void nvram_default() override { }
+ virtual bool nvram_read(util::read_stream &file) override { return true; };
+ virtual bool nvram_write(util::write_stream &file) override { return false; };
+
protected:
- virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }
+ virtual const software_list_loader &get_software_list_loader() const override;
- image_init_result smartmedia_format_1();
- image_init_result smartmedia_format_2();
+ std::error_condition smartmedia_format_1();
+ std::error_condition smartmedia_format_2();
int detect_geometry(uint8_t id1, uint8_t id2);
+
+ uint8_t m_mp_opcode; // multi-plane operation code
};
// device type definition
-DECLARE_DEVICE_TYPE(NAND, nand_device)
DECLARE_DEVICE_TYPE(SMARTMEDIA, smartmedia_image_device)
#endif // MAME_MACHINE_SMARTMEDIA_H
diff --git a/src/devices/machine/smc91c9x.cpp b/src/devices/machine/smc91c9x.cpp
index 7d85deee42b..ea153bc2d58 100644
--- a/src/devices/machine/smc91c9x.cpp
+++ b/src/devices/machine/smc91c9x.cpp
@@ -10,14 +10,16 @@
#include "emu.h"
#include "smc91c9x.h"
-#include <sstream>
+
+#include "multibyte.h"
+
#include <iomanip>
+#include <sstream>
/***************************************************************************
DEBUGGING
***************************************************************************/
-#define LOG_GENERAL (1U << 0)
#define LOG_PACKETS (1U << 1)
#define LOG_TX (1U << 2)
#define LOG_RX (1U << 3)
@@ -62,7 +64,7 @@ smc91c96_device::smc91c96_device(const machine_config &mconfig, const char *tag,
smc91c9x_device::smc91c9x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dev_type device_type)
: device_t(mconfig, type, tag, owner, clock)
- , device_network_interface(mconfig, *this, 10.0f)
+ , device_network_interface(mconfig, *this, 10)
, m_device_type(device_type)
, m_num_ebuf(16)
, m_irq_handler(*this)
@@ -71,7 +73,6 @@ smc91c9x_device::smc91c9x_device(const machine_config &mconfig, device_type type
}
const u8 smc91c9x_device::ETH_BROADCAST[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-const u8 smc91c9x_device::WMS_OUI[] = { 0x00, 0xA0, 0xAF };
//-------------------------------------------------
// device_start - device-specific startup
@@ -83,9 +84,7 @@ void smc91c9x_device::device_start()
m_buffer = std::make_unique<u8[]>(ETHER_BUFFER_SIZE * m_num_ebuf);
// TX timer
- m_tx_poll = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(smc91c9x_device::tx_poll), this));
-
- m_irq_handler.resolve_safe();
+ m_tx_poll = timer_alloc(FUNC(smc91c9x_device::tx_poll), this);
// These registers don't get cleared on reset
m_reg[B1_CONFIG] = 0x0030; m_regmask[B1_CONFIG] = 0x17c6;
@@ -95,12 +94,19 @@ void smc91c9x_device::device_start()
m_reg[B1_IA2_3] = 0x0000; m_regmask[B1_IA2_3] = 0xffff;
m_reg[B1_IA4_5] = 0x0000; m_regmask[B1_IA4_5] = 0xffff;
- // Revision is set based on chip type
+ // Revision and MIR is based on chip type
m_regmask[B3_REVISION] = 0x0000;
+ m_regmask[B0_MIR] = 0x0000;
if (m_device_type == dev_type::SMC91C94)
+ {
m_reg[B3_REVISION] = 0x3345;
+ m_reg[B0_MIR] = 0x1212;
+ }
else if (m_device_type == dev_type::SMC91C96)
+ {
m_reg[B3_REVISION] = 0x3346;
+ m_reg[B0_MIR] = 0x1818;
+ }
else
fatalerror("device_start: Unknown device type\n");
@@ -147,13 +153,12 @@ void smc91c9x_device::device_reset()
m_rx_active = 0;
m_tx_retry_count = 0;
- m_reg[B0_TCR] = 0x0000; m_regmask[B0_TCR] = 0x3d87;
- m_reg[B0_EPH_STATUS] = 0x0000; m_regmask[B0_EPH_STATUS] = 0x0000;
+ m_reg[B0_TCR] = 0x0000; m_regmask[B0_TCR] = 0xbd87;
+ m_reg[B0_EPH_STATUS] = 0x4000; m_regmask[B0_EPH_STATUS] = 0x0000;
m_reg[B0_RCR] = 0x0000; m_regmask[B0_RCR] = 0xc307;
m_reg[B0_COUNTER] = 0x0000; m_regmask[B0_COUNTER] = 0x0000;
- m_reg[B0_MIR] = 0x1212; m_regmask[B0_MIR] = 0x0000;
m_reg[B0_MCR] = 0x3300; m_regmask[B0_MCR] = 0x00ff;
- m_reg[B0_BANK] = 0x3300; m_regmask[B0_BANK] = 0x0007;
+ m_reg[B0_BANK] = 0x3330; m_regmask[B0_BANK] = 0x0007;
m_reg[B1_GENERAL_PURP] = 0x0000; m_regmask[B1_GENERAL_PURP] = 0xffff;
m_reg[B1_CONTROL] = 0x0100; m_regmask[B1_CONTROL] = 0x68e7;
@@ -174,6 +179,8 @@ void smc91c9x_device::device_reset()
m_reg[B3_ERCV] = 0x331f; m_regmask[B3_ERCV] = 0x009f;
+ set_promisc(false);
+
update_ethernet_irq();
// Reset MMU
@@ -186,6 +193,10 @@ void smc91c9x_device::mmu_reset()
m_alloc_rx = 0;
m_alloc_tx = 0;
+ // The register defaults to the MEMORY SIZE upon reset or upon the RESET MMU command.
+ m_reg[B0_MIR] &= 0xff;
+ m_reg[B0_MIR] |= m_reg[B0_MIR] << 8;
+
// Reset fifos.
reset_tx_fifos();
reset_completed_rx();
@@ -394,16 +405,8 @@ int smc91c9x_device::recv_start_cb(u8 *buf, int length)
return 0;
}
- // discard packets not from WMS
- if (memcmp(WMS_OUI, &buf[6], 3))
- {
- LOGMASKED(LOG_RX, "received non-WMS packet OUI: %02x:%02x:%02x length %d discarded\n", buf[6], buf[7], buf[8], length);
-
- return 0;
- }
-
// Check for active transmission
- if (m_tx_active)
+ if (m_tx_active && !(m_reg[B0_TCR] & FDSE))
{
// TODO: Update collision counters
LOGMASKED(LOG_RX, "transmit active COLLISION, rx packet length %d discarded\n", length);
@@ -524,7 +527,7 @@ void smc91c9x_device::recv_complete_cb(int result)
TIMER_CALLBACK_MEMBER(smc91c9x_device::tx_poll)
{
// Check for active RX and delay if necessary
- if (m_rx_active)
+ if (m_rx_active && !(m_reg[B0_TCR] & FDSE))
{
// TODO: Implement correct CSMA/CD algorithm
m_tx_poll->adjust(attotime::from_usec(40));
@@ -557,13 +560,12 @@ TIMER_CALLBACK_MEMBER(smc91c9x_device::tx_poll)
tx_buffer[length++] = 0x00;
// Add CRC
- // TODO: Calculate CRC
- if (1 && ((control & EBUF_CRC) || !(m_reg[B0_TCR] & NOCRC)))
+ if (((control & EBUF_CRC) || !(m_reg[B0_TCR] & NOCRC)))
{
- tx_buffer[length++] = 0x11;
- tx_buffer[length++] = 0x22;
- tx_buffer[length++] = 0x33;
- tx_buffer[length++] = 0x44;
+ u32 crc = util::crc32_creator::simple(tx_buffer + 4, length - 4);
+
+ put_u32le(&tx_buffer[length], crc);
+ length += 4;
}
// Remove status, length
@@ -590,7 +592,7 @@ TIMER_CALLBACK_MEMBER(smc91c9x_device::tx_poll)
if (m_reg[B0_TCR] & (EPH_LOOP | LOOP))
send_complete_cb(length);
else
- send(&tx_buffer[4], length);
+ send(&tx_buffer[4], length, 4);
}
}
@@ -655,11 +657,19 @@ void smc91c9x_device::send_complete_cb(int result)
m_reg[B2_INTERRUPT] |= EINT_EPH;
}
- // Update status in the transmit word
- *(u16*)&tx_buffer[0] = m_reg[B0_EPH_STATUS];
+ if (m_reg[B1_CONTROL] & AUTO_RELEASE)
+ {
+ alloc_release(packet_num);
+ }
+ else
+ {
+ // Update status in the transmit word
+ *(u16*)&tx_buffer[0] = m_reg[B0_EPH_STATUS];
+
+ // Push the packet number onto the tx completion fifo
+ push_completed_tx(packet_num);
+ }
- // Push the packet number onto the tx completion fifo
- push_completed_tx(packet_num);
update_ethernet_irq();
@@ -841,7 +851,9 @@ u16 smc91c9x_device::read(offs_t offset, u16 mem_mask)
else
buffer = &m_buffer[(m_reg[B2_PNR_ARR] & 0x1f) * ETHER_BUFFER_SIZE];
- result = buffer[addr++];
+ result = 0;
+ if ( ACCESSING_BITS_0_7 )
+ result = buffer[addr++];
if ( ACCESSING_BITS_8_15 )
result |= buffer[addr++] << 8;
if ( m_reg[B2_POINTER] & 0x4000 )
@@ -872,8 +884,10 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask)
if (offset != B0_BANK && offset < sizeof(m_reg))
LOG("%s:smc91c9x_w(%s) = [%04X]<-%04X & (%04X & %04X)\n", machine().describe_context(), ethernet_regname[offset], offset, data, mem_mask , m_regmask[offset]);
+ const uint16_t old_reg = m_reg[offset];
mem_mask &= m_regmask[offset];
COMBINE_DATA(&m_reg[offset]);
+ const uint16_t new_reg = m_reg[offset];
/* handle it */
switch (offset)
@@ -911,7 +925,7 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask)
reset();
}
- if ( !(data & RXEN) )
+ if ( (old_reg & RXEN) && !(new_reg & RXEN))
{
reset_completed_rx();
}
@@ -921,6 +935,11 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask)
m_reg[B0_EPH_STATUS] |= LINK_OK;
}
+ if ((old_reg ^ new_reg) & PRMS)
+ {
+ set_promisc(new_reg & PRMS);
+ }
+
if (VERBOSE & LOG_GENERAL)
{
if (data & SOFT_RST) LOG(" SOFT RST\n");
@@ -951,14 +970,21 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask)
break;
case B1_IA4_5:
- set_promisc(m_reg[B0_RCR] & PRMS);
- set_mac((char *)&m_reg[B1_IA0_1]);
+ if ( ACCESSING_BITS_8_15 )
+ {
+ set_promisc(m_reg[B0_RCR] & PRMS);
+ u8 mac[6];
+ put_u16le(&mac[0], m_reg[B1_IA0_1]);
+ put_u16le(&mac[2], m_reg[B1_IA2_3]);
+ put_u16le(&mac[4], m_reg[B1_IA4_5]);
+ set_mac(mac);
+ }
break;
case B1_CONTROL: /* control register */
// Clearing LE_EN clears interrupt from LINK_OK status change
- if (!(data & LE_ENABLE))
+ if ( (old_reg & LE_ENABLE) && !(new_reg & LE_ENABLE))
{
m_reg[B2_INTERRUPT] &= ~EINT_EPH;
update_ethernet_irq();
@@ -1002,7 +1028,8 @@ void smc91c9x_device::write(offs_t offset, u16 data, u16 mem_mask)
else
buffer = &m_buffer[(m_reg[B2_PNR_ARR] & 0x1f) * ETHER_BUFFER_SIZE];
- buffer[addr++] = data;
+ if ( ACCESSING_BITS_0_7 )
+ buffer[addr++] = data;
if ( ACCESSING_BITS_8_15 )
buffer[addr++] = data >> 8;
if ( m_reg[B2_POINTER] & AUTO_INCR)
diff --git a/src/devices/machine/smc91c9x.h b/src/devices/machine/smc91c9x.h
index 541721eafc0..e1c91a3e566 100644
--- a/src/devices/machine/smc91c9x.h
+++ b/src/devices/machine/smc91c9x.h
@@ -13,6 +13,8 @@
#pragma once
+#include "dinetwork.h"
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -25,7 +27,7 @@ public:
u16 read(offs_t offset, u16 mem_mask = ~0);
void write(offs_t offset, u16 data, u16 mem_mask = ~0);
- void set_link_connected(bool connected) { m_link_unconnected = !connected; };
+ void set_link_connected(bool connected) { m_link_unconnected = !connected; }
protected:
enum class dev_type {
@@ -215,9 +217,9 @@ private:
PTR = 0x07ff
};
+ static constexpr u32 FCS_RESIDUE = 0xdebb20e3;
static constexpr unsigned ETHER_BUFFER_SIZE = 256 * 6;
static const u8 ETH_BROADCAST[];
- static const u8 WMS_OUI[];
// mmu
@@ -258,7 +260,7 @@ private:
int m_rx_active;
int m_tx_retry_count;
u8 m_rx_hash;
- u8 m_loopback_result;
+ int m_loopback_result;
void update_ethernet_irq();
void update_stats();
@@ -273,29 +275,29 @@ private:
// FIFO for allocated (queued) transmit packets
u8 m_queued_tx[FIFO_SIZE];
int m_queued_tx_h, m_queued_tx_t;
- void reset_queued_tx() { m_queued_tx_t = m_queued_tx_h = 0; };
- void push_queued_tx(const u8 &data) { m_queued_tx[m_queued_tx_h++] = data; m_queued_tx_h &= FIFO_SIZE - 1; };
- u8 pop_queued_tx() { u8 val = m_queued_tx[m_queued_tx_t++]; m_queued_tx_t &= FIFO_SIZE - 1; return val; };
- bool empty_queued_tx() const { return m_queued_tx_h == m_queued_tx_t; };
- u8 curr_queued_tx() const { return m_queued_tx[m_queued_tx_t]; };
+ void reset_queued_tx() { m_queued_tx_t = m_queued_tx_h = 0; }
+ void push_queued_tx(const u8 &data) { m_queued_tx[m_queued_tx_h++] = data; m_queued_tx_h &= FIFO_SIZE - 1; }
+ u8 pop_queued_tx() { u8 val = m_queued_tx[m_queued_tx_t++]; m_queued_tx_t &= FIFO_SIZE - 1; return val; }
+ bool empty_queued_tx() const { return m_queued_tx_h == m_queued_tx_t; }
+ u8 curr_queued_tx() const { return m_queued_tx[m_queued_tx_t]; }
// FIFO for completed transmit packets
u8 m_completed_tx[FIFO_SIZE];
int m_completed_tx_h, m_completed_tx_t;
- void reset_completed_tx() { m_completed_tx_t = m_completed_tx_h = 0; };
- void push_completed_tx(const u8 &data) { m_completed_tx[m_completed_tx_h++] = data; m_completed_tx_h &= FIFO_SIZE - 1; };
- u8 pop_completed_tx() { u8 val = m_completed_tx[m_completed_tx_t++]; m_completed_tx_t &= FIFO_SIZE - 1; return val; };
- bool empty_completed_tx() const { return m_completed_tx_h == m_completed_tx_t; };
- u8 curr_completed_tx() const { return m_completed_tx[m_completed_tx_t]; };
+ void reset_completed_tx() { m_completed_tx_t = m_completed_tx_h = 0; }
+ void push_completed_tx(const u8 &data) { m_completed_tx[m_completed_tx_h++] = data; m_completed_tx_h &= FIFO_SIZE - 1; }
+ u8 pop_completed_tx() { u8 val = m_completed_tx[m_completed_tx_t++]; m_completed_tx_t &= FIFO_SIZE - 1; return val; }
+ bool empty_completed_tx() const { return m_completed_tx_h == m_completed_tx_t; }
+ u8 curr_completed_tx() const { return m_completed_tx[m_completed_tx_t]; }
// FIFO for completed receive packets
u8 m_completed_rx[FIFO_SIZE];
int m_completed_rx_h, m_completed_rx_t;
- void reset_completed_rx() { m_completed_rx_t = m_completed_rx_h = 0; };
- void push_completed_rx(const u8 &data) { m_completed_rx[m_completed_rx_h++] = data; m_completed_rx_h &= FIFO_SIZE - 1; };
- u8 pop_completed_rx() { u8 val = m_completed_rx[m_completed_rx_t++]; m_completed_rx_t &= FIFO_SIZE - 1; return val; };
- bool empty_completed_rx() const { return m_completed_rx_h == m_completed_rx_t; };
- u8 curr_completed_rx() const { return m_completed_rx[m_completed_rx_t]; };
+ void reset_completed_rx() { m_completed_rx_t = m_completed_rx_h = 0; }
+ void push_completed_rx(const u8 &data) { m_completed_rx[m_completed_rx_h++] = data; m_completed_rx_h &= FIFO_SIZE - 1; }
+ u8 pop_completed_rx() { u8 val = m_completed_rx[m_completed_rx_t++]; m_completed_rx_t &= FIFO_SIZE - 1; return val; }
+ bool empty_completed_rx() const { return m_completed_rx_h == m_completed_rx_t; }
+ u8 curr_completed_rx() const { return m_completed_rx[m_completed_rx_t]; }
};
diff --git a/src/devices/machine/smioc.cpp b/src/devices/machine/smioc.cpp
index 7f7f2046fb5..194d885c196 100644
--- a/src/devices/machine/smioc.cpp
+++ b/src/devices/machine/smioc.cpp
@@ -129,7 +129,6 @@ void smioc_device::smioc_mem(address_map &map)
static DEVICE_INPUT_DEFAULTS_START(terminal)
DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_9600)
DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0xff, RS232_BAUD_9600)
- DEVICE_INPUT_DEFAULTS("RS232_STARTBITS", 0xff, RS232_STARTBITS_1)
DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0xff, RS232_DATABITS_7)
DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0xff, RS232_PARITY_EVEN)
DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0xff, RS232_STOPBITS_1)
@@ -202,11 +201,9 @@ smioc_device::smioc_device(const machine_config &mconfig, const char *tag, devic
m_smioc_ram(*this, "smioc_ram"),
m_dma_timer(nullptr),
m_451_timer(nullptr),
- m_m68k_r_cb(*this),
+ m_m68k_r_cb(*this, 0),
m_m68k_w_cb(*this)
{
-
-
}
//-------------------------------------------------
@@ -215,12 +212,8 @@ smioc_device::smioc_device(const machine_config &mconfig, const char *tag, devic
void smioc_device::device_start()
{
- m_dma_timer = timer_alloc(0, nullptr);
- m_451_timer = timer_alloc(1, nullptr);
-
- /* Resolve callbacks */
- m_m68k_r_cb.resolve_safe(0);
- m_m68k_w_cb.resolve_safe();
+ m_dma_timer = timer_alloc(FUNC(smioc_device::raise_drq), this);
+ m_451_timer = timer_alloc(FUNC(smioc_device::raise_int1), this);
m_451_timer->adjust(attotime::from_msec(200), 0, attotime::from_msec(200));
}
@@ -246,20 +239,17 @@ void smioc_device::SoftReset()
m_deviceBusy = 1;
}
-
-void smioc_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(smioc_device::raise_drq)
{
- switch (tid)
- {
- case 0: // DMA Timer
- m_smioccpu->drq0_w(1);
- break;
+ // DMA Timer
+ m_smioccpu->drq0_w(1);
+}
- case 1: // 451 emulation timer - Trigger the SMIOC to read from C0180 and store data
- m_smioccpu->int1_w(CLEAR_LINE);
- m_smioccpu->int1_w(HOLD_LINE);
- break;
- }
+TIMER_CALLBACK_MEMBER(smioc_device::raise_int1)
+{
+ // 451 emulation timer - Trigger the SMIOC to read from C0180 and store data
+ m_smioccpu->int1_w(CLEAR_LINE);
+ m_smioccpu->int1_w(HOLD_LINE);
}
void smioc_device::SendCommand(u16 command)
diff --git a/src/devices/machine/smioc.h b/src/devices/machine/smioc.h
index a75a5b33ed3..73dd874d149 100644
--- a/src/devices/machine/smioc.h
+++ b/src/devices/machine/smioc.h
@@ -108,7 +108,9 @@ protected:
/* Optional information overrides */
virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry *device_rom_region() const override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(raise_drq);
+ TIMER_CALLBACK_MEMBER(raise_int1);
u16 ReadDmaParameter(smioc_dma_parameter_t param);
int DmaParameterAddress(smioc_dma_parameter_t param);
diff --git a/src/devices/machine/smpc.cpp b/src/devices/machine/smpc.cpp
index bff704cdcb3..e70ab757dc7 100644
--- a/src/devices/machine/smpc.cpp
+++ b/src/devices/machine/smpc.cpp
@@ -160,14 +160,16 @@ SMPC NVRAM contents:
*/
#include "emu.h"
-#include "machine/smpc.h"
+#include "smpc.h"
#include "screen.h"
#include "coreutil.h"
-#define LOG_SMPC 0
-#define LOG_PAD_CMD 0
+#define LOG_PAD_CMD (1U << 1)
+#define VERBOSE (0)
+#include "logmacro.h"
+
//**************************************************************************
// GLOBAL VARIABLES
@@ -205,6 +207,7 @@ void smpc_hle_device::smpc_regs(address_map &map)
smpc_hle_device::smpc_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SMPC_HLE, tag, owner, clock)
, device_memory_interface(mconfig, *this)
+ , device_rtc_interface(mconfig, *this)
, m_space_config("regs", ENDIANNESS_LITTLE, 8, 7, 0, address_map_constructor(FUNC(smpc_hle_device::smpc_regs), this))
, m_mini_nvram(*this, "smem")
, m_mshres(*this)
@@ -214,8 +217,8 @@ smpc_hle_device::smpc_hle_device(const machine_config &mconfig, const char *tag,
, m_sysres(*this)
, m_syshalt(*this)
, m_dotsel(*this)
- , m_pdr1_read(*this)
- , m_pdr2_read(*this)
+ , m_pdr1_read(*this, 0xff)
+ , m_pdr2_read(*this, 0xff)
, m_pdr1_write(*this)
, m_pdr2_write(*this)
, m_irq_line(*this)
@@ -244,27 +247,10 @@ void smpc_hle_device::device_add_mconfig(machine_config &config)
void smpc_hle_device::device_start()
{
- system_time systime;
- machine().base_datetime(systime);
-
// check if SMEM has valid data via byte 4 in the array, if not then simulate a battery backup fail
// (-> call the RTC / Language select menu for Saturn)
m_mini_nvram->set_base(&m_smem, 5);
- m_mshres.resolve_safe();
- m_mshnmi.resolve_safe();
- m_sshres.resolve_safe();
- m_sndres.resolve_safe();
- m_sysres.resolve_safe();
- m_syshalt.resolve_safe();
- m_dotsel.resolve_safe();
- m_irq_line.resolve_safe();
-
- m_pdr1_read.resolve_safe(0xff);
- m_pdr2_read.resolve_safe(0xff);
- m_pdr1_write.resolve_safe();
- m_pdr2_write.resolve_safe();
-
save_item(NAME(m_sf));
save_item(NAME(m_sr));
save_item(NAME(m_ddr1));
@@ -285,18 +271,10 @@ void smpc_hle_device::device_start()
save_item(NAME(m_rtc_data));
save_item(NAME(m_smem));
- m_cmd_timer = timer_alloc(COMMAND_ID);
- m_rtc_timer = timer_alloc(RTC_ID);
- m_intback_timer = timer_alloc(INTBACK_ID);
- m_sndres_timer = timer_alloc(SNDRES_ID);
-
- m_rtc_data[0] = DectoBCD(systime.local_time.year / 100);
- m_rtc_data[1] = DectoBCD(systime.local_time.year % 100);
- m_rtc_data[2] = (systime.local_time.weekday << 4) | (systime.local_time.month+1);
- m_rtc_data[3] = DectoBCD(systime.local_time.mday);
- m_rtc_data[4] = DectoBCD(systime.local_time.hour);
- m_rtc_data[5] = DectoBCD(systime.local_time.minute);
- m_rtc_data[6] = DectoBCD(systime.local_time.second);
+ m_cmd_timer = timer_alloc(FUNC(smpc_hle_device::handle_command), this);
+ m_rtc_timer = timer_alloc(FUNC(smpc_hle_device::handle_rtc_increment), this);
+ m_intback_timer = timer_alloc(FUNC(smpc_hle_device::intback_continue_request), this);
+ m_sndres_timer = timer_alloc(FUNC(smpc_hle_device::sound_reset), this);
}
@@ -328,6 +306,22 @@ void smpc_hle_device::device_reset()
m_rtc_timer->adjust(attotime::zero, 0, attotime::from_seconds(1));
}
+
+//-------------------------------------------------
+// rtc_clock_updated - update clock with real time
+//-------------------------------------------------
+
+void smpc_hle_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ m_rtc_data[0] = DectoBCD(year / 100);
+ m_rtc_data[1] = DectoBCD(year % 100);
+ m_rtc_data[2] = ((day_of_week - 1) << 4) | month;
+ m_rtc_data[3] = DectoBCD(day);
+ m_rtc_data[4] = DectoBCD(hour);
+ m_rtc_data[5] = DectoBCD(minute);
+ m_rtc_data[6] = DectoBCD(second);
+}
+
device_memory_interface::space_config_vector smpc_hle_device::memory_space_config() const
{
return space_config_vector {
@@ -353,13 +347,13 @@ void smpc_hle_device::ireg_w(offs_t offset, uint8_t data)
{
if(data & 0x40)
{
- if(LOG_PAD_CMD) printf("SMPC: BREAK request\n");
+ LOGMASKED(LOG_PAD_CMD, "SMPC: BREAK request\n");
sr_ack();
m_intback_stage = 0;
}
else if(data & 0x80)
{
- if(LOG_PAD_CMD) printf("SMPC: CONTINUE request\n");
+ LOGMASKED(LOG_PAD_CMD, "SMPC: CONTINUE request\n");
m_intback_timer->adjust(attotime::from_usec(700)); // TODO: is timing correct?
@@ -564,124 +558,119 @@ void smpc_hle_device::command_register_w(uint8_t data)
}
-void smpc_hle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(smpc_hle_device::handle_command)
{
- switch(id)
+ switch(m_comreg)
{
- case COMMAND_ID:
- {
- switch(m_comreg)
- {
- case 0x00: // MSHON
- // enable Master SH2
- m_mshres(m_comreg & 1);
- break;
-
- case 0x02: // SSHON
- case 0x03: // SSHOFF
- // enable or disable Slave SH2
- m_sshres(m_comreg & 1);
- break;
-
- case 0x06: // SNDON
- case 0x07: // SNDOFF
- // enable or disable 68k
- m_sndres(m_comreg & 1);
- break;
-
- case 0x08: // CDON
- case 0x09: // CDOFF
- // ...
- m_command_in_progress = false;
- m_oreg[31] = m_comreg;
- sf_ack(true); //clear hand-shake flag (TODO: diagnostic wants this to have bit 3 high)
- return;
-
-// case 0x0a: // NETLINKON
-// case 0x0b: // NETLINKOFF
-
- case 0x0d: // SYSRES
- // send a 1 -> 0 to device reset lines
- m_sysres(1);
- m_sysres(0);
-
- // send a 1 -> 0 transition to reset line (was PULSE_LINE)
- m_mshres(1);
- m_mshres(0);
- break;
-
- case 0x0e: // CKCHG352
- case 0x0f: // CKCHG320
- m_dotsel(m_comreg & 1);
-
- // send a NMI to Master SH2 if enabled
- if(m_NMI_reset == false)
- master_sh2_nmi();
-
- // assert Slave SH2 line
- m_sshres(1);
- // clear PLL system halt
- m_syshalt(0);
-
- // setup the new dot select
- m_cur_dotsel = (m_comreg & 1) ^ 1;
- break;
-
- case 0x10: // INTBACK
- resolve_intback();
- return;
-
- case 0x16: // SETTIME
- {
- for(int i=0;i<7;i++)
- m_rtc_data[i] = m_ireg[i];
- break;
- }
-
- case 0x17: // SETSMEM
- {
- for(int i=0;i<4;i++)
- m_smem[i] = m_ireg[i];
-
- // clear the SETIME variable, simulate a cr2032 battery alive in the system
- m_smem[4] = 0xff;
- break;
- }
-
- case 0x18: // NMIREQ
- // NMI is unconditionally requested
- master_sh2_nmi();
- break;
-
- case 0x19: // RESENAB
- case 0x1a: // RESDISA
- m_NMI_reset = m_comreg & 1;
- break;
-
- default:
- logerror("%s unemulated %02x command\n",this->tag(),m_comreg);
- return;
- }
+ case 0x00: // MSHON
+ // enable Master SH2
+ m_mshres(m_comreg & 1);
+ break;
+
+ case 0x02: // SSHON
+ case 0x03: // SSHOFF
+ // enable or disable Slave SH2
+ m_sshres(m_comreg & 1);
+ break;
+ case 0x06: // SNDON
+ case 0x07: // SNDOFF
+ // enable or disable 68k
+ m_sndres(m_comreg & 1);
+ break;
+
+ case 0x08: // CDON
+ case 0x09: // CDOFF
+ // ...
m_command_in_progress = false;
m_oreg[31] = m_comreg;
- sf_ack(false);
+ // TODO: diagnostic also wants this to have bit 3 high
+ sf_ack(true); //set hand-shake flag
+ return;
+
+ case 0x0a: // NETLINKON
+ // TODO: understand where NetLink actually lies and implement delegation accordingly
+ // (is it really an SH1 device like suggested by the space access or it overlays on CS2 bus?)
+ popmessage("%s: NetLink enabled", this->tag());
+ [[fallthrough]];
+ case 0x0b: // NETLINKOFF
+ break;
+
+ case 0x0d: // SYSRES
+ // send a 1 -> 0 to device reset lines
+ m_sysres(1);
+ m_sysres(0);
+
+ // send a 1 -> 0 transition to reset line (was PULSE_LINE)
+ m_mshres(1);
+ m_mshres(0);
+ break;
+
+ case 0x0e: // CKCHG352
+ case 0x0f: // CKCHG320
+ m_dotsel(m_comreg & 1);
+
+ // assert Slave SH2 line
+ m_sshres(1);
+ // clear PLL system halt
+ m_syshalt(0);
+
+ // setup the new dot select
+ m_cur_dotsel = (m_comreg & 1) ^ 1;
+
+ // send a NMI to Master SH2 if enabled
+ // it is unconditionally requested:
+ // bigichig, capgen1, capgen4 and capgen5 triggers a SLEEP opcode from BIOS call and expects this to wake them up.
+ //if(m_NMI_reset == false)
+ master_sh2_nmi();
+ break;
+
+ case 0x10: // INTBACK
+ resolve_intback();
+ return;
+
+ case 0x16: // SETTIME
+ {
+ for(int i=0;i<7;i++)
+ m_rtc_data[i] = m_ireg[i];
+ break;
+ }
+
+ case 0x17: // SETSMEM
+ {
+ for(int i=0;i<4;i++)
+ m_smem[i] = m_ireg[i];
+
+ // clear the SETIME variable, simulate a cr2032 battery alive in the system
+ m_smem[4] = 0xff;
break;
}
- case INTBACK_ID: intback_continue_request(); break;
- case RTC_ID: handle_rtc_increment(); break;
+ case 0x18: // NMIREQ
+ // NMI is unconditionally requested
+ master_sh2_nmi();
+ break;
- // from m68k reset opcode trigger
- case SNDRES_ID:
- m_sndres(1);
- m_sndres(0);
+ case 0x19: // RESENAB
+ case 0x1a: // RESDISA
+ m_NMI_reset = m_comreg & 1;
break;
default:
- printf("%d\n",id);
- break;
+ logerror("%s: unemulated %02x command\n",this->tag(),m_comreg);
+ return;
}
+
+ m_command_in_progress = false;
+ m_oreg[31] = m_comreg;
+ sf_ack(false);
+}
+
+TIMER_CALLBACK_MEMBER(smpc_hle_device::sound_reset)
+{
+ // from m68k reset opcode trigger
+ m_sndres(1);
+ m_sndres(0);
}
void smpc_hle_device::resolve_intback()
@@ -741,7 +730,7 @@ void smpc_hle_device::resolve_intback()
m_intback_stage = (m_intback_buf[1] & 8) >> 3; // first peripheral
sr_set(0x40);
m_oreg[31] = 0x10;
- intback_continue_request();
+ intback_continue_request(0);
}
else
{
@@ -751,7 +740,7 @@ void smpc_hle_device::resolve_intback()
}
}
-void smpc_hle_device::intback_continue_request()
+TIMER_CALLBACK_MEMBER(smpc_hle_device::intback_continue_request)
{
if( m_has_ctrl_ports == true )
read_saturn_ports();
@@ -793,7 +782,7 @@ int smpc_hle_device::DectoBCD(int num)
// RTC handling
//**************************************************************************
-void smpc_hle_device::handle_rtc_increment()
+TIMER_CALLBACK_MEMBER(smpc_hle_device::handle_rtc_increment)
{
const uint8_t dpm[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 };
int year_num, year_count;
diff --git a/src/devices/machine/smpc.h b/src/devices/machine/smpc.h
index b62d13dc1d3..26f43176a7d 100644
--- a/src/devices/machine/smpc.h
+++ b/src/devices/machine/smpc.h
@@ -14,6 +14,7 @@
#include "screen.h"
#include "bus/sat_ctrl/ctrl.h"
#include "machine/nvram.h"
+#include "dirtc.h"
//**************************************************************************
@@ -23,7 +24,8 @@
// ======================> smpc_hle_device
class smpc_hle_device : public device_t,
- public device_memory_interface
+ public device_memory_interface,
+ public device_rtc_interface
{
public:
// construction/destruction
@@ -86,18 +88,16 @@ protected:
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual space_config_vector memory_space_config() const override;
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return true; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+
private:
const address_space_config m_space_config;
- enum {
- COMMAND_ID = 1,
- RTC_ID,
- INTBACK_ID,
- SNDRES_ID
- };
emu_timer *m_cmd_timer;
emu_timer *m_rtc_timer;
@@ -142,8 +142,10 @@ private:
void irq_request();
void resolve_intback();
- void intback_continue_request();
- void handle_rtc_increment();
+ TIMER_CALLBACK_MEMBER(intback_continue_request);
+ TIMER_CALLBACK_MEMBER(handle_rtc_increment);
+ TIMER_CALLBACK_MEMBER(sound_reset);
+ TIMER_CALLBACK_MEMBER(handle_command);
void read_saturn_ports();
void sr_set(uint8_t data);
diff --git a/src/devices/machine/sonydriv.cpp b/src/devices/machine/sonydriv.cpp
deleted file mode 100644
index 8f23a832c36..00000000000
--- a/src/devices/machine/sonydriv.cpp
+++ /dev/null
@@ -1,628 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Nathan Woods, Raphael Nabet, R. Belmont
-/*********************************************************************
-
- sonydriv.c
-
- Apple/Sony 3.5" floppy drive emulation (to be interfaced with iwm.c)
-
- Nate Woods, Raphael Nabet, R. Belmont
-
- This floppy drive was present in all variants of Lisa 2 (including Mac XL),
- all Apple IIgs and IIc Plus machines, and in all Macintoshes in production
- before 1988, when SWIM and SuperDrive were introduced.
-
- There were three major variants :
- - A single-sided 400k unit which was used on Lisa 2/Mac XL, and Macintosh
- 128k/512k. This unit needs the computer to send the proper pulses to
- control the drive motor rotation. It can be connected to all early
- Macintosh (but not Mac Classic?) as an external unit.
- - A double-sided 800k unit which was used on Macintosh Plus, 512ke, and
- early SE and II*. This unit generates its own drive motor rotation
- control signals. It can be connected to earlier (and later) Macintosh as
- an external or internal unit. Some Lisa2/10 and Mac XL were upgraded to
- use it, too, but a fdc ROM upgrade was required.
- - A double-sided 1440k unit. This is fully back compatible with the 800k
- drive, and adds 1440k MFM capability. This drive, called FDHD or
- SuperDrive by Apple, came in automatic and manual-inject versions.
-
- TODO :
- * support for other image formats?
- * should we support more than 2 floppy disk units? (Mac SE supported 3 drives)
-
-*********************************************************************/
-
-#include "emu.h"
-#include "sonydriv.h"
-
-#include "machine/applefdc.h"
-#include "formats/ap_dsk35.h"
-#include "imagedev/flopdrv.h"
-
-
-#ifdef MAME_DEBUG
-#define LOG_SONY 1
-#define LOG_SONY_EXTRA 0
-#else
-#define LOG_SONY 0
-#define LOG_SONY_EXTRA 0
-#endif
-
-/*
- These lines are normally connected to the PHI0-PHI3 lines of the IWM
-*/
-enum
-{
- SONY_CA0 = 0x01,
- SONY_CA1 = 0x02,
- SONY_CA2 = 0x04,
- SONY_LSTRB = 0x08
-};
-
-/*
- Structure that describes the state of a floppy drive, and the associated
- disk image
-*/
-struct floppy_t
-{
- device_t *img;
- emu_file *fd;
-
- unsigned int disk_switched : 1; /* disk-in-place status bit */
- unsigned int head : 1; /* active head (-> floppy side) */
- unsigned int step : 1;
- int motor_on;
-
- unsigned int loadedtrack_valid : 1; /* is data in track buffer valid ? */
- unsigned int loadedtrack_dirty : 1; /* has data in track buffer been modified? */
- size_t loadedtrack_size; /* size of loaded track */
- size_t loadedtrack_pos; /* position within loaded track */
- uint8_t *loadedtrack_data; /* pointer to track buffer */
-
- int is_fdhd; /* is drive an FDHD? */
- int is_400k; /* drive is single-sided, which means 400K */
-};
-
-struct sonydriv_t
-{
- int lines; /* four lines SONY_CA0 - SONY_LSTRB */
-
- int floppy_enable; /* whether a drive is enabled or not (-> enable line) */
- int floppy_select; /* which drive is enabled */
-
- int sel_line; /* one single line Is 0 or 1 */
-
- unsigned int rotation_speed; /* drive rotation speed - ignored if ext_speed_control == 0 */
- floppy_t floppy[2]; /* data for two floppy disk units */
-};
-static sonydriv_t sony;
-
-/* bit of code used in several places - I am unsure why it is here */
-static int sony_enable2(void)
-{
- return (sony.lines & SONY_CA1) && (sony.lines & SONY_LSTRB);
-}
-
-static legacy_floppy_image_device *floppy_get_device(running_machine &machine,int drive)
-{
- switch(drive) {
- case 0 : return machine.device<legacy_floppy_image_device>(FLOPPY_0);
- case 1 : return machine.device<legacy_floppy_image_device>(FLOPPY_1);
- case 2 : return machine.device<legacy_floppy_image_device>(FLOPPY_2);
- case 3 : return machine.device<legacy_floppy_image_device>(FLOPPY_3);
- }
- return nullptr;
-}
-
-static legacy_floppy_image_device *floppy_get_device_by_type(running_machine &machine,int ftype,int drive)
-{
- int i;
- int cnt = 0;
- for (i=0;i<4;i++) {
- legacy_floppy_image_device *disk = floppy_get_device(machine,i);
- if (disk && disk->floppy_get_drive_type()==ftype) {
- if (cnt==drive) {
- return disk;
- }
- cnt++;
- }
- }
- return nullptr;
-}
-
-static int floppy_get_drive_by_type(legacy_floppy_image_device *image,int ftype)
-{
- int i,drive =0;
- for (i=0;i<4;i++) {
- legacy_floppy_image_device *disk = floppy_get_device(image->machine(),i);
- if (disk && disk->floppy_get_drive_type()==ftype) {
- if (image==disk) {
- return drive;
- }
- drive++;
- }
- }
- return -1;
-}
-
-static void load_track_data(device_t *device,int floppy_select)
-{
- int track_size;
- legacy_floppy_image_device *cur_image;
- uint8_t *new_data;
- floppy_t *f;
-
- f = &sony.floppy[floppy_select];
- cur_image = floppy_get_device_by_type(device->machine(), FLOPPY_TYPE_SONY, floppy_select);
-
- floppy_image_legacy *fimg = cur_image->flopimg_get_image();
-
- if (!fimg)
- {
- return;
- }
-
- track_size = floppy_get_track_size(fimg, f->head, cur_image->floppy_drive_get_current_track());
- if (f->loadedtrack_data) auto_free(device->machine(),f->loadedtrack_data);
- new_data = auto_alloc_array(device->machine(),uint8_t,track_size);
- if (!new_data)
- {
- return;
- }
-
- cur_image->floppy_drive_read_track_data_info_buffer(f->head, new_data, &track_size);
- f->loadedtrack_valid = 1;
- f->loadedtrack_dirty = 0;
- f->loadedtrack_size = track_size;
- f->loadedtrack_data = new_data;
- f->loadedtrack_pos = 0;
-}
-
-
-
-static void save_track_data(device_t *device, int floppy_select)
-{
- legacy_floppy_image_device *cur_image;
- floppy_t *f;
- int len;
-
- f = &sony.floppy[floppy_select];
- cur_image = floppy_get_device_by_type(device->machine(), FLOPPY_TYPE_SONY, floppy_select);
-
- if (f->loadedtrack_dirty)
- {
- len = f->loadedtrack_size;
- cur_image->floppy_drive_write_track_data_info_buffer(f->head, f->loadedtrack_data, &len);
- f->loadedtrack_dirty = 0;
- }
-}
-
-
-
-uint8_t sony_read_data(device_t *device)
-{
- uint8_t result = 0;
- legacy_floppy_image_device *cur_image;
- floppy_t *f;
-
- if (sony_enable2() || (! sony.floppy_enable))
- return 0xFF; /* right ??? */
-
- f = &sony.floppy[sony.floppy_select];
- cur_image = floppy_get_device_by_type(device->machine(), FLOPPY_TYPE_SONY, sony.floppy_select);
- if (!cur_image->exists())
- return 0xFF;
-
- if (!f->loadedtrack_valid)
- load_track_data(device, sony.floppy_select);
-
- if (!f->loadedtrack_data)
- {
- return 0xFF;
- }
-
- result = sony_fetchtrack(f->loadedtrack_data, f->loadedtrack_size, &f->loadedtrack_pos);
- return result;
-}
-
-
-
-void sony_write_data(device_t *device,uint8_t data)
-{
- device_image_interface *cur_image;
- floppy_t *f;
-
- f = &sony.floppy[sony.floppy_select];
- cur_image = dynamic_cast<device_image_interface *>(floppy_get_device_by_type(device->machine(), FLOPPY_TYPE_SONY, sony.floppy_select));
- if (!cur_image->exists())
- return;
-
- if (!f->loadedtrack_valid)
- load_track_data(device,sony.floppy_select);
-
- if (!f->loadedtrack_data)
- {
- return;
- }
-
- sony_filltrack(f->loadedtrack_data, f->loadedtrack_size, &f->loadedtrack_pos, data);
- f->loadedtrack_dirty = 1;
-}
-
-
-
-static int sony_rpm(floppy_t *f, legacy_floppy_image_device *cur_image)
-{
- int result = 0;
- /*
- * The Mac floppy controller was interesting in that its speed was adjusted
- * while the thing was running. On the tracks closer to the rim, it was
- * sped up so that more data could be placed on it. Hence, this function
- * has different results depending on the track number
- *
- * The Mac Plus (and probably the other Macs that use the IWM) verify that
- * the speed of the floppy drive is within a certain range depending on
- * what track the floppy is at. These RPM values are just guesses and are
- * probably not fully accurate, but they are within the range that the Mac
- * Plus expects and thus are probably in the right ballpark.
- *
- * Note - the timing values are the values returned by the Mac Plus routine
- * that calculates the speed; I'm not sure what units they are in
- */
-
- if ((f->is_400k) && (sony.rotation_speed))
- {
- /* 400k unit : rotation speed should be controlled by computer */
- result = sony.rotation_speed;
- }
- else
- { /* 800k unit : rotation speed controlled by drive */
-#if 1 /* Mac Plus */
- static const int speeds[] =
- {
- 500, /* 00-15: timing value 117B (acceptable range {1135-11E9} */
- 550, /* 16-31: timing value ???? (acceptable range {12C6-138A} */
- 600, /* 32-47: timing value ???? (acceptable range {14A7-157F} */
- 675, /* 48-63: timing value ???? (acceptable range {16F2-17E2} */
- 750 /* 64-79: timing value ???? (acceptable range {19D0-1ADE} */
- };
-#else /* Lisa 2 */
- /* 237 + 1.3*(256-reg) */
- static const int speeds[] =
- {
- 293, /* 00-15: timing value ???? (acceptable range {0330-0336} */
- 322, /* 16-31: timing value ???? (acceptable range {02ED-02F3} */
- 351, /* 32-47: timing value ???? (acceptable range {02A7-02AD} */
- 394, /* 48-63: timing value ???? (acceptable range {0262-0266} */
- 439 /* 64-79: timing value ???? (acceptable range {021E-0222} */
- };
-#endif
- if (cur_image && cur_image->exists())
- result = speeds[cur_image->floppy_drive_get_current_track() / 16];
- }
- return result;
-}
-
-int sony_read_status(device_t *device)
-{
- int result = 1;
- int action;
- floppy_t *f;
- legacy_floppy_image_device *cur_image;
-
- action = ((sony.lines & (SONY_CA1 | SONY_CA0)) << 2) | (sony.sel_line << 1) | ((sony.lines & SONY_CA2) >> 2);
-
- if (LOG_SONY_EXTRA)
- {
- device->logerror("%s sony.status(): action=%x%s\n",
- device->machine().describe_context(),
- action, sony.floppy_enable ? "" : " (no drive enabled)");
- }
-
- if ((! sony_enable2()) && sony.floppy_enable)
- {
- f = &sony.floppy[sony.floppy_select];
- cur_image = floppy_get_device_by_type(device->machine(), FLOPPY_TYPE_SONY, sony.floppy_select);
- if (!cur_image->exists())
- cur_image = nullptr;
-
- switch(action) {
- case 0x00: /* Step direction */
- result = f->step;
- break;
- case 0x01: /* Lower head activate */
- if (f->head != 0)
- {
- save_track_data(device,sony.floppy_select);
- f->head = 0;
- f->loadedtrack_valid = 0;
- }
- result = 0;
- break;
- case 0x02: /* Disk in place */
- result = cur_image ? 0 : 1; /* 0=disk 1=nodisk */
- break;
- case 0x03: /* Upper head activate (not on 400k) */
- if ((f->head != 1) && !(f->is_400k))
- {
- save_track_data(device,sony.floppy_select);
- f->head = 1;
- f->loadedtrack_valid = 0;
- }
- result = 0;
- break;
- case 0x04: /* Disk is stepping 0=stepping 1=not stepping*/
- result = 1;
- break;
- case 0x05: /* Drive is SuperDrive: 0 = 400/800k, 1 = SuperDrive */
- result = f->is_fdhd ? 1: 0;
- break;
- case 0x06: /* Disk is locked 0=locked 1=unlocked */
- if (cur_image)
- result = cur_image->floppy_wpt_r();
- else
- result = 0;
- break;
- case 0x08: /* Motor on 0=on 1=off */
- result = f->motor_on;
- break;
- case 0x09: /* Number of sides: 0=single sided, 1=double sided */
- if (cur_image)
- {
- floppy_image_legacy *fimg = cur_image->flopimg_get_image();
- if (fimg)
- {
- result = floppy_get_heads_per_disk(fimg) - 1;
- f->is_400k = result ? 0 : 1;
- }
- }
- break;
- case 0x0a: /* At track 0: 0=track zero 1=not track zero */
- device->logerror("%s sony.status(): reading Track 0\n", device->machine().describe_context());
- if (cur_image)
- result = cur_image->floppy_tk00_r();
- else
- result = 0;
- break;
- case 0x0b: /* Disk ready: 0=ready, 1=not ready */
- result = 0;
- break;
- case 0x0c: /* Disk switched */
- {
- if (cur_image)
- {
- if (!cur_image->floppy_dskchg_r())
- {
- f->disk_switched = 1;
- }
- }
- result = f->disk_switched;
- }
- break;
- case 0x0d: /* Unknown */
- /* I'm not sure what this one does, but the Mac Plus executes the
- * following code that uses this status:
- *
- * 417E52: moveq #$d, D0 ; Status 0x0d
- * 417E54: bsr 4185fe ; Query IWM status
- * 417E58: bmi 417e82 ; If result=1, then skip
- *
- * This code is called in the Sony driver's open method, and
- * _AddDrive does not get called if this status 0x0d returns 1.
- * Hence, we are returning 0
- */
- result = 0;
- break;
- case 0x0e: /* Tachometer */
- /* (time in seconds) / (60 sec/minute) * (rounds/minute) * (60 pulses) * (2 pulse phases) */
- if (cur_image)
- {
- result = ((int) (device->machine().time().as_double() / 60.0 * sony_rpm(f, cur_image) * 60.0 * 2.0)) & 1;
- }
- break;
- case 0x0f: /* 400k/800k: Drive installed: 0=drive connected, 1=drive not connected */
- /* FDHD: Inserted disk density: 0=HD, 1=DD */
- if (f->is_fdhd)
- {
- result = 1;
- }
- else
- {
- result = 0;
- }
- break;
- default:
- if (LOG_SONY)
- device->logerror("sony_status(): unknown action\n");
- break;
- }
- }
-
- return result;
-}
-
-static void sony_doaction(device_t *device)
-{
- int action;
- floppy_t *f;
- legacy_floppy_image_device *cur_image;
-
- action = ((sony.lines & (SONY_CA1 | SONY_CA0)) << 2) | ((sony.lines & SONY_CA2) >> 2) | (sony.sel_line << 1);
-
- if (LOG_SONY)
- {
- device->logerror("%s sony_doaction(): action=%d %s\n",
- device->machine().describe_context(), action, (sony.floppy_enable) ? "" : " (MOTOR OFF)");
- }
-
- if (sony.floppy_enable)
- {
- f = &sony.floppy[sony.floppy_select];
- cur_image = floppy_get_device_by_type(device->machine(), FLOPPY_TYPE_SONY, sony.floppy_select);
- if (!cur_image->exists())
- cur_image = nullptr;
-
- switch(action)
- {
- case 0x00: /* Set step inward (higher tracks) */
- f->step = 0;
- break;
- case 0x01: /* Set step outward (lower tracks) */
- f->step = 1;
- break;
- case 0x03: /* Reset diskswitched */
- f->disk_switched = 0;
- // flopdrv.cpp won't reset its disk switch flag without
- // doing a seek. So we do a seek of 0 tracks, which works.
- if (cur_image)
- {
- cur_image->floppy_drive_seek(0);
- }
- break;
- case 0x04: /* Step disk */
- if (cur_image)
- {
- save_track_data(device,sony.floppy_select);
- if (f->step)
- cur_image->floppy_drive_seek(-1);
- else
- cur_image->floppy_drive_seek(+1);
- f->loadedtrack_valid = 0;
- }
- break;
- case 0x08: /* Turn motor on */
- f->motor_on = CLEAR_LINE;
- if (cur_image)
- cur_image->floppy_mon_w(f->motor_on);
- break;
- case 0x09: /* Turn motor off */
- f->motor_on = ASSERT_LINE;
- if (cur_image)
- cur_image->floppy_mon_w(f->motor_on);
- break;
- case 0x0d: /* Eject disk */
- if (cur_image)
- cur_image->unload();
- break;
- default:
- if (LOG_SONY)
- device->logerror("sony_doaction(): unknown action %d\n", action);
- break;
- }
- }
-}
-
-void sony_set_lines(device_t *device,uint8_t lines)
-{
- int old_sony_lines = sony.lines;
-
- sony.lines = lines & 0x0F;
-
- {
- //int action = ((sony.lines & (SONY_CA1 | SONY_CA0)) << 2) | (sony.sel_line << 1) | ((sony.lines & SONY_CA2) >> 2);
- //logerror("sony.set_lines: %02x, action now %d\n", lines&0xf, action);
- }
-
- /* have we just set LSTRB ? */
- if ((sony.lines & ~old_sony_lines) & SONY_LSTRB)
- {
- /* if so, write drive reg */
- sony_doaction(device);
- }
-
- if (LOG_SONY_EXTRA)
- device->logerror("sony.set_lines(): %d\n", lines);
-}
-
-void sony_set_enable_lines(device_t *device,int enable_mask)
-{
- switch (enable_mask)
- {
- case 0:
- default: /* well, we have to do something, right ? */
- sony.floppy_enable = 0;
- break;
- case 1:
- sony.floppy_enable = 1;
- sony.floppy_select = 0;
- break;
- case 2:
- sony.floppy_enable = 1;
- sony.floppy_select = 1;
- break;
- }
-
- if (LOG_SONY_EXTRA)
- device->logerror("sony.set_enable_lines(): %d\n", enable_mask);
-}
-
-void sony_set_sel_line(device_t *device,int sel)
-{
- sony.sel_line = sel ? 1 : 0;
-
- {
- //int action = ((sony.lines & (SONY_CA1 | SONY_CA0)) << 2) | (sony.sel_line << 1) | ((sony.lines & SONY_CA2) >> 2);
- //logerror("sony.set_sel_line: %d, action now %d\n", sony.sel_line, action);
- }
-
- if (LOG_SONY_EXTRA)
- device->logerror("sony.set_sel_line(): %s line IWM_SEL\n", sony.sel_line ? "setting" : "clearing");
-}
-
-void sony_set_speed(int speed)
-{
- sony.rotation_speed = speed;
-}
-
-// device type definition
-DEFINE_DEVICE_TYPE(FLOPPY_SONY, sonydriv_floppy_image_device, "floppy_sonny", "Floppy Disk [Sony]")
-
-//-------------------------------------------------
-// sonydriv_floppy_image_device - constructor
-//-------------------------------------------------
-
-sonydriv_floppy_image_device::sonydriv_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : legacy_floppy_image_device(mconfig, FLOPPY_SONY, tag, owner, clock)
-{
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void sonydriv_floppy_image_device::device_start()
-{
- legacy_floppy_image_device::device_start();
- floppy_set_type(FLOPPY_TYPE_SONY);
-
- sony.floppy[0].is_fdhd = 0;
- sony.floppy[1].is_fdhd = 0;
- sony.floppy[0].is_400k = 0;
- sony.floppy[1].is_400k = 0;
- sony.floppy[0].loadedtrack_data = nullptr;
- sony.floppy[1].loadedtrack_data = nullptr;
- sony.floppy[0].head = 0;
- sony.floppy[1].head = 0;
- sony.rotation_speed = 0;
-}
-
-void sonydriv_floppy_image_device::call_unload()
-{
- int id;
- device_t *fdc;
-
- /* locate the FDC */
- fdc = machine().device("fdc");
-
- id = floppy_get_drive_by_type(this,FLOPPY_TYPE_SONY);
- save_track_data(fdc, id);
- memset(&sony.floppy[id], 0, sizeof(sony.floppy[id]));
-
- legacy_floppy_image_device::call_unload();
-}
-
-void sonydriv_floppy_image_device::legacy_2_drives_add(machine_config &mconfig, const floppy_interface *config)
-{
- FLOPPY_SONY(mconfig, FLOPPY_0).set_floppy_config(config);
- FLOPPY_SONY(mconfig, FLOPPY_1).set_floppy_config(config);
-}
diff --git a/src/devices/machine/sonydriv.h b/src/devices/machine/sonydriv.h
deleted file mode 100644
index 8e0e5a54e5d..00000000000
--- a/src/devices/machine/sonydriv.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Nathan Woods, Raphael Nabet, R. Belmont
-/*********************************************************************
-
- sonydriv.h
-
- Apple/Sony 3.5" floppy drive emulation (to be interfaced with applefdc.c)
-
-*********************************************************************/
-
-#ifndef MAME_MACHINE_SONYDRIV_H
-#define MAME_MACHINE_SONYDRIV_H
-
-#pragma once
-
-#include "imagedev/flopdrv.h"
-
-#define FLOPPY_0 "floppy0"
-#define FLOPPY_1 "floppy1"
-#define FLOPPY_2 "floppy2"
-#define FLOPPY_3 "floppy3"
-
-#if 0
-enum
-{
- SONY_FLOPPY_ALLOW400K = 0x0001,
- SONY_FLOPPY_ALLOW800K = 0x0002,
-
- SONY_FLOPPY_SUPPORT2IMG = 0x4000,
- SONY_FLOPPY_EXT_SPEED_CONTROL = 0x8000 // means the speed is controlled by computer
-};
-#endif
-
-void sony_set_lines(device_t *device, uint8_t lines);
-void sony_set_enable_lines(device_t *device, int enable_mask);
-void sony_set_sel_line(device_t *device, int sel);
-
-void sony_set_speed(int speed);
-
-uint8_t sony_read_data(device_t *device);
-void sony_write_data(device_t *device, uint8_t data);
-int sony_read_status(device_t *device);
-
-class sonydriv_floppy_image_device : public legacy_floppy_image_device
-{
-public:
- // construction/destruction
- sonydriv_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, const floppy_interface *config)
- : sonydriv_floppy_image_device(mconfig, tag, owner, (uint32_t)0)
- {
- set_floppy_config(config);
- }
- sonydriv_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
-
- static void legacy_2_drives_add(machine_config &mconfig, const floppy_interface *config);
-
- virtual void call_unload() override;
-
-protected:
- virtual void device_start() override;
-};
-
-// device type definition
-DECLARE_DEVICE_TYPE(FLOPPY_SONY, sonydriv_floppy_image_device)
-
-#endif // MAME_MACHINE_SONYDRIV_H
diff --git a/src/devices/machine/spg110.cpp b/src/devices/machine/spg110.cpp
index b4dbb4e8de8..c31ca87ac7a 100644
--- a/src/devices/machine/spg110.cpp
+++ b/src/devices/machine/spg110.cpp
@@ -26,10 +26,10 @@ spg110_device::spg110_device(const machine_config &mconfig, device_type type, co
m_porta_out(*this),
m_portb_out(*this),
m_portc_out(*this),
- m_porta_in(*this),
- m_portb_in(*this),
- m_portc_in(*this),
- m_adc_in(*this),
+ m_porta_in(*this, 0),
+ m_portb_in(*this, 0),
+ m_portc_in(*this, 0),
+ m_adc_in(*this, 0x0fff),
m_chip_sel(*this),
m_is_spiderman(false)
{
@@ -41,16 +41,16 @@ spg110_device::spg110_device(const machine_config &mconfig, const char *tag, dev
{
}
-WRITE_LINE_MEMBER(spg110_device::videoirq_w)
+void spg110_device::videoirq_w(int state)
{
set_state_unsynced(UNSP_IRQ0_LINE, state);
}
-WRITE_LINE_MEMBER(spg110_device::ffreq1_w)
+void spg110_device::ffreq1_w(int state)
{
}
-WRITE_LINE_MEMBER(spg110_device::ffreq2_w)
+void spg110_device::ffreq2_w(int state)
{
}
@@ -82,7 +82,7 @@ uint16_t spg110_device::space_r(offs_t offset)
return cpuspace.read_word(offset);
}
-WRITE_LINE_MEMBER(spg110_device::audioirq_w)
+void spg110_device::audioirq_w(int state)
{
set_state_unsynced(UNSP_FIQ_LINE, state);
}
@@ -168,22 +168,9 @@ void spg110_device::internal_map(address_map &map)
}
-void spg110_device::device_start()
-{
- unsp_device::device_start();
-
- m_porta_out.resolve_safe();
- m_portb_out.resolve_safe();
- m_portc_out.resolve_safe();
- m_porta_in.resolve_safe(0);
- m_portb_in.resolve_safe(0);
- m_portc_in.resolve_safe(0);
- m_adc_in.resolve_all_safe(0x0fff);
- m_chip_sel.resolve_safe();
-}
-
void spg110_device::device_reset()
{
unsp_device::device_reset();
+
m_spg_video->set_video_irq_spidman(m_is_spiderman);
}
diff --git a/src/devices/machine/spg110.h b/src/devices/machine/spg110.h
index 8ecee9dea75..f555c4ac736 100644
--- a/src/devices/machine/spg110.h
+++ b/src/devices/machine/spg110.h
@@ -40,14 +40,13 @@ public:
auto chip_select() { return m_chip_sel.bind(); }
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_spg_video->screen_update(screen,bitmap,cliprect); }
- DECLARE_WRITE_LINE_MEMBER(vblank) { m_spg_video->vblank(state); }
+ void vblank(int state) { m_spg_video->vblank(state); }
protected:
spg110_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal);
void internal_map(address_map &map);
- virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
@@ -60,7 +59,7 @@ private:
required_device<spg110_audio_device> m_spg_audio;
uint16_t space_r(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER(audioirq_w);
+ void audioirq_w(int state);
devcb_write16 m_porta_out;
devcb_write16 m_portb_out;
@@ -80,15 +79,15 @@ private:
void portb_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_portb_out(offset, data, mem_mask); }
void portc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_portc_out(offset, data, mem_mask); }
- DECLARE_WRITE_LINE_MEMBER(ffreq1_w);
- DECLARE_WRITE_LINE_MEMBER(ffreq2_w);
+ void ffreq1_w(int state);
+ void ffreq2_w(int state);
template <size_t Line> uint16_t adc_r() { return m_adc_in[Line](); }
void cs_w(offs_t offset, uint8_t data, uint8_t mem_mask = ~0) { m_chip_sel(offset, data, mem_mask); }
uint16_t get_pal_r() { return 0; /*m_pal_flag;*/ }
void configure_spg_io(spg2xx_io_device* io);
- DECLARE_WRITE_LINE_MEMBER(videoirq_w);
+ void videoirq_w(int state);
bool m_is_spiderman;
};
diff --git a/src/devices/machine/spg110_video.cpp b/src/devices/machine/spg110_video.cpp
index daf7fa5e158..ff7eab802e3 100644
--- a/src/devices/machine/spg110_video.cpp
+++ b/src/devices/machine/spg110_video.cpp
@@ -540,6 +540,152 @@ void spg110_video_device::map_video(address_map &map)
map(0x08000, 0x081ff).ram().w(FUNC(spg110_video_device::palette_w)).share("palram"); // palette format unknown
}
+// Not used, for reference
+uint16_t spg110_video_device::rgb_to_hsl(uint8_t r, uint8_t g, uint8_t b)
+{
+ uint16_t lum = uint16_t(0.0748*r + 0.1467*g + 0.0286*b + 0.5);
+ if(lum >= 64)
+ lum = 63;
+
+ uint16_t sat = uint16_t(fabs(0.0308*r - 0.0142*g - 0.0166*b) + fabs(0.0110*r - 0.0270*g + 0.0160*b));
+ if(sat >= 8)
+ sat = 7;
+
+ uint8_t mi = std::min(r, std::min(g, b));
+ uint8_t mx = std::max(r, std::max(g, b));
+
+ int16_t hue;
+ if(mi == mx)
+ hue = 47;
+
+ else {
+ if(r == mx)
+ hue = int16_t((44/3.0)*(g-b)/(mx-mi) - 11);
+ else if(g == mx)
+ hue = int16_t((44/3.0)*(b-r)/(mx-mi) + 18.33);
+ else
+ hue = int16_t((44/3.0)*(r-g)/(mx-mi) + 47.67);
+ if(hue < 0)
+ hue += 88;
+ }
+
+ return (lum << 10) | (sat << 7) | hue;
+}
+
+std::tuple<uint8_t, uint8_t, uint8_t> spg110_video_device::hsl_to_rgb(uint16_t hsl)
+{
+ // r/g/b is mostly linear with l, so this is a table of
+ // intercept/slope (e.g. color = intercept + l*slope) for each h/s
+ // value
+
+ static const struct {
+ float ri, rs;
+ float gi, gs;
+ float bi, bs;
+ } color_bases[88][8] = {
+ { { 5.4, 4.01, 0.2, 4.00, -14.6, 3.95 }, { 13.4, 4.00, 1.2, 3.97, -35.7, 3.94 }, { 22.7, 3.99, 1.0, 4.00, -59.0, 3.91 }, { 32.2, 3.95, 0.3, 4.02, -81.2, 3.85 }, { 43.3, 3.90, -1.0, 4.06, -104.1, 3.81 }, { 59.1, 3.73, -3.5, 4.13, -119.4, 3.61 }, { 94.4, 3.13, -15.1, 4.39, -126.9, 3.28 }, { 189.0, 1.28, -57.3, 5.30, -102.3, 2.33 } },
+ { { 3.7, 4.01, 1.1, 4.00, -15.2, 3.94 }, { 9.5, 4.01, 2.7, 4.00, -36.9, 3.94 }, { 16.3, 4.01, 4.2, 4.00, -61.6, 3.92 }, { 22.6, 4.00, 6.1, 4.00, -84.2, 3.85 }, { 29.9, 3.98, 7.3, 4.01, -108.8, 3.83 }, { 37.1, 3.96, 8.0, 4.03, -123.8, 3.61 }, { 50.6, 3.81, 7.8, 4.07, -139.6, 3.44 }, { 95.2, 3.01, -1.2, 4.28, -139.6, 3.03 } },
+ { { 2.9, 4.00, 1.8, 4.00, -16.1, 3.96 }, { 7.6, 4.00, 3.9, 4.00, -37.9, 3.95 }, { 12.8, 4.00, 6.3, 3.99, -62.5, 3.92 }, { 17.4, 4.01, 8.5, 4.01, -86.5, 3.85 }, { 23.3, 3.99, 10.9, 4.02, -107.9, 3.76 }, { 30.0, 3.95, 12.5, 4.03, -128.9, 3.66 }, { 37.8, 3.88, 13.1, 4.07, -144.3, 3.48 }, { 68.0, 3.39, 9.1, 4.19, -127.4, 2.71 } },
+ { { 1.8, 4.01, 1.8, 4.00, -12.2, 3.91 }, { 5.7, 4.00, 4.8, 4.00, -39.0, 3.92 }, { 8.9, 4.00, 8.7, 3.99, -64.0, 3.90 }, { 13.0, 4.00, 11.4, 4.01, -87.5, 3.85 }, { 16.7, 4.00, 14.3, 4.01, -110.5, 3.77 }, { 20.7, 4.00, 15.8, 4.06, -130.8, 3.64 }, { 28.9, 3.90, 18.2, 4.07, -138.5, 3.30 }, { 46.9, 3.63, 19.4, 4.10, -139.6, 2.89 } },
+ { { 1.8, 4.00, 2.9, 4.00, -17.8, 3.95 }, { 4.1, 3.98, 5.8, 4.00, -38.2, 3.93 }, { 5.9, 4.00, 10.8, 3.98, -65.0, 3.90 }, { 8.0, 4.00, 14.2, 4.01, -89.8, 3.85 }, { 12.2, 3.96, 17.8, 4.02, -112.0, 3.76 }, { 14.3, 3.97, 21.4, 4.02, -132.0, 3.63 }, { 16.2, 3.98, 25.2, 4.02, -143.7, 3.35 }, { 16.1, 4.04, 30.4, 3.99, -135.7, 2.77 } },
+ { { 1.1, 4.00, 3.9, 3.99, -15.8, 3.93 }, { 1.2, 3.99, 7.6, 4.00, -39.9, 3.92 }, { 2.2, 3.99, 12.1, 4.02, -64.7, 3.87 }, { 3.2, 4.00, 16.8, 4.02, -90.9, 3.84 }, { 4.6, 3.99, 21.6, 4.02, -115.2, 3.78 }, { 6.1, 3.98, 26.7, 4.01, -135.9, 3.65 }, { 6.5, 4.00, 31.6, 4.00, -147.5, 3.37 }, { 13.8, 3.89, 55.0, 3.62, -160.2, 3.21 } },
+ { { -0.6, 3.99, 3.4, 4.01, -15.8, 3.93 }, { -0.7, 3.99, 8.4, 4.01, -39.9, 3.90 }, { -1.3, 3.99, 14.3, 4.01, -66.5, 3.88 }, { -1.5, 3.97, 20.5, 4.00, -92.3, 3.84 }, { -2.1, 3.98, 25.4, 4.02, -117.7, 3.77 }, { -2.6, 3.98, 31.8, 4.00, -137.9, 3.63 }, { 1.4, 3.89, 34.8, 4.05, -134.6, 3.04 }, { 18.2, 3.60, 67.0, 3.50, -136.2, 2.70 } },
+ { { -1.5, 3.99, 4.3, 4.01, -16.4, 3.92 }, { -3.3, 3.98, 10.2, 4.01, -40.7, 3.90 }, { -4.9, 3.96, 16.7, 4.02, -68.5, 3.87 }, { -7.8, 3.98, 23.8, 4.01, -95.6, 3.85 }, { -8.4, 3.94, 29.0, 4.05, -117.1, 3.70 }, { -12.5, 3.99, 38.9, 3.97, -144.5, 3.71 }, { -11.4, 3.94, 46.1, 3.94, -143.1, 3.17 }, { 90.0, 2.00, 150.0, 2.00, -102.0, 2.00 } },
+ { { -2.3, 3.98, 4.3, 4.01, -16.4, 3.93 }, { -6.3, 3.99, 12.0, 4.01, -43.0, 3.93 }, { -9.5, 3.96, 19.6, 4.02, -70.3, 3.88 }, { -13.4, 3.95, 26.6, 4.04, -95.4, 3.79 }, { -17.0, 3.95, 33.9, 4.05, -120.4, 3.70 }, { -14.8, 3.82, 39.4, 4.08, -131.5, 3.35 }, { -12.6, 3.73, 55.0, 3.88, -139.6, 3.05 }, { 66.7, 2.17, 139.8, 2.30, -98.8, 2.00 } },
+ { { -3.0, 3.97, 5.2, 4.02, -17.0, 3.92 }, { -9.2, 3.99, 14.0, 4.01, -43.8, 3.93 }, { -14.7, 3.95, 22.3, 4.03, -70.7, 3.84 }, { -20.8, 3.94, 31.0, 4.03, -98.8, 3.81 }, { -26.2, 3.94, 40.0, 4.03, -124.1, 3.72 }, { -26.5, 3.83, 49.7, 3.99, -137.7, 3.43 }, { -4.0, 3.30, 60.6, 3.90, -120.8, 2.60 }, { 43.3, 2.33, 129.5, 2.60, -95.5, 2.00 } },
+ { { -4.4, 3.97, 5.7, 4.02, -16.0, 3.90 }, { -12.5, 3.97, 15.5, 4.02, -44.6, 3.90 }, { -21.1, 3.97, 26.2, 4.02, -74.7, 3.90 }, { -28.7, 3.94, 35.8, 4.03, -101.9, 3.80 }, { -37.3, 3.95, 48.2, 3.97, -128.9, 3.76 }, { -31.4, 3.68, 54.4, 4.03, -132.0, 3.24 }, { 95.0, 1.00, 110.0, 3.00, -47.0, 1.00 }, { 20.0, 2.50, 119.2, 2.90, -92.2, 2.00 } },
+ { { -6.9, 3.98, 8.1, 4.01, -20.0, 3.95 }, { -16.0, 3.96, 17.6, 4.02, -45.3, 3.91 }, { -27.1, 3.95, 29.1, 4.02, -74.5, 3.87 }, { -36.7, 3.93, 39.7, 4.05, -97.7, 3.69 }, { -47.0, 3.91, 50.8, 4.05, -114.5, 3.39 }, { -70.4, 4.23, 69.6, 3.85, -106.9, 2.66 }, { 19.7, 2.25, 91.2, 3.50, -70.8, 1.66 }, { -3.3, 2.67, 109.0, 3.20, -89.0, 2.00 } },
+ { { -6.8, 3.98, 7.1, 4.01, -16.1, 3.95 }, { -17.7, 3.96, 17.6, 4.02, -40.7, 3.93 }, { -28.8, 3.94, 27.9, 4.03, -64.7, 3.84 }, { -39.7, 3.92, 38.8, 4.05, -88.1, 3.73 }, { -49.5, 3.86, 48.2, 4.10, -105.3, 3.51 }, { -57.8, 3.79, 56.0, 4.17, -109.6, 3.05 }, { -55.6, 3.50, 72.3, 4.00, -94.7, 2.32 }, { -26.7, 2.83, 98.8, 3.50, -85.8, 2.00 } },
+ { { -7.8, 3.98, 7.0, 4.02, -14.8, 3.96 }, { -18.4, 3.97, 16.8, 4.02, -35.8, 3.95 }, { -30.8, 3.96, 27.5, 4.02, -58.3, 3.91 }, { -42.6, 3.94, 38.1, 4.03, -80.1, 3.84 }, { -53.2, 3.88, 47.6, 4.08, -98.4, 3.70 }, { -64.8, 3.87, 60.2, 4.02, -116.9, 3.61 }, { -70.8, 3.74, 68.0, 4.08, -108.7, 2.95 }, { -50.0, 3.00, 88.5, 3.80, -82.5, 2.00 } },
+ { { -8.0, 3.98, 6.5, 4.01, -13.3, 3.97 }, { -19.2, 3.97, 16.1, 4.01, -31.2, 3.95 }, { -32.2, 3.97, 27.1, 4.01, -52.7, 3.94 }, { -44.3, 3.94, 37.3, 4.03, -72.1, 3.88 }, { -56.4, 3.93, 47.8, 4.03, -91.2, 3.83 }, { -67.8, 3.88, 57.0, 4.07, -104.5, 3.66 }, { -74.3, 3.73, 64.6, 4.14, -106.4, 3.21 }, { -84.9, 3.72, 81.3, 3.94, -108.8, 2.91 } },
+ { { -8.2, 3.99, 6.6, 4.00, -11.8, 3.98 }, { -19.8, 3.98, 16.4, 4.00, -28.3, 3.97 }, { -32.7, 3.95, 26.0, 4.02, -46.4, 3.93 }, { -45.9, 3.96, 37.0, 4.01, -65.3, 3.93 }, { -58.9, 3.94, 46.6, 4.02, -82.8, 3.90 }, { -69.5, 3.88, 56.0, 4.06, -95.1, 3.72 }, { -82.6, 3.87, 66.6, 4.05, -110.6, 3.66 }, { -86.9, 3.65, 71.1, 4.19, -101.2, 2.98 } },
+ { { -8.4, 3.99, 6.8, 4.00, -11.1, 3.98 }, { -20.5, 3.97, 15.5, 4.00, -25.3, 3.97 }, { -33.5, 3.98, 25.5, 4.00, -41.8, 3.96 }, { -46.5, 3.95, 35.9, 4.01, -57.6, 3.93 }, { -60.6, 3.95, 46.0, 4.01, -74.8, 3.92 }, { -73.4, 3.95, 56.6, 4.01, -90.0, 3.88 }, { -85.5, 3.91, 65.8, 4.03, -101.2, 3.74 }, { -94.2, 3.72, 74.9, 4.09, -110.4, 3.50 } },
+ { { -10.7, 4.00, 8.0, 3.99, -11.7, 4.00 }, { -21.0, 3.98, 15.6, 4.00, -23.0, 3.98 }, { -35.2, 3.99, 25.8, 3.99, -38.9, 3.99 }, { -47.0, 3.94, 35.2, 4.01, -52.4, 3.95 }, { -62.1, 3.97, 46.0, 3.98, -68.3, 3.96 }, { -75.5, 3.95, 55.3, 4.00, -81.9, 3.92 }, { -88.0, 3.93, 65.8, 3.98, -94.1, 3.86 }, { -97.9, 3.70, 72.0, 4.18, -100.9, 3.50 } },
+ { { -7.0, 3.98, 5.5, 4.01, -7.0, 3.98 }, { -21.0, 3.98, 15.7, 4.00, -21.2, 3.99 }, { -34.8, 3.98, 24.7, 4.00, -34.0, 3.99 }, { -49.8, 3.98, 34.7, 4.00, -48.6, 3.98 }, { -63.0, 3.96, 44.7, 4.00, -61.3, 3.97 }, { -76.8, 3.96, 54.4, 4.00, -75.0, 3.96 }, { -89.5, 3.93, 64.4, 4.00, -88.0, 3.94 }, { -102.0, 3.70, 73.9, 4.14, -99.4, 3.69 } },
+ { { -9.5, 3.99, 7.0, 4.00, -8.5, 3.99 }, { -22.1, 3.98, 14.8, 4.00, -19.2, 3.99 }, { -35.7, 3.98, 24.7, 4.00, -30.8, 3.98 }, { -49.7, 3.98, 33.7, 4.00, -42.9, 3.98 }, { -62.9, 3.96, 43.6, 4.00, -54.2, 3.96 }, { -77.9, 3.96, 54.1, 3.98, -68.1, 4.00 }, { -91.9, 3.97, 63.7, 3.99, -78.8, 3.95 }, { -104.8, 3.75, 74.7, 4.07, -93.0, 3.85 } },
+ { { -9.4, 3.99, 6.8, 4.00, -7.4, 3.99 }, { -22.1, 3.98, 14.6, 4.00, -16.3, 3.99 }, { -35.7, 3.98, 23.7, 4.00, -27.0, 3.98 }, { -49.9, 3.98, 33.8, 3.99, -38.2, 3.99 }, { -64.6, 3.98, 42.8, 4.00, -48.9, 3.98 }, { -78.4, 3.95, 52.7, 3.99, -59.3, 3.97 }, { -91.8, 3.93, 62.9, 3.97, -70.0, 3.96 }, { -107.9, 3.78, 73.3, 4.07, -82.2, 3.86 } },
+ { { -9.4, 3.99, 5.8, 4.00, -5.6, 3.99 }, { -22.0, 3.98, 14.6, 4.00, -14.3, 3.99 }, { -35.8, 3.96, 23.5, 4.00, -23.0, 3.98 }, { -50.6, 3.98, 32.7, 4.00, -33.0, 3.98 }, { -65.3, 3.97, 41.7, 4.00, -41.9, 3.98 }, { -78.5, 3.93, 51.2, 4.01, -50.7, 3.96 }, { -93.6, 3.94, 61.0, 3.98, -61.0, 3.99 }, { -103.5, 3.62, 68.6, 4.16, -68.5, 3.80 } },
+ { { -10.2, 3.99, 6.8, 4.00, -5.5, 3.99 }, { -22.9, 3.98, 13.7, 4.00, -12.4, 3.99 }, { -37.2, 3.99, 22.8, 4.00, -19.7, 3.98 }, { -51.5, 3.98, 31.6, 4.00, -26.7, 3.97 }, { -65.2, 3.96, 41.1, 3.99, -35.3, 3.99 }, { -80.7, 3.96, 50.2, 4.01, -43.8, 3.98 }, { -93.2, 3.90, 59.8, 3.99, -51.6, 3.98 }, { -107.5, 3.71, 69.3, 4.09, -59.6, 3.89 } },
+ { { -8.7, 3.98, 5.6, 4.01, -3.4, 3.99 }, { -22.8, 3.98, 13.7, 4.00, -9.6, 3.99 }, { -36.9, 3.98, 22.7, 4.00, -16.4, 3.99 }, { -51.3, 3.97, 31.5, 4.00, -21.9, 3.98 }, { -66.3, 3.97, 40.7, 4.00, -29.0, 3.98 }, { -81.1, 3.97, 50.2, 3.98, -36.1, 3.99 }, { -95.8, 3.94, 57.9, 4.01, -41.9, 3.98 }, { -108.7, 3.69, 67.3, 4.11, -48.7, 3.89 } },
+ { { -9.0, 3.97, 5.8, 4.00, -3.7, 3.99 }, { -23.1, 3.99, 13.9, 3.99, -7.5, 3.99 }, { -37.8, 3.98, 21.7, 4.00, -12.5, 3.99 }, { -52.8, 3.98, 30.8, 4.00, -17.7, 3.99 }, { -66.8, 3.96, 39.6, 4.00, -22.3, 3.99 }, { -81.6, 3.96, 48.9, 3.97, -26.9, 3.97 }, { -97.3, 3.96, 57.5, 3.97, -33.1, 3.99 }, { -105.7, 3.58, 62.9, 4.19, -35.9, 3.86 } },
+ { { -8.7, 3.98, 5.4, 4.01, -1.7, 3.99 }, { -23.1, 3.99, 13.9, 3.98, -5.6, 3.99 }, { -37.4, 3.95, 21.5, 4.01, -8.3, 3.98 }, { -53.6, 3.98, 29.7, 4.00, -12.6, 3.99 }, { -68.4, 3.97, 38.8, 4.00, -16.6, 3.99 }, { -82.1, 3.94, 46.5, 4.00, -19.2, 3.98 }, { -97.1, 3.92, 55.8, 3.99, -23.3, 3.99 }, { -108.6, 3.63, 63.5, 4.12, -26.2, 3.92 } },
+ { { -10.3, 3.99, 5.8, 4.00, -1.6, 3.99 }, { -23.9, 3.99, 12.8, 4.00, -3.5, 3.99 }, { -38.8, 3.98, 21.1, 3.99, -5.6, 3.99 }, { -53.4, 3.97, 29.4, 4.01, -7.5, 3.99 }, { -69.2, 3.97, 37.6, 4.00, -9.7, 3.99 }, { -83.8, 3.96, 45.7, 4.00, -11.8, 3.99 }, { -96.7, 3.89, 54.4, 4.00, -14.7, 4.00 }, { -104.9, 3.50, 59.4, 4.19, -15.9, 3.95 } },
+ { { -10.2, 3.99, 5.7, 4.00, -0.8, 4.00 }, { -23.9, 3.98, 12.7, 4.00, -0.9, 3.99 }, { -38.8, 3.98, 20.7, 4.00, -1.9, 4.00 }, { -54.6, 3.98, 28.7, 4.00, -2.6, 3.99 }, { -70.1, 3.97, 37.3, 3.98, -3.5, 3.99 }, { -85.1, 3.97, 45.4, 3.98, -3.9, 4.00 }, { -99.2, 3.92, 52.8, 4.02, -4.7, 3.99 }, { -107.4, 3.52, 57.1, 4.21, -5.2, 3.97 } },
+ { { -9.1, 3.96, 4.8, 4.00, 0.8, 3.98 }, { -23.8, 3.98, 12.7, 4.00, 1.2, 3.99 }, { -39.5, 3.98, 19.8, 4.00, 2.3, 3.99 }, { -55.1, 3.97, 27.9, 3.99, 2.2, 3.99 }, { -70.1, 3.95, 36.0, 3.99, 3.4, 3.99 }, { -85.8, 3.94, 44.0, 3.99, 4.4, 3.99 }, { -100.0, 3.92, 52.1, 3.99, 4.3, 3.99 }, { -110.6, 3.58, 59.0, 4.12, 4.7, 4.01 } },
+ { { -10.2, 3.98, 4.7, 4.00, 1.0, 4.00 }, { -23.8, 3.98, 11.6, 4.00, 3.2, 3.99 }, { -39.5, 3.97, 19.6, 4.00, 5.2, 3.99 }, { -55.1, 3.96, 27.6, 4.00, 7.3, 3.99 }, { -70.8, 3.96, 34.6, 4.00, 10.1, 3.98 }, { -86.1, 3.94, 42.5, 4.00, 11.9, 4.00 }, { -99.9, 3.88, 50.1, 4.01, 13.7, 4.00 }, { -106.5, 3.44, 54.9, 4.19, 14.3, 4.06 } },
+ { { -10.1, 3.98, 4.8, 4.00, 2.0, 4.00 }, { -23.8, 3.98, 11.7, 4.00, 5.1, 3.99 }, { -39.5, 3.97, 18.6, 4.00, 8.9, 4.00 }, { -55.1, 3.96, 26.6, 4.00, 12.0, 4.00 }, { -71.1, 3.94, 33.5, 4.01, 15.7, 4.00 }, { -86.0, 3.92, 41.2, 4.01, 20.0, 3.99 }, { -100.2, 3.88, 48.7, 4.02, 21.9, 4.02 }, { -109.1, 3.50, 55.9, 4.11, 22.5, 4.14 } },
+ { { -10.3, 3.98, 4.8, 4.00, 3.0, 4.00 }, { -23.7, 3.98, 10.7, 4.00, 7.7, 4.00 }, { -40.2, 3.97, 18.6, 4.00, 12.7, 4.00 }, { -55.6, 3.95, 25.5, 4.01, 17.8, 3.98 }, { -70.8, 3.93, 32.6, 4.01, 21.6, 4.01 }, { -89.0, 3.97, 41.1, 3.99, 26.9, 4.00 }, { -104.1, 3.95, 48.2, 3.99, 31.8, 4.00 }, { -111.2, 3.50, 53.0, 4.15, 34.4, 4.13 } },
+ { { -8.5, 3.97, 3.6, 4.01, 3.6, 4.01 }, { -24.4, 3.97, 10.7, 4.00, 9.7, 4.00 }, { -40.1, 3.96, 17.7, 4.00, 15.8, 4.00 }, { -57.2, 3.97, 24.7, 4.00, 22.5, 4.01 }, { -73.5, 3.98, 32.7, 4.00, 28.8, 4.00 }, { -89.3, 3.95, 39.7, 4.00, 35.2, 4.01 }, { -104.0, 3.90, 46.4, 4.00, 41.2, 4.01 }, { -107.7, 3.38, 49.7, 4.20, 42.2, 4.23 } },
+ { { -12.6, 3.99, 5.2, 3.99, 6.2, 3.99 }, { -24.7, 3.98, 10.8, 4.00, 12.5, 4.00 }, { -40.9, 3.96, 17.6, 4.00, 19.7, 4.00 }, { -57.5, 3.97, 24.6, 4.00, 27.7, 4.00 }, { -73.8, 3.96, 31.6, 4.00, 35.7, 4.00 }, { -90.5, 3.97, 39.2, 3.98, 45.0, 3.95 }, { -106.0, 3.93, 45.5, 4.00, 52.9, 3.95 }, { -113.3, 3.54, 51.0, 4.11, 58.8, 4.06 } },
+ { { -11.1, 3.98, 4.8, 4.00, 5.9, 4.00 }, { -24.7, 3.98, 10.0, 3.99, 14.6, 4.00 }, { -41.8, 3.98, 16.8, 4.00, 23.6, 4.00 }, { -58.5, 3.98, 23.8, 4.00, 33.8, 3.99 }, { -75.0, 3.97, 30.9, 3.99, 43.4, 3.97 }, { -90.9, 3.95, 37.8, 3.99, 53.5, 3.95 }, { -109.4, 4.00, 44.2, 3.98, 66.2, 3.85 }, { -118.7, 3.69, 48.5, 4.10, 77.4, 3.87 } },
+ { { -10.2, 3.99, 3.9, 4.00, 6.7, 4.00 }, { -25.5, 3.98, 9.8, 4.00, 17.4, 4.00 }, { -42.7, 3.98, 16.7, 4.00, 28.6, 4.00 }, { -59.4, 3.98, 23.0, 3.99, 40.9, 3.98 }, { -75.4, 3.96, 29.7, 3.99, 51.9, 3.97 }, { -94.8, 4.01, 36.6, 3.97, 67.0, 3.87 }, { -109.8, 3.97, 43.3, 3.97, 79.9, 3.81 }, { -120.7, 3.78, 48.0, 4.03, 96.3, 3.68 } },
+ { { -11.2, 3.99, 3.8, 4.00, 8.6, 4.00 }, { -25.4, 3.97, 9.7, 4.00, 20.3, 4.01 }, { -43.7, 3.99, 15.9, 3.99, 34.6, 3.99 }, { -60.1, 3.98, 21.9, 3.99, 48.5, 3.98 }, { -78.8, 4.01, 28.0, 3.99, 63.1, 3.93 }, { -95.2, 4.00, 34.5, 3.98, 79.2, 3.85 }, { -110.5, 3.97, 41.7, 3.95, 97.4, 3.68 }, { -130.3, 4.07, 48.6, 3.92, 131.7, 3.05 } },
+ { { -9.7, 3.98, 3.9, 4.00, 9.3, 4.00 }, { -26.4, 3.98, 8.9, 3.99, 25.1, 3.99 }, { -43.8, 3.99, 14.9, 3.99, 41.5, 3.98 }, { -60.8, 3.97, 20.9, 3.99, 57.5, 3.97 }, { -80.2, 4.03, 27.4, 3.97, 77.1, 3.85 }, { -96.0, 4.01, 32.2, 3.98, 95.5, 3.76 }, { -115.3, 4.07, 38.4, 3.98, 125.3, 3.30 }, { -118.8, 3.75, 50.4, 3.79, 155.9, 2.71 } },
+ { { -11.5, 4.00, 4.0, 3.99, 12.7, 3.99 }, { -27.3, 4.01, 8.0, 3.99, 30.6, 3.97 }, { -45.0, 4.01, 14.1, 3.98, 50.1, 3.94 }, { -63.3, 4.02, 19.4, 3.98, 71.4, 3.89 }, { -81.0, 4.04, 25.7, 3.95, 93.1, 3.77 }, { -101.0, 4.11, 30.2, 3.98, 120.4, 3.48 }, { -112.3, 3.99, 37.4, 3.91, 151.4, 2.92 }, { -96.3, 3.08, 37.3, 4.05, 168.8, 2.49 } },
+ { { -11.4, 4.00, 3.1, 3.99, 14.8, 3.98 }, { -25.7, 3.99, 7.0, 3.99, 33.1, 3.99 }, { -42.0, 3.98, 12.0, 3.97, 54.3, 3.98 }, { -57.1, 3.93, 15.4, 4.01, 75.5, 3.99 }, { -71.1, 3.84, 19.4, 4.02, 98.3, 3.94 }, { -84.1, 3.72, 20.9, 4.11, 127.3, 3.64 }, { -57.6, 2.29, 10.3, 4.61, 164.1, 2.96 }, { -73.8, 2.41, 24.1, 4.31, 181.6, 2.27 } },
+ { { -9.2, 4.00, 2.1, 3.99, 14.2, 3.99 }, { -23.4, 4.01, 5.1, 3.99, 34.8, 3.97 }, { -37.4, 3.98, 8.0, 3.99, 57.0, 3.98 }, { -52.2, 3.98, 12.0, 3.99, 80.0, 3.94 }, { -63.3, 3.87, 14.0, 4.02, 102.5, 3.92 }, { -74.7, 3.76, 15.7, 4.07, 129.4, 3.70 }, { -67.8, 3.00, 11.1, 4.35, 162.1, 3.18 }, { -51.2, 1.74, 11.0, 4.58, 194.5, 2.04 } },
+ { { -8.4, 4.00, 1.2, 3.99, 15.5, 3.98 }, { -20.3, 4.00, 3.2, 3.99, 35.8, 3.97 }, { -32.7, 3.99, 6.0, 3.99, 58.7, 3.96 }, { -44.8, 3.97, 7.9, 3.99, 82.3, 3.95 }, { -57.6, 3.96, 9.8, 4.00, 108.7, 3.81 }, { -63.9, 3.73, 10.1, 4.06, 130.9, 3.78 }, { -65.9, 3.32, 8.4, 4.21, 164.7, 3.25 }, { -28.7, 1.07, -2.2, 4.84, 207.3, 1.82 } },
+ { { -7.6, 4.00, 1.2, 3.99, 15.7, 3.97 }, { -17.8, 4.01, 2.2, 3.99, 38.4, 3.93 }, { -28.1, 4.00, 3.3, 3.99, 61.0, 3.95 }, { -38.9, 3.99, 4.1, 3.99, 85.8, 3.90 }, { -50.1, 3.97, 4.9, 4.00, 111.1, 3.83 }, { -57.0, 3.82, 5.1, 4.03, 135.8, 3.74 }, { -60.7, 3.52, 3.5, 4.14, 165.6, 3.37 }, { -6.2, 0.40, -15.3, 5.10, 220.2, 1.60 } },
+ { { -6.6, 4.00, 0.3, 3.99, 17.2, 3.96 }, { -14.6, 4.00, 0.3, 3.99, 38.2, 3.95 }, { -24.8, 4.01, 0.1, 4.00, 63.7, 3.93 }, { -33.4, 4.00, 0.1, 4.00, 87.9, 3.91 }, { -42.3, 3.97, 1.0, 3.98, 113.1, 3.86 }, { -49.6, 3.87, -0.0, 4.04, 139.5, 3.74 }, { -51.7, 3.55, -2.0, 4.13, 166.4, 3.50 }, { -30.6, 1.94, -11.3, 4.63, 208.0, 2.29 } },
+ { { -4.9, 4.00, -0.8, 3.99, 17.2, 3.96 }, { -12.9, 4.01, -0.9, 4.00, 40.6, 3.94 }, { -20.7, 4.01, -1.9, 3.99, 65.0, 3.92 }, { -28.7, 4.01, -3.0, 4.00, 91.7, 3.86 }, { -35.2, 3.96, -3.8, 3.99, 115.5, 3.89 }, { -42.2, 3.93, -5.6, 4.04, 142.4, 3.75 }, { -46.2, 3.74, -7.0, 4.09, 171.4, 3.45 }, { -36.8, 2.71, -15.3, 4.55, 206.0, 2.55 } },
+ { { -3.7, 3.99, -0.8, 3.99, 18.6, 3.94 }, { -10.1, 4.01, -3.0, 4.00, 41.1, 3.93 }, { -16.9, 4.01, -3.9, 4.00, 67.0, 3.91 }, { -22.9, 4.01, -5.9, 4.00, 93.6, 3.87 }, { -29.3, 4.00, -8.1, 4.01, 118.9, 3.83 }, { -33.7, 3.92, -10.4, 4.03, 144.7, 3.79 }, { -38.9, 3.84, -12.3, 4.07, 175.5, 3.41 }, { -32.9, 3.03, -16.6, 4.28, 204.5, 2.84 } },
+ { { -2.9, 3.98, -1.8, 4.00, 18.4, 3.96 }, { -7.9, 4.00, -3.9, 4.00, 41.9, 3.93 }, { -12.7, 4.00, -6.8, 4.00, 67.5, 3.93 }, { -17.3, 3.99, -8.8, 4.00, 95.0, 3.88 }, { -21.8, 3.97, -12.0, 4.01, 120.9, 3.86 }, { -26.8, 3.95, -14.4, 4.03, 150.2, 3.64 }, { -30.1, 3.86, -17.8, 4.07, 178.7, 3.40 }, { -30.1, 3.46, -22.5, 4.28, 212.4, 2.53 } },
+ { { -2.0, 4.00, -2.0, 4.00, 17.0, 3.94 }, { -6.0, 4.01, -5.0, 4.00, 44.4, 3.91 }, { -10.0, 4.01, -9.0, 4.01, 70.6, 3.89 }, { -12.9, 4.00, -12.2, 4.01, 97.5, 3.83 }, { -16.9, 4.00, -15.1, 4.01, 125.1, 3.76 }, { -19.8, 3.96, -19.1, 4.03, 151.0, 3.73 }, { -22.2, 3.90, -22.0, 4.03, 179.2, 3.54 }, { -23.2, 3.61, -26.9, 4.20, 212.9, 2.67 } },
+ { { -1.8, 4.00, -2.8, 4.00, 20.3, 3.98 }, { -3.9, 4.00, -6.0, 4.00, 43.2, 3.92 }, { -5.9, 4.00, -11.0, 4.01, 71.5, 3.89 }, { -7.8, 3.99, -15.0, 4.01, 98.8, 3.86 }, { -11.1, 4.01, -19.0, 4.02, 127.3, 3.79 }, { -12.6, 3.97, -23.0, 4.03, 156.1, 3.60 }, { -14.6, 3.95, -26.9, 4.03, 186.5, 3.26 }, { -17.6, 3.92, -30.2, 4.04, 216.1, 2.58 } },
+ { { -0.8, 4.00, -3.1, 3.99, 19.5, 3.96 }, { -0.9, 3.99, -8.0, 4.01, 45.1, 3.91 }, { -1.8, 3.99, -12.8, 4.01, 72.0, 3.90 }, { -2.9, 3.99, -17.5, 4.00, 99.9, 3.87 }, { -3.7, 3.98, -23.1, 4.03, 130.0, 3.74 }, { -4.7, 3.97, -27.9, 4.04, 159.0, 3.59 }, { -5.9, 3.96, -32.3, 4.04, 188.6, 3.27 }, { -6.1, 3.81, -33.9, 3.88, 213.6, 2.93 } },
+ { { 1.3, 3.97, -4.0, 4.01, 19.8, 3.94 }, { 1.2, 3.99, -8.8, 4.00, 45.8, 3.91 }, { 2.2, 3.99, -15.0, 4.01, 74.3, 3.89 }, { 3.2, 3.98, -20.7, 4.00, 102.1, 3.87 }, { 3.1, 3.99, -27.0, 4.02, 133.1, 3.73 }, { 4.3, 3.96, -32.8, 4.04, 162.5, 3.58 }, { 4.6, 3.93, -36.3, 3.94, 190.0, 3.36 }, { 10.8, 3.30, -36.4, 3.60, 225.0, 2.20 } },
+ { { 2.3, 3.99, -5.0, 4.01, 20.7, 3.94 }, { 4.3, 3.99, -11.0, 4.01, 47.2, 3.91 }, { 6.2, 3.99, -17.7, 4.01, 75.7, 3.90 }, { 9.3, 3.97, -24.8, 4.02, 105.9, 3.82 }, { 11.7, 3.94, -32.4, 4.06, 137.0, 3.66 }, { 13.8, 3.96, -37.6, 4.00, 164.4, 3.62 }, { 17.1, 3.82, -43.9, 4.05, 197.5, 3.06 }, { 24.3, 3.00, -22.3, 2.00, 223.0, 2.50 } },
+ { { 3.2, 3.99, -5.9, 4.01, 20.6, 3.94 }, { 7.3, 3.98, -13.0, 4.02, 47.9, 3.91 }, { 11.3, 3.98, -21.0, 4.02, 77.6, 3.87 }, { 16.1, 3.97, -29.0, 4.03, 107.8, 3.82 }, { 20.9, 3.92, -37.0, 4.05, 139.7, 3.66 }, { 26.1, 3.86, -44.6, 4.06, 171.9, 3.40 }, { 26.8, 3.90, -43.6, 3.65, 194.4, 3.38 }, { 39.2, 3.00, -31.2, 2.30, 222.3, 2.35 } },
+ { { 4.2, 3.99, -5.8, 4.01, 20.5, 3.94 }, { 10.2, 3.98, -14.8, 4.01, 48.5, 3.92 }, { 17.0, 3.98, -23.4, 4.01, 78.6, 3.91 }, { 23.8, 3.94, -32.9, 4.03, 111.5, 3.78 }, { 30.5, 3.92, -42.5, 4.05, 142.7, 3.68 }, { 35.2, 3.95, -49.3, 3.99, 173.1, 3.50 }, { 43.5, 3.57, -47.4, 3.49, 202.4, 3.03 }, { 54.2, 3.00, -40.1, 2.60, 221.5, 2.20 } },
+ { { 6.4, 3.98, -8.1, 4.02, 22.8, 3.94 }, { 14.5, 3.96, -17.2, 4.03, 51.4, 3.88 }, { 23.3, 3.96, -27.7, 4.03, 81.8, 3.87 }, { 32.7, 3.92, -37.9, 4.04, 114.3, 3.78 }, { 40.7, 3.92, -47.5, 4.02, 145.2, 3.71 }, { 49.8, 3.81, -55.3, 3.95, 179.8, 3.31 }, { 49.0, 4.00, -15.0, 1.00, 222.0, 2.00 }, { 69.1, 3.00, -49.0, 2.90, 220.8, 2.05 } },
+ { { 7.1, 3.98, -7.8, 4.02, 21.0, 3.94 }, { 18.4, 3.96, -19.0, 4.03, 51.8, 3.88 }, { 29.3, 3.96, -30.9, 4.03, 83.5, 3.84 }, { 41.5, 3.93, -43.1, 4.06, 117.0, 3.73 }, { 51.5, 3.94, -54.1, 4.04, 152.2, 3.46 }, { 56.5, 4.18, -61.0, 3.89, 193.1, 2.63 }, { 67.0, 3.82, -43.1, 2.47, 213.3, 2.10 }, { 84.1, 3.00, -57.9, 3.20, 220.1, 1.90 } },
+ { { 8.2, 3.98, -7.6, 4.01, 19.0, 3.96 }, { 19.4, 3.96, -18.9, 4.02, 45.6, 3.92 }, { 32.6, 3.94, -30.0, 4.03, 74.4, 3.87 }, { 44.7, 3.93, -42.2, 4.05, 104.5, 3.77 }, { 58.6, 3.85, -55.0, 4.11, 137.9, 3.45 }, { 71.6, 3.77, -67.3, 4.19, 173.7, 2.90 }, { 85.1, 3.63, -71.2, 3.94, 204.7, 2.20 }, { 99.0, 3.00, -66.8, 3.50, 219.3, 1.75 } },
+ { { 9.1, 3.97, -7.7, 4.01, 16.7, 3.97 }, { 20.3, 3.97, -17.9, 4.02, 39.5, 3.93 }, { 33.7, 3.94, -29.2, 4.03, 64.2, 3.90 }, { 47.1, 3.92, -40.4, 4.02, 90.6, 3.82 }, { 59.2, 3.91, -51.5, 4.04, 115.1, 3.77 }, { 72.8, 3.86, -63.1, 4.08, 143.9, 3.53 }, { 84.9, 3.84, -73.9, 4.11, 176.0, 2.97 }, { 114.0, 3.00, -75.7, 3.80, 218.6, 1.60 } },
+ { { 8.9, 3.99, -6.5, 3.98, 14.7, 3.98 }, { 21.2, 3.97, -16.8, 4.01, 34.1, 3.97 }, { 34.0, 3.97, -27.3, 4.00, 55.7, 3.96 }, { 47.4, 3.95, -38.6, 4.01, 78.7, 3.91 }, { 61.0, 3.92, -50.0, 4.04, 102.9, 3.79 }, { 75.3, 3.85, -62.0, 4.09, 127.6, 3.61 }, { 88.1, 3.86, -69.7, 4.00, 147.4, 3.59 }, { 102.5, 3.73, -79.2, 4.00, 178.8, 2.92 } },
+ { { 8.9, 3.99, -6.6, 4.00, 12.8, 3.99 }, { 21.2, 3.97, -16.8, 4.01, 30.3, 3.96 }, { 34.9, 3.98, -26.5, 4.00, 50.0, 3.95 }, { 48.5, 3.95, -37.8, 4.02, 70.0, 3.91 }, { 61.7, 3.95, -49.3, 4.04, 89.9, 3.87 }, { 76.3, 3.90, -58.5, 4.02, 111.0, 3.78 }, { 91.3, 3.84, -70.4, 4.07, 134.4, 3.58 }, { 109.5, 3.64, -84.2, 4.21, 166.1, 3.01 } },
+ { { 9.2, 3.98, -6.9, 4.00, 12.2, 3.98 }, { 22.2, 3.97, -15.9, 4.00, 27.0, 3.98 }, { 34.9, 3.98, -25.6, 4.00, 43.9, 3.98 }, { 49.2, 3.97, -36.7, 4.01, 61.5, 3.95 }, { 63.0, 3.96, -46.3, 4.00, 79.3, 3.93 }, { 76.9, 3.94, -57.8, 4.03, 98.3, 3.85 }, { 92.4, 3.87, -68.4, 4.05, 118.6, 3.70 }, { 112.7, 3.69, -82.8, 4.16, 145.7, 3.37 } },
+ { { 11.2, 3.99, -7.7, 4.00, 12.1, 3.99 }, { 22.1, 3.98, -15.8, 4.00, 24.2, 3.98 }, { 35.9, 3.98, -25.6, 4.00, 39.6, 3.97 }, { 49.7, 3.96, -35.9, 4.01, 55.8, 3.94 }, { 64.3, 3.96, -45.5, 4.00, 71.8, 3.93 }, { 77.8, 3.95, -56.0, 4.02, 87.8, 3.89 }, { 92.3, 3.95, -66.1, 4.01, 102.2, 3.90 }, { 119.2, 3.62, -85.3, 4.23, 135.8, 3.40 } },
+ { { 9.4, 4.00, -6.6, 4.00, 9.9, 4.00 }, { 27.1, 4.00, -18.8, 3.99, 28.1, 4.00 }, { 35.0, 3.99, -24.5, 3.99, 36.0, 3.99 }, { 51.4, 3.96, -36.0, 4.01, 52.4, 3.96 }, { 64.0, 3.98, -44.0, 3.97, 66.2, 3.96 }, { 80.0, 3.93, -56.1, 4.02, 81.1, 3.93 }, { 92.4, 3.95, -64.0, 3.99, 94.4, 3.95 }, { 122.5, 3.61, -84.3, 4.19, 125.3, 3.59 } },
+ { { 7.7, 4.00, -5.5, 4.00, 7.7, 4.00 }, { 22.0, 3.98, -14.8, 4.00, 21.1, 3.98 }, { 36.1, 3.98, -24.6, 4.00, 35.1, 3.98 }, { 49.8, 3.99, -34.2, 3.99, 48.6, 3.99 }, { 64.9, 3.98, -44.3, 3.99, 63.1, 3.96 }, { 78.9, 3.97, -53.7, 3.98, 75.5, 3.99 }, { 93.2, 3.97, -64.0, 3.99, 90.2, 3.96 }, { 118.3, 3.79, -79.7, 4.04, 113.3, 3.82 } },
+ { { 10.0, 4.00, -6.8, 4.00, 8.9, 4.00 }, { 23.2, 3.98, -14.9, 4.00, 20.1, 3.98 }, { 36.3, 3.97, -24.7, 4.00, 32.2, 3.98 }, { 50.8, 3.98, -33.4, 3.99, 43.8, 3.99 }, { 65.1, 3.98, -43.6, 4.00, 56.2, 3.98 }, { 80.4, 3.96, -53.3, 3.99, 69.0, 3.97 }, { 94.8, 3.94, -63.5, 4.00, 81.4, 3.97 }, { 122.2, 3.69, -80.6, 4.12, 104.3, 3.80 } },
+ { { 10.1, 3.99, -6.9, 4.00, 8.1, 3.99 }, { 22.8, 3.99, -14.4, 3.99, 17.0, 3.99 }, { 37.0, 3.99, -23.7, 4.00, 28.0, 3.99 }, { 51.0, 3.98, -33.4, 3.99, 39.1, 3.98 }, { 66.4, 3.97, -42.4, 3.98, 50.3, 3.97 }, { 81.0, 3.97, -52.1, 3.99, 60.7, 3.99 }, { 95.3, 3.96, -61.6, 3.98, 71.3, 4.00 }, { 124.2, 3.69, -79.8, 4.13, 93.0, 3.79 } },
+ { { 9.9, 3.99, -5.6, 3.99, 6.0, 3.99 }, { 22.8, 3.99, -14.5, 4.00, 15.0, 3.99 }, { 37.0, 3.99, -23.8, 4.00, 24.0, 3.99 }, { 52.2, 3.97, -32.6, 4.00, 34.4, 3.96 }, { 66.8, 3.98, -41.3, 3.99, 42.9, 3.99 }, { 82.3, 3.96, -51.7, 4.00, 53.1, 3.98 }, { 97.3, 3.92, -60.4, 4.00, 62.3, 3.97 }, { 123.6, 3.75, -75.7, 4.05, 78.4, 3.89 } },
+ { { 11.2, 3.98, -6.9, 4.00, 6.2, 3.99 }, { 23.9, 3.97, -14.1, 3.99, 13.0, 3.99 }, { 38.2, 3.98, -22.8, 4.00, 20.1, 3.99 }, { 53.5, 3.96, -31.7, 4.00, 28.3, 3.98 }, { 67.3, 3.97, -41.3, 3.99, 36.2, 3.98 }, { 82.0, 3.97, -49.8, 3.98, 44.5, 4.00 }, { 98.6, 3.95, -59.5, 4.00, 53.2, 3.97 }, { 128.1, 3.63, -76.7, 4.14, 68.1, 3.85 } },
+ { { 9.8, 3.99, -5.6, 3.99, 4.0, 3.99 }, { 23.9, 3.99, -13.6, 4.00, 10.2, 3.99 }, { 38.2, 3.98, -22.9, 4.01, 17.2, 3.99 }, { 53.1, 3.98, -31.7, 4.00, 23.1, 3.99 }, { 68.5, 3.96, -40.6, 4.00, 30.2, 3.98 }, { 83.3, 3.96, -49.3, 3.99, 36.1, 3.99 }, { 98.3, 3.96, -57.5, 3.97, 42.3, 4.01 }, { 129.6, 3.64, -75.9, 4.16, 56.8, 3.83 } },
+ { { 10.5, 3.98, -5.6, 3.99, 4.3, 3.97 }, { 24.0, 3.98, -13.6, 4.00, 8.2, 3.99 }, { 38.8, 3.99, -21.4, 3.99, 13.1, 3.99 }, { 54.3, 3.97, -30.8, 4.00, 18.2, 3.99 }, { 69.2, 3.97, -39.6, 4.00, 23.0, 3.99 }, { 84.8, 3.94, -48.5, 4.00, 28.3, 3.98 }, { 100.8, 3.93, -56.2, 3.99, 34.3, 3.97 }, { 128.9, 3.69, -72.3, 4.11, 42.5, 3.93 } },
+ { { 9.8, 3.99, -5.6, 4.00, 2.1, 3.99 }, { 24.1, 3.98, -13.4, 4.00, 6.2, 3.99 }, { 39.0, 3.98, -21.6, 4.00, 9.2, 3.99 }, { 54.9, 3.98, -29.2, 3.97, 13.1, 3.99 }, { 70.4, 3.97, -38.8, 4.00, 17.3, 3.98 }, { 85.4, 3.96, -47.6, 4.00, 20.3, 3.99 }, { 102.6, 3.90, -55.8, 4.01, 24.2, 3.98 }, { 133.4, 3.57, -72.4, 4.16, 31.8, 3.90 } },
+ { { 11.3, 3.98, -6.0, 4.00, 2.2, 3.99 }, { 25.1, 3.98, -12.8, 4.00, 4.4, 3.98 }, { 40.0, 3.98, -20.4, 3.98, 6.2, 3.99 }, { 55.1, 3.98, -29.5, 4.00, 8.2, 3.99 }, { 71.0, 3.97, -37.3, 3.99, 10.3, 3.99 }, { 86.1, 3.97, -44.9, 3.98, 11.9, 4.00 }, { 102.9, 3.93, -54.9, 4.02, 15.3, 3.98 }, { 135.9, 3.55, -71.4, 4.17, 19.3, 3.94 } },
+ { { 10.9, 3.99, -5.7, 4.00, 1.2, 3.99 }, { 25.1, 3.98, -12.7, 4.00, 1.2, 3.99 }, { 40.1, 3.98, -20.7, 4.00, 2.2, 3.99 }, { 56.1, 3.97, -28.7, 4.00, 3.3, 3.99 }, { 72.3, 3.96, -36.6, 4.00, 4.3, 3.98 }, { 87.5, 3.95, -44.4, 3.99, 4.3, 3.99 }, { 103.6, 3.94, -53.1, 3.99, 5.1, 3.99 }, { 134.9, 3.62, -68.1, 4.12, 6.2, 4.00 } },
+ { { 9.9, 3.99, -4.7, 3.98, -0.8, 3.99 }, { 25.2, 3.97, -12.7, 4.00, -0.9, 4.00 }, { 41.2, 3.97, -19.6, 3.99, -1.7, 3.99 }, { 57.3, 3.96, -27.5, 3.98, -1.7, 3.99 }, { 72.5, 3.96, -35.7, 4.00, -2.8, 3.99 }, { 88.7, 3.94, -43.7, 4.00, -3.7, 3.99 }, { 105.1, 3.92, -51.6, 4.00, -3.9, 3.99 }, { 139.1, 3.51, -68.2, 4.18, -5.5, 4.01 } },
+ { { 10.9, 3.99, -4.7, 4.00, -0.6, 3.98 }, { 25.2, 3.97, -11.9, 4.00, -2.8, 3.99 }, { 41.3, 3.97, -19.8, 4.00, -4.9, 4.00 }, { 57.6, 3.96, -27.8, 4.01, -6.5, 3.97 }, { 73.9, 3.94, -35.3, 4.00, -9.8, 4.00 }, { 89.4, 3.96, -42.7, 4.00, -12.0, 4.00 }, { 105.7, 3.94, -50.8, 4.01, -13.9, 4.00 }, { 141.5, 3.48, -67.1, 4.18, -18.5, 4.06 } },
+ { { 11.0, 3.99, -4.7, 4.00, -1.8, 3.99 }, { 25.3, 3.97, -11.8, 4.00, -4.8, 3.98 }, { 41.5, 3.96, -18.9, 4.01, -8.8, 4.00 }, { 57.8, 3.95, -26.9, 4.01, -13.1, 4.01 }, { 74.5, 3.96, -33.9, 4.00, -16.0, 4.00 }, { 89.9, 3.97, -41.1, 3.98, -19.6, 3.99 }, { 106.2, 3.96, -49.1, 3.99, -23.0, 4.01 }, { 139.7, 3.57, -63.7, 4.12, -30.7, 4.10 } },
+ { { 11.2, 3.99, -4.9, 4.00, -2.9, 4.00 }, { 25.3, 3.97, -10.9, 4.00, -8.0, 4.00 }, { 42.7, 3.95, -18.9, 4.01, -13.0, 4.01 }, { 58.4, 3.97, -25.9, 4.00, -17.9, 4.00 }, { 74.0, 3.98, -33.4, 4.00, -22.6, 4.00 }, { 91.2, 3.96, -40.5, 3.99, -27.5, 3.99 }, { 107.9, 3.93, -47.4, 3.99, -32.8, 4.01 }, { 144.5, 3.43, -63.8, 4.19, -43.4, 4.15 } },
+ { { 9.9, 3.99, -3.8, 4.00, -3.8, 4.00 }, { 26.5, 3.96, -10.9, 4.00, -10.0, 4.00 }, { 42.3, 3.97, -17.9, 4.00, -16.0, 4.00 }, { 58.9, 3.98, -24.5, 3.99, -22.6, 4.00 }, { 75.3, 3.96, -32.7, 4.00, -28.7, 4.00 }, { 92.8, 3.93, -39.7, 4.00, -35.9, 4.01 }, { 110.8, 3.88, -46.8, 4.01, -42.0, 4.02 }, { 149.5, 3.28, -63.4, 4.24, -57.8, 4.27 } },
+ { { 13.1, 3.99, -4.8, 4.00, -5.8, 4.00 }, { 26.4, 3.97, -10.9, 4.00, -12.8, 4.00 }, { 43.1, 3.98, -17.8, 4.00, -19.8, 4.00 }, { 59.4, 3.96, -24.8, 4.00, -27.8, 4.00 }, { 76.1, 3.96, -31.5, 4.00, -34.7, 3.98 }, { 93.2, 3.95, -38.6, 4.00, -42.3, 3.96 }, { 111.2, 3.89, -45.3, 3.99, -50.5, 3.98 }, { 141.6, 3.61, -58.4, 4.12, -61.8, 4.00 } },
+ { { 12.3, 3.98, -4.9, 4.00, -6.4, 3.99 }, { 26.0, 3.97, -10.6, 4.00, -14.6, 4.00 }, { 42.5, 3.99, -16.5, 3.99, -23.2, 3.99 }, { 60.2, 3.96, -23.8, 4.00, -33.3, 4.00 }, { 77.3, 3.95, -30.6, 4.00, -41.9, 3.98 }, { 93.3, 3.98, -37.0, 3.98, -50.5, 3.94 }, { 110.4, 3.97, -43.7, 3.98, -58.5, 3.89 }, { 134.4, 3.83, -52.4, 4.00, -66.8, 3.79 } },
+ { { 11.1, 3.98, -3.9, 4.00, -6.9, 4.00 }, { 26.8, 3.99, -9.7, 4.00, -17.5, 4.00 }, { 43.5, 3.99, -16.3, 3.99, -28.0, 3.99 }, { 60.7, 3.97, -22.5, 3.99, -39.7, 3.98 }, { 77.5, 3.98, -29.4, 3.99, -50.3, 3.97 }, { 94.4, 4.00, -35.1, 3.98, -59.3, 3.89 }, { 112.6, 3.94, -42.3, 4.00, -69.1, 3.85 }, { 137.5, 3.67, -50.7, 4.05, -79.3, 3.81 } },
+ { { 11.5, 3.99, -3.6, 3.99, -8.2, 3.99 }, { 26.3, 4.00, -9.5, 3.99, -20.0, 3.99 }, { 43.3, 3.99, -15.4, 3.99, -33.3, 3.98 }, { 61.9, 3.96, -21.7, 4.00, -47.8, 4.00 }, { 78.1, 3.99, -27.4, 3.99, -58.7, 3.93 }, { 95.9, 3.97, -34.0, 3.99, -70.6, 3.88 }, { 114.0, 3.90, -38.7, 3.95, -79.8, 3.77 }, { 128.3, 3.98, -44.9, 3.96, -74.4, 3.16 } },
+ { { 11.0, 3.99, -3.5, 3.99, -9.8, 3.99 }, { 27.2, 4.00, -8.4, 3.99, -24.8, 3.99 }, { 44.6, 3.98, -14.4, 3.99, -40.5, 3.99 }, { 62.1, 4.00, -20.4, 3.99, -55.7, 3.96 }, { 79.0, 4.01, -25.3, 3.96, -68.8, 3.87 }, { 96.9, 3.96, -30.8, 3.96, -82.5, 3.84 }, { 112.1, 4.01, -36.8, 3.98, -84.3, 3.41 }, { 133.1, 3.79, -33.9, 3.69, -73.8, 2.73 } },
+ { { 11.5, 4.00, -3.5, 3.99, -12.2, 4.00 }, { 27.2, 4.00, -7.6, 3.98, -29.3, 3.98 }, { 44.8, 4.00, -13.1, 3.99, -47.1, 3.96 }, { 62.6, 4.00, -18.2, 3.98, -65.1, 3.91 }, { 79.5, 4.01, -23.1, 3.96, -79.9, 3.82 }, { 95.1, 4.07, -29.4, 4.00, -89.3, 3.55 }, { 117.0, 3.85, -30.2, 3.86, -90.7, 3.17 }, { 151.0, 3.17, -37.2, 3.95, -75.9, 2.58 } },
+ { { 11.3, 4.00, -2.7, 3.99, -13.7, 3.98 }, { 26.0, 4.00, -6.4, 3.99, -31.8, 3.98 }, { 43.6, 3.97, -11.3, 3.99, -54.0, 3.99 }, { 61.5, 3.93, -15.4, 4.00, -73.5, 3.96 }, { 79.3, 3.90, -21.2, 4.03, -93.4, 3.91 }, { 103.9, 3.66, -27.6, 4.10, -107.7, 3.74 }, { 169.4, 2.20, -46.9, 4.55, -92.8, 2.82 }, { 169.0, 2.55, -40.5, 4.21, -78.1, 2.44 } },
+ { { 8.7, 4.02, -1.5, 3.99, -12.7, 3.96 }, { 23.0, 4.00, -4.6, 3.99, -33.9, 3.98 }, { 37.5, 4.01, -7.4, 3.97, -54.3, 3.94 }, { 53.8, 3.96, -11.5, 4.00, -76.4, 3.95 }, { 69.3, 3.94, -14.9, 4.01, -94.1, 3.83 }, { 91.0, 3.73, -20.0, 4.07, -112.8, 3.76 }, { 135.0, 2.90, -33.5, 4.35, -113.1, 3.27 }, { 186.9, 1.94, -43.9, 4.48, -80.2, 2.29 } },
+ { { 8.2, 4.01, -0.6, 3.98, -14.3, 3.97 }, { 20.2, 4.00, -2.7, 3.99, -34.2, 3.96 }, { 32.9, 4.01, -5.3, 3.99, -55.9, 3.93 }, { 45.8, 4.00, -7.1, 3.98, -77.0, 3.89 }, { 60.6, 3.95, -9.8, 4.00, -97.4, 3.83 }, { 77.6, 3.82, -13.0, 4.04, -115.4, 3.72 }, { 110.0, 3.30, -21.8, 4.21, -122.5, 3.39 }, { 204.9, 1.32, -47.2, 4.74, -82.4, 2.15 } },
+ { { 7.1, 4.00, -0.8, 3.99, -14.1, 3.97 }, { 17.1, 4.01, -1.5, 3.99, -35.1, 3.95 }, { 27.9, 4.01, -2.5, 3.99, -57.3, 3.93 }, { 39.7, 3.99, -3.6, 3.99, -80.6, 3.93 }, { 52.1, 3.96, -5.1, 4.01, -101.6, 3.86 }, { 68.5, 3.81, -7.2, 4.03, -122.2, 3.81 }, { 93.2, 3.47, -11.9, 4.13, -129.7, 3.47 }, { 222.8, 0.70, -50.5, 5.00, -84.5, 2.00 } },
+ };
+
+ int h = hsl & 127;
+ int s = (hsl >> 7) & 7;
+ int l = hsl >> 10;
+
+ if(h >= 88)
+ h -= 88;
+
+ const auto &cinf = color_bases[h][s];
+ static auto conv = [](float i, float s, float l) -> uint8_t { int c = int(i + l*s + 0.5); if(c < 0) c = 0; if(c > 255) c = 255; return c; };
+
+ return std::make_tuple(conv(cinf.ri, cinf.rs, l), conv(cinf.gi, cinf.gs, l), conv(cinf.bi, cinf.bs, l));
+}
+
void spg110_video_device::device_start()
{
save_item(NAME(m_dma_src_step));
@@ -551,8 +697,6 @@ void spg110_video_device::device_start()
save_item(NAME(m_bg_scrollx));
save_item(NAME(m_bg_scrolly));
save_item(NAME(m_2036_scroll));
-
- m_video_irq_cb.resolve();
}
void spg110_video_device::device_reset()
@@ -575,60 +719,10 @@ void spg110_video_device::device_reset()
m_video_irq_status = 0x0000;
}
-double spg110_video_device::hue2rgb(double p, double q, double t)
-{
- if (t < 0) t += 1;
- if (t > 1) t -= 1;
- if (t < 1 / 6.0f) return p + (q - p) * 6 * t;
- if (t < 1 / 2.0f) return q;
- if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6;
- return p;
-}
-
-
-// wrong format!
void spg110_video_device::palette_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
- // probably not
- const double h_add = 0.65f;
- const double h_divide = 43.2f;
-
- COMBINE_DATA(&m_palram[offset]);
-
- uint16_t dat = m_palram[offset];
-
- // llll lsss sshh hhhh
- int l_raw = (dat & 0xfe00) >> 10;
- int sl_raw = (dat & 0x03c0) >> 6;
- int h_raw = (dat & 0x003f) >> 0;
-
- double l = (double)l_raw / 63.0f;
- double s = (double)sl_raw / 15.0f;
- double h = (double)h_raw / h_divide;
-
- // probably not
- h += h_add;
-
- if (h>1.0f)
- h-= 1.0f;
-
- double r, g, b;
-
- if (s == 0) {
- r = g = b = l; // greyscale
- } else {
- double q = l < 0.5f ? l * (1 + s) : l + s - l * s;
- double p = 2 * l - q;
- r = hue2rgb(p, q, h + 1/3.0f);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1/3.0f);
- }
-
- int r_real = r * 255.0f;
- int g_real = g * 255.0f;
- int b_real = b * 255.0f;
-
- m_palette->set_pen_color(offset, r_real, g_real, b_real);
+ auto rgb = hsl_to_rgb(data);
+ m_palette->set_pen_color(offset, std::get<0>(rgb), std::get<1>(rgb), std::get<2>(rgb));
}
uint32_t spg110_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
@@ -660,7 +754,7 @@ uint32_t spg110_video_device::screen_update(screen_device &screen, bitmap_rgb32
return 0;
}
-WRITE_LINE_MEMBER(spg110_video_device::vblank)
+void spg110_video_device::vblank(int state)
{
const int i = 0x0008;
diff --git a/src/devices/machine/spg110_video.h b/src/devices/machine/spg110_video.h
index 8d46ef6c7f3..c1bcc60395c 100644
--- a/src/devices/machine/spg110_video.h
+++ b/src/devices/machine/spg110_video.h
@@ -31,9 +31,8 @@ public:
void map_video(address_map &map);
- double hue2rgb(double p, double q, double t);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
- DECLARE_WRITE_LINE_MEMBER(vblank);
+ void vblank(int state);
void spg110_201c_w(uint16_t data);
void spg110_2020_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
@@ -86,7 +85,7 @@ public:
void tmap0_regs_w(offs_t offset, uint16_t data);
void tmap1_regs_w(offs_t offset, uint16_t data);
- auto write_video_irq_callback() { return m_video_irq_cb.bind(); };
+ auto write_video_irq_callback() { return m_video_irq_cb.bind(); }
protected:
virtual void device_start() override;
@@ -131,6 +130,9 @@ private:
required_shared_ptr<uint16_t> m_sprattr1;
required_shared_ptr<uint16_t> m_sprattr2;
+ static uint16_t rgb_to_hsl(uint8_t r, uint8_t g, uint8_t b);
+ static std::tuple<uint8_t, uint8_t, uint8_t> hsl_to_rgb(uint16_t hsl);
+
void palette_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t tmap0_regs[0x6];
diff --git a/src/devices/machine/spg290_cdservo.cpp b/src/devices/machine/spg290_cdservo.cpp
index 651d5e16818..02a65e5be72 100644
--- a/src/devices/machine/spg290_cdservo.cpp
+++ b/src/devices/machine/spg290_cdservo.cpp
@@ -33,10 +33,7 @@ spg290_cdservo_device::spg290_cdservo_device(const machine_config &mconfig, cons
void spg290_cdservo_device::device_start()
{
- m_irq_cb.resolve_safe();
- m_space_write_cb.resolve_safe();
-
- m_cdtimer = timer_alloc();
+ m_cdtimer = timer_alloc(FUNC(spg290_cdservo_device::cd_update), this);
m_dsp_memory = std::make_unique<uint32_t[]>(0x10000);
save_item(NAME(m_addr));
@@ -91,17 +88,13 @@ void spg290_cdservo_device::device_reset()
m_irq_cb(CLEAR_LINE);
// generate Q subchannel
- if (m_cdrom.found())
- {
- auto *cdrom = m_cdrom->get_cdrom_file();
- if (cdrom != nullptr)
- generate_qsub(cdrom);
- }
+ if (m_cdrom.found() && m_cdrom->exists())
+ generate_qsub();
change_status();
}
-void spg290_cdservo_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(spg290_cdservo_device::cd_update)
{
if (!(m_control1 & 0x04) && m_cur_sector == m_seek_lba + SPG290_LEADIN_LEN)
{
@@ -109,7 +102,7 @@ void spg290_cdservo_device::device_timer(emu_timer &timer, device_timer_id id, i
if (BIT(m_control0, 15)) // CDDA
{
- cdrom_read_data(m_cdrom->get_cdrom_file(), m_cur_sector - 150 - SPG290_LEADIN_LEN, cdbuf, CD_TRACK_AUDIO);
+ m_cdrom->read_data(m_cur_sector - 150 - SPG290_LEADIN_LEN, cdbuf, cdrom_file::CD_TRACK_AUDIO);
for (int i=0; i<2352; i++)
{
@@ -120,13 +113,13 @@ void spg290_cdservo_device::device_timer(emu_timer &timer, device_timer_id id, i
}
else
{
- cdrom_read_data(m_cdrom->get_cdrom_file(), m_cur_sector - 150 - SPG290_LEADIN_LEN, cdbuf, CD_TRACK_MODE1_RAW);
+ m_cdrom->read_data(m_cur_sector - 150 - SPG290_LEADIN_LEN, cdbuf, cdrom_file::CD_TRACK_MODE1_RAW);
// FIXME: this is required for load iso images
- if (cdrom_get_track_type(m_cdrom->get_cdrom_file(), m_qsub[m_cur_sector * 12 + 1] - 1) == CD_TRACK_MODE1)
+ if (m_cdrom->get_track_type(m_qsub[m_cur_sector * 12 + 1] - 1) == cdrom_file::CD_TRACK_MODE1)
{
int lba = (bcd_2_dec(cdbuf[12]) * 60 + bcd_2_dec(cdbuf[13])) * 75 + bcd_2_dec(cdbuf[14]);
- uint32_t msf = lba_to_msf(lba + 150);
+ uint32_t msf = cdrom_file::lba_to_msf(lba + 150);
cdbuf[12] = (msf >> 16) & 0xff;
cdbuf[13] = (msf >> 8) & 0xff;
cdbuf[14] = (msf >> 0) & 0xff;
@@ -332,7 +325,7 @@ void spg290_cdservo_device::servo_cmd_w()
void spg290_cdservo_device::change_status()
{
- if (m_speed == 0 || !m_cdrom.found() || !m_cdrom->get_cdrom_file())
+ if (m_speed == 0 || !m_cdrom.found() || !m_cdrom->exists())
m_cdtimer->adjust(attotime::never);
else
m_cdtimer->adjust(attotime::from_hz(75 * m_speed), 0, attotime::from_hz(75 * m_speed));
@@ -355,11 +348,11 @@ void spg290_cdservo_device::add_qsub(int sector, uint8_t addrctrl, uint8_t track
dest[11] = crc16;
}
-void spg290_cdservo_device::generate_qsub(cdrom_file *cdrom)
+void spg290_cdservo_device::generate_qsub()
{
- const cdrom_toc *toc = cdrom_get_toc(cdrom);
- int numtracks = cdrom_get_last_track(cdrom);
- uint32_t total_sectors = cdrom_get_track_start(cdrom, numtracks - 1) + toc->tracks[numtracks - 1].frames + 150;
+ const cdrom_file::toc &toc = m_cdrom->get_toc();
+ int numtracks = m_cdrom->get_last_track();
+ uint32_t total_sectors = m_cdrom->get_track_start(numtracks - 1) + toc.tracks[numtracks - 1].frames + 150;
m_tot_sectors = SPG290_LEADIN_LEN + total_sectors + SPG290_LEADOUT_LEN;
m_qsub = std::make_unique<uint8_t[]>(m_tot_sectors * 12);
@@ -369,54 +362,54 @@ void spg290_cdservo_device::generate_qsub(cdrom_file *cdrom)
// 7500 sectors lead-in
for (int s=0; s < SPG290_LEADIN_LEN; s += numtracks + 3)
{
- if (lba < SPG290_LEADIN_LEN) add_qsub(lba++, 0x14, 0, 0xa0, lba_to_msf(s + 0), 1 << 16); // first track number
- if (lba < SPG290_LEADIN_LEN) add_qsub(lba++, 0x14, 0, 0xa1, lba_to_msf(s + 1), numtracks << 16); // last track number
- if (lba < SPG290_LEADIN_LEN) add_qsub(lba++, 0x14, 0, 0xa2, lba_to_msf(s + 2), lba_to_msf(total_sectors)); // start time of lead-out
+ if (lba < SPG290_LEADIN_LEN) add_qsub(lba++, 0x14, 0, 0xa0, cdrom_file::lba_to_msf(s + 0), 1 << 16); // first track number
+ if (lba < SPG290_LEADIN_LEN) add_qsub(lba++, 0x14, 0, 0xa1, cdrom_file::lba_to_msf(s + 1), numtracks << 16); // last track number
+ if (lba < SPG290_LEADIN_LEN) add_qsub(lba++, 0x14, 0, 0xa2, cdrom_file::lba_to_msf(s + 2), cdrom_file::lba_to_msf(total_sectors)); // start time of lead-out
for(int track = 0; track < numtracks; track++)
{
- uint32_t track_start = cdrom_get_track_start(cdrom, track) + 150;
+ uint32_t track_start = m_cdrom->get_track_start(track) + 150;
if (lba < SPG290_LEADIN_LEN)
- add_qsub(lba++, cdrom_get_adr_control(cdrom, track), 0, dec_2_bcd(track + 1), lba_to_msf(s + 3 + track), lba_to_msf(track_start));
+ add_qsub(lba++, m_cdrom->get_adr_control(track), 0, dec_2_bcd(track + 1), cdrom_file::lba_to_msf(s + 3 + track), cdrom_file::lba_to_msf(track_start));
}
}
// data tracks
for(int track = 0; track < numtracks; track++)
{
- uint32_t control = cdrom_get_adr_control(cdrom, track);
- uint32_t track_start = cdrom_get_track_start(cdrom, track);
+ uint32_t control = m_cdrom->get_adr_control(track);
+ uint32_t track_start = m_cdrom->get_track_start(track);
// pregap
- uint32_t pregap = toc->tracks[track].pregap;
+ uint32_t pregap = toc.tracks[track].pregap;
// first track should have a 150 frames pregap
- if (track == 0 && toc->tracks[0].pregap == 0)
+ if (track == 0 && toc.tracks[0].pregap == 0)
pregap = 150;
- else if (track != 0 && toc->tracks[0].pregap == 0)
+ else if (track != 0 && toc.tracks[0].pregap == 0)
track_start += 150;
for(int s = 0; s < pregap; s++)
- add_qsub(lba++, control, dec_2_bcd(track + 1), 0, lba_to_msf(s), lba_to_msf(track_start + s));
+ add_qsub(lba++, control, dec_2_bcd(track + 1), 0, cdrom_file::lba_to_msf(s), cdrom_file::lba_to_msf(track_start + s));
track_start += pregap;
- for(int s = 0; s < toc->tracks[track].frames; s++)
+ for(int s = 0; s < toc.tracks[track].frames; s++)
{
// TODO: if present use subcode from CHD
- add_qsub(lba++, control, dec_2_bcd(track + 1), 1, lba_to_msf(s), lba_to_msf(track_start + s));
+ add_qsub(lba++, control, dec_2_bcd(track + 1), 1, cdrom_file::lba_to_msf(s), cdrom_file::lba_to_msf(track_start + s));
}
- track_start += toc->tracks[track].frames;
+ track_start += toc.tracks[track].frames;
// postgap
- for(int s = 0; s < toc->tracks[track].postgap; s++)
- add_qsub(lba++, control, dec_2_bcd(track + 1), 2, lba_to_msf(s), lba_to_msf(track_start + s));
+ for(int s = 0; s < toc.tracks[track].postgap; s++)
+ add_qsub(lba++, control, dec_2_bcd(track + 1), 2, cdrom_file::lba_to_msf(s), cdrom_file::lba_to_msf(track_start + s));
- track_start += toc->tracks[track].postgap;
+ track_start += toc.tracks[track].postgap;
}
// 6750 sectors lead-out
for(int s = 0; s < SPG290_LEADOUT_LEN; s++)
- add_qsub(lba++, 0x14, 0xaa, 1, lba_to_msf(s), lba_to_msf(total_sectors + s));
+ add_qsub(lba++, 0x14, 0xaa, 1, cdrom_file::lba_to_msf(s), cdrom_file::lba_to_msf(total_sectors + s));
}
diff --git a/src/devices/machine/spg290_cdservo.h b/src/devices/machine/spg290_cdservo.h
index 790e7b4c28d..2f44e96b353 100644
--- a/src/devices/machine/spg290_cdservo.h
+++ b/src/devices/machine/spg290_cdservo.h
@@ -7,7 +7,7 @@
#pragma once
-#include "imagedev/chd_cd.h"
+#include "imagedev/cdromimg.h"
class spg290_cdservo_device : public device_t
@@ -31,12 +31,13 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(cd_update);
private:
void change_status();
void add_qsub(int sector, uint8_t addrctrl, uint8_t track, uint8_t index, uint32_t rel_msf, uint32_t abs_msf, uint16_t crc16=0);
- void generate_qsub(cdrom_file *cdrom);
+ void generate_qsub();
void servo_cmd_r();
void servo_cmd_w();
diff --git a/src/devices/machine/spg290_i2c.cpp b/src/devices/machine/spg290_i2c.cpp
index 94faef82598..41eaaf58437 100644
--- a/src/devices/machine/spg290_i2c.cpp
+++ b/src/devices/machine/spg290_i2c.cpp
@@ -16,17 +16,14 @@ DEFINE_DEVICE_TYPE(SPG290_I2C, spg290_i2c_device, "spg290_i2c", "SPG290 I2C")
spg290_i2c_device::spg290_i2c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SPG290_I2C, tag, owner, clock)
, m_irq_cb(*this)
- , m_i2c_read_cb(*this)
+ , m_i2c_read_cb(*this, 0)
, m_i2c_write_cb(*this)
{
}
void spg290_i2c_device::device_start()
{
- m_irq_cb.resolve_safe();
- m_i2c_read_cb.resolve_safe(0);
- m_i2c_write_cb.resolve_safe();
- m_i2c_timer = timer_alloc();
+ m_i2c_timer = timer_alloc(FUNC(spg290_i2c_device::i2c_update), this);
save_item(NAME(m_config));
save_item(NAME(m_irq_control));
@@ -52,7 +49,7 @@ void spg290_i2c_device::device_reset()
m_irq_cb(CLEAR_LINE);
}
-void spg290_i2c_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(spg290_i2c_device::i2c_update)
{
if (m_config & 0x40)
m_rdata = m_i2c_read_cb(m_port_addr);
diff --git a/src/devices/machine/spg290_i2c.h b/src/devices/machine/spg290_i2c.h
index 9b6c35cd9d9..2dca1d145f4 100644
--- a/src/devices/machine/spg290_i2c.h
+++ b/src/devices/machine/spg290_i2c.h
@@ -23,7 +23,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ TIMER_CALLBACK_MEMBER(i2c_update);
private:
devcb_write_line m_irq_cb;
diff --git a/src/devices/machine/spg290_ppu.cpp b/src/devices/machine/spg290_ppu.cpp
index 19ff7ccb1d2..fde5b7338a0 100644
--- a/src/devices/machine/spg290_ppu.cpp
+++ b/src/devices/machine/spg290_ppu.cpp
@@ -27,7 +27,7 @@ spg290_ppu_device::spg290_ppu_device(const machine_config &mconfig, const char *
, m_voffset_ram(*this, "voffset_ram")
, m_sprite_ram(*this, "sprite_ram")
, m_vblank_irq_cb(*this)
- , m_space_read_cb(*this)
+ , m_space_read_cb(*this, 0)
{
}
@@ -49,9 +49,6 @@ void spg290_ppu_device::map(address_map &map)
void spg290_ppu_device::device_start()
{
- m_vblank_irq_cb.resolve_safe();
- m_space_read_cb.resolve_safe(0);
-
save_item(NAME(m_control));
save_item(NAME(m_sprite_control));
save_item(NAME(m_irq_control));
@@ -335,14 +332,14 @@ inline rgb_t spg290_ppu_device::blend_colors(const rgb_t &c0, const rgb_t &c1, u
if (m_blend_mode & 1)
{
int r = (c0.r() * level / 63) - (c1.r() * (63 - level) / 63);
- int g = (c0.b() * level / 63) - (c1.b() * (63 - level) / 63);
+ int g = (c0.g() * level / 63) - (c1.g() * (63 - level) / 63);
int b = (c0.b() * level / 63) - (c1.b() * (63 - level) / 63);
return rgb_t(r, g, b);
}
else
{
int r = (c0.r() * level / 63) + (c1.r() * (63 - level) / 63);
- int g = (c0.b() * level / 63) + (c1.b() * (63 - level) / 63);
+ int g = (c0.g() * level / 63) + (c1.g() * (63 - level) / 63);
int b = (c0.b() * level / 63) + (c1.b() * (63 - level) / 63);
return rgb_t(r, g, b);
}
@@ -382,7 +379,7 @@ void spg290_ppu_device::blit_sprite(bitmap_rgb32 &bitmap, const rectangle &clipr
uint8_t bit_pixel = ((attribute & 3) + 1) << 1;
uint8_t sprite_flip = (attribute >> 2) & 0x03;
uint16_t pen_bank = ((attribute >> 8) & 0x1f) * 0x10;
- uint8_t blend = (attribute & 0x8000) ? (attribute >> 26) & 0x3f : 0;
+ uint8_t blend = (attribute & 0x8000) ? 0x3f - ((attribute >> 26) & 0x3f) : 0;
uint8_t pixel_word = 32 / bit_pixel;
uint8_t pixel_byte = 8 / bit_pixel;
uint8_t word_line = sprite_hsize / pixel_word;
diff --git a/src/devices/machine/spg290_timer.cpp b/src/devices/machine/spg290_timer.cpp
index 25ee7790e8b..f0c0867a612 100644
--- a/src/devices/machine/spg290_timer.cpp
+++ b/src/devices/machine/spg290_timer.cpp
@@ -16,13 +16,13 @@ DEFINE_DEVICE_TYPE(SPG290_TIMER, spg290_timer_device, "spg290_timer", "SPG290 Ti
spg290_timer_device::spg290_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SPG290_TIMER, tag, owner, clock)
, m_irq_cb(*this)
+ , m_enabled(false)
{
}
void spg290_timer_device::device_start()
{
- m_irq_cb.resolve_safe();
- m_tick_timer = timer_alloc();
+ m_tick_timer = timer_alloc(FUNC(spg290_timer_device::timer_update), this);
save_item(NAME(m_enabled));
save_item(NAME(m_control));
@@ -56,7 +56,7 @@ void spg290_timer_device::device_clock_changed()
m_tick_timer->adjust(attotime::never);
}
-void spg290_timer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(spg290_timer_device::timer_update)
{
if (!BIT(m_control, 31))
return;
diff --git a/src/devices/machine/spg290_timer.h b/src/devices/machine/spg290_timer.h
index 44c399fbb64..486011cb90b 100644
--- a/src/devices/machine/spg290_timer.h
+++ b/src/devices/machine/spg290_timer.h
@@ -22,7 +22,7 @@ protected:
virtual void device_reset() override;
virtual void device_clock_changed() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ TIMER_CALLBACK_MEMBER(timer_update);
private:
devcb_write_line m_irq_cb;
diff --git a/src/devices/machine/spg2xx.cpp b/src/devices/machine/spg2xx.cpp
index 412b2d20a14..09e0e0c6f39 100644
--- a/src/devices/machine/spg2xx.cpp
+++ b/src/devices/machine/spg2xx.cpp
@@ -30,14 +30,14 @@ spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, co
m_porta_out(*this),
m_portb_out(*this),
m_portc_out(*this),
- m_porta_in(*this),
- m_portb_in(*this),
- m_portc_in(*this),
- m_adc_in(*this),
- m_guny_in(*this),
- m_gunx_in(*this),
+ m_porta_in(*this, 0),
+ m_portb_in(*this, 0),
+ m_portc_in(*this, 0),
+ m_adc_in(*this, 0x0fff),
+ m_guny_in(*this, 0),
+ m_gunx_in(*this, 0),
m_i2c_w(*this),
- m_i2c_r(*this),
+ m_i2c_r(*this, 0),
m_uart_tx(*this),
m_spi_tx(*this),
m_chip_sel(*this),
@@ -86,21 +86,6 @@ void spg2xx_device::device_start()
{
unsp_device::device_start();
- m_porta_out.resolve_safe();
- m_portb_out.resolve_safe();
- m_portc_out.resolve_safe();
- m_porta_in.resolve_safe(0);
- m_portb_in.resolve_safe(0);
- m_portc_in.resolve_safe(0);
- m_adc_in.resolve_all_safe(0x0fff);
- m_guny_in.resolve_safe(0);
- m_gunx_in.resolve_safe(0);
- m_i2c_w.resolve_safe();
- m_i2c_r.resolve_safe(0);
- m_uart_tx.resolve_safe();
- m_spi_tx.resolve_safe();
- m_chip_sel.resolve_safe();
-
save_item(NAME(m_sprite_limit));
save_item(NAME(m_pal_flag));
save_item(NAME(m_fiq_vector));
@@ -117,7 +102,7 @@ void spg2xx_device::fiq_vector_w(uint8_t data)
m_fiq_vector = data;
}
-WRITE_LINE_MEMBER(spg2xx_device::videoirq_w)
+void spg2xx_device::videoirq_w(int state)
{
if (m_fiq_vector == 0)
{
@@ -129,37 +114,37 @@ WRITE_LINE_MEMBER(spg2xx_device::videoirq_w)
}
}
-WRITE_LINE_MEMBER(spg2xx_device::timerirq_w)
+void spg2xx_device::timerirq_w(int state)
{
set_state_unsynced(UNSP_IRQ2_LINE, state);
}
-WRITE_LINE_MEMBER(spg2xx_device::uartirq_w)
+void spg2xx_device::uartirq_w(int state)
{
set_state_unsynced(UNSP_IRQ3_LINE, state);
}
-WRITE_LINE_MEMBER(spg2xx_device::audioirq_w)
+void spg2xx_device::audioirq_w(int state)
{
set_state_unsynced(UNSP_IRQ4_LINE, state);
}
-WRITE_LINE_MEMBER(spg2xx_device::audiochirq_w)
+void spg2xx_device::audiochirq_w(int state)
{
set_state_unsynced(UNSP_FIQ_LINE, state);
}
-WRITE_LINE_MEMBER(spg2xx_device::extirq_w)
+void spg2xx_device::extirq_w(int state)
{
set_state_unsynced(UNSP_IRQ5_LINE, state);
}
-WRITE_LINE_MEMBER(spg2xx_device::ffreq1_w)
+void spg2xx_device::ffreq1_w(int state)
{
set_state_unsynced(UNSP_IRQ6_LINE, state);
}
-WRITE_LINE_MEMBER(spg2xx_device::ffreq2_w)
+void spg2xx_device::ffreq2_w(int state)
{
set_state_unsynced(UNSP_IRQ7_LINE, state);
}
diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h
index 68d42675360..fab0da8a874 100644
--- a/src/devices/machine/spg2xx.h
+++ b/src/devices/machine/spg2xx.h
@@ -74,7 +74,7 @@ public:
void uart_rx(uint8_t data) { m_spg_io->uart_rx(data); }
void spi_rx(int state) { m_spg_io->spi_rx(state); }
- DECLARE_WRITE_LINE_MEMBER(vblank) { m_spg_video->vblank(state); }
+ void vblank(int state) { m_spg_video->vblank(state); }
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_spg_video->screen_update(screen, bitmap, cliprect); }
protected:
@@ -83,14 +83,14 @@ protected:
void internal_map(address_map &map);
void fiq_vector_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(videoirq_w);
- DECLARE_WRITE_LINE_MEMBER(audioirq_w);
- DECLARE_WRITE_LINE_MEMBER(audiochirq_w);
- DECLARE_WRITE_LINE_MEMBER(timerirq_w);
- DECLARE_WRITE_LINE_MEMBER(uartirq_w);
- DECLARE_WRITE_LINE_MEMBER(extirq_w);
- DECLARE_WRITE_LINE_MEMBER(ffreq1_w);
- DECLARE_WRITE_LINE_MEMBER(ffreq2_w);
+ void videoirq_w(int state);
+ void audioirq_w(int state);
+ void audiochirq_w(int state);
+ void timerirq_w(int state);
+ void uartirq_w(int state);
+ void extirq_w(int state);
+ void ffreq1_w(int state);
+ void ffreq2_w(int state);
uint16_t space_r(offs_t offset);
@@ -140,10 +140,10 @@ protected:
template <size_t Line> uint16_t adc_r() { return m_adc_in[Line](); }
void eepromx_w(offs_t offset, uint8_t data, uint8_t mem_mask = ~0) { m_i2c_w(offset, data, mem_mask); }
- uint8_t eepromx_r() { return m_i2c_r(); };
+ uint8_t eepromx_r() { return m_i2c_r(); }
void uart_tx_w(offs_t offset, uint8_t data, uint8_t mem_mask = ~0) { m_uart_tx(offset, data, mem_mask); }
- DECLARE_WRITE_LINE_MEMBER(spi_tx_w) { m_spi_tx(state); }
+ void spi_tx_w(int state) { m_spi_tx(state); }
void cs_w(offs_t offset, uint8_t data, uint8_t mem_mask = ~0) { m_chip_sel(offset, data, mem_mask); }
};
diff --git a/src/devices/machine/spg2xx_audio.cpp b/src/devices/machine/spg2xx_audio.cpp
index 2441ebf17ce..2cf0fd822d8 100644
--- a/src/devices/machine/spg2xx_audio.cpp
+++ b/src/devices/machine/spg2xx_audio.cpp
@@ -24,15 +24,15 @@ DEFINE_DEVICE_TYPE(SPG2XX_AUDIO, spg2xx_audio_device, "spg2xx_audio", "SPG2xx-se
DEFINE_DEVICE_TYPE(SPG110_AUDIO, spg110_audio_device, "spg110_audio", "SPG110-series System-on-a-Chip Audio")
DEFINE_DEVICE_TYPE(SUNPLUS_GCM394_AUDIO, sunplus_gcm394_audio_device, "gcm394_audio", "SunPlus GCM394 System-on-a-Chip (Audio)")
-#define LOG_SPU_READS (1U << 0)
-#define LOG_SPU_WRITES (1U << 1)
-#define LOG_UNKNOWN_SPU (1U << 2)
-#define LOG_CHANNEL_READS (1U << 3)
-#define LOG_CHANNEL_WRITES (1U << 4)
-#define LOG_ENVELOPES (1U << 5)
-#define LOG_SAMPLES (1U << 6)
-#define LOG_RAMPDOWN (1U << 7)
-#define LOG_BEAT (1U << 8)
+#define LOG_SPU_READS (1U << 1)
+#define LOG_SPU_WRITES (1U << 2)
+#define LOG_UNKNOWN_SPU (1U << 3)
+#define LOG_CHANNEL_READS (1U << 4)
+#define LOG_CHANNEL_WRITES (1U << 5)
+#define LOG_ENVELOPES (1U << 6)
+#define LOG_SAMPLES (1U << 7)
+#define LOG_RAMPDOWN (1U << 8)
+#define LOG_BEAT (1U << 9)
#define LOG_ALL (LOG_SPU_READS | LOG_SPU_WRITES | LOG_UNKNOWN_SPU | LOG_CHANNEL_READS | LOG_CHANNEL_WRITES \
| LOG_ENVELOPES | LOG_SAMPLES | LOG_RAMPDOWN | LOG_BEAT)
@@ -50,7 +50,7 @@ static FILE *adpcm_file[16] = {};
spg2xx_audio_device::spg2xx_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, device_sound_interface(mconfig, *this)
- , m_space_read_cb(*this)
+ , m_space_read_cb(*this, 0)
, m_irq_cb(*this)
, m_ch_irq_cb(*this)
{
@@ -73,7 +73,7 @@ sunplus_gcm394_audio_device::sunplus_gcm394_audio_device(const machine_config &m
void spg2xx_audio_device::device_start()
{
- m_audio_beat = timer_alloc(TIMER_BEAT);
+ m_audio_beat = timer_alloc(FUNC(spg2xx_audio_device::audio_beat_tick), this);
m_audio_beat->adjust(attotime::never);
m_stream = stream_alloc(0, 2, 281250/4);
@@ -107,13 +107,9 @@ void spg2xx_audio_device::device_start()
memset(m_adpcm36_state + i, 0, sizeof(adpcm36_state));
- m_channel_irq[i] = timer_alloc(TIMER_IRQ + i);
+ m_channel_irq[i] = timer_alloc(FUNC(spg2xx_audio_device::irq_tick), this);
m_channel_irq[i]->adjust(attotime::never);
}
-
- m_space_read_cb.resolve_safe(0);
- m_irq_cb.resolve();
- m_ch_irq_cb.resolve();
}
void spg2xx_audio_device::device_reset()
@@ -159,24 +155,12 @@ void spg2xx_audio_device::device_stop()
#endif
}
-void spg2xx_audio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(spg2xx_audio_device::irq_tick)
{
- if (id >= TIMER_IRQ && id < (TIMER_IRQ + 16))
- {
- const uint32_t bit = id - TIMER_IRQ;
- if (!BIT(m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_STATUS], bit))
- {
- m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_STATUS] |= (1 << (id - TIMER_IRQ));
- m_ch_irq_cb(1);
- }
- return;
- }
-
- switch (id)
+ if (!BIT(m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_STATUS], param))
{
- case TIMER_BEAT:
- audio_beat_tick();
- break;
+ m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_STATUS] |= (1 << param);
+ m_ch_irq_cb(1);
}
}
@@ -480,7 +464,7 @@ void spg2xx_audio_device::audio_ctrl_w(offs_t offset, uint16_t data)
m_audio_ctrl_regs[offset] |= mask;
if (BIT(m_audio_ctrl_regs[AUDIO_CHANNEL_FIQ_ENABLE], channel_bit))
{
- m_channel_irq[channel_bit]->adjust(attotime::from_hz(m_channel_rate[channel_bit]), 0, attotime::from_hz(m_channel_rate[channel_bit]));
+ m_channel_irq[channel_bit]->adjust(attotime::from_hz(m_channel_rate[channel_bit]), channel_bit, attotime::from_hz(m_channel_rate[channel_bit]));
}
else
{
@@ -1250,7 +1234,7 @@ inline void spg2xx_audio_device::loop_channel(const uint32_t channel)
LOGMASKED(LOG_SAMPLES, "Channel %d: Looping to address %08x\n", channel, m_sample_addr[channel]);
}
-void spg2xx_audio_device::audio_beat_tick()
+TIMER_CALLBACK_MEMBER(spg2xx_audio_device::audio_beat_tick)
{
if (m_audio_curr_beat_base_count > 0)
{
diff --git a/src/devices/machine/spg2xx_audio.h b/src/devices/machine/spg2xx_audio.h
index 588d49e7895..d0712139134 100644
--- a/src/devices/machine/spg2xx_audio.h
+++ b/src/devices/machine/spg2xx_audio.h
@@ -35,7 +35,8 @@ protected:
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
- void audio_beat_tick();
+ TIMER_CALLBACK_MEMBER(irq_tick);
+ TIMER_CALLBACK_MEMBER(audio_beat_tick);
void audio_rampdown_tick(const uint32_t channel);
bool audio_envelope_tick(const uint32_t channel);
inline uint32_t get_rampdown_frame_count(const uint32_t channel);
@@ -329,15 +330,11 @@ protected:
int16_t m_prevsamp[2];
};
- static const device_timer_id TIMER_BEAT = 3;
- static const device_timer_id TIMER_IRQ = 4;
-
void check_irqs(const uint16_t changed);
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_stop() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
uint16_t read_space(offs_t offset);
diff --git a/src/devices/machine/spg2xx_io.cpp b/src/devices/machine/spg2xx_io.cpp
index 14cf55d7929..9c930360eec 100644
--- a/src/devices/machine/spg2xx_io.cpp
+++ b/src/devices/machine/spg2xx_io.cpp
@@ -43,18 +43,18 @@ spg2xx_io_device::spg2xx_io_device(const machine_config &mconfig, device_type ty
m_porta_out(*this),
m_portb_out(*this),
m_portc_out(*this),
- m_porta_in(*this),
- m_portb_in(*this),
- m_portc_in(*this),
- m_adc_in(*this),
+ m_porta_in(*this, 0),
+ m_portb_in(*this, 0),
+ m_portc_in(*this, 0),
+ m_adc_in(*this, 0x0fff),
m_i2c_w(*this),
- m_i2c_r(*this),
+ m_i2c_r(*this, 0),
m_uart_tx(*this),
m_spi_tx(*this),
m_chip_sel(*this),
m_cpu(*this, finder_base::DUMMY_TAG),
m_screen(*this, finder_base::DUMMY_TAG),
- m_pal_read_cb(*this),
+ m_pal_read_cb(*this, 0),
m_timer_irq_cb(*this),
m_uart_adc_irq_cb(*this),
m_external_irq_cb(*this),
@@ -77,62 +77,24 @@ spg28x_io_device::spg28x_io_device(const machine_config &mconfig, const char *ta
void spg2xx_io_device::device_start()
{
- m_porta_out.resolve_safe();
- m_portb_out.resolve_safe();
- m_portc_out.resolve_safe();
- m_porta_in.resolve_safe(0);
- m_portb_in.resolve_safe(0);
- m_portc_in.resolve_safe(0);
- m_adc_in.resolve_all_safe(0x0fff);
- m_i2c_w.resolve_safe();
- m_i2c_r.resolve_safe(0);
- m_uart_tx.resolve_safe();
- m_spi_tx.resolve_safe();
- m_chip_sel.resolve_safe();
- m_pal_read_cb.resolve_safe(0);
-
- m_timer_irq_cb.resolve();
- m_uart_adc_irq_cb.resolve();
- m_external_irq_cb.resolve();
- m_ffreq_tmr1_irq_cb.resolve();
- m_ffreq_tmr2_irq_cb.resolve();
-
- m_fiq_vector_w.resolve();
-
- m_tmb1 = timer_alloc(TIMER_TMB1);
- m_tmb2 = timer_alloc(TIMER_TMB2);
- m_tmb1->adjust(attotime::never);
- m_tmb2->adjust(attotime::never);
-
- m_uart_tx_timer = timer_alloc(TIMER_UART_TX);
- m_uart_tx_timer->adjust(attotime::never);
-
- m_uart_rx_timer = timer_alloc(TIMER_UART_RX);
- m_uart_rx_timer->adjust(attotime::never);
-
- m_4khz_timer = timer_alloc(TIMER_4KHZ);
- m_4khz_timer->adjust(attotime::never);
-
- m_timer_src_ab = timer_alloc(TIMER_SRC_AB);
- m_timer_src_ab->adjust(attotime::never);
+ m_tmb1 = timer_alloc(FUNC(spg2xx_io_device::tmb_timer_tick<0>), this);
+ m_tmb2 = timer_alloc(FUNC(spg2xx_io_device::tmb_timer_tick<1>), this);
- m_timer_src_c = timer_alloc(TIMER_SRC_C);
- m_timer_src_c->adjust(attotime::never);
+ m_uart_tx_timer = timer_alloc(FUNC(spg2xx_io_device::uart_transmit_tick), this);
+ m_uart_rx_timer = timer_alloc(FUNC(spg2xx_io_device::uart_receive_tick), this);
- m_rng_timer = timer_alloc(TIMER_RNG);
- m_rng_timer->adjust(attotime::never);
+ m_4khz_timer = timer_alloc(FUNC(spg2xx_io_device::system_timer_tick), this);
- m_watchdog_timer = timer_alloc(TIMER_WATCHDOG);
- m_watchdog_timer->adjust(attotime::never);
+ m_timer_src_ab = timer_alloc(FUNC(spg2xx_io_device::timer_ab_tick), this);
+ m_timer_src_c = timer_alloc(FUNC(spg2xx_io_device::timer_c_tick), this);
+ m_rng_timer = timer_alloc(FUNC(spg2xx_io_device::rng_clock_tick), this);
+ m_watchdog_timer = timer_alloc(FUNC(spg2xx_io_device::watchdog_tick), this);
+ m_spi_tx_timer = timer_alloc(FUNC(spg2xx_io_device::spi_tx_tick), this);
- m_spi_tx_timer = timer_alloc(TIMER_SPI_TX);
- m_spi_tx_timer->adjust(attotime::never);
-
- for (int i = 0; i < 4; i++)
- {
- m_adc_timer[i] = timer_alloc(TIMER_ADC0 + i);
- m_adc_timer[i]->adjust(attotime::never);
- }
+ m_adc_timer[0] = timer_alloc(FUNC(spg2xx_io_device::adc_convert_tick<0>), this);
+ m_adc_timer[1] = timer_alloc(FUNC(spg2xx_io_device::adc_convert_tick<1>), this);
+ m_adc_timer[2] = timer_alloc(FUNC(spg2xx_io_device::adc_convert_tick<2>), this);
+ m_adc_timer[3] = timer_alloc(FUNC(spg2xx_io_device::adc_convert_tick<3>), this);
save_item(NAME(m_io_regs));
@@ -179,7 +141,7 @@ void spg2xx_io_device::device_start()
void spg2xx_io_device::device_reset()
{
- memset(m_io_regs, 0, 0x100 * sizeof(uint16_t));
+ std::fill_n(&m_io_regs[0], 0x100, 0);
m_timer_a_preload = 0;
m_timer_b_preload = 0;
@@ -190,7 +152,7 @@ void spg2xx_io_device::device_reset()
m_io_regs[REG_PRNG1] = 0x1418;
m_io_regs[REG_PRNG2] = 0x1658;
- memset(m_uart_rx_fifo, 0, ARRAY_LENGTH(m_uart_rx_fifo));
+ std::fill(std::begin(m_uart_rx_fifo), std::end(m_uart_rx_fifo), 0);
m_uart_rx_fifo_start = 0;
m_uart_rx_fifo_end = 0;
m_uart_rx_fifo_count = 0;
@@ -198,14 +160,14 @@ void spg2xx_io_device::device_reset()
m_uart_tx_irq = false;
m_uart_rx_irq = false;
- memset(m_spi_tx_fifo, 0, ARRAY_LENGTH(m_spi_tx_fifo));
+ std::fill(std::begin(m_spi_tx_fifo), std::end(m_spi_tx_fifo), 0);
m_spi_tx_fifo_start = 0;
m_spi_tx_fifo_end = 0;
m_spi_tx_fifo_count = 0;
m_spi_tx_buf = 0x00;
m_spi_tx_bit = 8;
- memset(m_spi_rx_fifo, 0, ARRAY_LENGTH(m_spi_rx_fifo));
+ std::fill(std::begin(m_spi_rx_fifo), std::end(m_spi_rx_fifo), 0);
m_spi_rx_fifo_start = 0;
m_spi_rx_fifo_end = 0;
m_spi_rx_fifo_count = 0;
@@ -214,7 +176,7 @@ void spg2xx_io_device::device_reset()
m_spi_rate = 0;
- memset(m_extint, 0, sizeof(bool) * 2);
+ std::fill_n(&m_extint[0], 2, false);
m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096));
@@ -252,7 +214,7 @@ void spg2xx_io_device::uart_rx(uint8_t data)
if (BIT(m_io_regs[REG_UART_CTRL], 6))
{
m_uart_rx_fifo[m_uart_rx_fifo_end] = data;
- m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % ARRAY_LENGTH(m_uart_rx_fifo);
+ m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % std::size(m_uart_rx_fifo);
m_uart_rx_fifo_count++;
if (m_uart_rx_timer->remaining() == attotime::never)
m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[REG_UART_CTRL], 5) ? 11 : 10, m_uart_baud_rate));
@@ -275,7 +237,7 @@ void spg2xx_io_device::set_spi_irq(bool set)
const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
if (changed)
- check_irqs(changed);
+ check_data_irq();
}
void spg2xx_io_device::update_spi_irqs()
@@ -286,7 +248,7 @@ void spg2xx_io_device::update_spi_irqs()
set_spi_irq(ovf_set || rxi_set || txi_set);
}
-void spg2xx_io_device::do_spi_tx()
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::spi_tx_tick)
{
if (!BIT(m_io_regs[REG_SPI_CTRL], 15) || m_spi_tx_fifo_count == 0)
{
@@ -387,6 +349,12 @@ void spg2xx_io_device::spi_rx(int state)
}
}
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::rng_clock_tick)
+{
+ clock_rng(0);
+ clock_rng(1);
+}
+
uint16_t spg2xx_io_device::clock_rng(int which)
{
const uint16_t value = m_io_regs[REG_PRNG1 + which];
@@ -458,15 +426,7 @@ uint16_t spg2xx_io_device::io_r(offs_t offset)
break;
case REG_ADC_DATA:
- if (!machine().side_effects_disabled())
- {
- const uint16_t old = IO_IRQ_STATUS;
- IO_IRQ_STATUS &= ~0x2000;
- const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
- if (changed)
- check_irqs(changed);
- LOGMASKED(LOG_IO_READS | LOG_ADC, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val);
- }
+ LOGMASKED(LOG_IO_READS | LOG_ADC, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val);
break;
case REG_WAKEUP_SOURCE:
@@ -535,7 +495,7 @@ uint16_t spg2xx_io_device::io_extended_r(offs_t offset)
LOGMASKED(LOG_UART, "%s: Remaining count %d, value %02x\n", machine().describe_context(), m_uart_rx_fifo_count, m_uart_rx_fifo[m_uart_rx_fifo_start]);
m_io_regs[REG_UART_RXBUF] = m_uart_rx_fifo[m_uart_rx_fifo_start];
val = m_io_regs[REG_UART_RXBUF];
- m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo);
+ m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % std::size(m_uart_rx_fifo);
m_uart_rx_fifo_count--;
if (m_uart_rx_fifo_count == 0)
@@ -545,7 +505,6 @@ uint16_t spg2xx_io_device::io_extended_r(offs_t offset)
else
{
LOGMASKED(LOG_UART, "Remaining count %d, setting up timer\n", m_uart_rx_fifo_count);
- //uart_receive_tick();
if (m_uart_rx_timer->remaining() == attotime::never)
m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[REG_UART_CTRL], 5) ? 11 : 10, m_uart_baud_rate));
}
@@ -718,7 +677,7 @@ void spg2xx_io_device::update_timer_b_rate()
}
}
-void spg2xx_io_device::update_timer_ab_src()
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::timer_ab_tick)
{
if (m_timer_b_tick_rate == 0)
return;
@@ -741,14 +700,11 @@ void spg2xx_io_device::increment_timer_a()
IO_IRQ_STATUS |= 0x0800;
const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
if (changed)
- {
- //printf("Timer A overflow\n");
- check_irqs(0x0800);
- }
+ check_timers_irq();
}
}
-void spg2xx_io_device::update_timer_c_src()
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::timer_c_tick)
{
m_io_regs[REG_TIMERB_DATA]++;
if (m_io_regs[REG_TIMERB_DATA] == 0)
@@ -758,10 +714,7 @@ void spg2xx_io_device::update_timer_c_src()
IO_IRQ_STATUS |= 0x0400;
const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
if (changed)
- {
- printf("Timer B overflow\n");
- check_irqs(0x0400);
- }
+ check_timers_irq();
}
}
@@ -954,7 +907,7 @@ void spg2xx_io_device::io_w(offs_t offset, uint16_t data)
IO_IRQ_STATUS &= ~0x0800;
const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
if (changed)
- check_irqs(0x0800);
+ check_timers_irq();
break;
}
@@ -998,7 +951,7 @@ void spg2xx_io_device::io_w(offs_t offset, uint16_t data)
IO_IRQ_STATUS &= ~0x0400;
const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
if (changed)
- check_irqs(0x0400);
+ check_timers_irq();
break;
}
@@ -1030,7 +983,7 @@ void spg2xx_io_device::io_w(offs_t offset, uint16_t data)
m_io_regs[REG_INT_CTRL] = data;
const uint16_t changed = (IO_IRQ_STATUS & old) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
if (changed)
- check_irqs(changed);
+ check_all_irqs(changed);
break;
}
@@ -1046,7 +999,7 @@ void spg2xx_io_device::io_w(offs_t offset, uint16_t data)
IO_IRQ_STATUS |= 0x0100;
}
if (changed)
- check_irqs(changed);
+ check_all_irqs(changed);
break;
}
@@ -1099,33 +1052,24 @@ void spg2xx_io_device::io_w(offs_t offset, uint16_t data)
const uint16_t old_ctrl = m_io_regs[REG_ADC_CTRL];
m_io_regs[REG_ADC_CTRL] = data & ~0x2000;
- const uint16_t channel = (m_io_regs[REG_ADC_CTRL] >> 4) & 3;
- if (BIT(m_io_regs[REG_ADC_CTRL], 0))
+ if (BIT(old_ctrl, 13) && BIT(data, 13))
{
- if (!BIT(old_ctrl, 0))
- {
- m_io_regs[REG_ADC_CTRL] |= 0x2000;
- if (BIT(m_io_regs[REG_ADC_CTRL], 9))
- {
- const uint16_t old = IO_IRQ_STATUS;
- IO_IRQ_STATUS |= 0x2000;
- const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
- if (changed)
- check_irqs(changed);
- }
- }
+ m_io_regs[REG_ADC_CTRL] &= ~0x2000;
+ IO_IRQ_STATUS &= ~0x2000;
+ check_data_irq();
+ }
- if (BIT(data, 13))
- {
- m_io_regs[REG_ADC_CTRL] &= ~0x2000;
- check_irqs(0x2000);
- }
+ if (BIT(m_io_regs[REG_ADC_CTRL], 0))
+ {
+ // Assume ready unless stated otherwise (i.e., conversion request is issued).
+ m_io_regs[REG_ADC_CTRL] |= 0x2000;
+ const uint16_t adc_channel = (m_io_regs[REG_ADC_CTRL] >> 4) & 3;
if (!BIT(old_ctrl, 12) && BIT(m_io_regs[REG_ADC_CTRL], 12))
{
m_io_regs[REG_ADC_CTRL] &= ~0x3000;
const uint32_t adc_clocks = 16 << ((m_io_regs[REG_ADC_CTRL] >> 2) & 3);
- m_adc_timer[channel]->adjust(attotime::from_ticks(adc_clocks, 27000000));
+ m_adc_timer[adc_channel]->adjust(attotime::from_ticks(adc_clocks, 27000000));
m_io_regs[REG_ADC_DATA] &= ~0x8000;
}
@@ -1133,7 +1077,7 @@ void spg2xx_io_device::io_w(offs_t offset, uint16_t data)
if (BIT(data, 10))
{
m_io_regs[REG_ADC_DATA] &= ~0x8000;
- m_adc_timer[channel]->adjust(attotime::from_hz(8000), 0, attotime::from_hz(8000));
+ m_adc_timer[adc_channel]->adjust(attotime::from_hz(8000), 0, attotime::from_hz(8000));
}
}
else
@@ -1280,7 +1224,7 @@ void spg2xx_io_device::io_extended_w(offs_t offset, uint16_t data)
IO_IRQ_STATUS &= ~0x0100;
const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
if (changed)
- check_irqs(0x0100);
+ check_data_irq();
}
break;
@@ -1495,111 +1439,57 @@ void spg2xx_io_device::io_extended_w(offs_t offset, uint16_t data)
}
}
-void spg2xx_io_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+template <int Which>
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::tmb_timer_tick)
{
- switch (id)
- {
- case TIMER_TMB1:
- {
- LOGMASKED(LOG_TIMERS, "TMB1 elapsed, setting IRQ Status bit 0 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 1, IO_IRQ_ENABLE);
- const uint16_t old = IO_IRQ_STATUS;
- IO_IRQ_STATUS |= 1;
- const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
- if (changed)
- check_irqs(0x0001);
- break;
- }
-
- case TIMER_TMB2:
- {
- LOGMASKED(LOG_TIMERS, "TMB2 elapsed, setting IRQ Status bit 1 (old:%04x, new:%04x, enable:%04x)\n", IO_IRQ_STATUS, IO_IRQ_STATUS | 2, IO_IRQ_ENABLE);
- const uint16_t old = IO_IRQ_STATUS;
- IO_IRQ_STATUS |= 2;
- const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
- if (changed)
- check_irqs(0x0002);
- break;
- }
-
- case TIMER_UART_TX:
- uart_transmit_tick();
- break;
-
- case TIMER_UART_RX:
- uart_receive_tick();
- break;
-
- case TIMER_4KHZ:
- system_timer_tick();
- break;
-
- case TIMER_SRC_AB:
- update_timer_ab_src();
- break;
-
- case TIMER_SRC_C:
- update_timer_c_src();
- break;
-
- case TIMER_RNG:
- clock_rng(0);
- clock_rng(1);
- break;
-
- case TIMER_WATCHDOG:
- m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
- m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
- break;
-
- case TIMER_SPI_TX:
- do_spi_tx();
- break;
+ LOGMASKED(LOG_TIMERS, "TMB%d elapsed, setting IRQ Status bit 0 (old:%04x, new:%04x, enable:%04x)\n", Which + 1, IO_IRQ_STATUS, IO_IRQ_STATUS | (1 << Which), IO_IRQ_ENABLE);
+ const uint16_t old = IO_IRQ_STATUS;
+ IO_IRQ_STATUS |= (1 << Which);
+ const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
+ if (changed)
+ check_tmb_lofreq_key_irq();
+}
- case TIMER_ADC0:
- case TIMER_ADC1:
- case TIMER_ADC2:
- case TIMER_ADC3:
- do_adc_capture(id - TIMER_ADC0);
- break;
- }
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::watchdog_tick)
+{
+ m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
}
-void spg2xx_io_device::system_timer_tick()
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::system_timer_tick)
{
- const uint16_t old = IO_IRQ_STATUS;
- uint16_t check_mask = 0x0040;
IO_IRQ_STATUS |= 0x0040;
+ bool check_lofreq = false;
+
m_2khz_divider++;
if (m_2khz_divider == 2)
{
m_2khz_divider = 0;
IO_IRQ_STATUS |= 0x0020;
- check_mask |= 0x0020;
m_1khz_divider++;
if (m_1khz_divider == 2)
{
m_1khz_divider = 0;
IO_IRQ_STATUS |= 0x0010;
- check_mask |= 0x0010;
m_4hz_divider++;
if (m_4hz_divider == 256)
{
m_4hz_divider = 0;
IO_IRQ_STATUS |= 0x0008;
- check_mask |= 0x0008;
+ check_lofreq = BIT(IO_IRQ_ENABLE, 3);
}
}
}
- const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
- if (changed)
- check_irqs(check_mask);
+ check_hifreq_periodic_irq();
+ if (check_lofreq)
+ check_tmb_lofreq_key_irq();
}
-void spg2xx_io_device::uart_transmit_tick()
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::uart_transmit_tick)
{
LOGMASKED(LOG_UART, "uart_transmit_tick: Transmitting %02x, setting TxReady, clearing TxBusy\n", (uint8_t)m_io_regs[REG_UART_TXBUF]);
m_uart_tx((uint8_t)m_io_regs[REG_UART_TXBUF]);
@@ -1611,15 +1501,15 @@ void spg2xx_io_device::uart_transmit_tick()
IO_IRQ_STATUS |= 0x0100;
m_uart_tx_irq = true;
LOGMASKED(LOG_UART, "uart_transmit_tick: Setting UART IRQ bit\n");
- if (IO_IRQ_STATUS != old)
+ if (IO_IRQ_STATUS != old && BIT(IO_IRQ_ENABLE, 8))
{
LOGMASKED(LOG_UART, "uart_transmit_tick: Bit newly set, checking IRQs\n");
- check_irqs(0x0100);
+ check_data_irq();
}
}
}
-void spg2xx_io_device::uart_receive_tick()
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::uart_receive_tick)
{
LOGMASKED(LOG_UART, "uart_receive_tick: Setting RBF and RxRDY\n");
m_io_regs[REG_UART_STATUS] |= 0x81;
@@ -1629,7 +1519,8 @@ void spg2xx_io_device::uart_receive_tick()
LOGMASKED(LOG_UART, "uart_receive_tick: RxIntEn is set, setting rx_irq to true and setting UART IRQ\n");
m_uart_rx_irq = true;
IO_IRQ_STATUS |= 0x0100;
- check_irqs(0x0100);
+ if (BIT(IO_IRQ_ENABLE, 8))
+ check_data_irq();
}
}
@@ -1653,59 +1544,56 @@ void spg2xx_io_device::check_extint_irq(int channel)
if (old_irq != IO_IRQ_STATUS)
{
LOGMASKED(LOG_EXTINT, "extint IRQ changed, so checking interrupts\n");
- check_irqs(mask);
+ check_external_irq();
}
}
-void spg2xx_io_device::check_irqs(const uint16_t changed)
+void spg2xx_io_device::check_timers_irq()
{
- if (changed & 0x0c00) // Timer A, Timer B IRQ
- {
- LOGMASKED(LOG_TIMERS, "%ssserting IRQ2 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00), changed);
+ LOGMASKED(LOG_TIMERS, "Checking IRQ2 (%04x)\n", IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00);
+ m_timer_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? ASSERT_LINE : CLEAR_LINE);
+}
- if (m_timer_irq_cb)
- m_timer_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0c00) ? ASSERT_LINE : CLEAR_LINE);
- else
- logerror("spg2xx_io_device::check_irqs, attempted to use m_timer_irq_cb without setting it\n");
- }
+void spg2xx_io_device::check_data_irq()
+{
+ LOGMASKED(LOG_UART | LOG_SIO | LOG_SPI | LOG_I2C | LOG_ADC, "Checking IRQ3 (%04x)\n", IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100);
+ m_uart_adc_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x6100) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void spg2xx_io_device::check_external_irq()
+{
+ LOGMASKED(LOG_EXTINT, "Checking IRQ5 (%04x)\n", IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200);
+ m_external_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void spg2xx_io_device::check_hifreq_periodic_irq()
+{
+ LOGMASKED(LOG_TIMERS, "Checking IRQ6 (%04x)\n", IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070);
+ m_ffreq_tmr1_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void spg2xx_io_device::check_tmb_lofreq_key_irq()
+{
+ LOGMASKED(LOG_IRQS, "Checking IRQ7 (%04x)\n", IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b);
+ m_ffreq_tmr2_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void spg2xx_io_device::check_all_irqs(const uint16_t changed)
+{
+ if (changed & 0x0c00) // Timer A, Timer B IRQ
+ check_timers_irq();
if (changed & 0x6100) // UART, SPI, SIO, I2C, ADC IRQ
- {
- LOGMASKED(LOG_UART | LOG_SIO | LOG_SPI | LOG_I2C | LOG_ADC, "%ssserting IRQ3 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x6100) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x2100), changed);
- if (m_uart_adc_irq_cb)
- m_uart_adc_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x6100) ? ASSERT_LINE : CLEAR_LINE);
- else
- logerror("spg2xx_io_device::check_irqs, attempted to use m_uart_adc_irq_cb without setting it\n");
- }
+ check_data_irq();
if (changed & 0x1200) // External IRQ
- {
- LOGMASKED(LOG_EXTINT, "%ssserting IRQ5 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200), changed);
- if (m_external_irq_cb)
- m_external_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x1200) ? ASSERT_LINE : CLEAR_LINE);
- else
- logerror("spg2xx_io_device::check_irqs, attempted to use m_external_irq_cb without setting it\n");
-
- }
+ check_external_irq();
if (changed & 0x0070) // 1024Hz, 2048Hz, 4096Hz IRQ
- {
- LOGMASKED(LOG_TIMERS, "%ssserting IRQ6 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070), changed); //m_cpu->set_state_unsynced(UNSP_IRQ6_LINE, (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? ASSERT_LINE : CLEAR_LINE);
- if (m_ffreq_tmr1_irq_cb)
- m_ffreq_tmr1_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x0070) ? ASSERT_LINE : CLEAR_LINE);
- else
- logerror("spg2xx_io_device::check_irqs, attempted to use m_ffreq_tmr1_irq_cb without setting it\n");
- }
+ check_hifreq_periodic_irq();
if (changed & 0x008b) // TMB1, TMB2, 4Hz, key change IRQ
- {
- LOGMASKED(LOG_IRQS, "%ssserting IRQ7 (%04x, %04x)\n", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? "A" : "Dea", (IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b), changed);
- if (m_ffreq_tmr2_irq_cb)
- m_ffreq_tmr2_irq_cb((IO_IRQ_ENABLE & IO_IRQ_STATUS & 0x008b) ? ASSERT_LINE : CLEAR_LINE);
- else
- logerror("spg2xx_io_device::check_irqs, attempted to use m_ffreq_tmr2_irq_cb without setting it\n");
-
- }
+ check_tmb_lofreq_key_irq();
}
uint16_t spg2xx_io_device::do_special_gpio(uint32_t index, uint16_t mask)
@@ -1776,22 +1664,17 @@ void spg2xx_io_device::do_gpio(uint32_t offset, bool write)
m_io_regs[5 * index + 1] = what;
}
-void spg2xx_io_device::do_adc_capture(int channel)
+template <int Which>
+TIMER_CALLBACK_MEMBER(spg2xx_io_device::adc_convert_tick)
{
- m_io_regs[REG_ADC_DATA] = (m_adc_in[channel]() & 0x0fff) | 0x8000;
- if (BIT(m_io_regs[REG_ADC_DATA], 11))
- {
- //m_io_regs[REG_ADC_DATA] |= 0xf000;
- }
+ m_io_regs[REG_ADC_DATA] = (m_adc_in[Which]() & 0x0fff) | 0x8000;
m_io_regs[REG_ADC_CTRL] |= 0x2000;
- const uint16_t old = IO_IRQ_STATUS;
if (BIT(m_io_regs[REG_ADC_CTRL], 9))
{
IO_IRQ_STATUS |= 0x2000;
- const uint16_t changed = (old & IO_IRQ_ENABLE) ^ (IO_IRQ_STATUS & IO_IRQ_ENABLE);
- if (changed)
+ if (BIT(m_io_regs[REG_ADC_CTRL], 9) && BIT(IO_IRQ_ENABLE, 13))
{
- check_irqs(changed);
+ check_data_irq();
}
}
}
diff --git a/src/devices/machine/spg2xx_io.h b/src/devices/machine/spg2xx_io.h
index 6cbe3f95098..c674ae72e6b 100644
--- a/src/devices/machine/spg2xx_io.h
+++ b/src/devices/machine/spg2xx_io.h
@@ -41,15 +41,15 @@ public:
virtual uint16_t io_extended_r(offs_t offset);
virtual void io_extended_w(offs_t offset, uint16_t data);
- auto pal_read_callback() { return m_pal_read_cb.bind(); };
+ auto pal_read_callback() { return m_pal_read_cb.bind(); }
- auto write_timer_irq_callback() { return m_timer_irq_cb.bind(); };
- auto write_uart_adc_irq_callback() { return m_uart_adc_irq_cb.bind(); };
- auto write_external_irq_callback() { return m_external_irq_cb.bind(); };
- auto write_ffrq_tmr1_irq_callback() { return m_ffreq_tmr1_irq_cb.bind(); };
- auto write_ffrq_tmr2_irq_callback() { return m_ffreq_tmr2_irq_cb.bind(); };
+ auto write_timer_irq_callback() { return m_timer_irq_cb.bind(); }
+ auto write_uart_adc_irq_callback() { return m_uart_adc_irq_cb.bind(); }
+ auto write_external_irq_callback() { return m_external_irq_cb.bind(); }
+ auto write_ffrq_tmr1_irq_callback() { return m_ffreq_tmr1_irq_cb.bind(); }
+ auto write_ffrq_tmr2_irq_callback() { return m_ffreq_tmr2_irq_cb.bind(); }
- auto write_fiq_vector_callback() { return m_fiq_vector_w.bind(); };
+ auto write_fiq_vector_callback() { return m_fiq_vector_w.bind(); }
template <size_t Line> uint16_t adc_r() { return m_adc_in[Line](); }
@@ -149,26 +149,26 @@ protected:
REG_IO_DRIVE_CTRL
};
void check_extint_irq(int channel);
- void check_irqs(const uint16_t changed);
-
- static const device_timer_id TIMER_TMB1 = 0;
- static const device_timer_id TIMER_TMB2 = 1;
- static const device_timer_id TIMER_UART_TX = 4;
- static const device_timer_id TIMER_UART_RX = 5;
- static const device_timer_id TIMER_4KHZ = 6;
- static const device_timer_id TIMER_SRC_AB = 7;
- static const device_timer_id TIMER_SRC_C = 8;
- static const device_timer_id TIMER_RNG = 9;
- static const device_timer_id TIMER_WATCHDOG = 10;
- static const device_timer_id TIMER_SPI_TX = 11;
- static const device_timer_id TIMER_ADC0 = 12;
- static const device_timer_id TIMER_ADC1 = 13;
- static const device_timer_id TIMER_ADC2 = 14;
- static const device_timer_id TIMER_ADC3 = 15;
+ void check_timers_irq();
+ void check_data_irq();
+ void check_external_irq();
+ void check_hifreq_periodic_irq();
+ void check_tmb_lofreq_key_irq();
+ void check_all_irqs(const uint16_t changed);
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(timer_ab_tick);
+ TIMER_CALLBACK_MEMBER(timer_c_tick);
+ template <int Which> TIMER_CALLBACK_MEMBER(tmb_timer_tick);
+ TIMER_CALLBACK_MEMBER(uart_transmit_tick);
+ TIMER_CALLBACK_MEMBER(uart_receive_tick);
+ TIMER_CALLBACK_MEMBER(system_timer_tick);
+ TIMER_CALLBACK_MEMBER(rng_clock_tick);
+ TIMER_CALLBACK_MEMBER(watchdog_tick);
+ TIMER_CALLBACK_MEMBER(spi_tx_tick);
+ template <int Which> TIMER_CALLBACK_MEMBER(adc_convert_tick);
uint16_t clock_rng(int which);
@@ -178,23 +178,13 @@ protected:
uint16_t do_special_gpio(uint32_t index, uint16_t mask);
void update_timer_b_rate();
- void update_timer_ab_src();
- void update_timer_c_src();
void increment_timer_a();
- void uart_transmit_tick();
- void uart_receive_tick();
-
- void system_timer_tick();
-
- void do_spi_tx();
void set_spi_irq(bool set);
void update_spi_irqs();
void do_i2c();
- void do_adc_capture(int channel);
-
uint16_t m_io_regs[0x100];
uint8_t m_uart_rx_fifo[8];
diff --git a/src/devices/machine/spg2xx_sysdma.cpp b/src/devices/machine/spg2xx_sysdma.cpp
index d48eee75fdf..1cdadba8251 100644
--- a/src/devices/machine/spg2xx_sysdma.cpp
+++ b/src/devices/machine/spg2xx_sysdma.cpp
@@ -11,7 +11,7 @@
DEFINE_DEVICE_TYPE(SPG2XX_SYSDMA, spg2xx_sysdma_device, "spg2xx_sysdma", "SPG240-series System-on-a-Chip System DMA")
-#define LOG_DMA (1U << 9)
+#define LOG_DMA (1U << 1)
#define LOG_ALL (LOG_DMA)
#define VERBOSE (0)
diff --git a/src/devices/machine/spg2xx_video.cpp b/src/devices/machine/spg2xx_video.cpp
index da3bb29f7df..f165e930654 100644
--- a/src/devices/machine/spg2xx_video.cpp
+++ b/src/devices/machine/spg2xx_video.cpp
@@ -11,12 +11,12 @@
DEFINE_DEVICE_TYPE(SPG24X_VIDEO, spg24x_video_device, "spg24x_video", "SPG240-series System-on-a-Chip (Video)")
-#define LOG_IRQS (1U << 4)
-#define LOG_VLINES (1U << 5)
-#define LOG_DMA (1U << 9)
-#define LOG_PPU_READS (1U << 22)
-#define LOG_PPU_WRITES (1U << 23)
-#define LOG_UNKNOWN_PPU (1U << 24)
+#define LOG_IRQS (1U << 1)
+#define LOG_VLINES (1U << 2)
+#define LOG_DMA (1U << 3)
+#define LOG_PPU_READS (1U << 4)
+#define LOG_PPU_WRITES (1U << 5)
+#define LOG_UNKNOWN_PPU (1U << 6)
#define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU)
#define LOG_ALL (LOG_IRQS | LOG_PPU | LOG_VLINES | LOG_DMA )
@@ -28,16 +28,16 @@ DEFINE_DEVICE_TYPE(SPG24X_VIDEO, spg24x_video_device, "spg24x_video", "SPG240-se
spg2xx_video_device::spg2xx_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
- m_guny_in(*this),
- m_gunx_in(*this),
- m_sprlimit_read_cb(*this),
+ m_guny_in(*this, 0),
+ m_gunx_in(*this, 0),
+ m_sprlimit_read_cb(*this, 0),
+ m_video_irq_cb(*this),
m_cpu(*this, finder_base::DUMMY_TAG),
m_screen(*this, finder_base::DUMMY_TAG),
m_scrollram(*this, "scrollram"),
m_hcompram(*this, "hcompram"),
m_paletteram(*this, "paletteram"),
m_spriteram(*this, "spriteram"),
- m_video_irq_cb(*this),
m_renderer(*this, "renderer")
{
}
@@ -49,16 +49,10 @@ spg24x_video_device::spg24x_video_device(const machine_config &mconfig, const ch
void spg2xx_video_device::device_start()
{
- m_guny_in.resolve_safe(0);
- m_gunx_in.resolve_safe(0);
-
- m_screenpos_timer = timer_alloc(TIMER_SCREENPOS);
+ m_screenpos_timer = timer_alloc(FUNC(spg2xx_video_device::screenpos_hit), this);
m_screenpos_timer->adjust(attotime::never);
save_item(NAME(m_video_regs));
-
- m_sprlimit_read_cb.resolve_safe(0);
- m_video_irq_cb.resolve();
}
void spg2xx_video_device::device_reset()
@@ -439,7 +433,7 @@ void spg2xx_video_device::video_w(offs_t offset, uint16_t data)
}
}
-WRITE_LINE_MEMBER(spg2xx_video_device::vblank)
+void spg2xx_video_device::vblank(int state)
{
if (!state)
{
@@ -463,24 +457,17 @@ void spg2xx_video_device::check_video_irq()
m_video_irq_cb((VIDEO_IRQ_STATUS & VIDEO_IRQ_ENABLE) ? ASSERT_LINE : CLEAR_LINE);
}
-void spg2xx_video_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(spg2xx_video_device::screenpos_hit)
{
- switch (id)
+ if (VIDEO_IRQ_ENABLE & 2)
{
- case TIMER_SCREENPOS:
- {
- if (VIDEO_IRQ_ENABLE & 2)
- {
- VIDEO_IRQ_STATUS |= 2;
- check_video_irq();
- }
- m_screen->update_partial(m_screen->vpos());
-
- // fire again, jak_dbz pinball needs this
- m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1));
- break;
- }
+ VIDEO_IRQ_STATUS |= 2;
+ check_video_irq();
}
+ m_screen->update_partial(m_screen->vpos());
+
+ // fire again, jak_dbz pinball needs this
+ m_screenpos_timer->adjust(m_screen->time_until_pos(m_video_regs[0x36], m_video_regs[0x37] << 1));
}
diff --git a/src/devices/machine/spg2xx_video.h b/src/devices/machine/spg2xx_video.h
index 2d48f247bdc..69a96b449c3 100644
--- a/src/devices/machine/spg2xx_video.h
+++ b/src/devices/machine/spg2xx_video.h
@@ -25,36 +25,29 @@ public:
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
- DECLARE_WRITE_LINE_MEMBER(vblank);
+ void vblank(int state);
uint16_t video_r(offs_t offset);
void video_w(offs_t offset, uint16_t data);
- auto sprlimit_read_callback() { return m_sprlimit_read_cb.bind(); };
+ auto sprlimit_read_callback() { return m_sprlimit_read_cb.bind(); }
- auto write_video_irq_callback() { return m_video_irq_cb.bind(); };
+ auto write_video_irq_callback() { return m_video_irq_cb.bind(); }
protected:
- virtual void device_add_mconfig(machine_config &config) override;
-
- devcb_read16 m_guny_in;
- devcb_read16 m_gunx_in;
-
- inline void check_video_irq();
-
- static const device_timer_id TIMER_SCREENPOS = 2;
-
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ virtual void device_add_mconfig(machine_config &config) override;
- void do_sprite_dma(uint32_t len);
+ void check_video_irq();
+ TIMER_CALLBACK_MEMBER(screenpos_hit);
- uint16_t m_video_regs[0x100];
+ void do_sprite_dma(uint32_t len);
+ devcb_read16 m_guny_in;
+ devcb_read16 m_gunx_in;
devcb_read16 m_sprlimit_read_cb;
-
- emu_timer *m_screenpos_timer;
+ devcb_write_line m_video_irq_cb;
required_device<unsp_device> m_cpu;
required_device<screen_device> m_screen;
@@ -62,10 +55,10 @@ protected:
required_shared_ptr<uint16_t> m_hcompram;
required_shared_ptr<uint16_t> m_paletteram;
required_shared_ptr<uint16_t> m_spriteram;
-
- devcb_write_line m_video_irq_cb;
-
required_device<spg_renderer_device> m_renderer;
+
+ emu_timer *m_screenpos_timer;
+ uint16_t m_video_regs[0x100];
};
class spg24x_video_device : public spg2xx_video_device
diff --git a/src/devices/machine/spg_renderer.cpp b/src/devices/machine/spg_renderer.cpp
index 255e8369125..0bb116ef784 100644
--- a/src/devices/machine/spg_renderer.cpp
+++ b/src/devices/machine/spg_renderer.cpp
@@ -8,7 +8,7 @@ DEFINE_DEVICE_TYPE(SPG_RENDERER, spg_renderer_device, "spg_renderer", "SunPlus /
spg_renderer_device::spg_renderer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
- m_space_read_cb(*this)
+ m_space_read_cb(*this, 0)
{
}
@@ -19,8 +19,6 @@ spg_renderer_device::spg_renderer_device(const machine_config &mconfig, const ch
void spg_renderer_device::device_start()
{
- m_space_read_cb.resolve_safe(0);
-
for (uint8_t i = 0; i < 32; i++)
{
m_rgb5_to_rgb8[i] = (i << 3) | (i >> 2);
@@ -467,7 +465,11 @@ void spg_renderer_device::draw_page(bool read_from_csspace, bool has_extended_ti
const uint32_t bits_per_row = nc_bpp * tile_w / 16;
//const uint32_t words_per_tile = bits_per_row * tile_h;
const bool row_scroll = (ctrl & 0x0010);
- uint8_t blendlevel = (m_video_regs_2a & 3) << 3;
+
+ // Max blend level (3) should result in 100% opacity, per docs
+ // Min blend level (0) should result in 25% opacity, per docs
+ static const uint8_t s_blend_levels[4] = { 0x08, 0x10, 0x18, 0x20 };
+ uint8_t blendlevel = s_blend_levels[m_video_regs_2a & 3];
uint32_t words_per_tile;
@@ -653,7 +655,11 @@ void spg_renderer_device::draw_sprite(bool read_from_csspace, int extended_sprit
const uint8_t bpp = attr & 0x0003;
const uint32_t nc_bpp = ((bpp)+1) << 1;
const uint32_t bits_per_row = nc_bpp * tile_w / 16;
- uint8_t blendlevel = (m_video_regs_2a & 3) << 3;
+
+ // Max blend level (3) should result in 100% opacity on the sprite, per docs
+ // Min blend level (0) should result in 25% opacity on the sprite, per docs
+ static const uint8_t s_blend_levels[4] = { 0x08, 0x10, 0x18, 0x20 };
+ uint8_t blendlevel = s_blend_levels[m_video_regs_2a & 3];
uint32_t words_per_tile;
diff --git a/src/devices/machine/spg_renderer.h b/src/devices/machine/spg_renderer.h
index 55199a6c622..23a6a515106 100644
--- a/src/devices/machine/spg_renderer.h
+++ b/src/devices/machine/spg_renderer.h
@@ -53,7 +53,7 @@ public:
uint16_t get_video_reg_7f(void) { return m_video_regs_7f; }
auto space_read_callback() { return m_space_read_cb.bind(); }
- void set_video_spaces(address_space* cpuspace, address_space* cs_space, int csbase) { m_cpuspace = cpuspace; m_cs_space = cs_space; m_csbase = csbase; }
+ void set_video_spaces(address_space* cpuspace, address_space* cs_space, uint32_t csbase) { m_cpuspace = cpuspace; m_cs_space = cs_space; m_csbase = csbase; }
protected:
@@ -109,7 +109,7 @@ private:
address_space* m_cpuspace;
address_space* m_cs_space;
- int m_csbase;
+ uint32_t m_csbase;
bool m_brightness_or_saturation_dirty;
void update_palette_lookup(void);
uint16_t m_linebuf[640];
diff --git a/src/devices/machine/spi_sdcard.cpp b/src/devices/machine/spi_sdcard.cpp
new file mode 100644
index 00000000000..e0da9b8c63f
--- /dev/null
+++ b/src/devices/machine/spi_sdcard.cpp
@@ -0,0 +1,458 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*
+ SD Card emulation, SPI interface.
+ Emulation by R. Belmont
+
+ This emulates either an SDHC (SPI_SDCARD) or an SDV2 card (SPI_SDCARDV2). SDHC has a fixed
+ 512 byte block size and the arguments to the read/write commands are block numbers. SDV2
+ has a variable block size defaulting to 512 and the arguments to the read/write commands
+ are byte offsets.
+
+ The block size set with CMD16 must match the underlying CHD block size if it's not 512.
+
+ Adding the native 4-bit-wide SD interface is also possible; this should be broken up into a base
+ SD Card class with SPI and SD frontends in that case.
+
+ Multiple block read/write commands are not supported but would be straightforward to add.
+
+ References:
+ https://www.sdcard.org/downloads/pls/ (Physical Layer Simplified Specification)
+ REF: tags are referring to the spec form above. 'Physical Layer Simplified Specification v8.00'
+
+ http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf
+ https://embdev.net/attachment/39390/TOSHIBA_SD_Card_Specification.pdf
+ http://elm-chan.org/docs/mmc/mmc_e.html
+*/
+
+#include "emu.h"
+#include "spi_sdcard.h"
+#include "imagedev/harddriv.h"
+
+#include "multibyte.h"
+
+#define LOG_COMMAND (1U << 1)
+#define LOG_SPI (1U << 2)
+
+//#define VERBOSE (LOG_GENERAL | LOG_COMMAND)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+
+#include "logmacro.h"
+
+static constexpr u8 DATA_RESPONSE_OK = 0x05;
+static constexpr u8 DATA_RESPONSE_IO_ERROR = 0x0d;
+
+DEFINE_DEVICE_TYPE(SPI_SDCARD, spi_sdcard_sdhc_device, "spi_sdhccard", "SDHC Card (SPI Interface)")
+DEFINE_DEVICE_TYPE(SPI_SDCARDV2, spi_sdcard_sdv2_device, "spi_sdv2card", "SDV2 Card (SPI Interface)")
+
+spi_sdcard_device::spi_sdcard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ write_miso(*this),
+ m_image(*this, "image"),
+ m_state(SD_STATE_IDLE),
+ m_ss(0), m_in_bit(0), m_clk_state(0),
+ m_in_latch(0), m_out_latch(0xff), m_cur_bit(0),
+ m_out_count(0), m_out_ptr(0), m_write_ptr(0), m_blksize(512), m_blknext(0),
+ m_bACMD(false)
+{
+}
+
+spi_sdcard_sdv2_device::spi_sdcard_sdv2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ spi_sdcard_device(mconfig, SPI_SDCARDV2, tag, owner, clock)
+{
+ m_type = SD_TYPE_V2;
+}
+
+spi_sdcard_sdhc_device::spi_sdcard_sdhc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ spi_sdcard_device(mconfig, SPI_SDCARD, tag, owner, clock)
+{
+ m_type = SD_TYPE_HC;
+}
+
+ALLOW_SAVE_TYPE(spi_sdcard_device::sd_state);
+ALLOW_SAVE_TYPE(spi_sdcard_device::sd_type);
+
+void spi_sdcard_device::device_start()
+{
+ save_item(NAME(m_state));
+ save_item(NAME(m_in_latch));
+ save_item(NAME(m_out_latch));
+ save_item(NAME(m_out_ptr));
+ save_item(NAME(m_out_count));
+ save_item(NAME(m_ss));
+ save_item(NAME(m_in_bit));
+ save_item(NAME(m_clk_state));
+ save_item(NAME(m_cur_bit));
+ save_item(NAME(m_write_ptr));
+ save_item(NAME(m_blksize));
+ save_item(NAME(m_blknext));
+ save_item(NAME(m_type));
+ save_item(NAME(m_cmd));
+ save_item(NAME(m_data));
+ save_item(NAME(m_bACMD));
+}
+
+void spi_sdcard_device::device_reset()
+{
+}
+
+void spi_sdcard_device::device_add_mconfig(machine_config &config)
+{
+ HARDDISK(config, m_image).set_interface("spi_sdcard");
+}
+
+void spi_sdcard_device::send_data(u16 count, sd_state new_state)
+{
+ m_out_ptr = 0;
+ m_out_count = count;
+ change_state(new_state);
+}
+
+void spi_sdcard_device::spi_clock_w(int state)
+{
+ // only respond if selected, and a clock edge
+ if (m_ss && state != m_clk_state)
+ {
+ // We implement SPI Mode 3 signalling, in which we latch the data on
+ // rising clock edges, and shift the data on falling clock edges.
+ // See http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf for details
+ // on the 4 SPI signalling modes. SD Cards can work in either Mode 0 or Mode 3,
+ // both of which shift on the falling edge and latch on the rising edge but
+ // have opposite CLK polarity.
+ if (state)
+ latch_in();
+ else
+ shift_out();
+ }
+ m_clk_state = state;
+}
+
+void spi_sdcard_device::latch_in()
+{
+ m_in_latch &= ~0x01;
+ m_in_latch |= m_in_bit;
+ LOGMASKED(LOG_SPI, "\tsdcard: L %02x (%d) (out %02x)\n", m_in_latch, m_cur_bit, m_out_latch);
+ m_cur_bit++;
+ if (m_cur_bit == 8)
+ {
+ LOGMASKED(LOG_SPI, "SDCARD: got %02x\n", m_in_latch);
+ if (m_state == SD_STATE_WRITE_WAITFE)
+ {
+ if (m_in_latch == 0xfe)
+ {
+ m_state = SD_STATE_WRITE_DATA;
+ m_out_latch = 0xff;
+ m_write_ptr = 0;
+ }
+ }
+ else if (m_state == SD_STATE_WRITE_DATA)
+ {
+ m_data[m_write_ptr++] = m_in_latch;
+ if (m_write_ptr == (m_blksize + 2))
+ {
+ LOG("writing LBA %x, data %02x %02x %02x %02x\n", m_blknext, m_data[0], m_data[1], m_data[2], m_data[3]);
+ if (m_image->write(m_blknext, &m_data[0]))
+ {
+ m_data[0] = DATA_RESPONSE_OK;
+ }
+ else
+ {
+ m_data[0] = DATA_RESPONSE_IO_ERROR;
+ }
+ m_data[1] = 0x01;
+
+ send_data(2, SD_STATE_IDLE);
+ }
+ }
+ else // receive CMD
+ {
+ std::memmove(m_cmd, m_cmd + 1, 5);
+ m_cmd[5] = m_in_latch;
+
+ if (m_state == SD_STATE_DATA_MULTI)
+ {
+ do_command();
+ if (m_state == SD_STATE_DATA_MULTI && m_out_count == 0)
+ {
+ m_data[0] = 0xfe; // data token
+ m_image->read(m_blknext++, &m_data[1]);
+ util::crc16_t crc16 = util::crc16_creator::simple(&m_data[1], m_blksize);
+ put_u16be(&m_data[m_blksize + 1], crc16);
+ send_data(1 + m_blksize + 2, SD_STATE_DATA_MULTI);
+ }
+ }
+ else if ((m_state == SD_STATE_IDLE) || (((m_cmd[0] & 0x70) == 0x40) || (m_out_count == 0))) // CMD0 - GO_IDLE_STATE
+ {
+ do_command();
+ }
+ }
+ }
+}
+
+void spi_sdcard_device::shift_out()
+{
+ m_in_latch <<= 1;
+ m_out_latch <<= 1;
+ m_out_latch |= 1;
+ LOGMASKED(LOG_SPI, "\tsdcard: S %02x %02x (%d)\n", m_in_latch, m_out_latch, m_cur_bit);
+
+ m_cur_bit &= 0x07;
+ if (m_cur_bit == 0)
+ {
+ if (m_out_ptr < SPI_DELAY_RESPONSE)
+ {
+ m_out_ptr++;
+ }
+ else if (m_out_count > 0)
+ {
+ m_out_latch = m_data[m_out_ptr - SPI_DELAY_RESPONSE];
+ m_out_ptr++;
+ LOGMASKED(LOG_SPI, "SDCARD: latching %02x (start of shift)\n", m_out_latch);
+ m_out_count--;
+ }
+ }
+ write_miso(BIT(m_out_latch, 7));
+}
+
+void spi_sdcard_device::do_command()
+{
+ if (((m_cmd[0] & 0xc0) == 0x40) && (m_cmd[5] & 1))
+ {
+ LOGMASKED(LOG_COMMAND, "SDCARD: cmd %02d %02x %02x %02x %02x %02x\n", m_cmd[0] & 0x3f, m_cmd[1], m_cmd[2], m_cmd[3], m_cmd[4], m_cmd[5]);
+ bool clean_cmd = true;
+ switch (m_cmd[0] & 0x3f)
+ {
+ case 0: // CMD0 - GO_IDLE_STATE
+ if (m_image->exists())
+ {
+ m_data[0] = 0x01;
+ send_data(1, SD_STATE_IDLE);
+ }
+ else
+ {
+ m_data[0] = 0x00;
+ send_data(1, SD_STATE_INA);
+ }
+ break;
+
+ case 1: // CMD1 - SEND_OP_COND
+ m_data[0] = 0x00;
+ send_data(1, SD_STATE_READY);
+ break;
+
+ case 8: // CMD8 - SEND_IF_COND (SD v2 only)
+ m_data[0] = 0x01;
+ m_data[1] = 0;
+ m_data[2] = 0;
+ m_data[3] = 0x01;
+ m_data[4] = 0xaa;
+ send_data(5, SD_STATE_IDLE);
+ break;
+
+ case 9: // CMD9 - SEND_CSD
+ m_data[0] = 0x00;
+ m_data[1] = 0xff;
+ m_data[2] = 0xfe;
+
+ //if (m_type == SD_TYPE_V2) // CSD Version 1.0
+ {
+ u8 block_len = 9;
+ for (auto i = m_blksize >> 10; i; i >>= 1, ++block_len);
+
+ m_data[3] = 0x00; // 127: CSD_STRUCTURE:2 (00b) 0:6
+ m_data[4] = 0x0e; // 119: TAAC:8
+ m_data[5] = 0x00; // 111: NSAC:8
+ m_data[6] = 0x32; // 103: TRAN_SPEED:8 (32h or 5Ah)
+ m_data[7] = 0x5b; // 95: CCC:12 (01x110110101b)
+ m_data[8] = 0x50; // .. READ_BL_LN:4
+ m_data[8] |= block_len;
+ m_data[9] = 0x83; // 79: READ_BL_PARTIAL:1 (1b) WRITE_BLK_MISALIGN:1 READ_BLK_MISALIGN:1 DSR_IMP:1 0:2 C_SIZE:12
+ m_data[10] = 0xff; // ..
+ m_data[11] = 0xed; // .. VDD_R_CURR_MIN:3 VDD_R_CURR_MAX:3
+ m_data[12] = 0xb7; // 55: VDD_W_CURR_MIN:3 VDD_W_CURR_MAX:3 C_SIZE_MUL:3
+ m_data[13] = 0xbf; // .. ERASE_BLK_EN:1 SECTOR_SIZE:7
+ m_data[14] = 0xbf; // .. WP_GRP_SIZE:7
+ m_data[15] = 0x04; // 31: WP_GRP_ENABLE:1 0:2 R2W_FACTOR:3 WRITE_BL_LEN:4
+ m_data[15] |= (block_len >> 2);
+ m_data[16] = 0x00; /// .. WRITE_BL_PARTIAL:1 0:5
+ m_data[16] |= (block_len & 3) << 6;
+ m_data[17] = 0x00; // 15: FILE_FORMAT_GRP:1 COPY:1 PERM_WRITE_PROTECT:1 TMP_WRITE_PROTECT:1 FILE_FORMAT:2 WP_UPC:1 0:1
+ m_data[18] = 0x01; // 7: CRC7 1:1
+ }
+ /*
+ else // SD_TYPE_HC: CSD Version 2.0
+ {
+ m_data[3] = 0x40;
+ }
+ */
+
+ send_data(3 + 16, SD_STATE_STBY);
+ break;
+
+ case 10: // CMD10 - SEND_CID
+ m_data[0] = 0x00; // initial R1 response
+ m_data[1] = 0xff; // throwaway byte before data transfer
+ m_data[2] = 0xfe; // data token
+ m_data[3] = 'M'; // Manufacturer ID - we'll use M for MAME
+ m_data[4] = 'M'; // OEM ID - MD for MAMEdev
+ m_data[5] = 'D';
+ m_data[6] = 'M'; // Product Name - "MCARD"
+ m_data[7] = 'C';
+ m_data[8] = 'A';
+ m_data[9] = 'R';
+ m_data[10] = 'D';
+ m_data[11] = 0x10; // Product Revision in BCD (1.0)
+ {
+ u32 uSerial = 0x12345678;
+ put_u32be(&m_data[12], uSerial); // PSN - Product Serial Number
+ }
+ m_data[16] = 0x01; // MDT - Manufacturing Date
+ m_data[17] = 0x59; // 0x15 9 = 2021, September
+ m_data[18] = 0x00; // CRC7, bit 0 is always 0
+ {
+ util::crc16_t crc16 = util::crc16_creator::simple(&m_data[3], 16);
+ put_u16be(&m_data[19], crc16);
+ }
+ send_data(3 + 16 + 2, SD_STATE_STBY);
+ break;
+
+ case 12: // CMD12 - STOP_TRANSMISSION
+ m_data[0] = 0;
+ send_data(1, (m_state == SD_STATE_RCV) ? SD_STATE_PRG : SD_STATE_TRAN);
+ break;
+
+ case 13: // CMD13 - SEND_STATUS
+ m_data[0] = 0; // TODO
+ m_data[1] = 0;
+ send_data(2, SD_STATE_STBY);
+ break;
+
+ case 16: // CMD16 - SET_BLOCKLEN
+ m_blksize = get_u16be(&m_cmd[3]);
+ if (m_image->exists() && m_image->set_block_size(m_blksize))
+ {
+ m_data[0] = 0;
+ }
+ else
+ {
+ m_data[0] = 0xff; // indicate an error
+ // if false was returned, it means the hard disk is a CHD file, and we can't resize the
+ // blocks on CHD files.
+ logerror("spi_sdcard: Couldn't change block size to %d, wrong CHD file?", m_blksize);
+ }
+ send_data(1, SD_STATE_TRAN);
+ break;
+
+ case 17: // CMD17 - READ_SINGLE_BLOCK
+ if (m_image->exists())
+ {
+ m_data[0] = 0x00; // initial R1 response
+ // data token occurs some time after the R1 response. A2SD expects at least 1
+ // byte of space between R1 and the data packet.
+ m_data[1] = 0xff;
+ m_data[2] = 0xfe; // data token
+ u32 blk = get_u32be(&m_cmd[1]);
+ if (m_type == SD_TYPE_V2)
+ {
+ blk /= m_blksize;
+ }
+ LOG("reading LBA %x\n", blk);
+ m_image->read(blk, &m_data[3]);
+ {
+ util::crc16_t crc16 = util::crc16_creator::simple(&m_data[3], m_blksize);
+ put_u16be(&m_data[m_blksize + 3], crc16);
+ }
+ send_data(3 + m_blksize + 2, SD_STATE_DATA);
+ }
+ else
+ {
+ m_data[0] = 0xff; // show an error
+ send_data(1, SD_STATE_DATA);
+ }
+ break;
+
+ case 18: // CMD18 - CMD_READ_MULTIPLE_BLOCK
+ if (m_image->exists())
+ {
+ m_data[0] = 0x00; // initial R1 response
+ // data token occurs some time after the R1 response. A2SD
+ // expects at least 1 byte of space between R1 and the data
+ // packet.
+ m_blknext = get_u32be(&m_cmd[1]);
+ if (m_type == SD_TYPE_V2)
+ {
+ m_blknext /= m_blksize;
+ }
+ }
+ else
+ {
+ m_data[0] = 0xff; // show an error
+ }
+ send_data(1, SD_STATE_DATA_MULTI);
+ break;
+
+ case 24: // CMD24 - WRITE_BLOCK
+ m_data[0] = 0;
+ m_blknext = get_u32be(&m_cmd[1]);
+ if (m_type == SD_TYPE_V2)
+ {
+ m_blknext /= m_blksize;
+ }
+ send_data(1, SD_STATE_WRITE_WAITFE);
+ break;
+
+ case 41:
+ if (m_bACMD) // ACMD41 - SD_SEND_OP_COND
+ {
+ m_data[0] = 0;
+ send_data(1, SD_STATE_READY); // + SD_STATE_IDLE
+ }
+ else // CMD41 - illegal
+ {
+ m_data[0] = 0xff;
+ send_data(1, SD_STATE_INA);
+ }
+ break;
+
+ case 55: // CMD55 - APP_CMD
+ m_data[0] = 0x01;
+ send_data(1, SD_STATE_IDLE);
+ break;
+
+ case 58: // CMD58 - READ_OCR
+ m_data[0] = 0;
+ m_data[1] = 0x80; // Busy Status: 1b - Initialization Complete
+ m_data[1] |= (m_type == SD_TYPE_V2) ? 0 : 0x40; // Card Capacity Status: 0b - SDCS, 1b SDHC, SDXC
+ m_data[2] = 0;
+ m_data[3] = 0;
+ m_data[4] = 0;
+ send_data(5, SD_STATE_DATA);
+ break;
+
+ case 59: // CMD59 - CRC_ON_OFF
+ m_data[0] = 0;
+ // TODO CRC 1-on, 0-off
+ send_data(1, SD_STATE_STBY);
+ break;
+
+ default:
+ LOGMASKED(LOG_COMMAND, "SDCARD: Unsupported CMD%02d\n", m_cmd[0] & 0x3f);
+ clean_cmd = false;
+ break;
+ }
+
+ // if this is command 55, that's a prefix indicating the next command is an "app command" or "ACMD"
+ m_bACMD = (m_cmd[0] & 0x3f) == 55;
+
+ if (clean_cmd)
+ memset(m_cmd, 0xff, 6);
+ }
+}
+
+void spi_sdcard_device::change_state(sd_state new_state)
+{
+ // TODO validate if transition is valid using refs below.
+ // REF Figure 4-13:SD Memory Card State Diagram (Transition Mode)
+ // REF Table 4-35:Card State Transition Table
+ m_state = new_state;
+}
diff --git a/src/devices/machine/spi_sdcard.h b/src/devices/machine/spi_sdcard.h
new file mode 100644
index 00000000000..0d8a7cbdc7f
--- /dev/null
+++ b/src/devices/machine/spi_sdcard.h
@@ -0,0 +1,96 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+#ifndef MAME_MACHINE_SPI_SDCARD_H
+#define MAME_MACHINE_SPI_SDCARD_H
+
+#pragma once
+
+#include "imagedev/harddriv.h"
+
+class spi_sdcard_device : public device_t
+{
+public:
+ // SPI 4-wire interface
+ auto spi_miso_callback() { return write_miso.bind(); }
+ void spi_clock_w(int state);
+ void spi_ss_w(int state) { m_ss = state; }
+ void spi_mosi_w(int state) { m_in_bit = state; }
+
+ bool get_card_present() { return m_image->exists(); }
+
+ devcb_write_line write_miso;
+
+protected:
+ enum sd_type : u8
+ {
+ SD_TYPE_V2 = 0,
+ SD_TYPE_HC
+ };
+
+ spi_sdcard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ required_device<harddisk_image_device> m_image;
+
+ sd_type m_type;
+
+private:
+ enum sd_state : u8
+ {
+ //REF Table 4-1:Overview of Card States vs. Operation Mode
+ SD_STATE_IDLE = 0,
+ SD_STATE_READY,
+ SD_STATE_IDENT,
+ SD_STATE_STBY,
+ SD_STATE_TRAN,
+ SD_STATE_DATA,
+ SD_STATE_DATA_MULTI, // synthetical state for this implementation
+ SD_STATE_RCV,
+ SD_STATE_PRG,
+ SD_STATE_DIS,
+ SD_STATE_INA,
+
+ //FIXME Existing states which must be revisited
+ SD_STATE_WRITE_WAITFE,
+ SD_STATE_WRITE_DATA
+ };
+ sd_state m_state;
+
+ // MMFS for Acorn machines expect dummy byte before response
+ static constexpr int SPI_DELAY_RESPONSE = 1;
+
+ void send_data(u16 count, sd_state new_state);
+ void do_command();
+ void change_state(sd_state new_state);
+
+ void latch_in();
+ void shift_out();
+
+ u8 m_data[520], m_cmd[6];
+
+ int m_ss, m_in_bit, m_clk_state;
+ u8 m_in_latch, m_out_latch, m_cur_bit;
+ u16 m_out_count, m_out_ptr, m_write_ptr, m_blksize;
+ u32 m_blknext;
+ bool m_bACMD;
+};
+
+class spi_sdcard_sdhc_device : public spi_sdcard_device
+{
+public:
+ spi_sdcard_sdhc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+class spi_sdcard_sdv2_device : public spi_sdcard_device
+{
+public:
+ spi_sdcard_sdv2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
+DECLARE_DEVICE_TYPE(SPI_SDCARD, spi_sdcard_sdhc_device)
+DECLARE_DEVICE_TYPE(SPI_SDCARDV2, spi_sdcard_sdv2_device)
+
+#endif // MAME_MACHINE_SPI_SDCARD_H
diff --git a/src/devices/machine/spifi3.cpp b/src/devices/machine/spifi3.cpp
new file mode 100644
index 00000000000..d0ea43147c0
--- /dev/null
+++ b/src/devices/machine/spifi3.cpp
@@ -0,0 +1,1878 @@
+// license:BSD-3-Clause
+// copyright-holders:Brice Onken,Olivier Galibert
+
+/*
+ * HP 1TV3-0302 SPIFI3-SE SCSI controller
+ *
+ * References:
+ * - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifireg.h
+ * - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifi.c
+ * - https://github.com/mamedev/mame/blob/master/src/devices/machine/ncr53c90.cpp
+ *
+ * TODO:
+ * - NetBSD compatibility
+ * - Reselection, target mode, SDTR
+ * - LUN selection (currently assumes 0)
+ * - Non-chip-reset conditions
+ * - Other SPSTAT and ICOND values
+ * - CMDPAGE details
+ * - Anything the Sony NEWS driver doesn't use
+ */
+
+#include "emu.h"
+#include "spifi3.h"
+
+#define LOG_STATE (1U << 1)
+#define LOG_INTERRUPT (1U << 2)
+#define LOG_DATA (1U << 3)
+#define LOG_REGISTER (1U << 4)
+#define LOG_CMD (1U << 5)
+#define LOG_AUTO (1U << 6)
+
+#define SPIFI3_DEBUG (LOG_GENERAL | LOG_REGISTER | LOG_INTERRUPT | LOG_AUTO)
+#define SPIFI3_TRACE (SPIFI3_DEBUG | LOG_STATE | LOG_CMD)
+#define SPIFI3_MAX (SPIFI3_TRACE | LOG_DATA)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SPIFI3, spifi3_device, "spifi3", "HP 1TV3-0302 SPIFI3 SCSI-2 Protocol Controller")
+
+ALLOW_SAVE_TYPE(spifi3_device::scsi_mode)
+ALLOW_SAVE_TYPE(spifi3_device::scsi_data_target)
+ALLOW_SAVE_TYPE(spifi3_device::dma_direction)
+
+namespace
+{
+ // AUXCTRL constants and functions
+ constexpr uint32_t AUXCTRL_DMAEDGE = 0x04;
+ constexpr uint32_t AUXCTRL_SETRST = 0x20;
+ constexpr uint32_t AUXCTRL_CRST = 0x40;
+ constexpr uint32_t AUXCTRL_SRST = 0x80;
+
+ // spstat - not fully implemented yet
+ constexpr uint32_t SPS_IDLE = 0x00;
+ constexpr uint32_t SPS_MSGOUT = 0x04;
+ constexpr uint32_t SPS_COMMAND = 0x05;
+ constexpr uint32_t SPS_INTR = 0x08;
+ constexpr uint32_t SPS_STATUS = 0x0c;
+ constexpr uint32_t SPS_MSGIN = 0x0d;
+ constexpr uint32_t SPS_DATAOUT = 0x0e;
+ constexpr uint32_t SPS_DATAIN = 0x0f;
+
+ // prstat - PRS_Z not implemented yet
+ constexpr uint32_t PRS_IO = 0x08;
+ constexpr uint32_t PRS_CD = 0x10;
+ constexpr uint32_t PRS_MSG = 0x20;
+ constexpr uint32_t PRS_ATN = 0x40;
+
+ // Interrupt status register - Not all interrupts implemented yet
+ constexpr uint32_t INTR_BSRQ = 0x01;
+ constexpr uint32_t INTR_TIMEO = 0x08;
+ constexpr uint32_t INTR_FCOMP = 0x80;
+
+ // Interrupt condition register - Not all interrupts implemented yet
+ constexpr uint32_t ICOND_CNTZERO = 0x40;
+ constexpr uint32_t ICOND_UXPHASEZ = 0x80;
+
+ // Select register - SETATN and IRESELEN not implemented yet
+ constexpr uint32_t SEL_ISTART = 0x08;
+ constexpr uint32_t SEL_WATN = 0x80;
+ constexpr uint32_t SEL_TARGET = 0x70;
+
+ // Autodata register
+ constexpr uint32_t ADATA_IN = 0x40;
+ constexpr uint32_t ADATA_EN = 0x80;
+ constexpr uint32_t ADATA_TARGET_ID = 0x07;
+
+ // cmlen register
+ constexpr uint32_t CML_LENMASK = 0x0f;
+ constexpr uint32_t CML_AMSG_EN = 0x40;
+ constexpr uint32_t CML_ACOM_EN = 0x80;
+
+ // init_status register
+ constexpr uint32_t INIT_STATUS_ACK = 0x40;
+
+ // FIFOCTRL constants and functions
+ // Based on the existence of CLREVEN/ODD, the fact that NetBSD only uses EVEN, and the max is 8
+ // even though this is a 4 bit value, it seems likely that there are actually two FIFOs,
+ // one in the even slots, and one in the odd slots
+ constexpr uint32_t FIFOC_FSLOT = 0x0f; // Free slots in FIFO, max 8. Free slots = 8 - (FIFOCTRL & FIFOC_FSLOT)
+ constexpr uint32_t FIFOC_SSTKACT = 0x10;
+ constexpr uint32_t FIFOC_RQOVRN = 0x20;
+ constexpr uint32_t FIFOC_CLREVEN = 0x00;
+ constexpr uint32_t FIFOC_CLRODD = 0x40;
+ constexpr uint32_t FIFOC_FLUSH = 0x80;
+ constexpr uint32_t FIFOC_LOAD = 0xc0;
+
+ // SPIFI commands
+ enum PRCMD_COMMANDS : uint32_t
+ {
+ PRC_DATAOUT = 0x0,
+ PRC_DATAIN = 0x1,
+ PRC_COMMAND = 0x2,
+ PRC_STATUS = 0x3,
+ PRC_TRPAD = 0x4,
+ PRC_MSGOUT = 0x6,
+ PRC_MSGIN = 0x7,
+ PRC_KILLREQ = 0x08,
+ PRC_CLRACK = 0x10,
+ PRC_NJMP = 0x80
+ };
+
+ constexpr uint32_t PRCMD_MASK = 0x1f;
+ const std::string_view prcmd_command_names[9] = {"PRC_DATAOUT", "PRC_DATAIN", "PRC_COMMAND", "PRC_STATUS", "PRC_TRPAD", "UNKNOWN", "PRC_MSGOUT", "PRC_MSGIN", "PRC_KILLREQ"};
+
+ 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_INIT,
+ 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_FUNCTION_COMPLETE,
+ INIT_XFR_BUS_COMPLETE,
+ INIT_XFR_WAIT_REQ,
+ INIT_CPT_RECV_BYTE_ACK,
+ INIT_CPT_RECV_WAIT_REQ,
+ INIT_CPT_RECV_BYTE_NACK,
+ INIT_XFR_RECV_BYTE_ACK_AUTOMSG
+ };
+
+ enum
+ {
+ // Arbitration
+ ARB_WAIT_BUS_FREE = 1,
+ ARB_COMPLETE,
+ ARB_ASSERT_SEL,
+ ARB_SET_DEST,
+ ARB_RELEASE_BUSY,
+ ARB_TIMEOUT_BUSY,
+ ARB_TIMEOUT_ABORT,
+ ARB_DESKEW_WAIT,
+
+ // Send/receive byte
+ SEND_WAIT_SETTLE,
+ SEND_WAIT_REQ_0,
+ RECV_WAIT_REQ_1,
+ RECV_WAIT_SETTLE,
+ RECV_WAIT_REQ_0
+ };
+
+ enum
+ {
+ STATE_MASK = 0x00ff,
+ SUB_SHIFT = 8,
+ SUB_MASK = 0xff00
+ };
+
+ enum
+ {
+ BUS_BUSY,
+ BUS_FREE_WAIT,
+ BUS_FREE
+ };
+
+ // Helper functions
+ inline uint32_t prcmd_to_spstat(uint32_t cmd)
+ {
+ uint32_t spstat_val = 0;
+ switch (cmd)
+ {
+ case PRC_DATAIN:
+ spstat_val = SPS_DATAIN;
+ break;
+ case PRC_DATAOUT:
+ spstat_val = SPS_DATAOUT;
+ break;
+ case PRC_COMMAND:
+ spstat_val = SPS_COMMAND;
+ break;
+ case PRC_STATUS:
+ spstat_val = SPS_STATUS;
+ break;
+ case PRC_MSGOUT:
+ spstat_val = SPS_MSGOUT;
+ break;
+ case PRC_MSGIN:
+ spstat_val = SPS_MSGIN;
+ break;
+ }
+ return spstat_val;
+ }
+}
+
+spifi3_device::spifi3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ nscsi_device(mconfig, SPIFI3, tag, owner, clock),
+ nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF),
+ m_even_fifo(),
+ m_odd_fifo(),
+ m_irq_handler(*this),
+ m_drq_handler(*this)
+{
+}
+
+void spifi3_device::device_start()
+{
+ nscsi_device::device_start();
+
+ save_item(NAME(dma_dir));
+ save_item(NAME(mode));
+ save_item(NAME(xfr_data_source));
+ save_item(NAME(state));
+ save_item(NAME(xfr_phase));
+ save_item(NAME(command_pos));
+ save_item(NAME(irq));
+ save_item(NAME(drq));
+ save_item(NAME(tcounter));
+ save_item(NAME(sync_period));
+ save_item(NAME(clock_conv));
+ save_item(NAME(bus_id));
+ save_item(STRUCT_MEMBER(spifi_reg, spstat));
+ save_item(STRUCT_MEMBER(spifi_reg, cmlen));
+ save_item(STRUCT_MEMBER(spifi_reg, cmdpage));
+ save_item(STRUCT_MEMBER(spifi_reg, svptr_hi));
+ save_item(STRUCT_MEMBER(spifi_reg, svptr_mid));
+ save_item(STRUCT_MEMBER(spifi_reg, svptr_low));
+ save_item(STRUCT_MEMBER(spifi_reg, intr));
+ save_item(STRUCT_MEMBER(spifi_reg, imask));
+ save_item(STRUCT_MEMBER(spifi_reg, prctrl));
+ save_item(STRUCT_MEMBER(spifi_reg, prstat));
+ save_item(STRUCT_MEMBER(spifi_reg, init_status));
+ save_item(STRUCT_MEMBER(spifi_reg, fifoctrl));
+ save_item(STRUCT_MEMBER(spifi_reg, fifodata));
+ save_item(STRUCT_MEMBER(spifi_reg, config));
+ save_item(STRUCT_MEMBER(spifi_reg, data_xfer));
+ save_item(STRUCT_MEMBER(spifi_reg, autocmd));
+ save_item(STRUCT_MEMBER(spifi_reg, autostat));
+ save_item(STRUCT_MEMBER(spifi_reg, resel));
+ save_item(STRUCT_MEMBER(spifi_reg, select));
+ save_item(STRUCT_MEMBER(spifi_reg, auxctrl));
+ save_item(STRUCT_MEMBER(spifi_reg, autodata));
+ save_item(STRUCT_MEMBER(spifi_reg, loopctrl));
+ save_item(STRUCT_MEMBER(spifi_reg, loopdata));
+ save_item(STRUCT_MEMBER(spifi_reg, identify));
+ save_item(STRUCT_MEMBER(spifi_reg, complete));
+ save_item(STRUCT_MEMBER(spifi_reg, scsi_status));
+ save_item(STRUCT_MEMBER(spifi_reg, data));
+ save_item(STRUCT_MEMBER(spifi_reg, icond));
+ save_item(STRUCT_MEMBER(spifi_reg, fastwide));
+ save_item(STRUCT_MEMBER(spifi_reg, exctrl));
+ save_item(STRUCT_MEMBER(spifi_reg, exstat));
+ save_item(STRUCT_MEMBER(spifi_reg, test));
+ save_item(STRUCT_MEMBER(spifi_reg, quematch));
+ save_item(STRUCT_MEMBER(spifi_reg, quecode));
+ save_item(STRUCT_MEMBER(spifi_reg, quetag));
+ save_item(STRUCT_MEMBER(spifi_reg, quepage));
+ save_item(STRUCT_MEMBER(spifi_reg.cmbuf, cdb));
+ save_item(STRUCT_MEMBER(spifi_reg.cmbuf, quecode));
+ save_item(STRUCT_MEMBER(spifi_reg.cmbuf, quetag));
+ save_item(STRUCT_MEMBER(spifi_reg.cmbuf, idmsg));
+ save_item(STRUCT_MEMBER(spifi_reg.cmbuf, status));
+ save_item(STRUCT_MEMBER(m_even_fifo, head));
+ save_item(STRUCT_MEMBER(m_even_fifo, tail));
+ save_item(STRUCT_MEMBER(m_even_fifo, size));
+ save_item(STRUCT_MEMBER(m_even_fifo, fifo));
+ save_item(STRUCT_MEMBER(m_odd_fifo, head));
+ save_item(STRUCT_MEMBER(m_odd_fifo, tail));
+ save_item(STRUCT_MEMBER(m_odd_fifo, size));
+ save_item(STRUCT_MEMBER(m_odd_fifo, fifo));
+
+ bus_id = 0;
+ tm = timer_alloc(FUNC(spifi3_device::tick), this);
+}
+
+void spifi3_device::map(address_map &map)
+{
+ map(0x00, 0x03).r(FUNC(spifi3_device::spstat_r));
+ map(0x04, 0x07).rw(FUNC(spifi3_device::cmlen_r), FUNC(spifi3_device::cmlen_w));
+ map(0x08, 0x0b).rw(FUNC(spifi3_device::cmdpage_r), FUNC(spifi3_device::cmdpage_w));
+ map(0x0c, 0x17).rw(FUNC(spifi3_device::count_r), FUNC(spifi3_device::count_w));
+ // svptr
+ map(0x24, 0x27).rw(FUNC(spifi3_device::intr_r), FUNC(spifi3_device::intr_w));
+ map(0x28, 0x2b).rw(FUNC(spifi3_device::imask_r), FUNC(spifi3_device::imask_w));
+ // prctrl
+ map(0x30, 0x33).r(FUNC(spifi3_device::prstat_r));
+ map(0x34, 0x37).r(FUNC(spifi3_device::init_status_r));
+ map(0x38, 0x3b).rw(FUNC(spifi3_device::fifoctrl_r), FUNC(spifi3_device::fifoctrl_w));
+ // fifodata, config
+ map(0x44, 0x47).rw(FUNC(spifi3_device::data_xfer_r), FUNC(spifi3_device::data_xfer_w));
+ map(0x48, 0x4b).rw(FUNC(spifi3_device::autocmd_r), FUNC(spifi3_device::autocmd_w));
+ map(0x4c, 0x4f).rw(FUNC(spifi3_device::autostat_r), FUNC(spifi3_device::autostat_w));
+ // resel
+ map(0x54, 0x57).rw(FUNC(spifi3_device::select_r), FUNC(spifi3_device::select_w));
+ map(0x58, 0x5b).w(FUNC(spifi3_device::prcmd_w));
+ map(0x5c, 0x5f).rw(FUNC(spifi3_device::auxctrl_r), FUNC(spifi3_device::auxctrl_w));
+ map(0x60, 0x63).rw(FUNC(spifi3_device::autodata_r), FUNC(spifi3_device::autodata_w));
+ // loopctrl, loopdata
+ map(0x6c, 0x6f).rw(FUNC(spifi3_device::identify_r), FUNC(spifi3_device::identify_w));
+ // complete
+ map(0x74, 0x77).rw(FUNC(spifi3_device::scsi_status_r), FUNC(spifi3_device::scsi_status_w));
+ // data
+ map(0x7c, 0x7f).rw(FUNC(spifi3_device::icond_r), FUNC(spifi3_device::icond_w));
+ map(0x80, 0x83).rw(FUNC(spifi3_device::fastwide_r), FUNC(spifi3_device::fastwide_w));
+ map(0x84, 0x87).rw(FUNC(spifi3_device::exctrl_r), FUNC(spifi3_device::exctrl_w));
+ // exstat, test, quematch, quecode, quetag, quepage
+
+ map(0x200, 0x3ff).rw(FUNC(spifi3_device::cmd_buf_r), FUNC(spifi3_device::cmd_buf_w)).umask32(0xff);
+}
+
+uint32_t spifi3_device::spstat_r()
+{
+ const uint32_t spstat = (spifi_reg.spstat << 4) | ((spifi_reg.intr > 0) ? SPS_INTR : 0);
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.spstat = 0x%x\n", spstat);
+ return spstat;
+}
+
+uint32_t spifi3_device::cmlen_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.cmlen = 0x%x\n", spifi_reg.cmlen);
+ return spifi_reg.cmlen;
+}
+
+void spifi3_device::cmlen_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.cmlen = 0x%x\n", data);
+ spifi_reg.cmlen = data;
+
+ // Not sure if this is where this is actually cleared.
+ // Putting it here prevents NEWS-OS from trying to
+ // transition to the DATAOUT phase too early when it sees
+ // the CNTZERO condition flag
+ spifi_reg.icond &= ~ICOND_CNTZERO;
+}
+
+uint32_t spifi3_device::cmdpage_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.cmdpage = 0x%x\n", spifi_reg.cmdpage);
+ return spifi_reg.cmdpage;
+}
+
+void spifi3_device::cmdpage_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.cmdpage = 0x%x\n", data);
+ spifi_reg.cmdpage = data;
+}
+
+uint32_t spifi3_device::count_r(offs_t offset)
+{
+ const uint8_t count = (tcounter >> (8 * (2 - offset))) & 0xff;
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.count%d = 0x%x -> 0x%x\n", offset, tcounter, count);
+ return count;
+}
+
+void spifi3_device::count_w(offs_t offset, uint32_t data)
+{
+ spifi_reg.icond &= ~ICOND_CNTZERO;
+ tcounter &= ~(0xff << (8 * (2 - offset)));
+ tcounter |= (data & 0xff) << (8 * (2 - offset));
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.count%d = 0x%x -> 0x%x\n", offset, data, tcounter);
+}
+
+uint32_t spifi3_device::intr_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.intr = 0x%x (%s)\n", spifi_reg.intr, machine().describe_context());
+ return spifi_reg.intr;
+}
+
+void spifi3_device::intr_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.intr = 0x%x\n", data);
+ spifi_reg.intr &= data;
+ spifi_reg.icond = 0;
+ check_irq();
+}
+
+uint32_t spifi3_device::imask_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.imask = 0x%x\n", spifi_reg.imask);
+ return spifi_reg.imask;
+}
+
+void spifi3_device::imask_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.imask = 0x%x\n", data);
+ spifi_reg.imask = data;
+}
+
+uint32_t spifi3_device::prstat_r()
+{
+ auto ctrl = scsi_bus->ctrl_r();
+
+ // TODO: PRS_Z (disconnect state?)
+ uint32_t prstat = 0;
+ prstat |= (ctrl & S_ATN) ? PRS_ATN : 0;
+ prstat |= (ctrl & S_MSG) ? PRS_MSG : 0;
+ prstat |= (ctrl & S_CTL) ? PRS_CD : 0;
+ prstat |= (ctrl & S_INP) ? PRS_IO : 0;
+ spifi_reg.prstat = prstat; // Might be able to get rid of the register copy of this since we can compute it on demand.
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.prstat = 0x%x\n", prstat);
+ return prstat;
+}
+
+uint32_t spifi3_device::init_status_r()
+{
+ // NetBSD only lists this bit, but there is probably more in this register.
+ const auto init_status = (scsi_bus->ctrl_r() & S_ACK) > 0 ? INIT_STATUS_ACK : 0x0;
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.init_status = 0x%x\n", init_status);
+ return init_status;
+}
+
+uint32_t spifi3_device::fifoctrl_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.fifoctrl = 0x%x\n", spifi_reg.fifoctrl);
+
+ const auto evenCount = FIFO_SIZE - m_even_fifo.get_size();
+ spifi_reg.fifoctrl &= ~FIFOC_FSLOT;
+ spifi_reg.fifoctrl |= evenCount & FIFOC_FSLOT;
+
+ return spifi_reg.fifoctrl;
+}
+
+void spifi3_device::fifoctrl_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.fifoctrl = 0x%x\n", data);
+ spifi_reg.fifoctrl = data & ~FIFOC_FSLOT; // TODO: this might not be persisted - read/write might be different. TBD.
+ if (spifi_reg.fifoctrl & FIFOC_SSTKACT)
+ {
+ LOG("fifoctrl.SSTKACT: w unimplemented");
+ } // likely RO guess: NetBSD uses this to know when synchronous data should be loaded into the FIFO?
+ if (spifi_reg.fifoctrl & FIFOC_RQOVRN)
+ {
+ LOG("fifoctrl.RQOVRN: w unimplemented");
+ } // likely RO - probably fifo overrun. Whatever this is, it would cause NetBSD to panic
+ if (spifi_reg.fifoctrl & FIFOC_CLREVEN)
+ {
+ LOG("Clearing even FIFO of %d items\n", m_even_fifo.get_size());
+ m_even_fifo.clear_queue();
+ }
+ if (spifi_reg.fifoctrl & FIFOC_CLRODD)
+ {
+ LOG("Clearing odd FIFO of %d items\n", m_odd_fifo.get_size());
+ m_odd_fifo.clear_queue();
+ }
+ if (spifi_reg.fifoctrl & FIFOC_FLUSH)
+ {
+ LOG("fifoctrl.FLUSH: unimplemented");
+ } // flush FIFO - kick off DMA regardless of FIFO count, I assume
+ if (spifi_reg.fifoctrl & FIFOC_LOAD)
+ {
+ LOG("fifoctrl.LOAD: unimplemented");
+ } // Load FIFO synchronously (only needed for SDTR mode?)
+}
+
+uint32_t spifi3_device::data_xfer_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.data_xfer = 0x%x\n", spifi_reg.data_xfer);
+ return spifi_reg.data_xfer;
+}
+
+void spifi3_device::data_xfer_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.data_xfer = 0x%x\n", data);
+ spifi_reg.data_xfer = data;
+}
+
+uint32_t spifi3_device::autocmd_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.autocmd = 0x%x\n", spifi_reg.autocmd);
+ return spifi_reg.autocmd;
+}
+
+void spifi3_device::autocmd_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.autocmd = 0x%x\n", data);
+ spifi_reg.autocmd = data;
+}
+
+uint32_t spifi3_device::autodata_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.autodata = 0x%x\n", spifi_reg.autodata);
+ return spifi_reg.autodata;
+}
+
+uint32_t spifi3_device::autostat_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.autostat = 0x%x\n", spifi_reg.autostat);
+ return spifi_reg.autostat;
+}
+
+void spifi3_device::autostat_w(uint32_t data)
+{
+ // This is based on what the NEWS-OS kernel does with this register.
+ // NetBSD doesn't use this register the same way based on its source code.
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.autostat = 0x%x\n", data);
+ spifi_reg.autostat |= data;
+}
+
+uint32_t spifi3_device::select_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.select = 0x%x\n", spifi_reg.select);
+ return spifi_reg.select;
+}
+
+void spifi3_device::select_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.select = 0x%x\n", data);
+ spifi_reg.select = data & ~SEL_ISTART;
+
+ if (data & SEL_ISTART)
+ {
+ const auto target_id = (data & SEL_TARGET) >> 4;
+ LOGMASKED(LOG_AUTO, "Select started! Targeting ID %d\n", target_id);
+
+ // Selects cmbuf entry, maybe? - can be manually set before a command based on NetBSD source, not supported yet
+ spifi_reg.cmdpage = target_id;
+ state = DISC_SEL_ARBITRATION_INIT;
+ arbitrate();
+ }
+}
+
+uint32_t spifi3_device::auxctrl_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.auxctrl = 0x%x\n", spifi_reg.auxctrl);
+ return spifi_reg.auxctrl;
+}
+
+void spifi3_device::auxctrl_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.auxctrl = 0x%x\n", data);
+ const auto prev_auxctrl = spifi_reg.auxctrl;
+ spifi_reg.auxctrl = data;
+ if (spifi_reg.auxctrl & AUXCTRL_SRST)
+ {
+ // TODO: reset of some kind
+ LOG("SRST asserted\n");
+ }
+ if (spifi_reg.auxctrl & AUXCTRL_CRST)
+ {
+ LOG("chip reset\n");
+ spifi_reg = {};
+ dma_dir = DMA_NONE;
+ tcounter = 0;
+ command_pos = 0;
+ }
+ if ((spifi_reg.auxctrl & AUXCTRL_SETRST) && !(prev_auxctrl & AUXCTRL_SETRST))
+ {
+ LOG("SETRST asserted - resetting SCSI bus\n");
+ state = BUSRESET_WAIT_INT;
+ scsi_bus->ctrl_w(scsi_refid, S_RST, S_RST);
+ delay(130);
+ }
+ if (spifi_reg.auxctrl & AUXCTRL_DMAEDGE)
+ {
+ // TODO: do we need to take action here?
+ LOG("DMAEDGE asserted\n");
+ }
+}
+
+void spifi3_device::autodata_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.autodata = 0x%x\n", data);
+ spifi_reg.autodata = data;
+
+ if (spifi_reg.autodata & ADATA_EN)
+ {
+ LOGMASKED(LOG_AUTO, "autodata enabled! target %d direction %s\n", spifi_reg.autodata & ADATA_TARGET_ID, spifi_reg.autodata & ADATA_IN ? "in" : "out");
+ }
+}
+
+uint32_t spifi3_device::identify_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.identify = 0x%x\n", spifi_reg.identify);
+ return spifi_reg.identify;
+}
+
+void spifi3_device::identify_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.identify = 0x%x\n", data);
+ spifi_reg.identify = data;
+}
+
+uint32_t spifi3_device::scsi_status_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.scsi_status = 0x%x\n", spifi_reg.scsi_status);
+ return spifi_reg.scsi_status;
+}
+
+void spifi3_device::scsi_status_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.scsi_status = 0x%x\n", data);
+ spifi_reg.scsi_status = data;
+}
+
+uint32_t spifi3_device::icond_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.icond = 0x%x\n", spifi_reg.icond);
+ return spifi_reg.icond;
+}
+
+void spifi3_device::icond_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.icond = 0x%x\n", data);
+ spifi_reg.icond = data;
+}
+
+uint32_t spifi3_device::fastwide_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.fastwide = 0x%x\n", spifi_reg.fastwide);
+ return spifi_reg.fastwide;
+}
+
+void spifi3_device::fastwide_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.fastwide = 0x%x\n", data);
+ spifi_reg.fastwide = data;
+}
+
+uint32_t spifi3_device::exctrl_r()
+{
+ LOGMASKED(LOG_REGISTER, "read spifi_reg.exctrl = 0x%x\n", spifi_reg.exctrl);
+ return spifi_reg.exctrl;
+}
+
+void spifi3_device::exctrl_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.exctrl = 0x%x\n", data);
+ spifi_reg.exctrl = data;
+}
+
+void spifi3_device::clear_fifo()
+{
+ m_even_fifo.clear_queue();
+ m_odd_fifo.clear_queue();
+}
+
+void spifi3_device::prcmd_w(uint32_t data)
+{
+ LOGMASKED(LOG_REGISTER, "write spifi_reg.prcmd = 0x%x (%s)\n", data, machine().describe_context());
+
+ // TODO: NJMP and other commands
+ const auto cmd = data & PRCMD_MASK;
+ switch (cmd)
+ {
+ case PRC_DATAOUT:
+ {
+ state = INIT_XFR;
+ xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK;
+
+ const dma_direction luntar_dma_setting = dma_setting(bus_id) == DMA_OUT ? DMA_OUT : DMA_NONE;
+ dma_set(luntar_dma_setting);
+ LOGMASKED(LOG_CMD, "start command DATAOUT, DMA = %d\n", luntar_dma_setting);
+ spifi_reg.spstat = SPS_DATAOUT;
+ break;
+ }
+ case PRC_DATAIN:
+ {
+ state = INIT_XFR;
+ xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK;
+
+ const dma_direction luntar_dma_setting = dma_setting(bus_id) == DMA_IN ? DMA_IN : DMA_NONE;
+ dma_set(luntar_dma_setting);
+ LOGMASKED(LOG_CMD, "start command DATAIN, DMA = %d\n", luntar_dma_setting);
+ spifi_reg.spstat = SPS_DATAIN;
+ break;
+ }
+ case PRC_MSGOUT:
+ case PRC_MSGIN:
+ case PRC_COMMAND:
+ case PRC_STATUS:
+ {
+ LOGMASKED(LOG_CMD, "start command %s\n", prcmd_command_names[cmd]);
+ state = INIT_XFR;
+ xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK;
+
+ command_pos = 0;
+ dma_set(DMA_NONE);
+ spifi_reg.spstat = prcmd_to_spstat(cmd);
+ break;
+ }
+ case PRC_TRPAD:
+ {
+ LOGMASKED(LOG_CMD, "start command TRPAD\n");
+ 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);
+ break;
+ }
+ default:
+ {
+ LOG("Unimplemented command %d!\n", data);
+ return;
+ }
+ }
+
+ if (data != PRC_TRPAD)
+ {
+ check_drq();
+ }
+
+ step(false);
+}
+
+uint8_t spifi3_device::cmd_buf_r(offs_t offset)
+{
+ // 8 slots in the buffer, 16 bytes each
+ // so, divide the offset by 16 (truncated) to get the cmd entry
+ const int cmd_entry = offset / 16;
+ uint8_t result = 0;
+ const int register_offset = offset % 16;
+ if (register_offset < 12)
+ {
+ result = spifi_reg.cmbuf[cmd_entry].cdb[register_offset];
+ }
+ else if (register_offset == 12)
+ {
+ result = spifi_reg.cmbuf[cmd_entry].quecode;
+ }
+ else if (register_offset == 13)
+ {
+ result = spifi_reg.cmbuf[cmd_entry].quetag;
+ }
+ else if (register_offset == 14)
+ {
+ result = spifi_reg.cmbuf[cmd_entry].idmsg;
+ }
+ else if (register_offset == 15)
+ {
+ result = spifi_reg.cmbuf[cmd_entry].status;
+ }
+
+ LOGMASKED(LOG_CMD, "cmd_buf_r(0x%x) -> 0x%x\n", offset, result);
+
+ return result;
+}
+
+void spifi3_device::cmd_buf_w(offs_t offset, uint8_t data)
+{
+ LOGMASKED(LOG_CMD, "cmd_buf_w(0x%x, 0x%x)\n", offset, data);
+
+ // 8 slots in the buffer, 16 bytes each
+ // so, divide the offset by 16 (truncated) to get the cmd entry
+ const int cmd_entry = offset / 16;
+ const int register_offset = offset % 16;
+ if (register_offset < 12)
+ {
+ spifi_reg.cmbuf[cmd_entry].cdb[register_offset] = data;
+ }
+ else if (register_offset == 12)
+ {
+ spifi_reg.cmbuf[cmd_entry].quecode = data;
+ }
+ else if (register_offset == 13)
+ {
+ spifi_reg.cmbuf[cmd_entry].quetag = data;
+ }
+ else if (register_offset == 14)
+ {
+ spifi_reg.cmbuf[cmd_entry].idmsg = data;
+ }
+ else if (register_offset == 15)
+ {
+ spifi_reg.cmbuf[cmd_entry].status = data;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(spifi3_device::tick)
+{
+ step(true);
+}
+
+void spifi3_device::check_irq()
+{
+ // There are various ways interrupts can be triggered by the SPIFI - this method is a work in progress.
+ // TODO: ICOND, which doesn't seem to be needed much on the "happy path" (no errors)
+ const bool irqState = spifi_reg.intr & ~spifi_reg.imask;
+ if (irq != irqState)
+ {
+ LOGMASKED(LOG_INTERRUPT, "Setting IRQ line to %d\n", irqState);
+ irq = irqState;
+ m_irq_handler(irq);
+ }
+}
+
+void spifi3_device::check_drq()
+{
+ bool drq_state = drq;
+
+ switch (dma_dir)
+ {
+ case DMA_NONE:
+ {
+ drq_state = false;
+ break;
+ }
+
+ case DMA_IN: // device to memory
+ {
+ drq_state = !transfer_count_zero() && !m_even_fifo.empty();
+ break;
+ }
+
+ case DMA_OUT: // memory to device
+ {
+ drq_state = !transfer_count_zero() && !m_even_fifo.full();
+ break;
+ }
+ }
+
+ if (drq_state != drq)
+ {
+ LOGMASKED(LOG_DATA, "DRQ changed to %d!\n", drq_state);
+ drq = drq_state;
+ m_drq_handler(drq);
+ }
+}
+
+bool spifi3_device::transfer_count_zero()
+{
+ return spifi_reg.icond & ICOND_CNTZERO;
+}
+
+void spifi3_device::reset_disconnect()
+{
+ scsi_bus->ctrl_w(scsi_refid, 0, ~S_RST);
+
+ command_pos = 0;
+ mode = MODE_D;
+}
+
+void spifi3_device::send_byte(scsi_data_target data_source)
+{
+ state = (state & STATE_MASK) | (SEND_WAIT_SETTLE << SUB_SHIFT);
+
+ if (data_source == COMMAND_BUFFER)
+ {
+ // Send next data from cmbuf
+ if (command_pos > 11)
+ {
+ fatalerror("%s: Tried to send command past the end of cdb! Command_pos: %d", tag(), command_pos);
+ }
+ LOGMASKED(LOG_CMD, "Sending byte from cmbuf[%d].cdb[%d] = 0x%x\n", scsi_id, command_pos, spifi_reg.cmbuf[scsi_id].cdb[command_pos]);
+ scsi_bus->data_w(scsi_refid, spifi_reg.cmbuf[scsi_id].cdb[command_pos++]);
+ }
+ else if (data_source == FIFO && (state & STATE_MASK) != INIT_XFR_SEND_PAD)
+ {
+ // Send next data from FIFO
+ scsi_bus->data_w(scsi_refid, m_even_fifo.pop());
+ check_drq();
+ }
+ 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 spifi3_device::recv_byte()
+{
+ // Wait for valid input
+ scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
+ state = (state & STATE_MASK) | (RECV_WAIT_REQ_1 << SUB_SHIFT);
+ step(false);
+}
+
+void spifi3_device::function_bus_complete()
+{
+ LOG("function_bus_complete\n");
+ state = IDLE;
+ spifi_reg.spstat = SPS_IDLE;
+
+ // TODO: Any ICOND changes needed here?
+ spifi_reg.intr |= INTR_FCOMP | INTR_BSRQ;
+ dma_set(DMA_NONE);
+ check_drq();
+ check_irq();
+}
+
+void spifi3_device::function_complete()
+{
+ LOG("function_complete\n");
+ state = IDLE;
+ spifi_reg.spstat = SPS_IDLE;
+
+ // TODO: Any ICOND changes needed here?
+ spifi_reg.intr |= INTR_FCOMP;
+ dma_set(DMA_NONE);
+ check_drq();
+ check_irq();
+}
+
+void spifi3_device::bus_complete()
+{
+ LOG("bus_complete\n");
+ state = IDLE;
+
+ spifi_reg.intr |= INTR_BSRQ;
+ dma_set(DMA_NONE);
+ check_drq();
+ check_irq();
+}
+
+void spifi3_device::dma_set(dma_direction dir)
+{
+ dma_dir = dir;
+
+ // account for data already in the fifo
+ if (dir == DMA_OUT && !m_even_fifo.empty())
+ {
+ decrement_tcounter(m_even_fifo.get_size());
+ }
+}
+
+void spifi3_device::decrement_tcounter(uint32_t count)
+{
+ if (!dma_command(dma_dir))
+ {
+ return;
+ }
+ else if (count > tcounter)
+ {
+ fatalerror("%s: tcounter ran out of bytes!", tag());
+ }
+
+ tcounter -= count;
+ if (tcounter == 0)
+ {
+ // TODO: does this immediately trigger an interrupt? or is this just a status thing?
+ spifi_reg.icond |= ICOND_CNTZERO;
+ }
+}
+
+void spifi3_device::delay(uint32_t cycles)
+{
+ if (!clock_conv)
+ {
+ return;
+ }
+ cycles *= clock_conv;
+ tm->adjust(clocks_to_attotime(cycles));
+}
+
+void spifi3_device::delay_cycles(uint32_t cycles)
+{
+ tm->adjust(clocks_to_attotime(cycles));
+}
+
+void spifi3_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 spifi3_device::dma_w(uint8_t val)
+{
+ m_even_fifo.push(val);
+ decrement_tcounter();
+ check_drq();
+ step(false);
+}
+
+uint8_t spifi3_device::dma_r()
+{
+ LOGMASKED(LOG_DATA, "dma_r called! Fifo count = %d, state = %d.%d, tcounter = %d\n", m_even_fifo.get_size(), state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT, tcounter);
+ uint8_t val = m_even_fifo.pop();
+ decrement_tcounter();
+ check_drq();
+ step(false);
+ return val;
+}
+
+void spifi3_device::scsi_ctrl_changed()
+{
+ uint32_t ctrl = scsi_bus->ctrl_r();
+ if (ctrl & S_RST)
+ {
+ LOG("scsi bus reset\n");
+ return;
+ }
+
+ step(false);
+}
+
+spifi3_device::dma_direction spifi3_device::dma_setting(uint32_t target_id)
+{
+ // TODO: LUN? That is also written to this register in NetBSD
+ // (and probably NEWS-OS). Need to figure out how to get
+ // a device with multiple LUNs to test to nail down this
+ // logic.
+ dma_direction result = DMA_NONE;
+ if ((spifi_reg.autodata & ADATA_TARGET_ID) == target_id)
+ {
+ result = (spifi_reg.autodata & ADATA_IN) ? DMA_IN :
+ DMA_OUT;
+ }
+ return result;
+}
+
+uint32_t spifi3_device::get_target_id()
+{
+ return (spifi_reg.select & SEL_TARGET) >> 4;
+}
+
+bool spifi3_device::autodata_active(uint32_t target_id)
+{
+ return (spifi_reg.autodata & ADATA_EN) && ((spifi_reg.autodata & ADATA_TARGET_ID) == target_id);
+}
+
+bool spifi3_device::autodata_in(uint32_t target_id)
+{
+ return autodata_active(target_id) && (spifi_reg.autodata & ADATA_IN);
+}
+
+bool spifi3_device::autodata_out(uint32_t target_id)
+{
+ return autodata_active(target_id) && !(spifi_reg.autodata & ADATA_IN);
+}
+
+void spifi3_device::autostat_done(uint32_t target_id)
+{
+ spifi_reg.autostat &= ~(1 << target_id);
+}
+
+bool spifi3_device::autostat_active(uint32_t target_id)
+{
+ return spifi_reg.autostat & (1 << target_id);
+}
+
+bool spifi3_device::automsg_active()
+{
+ return spifi_reg.cmlen & CML_AMSG_EN;
+}
+
+bool spifi3_device::autocmd_active()
+{
+ return spifi_reg.cmlen & CML_ACOM_EN;
+}
+
+void spifi3_device::start_autostat()
+{
+ LOGMASKED(LOG_AUTO, "start AUTOSTAT\n");
+ state = INIT_XFR;
+ xfr_phase = S_PHASE_STATUS;
+ spifi_reg.spstat = SPS_STATUS;
+ dma_set(DMA_NONE);
+}
+
+void spifi3_device::start_automsg(uint32_t msg_phase)
+{
+ LOGMASKED(LOG_AUTO, "start AUTOMSG\n");
+ state = INIT_XFR;
+ xfr_phase = msg_phase;
+ spifi_reg.spstat = msg_phase == S_PHASE_MSG_IN ? SPS_MSGIN : SPS_MSGOUT;
+ dma_set(DMA_NONE);
+}
+
+void spifi3_device::start_autocmd()
+{
+ LOGMASKED(LOG_AUTO, "start AUTOCMD\n");
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); // Deassert ACK since we are automatically moving to the command phase
+ state = INIT_XFR;
+ xfr_phase = S_PHASE_COMMAND;
+ spifi_reg.spstat = SPS_COMMAND;
+ dma_set(DMA_NONE);
+}
+
+void spifi3_device::start_autodata(uint32_t data_phase)
+{
+ LOGMASKED(LOG_AUTO, "start AUTODATA\n");
+ state = INIT_XFR;
+ xfr_phase = data_phase;
+ dma_set(data_phase == S_PHASE_DATA_IN ? DMA_IN : DMA_OUT);
+ spifi_reg.spstat = data_phase == S_PHASE_DATA_IN ? SPS_DATAIN : SPS_DATAOUT;
+ check_drq();
+}
+
+/*
+ * auto_phase_transfer
+ *
+ * This will override the current xfr_phase if needed, otherwise will proceed to BSRQ
+ * This is called when a new xfr_phase is detected and there is the possibility of an
+ * auto-progression to a new phase
+ */
+void spifi3_device::auto_phase_transfer(uint32_t new_phase)
+{
+ if (xfr_phase == new_phase)
+ {
+ fatalerror("%s: auto_phase_transfer called without phase transition!", tag());
+ }
+ LOGMASKED(LOG_STATE, "Phase changed to %d\n", new_phase);
+ state = INIT_XFR_BUS_COMPLETE;
+ command_pos = 0;
+
+ if ((new_phase == S_PHASE_DATA_IN && autodata_in(bus_id)) || (new_phase == S_PHASE_DATA_OUT && autodata_out(bus_id)))
+ {
+ start_autodata(new_phase);
+ }
+ else if (new_phase == S_PHASE_STATUS && autostat_active(bus_id))
+ {
+ start_autostat();
+ }
+ else if ((new_phase == S_PHASE_MSG_IN || new_phase == S_PHASE_MSG_OUT) && automsg_active())
+ {
+ start_automsg(new_phase);
+ }
+ else if (new_phase == S_PHASE_COMMAND && autocmd_active())
+ {
+ start_autocmd();
+ }
+}
+
+void spifi3_device::step(bool timeout)
+{
+ uint32_t ctrl = scsi_bus->ctrl_r();
+ uint32_t data = scsi_bus->data_r();
+
+ LOGMASKED(LOG_STATE, "state=%d.%d %s\n", state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT, timeout ? "timeout" : "change");
+
+ if (mode == MODE_I && !(ctrl & S_BSY)) // Not busy and we are the initiator. We can disconnect.
+ {
+ // TODO: Set Z state flag? Any interrupts needed?
+ state = IDLE;
+ spifi_reg.spstat = SPS_IDLE;
+ reset_disconnect();
+ check_irq();
+ }
+
+ switch (state & SUB_MASK ? state & SUB_MASK : state & STATE_MASK)
+ {
+ case IDLE:
+ {
+ break;
+ }
+
+ case BUSRESET_WAIT_INT: // Bus was reset by a command, go to idle state and clear reset signal
+ {
+ state = IDLE;
+ scsi_bus->ctrl_w(scsi_refid, 0, S_RST);
+ reset_disconnect();
+ break;
+ }
+
+ case ARB_COMPLETE << SUB_SHIFT: // Arbitration process done, check results and assert SEL if we won
+ {
+ if (!timeout) // Synchronize state to clock
+ {
+ break;
+ }
+
+ // Scan to see if we won arbitration
+ int arbitrationWinner;
+ for (arbitrationWinner = 7; arbitrationWinner >= 0 && !(data & (1 << arbitrationWinner)); arbitrationWinner--)
+ {
+ }
+
+ if (arbitrationWinner != scsi_id)
+ {
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
+ fatalerror("%s: need to wait for bus free (lost arbitration)\n", tag());
+ }
+
+ // Now that we won arbitration, we need to assert SEL and wait for the bus to settle.
+ 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: // Won arbitration and asserted SEL, time to write target to data bus
+ {
+ if (!timeout) // Synchronize state to clock
+ {
+ break;
+ }
+
+ bus_id = get_target_id();
+ 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: // Set target, time to release BSY
+ {
+ if (!timeout) // Synchronize state to clock
+ {
+ break;
+ }
+
+ state = (state & STATE_MASK) | (ARB_RELEASE_BUSY << SUB_SHIFT);
+ scsi_bus->ctrl_w(scsi_refid, spifi_reg.select & SEL_WATN ? S_ATN : 0, S_ATN | S_BSY);
+ delay(2);
+ break;
+ }
+
+ case ARB_RELEASE_BUSY << SUB_SHIFT: // BSY released, if target responds, we need to do the deskew wait
+ {
+ if (!timeout) // Synchronize state to clock
+ {
+ break;
+ }
+
+ if (ctrl & S_BSY) // Check if target responded
+ {
+ state = (state & STATE_MASK) | (ARB_DESKEW_WAIT << SUB_SHIFT);
+ // TODO: reselection logic for this step
+ delay_cycles(2);
+ }
+ else // If not, we ran out of time - wait until the next timeout and check again
+ {
+ state = (state & STATE_MASK) | (ARB_TIMEOUT_BUSY << SUB_SHIFT);
+
+ // TODO: What is the correct delay time for the SPIFI?
+ delay(1);
+ }
+ break;
+ }
+
+ case ARB_DESKEW_WAIT << SUB_SHIFT: // Waited for deskew, now we can proceed to the next state.
+ {
+ if (!timeout)
+ {
+ break;
+ }
+
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_SEL); // Clear SEL - target may now assert REQ
+
+ // TODO: reselection logic for this step
+ // Target mode not supported for now
+ if (false)
+ {
+ LOG("mode switch to Target\n");
+ mode = MODE_T;
+ }
+ else
+ {
+ LOG("mode switch to Initiator\n");
+ mode = MODE_I;
+ }
+
+ state &= STATE_MASK;
+ step(true);
+ break;
+ }
+
+ case ARB_TIMEOUT_BUSY << SUB_SHIFT: // Timed out during selection, try again
+ {
+ if (timeout) // No response from target
+ {
+ scsi_bus->data_w(scsi_refid, 0);
+ LOG("select timeout\n");
+ state = (state & STATE_MASK) | (ARB_TIMEOUT_ABORT << SUB_SHIFT); // handle timeout
+ delay(1000);
+ }
+ else if (ctrl & S_BSY) // Got response from target, wait before allowing transaction
+ {
+ state = (state & STATE_MASK) | (ARB_DESKEW_WAIT << SUB_SHIFT);
+ // TODO: reselection logic for this step
+ delay_cycles(2);
+ }
+ break;
+ }
+
+ case ARB_TIMEOUT_ABORT << SUB_SHIFT: // Selection timed out - need to abort
+ {
+ if (!timeout)
+ {
+ break;
+ }
+
+ if (ctrl & S_BSY) // Last chance for target to respond
+ {
+ state = (state & STATE_MASK) | (ARB_DESKEW_WAIT << SUB_SHIFT);
+ // TODO: reselection logic for this step
+ delay_cycles(2);
+ }
+ else // If not, force bus free
+ {
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
+ state = IDLE;
+ spifi_reg.intr = INTR_TIMEO;
+ 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;
+ }
+
+ const auto masked_state = state & STATE_MASK;
+ if (masked_state != INIT_XFR_RECV_PAD)
+ {
+ const auto data = scsi_bus->data_r();
+ const auto xfr_masked = xfr_phase & S_PHASE_MASK;
+ if (xfr_masked == S_PHASE_STATUS && masked_state == INIT_XFR_RECV_BYTE_ACK && autostat_active(bus_id))
+ {
+ LOGMASKED(LOG_AUTO, "AUTOSTAT setting cmbuf[%d].status = 0x%x\n", data, bus_id);
+ spifi_reg.cmbuf[bus_id].status = data;
+ autostat_done(bus_id);
+ }
+ else if (xfr_masked == S_PHASE_MSG_IN && (masked_state == INIT_XFR_RECV_BYTE_ACK_AUTOMSG || masked_state == INIT_XFR_RECV_BYTE_ACK) && automsg_active())
+ {
+ // TODO: determine where AUTOMSG byte goes - probably in the matching ID's cdb
+ LOGMASKED(LOG_AUTO, "AUTOMSG accepted byte 0x%x\n", data);
+ }
+ else
+ {
+ m_even_fifo.push(data);
+ }
+ check_drq();
+ }
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
+ state = masked_state | (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_INIT: // Arbitration and selection complete, time to execute the queued command
+ {
+ if (automsg_active())
+ {
+ state = DISC_SEL_ARBITRATION;
+ step(false);
+ }
+ else
+ {
+ // TODO: It isn't clear what the correct behavior here should be.
+ // The NWS-5000 APmonitor, NEWS-OS, and NetBSD all set AUTOMSG, so this code path is never taken.
+ // For now, kick it up to the firmware or software to handle, hang, or panic.
+ bus_complete();
+ }
+ break;
+ }
+
+ case DISC_SEL_ARBITRATION:
+ {
+ if (!(spifi_reg.select & SEL_WATN))
+ {
+ // The NWS-5000 APmonitor, NEWS-OS, and NetBSD all set SEL_WATN, so this code path is never taken.
+ fatalerror("%s: SEL_WATN was not asserted - this is not yet implemented!", tag());
+ state = DISC_SEL_WAIT_REQ;
+ }
+ else
+ {
+ state = DISC_SEL_ATN_WAIT_REQ;
+ }
+
+ scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); // wait for REQ
+ if (ctrl & S_REQ)
+ {
+ step(false);
+ }
+ break;
+ }
+
+ case DISC_SEL_ATN_WAIT_REQ: // REQ asserted, either get read to send a byte, or complete the command.
+ {
+ if (!(ctrl & S_REQ))
+ {
+ break;
+ }
+
+ // If we're no longer in MSG_OUT, we're done
+ if ((ctrl & S_PHASE_MASK) != S_PHASE_MSG_OUT)
+ {
+ function_complete();
+ break;
+ }
+
+ // Deassert ATN now if we asserted it before
+ if (spifi_reg.select & SEL_WATN)
+ {
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ATN);
+ }
+
+ state = DISC_SEL_ATN_SEND_BYTE;
+ if (spifi_reg.identify & 0x80)
+ {
+ // Identify register has an identify packet - send it.
+ scsi_bus->data_w(scsi_refid, spifi_reg.identify);
+ scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
+ scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
+ }
+ else
+ {
+ // Send the next byte from the CDB
+ send_byte(COMMAND_BUFFER);
+ }
+ break;
+ }
+
+ case DISC_SEL_ATN_SEND_BYTE:
+ {
+ if ((spifi_reg.identify & 0x80) || command_pos >= (spifi_reg.cmlen & CML_LENMASK))
+ {
+ // autoidentified target, now we need to see if autocmd is enabled. If so, we can just proceed to the XFR phase automatically.
+ spifi_reg.identify = 0x0; // in case we just sent an ID packet
+ command_pos = 0;
+ const auto new_phase = (ctrl & S_PHASE_MASK);
+ auto_phase_transfer(new_phase);
+ if (state == INIT_XFR_BUS_COMPLETE) // auto_phase_transfer fell through
+ {
+ function_bus_complete();
+ }
+ else
+ {
+ step(false);
+ }
+ }
+ else
+ {
+ state = DISC_SEL_WAIT_REQ;
+ }
+ break;
+ }
+
+ case DISC_SEL_WAIT_REQ:
+ {
+ if (!(ctrl & S_REQ))
+ {
+ break;
+ }
+ if ((ctrl & S_PHASE_MASK) != S_PHASE_COMMAND)
+ {
+ scsi_bus->ctrl_wait(scsi_refid, 0, S_REQ);
+ function_bus_complete();
+ break;
+ }
+
+ state = DISC_SEL_SEND_BYTE;
+ send_byte(COMMAND_BUFFER);
+ break;
+ }
+
+ case DISC_SEL_SEND_BYTE:
+ {
+ 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:
+ {
+ function_complete();
+ break;
+ }
+
+ case INIT_MSG_WAIT_REQ:
+ {
+ if ((ctrl & (S_REQ | S_BSY)) == S_BSY)
+ {
+ break;
+ }
+ bus_complete();
+ break;
+ }
+
+ case INIT_XFR:
+ {
+ LOGMASKED(LOG_STATE, "INIT_XFR: %d\n", xfr_phase);
+ switch (xfr_phase)
+ {
+ case S_PHASE_DATA_OUT:
+ case S_PHASE_COMMAND:
+ case S_PHASE_MSG_OUT:
+ {
+ state = INIT_XFR_SEND_BYTE;
+
+ // can't send if the fifo is empty and we are sending data
+ if (m_even_fifo.empty() && xfr_phase == S_PHASE_DATA_OUT)
+ {
+ xfr_data_source = FIFO;
+ break;
+ }
+
+ // if it's the last message byte, ensure ATN is low before sending
+ if ((xfr_phase == S_PHASE_MSG_OUT) && (command_pos == (spifi_reg.cmlen & CML_LENMASK) - 1))
+ {
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ATN);
+ }
+
+ if (xfr_phase == S_PHASE_DATA_OUT)
+ {
+ xfr_data_source = FIFO;
+ send_byte(FIFO);
+ }
+ else
+ {
+ // Both commands and messages come from the CDB
+ xfr_data_source = COMMAND_BUFFER;
+ send_byte(COMMAND_BUFFER);
+ }
+ break;
+ }
+
+ case S_PHASE_DATA_IN:
+ case S_PHASE_STATUS:
+ case S_PHASE_MSG_IN:
+ {
+ // can't receive if the fifo is full
+ if (m_even_fifo.full() && !(xfr_phase == S_PHASE_STATUS && autostat_active(bus_id) && !(xfr_phase == S_PHASE_MSG_IN && automsg_active())))
+ {
+ break;
+ }
+
+ // if it's the last message byte, ACK remains asserted.
+ // However, if AUTOMSG is enabled, automatically accept the message by lowering ACK before continuing.
+ if ((xfr_phase == S_PHASE_MSG_IN && (!dma_command(dma_dir) || tcounter == 1)))
+ {
+ state = automsg_active() ? INIT_XFR_RECV_BYTE_ACK_AUTOMSG : INIT_XFR_RECV_BYTE_NACK;
+ }
+ else
+ {
+ state = INIT_XFR_RECV_BYTE_ACK;
+ }
+
+ xfr_data_source = FIFO;
+ recv_byte();
+ break;
+ }
+
+ default:
+ {
+ LOG("xfer on phase %d\n", scsi_bus->ctrl_r() & S_PHASE_MASK);
+ function_complete();
+ break;
+ }
+ }
+ break;
+ }
+
+ case INIT_XFR_WAIT_REQ:
+ {
+ if (!(ctrl & S_REQ))
+ {
+ break;
+ }
+
+ // check for command complete
+ const auto new_phase = (ctrl & S_PHASE_MASK);
+ if (xfr_data_source == FIFO && (dma_command(dma_dir) && transfer_count_zero() && (dma_dir == DMA_IN || m_even_fifo.empty())))
+ {
+ LOGMASKED(LOG_DATA, "DMA transfer complete\n");
+ if (xfr_phase == S_PHASE_DATA_OUT && new_phase == S_PHASE_DATA_OUT)
+ {
+ // Set ICOND so that NEWS-OS knows that SPIFI is ready to send pad bytes.
+ // NEWS-OS will sometimes set tcounter to less than one block size, then sends TR_PAD in response to this ICOND value.
+ spifi_reg.icond = ICOND_UXPHASEZ;
+ state = INIT_XFR_BUS_COMPLETE;
+ }
+ else if (xfr_phase == S_PHASE_DATA_IN && new_phase == S_PHASE_DATA_IN)
+ {
+ // Dump the remaining contents of the FIFO - at this point, the transfer counter is exhausted so whatever
+ // is left in the queue is pad byte junk read after the real data was received but before the DMA transfer completed
+ m_even_fifo.clear_queue();
+
+ // See above
+ spifi_reg.icond = ICOND_UXPHASEZ;
+ state = INIT_XFR_BUS_COMPLETE;
+ }
+ else
+ {
+ auto_phase_transfer(new_phase);
+ }
+ }
+ else if (xfr_data_source == FIFO && (!dma_command(dma_dir) && (xfr_phase & S_INP) == 0 && m_even_fifo.empty()))
+ {
+ LOGMASKED(LOG_DATA, "Non-DMA transfer out complete\n");
+ auto_phase_transfer(new_phase);
+ }
+ else if (xfr_data_source == FIFO && (!dma_command(dma_dir) && ((xfr_phase & S_INP) == S_INP) && m_even_fifo.get_size() == 1))
+ {
+ LOGMASKED(LOG_DATA, "Non-DMA transfer in complete\n");
+ auto_phase_transfer(new_phase);
+ }
+ else if (xfr_data_source == COMMAND_BUFFER && (command_pos >= (spifi_reg.cmlen & CML_LENMASK))) // Done transferring message or command
+ {
+ if (new_phase != xfr_phase)
+ {
+ auto_phase_transfer(new_phase);
+ }
+ else
+ {
+ fatalerror("%s: ran out of CDB bytes to transfer!", tag());
+ }
+ }
+ else
+ {
+ const auto new_phase = ctrl & S_PHASE_MASK;
+ if (new_phase != xfr_phase)
+ {
+ auto_phase_transfer(new_phase);
+ }
+ else
+ {
+ state = INIT_XFR;
+ }
+ }
+ step(false);
+ break;
+ }
+
+ case INIT_XFR_SEND_BYTE:
+ {
+ state = INIT_XFR_WAIT_REQ;
+ step(false);
+ break;
+ }
+
+ case INIT_XFR_RECV_BYTE_ACK:
+ {
+ state = INIT_XFR_WAIT_REQ;
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ step(false);
+ break;
+ }
+
+ case INIT_XFR_RECV_BYTE_NACK:
+ {
+ state = INIT_XFR_FUNCTION_COMPLETE;
+ step(false);
+ break;
+ }
+
+ case INIT_XFR_RECV_BYTE_ACK_AUTOMSG:
+ {
+ // Bypass the rest of the state machine, because if we allow this to do another cycle,
+ // the bus will be free and the interrupts won't be set correctly.
+ // This would have gone to INIT_XFR_FUNCTION_COMPLETE otherwise.
+ if (dma_command(dma_dir) && !transfer_count_zero() && !m_even_fifo.empty())
+ {
+ break;
+ }
+ LOGMASKED(LOG_AUTO, "AUTOMSG cleared ACK\n");
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ function_complete();
+
+ // Since we auto-accepted the message, we step again here to complete the disconnect
+ step(false);
+ break;
+ }
+
+ case INIT_XFR_FUNCTION_COMPLETE:
+ {
+ // wait for dma transfer to complete or fifo to drain
+ if (dma_command(dma_dir) && !transfer_count_zero() && !m_even_fifo.empty())
+ {
+ break;
+ }
+
+ function_complete();
+ break;
+ }
+
+ case INIT_XFR_BUS_COMPLETE:
+ {
+ // wait for dma transfer to complete or fifo to drain
+ if (dma_command(dma_dir) && !transfer_count_zero() && !m_even_fifo.empty())
+ {
+ break;
+ }
+
+ bus_complete();
+ break;
+ }
+
+ case INIT_XFR_SEND_PAD_WAIT_REQ:
+ {
+ if (!(ctrl & S_REQ))
+ {
+ break;
+ }
+
+ const auto new_phase = (ctrl & S_PHASE_MASK);
+ if (new_phase != xfr_phase)
+ {
+ auto_phase_transfer(new_phase);
+ step(false);
+ }
+ else
+ {
+ state = INIT_XFR_SEND_PAD;
+ send_byte(FIFO);
+ }
+ break;
+ }
+
+ case INIT_XFR_SEND_PAD:
+ {
+ state = INIT_XFR_SEND_PAD_WAIT_REQ;
+ step(false);
+ break;
+ }
+
+ case INIT_XFR_RECV_PAD_WAIT_REQ:
+ {
+ if (!(ctrl & S_REQ))
+ {
+ break;
+ }
+
+ const auto new_phase = (ctrl & S_PHASE_MASK);
+ if (new_phase != xfr_phase)
+ {
+ auto_phase_transfer(new_phase);
+ step(false);
+ }
+ else
+ {
+ state = INIT_XFR_RECV_PAD;
+ recv_byte();
+ }
+ break;
+ }
+
+ case INIT_XFR_RECV_PAD:
+ {
+ state = INIT_XFR_RECV_PAD_WAIT_REQ;
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
+ step(false);
+ break;
+ }
+
+ default:
+ {
+ fatalerror("%s: step() unexpected state %d.%d\n", tag(), state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT);
+ }
+ }
+}
diff --git a/src/devices/machine/spifi3.h b/src/devices/machine/spifi3.h
new file mode 100644
index 00000000000..6afa51ded06
--- /dev/null
+++ b/src/devices/machine/spifi3.h
@@ -0,0 +1,304 @@
+// license:BSD-3-Clause
+// copyright-holders:Brice Onken,Tsubai Masanari,Olivier Galibert
+// thanks-to:Patrick Mackinlay
+
+/*
+ * HP 1TV3-0302 SPIFI3-SE SCSI controller
+ *
+ * Datasheets for this seem to be impossible to find - the only avaliable implementation to reference that I have
+ * found is the Sony NEWS APBus NetBSD driver. Hopefully a datasheet will turn up eventually.
+ * Based on internet research, it seems some HP PA-RISC systems also used the SPIFI3, including the E55.
+ *
+ * Because this driver was developed to work with NetBSD, NEWS-OS, and the NWS-5000 monitor ROM, only
+ * the features and flows that Sony used are implemented. Emulating non-Sony designs using this chip will likely
+ * require similar RE work to determine the exact SPIFI features used and add support for them into this driver.
+ * In its current state, this driver is unlikely to work out of the box with any other machines.
+ *
+ * Register definitions were derived from the NetBSD source code, copyright (c) 2000 Tsubai Masanari.
+ * SCSI state machine code was derived from the MAME NCR53C90 driver, copyright (c) Olivier Galibert
+ *
+ * References:
+ * - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifireg.h
+ * - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifi.c
+ * - https://github.com/mamedev/mame/blob/master/src/devices/machine/ncr53c90.cpp
+ */
+
+#ifndef MAME_MACHINE_SPIFI3_H
+#define MAME_MACHINE_SPIFI3_H
+
+#pragma once
+
+#include "machine/nscsi_bus.h"
+
+class spifi3_device
+ : public nscsi_device,
+ public nscsi_slot_card_interface
+{
+public:
+ spifi3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+ void map(address_map &map);
+
+ auto irq_handler_cb() { return m_irq_handler.bind(); }
+ auto drq_handler_cb() { return m_drq_handler.bind(); }
+
+ uint8_t dma_r();
+ void dma_w(uint8_t val);
+
+protected:
+ virtual void device_start() override;
+ virtual void scsi_ctrl_changed() override;
+
+private:
+ static constexpr int FIFO_SIZE = 8;
+
+ enum scsi_mode : uint8_t
+ {
+ MODE_D, // Disconnected
+ MODE_T, // Target
+ MODE_I // Initiator
+ };
+
+ enum scsi_data_target : uint8_t
+ {
+ COMMAND_BUFFER,
+ FIFO
+ };
+
+ enum dma_direction : uint8_t
+ {
+ DMA_NONE,
+ DMA_IN,
+ DMA_OUT
+ };
+
+ struct spifi_cmd_entry
+ {
+ // NetBSD has these mapped as uint32_t to align the accesses and such
+ // in reality, these are all 8-bit values that are mapped, in typical NWS-5000 series
+ // fashion, to be 32-bit word aligned.
+ // the same probably applies to the register file.
+ uint8_t cdb[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uint8_t quecode = 0;
+ uint8_t quetag = 0;
+ uint8_t idmsg = 0;
+ uint8_t status = 0;
+ };
+
+ struct register_file
+ {
+ uint32_t spstat = 0;
+ uint32_t cmlen = 0;
+ uint32_t cmdpage = 0;
+ // count_hi, count_mid, count_low
+
+ uint32_t svptr_hi = 0;
+ uint32_t svptr_mid = 0;
+ uint32_t svptr_low = 0;
+
+ uint32_t intr = 0;
+ uint32_t imask = 0;
+ uint32_t prctrl = 0;
+
+ uint32_t prstat = 0;
+ uint32_t init_status = 0;
+ uint32_t fifoctrl = 0;
+ uint32_t fifodata = 0;
+
+ uint32_t config = 0;
+ uint32_t data_xfer = 0;
+ uint32_t autocmd = 0;
+ uint32_t autostat = 0;
+
+ uint32_t resel = 0;
+ uint32_t select = 0;
+ // prcmd, which is used to trigger commands
+ uint32_t auxctrl = 0;
+
+ uint32_t autodata = 0;
+ uint32_t loopctrl = 0;
+ uint32_t loopdata = 0;
+ uint32_t identify = 0;
+
+ uint32_t complete = 0;
+ uint32_t scsi_status = 0x1; // Must be 0x1 for SPIFI to be recognized at boot
+ uint32_t data = 0;
+ uint32_t icond = 0;
+
+ uint32_t fastwide = 0;
+ uint32_t exctrl = 0;
+ uint32_t exstat = 0;
+ uint32_t test = 0;
+
+ uint32_t quematch = 0;
+ uint32_t quecode = 0;
+ uint32_t quetag = 0;
+ uint32_t quepage = 0;
+
+ spifi_cmd_entry cmbuf[8];
+ } spifi_reg;
+
+ template<typename T>
+ class spifi_queue
+ {
+ public:
+ uint32_t head;
+ uint32_t tail;
+ uint32_t size;
+ T fifo[FIFO_SIZE];
+
+ spifi_queue() { clear_queue(); }
+
+ uint32_t get_size() { return size; }
+
+ bool empty() { return size == 0; }
+
+ bool full() { return size == FIFO_SIZE; }
+
+ void clear_queue()
+ {
+ head = 0;
+ tail = 0;
+ size = 0;
+
+ for (int i = 0; i < FIFO_SIZE; ++i)
+ {
+ fifo[i] = 0;
+ }
+ }
+
+ void push(T value)
+ {
+ if(size == FIFO_SIZE)
+ {
+ fatalerror("spifi3: FIFO overflow!");
+ }
+
+ fifo[tail] = value;
+ tail = (tail + 1) % FIFO_SIZE;
+ ++size;
+ }
+
+ T pop()
+ {
+ if (size == 0)
+ {
+ fatalerror("spifi3: FIFO underflow!");
+ }
+
+ const T removed_value = fifo[head];
+ head = (head + 1) % FIFO_SIZE;
+ --size;
+ return removed_value;
+ }
+ };
+
+ // State tracking variables
+ dma_direction dma_dir;
+ scsi_mode mode;
+ scsi_data_target xfr_data_source;
+ uint32_t state;
+ uint32_t xfr_phase;
+ uint32_t command_pos;
+ bool irq = false;
+ bool drq = false;
+ uint32_t tcounter;
+ uint8_t sync_period = 5; // TODO: appropriate value for SPIFI
+ uint8_t clock_conv = 2; // TODO: appropriate value for SPIFI
+ uint32_t bus_id;
+ spifi_queue<uint8_t> m_even_fifo;
+ spifi_queue<uint8_t> m_odd_fifo;
+ emu_timer *tm;
+
+ // I/O ports
+ devcb_write_line m_irq_handler;
+ devcb_write_line m_drq_handler;
+
+ // State-related methods
+ TIMER_CALLBACK_MEMBER(tick);
+ void step(bool timeout);
+ void check_irq();
+ void check_drq();
+ void reset_disconnect();
+ void send_byte(scsi_data_target data_source);
+ void recv_byte();
+ void function_complete();
+ void function_bus_complete();
+ void bus_complete();
+ void dma_set(dma_direction dir);
+ void decrement_tcounter(uint32_t count = 1);
+ bool transfer_count_zero();
+ void delay(uint32_t cycles);
+ void delay_cycles(uint32_t cycles);
+ void arbitrate();
+ void clear_fifo();
+ void auto_phase_transfer(uint32_t new_phase);
+ void start_autodata(uint32_t data_phase);
+ void start_autostat();
+ void start_automsg(uint32_t msg_phase);
+ void start_autocmd();
+ dma_direction dma_setting(uint32_t target_id);
+
+ // Register processing methods
+ uint32_t get_target_id();
+ bool autodata_active(uint32_t target_id);
+ bool autodata_in(uint32_t target_id);
+ bool autodata_out(uint32_t target_id);
+ void autostat_done(uint32_t target_id);
+ bool autostat_active(uint32_t target_id);
+ bool automsg_active();
+ bool autocmd_active();
+
+ // Register accessors
+ uint32_t spstat_r();
+ uint32_t cmlen_r();
+ void cmlen_w(uint32_t data);
+ uint32_t cmdpage_r();
+ void cmdpage_w(uint32_t data);
+ uint32_t count_r(offs_t offset);
+ void count_w(offs_t offset, uint32_t data);
+ uint32_t intr_r();
+ void intr_w(uint32_t data);
+ uint32_t imask_r();
+ void imask_w(uint32_t data);
+ uint32_t prstat_r();
+ uint32_t init_status_r();
+ uint32_t fifoctrl_r();
+ void fifoctrl_w(uint32_t data);
+ uint32_t data_xfer_r();
+ void data_xfer_w(uint32_t data);
+ uint32_t autocmd_r();
+ void autocmd_w(uint32_t data);
+ uint32_t autostat_r();
+ void autostat_w(uint32_t data);
+ uint32_t select_r();
+ void select_w(uint32_t data);
+ void prcmd_w(uint32_t data);
+ uint32_t auxctrl_r();
+ void auxctrl_w(uint32_t data);
+ uint32_t autodata_r();
+ void autodata_w(uint32_t data);
+ uint32_t identify_r();
+ void identify_w(uint32_t data);
+ uint32_t scsi_status_r();
+ void scsi_status_w(uint32_t data);
+ uint32_t icond_r();
+ void icond_w(uint32_t data);
+ uint32_t fastwide_r();
+ void fastwide_w(uint32_t data);
+ uint32_t exctrl_r();
+ void exctrl_w(uint32_t data);
+
+ // Command buffer accessors
+ uint8_t cmd_buf_r(offs_t offset);
+ void cmd_buf_w(offs_t offset, uint8_t data);
+
+ // Data helpers
+ bool dma_command(dma_direction current_direction) const
+ {
+ return current_direction != DMA_NONE;
+ }
+};
+
+DECLARE_DEVICE_TYPE(SPIFI3, spifi3_device)
+
+#endif // MAME_MACHINE_SPIFI3_H
diff --git a/src/devices/machine/steppers.cpp b/src/devices/machine/steppers.cpp
index 0350017d976..308f2a4ff25 100644
--- a/src/devices/machine/steppers.cpp
+++ b/src/devices/machine/steppers.cpp
@@ -95,9 +95,6 @@ void stepper_device::update_optic()
void stepper_device::device_start()
{
- /* resolve callbacks */
- m_optic_cb.resolve_safe();
-
/* register for state saving */
save_item(NAME(m_index_start));
save_item(NAME(m_index_end));
@@ -189,7 +186,7 @@ void stepper_device::advance_phase()
{
//Standard drive table is 2,6,4,5,1,9,8,a
//NOTE: This runs through the stator patterns in such a way as to drive the reel forward (downwards from the player's view, clockwise on our rose)
- //The Heber 'Pluto' controller runs this in reverse
+ //The Heber 'Pluto' controller runs this in reverse, this needs checking on real hardware
switch (m_pattern)
{ //Black Blue Red Yellow
case 0x02:// 0 0 1 0
@@ -257,7 +254,8 @@ void reel_device::advance_phase()
case STARPOINT_48STEP_REEL : /* STARPOINT RMxxx */
case GAMESMAN_200STEP_REEL : /* Gamesman GMxxxx */
case STARPOINT_144STEP_DICE :/* STARPOINT 1DCU DICE mechanism */
- case STARPOINT_200STEP_REEL :/* STARPOINT 1DCU DICE mechanism */
+ case STARPOINT_200STEP_REEL :
+ case SYS5_100STEP_REEL :
stepper_device::advance_phase();
break;
@@ -325,23 +323,22 @@ void reel_device::advance_phase()
break;
case MPU3_48STEP_REEL :
- /* The MPU3 interface is actually the same as the MPU4 setup, but with two active lines instead of four
+ /* The MPU3 harness is actually the same as the MPU4 setup, but with two active lines instead of four, and a slight change to the windings.
Inverters are used so if a pin is low, the higher bit of the pair is activated, and if high the lower bit is activated.
- TODO:Check this, 2 and 1 could be switched over.
- */
+ */
switch (m_pattern)
{
- // Yellow(2) Brown(1) Orange(!2) Black(!1)
- case 0x00 :// 0 0 1 1
+ // Grey(1) Yellow(2) Grey (2) Yellow (2)
+ case 0x02 :// 0 1 0 1
m_phase = 6;
break;
- case 0x01 :// 0 1 1 0
+ case 0x03 :// 0 1 1 0
m_phase = 4;
break;
- case 0x03 :// 1 1 0 0
+ case 0x01 :// 1 0 1 0
m_phase = 2;
break;
- case 0x02 :// 1 0 0 1
+ case 0x00 :// 1 0 0 1
m_phase = 0;
break;
}
@@ -404,6 +401,38 @@ void reel_device::advance_phase()
}
break;
+ case SRU_200STEP_REEL :
+ //Standard drive table is 2,3,1,9,8,c,4,6
+ //Starpoint mechanism, custom for JPM?
+ switch (m_pattern)
+ {
+ case 0x02:
+ m_phase = 7;
+ break;
+ case 0x03:
+ m_phase = 6;
+ break;
+ case 0x01:
+ m_phase = 5;
+ break;
+ case 0x09:
+ m_phase = 4;
+ break;
+ case 0x08:
+ m_phase = 3;
+ break;
+ case 0x0c:
+ m_phase = 2;
+ break;
+ case 0x04:
+ m_phase = 1;
+ break;
+ case 0x06:
+ m_phase = 0;
+ break;
+ }
+ break;
+
case PROJECT_48STEP_REEL :
//Standard drive table is 8,c,4,5,1,3,2,a
//This appears to be basically a rewired Gamesman (the reel PCB looks like it does some shuffling)
diff --git a/src/devices/machine/steppers.h b/src/devices/machine/steppers.h
index fac2a8e129c..fc9e5822870 100644
--- a/src/devices/machine/steppers.h
+++ b/src/devices/machine/steppers.h
@@ -33,6 +33,10 @@
#define PROJECT_48STEP_REEL 10
+#define SRU_200STEP_REEL 11
+
+#define SYS5_100STEP_REEL 12
+
class stepper_device : public device_t
{
@@ -69,6 +73,8 @@ public:
int get_position() { return m_step_pos; }
/* get current absolute position in half steps */
int get_absolute_position() { return m_abs_step_pos; }
+ /* set absolute position in half steps */
+ void set_absolute_position(int pos) { m_abs_step_pos = pos; }
/* get maximum position in half steps */
int get_max() { return m_max_steps; }
@@ -132,6 +138,7 @@ protected:
case STARPOINT_200STEP_REEL :
case GAMESMAN_200STEP_REEL :
case ECOIN_200STEP_REEL :
+ case SRU_200STEP_REEL :
m_max_steps = (200*2);
break;
}
diff --git a/src/devices/machine/strata.cpp b/src/devices/machine/strata.cpp
index 7976a16def9..7ed6251bba0 100644
--- a/src/devices/machine/strata.cpp
+++ b/src/devices/machine/strata.cpp
@@ -66,9 +66,11 @@ void strataflash_device::nvram_default()
// .nv file
//-------------------------------------------------
-void strataflash_device::nvram_read(emu_file &file)
+bool strataflash_device::nvram_read(util::read_stream &file)
{
- file.read(m_flashmemory.get(), COMPLETE_SIZE);
+ auto const [err, actual] = read(file, m_flashmemory.get(), COMPLETE_SIZE);
+ if (err || (COMPLETE_SIZE != actual))
+ return false;
// TODO
@@ -111,6 +113,8 @@ void strataflash_device::nvram_read(emu_file &file)
return 0;
*/
+
+ return true;
}
//-------------------------------------------------
@@ -118,7 +122,7 @@ void strataflash_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void strataflash_device::nvram_write(emu_file &file)
+bool strataflash_device::nvram_write(util::write_stream &file)
{
// TODO
@@ -172,7 +176,8 @@ void strataflash_device::nvram_write(emu_file &file)
return 0;
*/
- file.write(m_flashmemory.get(), COMPLETE_SIZE);
+ auto const [err, actual] = write(file, m_flashmemory.get(), COMPLETE_SIZE);
+ return !err;
}
//-------------------------------------------------
diff --git a/src/devices/machine/strata.h b/src/devices/machine/strata.h
index 1a3acbbd9dd..0c6f487c50e 100644
--- a/src/devices/machine/strata.h
+++ b/src/devices/machine/strata.h
@@ -24,8 +24,8 @@ protected:
void device_start() override;
void nvram_default() override;
- void nvram_read(emu_file &file) override;
- void nvram_write(emu_file &file) override;
+ bool nvram_read(util::read_stream &file) override;
+ bool nvram_write(util::write_stream &file) override;
private:
diff --git a/src/devices/machine/stvcd.cpp b/src/devices/machine/stvcd.cpp
index 88af2d7e0cf..0cb67d62cc8 100644
--- a/src/devices/machine/stvcd.cpp
+++ b/src/devices/machine/stvcd.cpp
@@ -41,14 +41,28 @@ DASM notes:
***************************************************************************/
#include "emu.h"
-#include "machine/stvcd.h"
+#include "stvcd.h"
#include "coreutil.h"
+#include "multibyte.h"
+
+#define LOG_WARN (1U << 1)
+#define LOG_CMD (1U << 2)
+#define LOG_SEEK (1U << 3)
+#define LOG_XFER (1U << 4)
+
+#define VERBOSE (LOG_CMD | LOG_WARN)
+//#define LOG_OUTPUT_FUNC osd_printf_info
-// super-verbose
-//#define VERBOSE 1
#include "logmacro.h"
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__)
+#define LOGSEEK(...) LOGMASKED(LOG_SEEK, __VA_ARGS__)
+#define LOGXFER(...) LOGMASKED(LOG_XFER, __VA_ARGS__)
+
+#define LIVE_CD_VIEW 0
+
// HIRQ definitions
#define CMOK 0x0001 // command dispatch possible
#define DRDY 0x0002 // data transfer preparations complete
@@ -108,6 +122,7 @@ void stvcd_device::device_add_mconfig(machine_config &config)
CDDA(config, m_cdda);
m_cdda->add_route(0, *this, 1.0, AUTO_ALLOC_INPUT, 0);
m_cdda->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1);
+ m_cdda->set_cdrom_tag("cdrom");
}
void stvcd_device::device_start()
@@ -135,6 +150,10 @@ void stvcd_device::io_regs(address_map &map)
map(0x9001c, 0x9001f).mirror(0x08000).rw(FUNC(stvcd_device::cr2_r), FUNC(stvcd_device::cr2_w)).umask32(0xffffffff);
map(0x90020, 0x90023).mirror(0x08000).rw(FUNC(stvcd_device::cr3_r), FUNC(stvcd_device::cr3_w)).umask32(0xffffffff);
map(0x90024, 0x90027).mirror(0x08000).rw(FUNC(stvcd_device::cr4_r), FUNC(stvcd_device::cr4_w)).umask32(0xffffffff);
+
+ // NetLink access
+ // dragndrm expects this value, most likely for status
+ map(0x8502a, 0x8502a).lr8(NAME([] () -> u8 { return 0x11; }));
}
u32 stvcd_device::datatrns_r(offs_t offset, uint32_t mem_mask)
@@ -155,7 +174,7 @@ u32 stvcd_device::datatrns_r(offs_t offset, uint32_t mem_mask)
}
else
{
- printf("CD: Unknown data buffer read with mask = %08x\n", mem_mask);
+ LOGWARN("CD: Unknown data buffer read with mask = %08x\n", mem_mask);
rv = 0;
}
return rv;
@@ -166,7 +185,7 @@ void stvcd_device::datatrns_w(offs_t offset, uint32_t data, uint32_t mem_mask)
if (mem_mask == 0xffffffff)
dataxfer_long_w(data);
else
- printf("CD: Unknown data buffer write with mask = %08x\n", mem_mask);
+ LOGWARN("CD: Unknown data buffer write with mask = %08x\n", mem_mask);
}
inline u32 stvcd_device::dataxfer_long_r()
@@ -181,10 +200,7 @@ inline u32 stvcd_device::dataxfer_long_r()
if (xfersect < xfersectnum)
{
// get next longword
- rv = (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 0]<<24) |
- (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 1]<<16) |
- (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 2]<<8) |
- (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 3]<<0);
+ rv = get_u32be(&transpart->blocks[xfersectpos+xfersect]->data[xferoffs]);
xferdnum += 4;
xferoffs += 4;
@@ -221,14 +237,14 @@ inline u32 stvcd_device::dataxfer_long_r()
transpart->size -= xferdnum;
transpart->numblks -= xfersectnum;
- /* TODO: is this correct? */
+ // TODO: is this correct?
xfertype32 = XFERTYPE32_INVALID;
}
}
break;
default:
- osd_printf_error("CD: unhandled 32-bit transfer type\n");
+ LOGWARN("CD: unhandled 32-bit transfer type %d\n", (int)xfertype32);
break;
}
@@ -244,10 +260,7 @@ inline void stvcd_device::dataxfer_long_w(u32 data)
if (xfersect < xfersectnum)
{
// get next longword
- transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 0] = (data >> 24) & 0xff;
- transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 1] = (data >> 16) & 0xff;
- transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 2] = (data >> 8) & 0xff;
- transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 3] = (data >> 0) & 0xff;
+ put_u32be(&transpart->blocks[xfersectpos+xfersect]->data[xferoffs], data);
xferdnum += 4;
xferoffs += 4;
@@ -269,7 +282,7 @@ inline void stvcd_device::dataxfer_long_w(u32 data)
break;
default:
- printf("CD: unhandled 32-bit transfer type write\n");
+ LOGWARN("CD: unhandled 32-bit transfer type write %d\n", (int)xfertype32);
break;
}
}
@@ -282,7 +295,7 @@ inline u16 stvcd_device::dataxfer_word_r()
switch (xfertype)
{
case XFERTYPE_TOC:
- rv = tocbuf[xfercount]<<8 | tocbuf[xfercount+1];
+ rv = get_u16be(&tocbuf[xfercount]);
xfercount += 2;
xferdnum += 2;
@@ -295,7 +308,7 @@ inline u16 stvcd_device::dataxfer_word_r()
break;
case XFERTYPE_FILEINFO_1:
- rv = finfbuf[xfercount]<<8 | finfbuf[xfercount+1];
+ rv = get_u16be(&finfbuf[xfercount]);
xfercount += 2;
xferdnum += 2;
@@ -312,22 +325,16 @@ inline u16 stvcd_device::dataxfer_word_r()
uint32_t temp = 2 + (xfercount / (0x6 * 2));
// first 4 bytes = FAD
- finfbuf[0] = (curdir[temp].firstfad>>24)&0xff;
- finfbuf[1] = (curdir[temp].firstfad>>16)&0xff;
- finfbuf[2] = (curdir[temp].firstfad>>8)&0xff;
- finfbuf[3] = (curdir[temp].firstfad&0xff);
+ put_u32be(&finfbuf[0], curdir[temp].firstfad);
// second 4 bytes = length of file
- finfbuf[4] = (curdir[temp].length>>24)&0xff;
- finfbuf[5] = (curdir[temp].length>>16)&0xff;
- finfbuf[6] = (curdir[temp].length>>8)&0xff;
- finfbuf[7] = (curdir[temp].length&0xff);
+ put_u32be(&finfbuf[4], curdir[temp].length);
finfbuf[8] = curdir[temp].interleave_gap_size;
finfbuf[9] = curdir[temp].file_unit_size;
finfbuf[10] = temp;
finfbuf[11] = curdir[temp].flags;
}
- rv = finfbuf[xfercount % (6 * 2)]<<8 | finfbuf[(xfercount % (6 * 2)) +1];
+ rv = get_u16be(&finfbuf[xfercount % (6 * 2)]);
xfercount += 2;
xferdnum += 2;
@@ -340,7 +347,7 @@ inline u16 stvcd_device::dataxfer_word_r()
break;
case XFERTYPE_SUBQ:
- rv = subqbuf[xfercount]<<8 | subqbuf[xfercount+1];
+ rv = get_u16be(&subqbuf[xfercount]);
xfercount += 2;
xferdnum += 2;
@@ -354,7 +361,7 @@ inline u16 stvcd_device::dataxfer_word_r()
case XFERTYPE_SUBRW:
- rv = subrwbuf[xfercount]<<8 | subrwbuf[xfercount+1];
+ rv = get_u16be(&subrwbuf[xfercount]);
xfercount += 2;
xferdnum += 2;
@@ -367,7 +374,7 @@ inline u16 stvcd_device::dataxfer_word_r()
break;
default:
- osd_printf_error("STVCD: Unhandled xfer type %d\n", (int)xfertype);
+ LOGWARN("STVCD: Unhandled xfer type %d\n", (int)xfertype);
rv = 0;
break;
}
@@ -399,13 +406,13 @@ void stvcd_device::hirq_w(uint16_t data) { hirqreg &= data; }
// TODO: these two are actually never read or written to by host?
uint16_t stvcd_device::hirqmask_r()
{
- printf("RW HIRM: %04x\n", hirqmask);
+ LOGWARN("RW HIRM: %04x\n", hirqmask);
return hirqmask;
}
void stvcd_device::hirqmask_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
- printf("WW HIRM: %04x => %04x\n", hirqmask, data);
+ LOGWARN("WW HIRM: %04x => %04x\n", hirqmask, data);
COMBINE_DATA(&hirqmask);
}
@@ -462,7 +469,9 @@ void stvcd_device::stvcd_w(offs_t offset, uint32_t data, uint32_t mem_mask)
*/
int stvcd_device::get_timing_command(void)
{
- /* TODO: calculate timings based off command params */
+ // TODO: calculate timings based off command params
+ // given the CMOK returns it looks like SH2 expects way slower responses
+ // (loops for 0x7xx times at most, max number of iterations is 0x240000)
return 16667;
}
@@ -472,12 +481,12 @@ int stvcd_device::get_track_index(uint32_t fad)
uint32_t rel_fad;
uint8_t track;
- if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, fad)) != CD_TRACK_AUDIO)
+ if(m_cdrom_image->get_track_type(m_cdrom_image->get_track(fad)) != cdrom_file::CD_TRACK_AUDIO)
return 1;
- track = cdrom_get_track( cdrom, fad );
+ track = m_cdrom_image->get_track( fad );
- rel_fad = fad - cdrom_get_track_start( cdrom, track );
+ rel_fad = fad - m_cdrom_image->get_track_start( track );
if(rel_fad < 150)
return 0;
@@ -485,27 +494,34 @@ int stvcd_device::get_track_index(uint32_t fad)
return 1;
}
-int stvcd_device::sega_cdrom_get_adr_control(cdrom_file *file, int track)
+int stvcd_device::sega_cdrom_get_adr_control(int track)
{
- return bitswap<8>(cdrom_get_adr_control(file, cur_track),3,2,1,0,7,6,5,4);
+ return bitswap<8>(m_cdrom_image->get_adr_control(cur_track),3,2,1,0,7,6,5,4);
}
void stvcd_device::cr_standard_return(uint16_t cur_status)
{
- if ((cd_stat & 0x0f00) == CD_STAT_SEEK)
+ if (!m_cdrom_image->exists())
+ {
+ cr1 = cur_status;
+ cr2 = 0;
+ cr3 = 0;
+ cr4 = 0;
+ }
+ else if ((cd_stat & 0x0f00) == CD_STAT_SEEK)
{
/* During seek state, values returned are from the target position */
- uint8_t seek_track = cdrom_get_track(cdrom, cd_fad_seek-150);
+ uint8_t seek_track = m_cdrom_image->get_track(cd_fad_seek-150);
cr1 = cur_status | (playtype << 7) | 0x00 | (cdda_repeat_count & 0xf);
- cr2 = (seek_track == 0xff) ? 0xffff : ((sega_cdrom_get_adr_control(cdrom, seek_track)<<8) | seek_track);
+ cr2 = (seek_track == 0xff) ? 0xffff : ((sega_cdrom_get_adr_control(seek_track)<<8) | seek_track);
cr3 = (get_track_index(cd_fad_seek)<<8) | (cd_fad_seek>>16); //index & 0xff00
cr4 = cd_fad_seek;
}
else
{
cr1 = cur_status | (playtype << 7) | 0x00 | (cdda_repeat_count & 0xf); //options << 4 | repeat & 0xf
- cr2 = (cur_track == 0xff) ? 0xffff : ((sega_cdrom_get_adr_control(cdrom, cur_track)<<8) | (cdrom_get_track(cdrom, cd_curfad-150)+1));
+ cr2 = (cur_track == 0xff) ? 0xffff : ((sega_cdrom_get_adr_control(cur_track)<<8) | (m_cdrom_image->get_track(cd_curfad-150)+1));
cr3 = (get_track_index(cd_curfad)<<8) | (cd_curfad>>16); //index & 0xff00
cr4 = cd_curfad;
}
@@ -525,7 +541,7 @@ void stvcd_device::mpeg_standard_return(uint16_t cur_status)
void stvcd_device::cmd_get_status()
{
- //LOG("%s: Get Status\n", machine().describe_context();
+ //LOGCMD("%s: Get Status\n", machine().describe_context();
hirqreg |= CMOK;
if(status_type == 0)
cr_standard_return(cd_stat);
@@ -542,7 +558,7 @@ void stvcd_device::cmd_get_status()
void stvcd_device::cmd_get_hw_info()
{
- LOG("%s: Get Hardware Info\n", machine().describe_context());
+ LOGCMD("%s: Get Hardware Info\n", machine().describe_context());
hirqreg |= CMOK;
cr1 = cd_stat;
cr2 = 0x0201;
@@ -553,7 +569,7 @@ void stvcd_device::cmd_get_hw_info()
void stvcd_device::cmd_get_toc()
{
- LOG("%s: Get TOC\n", machine().describe_context());
+ LOGCMD("%s: Get TOC\n", machine().describe_context());
cd_readTOC();
cd_stat = CD_STAT_TRANS|CD_STAT_PAUSE;
cr1 = cd_stat;
@@ -571,7 +587,8 @@ void stvcd_device::cmd_get_session_info()
// bios is interested in returns in cr3 and cr4
// cr3 should be data track #
// cr4 must be > 1 and < 100 or bios gets angry.
- LOG("%s: Get Session Info\n", machine().describe_context());
+ LOGCMD("%s: Get Session Info\n", machine().describe_context());
+ // TODO: shouldn't really read from TOC
cd_readTOC();
switch (cr1 & 0xff)
{
@@ -580,7 +597,7 @@ void stvcd_device::cmd_get_session_info()
cr1 = cd_stat;
cr2 = 0;
cr3 = 0x0100 | tocbuf[(101*4)+1];
- cr4 = tocbuf[(101*4)+2]<<8 | tocbuf[(101*4)+3];
+ cr4 = get_u16be(&tocbuf[(101*4)+2]);
break;
case 1: // get total session info / disc start
@@ -592,7 +609,7 @@ void stvcd_device::cmd_get_session_info()
break;
default:
- osd_printf_error("CD: Unknown request to Get Session Info %x\n", cr1 & 0xff);
+ LOGWARN("CD: Unknown request to Get Session Info %x\n", cr1 & 0xff);
cr1 = cd_stat;
cr2 = 0;
cr3 = 0;
@@ -614,7 +631,7 @@ void stvcd_device::cmd_init_cdsystem()
// CR1 & 8 = retry reading mode 2 sectors
// CR1 & 10 = force single-speed
// CR1 & 80 = no change flag (done by Assault Suit Leynos 2)
- LOG("%s: Initialize CD system\n", machine().describe_context());
+ LOGCMD("%s: Initialize CD system\n", machine().describe_context());
//if((cr1 & 0x81) == 0x00) //guess TODO: nope, Choice Cuts doesn't like it, it crashes if you try to skip the FMV otherwise.
{
if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN))
@@ -661,7 +678,7 @@ void stvcd_device::cmd_end_data_transfer()
// end data transfer (TODO: needs to be worked on!)
// returns # of bytes transferred (24 bits) in
// low byte of cr1 (MSB) and cr2 (middle byte, LSB)
- LOG("%s: End data transfer (%d bytes xfer'd)\n", machine().describe_context(), xferdnum);
+ LOGXFER("%s: End data transfer (%d bytes xfer'd)\n", machine().describe_context(), xferdnum);
// clear the "transfer" flag
cd_stat &= ~CD_STAT_TRANS;
@@ -675,7 +692,7 @@ void stvcd_device::cmd_end_data_transfer()
}
else
{
- logerror("No xferdnum error\n");
+ LOGWARN("No xferdnum error\n");
cr1 = (cd_stat) | (0xff); // is this right?
cr2 = 0xffff;
cr3 = 0;
@@ -729,17 +746,17 @@ void stvcd_device::cmd_end_data_transfer()
xferdnum = 0;
hirqreg |= CMOK;
- LOG(" = %04x %04x %04x %04x %04x\n", hirqreg, cr1, cr2, cr3, cr4);
+ LOGXFER("\t%04x %04x %04x %04x %04x\n", hirqreg, cr1, cr2, cr3, cr4);
status_type = 1;
}
void stvcd_device::cmd_play_disc()
{
- // Play Disc. FAD is in lowest 7 bits of cr1 and all of cr2.
+ // Play Disc. FAD is in lowest 7 bits of cr1 and all of cr2.
uint32_t start_pos, end_pos;
uint8_t play_mode;
- LOG("%s: Play Disc\n", machine().describe_context());
+ LOGCMD("%s: Play Disc\n", machine().describe_context());
cd_stat = CD_STAT_PLAY;
play_mode = (cr3 >> 8) & 0x7f;
@@ -754,8 +771,8 @@ void stvcd_device::cmd_play_disc()
if (start_pos != 0xffffff)
cd_curfad = start_pos & 0xfffff;
- logerror("fad mode\n");
- cur_track = cdrom_get_track(cdrom, cd_curfad-150);
+ LOGCMD("\tFAD mode\n");
+ cur_track = m_cdrom_image->get_track(cd_curfad-150);
}
else
{
@@ -763,20 +780,20 @@ void stvcd_device::cmd_play_disc()
if(((start_pos)>>8) != 0)
{
cur_track = (start_pos)>>8;
- cd_fad_seek = cdrom_get_track_start(cdrom, cur_track-1);
+ cd_fad_seek = m_cdrom_image->get_track_start(cur_track-1);
cd_stat = CD_STAT_SEEK;
m_cdda->pause_audio(0);
}
else
{
- /* TODO: Waku Waku 7 sets up track 0, that basically doesn't make any sense. Just skip it for now. */
+ // FIXME: Waku Waku 7 sets up track 0, that basically doesn't make any sense. Just skip it for now.
popmessage("Warning: track mode == 0, contact MAMEdev");
cr_standard_return(cd_stat);
hirqreg |= (CMOK);
return;
}
- printf("track mode %d\n",cur_track);
+ LOGCMD("\ttrack mode %d\n",cur_track);
}
if (end_pos & 0x800000)
@@ -789,7 +806,7 @@ void stvcd_device::cmd_play_disc()
uint8_t end_track;
end_track = (end_pos)>>8;
- fadstoplay = cdrom_get_track_start(cdrom, end_track) - cd_fad_seek;
+ fadstoplay = m_cdrom_image->get_track_start(end_track) - cd_fad_seek;
}
}
else // play until the end of the disc
@@ -805,28 +822,31 @@ void stvcd_device::cmd_play_disc()
else
{
if(end_pos == 0)
- fadstoplay = (cdrom_get_track_start(cdrom, 0xaa)) - cd_curfad;
+ fadstoplay = (m_cdrom_image->get_track_start(0xaa)) - cd_curfad;
else
- fadstoplay = (cdrom_get_track_start(cdrom, (end_pos & 0xff00) >> 8)) - cd_curfad;
+ fadstoplay = (m_cdrom_image->get_track_start((end_pos & 0xff00) >> 8)) - cd_curfad;
}
- logerror("track mode %08x %08x\n",cd_curfad,fadstoplay);
+ LOGCMD("\ttrack mode %08x %08x\n", cd_curfad, fadstoplay);
}
else
{
/* resume from a pause state */
- /* TODO: Galaxy Fight calls 10ff ffff ffff ffff, but then it calls 0x04->0x02->0x06->0x11->0x04->0x02->0x06 command sequence
- (and current implementation nukes start/end FAD addresses at 0x04). I'm sure that this doesn't work like this, but there could
- be countless possible combinations ... */
+ // FIXME: verify implementation with Galaxy Fight
+ // it calls 10ff ffff ffff ffff, but then it follows up with
+ // 0x04->0x02->0x06->0x11->0x04->0x02->0x06 command sequence
+ // (and current implementation nukes start/end FAD addresses at 0x04).
+ // I'm sure that this doesn't work like this, but there could
+ // be countless possible combinations ...
if(fadstoplay == 0)
{
- cd_curfad = cdrom_get_track_start(cdrom, cur_track-1);
- fadstoplay = cdrom_get_track_start(cdrom, cur_track) - cd_curfad;
+ cd_curfad = m_cdrom_image->get_track_start(cur_track-1);
+ fadstoplay = m_cdrom_image->get_track_start(cur_track) - cd_curfad;
}
- logerror("track resume %08x %08x\n",cd_curfad,fadstoplay);
+ LOGCMD("\ttrack resume %08x %08x\n",cd_curfad,fadstoplay);
}
}
- LOG("Play Disc: start %x length %x\n", cd_curfad, fadstoplay);
+ LOGCMD("\tPlay Disc: start %x length %x\n", cd_curfad, fadstoplay);
cr_standard_return(cd_stat);
hirqreg |= (CMOK);
@@ -836,7 +856,7 @@ void stvcd_device::cmd_play_disc()
playtype = 0;
// cdda
- if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, cd_curfad)) == CD_TRACK_AUDIO)
+ if(m_cdrom_image->get_track_type(m_cdrom_image->get_track(cd_curfad)) == cdrom_file::CD_TRACK_AUDIO)
{
m_cdda->pause_audio(0);
//m_cdda->start_audio(cd_curfad, fadstoplay);
@@ -856,8 +876,8 @@ void stvcd_device::cmd_seek_disc()
{
uint32_t temp;
- LOG("%s: Disc seek\n", machine().describe_context());
- //printf("%08x %08x %08x %08x\n",cr1,cr2,cr3,cr4);
+ LOGCMD("%s: Disc seek\n", machine().describe_context());
+ LOGCMD("\t%08x %08x %08x %08x\n",cr1,cr2,cr3,cr4);
if (cr1 & 0x80)
{
temp = (cr1&0xff)<<16; // get FAD to seek to
@@ -873,7 +893,7 @@ void stvcd_device::cmd_seek_disc()
else
{
cd_curfad = ((cr1&0x7f)<<16) | cr2;
- printf("disc seek with params %04x %04x\n",cr1,cr2); //Area 51 sets this up
+ LOGCMD("\tdisc seek with params %04x %04x\n",cr1,cr2); //Area 51 sets this up
}
}
else
@@ -883,7 +903,7 @@ void stvcd_device::cmd_seek_disc()
{
cd_stat = CD_STAT_PAUSE;
cur_track = cr2>>8;
- cd_curfad = cdrom_get_track_start(cdrom, cur_track-1);
+ cd_curfad = m_cdrom_image->get_track_start(cur_track-1);
m_cdda->pause_audio(1);
// (index is cr2 low byte)
}
@@ -943,13 +963,13 @@ void stvcd_device::cmd_get_subcode_q_rw_channel()
xxxx xxxx [11] CRCC
*/
- msf_abs = lba_to_msf_alt( cd_curfad - 150 );
- track = cdrom_get_track( cdrom, cd_curfad );
- msf_rel = lba_to_msf_alt( cd_curfad - 150 - cdrom_get_track_start( cdrom, track ) );
+ msf_abs = cdrom_file::lba_to_msf_alt( cd_curfad - 150 );
+ track = m_cdrom_image->get_track( cd_curfad );
+ msf_rel = cdrom_file::lba_to_msf_alt( cd_curfad - 150 - m_cdrom_image->get_track_start( track ) );
xfertype = XFERTYPE_SUBQ;
xfercount = 0;
- subqbuf[0] = 0x01 | ((cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, track+1)) == CD_TRACK_AUDIO) ? 0x00 : 0x40);
+ subqbuf[0] = 0x01 | ((m_cdrom_image->get_track_type(m_cdrom_image->get_track(track+1)) == cdrom_file::CD_TRACK_AUDIO) ? 0x00 : 0x40);
subqbuf[1] = dec_2_bcd(track+1);
subqbuf[2] = dec_2_bcd(get_track_index(cd_curfad));
subqbuf[3] = dec_2_bcd((msf_rel >> 16) & 0xff);
@@ -992,7 +1012,7 @@ void stvcd_device::cmd_set_cddevice_connection()
// get operation
parm = cr3>>8;
- LOG("%s: Set CD Device Connection filter # %x\n", machine().describe_context(), parm);
+ LOGCMD("%s: Set CD Device Connection filter # %x\n", machine().describe_context(), parm);
cddevicenum = parm;
@@ -1037,12 +1057,12 @@ void stvcd_device::cmd_set_filter_range()
// cr3 hi = filter num.
uint8_t fnum = (cr3>>8)&0xff;
- LOG("%s: Set Filter Range\n", machine().describe_context());
+ LOGCMD("%s: Set Filter Range\n", machine().describe_context());
filters[fnum].fad = ((cr1 & 0xff)<<16) | cr2;
filters[fnum].range = ((cr3 & 0xff)<<16) | cr4;
- printf("%08x %08x %d\n",filters[fnum].fad,filters[fnum].range,fnum);
+ LOGCMD("\t%08x %08x %d\n",filters[fnum].fad,filters[fnum].range,fnum);
hirqreg |= (CMOK|ESEL);
cr_standard_return(cd_stat);
@@ -1060,7 +1080,7 @@ void stvcd_device::cmd_set_filter_subheader_conditions()
// Set Filter Subheader conditions
uint8_t fnum = (cr3>>8)&0xff;
- LOG("%s: Set Filter Subheader conditions %x => chan %x masks %x fid %x vals %x\n", machine().describe_context(), fnum, cr1&0xff, cr2, cr3&0xff, cr4);
+ LOGCMD("%s: Set Filter Subheader conditions %x => chan %x masks %x fid %x vals %x\n", machine().describe_context(), fnum, cr1&0xff, cr2, cr3&0xff, cr4);
filters[fnum].chan = cr1 & 0xff;
filters[fnum].smmask = (cr2>>8)&0xff;
@@ -1080,7 +1100,7 @@ void stvcd_device::cmd_get_filter_subheader_conditions()
// Get Filter Subheader conditions
uint8_t fnum = (cr3>>8)&0xff;
- LOG("%s: Set Filter Subheader conditions %x => chan %x masks %x fid %x vals %x\n", machine().describe_context(), fnum, cr1&0xff, cr2, cr3&0xff, cr4);
+ LOGCMD("%s: Set Filter Subheader conditions %x => chan %x masks %x fid %x vals %x\n", machine().describe_context(), fnum, cr1&0xff, cr2, cr3&0xff, cr4);
cr1 = cd_stat | (filters[fnum].chan & 0xff);
cr2 = (filters[fnum].smmask << 8) | (filters[fnum].cimask & 0xff);
@@ -1107,7 +1127,7 @@ void stvcd_device::cmd_set_filter_mode()
filters[fnum].mode = mode;
}
- LOG("%s: Set Filter Mode filt %x mode %x\n", machine().describe_context(), fnum, mode);
+ LOGCMD("%s: Set Filter Mode filt %x mode %x\n", machine().describe_context(), fnum, mode);
hirqreg |= (CMOK|ESEL);
cr_standard_return(cd_stat);
status_type = 0;
@@ -1130,10 +1150,11 @@ void stvcd_device::cmd_get_filter_mode()
void stvcd_device::cmd_set_filter_connection()
{
// Set Filter Connection
- /* TODO: maybe condition false is cr3 low? */
+ // FIXME: verify usage of cr3 LSB
+ // (false condition?)
uint8_t fnum = (cr3>>8)&0xff;
- LOG("%s:CD: Set Filter Connection %x => mode %x parm %04x\n", machine().describe_context(), fnum, cr1 & 0xf, cr2);
+ LOGCMD("%s: Set Filter Connection %x => mode %x parm %04x\n", machine().describe_context(), fnum, cr1 & 0xf, cr2);
if (cr1 & 1) // set true condition
filters[fnum].condtrue = (cr2>>8)&0xff;
@@ -1151,7 +1172,7 @@ void stvcd_device::cmd_reset_selector()
int i,j;
// Reset Selector
- LOG("%s: Reset Selector\n", machine().describe_context());
+ LOGCMD("%s: Reset Selector\n", machine().describe_context());
if((cr1 & 0xff) == 0x00)
{
@@ -1181,7 +1202,7 @@ void stvcd_device::cmd_reset_selector()
}
/* reset false filter output conditions */
- /* TODO: check these two. */
+ /// TODO: verify default value for these two
if(cr1 & 0x80)
{
for(i=0;i<MAX_FILTERS;i++)
@@ -1254,12 +1275,12 @@ void stvcd_device::cmd_get_buffer_partition_sector_number()
uint32_t bufnum = cr3>>8;
- LOG("%s: Get Sector Number (bufno %d) = %d blocks\n", machine().describe_context(), bufnum, cr4);
+ LOGCMD("%s: Get Sector Number (bufno %d) = %d blocks\n", machine().describe_context(), bufnum, cr4);
cr1 = cd_stat;
cr2 = 0;
cr3 = 0;
if(cr1 & 0xff || cr2 || cr3 & 0xff || cr4)
- printf("Get # sectors used with params %04x %04x %04x %04x\n",cr1,cr2,cr3,cr4);
+ LOGWARN("Get # sectors used with params %04x %04x %04x %04x\n",cr1,cr2,cr3,cr4);
// is the partition empty?
if (partitions[bufnum].size == -1)
@@ -1269,10 +1290,10 @@ void stvcd_device::cmd_get_buffer_partition_sector_number()
else
{
cr4 = partitions[bufnum].numblks;
- //printf("Partition %08x %04x\n",bufnum,cr4);
+ //LOGWARN("Partition %08x %04x\n",bufnum,cr4);
}
- //printf("%04x\n",cr4);
+ //LOGWARN("%04x\n",cr4);
if(cr4 == 0)
hirqreg |= (CMOK);
else
@@ -1287,7 +1308,7 @@ void stvcd_device::cmd_calculate_actual_data_size()
uint32_t sectoffs = cr2;
uint32_t numsect = cr4;
- LOG("%s: Calculate actual size: buf %x offs %x numsect %x\n", machine().describe_context(), bufnum, sectoffs, numsect);
+ LOGCMD("%s: Calculate actual size: buf %x offs %x numsect %x\n", machine().describe_context(), bufnum, sectoffs, numsect);
calcsize = 0;
if (partitions[bufnum].size != -1)
@@ -1311,7 +1332,7 @@ void stvcd_device::cmd_calculate_actual_data_size()
void stvcd_device::cmd_get_actual_data_size()
{
// get actual block size
- LOG("%s: Get actual block size\n", machine().describe_context());
+ LOGCMD("%s: Get actual block size\n", machine().describe_context());
cr1 = cd_stat | ((calcsize>>16)&0xff);
cr2 = (calcsize & 0xffff);
cr3 = 0;
@@ -1330,7 +1351,7 @@ void stvcd_device::cmd_get_sector_information()
{
cr1 |= CD_STAT_REJECT & 0xff00;
hirqreg |= (CMOK|ESEL);
- printf("Get sector info reject\n");
+ LOGWARN("Get sector info reject\n");
}
else
{
@@ -1347,7 +1368,7 @@ void stvcd_device::cmd_get_sector_information()
void stvcd_device::cmd_set_sector_length()
{
// set sector length
- LOG("%s: Set sector length\n", machine().describe_context());
+ LOGCMD("%s: Set sector length\n", machine().describe_context());
switch (cr1 & 0xff)
{
@@ -1392,12 +1413,13 @@ void stvcd_device::cmd_get_sector_data()
uint32_t sectofs = cr2;
uint32_t bufnum = cr3>>8;
- LOG("%s: Get sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum);
+ LOGCMD("%s: Get sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum);
if (bufnum >= MAX_FILTERS)
{
- osd_printf_error("CD: invalid buffer number\n");
- /* TODO: why this is happening? */
+ // TODO: find actual SW that does this
+ // (may conceal a bigger issue)
+ LOGWARN("CD: invalid buffer number\n");
cr_standard_return(CD_STAT_REJECT);
hirqreg |= (CMOK|EHST);
return;
@@ -1405,7 +1427,7 @@ void stvcd_device::cmd_get_sector_data()
if (partitions[bufnum].numblks < sectnum)
{
- osd_printf_error("CD: buffer is not full %08x %08x\n",partitions[bufnum].numblks,sectnum);
+ LOGWARN("CD: buffer is not full %08x %08x\n",partitions[bufnum].numblks,sectnum);
cr_standard_return(CD_STAT_REJECT);
hirqreg |= (CMOK|EHST);
return;
@@ -1435,21 +1457,22 @@ void stvcd_device::cmd_delete_sector_data()
uint32_t bufnum = cr3>>8;
int32_t i;
- LOG("%s: Delete sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum);
+ LOGCMD("%s: Delete sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum);
if (bufnum >= MAX_FILTERS)
{
- osd_printf_error("CD: invalid buffer number\n");
- /* TODO: why this is happening? */
+ // TODO: mustn't happen
+ LOGWARN("CD: invalid buffer number\n");
cr_standard_return(CD_STAT_REJECT);
hirqreg |= (CMOK|EHST);
return;
}
- /* TODO: Phantasy Star 2 throws this one. */
+ // pstarcol PS2 does this
+ // TODO: verify if implementation is correct
if (partitions[bufnum].numblks == 0)
{
- osd_printf_error("CD: buffer is already empty\n");
+ LOGWARN("CD: buffer is already empty\n");
cr_standard_return(CD_STAT_REJECT);
hirqreg |= (CMOK|EHST);
return;
@@ -1459,10 +1482,15 @@ void stvcd_device::cmd_delete_sector_data()
for (i = sectofs; i < (sectofs + sectnum); i++)
{
- partitions[bufnum].size -= partitions[bufnum].blocks[i]->size;
- cd_free_block(partitions[bufnum].blocks[i]);
- partitions[bufnum].blocks[i] = (blockT *)nullptr;
- partitions[bufnum].bnum[i] = 0xff;
+ // pstarcol PS2 tries to delete partial partitions,
+ // need to guard against it (otherwise it would crash after first attract cycle)
+ if (partitions[bufnum].size > 0)
+ {
+ partitions[bufnum].size -= partitions[bufnum].blocks[i]->size;
+ cd_free_block(partitions[bufnum].blocks[i]);
+ partitions[bufnum].blocks[i] = (blockT *)nullptr;
+ partitions[bufnum].bnum[i] = 0xff;
+ }
}
cd_defragblocks(&partitions[bufnum]);
@@ -1488,21 +1516,22 @@ void stvcd_device::cmd_get_and_delete_sector_data()
uint32_t sectofs = cr2;
uint32_t bufnum = cr3>>8;
- LOG("%s: Get and delete sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum);
+ LOGCMD("%s: Get and delete sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum);
if (bufnum >= MAX_FILTERS)
{
- osd_printf_error("CD: invalid buffer number\n");
- /* TODO: why this is happening? */
+ // TODO: mustn't happen
+ LOGWARN("CD: invalid buffer number\n");
cr_standard_return(CD_STAT_REJECT);
hirqreg |= (CMOK|EHST);
return;
}
/* Yoshimoto Mahjong uses the REJECT status to verify when the data is ready. */
+ // TODO: verify again if it's really REJECT or something else
if (partitions[bufnum].numblks < sectnum)
{
- osd_printf_error("CD: buffer is not full %08x %08x\n",partitions[bufnum].numblks,sectnum);
+ LOGWARN("CD: buffer is not full %08x %08x\n",partitions[bufnum].numblks,sectnum);
cr_standard_return(CD_STAT_REJECT);
hirqreg |= (CMOK|EHST);
return;
@@ -1609,7 +1638,7 @@ void stvcd_device::cmd_copy_sector_data()
void stvcd_device::cmd_get_sector_data_copy_or_move_error()
{
// get copy error
- LOG("%s: Get copy error\n", machine().describe_context());
+ LOGCMD("%s: Get copy error\n", machine().describe_context());
logerror("Get copy error\n");
cr1 = cd_stat;
cr2 = 0;
@@ -1623,7 +1652,7 @@ void stvcd_device::cmd_change_directory()
{
uint32_t temp;
// change directory
- LOG("%s: Change Directory\n", machine().describe_context());
+ LOGCMD("%s: Change Directory\n", machine().describe_context());
hirqreg |= (CMOK|EFLS);
temp = (cr3&0xff)<<16;
@@ -1637,7 +1666,7 @@ void stvcd_device::cmd_change_directory()
void stvcd_device::cmd_read_directory()
{
// Read directory entry
- LOG("%s: Read Directory Entry\n", machine().describe_context());
+ LOGCMD("%s: Read Directory Entry\n", machine().describe_context());
// uint32_t read_dir;
// read_dir = ((cr3&0xff)<<16)|cr4;
@@ -1658,13 +1687,13 @@ void stvcd_device::cmd_read_directory()
void stvcd_device::cmd_get_file_scope()
{
// Get file system scope
- LOG("%s: Get file system scope\n", machine().describe_context());
+ LOGCMD("%s: Get file system scope\n", machine().describe_context());
hirqreg |= (CMOK|EFLS);
cr1 = cd_stat;
cr2 = numfiles; // # of files in directory
cr3 = 0x0100; // report directory held
cr4 = firstfile; // first file id
- printf("%04x %04x %04x %04x\n",cr1,cr2,cr3,cr4);
+ LOGWARN("%04x %04x %04x %04x\n",cr1,cr2,cr3,cr4);
status_type = 0;
}
@@ -1673,7 +1702,7 @@ void stvcd_device::cmd_get_target_file_info()
uint32_t temp;
// Get File Info
- LOG("%s: Get File Info\n", machine().describe_context());
+ LOGCMD("%s: Get File Info\n", machine().describe_context());
cd_stat |= CD_STAT_TRANS;
cd_stat &= 0xff00; // clear top byte of return value
playtype = 0;
@@ -1708,22 +1737,21 @@ void stvcd_device::cmd_get_target_file_info()
cr3 = 0;
cr4 = 0;
- printf("%08x %08x\n",curdir[temp].firstfad,curdir[temp].length);
+ // TODO: chaossd and sengblad does this
+ // (iso9660 parsing doesn't read beyond the first sector)
+ if (curdir[temp].firstfad == 0 || curdir[temp].length == 0)
+ throw emu_fatalerror("File ID not found in XFERTYPE_FILEINFO_1");
+// LOGWARN("%08x %08x\n",curdir[temp].firstfad,curdir[temp].length);
// first 4 bytes = FAD
- finfbuf[0] = (curdir[temp].firstfad>>24)&0xff;
- finfbuf[1] = (curdir[temp].firstfad>>16)&0xff;
- finfbuf[2] = (curdir[temp].firstfad>>8)&0xff;
- finfbuf[3] = (curdir[temp].firstfad&0xff);
+ put_u32be(&finfbuf[0], curdir[temp].firstfad);
// second 4 bytes = length of file
- finfbuf[4] = (curdir[temp].length>>24)&0xff;
- finfbuf[5] = (curdir[temp].length>>16)&0xff;
- finfbuf[6] = (curdir[temp].length>>8)&0xff;
- finfbuf[7] = (curdir[temp].length&0xff);
+ put_u32be(&finfbuf[4], curdir[temp].length);
finfbuf[8] = curdir[temp].interleave_gap_size;
finfbuf[9] = curdir[temp].file_unit_size;
finfbuf[10] = temp;
finfbuf[11] = curdir[temp].flags;
+
xfertype = XFERTYPE_FILEINFO_1;
xfercount = 0;
}
@@ -1734,7 +1762,7 @@ void stvcd_device::cmd_get_target_file_info()
void stvcd_device::cmd_read_file()
{
// Read File
- LOG("%s: Read File\n", machine().describe_context());
+ LOGCMD("%s: Read File\n", machine().describe_context());
uint16_t file_offset,file_filter,file_id,file_size;
file_offset = ((cr1 & 0xff)<<8)|(cr2 & 0xff); /* correct? */
@@ -1750,7 +1778,7 @@ void stvcd_device::cmd_read_file()
else
cddevice = (filterT *)nullptr;
- printf("Read file %08x (%08x %08x) %02x %d\n",curdir[file_id].firstfad,cd_curfad,fadstoplay,file_filter,sectlenin);
+ LOGWARN("Read file %08x (%08x %08x) %02x %d\n",curdir[file_id].firstfad,cd_curfad,fadstoplay,file_filter,sectlenin);
cr_standard_return(cd_stat);
@@ -1765,7 +1793,7 @@ void stvcd_device::cmd_read_file()
void stvcd_device::cmd_abort_file()
{
- LOG("%s: Abort File\n", machine().describe_context());
+ LOGCMD("%s: Abort File\n", machine().describe_context());
// bios expects "2bc" mask to work against this
hirqreg |= (CMOK|EFLS);
sectorstore = 0;
@@ -1780,7 +1808,7 @@ void stvcd_device::cmd_abort_file()
void stvcd_device::cmd_check_copy_protection()
{
// appears to be copy protection check. needs only to return OK.
- LOG("%s: Verify copy protection\n", machine().describe_context());
+ LOGCMD("%s: Verify copy protection\n", machine().describe_context());
if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN))
cd_stat = CD_STAT_PAUSE;
@@ -1803,7 +1831,7 @@ void stvcd_device::cmd_check_copy_protection()
void stvcd_device::cmd_get_disc_region()
{
// get disc region
- LOG("%s: Get disc region\n", machine().describe_context());
+ LOGCMD("%s: Get disc region\n", machine().describe_context());
if(cd_stat != CD_STAT_NODISC && cd_stat != CD_STAT_OPEN)
cd_stat = CD_STAT_PAUSE;
cr1 = cd_stat; // necessary to pass
@@ -1889,6 +1917,11 @@ void stvcd_device::cd_exec_command()
1)
logerror("Command exec %04x %04x %04x %04x %04x (stat %04x)\n", hirqreg, cr1, cr2, cr3, cr4, cd_stat);
+ if(!m_cdrom_image->exists() && ((cr1 >> 8) & 0xff) != 0x00) {
+ hirqreg |= (CMOK);
+ return;
+ }
+
switch ((cr1 >> 8) & 0xff)
{
case 0x00: cmd_get_status(); break;
@@ -1977,19 +2010,23 @@ TIMER_DEVICE_CALLBACK_MEMBER( stvcd_device::stv_sh1_sim )
TIMER_DEVICE_CALLBACK_MEMBER( stvcd_device::stv_sector_cb )
{
+ if(!m_cdrom_image->exists())
+ return;
+
//m_sector_timer->reset();
//popmessage("%08x %08x %d %d",cd_curfad,fadstoplay,cmd_pending,cd_speed);
cd_playdata();
- if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, cd_curfad)) == CD_TRACK_AUDIO)
+ if(m_cdrom_image->get_track_type(m_cdrom_image->get_track(cd_curfad)) == cdrom_file::CD_TRACK_AUDIO)
m_sector_timer->adjust(attotime::from_hz(75)); // 75 sectors / second = 150kBytes/second (cdda track ignores cd_speed setting)
else
m_sector_timer->adjust(attotime::from_hz(75*cd_speed)); // 75 / 150 sectors / second = 150 / 300kBytes/second
- /* TODO: doesn't boot if a disk isn't in? */
- /* TODO: Check out when this really happens. (Daytona USA original version definitely wants it to be on).*/
+ // TODO: Saturn refuses to boot with this if a disk isn't in and condition is applied!?
+ // TODO: Check out actual timing of SCDQ acquisition.
+ // (Daytona USA original version definitely wants it to be on).
//if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN))
hirqreg |= SCDQ;
@@ -2045,15 +2082,11 @@ void stvcd_device::device_reset()
for (i = 0; i < MAX_BLOCKS; i++)
{
blocks[i].size = -1;
- memset(&blocks[i].data, 0, CD_MAX_SECTOR_DATA);
+ memset(&blocks[i].data, 0, cdrom_file::MAX_SECTOR_DATA);
}
// open device
- cdrom = m_cdrom_image->get_cdrom_file();
-
- m_cdda->set_cdrom(cdrom);
-
- if (cdrom)
+ if (m_cdrom_image->exists())
{
LOG("Opened CD-ROM successfully, reading root directory\n");
read_new_dir(0xffffff); // read root directory
@@ -2083,7 +2116,7 @@ stvcd_device::blockT *stvcd_device::cd_alloc_block(uint8_t *blknum)
if (freeblocks <= 0)
{
buffull = 1;
- printf("buffull in cd_alloc_block\n");
+ LOGWARN("buffull in cd_alloc_block\n");
}
blocks[i].size = sectlenin;
@@ -2129,7 +2162,7 @@ void stvcd_device::cd_getsectoroffsetnum(uint32_t bufnum, uint32_t *sectoffs, ui
if (*sectoffs == 0xffff)
{
// last sector
- osd_printf_error("CD: Don't know how to handle offset ffff\n");
+ LOGWARN("CD: Don't know how to handle offset ffff\n");
}
else if (*sectnum == 0xffff)
{
@@ -2208,13 +2241,13 @@ void stvcd_device::read_new_dir(uint32_t fileno)
// got primary vol. desc.
if (foundpd)
{
- //dirfad = sect[140] | (sect[141]<<8) | (sect[142]<<16) | (sect[143]<<24);
+ //dirfad = get_u32le(&sect[140]);
//dirfad += 150;
// parse root entry
- curroot.firstfad = sect[158] | (sect[159]<<8) | (sect[160]<<16) | (sect[161]<<24);
+ curroot.firstfad = get_u32le(&sect[158]);
curroot.firstfad += 150;
- curroot.length = sect[166] | (sect[167]<<8) | (sect[168]<<16) | (sect[169]<<24);
+ curroot.length = get_u32le(&sect[166]);
curroot.flags = sect[181];
for (i = 0; i < sect[188]; i++)
{
@@ -2225,7 +2258,7 @@ void stvcd_device::read_new_dir(uint32_t fileno)
// easy to fix, but make sure we *need* to first
if (curroot.length > MAX_DIR_SIZE)
{
- osd_printf_error("ERROR: root directory too big (%d)\n", curroot.length);
+ LOGWARN("ERROR: root directory too big (%d)\n", curroot.length);
}
// done with all that, read the root directory now
@@ -2236,7 +2269,7 @@ void stvcd_device::read_new_dir(uint32_t fileno)
{
if (curdir[fileno].length > MAX_DIR_SIZE)
{
- osd_printf_error("ERROR: new directory too big (%d)!\n", curdir[fileno].length);
+ LOGWARN("ERROR: new directory too big (%d)!\n", curdir[fileno].length);
}
make_dir_current(curdir[fileno].firstfad);
}
@@ -2304,9 +2337,9 @@ void stvcd_device::make_dir_current(uint32_t fad)
curentry->record_size = sect[nextent+0];
curentry->xa_record_size = sect[nextent+1];
- curentry->firstfad = sect[nextent+2] | (sect[nextent+3]<<8) | (sect[nextent+4]<<16) | (sect[nextent+5]<<24);
+ curentry->firstfad = get_u32le(&sect[nextent+2]);
curentry->firstfad += 150;
- curentry->length = sect[nextent+10] | (sect[nextent+11]<<8) | (sect[nextent+12]<<16) | (sect[nextent+13]<<24);
+ curentry->length = get_u32le(&sect[nextent+10]);
curentry->year = sect[nextent+18];
curentry->month = sect[nextent+19];
curentry->day = sect[nextent+20];
@@ -2317,14 +2350,14 @@ void stvcd_device::make_dir_current(uint32_t fad)
curentry->flags = sect[nextent+25];
curentry->file_unit_size = sect[nextent+26];
curentry->interleave_gap_size = sect[nextent+27];
- curentry->volume_sequencer_number = sect[nextent+28] | (sect[nextent+29] << 8);
+ curentry->volume_sequencer_number = get_u16le(&sect[nextent+28]);
for (i = 0; i < sect[nextent+32]; i++)
{
curentry->name[i] = sect[nextent+33+i];
}
curentry->name[i] = '\0'; // terminate
- //printf("%08x %08x %s %d/%d/%d\n",curentry->firstfad,curentry->length,curentry->name,curentry->year,curentry->month,curentry->day);
+ //LOGWARN("%08x %08x %s %d/%d/%d\n",curentry->firstfad,curentry->length,curentry->name,curentry->year,curentry->month,curentry->day);
nextent += sect[nextent];
curentry++;
@@ -2344,11 +2377,6 @@ void stvcd_device::make_dir_current(uint32_t fad)
void stvcd_device::device_stop()
{
curdir.clear();
-
- if (cdrom)
- {
- cdrom = (cdrom_file *)nullptr;
- }
}
void stvcd_device::cd_readTOC(void)
@@ -2358,9 +2386,9 @@ void stvcd_device::cd_readTOC(void)
xfertype = XFERTYPE_TOC;
xfercount = 0;
- if (cdrom)
+ if (m_cdrom_image->exists())
{
- ntrks = cdrom_get_last_track(cdrom);
+ ntrks = m_cdrom_image->get_last_track();
}
else
{
@@ -2381,24 +2409,22 @@ void stvcd_device::cd_readTOC(void)
for (i = 0; i < ntrks; i++)
{
- if (cdrom)
+ if (m_cdrom_image->exists())
{
//tocbuf[tocptr] = sega_cdrom_get_adr_control(cdrom, i);
//HACK: ddsom does not enter ingame with the line above!
- tocbuf[tocptr] = cdrom_get_adr_control(cdrom, i)<<4 | 0x01;
+ tocbuf[tocptr] = m_cdrom_image->get_adr_control(i)<<4 | 0x01;
}
else
{
tocbuf[tocptr] = 0xff;
}
- if (cdrom)
+ if (m_cdrom_image->exists())
{
- fad = cdrom_get_track_start(cdrom, i) + 150;
+ fad = m_cdrom_image->get_track_start(i) + 150;
- tocbuf[tocptr+1] = (fad>>16)&0xff;
- tocbuf[tocptr+2] = (fad>>8)&0xff;
- tocbuf[tocptr+3] = fad&0xff;
+ put_u24be(&tocbuf[tocptr+1], fad);
}
else
{
@@ -2435,12 +2461,10 @@ void stvcd_device::cd_readTOC(void)
tocbuf[tocptr+7] = 0;
// get total disc length (start of lead-out)
- fad = cdrom_get_track_start(cdrom, 0xaa) + 150;
+ fad = m_cdrom_image->get_track_start(0xaa) + 150;
tocbuf[tocptr+8] = tocbuf[0];
- tocbuf[tocptr+9] = (fad>>16)&0xff;
- tocbuf[tocptr+10] = (fad>>8)&0xff;
- tocbuf[tocptr+11] = fad&0xff;
+ put_u24be(&tocbuf[tocptr+9], fad);
}
stvcd_device::partitionT *stvcd_device::cd_filterdata(filterT *flt, int trktype, uint8_t *p_ok)
@@ -2462,20 +2486,20 @@ stvcd_device::partitionT *stvcd_device::cd_filterdata(filterT *flt, int trktype,
{
if ((cd_curfad < flt->fad) || (cd_curfad > (flt->fad + flt->range)))
{
- printf("curfad reject %08x %08x %08x %08x\n",cd_curfad,fadstoplay,flt->fad,flt->fad+flt->range);
+ LOGWARN("curfad reject %08x %08x %08x %08x\n",cd_curfad,fadstoplay,flt->fad,flt->fad+flt->range);
match = 0;
//lastbuf = flt->condfalse;
//flt = &filters[lastbuf];
}
}
- if ((trktype != CD_TRACK_AUDIO) && (curblock.data[15] == 2))
+ if ((trktype != cdrom_file::CD_TRACK_AUDIO) && (curblock.data[15] == 2))
{
if (flt->mode & 1) // file number
{
if (curblock.fnum != flt->fid)
{
- printf("fnum reject\n");
+ LOGWARN("fnum reject\n");
match = 0;
}
}
@@ -2484,7 +2508,7 @@ stvcd_device::partitionT *stvcd_device::cd_filterdata(filterT *flt, int trktype,
{
if (curblock.chan != flt->chan)
{
- printf("channel number reject\n");
+ LOGWARN("channel number reject\n");
match = 0;
}
}
@@ -2493,7 +2517,7 @@ stvcd_device::partitionT *stvcd_device::cd_filterdata(filterT *flt, int trktype,
{
if((curblock.subm & flt->smmask) != flt->smval)
{
- printf("sub mode reject\n");
+ LOGWARN("sub mode reject\n");
match = 0;
}
}
@@ -2502,7 +2526,7 @@ stvcd_device::partitionT *stvcd_device::cd_filterdata(filterT *flt, int trktype,
{
if((curblock.cinf & flt->cimask) != flt->cival)
{
- printf("coding information reject\n");
+ LOGWARN("coding information reject\n");
match = 0;
}
}
@@ -2606,27 +2630,27 @@ stvcd_device::partitionT *stvcd_device::cd_read_filtered_sector(int32_t fad, uin
if ((cddevice != nullptr) && (!buffull))
{
// find out the track's type
- trktype = cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, fad-150));
+ trktype = m_cdrom_image->get_track_type(m_cdrom_image->get_track(fad-150));
// now get a raw 2352 byte sector - if it's mode 1, get mode1_raw
- if ((trktype == CD_TRACK_MODE1) || (trktype == CD_TRACK_MODE1_RAW))
+ if ((trktype == cdrom_file::CD_TRACK_MODE1) || (trktype == cdrom_file::CD_TRACK_MODE1_RAW))
{
- cdrom_read_data(cdrom, fad-150, curblock.data, CD_TRACK_MODE1_RAW);
+ m_cdrom_image->read_data(fad-150, curblock.data, cdrom_file::CD_TRACK_MODE1_RAW);
}
- else if (trktype != CD_TRACK_AUDIO) // if not audio it must be mode 2 so get mode2_raw
+ else if (trktype != cdrom_file::CD_TRACK_AUDIO) // if not audio it must be mode 2 so get mode2_raw
{
- cdrom_read_data(cdrom, fad-150, curblock.data, CD_TRACK_MODE2_RAW);
+ m_cdrom_image->read_data(fad-150, curblock.data, cdrom_file::CD_TRACK_MODE2_RAW);
}
else
{
- cdrom_read_data(cdrom, fad-150, curblock.data, CD_TRACK_AUDIO);
+ m_cdrom_image->read_data(fad-150, curblock.data, cdrom_file::CD_TRACK_AUDIO);
}
curblock.size = sectlenin;
curblock.FAD = fad;
// if track is Mode 2, get the subheader values
- if ((trktype != CD_TRACK_AUDIO) && (curblock.data[15] == 2))
+ if ((trktype != cdrom_file::CD_TRACK_AUDIO) && (curblock.data[15] == 2))
{
curblock.chan = curblock.data[17];
curblock.fnum = curblock.data[16];
@@ -2653,26 +2677,26 @@ void stvcd_device::cd_playdata()
if ((cd_stat & 0x0f00) == CD_STAT_SEEK)
{
int32_t fad_diff;
- //printf("PRE %08x %08x %08x %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad);
+ LOGSEEK("PRE %08x %08x %08x %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad);
fad_diff = (cd_fad_seek - cd_curfad);
/* Zero Divide wants this TODO: timings. */
if(fad_diff > (750*cd_speed))
{
- //printf("PRE FFWD %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad,750*cd_speed);
+ LOGSEEK("PRE FFWD %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad,750*cd_speed);
cd_curfad += (750*cd_speed);
- //printf("POST FFWD %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, 750*cd_speed);
+ LOGSEEK("POST FFWD %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, 750*cd_speed);
}
else if(fad_diff < (-750*cd_speed))
{
- //printf("PRE REW %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, -750*cd_speed);
+ LOGSEEK("PRE REW %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, -750*cd_speed);
cd_curfad -= (750*cd_speed);
- //printf("POST REW %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, -750*cd_speed);
+ LOGSEEK("POST REW %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, -750*cd_speed);
}
else
{
- //printf("Ready\n");
+ LOGSEEK("Ready\n");
cd_curfad = cd_fad_seek;
cd_stat = CD_STAT_PLAY;
}
@@ -2680,24 +2704,29 @@ void stvcd_device::cd_playdata()
return;
}
+ if (LIVE_CD_VIEW)
+ popmessage("%04x %d %d", cd_stat, cd_curfad, fadstoplay);
+
if ((cd_stat & 0x0f00) == CD_STAT_PLAY)
{
if (fadstoplay)
{
- logerror("STVCD: Reading FAD %d\n", cd_curfad);
+ LOGXFER("STVCD: Reading FAD %d\n", cd_curfad);
- if (cdrom)
+ if (m_cdrom_image->exists())
{
uint8_t p_ok;
- if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, cd_curfad)) != CD_TRACK_AUDIO)
+ if(m_cdrom_image->get_track_type(m_cdrom_image->get_track(cd_curfad)) != cdrom_file::CD_TRACK_AUDIO)
{
cd_read_filtered_sector(cd_curfad,&p_ok);
m_cdda->stop_audio(); //stop any pending CD-DA
}
else
{
- p_ok = 1; // TODO
+ // TODO: pinpoint cases when this isn't okay
+ // (out of bounds disc for example)
+ p_ok = 1;
m_cdda->start_audio(cd_curfad, 1);
}
@@ -2728,8 +2757,8 @@ void stvcd_device::cd_playdata()
if(cdda_repeat_count < 0xe)
cdda_repeat_count++;
- cd_curfad = cdrom_get_track_start(cdrom, cur_track-1) + 150;
- fadstoplay = cdrom_get_track_start(cdrom, cur_track) - cd_curfad;
+ cd_curfad = m_cdrom_image->get_track_start(cur_track-1) + 150;
+ fadstoplay = m_cdrom_image->get_track_start(cur_track) - cd_curfad;
}
}
}
@@ -2741,9 +2770,9 @@ void stvcd_device::cd_playdata()
// loads a single sector off the CD, anywhere from FAD 150 on up
void stvcd_device::cd_readblock(uint32_t fad, uint8_t *dat)
{
- if (cdrom)
+ if (m_cdrom_image->exists())
{
- cdrom_read_data(cdrom, fad-150, dat, CD_TRACK_MODE1);
+ m_cdrom_image->read_data(fad-150, dat, cdrom_file::CD_TRACK_MODE1);
}
}
@@ -2755,7 +2784,7 @@ void stvcd_device::set_tray_open()
hirqreg |= DCHG;
cd_stat = CD_STAT_OPEN;
- cdrom = (cdrom_file *)nullptr;
+ // TODO: unmount image
tray_is_closed = 0;
popmessage("Tray Open");
@@ -2768,11 +2797,8 @@ void stvcd_device::set_tray_close()
return;
hirqreg |= DCHG;
- cdrom = m_cdrom_image->get_cdrom_file();
-
- m_cdda->set_cdrom(cdrom);
- if (cdrom)
+ if (m_cdrom_image->exists())
{
LOG("Opened CD-ROM successfully, reading root directory\n");
//read_new_dir(0xffffff); // read root directory
diff --git a/src/devices/machine/stvcd.h b/src/devices/machine/stvcd.h
index 2cef9608be8..98859d9356f 100644
--- a/src/devices/machine/stvcd.h
+++ b/src/devices/machine/stvcd.h
@@ -7,7 +7,7 @@
#pragma once
#include "cdrom.h"
-#include "imagedev/chd_cd.h"
+#include "imagedev/cdromimg.h"
#include "machine/timer.h"
#include "sound/cdda.h"
@@ -82,7 +82,7 @@ private:
{
int32_t size; // size of block
int32_t FAD; // FAD on disc
- uint8_t data[CD_MAX_SECTOR_DATA];
+ uint8_t data[cdrom_file::MAX_SECTOR_DATA];
uint8_t chan; // channel
uint8_t fnum; // file number
uint8_t subm; // subchannel mode
@@ -119,7 +119,7 @@ private:
};
int get_track_index(uint32_t fad);
- int sega_cdrom_get_adr_control(cdrom_file *file, int track);
+ int sega_cdrom_get_adr_control(int track);
void cr_standard_return(uint16_t cur_status);
void mpeg_standard_return(uint16_t cur_status);
void cd_free_block(blockT *blktofree);
@@ -139,8 +139,6 @@ private:
partitionT *cd_filterdata(filterT *flt, int trktype, uint8_t *p_ok);
partitionT *cd_read_filtered_sector(int32_t fad, uint8_t *p_ok);
- cdrom_file *cdrom;// = (cdrom_file *)nullptr;
-
// local variables
partitionT partitions[MAX_FILTERS];
partitionT *transpart;
diff --git a/src/devices/machine/sun4c_mmu.cpp b/src/devices/machine/sun4c_mmu.cpp
index fce37a92824..038a47e7158 100644
--- a/src/devices/machine/sun4c_mmu.cpp
+++ b/src/devices/machine/sun4c_mmu.cpp
@@ -12,44 +12,41 @@
#include "cpu/sparc/sparc.h"
#include "debug/debugcon.h"
-#include "debug/debugcmd.h"
#include "debugger.h"
DEFINE_DEVICE_TYPE(SUN4_MMU, sun4_mmu_device, "sun4_mmu", "Sun 4 MMU")
DEFINE_DEVICE_TYPE(SUN4C_MMU, sun4c_mmu_device, "sun4c_mmu", "Sun 4c MMU")
-#define LOG_PAGE_MAP (1U << 0)
-#define LOG_SEGMENT_MAP (1U << 1)
-#define LOG_INVALID_PTE (1U << 2)
-#define LOG_SYSTEM (1U << 3)
-#define LOG_CONTEXT (1U << 4)
-#define LOG_SYSTEM_ENABLE (1U << 5)
-#define LOG_BUSERROR (1U << 6)
-#define LOG_CACHE_TAGS (1U << 7)
-#define LOG_CACHE_DATA (1U << 8)
-#define LOG_UNKNOWN_SYSTEM (1U << 9)
-#define LOG_UNKNOWN_SEGMENT (1U << 10)
-#define LOG_TYPE0_TIMEOUT (1U << 11)
-#define LOG_TYPE1_TIMEOUT (1U << 12)
-#define LOG_UNKNOWN_SPACE (1U << 13)
-#define LOG_WRITE_PROTECT (1U << 14)
-#define LOG_READ_PROTECT (1U << 15)
-#define LOG_PARITY (1U << 16)
-#define LOG_ALL_ASI (1U << 17) // WARNING: Heavy!
-#define LOG_UNKNOWN_ASI (1U << 18)
-#define LOG_SEGMENT_FLUSH (1U << 19)
-#define LOG_PAGE_FLUSH (1U << 20)
-#define LOG_CONTEXT_FLUSH (1U << 21)
-#define LOG_CACHE_FILLS (1U << 22)
-#define LOG_PAGE_ENTRIES (1U << 23)
-
-#if SUN4CMMU_LOG_MEM_ACCESSES
-static FILE* s_mem_log = nullptr;
-#endif
-
-#define VERBOSE (0)
+#define LOG_PAGE_MAP (1U << 1)
+#define LOG_SEGMENT_MAP (1U << 2)
+#define LOG_CONTEXT (1U << 3)
+#define LOG_SYSTEM_ENABLE (1U << 4)
+#define LOG_UART (1U << 5)
+#define LOG_PARITY (1U << 6)
+#define LOG_SEGMENT_FLUSH (1U << 7)
+#define LOG_PAGE_FLUSH (1U << 8)
+#define LOG_CONTEXT_FLUSH (1U << 9)
+#define LOG_ALL_FLUSH (1U << 10)
+#define LOG_CACHE_TAGS (1U << 11)
+#define LOG_CACHE_DATA (1U << 12)
+#define LOG_INVALID_PTE (1U << 13)
+#define LOG_BUSERROR (1U << 14)
+#define LOG_TYPE0_TIMEOUT (1U << 15)
+#define LOG_TYPE1_TIMEOUT (1U << 16)
+#define LOG_UNKNOWN_SPACE (1U << 17)
+#define LOG_UNKNOWN_SEGMENT (1U << 18)
+#define LOG_WRITE_PROTECT (1U << 19)
+#define LOG_MMU (LOG_PAGE_MAP | LOG_SEGMENT_MAP | LOG_CONTEXT)
+#define LOG_MISC_HW (LOG_SYSTEM_ENABLE | LOG_UART | LOG_PARITY)
+#define LOG_FLUSHES (LOG_SEGMENT_FLUSH | LOG_PAGE_FLUSH | LOG_CONTEXT_FLUSH | LOG_ALL_FLUSH)
+#define LOG_CACHE (LOG_CACHE_TAGS | LOG_CACHE_DATA | LOG_FLUSHES)
+#define LOG_ERRORS (LOG_INVALID_PTE | LOG_BUSERROR | LOG_TYPE0_TIMEOUT | LOG_TIME1_TIMEOUT | LOG_UNKNOWN_SPACE | LOG_UNKNOWN_SEGMENT | LOG_WRITE_PROTECT)
+
+//#define VERBOSE (LOG_MMU | LOG_MISC_HW | LOG_FLUSHES | LOG_CACHE | LOG_ERRORS)
#include "logmacro.h"
+#define PRINT_UART_DATA (0)
+
sun4_mmu_base_device::sun4_mmu_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, m_cpu(*this, finder_base::DUMMY_TAG)
@@ -57,7 +54,7 @@ sun4_mmu_base_device::sun4_mmu_base_device(const machine_config &mconfig, device
, m_rom(*this, finder_base::DUMMY_TAG)
, m_scc(*this, finder_base::DUMMY_TAG)
, m_host(nullptr)
- , m_type1_r(*this)
+ , m_type1_r(*this, 0xffffffff)
, m_type1_w(*this)
, m_rom_ptr(nullptr)
, m_ram_ptr(nullptr)
@@ -82,25 +79,10 @@ sun4c_mmu_device::sun4c_mmu_device(const machine_config &mconfig, const char *ta
{
}
-void sun4_mmu_base_device::device_stop()
-{
-#if SUN4CMMU_LOG_MEM_ACCESSES
- fclose(s_mem_log);
-#endif
-}
-
void sun4_mmu_base_device::device_start()
{
-#if SUN4CMMU_LOG_MEM_ACCESSES
- s_mem_log = fopen("sun4c_mem.bin", "wb");
- m_fpos = 0;
-#endif
-
- m_type1_r.resolve_safe(0xffffffff);
- m_type1_w.resolve_safe();
-
// allocate timer for system reset
- m_reset_timer = timer_alloc(TIMER_RESET);
+ m_reset_timer = timer_alloc(FUNC(sun4_mmu_base_device::reset_off_tick), this);
m_reset_timer->adjust(attotime::never);
m_segmap = std::make_unique<std::unique_ptr<uint8_t[]>[]>(16);
@@ -151,31 +133,12 @@ void sun4_mmu_base_device::device_start()
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
{
using namespace std::placeholders;
- machine().debugger().console().register_command("l2p", CMDFLAG_NONE, 0, 1, 1, std::bind(&sun4_mmu_base_device::l2p_command, this, _1, _2));
- }
-
- m_cache_word_size = m_cache_line_size >> 2;
- m_cache_tag_shift = 0;
- while ((m_cache_word_size & (1 << m_cache_tag_shift)) == 0)
- {
- m_cache_tag_shift++;
+ machine().debugger().console().register_command("l2p", CMDFLAG_NONE, 1, 1, std::bind(&sun4_mmu_base_device::l2p_command, this, _1));
}
- m_cache_vaddr_shift = 14;
- m_cache_tag_id_mask = 0xfffc;
- m_cache_tag_id_shift = 12;//13 + (m_cache_tag_shift - 2);
- m_cache_tag_mask = m_cache_mask >> m_cache_tag_shift;
-
- printf("m_cache_tag_shift %d\n", m_cache_tag_shift);
- printf("m_page_mask %08x\n", m_page_mask);
- printf("m_seg_entry_shift %08x\n", m_seg_entry_shift);
- printf("m_seg_entry_mask %08x\n", m_seg_entry_mask);
- printf("m_page_entry_mask %08x\n", m_page_entry_mask);
- printf("m_cache_mask %08x\n", m_cache_mask);
}
void sun4_mmu_base_device::device_reset()
{
- m_log_mem = false;
m_rom_ptr = (uint32_t *)m_rom->base();
m_ram_ptr = (uint32_t *)m_ram->pointer();
m_ram_size = m_ram->size();
@@ -210,8 +173,12 @@ void sun4_mmu_base_device::device_reset()
m_curr_segmap_masked = &m_segmap_masked[0][0];
m_system_enable = 0;
m_fetch_bootrom = true;
+ m_type1_offset = 0;
+ m_parity_err_reg = 0;
+ m_memory_err_reg = 0;
+ m_parity_err = 0;
- memset(m_buserr, 0, sizeof(uint32_t) * 16);
+ memset(m_buserr, 0, sizeof(uint32_t) * 4);
for (int i = 0; i < 16; i++)
{
memset(&m_segmap[i][0], 0, 4096);
@@ -221,16 +188,13 @@ void sun4_mmu_base_device::device_reset()
memset(&m_cachedata[0], 0, sizeof(uint32_t) * 16384);
}
-void sun4_mmu_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(sun4_mmu_base_device::reset_off_tick)
{
- if (id == TIMER_RESET)
- {
- m_reset_timer->adjust(attotime::never);
- m_cpu->set_input_line(SPARC_RESET, CLEAR_LINE);
- }
+ m_reset_timer->adjust(attotime::never);
+ m_cpu->set_input_line(SPARC_RESET, CLEAR_LINE);
}
-uint32_t sun4_mmu_base_device::fetch_insn(const bool supervisor, uint32_t offset)
+uint32_t sun4_mmu_base_device::fetch_insn(const bool supervisor, const uint32_t offset)
{
if (supervisor)
return insn_data_r<SUPER_INSN>(offset, 0xffffffff);
@@ -238,199 +202,58 @@ uint32_t sun4_mmu_base_device::fetch_insn(const bool supervisor, uint32_t offset
return insn_data_r<USER_INSN>(offset, 0xffffffff);
}
-void sun4_mmu_base_device::hw_segment_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
-{
- for (uint32_t i = 0x0000; i < (0x1000 >> (m_cache_tag_shift + 2)); i++)
- {
- segment_flush_w(offset | (i << m_cache_tag_shift), data, mem_mask);
- }
-}
-
-void sun4_mmu_base_device::hw_page_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::segment_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- for (uint32_t i = 0x0000; i < (0x1000 >> (m_cache_tag_shift + 2)); i++)
- {
- page_flush_w(offset | (i << m_cache_tag_shift), data, mem_mask);
- }
+ // Do nothing for now
+ LOGMASKED(LOG_SEGMENT_FLUSH, "%s: segment_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-void sun4_mmu_base_device::hw_context_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::page_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- for (uint32_t i = 0x0000; i < (0x1000 >> (m_cache_tag_shift + 2)); i++)
- {
- context_flush_w(offset | (i << m_cache_tag_shift), data, mem_mask);
- }
+ // Do nothing for now
+ LOGMASKED(LOG_PAGE_FLUSH, "%s: page_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-void sun4_mmu_base_device::hw_flush_all_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::context_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- for (uint32_t i = 0x0000; i < (0x1000 >> (m_cache_tag_shift + 2)); i++)
- {
- const uint32_t vaddr = offset | (i << m_cache_tag_shift);
- const uint32_t tag_addr = vaddr_to_cache_line(vaddr);
- m_cachetags[tag_addr] &= ~(1 << 19);
- }
+ // Do nothing for now
+ LOGMASKED(LOG_CONTEXT_FLUSH, "%s: context_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-uint32_t sun4_mmu_base_device::parity_r(uint32_t offset, uint32_t mem_mask)
+void sun4_mmu_base_device::hw_segment_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- if (offset == 0)
- {
- const uint32_t data = m_parity_err_reg;
- LOGMASKED(LOG_PARITY, "%s: parity_err_reg read: %08x & %08x\n", machine().describe_context(), m_parity_err_reg, mem_mask);
- m_parity_err_reg &= ~0xcf;
- return data;
- }
- else if (offset == 1)
- {
- LOGMASKED(LOG_PARITY, "%s: memory_err_reg read: %08x & %08x\n", machine().describe_context(), m_memory_err_reg, mem_mask);
- return m_memory_err_reg;
- }
- return 0;
+ // Do nothing for now
+ LOGMASKED(LOG_SEGMENT_FLUSH, "%s: segment_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-void sun4_mmu_base_device::parity_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
-{
- if (offset == 0)
- {
- LOGMASKED(LOG_PARITY, "%s: parity_err_reg write: %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_parity_err_reg);
- }
- else
- {
- LOGMASKED(LOG_PARITY, "%s: memory_err_reg write: %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_memory_err_reg);
- }
-}
-
-void sun4_mmu_base_device::segment_flush_w(uint32_t vaddr, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::hw_page_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_SEGMENT_FLUSH, "%s: segment_flush_w %08x\n", machine().describe_context(), vaddr);
- const uint32_t tag_addr = vaddr_to_cache_line(vaddr);
- const uint32_t tag = m_cachetags[tag_addr];
- if ((tag & (1 << 19)) != 0 && ((tag >> 22) & m_ctx_mask) == m_context_masked)
- {
- // Unshifted
- // 00SS|SSSS|SSSS|SSPP|PPPP|BBBB|BBBB|BBBB
- // 00TT|TTTT|TTTT|TTTT|LLLL|LLLL|LLLL|bbbb
- //
- // 00ss|ssss|ssss|ss--|LLLL|LLLL|LLLL|----
-
- // Shifted
- // SSSS|SSSS|SSSS|PPPP|PPBB|BBBB|BBBB
- // TTTT|TTTT|TTTT|TTLL|LLLL|LLLL|LLww
- //
- // ssss|ssss|ssss|--LL|LLLL|LLLL|LL--
-
- const uint32_t tag_id = (tag >> 4) & m_cache_tag_mask;
- if (tag_id == ((vaddr >> 16) & 0xfff))
- {
- m_cachetags[tag_addr] &= ~(1 << 19);
- LOGMASKED(LOG_SEGMENT_FLUSH, "flushing line with tag %08x from vaddr %08x\n", tag, vaddr << 2);
- }
- }
+ // Do nothing for now
+ LOGMASKED(LOG_PAGE_FLUSH, "%s: page_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-void sun4_mmu_base_device::context_flush_w(uint32_t vaddr, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::hw_context_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_CONTEXT_FLUSH, "%s: context_flush_w %08x\n", machine().describe_context(), vaddr << 2);
- const uint32_t tag_addr = vaddr_to_cache_line(vaddr);
- const uint32_t tag = m_cachetags[tag_addr];
- if ((tag & (1 << 19)) != 0)
- {
- LOGMASKED(LOG_CONTEXT_FLUSH, "tag is valid: %08x (%d vs. %d)\n", tag, ((tag >> 22) & m_ctx_mask), m_context_masked);
- if (((tag >> 22) & m_ctx_mask) == m_context_masked && !BIT(tag, 20))
- {
- const uint32_t tag_id = (tag >> 2) & m_cache_tag_mask;
- if (tag_id == ((vaddr >> 14) & 0xfff))
- {
- LOGMASKED(LOG_CONTEXT_FLUSH, "flushing line with tag %08x from vaddr %08x\n", tag, vaddr << 2);
- m_cachetags[tag_addr] &= ~(1 << 19);
- }
- }
- }
+ // Do nothing for now
+ LOGMASKED(LOG_CONTEXT_FLUSH, "%s: context_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-void sun4_mmu_base_device::page_flush_w(uint32_t vaddr, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::hw_flush_all_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_PAGE_FLUSH, "%s: page_flush_w %08x\n", machine().describe_context(), vaddr << 2);
- const uint32_t tag_addr = vaddr_to_cache_line(vaddr);
- const uint32_t tag = m_cachetags[tag_addr];
- if ((tag & (1 << 19)) != 0 && ((tag >> 22) & m_ctx_mask) == m_context_masked)
- {
- // Unshifted
- // 00SS|SSSS|SSSS|SSPP|PPPP|BBBB|BBBB|BBBB
- // 00TT|TTTT|TTTT|TTTT|LLLL|LLLL|LLLL|bbbb
- //
- // 00pp|pppp|pppp|pppp|pppp|LLLL|LLLL|---- ff1dc000
- // 1111|1111|0001|1101|1100|0000|0000|---- 0000fc70
-
- // Shifted
- // SSSS|SSSS|SSSS|PPPP|PPBB|BBBB|BBBB
- // TTTT|TTTT|TTTT|TTLL|LLLL|LLLL|LLww
- //
- // pppp|pppp|pppp|pppp|ppLL|LLLL|LL--
-
- const uint32_t tag_id = tag & m_cache_tag_id_mask;
- LOGMASKED(LOG_PAGE_FLUSH, "tag is valid: %08x (%04x vs. %04x)\n", tag, tag_id, (vaddr >> (m_cache_tag_id_shift + 2)) & 0x3fff);
- if (tag_id == ((vaddr >> m_cache_tag_id_shift) & 0xfffc))
- {
- m_cachetags[tag_addr] &= ~(1 << 19);
- LOGMASKED(LOG_PAGE_FLUSH, "flushing line with tag %08x from vaddr %08x\n", tag, vaddr << 2);
- }
- }
+ // Do nothing for now
+ LOGMASKED(LOG_ALL_FLUSH, "%s: hw_flush_all_w %08x = %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
uint32_t sun4_mmu_base_device::context_reg_r(uint32_t offset, uint32_t mem_mask)
{
- if (mem_mask == 0x00ff0000)
- {
- LOGMASKED(LOG_CONTEXT, "sun4c_mmu: read context %08x & %08x = %08x\n", offset << 2, mem_mask, m_context<<16);
- return m_context<<16;
- }
- LOGMASKED(LOG_CONTEXT, "sun4c_mmu: read context %08x & %08x = %08x\n", offset << 2, mem_mask, m_context<<24);
- return m_context<<24;
-}
-
-uint32_t sun4_mmu_base_device::system_enable_r(uint32_t offset, uint32_t mem_mask)
-{
- LOGMASKED(LOG_SYSTEM_ENABLE, "sun4c_mmu: read system enable %08x & %08x = %08x\n", offset << 2, mem_mask, m_system_enable<<24);
- return m_system_enable<<24;
-}
-
-uint32_t sun4_mmu_base_device::bus_error_r(uint32_t offset, uint32_t mem_mask)
-{
- const uint32_t ret = m_buserr[offset & 0xf];
- LOGMASKED(LOG_BUSERROR, "sun4c_mmu: read buserror %08x & %08x = %08x, PC=%x\n", 0x60000000 | (offset << 2), mem_mask, ret, m_cpu->pc());
- m_buserr[offset & 0xf] = 0; // clear on reading
- return ret;
-}
-
-uint32_t sun4_mmu_base_device::cache_tag_r(uint32_t offset, uint32_t mem_mask)
-{
- LOGMASKED(LOG_CACHE_TAGS, "%s: sun4c_mmu: read dcache tags @ %x, %08x\n", machine().describe_context(), offset << 2, m_cachetags[vaddr_to_cache_line(offset)]);
- return m_cachetags[vaddr_to_cache_line(offset)];
-}
-
-uint32_t sun4_mmu_base_device::cache_data_r(uint32_t offset, uint32_t mem_mask)
-{
- LOGMASKED(LOG_CACHE_DATA, "%s: sun4c_mmu: read dcache data @ %x, PC = %x\n", machine().describe_context(), offset << 2, m_cpu->pc());
- return m_cachedata[offset & 0x3fff];
-}
-
-uint32_t sun4_mmu_base_device::uart_r(uint32_t offset, uint32_t mem_mask)
-{
- switch (offset & 3)
- {
- case 0: if (mem_mask == 0xff000000) return m_scc->cb_r(0)<<24; else return m_scc->db_r(0)<<8; break;
- case 1: if (mem_mask == 0xff000000) return m_scc->ca_r(0)<<24; else return m_scc->da_r(0)<<8; break;
- }
- return 0xffffffff;
+ const uint32_t data = m_context << (mem_mask == 0x00ff0000 ? 16 : 24);
+ LOGMASKED(LOG_CONTEXT, "%s: context_reg_r %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ return data;
}
void sun4_mmu_base_device::context_reg_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_CONTEXT, "write context = %08x & %08x\n", data, mem_mask);
+ LOGMASKED(LOG_CONTEXT, "%s: context_reg_w: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
m_context = data >> 24;
m_context_masked = m_context & m_ctx_mask;
m_cache_context = m_context & m_ctx_mask;
@@ -438,9 +261,16 @@ void sun4_mmu_base_device::context_reg_w(uint32_t offset, uint32_t data, uint32_
m_curr_segmap_masked = &m_segmap_masked[m_context_masked][0];
}
+uint32_t sun4_mmu_base_device::system_enable_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_system_enable << 24;
+ LOGMASKED(LOG_SYSTEM_ENABLE, "%s: system_enable_r %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ return data;
+}
+
void sun4_mmu_base_device::system_enable_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_SYSTEM_ENABLE, "write system enable = %08x & %08x\n", data, mem_mask);
+ LOGMASKED(LOG_SYSTEM_ENABLE, "%s: system_enable_w: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
m_system_enable = data >> 24;
m_fetch_bootrom = !(m_system_enable & ENA_NOTBOOT);
@@ -457,64 +287,132 @@ void sun4_mmu_base_device::system_enable_w(uint32_t offset, uint32_t data, uint3
}
}
+uint32_t sun4_mmu_base_device::bus_error_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_buserr[offset & 0xf];
+ LOGMASKED(LOG_BUSERROR, "%s: bus_error_r %08x & %08x: %08x\n", machine().describe_context(), 0x60000000 | (offset << 2), mem_mask, data);
+ m_buserr[offset & 0xf] = 0; // clear on reading
+ return data;
+}
+
void sun4_mmu_base_device::bus_error_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
const uint32_t masked_offset = offset & 0xf;
- LOGMASKED(LOG_BUSERROR, "write bus error %08x = %08x & %08x\n", offset << 2, data, mem_mask);
+ LOGMASKED(LOG_BUSERROR, "%s: bus_error_w: %08x = %08x & %08x\n", machine().describe_context(), 0x60000000 | (offset << 2), data, mem_mask);
if (masked_offset == 0)
m_buserr[0] = (data & 0x000000ff) | 0x00008000;
- else
- m_buserr[masked_offset] = data;
+ else if (masked_offset == 1)
+ m_buserr[1] = data;
+ else if (masked_offset == 2)
+ m_buserr[2] = data & 0x000000b0;
+ else if (masked_offset == 3)
+ m_buserr[3] = (data & 0x3fffffff) | ((data & 0x20000000) << 1) | ((data & 0x20000000) << 2);
+}
+
+uint32_t sun4_mmu_base_device::cache_tag_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_cachetags[offset & m_cache_mask];
+ LOGMASKED(LOG_CACHE_TAGS, "%s: cache_tag_r %08x & %08x: %08x\n", machine().describe_context(), offset, mem_mask, data);
+ return data;
}
void sun4_mmu_base_device::cache_tag_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_CACHE_TAGS, "%s: write dcache tags %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
- m_cachetags[vaddr_to_cache_line(offset)] = data & 0x03f8fffc;
+ LOGMASKED(LOG_CACHE_TAGS, "%s: cache_tag_w: %08x = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_cachetags[offset & m_cache_mask] = data & 0x03f8fffc;
+}
+
+uint32_t sun4_mmu_base_device::cache_data_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_cachedata[offset & m_cache_mask];
+ LOGMASKED(LOG_CACHE_DATA, "%s: cache_data_r %08x & %08x: %08x\n", machine().describe_context(), offset, mem_mask, data);
+ return data;
}
void sun4_mmu_base_device::cache_data_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_CACHE_DATA, "write cache data %08x = %08x & %08x\n", offset << 2, data, mem_mask);
- COMBINE_DATA(&m_cachedata[offset & 0x3fff]);
- m_cachetags[vaddr_to_cache_line(offset)] &= ~(1 << 19);
+ LOGMASKED(LOG_CACHE_DATA, "%s: cache_data_w: %08x = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_cachedata[offset & m_cache_mask] = data | (1 << 19);
+}
+
+uint32_t sun4_mmu_base_device::uart_r(uint32_t offset, uint32_t mem_mask)
+{
+ uint32_t data = 0xffffffff;
+ switch (offset & 3)
+ {
+ case 0:
+ if (mem_mask == 0xff000000)
+ data = m_scc->cb_r(0) << 24;
+ else
+ data = m_scc->db_r(0) << 8;
+ break;
+ case 1:
+ if (mem_mask == 0xff000000)
+ data = m_scc->ca_r(0) << 24;
+ else
+ data = m_scc->da_r(0) << 8;
+ break;
+ }
+ LOGMASKED(LOG_UART, "%s: uart_r %08x & %08x: %08x\n", machine().describe_context(), offset, mem_mask, data);
+ return data;
}
void sun4_mmu_base_device::uart_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
+ LOGMASKED(LOG_UART, "%s: uart_w: %08x = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
switch (offset & 3)
{
- case 0: if (mem_mask == 0xff000000) m_scc->cb_w(0, data>>24); else m_scc->db_w(0, data>>8); break;
- case 1: if (mem_mask == 0xff000000) m_scc->ca_w(0, data>>24); else { m_scc->da_w(0, data>>8); logerror("%c\n", data>>8); printf("%c", data>>8); } break;
+ case 0:
+ if (mem_mask == 0xff000000)
+ m_scc->cb_w(0, data >> 24);
+ else
+ m_scc->db_w(0, data >> 8);
+ return;
+ case 1:
+ if (mem_mask == 0xff000000)
+ m_scc->ca_w(0, data >> 24);
+ else
+ {
+ m_scc->da_w(0, data >> 8);
+ if (PRINT_UART_DATA)
+ {
+ printf("%c", data >> 8);
+ }
+ }
+ return;
}
}
uint32_t sun4_mmu_base_device::segment_map_r(uint32_t offset, uint32_t mem_mask)
{
- uint32_t ret = 0;
+ uint32_t data = 0;
if (mem_mask == 0xffff0000)
- ret = m_curr_segmap[(offset>>16) & 0xfff]<<16;
+ data = m_curr_segmap[(offset >> 16) & 0xfff] << 16;
else if (mem_mask == 0xff000000)
- ret = m_curr_segmap[(offset>>16) & 0xfff]<<24;
+ data = m_curr_segmap[(offset >> 16) & 0xfff] << 24;
else if (mem_mask == 0xffffffff)
- ret = m_curr_segmap[(offset>>16) & 0xfff];
+ data = m_curr_segmap[(offset >> 16) & 0xfff];
else
- LOGMASKED(LOG_UNKNOWN_SEGMENT, "read segment map w/ unknown mask %08x & %08x\n", offset << 2, mem_mask);
- LOGMASKED(LOG_SEGMENT_MAP, "read segment map %08x & %08x = %08x\n", offset << 2, mem_mask, ret);
- return ret;
+ LOGMASKED(LOG_UNKNOWN_SEGMENT, "%s: segment_map_r: %08x & %08x (unknown mask)\n", machine().describe_context(), offset << 2, mem_mask);
+ LOGMASKED(LOG_SEGMENT_MAP, "%s: segment_map_r: %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ return data;
}
void sun4_mmu_base_device::segment_map_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_SEGMENT_MAP, "write segment map %08x = %08x & %08x\n", offset << 2, data, mem_mask);
+ LOGMASKED(LOG_SEGMENT_MAP, "%s: segment_map_w: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
uint8_t segdata = 0;
- if (mem_mask == 0xffff0000) segdata = (data >> 16) & 0xff;
- else if (mem_mask == 0xff000000) segdata = (data >> 24) & 0xff;
- else if (mem_mask == 0xffffffff) segdata = data & 0xff;
- else LOGMASKED(LOG_UNKNOWN_SEGMENT, "write segment map w/ unknown mask %08x = %08x & %08x, PC=%08x\n", offset << 2, data, mem_mask, m_cpu->pc());
+ if (mem_mask == 0xffff0000)
+ segdata = (data >> 16) & 0xff;
+ else if (mem_mask == 0xff000000)
+ segdata = (data >> 24) & 0xff;
+ else if (mem_mask == 0xffffffff)
+ segdata = data & 0xff;
+ else
+ LOGMASKED(LOG_UNKNOWN_SEGMENT, "%s: segment_map_w: %08x = %08x & %08x (unknown mask)\n", machine().describe_context(), offset << 2, data, mem_mask);
- const uint32_t seg = (offset>>16) & 0xfff;
+ const uint32_t seg = (offset >> 16) & 0xfff;
m_curr_segmap[seg] = segdata;
m_curr_segmap_masked[seg] = (segdata & m_pmeg_mask) << 6;
}
@@ -522,30 +420,30 @@ void sun4_mmu_base_device::segment_map_w(uint32_t offset, uint32_t data, uint32_
uint32_t sun4_mmu_base_device::page_map_r(uint32_t offset, uint32_t mem_mask)
{
const uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
- const uint32_t ret = page_entry_to_uint(page);
- LOGMASKED(LOG_PAGE_MAP, "read page map %08x & %08x (%x) = %08x\n", offset << 2, mem_mask, page, ret);
- return ret;
+ const uint32_t data = page_entry_to_uint(page);
+ LOGMASKED(LOG_PAGE_MAP, "%s: page_map_r: %08x (%x) & %08x: %08x\n", machine().describe_context(), offset << 2, page, mem_mask, data);
+ return data;
}
void sun4_mmu_base_device::page_map_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
- LOGMASKED(LOG_PAGE_MAP, "write page map %08x (%x) = %08x & %08x\n", offset << 2, page, data, mem_mask);
+ const uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
+ LOGMASKED(LOG_PAGE_MAP, "%s: page_map_w: %08x (%x) = %08x & %08x\n", machine().describe_context(), offset << 2, page, data, mem_mask);
merge_page_entry(page, data, mem_mask);
m_page_valid[page] = m_pagemap[page].valid;
}
-void sun4_mmu_base_device::type0_timeout_r(uint32_t offset)
+void sun4_mmu_base_device::type0_timeout_r(const uint32_t offset)
{
- LOGMASKED(LOG_TYPE0_TIMEOUT, "type 0 read timeout %08x, PC=%08x\n", offset << 2, m_cpu->pc());
+ LOGMASKED(LOG_TYPE0_TIMEOUT, "%s: type0_timeout_r (%08x)\n", machine().describe_context(), offset << 2);
m_buserr[0] = 0x20; // read timeout
m_buserr[1] = 0x04000000 + (offset << 2);
m_host->set_mae();
}
-void sun4_mmu_base_device::type0_timeout_w(uint32_t offset)
+void sun4_mmu_base_device::type0_timeout_w(const uint32_t offset)
{
- LOGMASKED(LOG_TYPE0_TIMEOUT, "type 0 write timeout %08x, PC=%08x\n", offset << 2, m_cpu->pc());
+ LOGMASKED(LOG_TYPE0_TIMEOUT, "%s: type0_timeout_w (%08x)\n", machine().describe_context(), offset << 2);
m_buserr[0] = 0x8020; // write timeout
m_buserr[1] = 0x04000000 + (offset << 2);
m_host->set_mae();
@@ -553,7 +451,7 @@ void sun4_mmu_base_device::type0_timeout_w(uint32_t offset)
uint32_t sun4_mmu_base_device::type1_timeout_r(uint32_t offset)
{
- LOGMASKED(LOG_TYPE1_TIMEOUT, "type 1 read timeout %08x, PC=%08x\n", offset << 2, m_cpu->pc());
+ LOGMASKED(LOG_TYPE1_TIMEOUT, "%s: type1_timeout_r (%08x)\n", machine().describe_context(), offset << 2);
m_buserr[2] = 0x20; // read timeout
m_buserr[3] = m_type1_offset << 2;
return 0;
@@ -561,11 +459,42 @@ uint32_t sun4_mmu_base_device::type1_timeout_r(uint32_t offset)
void sun4_mmu_base_device::type1_timeout_w(uint32_t offset, uint32_t data)
{
- LOGMASKED(LOG_TYPE1_TIMEOUT, "type 1 write timeout %08x = %08x, PC=%08x\n", offset << 2, data, m_cpu->pc());
+ LOGMASKED(LOG_TYPE1_TIMEOUT, "%s: type1_timeout_w (%08x)\n", machine().describe_context(), offset << 2);
m_buserr[2] = 0x120; // write timeout
m_buserr[3] = m_type1_offset << 2;
}
+uint32_t sun4_mmu_base_device::parity_r(uint32_t offset, uint32_t mem_mask)
+{
+ uint32_t data = 0;
+ if (offset == 0)
+ {
+ data = m_parity_err_reg;
+ LOGMASKED(LOG_PARITY, "%s: parity_r (parity error register): %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ m_parity_err_reg &= ~0xcf;
+ }
+ else if (offset == 1)
+ {
+ data = m_memory_err_reg;
+ LOGMASKED(LOG_PARITY, "%s: parity_r (memory error register): %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ }
+ return data;
+}
+
+void sun4_mmu_base_device::parity_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ if (offset == 0)
+ {
+ LOGMASKED(LOG_PARITY, "%s: parity_w (parity error register): %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+ COMBINE_DATA(&m_parity_err_reg);
+ }
+ else
+ {
+ LOGMASKED(LOG_PARITY, "%s: parity_w (memory error register): %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+ COMBINE_DATA(&m_memory_err_reg);
+ }
+}
+
uint32_t sun4_mmu_base_device::page_entry_to_uint(uint32_t index)
{
const page_entry &pe = m_pagemap[index];
@@ -584,92 +513,6 @@ void sun4_mmu_base_device::merge_page_entry(uint32_t index, uint32_t data, uint3
pe.accessed = new_value & PM_ACCESSED;
pe.modified = new_value & PM_MODIFIED;
pe.page = (new_value & m_page_entry_mask) << m_seg_entry_shift;
- pe.raw = new_value;
- pe.index = index;
- LOGMASKED(LOG_PAGE_ENTRIES, "page entry %05x: data %08x, sanity %08x, mem_mask %08x, valid %d, write %d, super %d, cached %d\n", index, new_value, page_entry_to_uint(index), mem_mask, pe.valid ? 1 : 0, pe.writable ? 1 : 0, pe.supervisor ? 1 : 0, pe.uncached ? 0 : 1);
-}
-
-uint32_t sun4_mmu_base_device::vaddr_to_cache_line(uint32_t vaddr)
-{
- return (vaddr >> m_cache_tag_shift) & m_cache_tag_mask;
-}
-
-void sun4_mmu_base_device::cache_fill(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t entry_index)
-{
- const uint32_t cache_line = vaddr_to_cache_line(vaddr);
- m_cachetags[cache_line] = (1 << 19);
- m_cachetags[cache_line] |= entry.supervisor ? (1 << 20) : (0 << 20);
- m_cachetags[cache_line] |= entry.writable ? (1 << 21) : (0 << 21);
- m_cachetags[cache_line] |= (vaddr >> m_cache_tag_id_shift) & m_cache_tag_id_mask;
- m_cachetags[cache_line] |= (m_context_masked) << 22;
- const uint32_t cache_line_start = cache_line << m_cache_tag_shift;
- const uint32_t mem_line_mask = (1 << m_cache_tag_shift) - 1;
- const uint32_t mem_line_start = paddr & ~mem_line_mask;
-
- if (paddr < m_populated_ram_words)
- {
- LOGMASKED(LOG_CACHE_FILLS, "Filling cache line %04x (%08x) with data from paddr %08x, vaddr %08x, cache_line %04x, mem_line %08x, tag entry %04x\n",
- cache_line, 0x80000000 | (cache_line << m_cache_tag_shift), paddr << 2, vaddr << 2, cache_line_start << 2, mem_line_start << 2,
- (m_cachetags[cache_line] >> m_cache_line_size) & (0xfffc >> m_cache_tag_shift));
- LOGMASKED(LOG_CACHE_FILLS, "Tag: %08x, valid %d, super %d, write %d, ctx %d\n", m_cachetags[cache_line], BIT(m_cachetags[cache_line], 19),
- BIT(m_cachetags[cache_line], 20), BIT(m_cachetags[cache_line], 21), (m_cachetags[cache_line] >> 22) & 7);
- LOGMASKED(LOG_CACHE_FILLS, "Entry %05x: raw: %08x, valid %d, super %d, write %d, cache %d\n", entry_index, page_entry_to_uint(entry_index),
- entry.valid ? 1 : 0, entry.supervisor ? 1 : 0, entry.writable ? 1 : 0, entry.uncached ? 0 : 1);
- memcpy(&m_cachedata[cache_line_start], m_ram_ptr + mem_line_start, sizeof(uint32_t) * m_cache_word_size);
- }
- else
- {
- LOGMASKED(LOG_CACHE_FILLS, "Unable to fill cache line, paddr %08x exceeds populated RAM range\n", paddr << 2);
- }
-}
-
-template bool sun4_mmu_base_device::cache_fetch<sun4_mmu_base_device::USER_INSN>(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t &cached_data, uint32_t entry_index);
-template bool sun4_mmu_base_device::cache_fetch<sun4_mmu_base_device::USER_DATA>(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t &cached_data, uint32_t entry_index);
-template bool sun4_mmu_base_device::cache_fetch<sun4_mmu_base_device::SUPER_INSN>(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t &cached_data, uint32_t entry_index);
-template bool sun4_mmu_base_device::cache_fetch<sun4_mmu_base_device::SUPER_DATA>(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t &cached_data, uint32_t entry_index);
-
-template <sun4_mmu_base_device::insn_data_mode MODE>
-bool sun4_mmu_base_device::cache_fetch(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t &cached_data, uint32_t entry_index)
-{
- const uint32_t cache_line = vaddr_to_cache_line(vaddr);
- const uint32_t tag = m_cachetags[cache_line];
- if (!(tag & (1 << 19)))
- {
- // If the current tag is invalid, bail if the corresponding entry is invalid
- if (!entry.valid)
- {
- return false;
- }
- cache_fill(entry, vaddr, paddr, entry_index);
- cached_data = m_cachedata[vaddr & 0x3fff];
- return true;
- }
- else if ((tag & m_cache_tag_id_mask) == ((vaddr >> m_cache_tag_id_shift) & m_cache_tag_id_mask))
- {
- // If the current tag is valid and the tag IDs match, fetch from the cache
- if ((MODE >> 1) == USER_MODE)
- {
- // If we're in user mode and the context does not match, this is a miss
- if (((tag >> 22) & m_ctx_mask) != m_context_masked && (tag & (1 << 20)))
- {
- return false;
- }
- }
- cached_data = m_cachedata[vaddr & 0x3fff];
- return true;
- }
- else if (!entry.valid)
- {
- // If the current tag is valid, the tag IDs don't match, and the memory entry is invalid, miss
- return false;
- }
- else
- {
- // If the current tag is valid, the tag IDs don't match, and the memory entry is valid, it's a miss
- cache_fill(entry, vaddr, paddr, entry_index);
- cached_data = m_cachedata[vaddr & 0x3fff];
- return true;
- }
}
template uint32_t sun4_mmu_base_device::insn_data_r<sun4_mmu_base_device::USER_INSN>(const uint32_t, const uint32_t);
@@ -678,122 +521,47 @@ template uint32_t sun4_mmu_base_device::insn_data_r<sun4_mmu_base_device::USER_D
template uint32_t sun4_mmu_base_device::insn_data_r<sun4_mmu_base_device::SUPER_DATA>(const uint32_t, const uint32_t);
template <sun4_mmu_base_device::insn_data_mode MODE>
-uint32_t sun4_mmu_base_device::insn_data_r(uint32_t offset, uint32_t mem_mask)
+uint32_t sun4_mmu_base_device::insn_data_r(const uint32_t offset, const uint32_t mem_mask)
{
// supervisor program fetches in boot state are special
if (MODE == SUPER_INSN && m_fetch_bootrom)
{
- if (!machine().side_effects_disabled())
- m_cpu->eat_cycles(50); // !?
return m_rom_ptr[offset & 0x1ffff];
}
// it's translation time
- const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];// & m_pmeg_mask;
+ const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];
const uint32_t entry_index = pmeg | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
- page_entry &entry = m_pagemap[entry_index];
- uint32_t cached_data = 0;
- if (entry.valid)
+ if (m_page_valid[entry_index])
{
- const uint32_t paddr = entry.page | (offset & m_page_mask);
-
+ page_entry &entry = m_pagemap[entry_index];
entry.accessed = PM_ACCESSED;
- {
- uint32_t tag_entry = vaddr_to_cache_line(offset);
- uint32_t tag = m_cachetags[tag_entry];
- bool user_mode = ((MODE >> 1) == USER_MODE);
- bool cache_hit = (tag & m_cache_tag_id_mask) == ((offset >> m_cache_tag_id_shift) & m_cache_tag_id_mask);
- bool cacheable = entry.type == 0 && !entry.uncached;
- bool check_cache = cacheable && cache_hit && (m_system_enable & ENA_CACHE);
- bool cache_valid = BIT(tag, 19);
- bool cache_protected = user_mode && BIT(tag, 20) && (((m_cachetags[tag_entry] >> 22) & m_ctx_mask) != m_context_masked);
-
- if (check_cache && cache_valid && cache_protected)
- {
- LOGMASKED(LOG_READ_PROTECT, "%s: read protect error with PTE %04x (%08x), %08x & %08x\n", machine().describe_context(),
- entry_index, page_entry_to_uint(entry_index), offset << 2, mem_mask);
- LOGMASKED(LOG_WRITE_PROTECT, "%s: tag %08x, line %04x, writable %d, check %d, valid %d, super %d, tag ctx %d, ctx reg %d\n",
- machine().describe_context(), m_cachetags[tag_entry], tag_entry, BIT(m_cachetags[tag_entry], 21), check_cache ? 1 : 0, cache_valid ? 1 : 0,
- BIT(m_cachetags[tag_entry], 20), (m_cachetags[tag_entry] >> 22) & 7, m_context_masked);
- LOGMASKED(LOG_WRITE_PROTECT, "%s: entry cached %d, entry writable %d, entry super %d\n",
- machine().describe_context(), entry.uncached ? 0 : 1, entry.writable ? 1 : 0, entry.supervisor ? 1 : 0);
- LOGMASKED(LOG_WRITE_PROTECT, "%s: pmeg %08x, seg entry %08x\n", machine().describe_context(), pmeg, ((offset >> m_seg_entry_shift) & m_seg_entry_mask));
- m_buserr[0] |= 0x0040; // read protection error
- m_buserr[1] = offset << 2;
- m_host->set_mae();
- m_cachetags[tag_entry] &= ~(1 << 19);
- return 0;
- }
- }
+ const uint32_t tmp = entry.page | (offset & m_page_mask);
switch (entry.type)
{
case 0: // type 0 space
- if (paddr < m_populated_ram_words)
+ if (tmp < m_populated_ram_words)
{
- if (BIT(m_parity_err_reg, 4) && m_parity_err)
- {
- LOGMASKED(LOG_PARITY, "%s: ram read with parity %08x: %08x & %08x\n", machine().describe_context(), m_parity_err_reg, offset, mem_mask);
- m_parity_err_reg |= m_parity_err;
- if (BIT(m_parity_err_reg, 7))
- {
- m_parity_err_reg |= (1 << 6);
- }
- uint8_t boffs = 0;
-
- if (ACCESSING_BITS_24_31)
- boffs = 0;
- else if (ACCESSING_BITS_16_23)
- boffs = 1;
- else if (ACCESSING_BITS_8_15)
- boffs = 2;
- else if (ACCESSING_BITS_0_7)
- boffs = 3;
-
- m_parity_err_reg |= (1 << 7);
- m_parity_err = 0;
- m_buserr[0] = 0x8; // Read cycle, memory error
- m_buserr[1] = (offset << 2) | boffs;
- m_host->set_mae();
- }
- const uint32_t set = (paddr >> 22) & 3;
+ const uint32_t set = (tmp >> 22) & 3;
const uint32_t addr_mask = m_ram_set_mask[set];
- const uint32_t masked_addr = m_ram_set_base[set] + (paddr & addr_mask);
- if (!entry.uncached && (m_system_enable & ENA_CACHE))
- {
- if (cache_fetch<MODE>(entry, offset, masked_addr, cached_data, entry_index))
- {
-#if SUN4CMMU_LOG_MEM_ACCESSES
- uint32_t value = masked_addr | 0x80000000;
- fwrite(&value, 1, 4, s_mem_log);
- fwrite(&cached_data, 1, 4, s_mem_log);
- m_fpos += 8;
-#endif
- return cached_data;
- }
- }
-#if SUN4CMMU_LOG_MEM_ACCESSES
- uint32_t value = masked_addr | 0x80000000;
- fwrite(&value, 1, 4, s_mem_log);
- fwrite(&m_ram_ptr[masked_addr], 1, 4, s_mem_log);
- m_fpos += 8;
-#endif
+ const uint32_t masked_addr = m_ram_set_base[set] + (tmp & addr_mask);
return m_ram_ptr[masked_addr];
}
- else if (paddr >= 0x4000000 >> 2 && paddr < 0x10000000 >> 2)
+ else if (tmp >= 0x4000000 >> 2 && tmp < 0x10000000 >> 2)
{
- type0_timeout_r(paddr);
+ type0_timeout_r(tmp);
}
return ~0;
case 1: // type 1 space
m_type1_offset = offset;
- return m_type1_r(paddr, mem_mask);
+ return m_type1_r(tmp, mem_mask);
default:
- LOGMASKED(LOG_UNKNOWN_SPACE, "read unknown space type %d, %08x & %08x, PC=%08x\n", entry.type, paddr << 2, mem_mask, m_cpu->pc());
+ LOGMASKED(LOG_UNKNOWN_SPACE, "read unknown space type %d, %08x & %08x, PC=%08x\n", entry.type, tmp << 2, mem_mask, m_cpu->pc());
m_host->set_mae();
m_buserr[0] = 0x20;
m_buserr[1] = offset << 2;
@@ -804,10 +572,6 @@ uint32_t sun4_mmu_base_device::insn_data_r(uint32_t offset, uint32_t mem_mask)
{
if (!machine().side_effects_disabled())
{
- if ((m_system_enable & ENA_CACHE) && cache_fetch<MODE>(entry, offset, 0, cached_data, entry_index))
- {
- return cached_data;
- }
LOGMASKED(LOG_INVALID_PTE, "read invalid PTE %d (%08x), %08x & %08x, PC=%08x\n", entry_index, page_entry_to_uint(entry_index), offset << 2, mem_mask, m_cpu->pc());
m_host->set_mae();
m_buserr[0] |= 0x80; // invalid PTE
@@ -839,7 +603,7 @@ template void sun4_mmu_base_device::insn_data_w<sun4_mmu_base_device::USER_DATA>
template void sun4_mmu_base_device::insn_data_w<sun4_mmu_base_device::SUPER_DATA>(const uint32_t, const uint32_t, const uint32_t);
template <sun4_mmu_base_device::insn_data_mode MODE>
-void sun4_mmu_base_device::insn_data_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::insn_data_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask)
{
// it's translation time
const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];// & m_pmeg_mask;
@@ -848,104 +612,43 @@ void sun4_mmu_base_device::insn_data_w(uint32_t offset, uint32_t data, uint32_t
if (m_page_valid[entry_index])
{
page_entry &entry = m_pagemap[entry_index];
- const uint32_t paddr = entry.page | (offset & m_page_mask);
-
+ if ((!entry.writable) || (entry.supervisor && MODE != SUPER_DATA && MODE != SUPER_INSN))
{
- uint32_t tag_entry = vaddr_to_cache_line(offset);
- uint32_t tag = m_cachetags[tag_entry];
- bool user_mode = (MODE >> 1) == USER_MODE;
- bool cacheable = entry.type == 0 && !entry.uncached;
- bool check_cache = cacheable && (m_system_enable & ENA_CACHE);
- bool cache_valid = BIT(tag, 19);
- bool cache_hit = (tag & m_cache_tag_id_mask) == ((offset >> m_cache_tag_id_shift) & m_cache_tag_id_mask);
- bool cache_writable = BIT(tag, 21);
- bool cache_protected = user_mode && BIT(tag, 20) && (((tag >> 22) & m_ctx_mask) != m_context_masked);
-
- if (cacheable && (!cache_valid || !cache_hit || !cache_writable || cache_protected))
- {
- m_cachetags[tag_entry] &= ~(1 << 19);
- }
-
- if ((check_cache && cache_hit && cache_valid && (!cache_writable || cache_protected)) ||
- (!check_cache && (!entry.writable || (user_mode && entry.supervisor))))
- {
- LOGMASKED(LOG_WRITE_PROTECT, "%s: write protect error with PTE %04x (%08x), %08x = %08x & %08x, mode %c\n", machine().describe_context(),
- entry_index, page_entry_to_uint(entry_index), offset << 2, data, mem_mask, user_mode ? 'U' : 'S');
- LOGMASKED(LOG_WRITE_PROTECT, "%s: tag %08x, line %04x, writable %d, check %d, valid %d, super %d, tag ctx %d, ctx reg %d\n",
- machine().describe_context(), m_cachetags[tag_entry], tag_entry, BIT(m_cachetags[tag_entry], 21), check_cache ? 1 : 0, cache_valid ? 1 : 0,
- BIT(m_cachetags[tag_entry], 20), (m_cachetags[tag_entry] >> 22) & 7, m_context_masked);
- LOGMASKED(LOG_WRITE_PROTECT, "%s: entry cached %d, entry writable %d, entry super %d\n",
- machine().describe_context(), entry.uncached ? 0 : 1, entry.writable ? 1 : 0, entry.supervisor ? 1 : 0);
- LOGMASKED(LOG_WRITE_PROTECT, "%s: pmeg %08x, seg entry %08x\n", machine().describe_context(), pmeg, ((offset >> m_seg_entry_shift) & m_seg_entry_mask));
- m_buserr[0] |= 0x8040; // write protection error
- m_buserr[1] = offset << 2;
- m_host->set_mae();
- return;
- }
+ LOGMASKED(LOG_WRITE_PROTECT, "write protect error with PTE %d (%08x), %08x = %08x & %08x, PC=%08x\n", entry_index, page_entry_to_uint(entry_index), offset << 2, data, mem_mask, m_cpu->pc());
+ m_buserr[0] |= 0x8040; // write, protection error
+ m_buserr[1] = offset << 2;
+ m_host->set_mae();
+ return;
}
entry.accessed = PM_ACCESSED;
entry.modified = PM_MODIFIED;
+ const uint32_t tmp = entry.page | (offset & m_page_mask);
+
switch (entry.type)
{
case 0: // type 0
- if (paddr < m_populated_ram_words)
+ if (tmp < m_populated_ram_words)
{
- if (BIT(m_parity_err_reg, 5))
- {
- LOGMASKED(LOG_PARITY, "%s: ram write with parity %08x: %08x = %08x & %08x\n", machine().describe_context(), m_parity_err_reg,
- offset, data, mem_mask);
- if (ACCESSING_BITS_24_31)
- m_parity_err |= (1 << 0);
- if (ACCESSING_BITS_16_23)
- m_parity_err |= (1 << 1);
- if (ACCESSING_BITS_8_15)
- m_parity_err |= (1 << 2);
- if (ACCESSING_BITS_0_7)
- m_parity_err |= (1 << 3);
- }
- const uint32_t set = (paddr >> 22) & 3;
+ const uint32_t set = (tmp >> 22) & 3;
const uint32_t addr_mask = m_ram_set_mask[set];
- const uint32_t masked_addr = m_ram_set_base[set] + (paddr & addr_mask);
- if (!entry.uncached && (m_system_enable & ENA_CACHE))
- {
- const uint32_t cache_entry = vaddr_to_cache_line(offset);
- const uint32_t tag = m_cachetags[cache_entry];
- if (tag & (1 << 19))
- {
- if ((m_cachetags[cache_entry] & m_cache_tag_id_mask) == ((offset >> m_cache_tag_id_shift) & m_cache_tag_id_mask))
- {
- COMBINE_DATA(&m_cachedata[offset & 0x3fff]);
- }
- else
- {
- //m_cachetags[cache_entry] &= ~(1 << 19);
- //cache_fill(entry, offset, masked_addr, entry_index);
- //COMBINE_DATA(&m_cachedata[offset & 0x3fff]);
- }
- }
- }
+ const uint32_t masked_addr = m_ram_set_base[set] + (tmp & addr_mask);
COMBINE_DATA((m_ram_ptr + masked_addr));
-#if SUN4CMMU_LOG_MEM_ACCESSES
- fwrite(&masked_addr, 1, 4, s_mem_log);
- fwrite(&m_ram_ptr[masked_addr], 1, 4, s_mem_log);
- m_fpos += 8;
-#endif
}
- else if (paddr >= 0x4000000 >> 2 && paddr < 0x10000000 >> 2)
+ else if (tmp >= 0x4000000 >> 2 && tmp < 0x10000000 >> 2)
{
- type0_timeout_w(paddr);
+ type0_timeout_w(tmp);
}
return;
case 1: // type 1
m_type1_offset = offset;
- m_type1_w(paddr, data, mem_mask);
+ m_type1_w(tmp, data, mem_mask);
return;
default:
- LOGMASKED(LOG_UNKNOWN_SPACE, "write unknown space type %d, %08x = %08x & %08x, PC=%08x\n", entry.type, paddr << 2, data, mem_mask, m_cpu->pc());
+ LOGMASKED(LOG_UNKNOWN_SPACE, "write unknown space type %d, %08x = %08x & %08x, PC=%08x\n", entry.type, tmp << 2, data, mem_mask, m_cpu->pc());
m_host->set_mae();
m_buserr[0] = 0x8020;
m_buserr[1] = offset << 2;
@@ -976,35 +679,26 @@ void sun4_mmu_base_device::insn_data_w(uint32_t offset, uint32_t data, uint32_t
}
}
-bool sun4_mmu_base_device::translate(uint32_t &addr)
+void sun4_mmu_base_device::l2p_command(const std::vector<std::string_view> &params)
{
- const uint32_t pmeg = m_curr_segmap_masked[(addr >> 16) & 0xfff];// & m_pmeg_mask;
- const uint32_t entry_index = pmeg | ((addr >> m_seg_entry_shift) & m_seg_entry_mask);
- const page_entry &entry = m_pagemap[entry_index];
- addr = entry.page | (addr & m_page_mask);
- return entry.valid;
-}
-
-void sun4_mmu_base_device::l2p_command(int ref, const std::vector<std::string> &params)
-{
- uint64_t addr, offset;
-
- if (!machine().debugger().commands().validate_number_parameter(params[0], addr)) return;
+ uint64_t addr;
+ if (!machine().debugger().console().validate_number_parameter(params[0], addr)) return;
addr &= 0xffffffff;
- offset = addr >> 2;
+ uint64_t offset = addr >> 2;
- uint8_t pmeg = m_curr_segmap_masked[(addr >> 18) & 0xfff];
- uint32_t entry_index = pmeg | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
- uint32_t paddr = m_pagemap[entry_index].page | (offset & m_page_mask);
- uint32_t entry_value = page_entry_to_uint(entry_index);
+ const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];
+ const uint32_t entry_index = pmeg | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
+ const uint32_t tmp = m_pagemap[entry_index].page | (offset & m_page_mask);
+ const uint32_t entry_value = page_entry_to_uint(entry_index);
if (m_page_valid[entry_index])
{
- machine().debugger().console().printf("logical %08x => phys %08x, type %d (pmeg %d, entry %d PTE %08x)\n", addr, paddr << 2, m_pagemap[entry_index].type, pmeg, entry_index, entry_value);
+ machine().debugger().console().printf("logical %08x => phys %08x, type %d (pmeg %d, entry %d PTE %08x)\n", addr, tmp << 2, m_pagemap[entry_index].type, pmeg, entry_index, entry_value);
}
else
{
- machine().debugger().console().printf("logical %08x points to an invalid PTE! (pmeg %d, entry %d PTE %08x)\n", addr, paddr << 2, pmeg, entry_index, entry_value);
+ machine().debugger().console().printf("logical %08x points to an invalid PTE! (tmp %08x, pmeg %d, entry %d PTE %08x)\n", addr, tmp << 2, pmeg, entry_index, entry_value);
}
}
+
diff --git a/src/devices/machine/sun4c_mmu.h b/src/devices/machine/sun4c_mmu.h
index d9fa7a80783..87db83ec4a7 100644
--- a/src/devices/machine/sun4c_mmu.h
+++ b/src/devices/machine/sun4c_mmu.h
@@ -15,8 +15,6 @@
#include "machine/ram.h"
#include "machine/z80scc.h"
-#define SUN4CMMU_LOG_MEM_ACCESSES (0)
-
class sun4_mmu_base_device : public device_t, public sparc_mmu_interface
{
public:
@@ -39,7 +37,6 @@ public:
template <typename T> void set_ram(T &&ram_tag) { m_ram.set_tag(std::forward<T>(ram_tag)); }
template <typename T> void set_rom(T &&rom_tag) { m_rom.set_tag(std::forward<T>(rom_tag)); }
template <typename T> void set_scc(T &&scc_tag) { m_scc.set_tag(std::forward<T>(scc_tag)); }
- void set_cache_line_size(uint32_t line_size) { m_cache_line_size = line_size; }
auto type1_r() { return m_type1_r.bind(); }
auto type1_w() { return m_type1_w.bind(); }
@@ -51,31 +48,26 @@ public:
void set_seg_entry_mask(uint32_t seg_entry_mask) { m_seg_entry_mask = seg_entry_mask; }
void set_page_entry_mask(uint32_t page_entry_mask) { m_page_entry_mask = page_entry_mask; }
void set_cache_mask(uint32_t cache_mask) { m_cache_mask = cache_mask; }
-
- enum perm_mode
- {
- USER_MODE,
- SUPER_MODE
- };
+ void set_cache_line_size(uint32_t cache_line_size) { m_cache_line_size = cache_line_size; }
enum insn_data_mode
{
USER_INSN,
- USER_DATA,
SUPER_INSN,
+ USER_DATA,
SUPER_DATA
};
- template <insn_data_mode MODE> uint32_t insn_data_r(uint32_t offset, uint32_t mem_mask);
- template <insn_data_mode MODE> void insn_data_w(uint32_t offset, uint32_t data, uint32_t mem_mask);
+ template <insn_data_mode MODE> uint32_t insn_data_r(const uint32_t offset, const uint32_t mem_mask);
+ template <insn_data_mode MODE> void insn_data_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask);
uint32_t type1_timeout_r(uint32_t offset);
void type1_timeout_w(uint32_t offset, uint32_t data);
uint32_t parity_r(uint32_t offset, uint32_t mem_mask);
void parity_w(uint32_t offset, uint32_t data, uint32_t mem_mask);
- // sparc_mmu_device overrides
- uint32_t fetch_insn(const bool supervisor, uint32_t offset) override;
+ // sparc_mmu_interface overrides
+ uint32_t fetch_insn(const bool supervisor, const uint32_t offset) override;
void set_host(sparc_mmu_host_interface *host) override { m_host = host; }
uint32_t context_reg_r(uint32_t offset, uint32_t mem_mask);
@@ -107,39 +99,17 @@ public:
protected:
sun4_mmu_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- struct page_entry
- {
- uint32_t index;
- uint32_t raw;
- uint32_t valid;
- uint32_t writable;
- uint32_t supervisor;
- uint32_t uncached;
- uint32_t accessed;
- uint32_t modified;
- uint32_t page;
- uint8_t type;
- uint8_t pad[3];
- };
-
- static const device_timer_id TIMER_RESET = 0;
-
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_stop() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(reset_off_tick);
uint32_t page_entry_to_uint(uint32_t index);
void merge_page_entry(uint32_t index, uint32_t data, uint32_t mem_mask);
- template <insn_data_mode MODE> bool cache_fetch(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t &cached_data, uint32_t entry_index);
- void cache_fill(page_entry &entry, uint32_t vaddr, uint32_t paddr, uint32_t entry_index);
-
void type0_timeout_r(const uint32_t offset);
void type0_timeout_w(const uint32_t offset);
- bool translate(uint32_t &addr);
- void l2p_command(int ref, const std::vector<std::string> &params);
- uint32_t vaddr_to_cache_line(uint32_t vaddr);
+ void l2p_command(const std::vector<std::string_view> &params);
enum
{
@@ -160,6 +130,19 @@ protected:
PM_MODIFIED = 0x01000000 // modified flag
};
+ struct page_entry
+ {
+ uint32_t valid;
+ uint32_t writable;
+ uint32_t supervisor;
+ uint32_t uncached;
+ uint32_t accessed;
+ uint32_t modified;
+ uint32_t page;
+ uint8_t type;
+ uint8_t pad[3];
+ };
+
required_device<cpu_device> m_cpu;
required_device<ram_device> m_ram;
required_memory_region m_rom;
@@ -186,7 +169,7 @@ protected:
uint32_t m_cache_context;
uint8_t m_system_enable;
bool m_fetch_bootrom;
- uint32_t m_buserr[16];
+ uint32_t m_buserr[4];
uint32_t m_type1_offset;
uint32_t m_parity_err_reg;
uint32_t m_memory_err_reg;
@@ -206,21 +189,11 @@ protected:
uint32_t m_seg_entry_mask;
uint32_t m_page_entry_mask;
uint32_t m_cache_mask;
- uint32_t m_cache_tag_mask;
uint32_t m_cache_line_size;
- uint32_t m_cache_word_size;
- uint32_t m_cache_tag_shift;
- uint32_t m_cache_tag_id_mask;
- uint32_t m_cache_tag_id_shift;
- uint32_t m_cache_vaddr_shift;
uint32_t m_ram_set_mask[4]; // Used for mirroring within 4 megabyte sets
uint32_t m_ram_set_base[4];
uint32_t m_populated_ram_words;
-#if SUN4CMMU_LOG_MEM_ACCESSES
- uint64_t m_fpos;
-#endif
emu_timer *m_reset_timer;
- bool m_log_mem;
};
class sun4_mmu_device : public sun4_mmu_base_device
diff --git a/src/devices/machine/swim1.cpp b/src/devices/machine/swim1.cpp
index d313d777b42..2a54d1d613e 100644
--- a/src/devices/machine/swim1.cpp
+++ b/src/devices/machine/swim1.cpp
@@ -9,38 +9,102 @@
#include "emu.h"
#include "swim1.h"
+#define VERBOSE 0
+#include "logmacro.h"
+
DEFINE_DEVICE_TYPE(SWIM1, swim1_device, "swim1", "Apple SWIM1 (Sander/Wozniak Integrated Machine) version 1 floppy controller")
swim1_device::swim1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- applefdintf_device(mconfig, SWIM1, tag, owner, clock)
+ applefdintf_device(mconfig, SWIM1, tag, owner, clock),
+ m_floppy(nullptr),
+ m_timer(nullptr)
{
}
void swim1_device::device_start()
{
applefdintf_device::device_start();
- save_item(NAME(m_mode));
- save_item(NAME(m_setup));
- save_item(NAME(m_param_idx));
- save_item(NAME(m_param));
+
+ m_timer = timer_alloc(FUNC(swim1_device::update), this);
+ save_item(NAME(m_last_sync));
+ save_item(NAME(m_flux_write_start));
+ save_item(NAME(m_flux_write));
+ save_item(NAME(m_flux_write_count));
+
+ save_item(NAME(m_ism_param));
+ save_item(NAME(m_ism_mode));
+ save_item(NAME(m_ism_setup));
+ save_item(NAME(m_ism_error));
+ save_item(NAME(m_ism_param_idx));
+ save_item(NAME(m_ism_fifo_pos));
+ save_item(NAME(m_ism_tss_sr));
+ save_item(NAME(m_ism_tss_output));
+ save_item(NAME(m_ism_current_bit));
+ save_item(NAME(m_ism_fifo));
+ save_item(NAME(m_ism_sr));
+ save_item(NAME(m_ism_crc));
+ save_item(NAME(m_ism_half_cycles_before_change));
+ save_item(NAME(m_ism_correction_factor));
+ save_item(NAME(m_ism_latest_edge));
+ save_item(NAME(m_ism_prev_ls));
+ save_item(NAME(m_ism_csm_state));
+ save_item(NAME(m_ism_csm_error_counter));
+ save_item(NAME(m_ism_csm_pair_side));
+ save_item(NAME(m_ism_csm_min_count));
+ save_item(NAME(m_ism_tsm_out));
+ save_item(NAME(m_ism_tsm_bits));
+ save_item(NAME(m_ism_tsm_mark));
+
+ save_item(NAME(m_iwm_next_state_change));
+ save_item(NAME(m_iwm_sync_update));
+ save_item(NAME(m_iwm_async_update));
+ save_item(NAME(m_iwm_active));
+ save_item(NAME(m_iwm_rw));
+ save_item(NAME(m_iwm_rw_state));
+ save_item(NAME(m_iwm_data));
+ save_item(NAME(m_iwm_whd));
+ save_item(NAME(m_iwm_mode));
+ save_item(NAME(m_iwm_status));
+ save_item(NAME(m_iwm_control));
+ save_item(NAME(m_iwm_rsh));
+ save_item(NAME(m_iwm_wsh));
+ save_item(NAME(m_iwm_rw_bit_count));
+ save_item(NAME(m_iwm_to_ism_counter));
+ save_item(NAME(m_iwm_devsel));
}
void swim1_device::device_reset()
{
applefdintf_device::device_reset();
- m_mode = 0x40;
- m_setup = 0x00;
- m_param_idx = 0;
- memset(m_param, 0, sizeof(m_param));
+ m_ism_mode = 0x00;
+ m_ism_setup = 0x00;
+ m_ism_param_idx = 0;
+ memset(m_ism_param, 0, sizeof(m_ism_param));
m_floppy = nullptr;
+ m_last_sync = machine().time().as_ticks(clock());
+ m_flux_write_start = 0;
+ m_flux_write_count = 0;
+
+ m_iwm_next_state_change = 0;
+ m_iwm_active = MODE_IDLE;
+ m_iwm_rw = MODE_IDLE;
+ m_iwm_rw_state = S_IDLE;
+ m_iwm_data = 0x00;
+ m_iwm_whd = 0xbf;
+ m_iwm_mode = 0x00;
+ m_iwm_status = 0x00;
+ m_iwm_control = 0x00;
+ m_iwm_wsh = 0x00;
+ m_iwm_rsh = 0x00;
+ m_iwm_rw_bit_count = 0;
+ m_iwm_to_ism_counter = 0;
+ m_iwm_devsel = 0;
+
m_devsel_cb(0);
m_sel35_cb(true);
m_hdsel_cb(false);
-}
-
-void swim1_device::device_timer(emu_timer &, device_timer_id, int, void *)
-{
+ m_dat1byte_cb(0);
}
void swim1_device::set_floppy(floppy_image_device *floppy)
@@ -48,12 +112,15 @@ void swim1_device::set_floppy(floppy_image_device *floppy)
if(m_floppy == floppy)
return;
- if(m_floppy)
- m_floppy->mon_w(true);
+ sync();
+ flush_write();
+
+ LOG("floppy %s\n", floppy ? floppy->tag() : "-");
+
m_floppy = floppy;
- if(m_mode & 0x80)
- m_floppy->mon_w(false);
update_phases();
+ if(m_ism_mode & 0x40)
+ m_hdsel_cb((m_ism_mode >> 5) & 1);
}
floppy_image_device *swim1_device::get_floppy() const
@@ -61,113 +128,1085 @@ floppy_image_device *swim1_device::get_floppy() const
return m_floppy;
}
-void swim1_device::show_mode() const
+void swim1_device::ism_show_mode() const
{
- logerror("mode%s %s hdsel=%c %c%s %c%c%s\n",
- m_mode & 0x80 ? " motoron" : "",
- m_mode & 0x40 ? "ism" : "iwm",
- m_mode & 0x20 ? '1' : '0',
- m_mode & 0x10 ? 'w' : 'r',
- m_mode & 0x08 ? " action" : "",
- m_mode & 0x04 ? 'a' : '-',
- m_mode & 0x02 ? 'b' : '-',
- m_mode & 0x01 ? " clear" : "");
+ LOG("ism mode%s %s hdsel=%c %c%s %c%c%s\n",
+ m_ism_mode & 0x80 ? " motoron" : "",
+ m_ism_mode & 0x40 ? "ism" : "iwm",
+ m_ism_mode & 0x20 ? '1' : '0',
+ m_ism_mode & 0x10 ? 'w' : 'r',
+ m_ism_mode & 0x08 ? " action" : "",
+ m_ism_mode & 0x04 ? 'a' : '-',
+ m_ism_mode & 0x02 ? 'b' : '-',
+ m_ism_mode & 0x01 ? " clear" : "");
}
u8 swim1_device::read(offs_t offset)
{
- static const char *const names[] = {
- "?0", "?1", "?2", "?3", "?4", "?5", "?6", "?7",
- "data", "mark", "crc", "param", "phases", "setup", "status", "handshake"
- };
- switch(offset) {
- case 0x3: case 0xb: {
- u8 r = m_param[m_param_idx];
- m_param_idx = (m_param_idx + 1) & 15;
+ if(m_ism_mode & 0x40)
+ return ism_read(offset);
+ else
+ {
+ if(!machine().side_effects_disabled())
+ iwm_control(offset, 0x00);
+
+ switch(m_iwm_control & 0xc0) {
+ case 0x00: return m_iwm_active ? m_iwm_data : 0xff;
+ case 0x40: return (m_iwm_status & 0x7f) | ((!m_floppy || m_floppy->wpt_r()) ? 0x80 : 0x00);
+ case 0x80: return m_iwm_whd;
+ case 0xc0: return 0xff;
+ }
+
+ abort();
+ }
+}
+
+void swim1_device::write(offs_t offset, u8 data)
+{
+ if(m_ism_mode & 0x40)
+ ism_write(offset, data);
+ else
+ iwm_control(offset, data);
+}
+
+u8 swim1_device::ism_read(offs_t offset)
+{
+ ism_sync();
+
+ // static const char *const names[] = {
+ // "data", "mark", "crc", "param", "phases", "setup", "status", "handshake"
+ // };
+
+ // LOG("read ism %s\n", names[offset & 7]);
+ switch(offset & 7) {
+ case 0x0: { // data
+ u16 r = ism_fifo_pop();
+ if(!m_ism_error) {
+ if(r == 0xffff)
+ m_ism_error |= 4;
+ else if(r & M_MARK)
+ m_ism_error |= 2;
+ }
+ return r;
+ }
+
+ case 0x1: { // mark
+ u16 r = ism_fifo_pop();
+ if(!m_ism_error && r == 0xffff)
+ m_ism_error |= 4;
+ return r;
+ }
+
+ case 0x2: { // error
+ u8 err = m_ism_error;
+ m_ism_error = 0;
+ return err;
+ }
+
+ case 0x3: {
+ u8 r = m_ism_param[m_ism_param_idx];
+ m_ism_param_idx = (m_ism_param_idx + 1) & 15;
return r;
}
- case 0x4: case 0xc:
+
+ case 0x4: // phases
return m_phases;
- case 0x5: case 0xd:
- return m_setup;
- case 0xe:
- return m_mode;
+
+ case 0x5: // setup
+ return m_ism_setup;
+
+ case 0x6: // mode
+ return m_ism_mode;
+
+ case 0x7: { // handshake
+ u8 h = 0;
+ if(m_ism_fifo_pos > 0) {
+ if(m_ism_fifo[m_ism_fifo_pos - 1] & M_MARK)
+ h |= 0x01;
+ if(!(m_ism_fifo[m_ism_fifo_pos - 1] & M_CRC0))
+ h |= 0x02;
+ }
+ // rddata on 4
+ if(!m_floppy || m_floppy->wpt_r())
+ h |= 0x08;
+ if(m_ism_error)
+ h |= 0x20;
+ if(m_ism_mode & 0x10) {
+ // write
+ if(m_ism_fifo_pos == 0)
+ h |= 0xc0;
+ else if(m_ism_fifo_pos == 1)
+ h |= 0x80;
+ } else {
+ // read
+ if(m_ism_fifo_pos == 2)
+ h |= 0xc0;
+ else if(m_ism_fifo_pos == 1)
+ h |= 0x80;
+ }
+ return h;
+ }
+
default:
- logerror("read %s\n", names[offset & 15]);
+ // logerror("read %s\n", names[offset & 7]);
break;
}
return 0xff;
}
-void swim1_device::write(offs_t offset, u8 data)
+void swim1_device::ism_write(offs_t offset, u8 data)
{
- machine().debug_break();
+ ism_sync();
+
+ u8 prev_mode = m_ism_mode;
+
static const char *const names[] = {
"data", "mark", "crc", "param", "phases", "setup", "mode0", "mode1",
- "?8", "?9", "?a", "?b", "?c", "?d", "?e", "?f"
};
switch(offset) {
- case 0x3: case 0xb: {
-#if 0
+ case 0:
+ if(ism_fifo_push(data) && !m_ism_error)
+ m_ism_error |= 0x04;
+ break;
+
+ case 1:
+ if(ism_fifo_push(M_MARK | data) && !m_ism_error)
+ m_ism_error |= 0x04;
+ break;
+
+ case 2:
+ if(ism_fifo_push(M_CRC) && !m_ism_error)
+ m_ism_error |= 0x04;
+ break;
+
+ case 0x3: {
static const char *const pname[16] = {
"minct", "mult", "ssl", "sss", "sll", "sls", "rpt", "csls",
"lsl", "lss", "lll", "lls", "late", "time0", "early", "time1"
};
-#endif
- static const char *const pname[4] = {
- "late", "time0", "early", "time1"
- };
- logerror("param[%s] = %02x\n", pname[m_param_idx], data);
- m_param[m_param_idx] = data;
- m_param_idx = (m_param_idx + 1) & 3;
+ LOG("param[%s] = %02x\n", pname[m_ism_param_idx], data);
+ m_ism_param[m_ism_param_idx] = data;
+ m_ism_param_idx = (m_ism_param_idx + 1) & 15;
break;
}
+
case 0x4: {
+ LOG("ism phases %02x\n", data);
m_phases = data;
update_phases();
break;
}
- case 0x5: case 0xd:
- m_setup = data;
-#if 0
- logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
- m_setup & 0x80 ? "on" : "off",
- m_setup & 0x40 ? "off" : "on",
- m_setup & 0x20 ? "ibm" : "apple",
- m_setup & 0x10 ? "on" : "off",
- m_setup & 0x08 ? "fclk/2" : "fclk",
- m_setup & 0x04 ? "gcr" : "mfm",
- m_setup & 0x02 ? "off" : "on",
- m_setup & 0x01 ? "hdsel" : "q3");
-#endif
- logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
- m_setup & 0x80 ? "on" : "off",
- m_setup & 0x40 ? "off" : "on",
- m_setup & 0x20 ? "ibm" : "apple",
- m_setup & 0x10 ? "on" : "off",
- m_setup & 0x08 ? "fclk/2" : "fclk",
- m_setup & 0x04 ? "gcr" : "mfm",
- m_setup & 0x02 ? "off" : "on",
- m_setup & 0x01 ? "hdsel" : "q3");
+ case 0x5:
+ m_ism_setup = data;
+ LOG("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
+ m_ism_setup & 0x80 ? "on" : "off",
+ m_ism_setup & 0x40 ? "off" : "on",
+ m_ism_setup & 0x20 ? "ibm" : "apple",
+ m_ism_setup & 0x10 ? "on" : "off",
+ m_ism_setup & 0x08 ? "fclk/2" : "fclk",
+ m_ism_setup & 0x04 ? "gcr" : "mfm",
+ m_ism_setup & 0x02 ? "off" : "on",
+ m_ism_setup & 0x01 ? "hdsel" : "q3");
break;
case 0x6:
- m_mode &= ~data;
- m_mode |= 0x40;
- m_param_idx = 0;
- show_mode();
+ m_ism_mode &= ~data;
+ m_ism_param_idx = 0;
+ ism_show_mode();
+ if(data & 0x10)
+ m_dat1byte_cb((m_ism_fifo_pos != 0) ? 1 : 0);
+ if(!(m_ism_mode & 0x40)) {
+ LOG("switch to iwm\n");
+ u8 ism_devsel = m_ism_mode & 0x80 ? (m_ism_mode >> 1) & 3 : 0;
+ if(ism_devsel != m_iwm_devsel)
+ m_devsel_cb(m_iwm_devsel);
+ }
break;
case 0x7:
- m_mode |= data;
- show_mode();
+ m_ism_mode |= data;
+ ism_show_mode();
+ if(data & 0x10)
+ m_dat1byte_cb((m_ism_fifo_pos != 2) ? 1 : 0);
break;
default:
- logerror("write %s, %02x\n", names[offset], data);
+ logerror("write %s, %02x\n", names[offset & 7], data);
break;
}
+
+ if(m_ism_mode & 0x01)
+ ism_fifo_clear();
+
+ if((m_ism_mode ^ prev_mode) & 0x86)
+ m_devsel_cb(m_ism_mode & 0x80 ? (m_ism_mode >> 1) & 3 : 0);
+ if((m_ism_mode ^ prev_mode) & 0x20)
+ m_hdsel_cb((m_ism_mode >> 5) & 1);
+
+ if((m_ism_mode & 0x18) == 0x18 && ((prev_mode & 0x18) != 0x18)) {
+ // Entering write mode
+ m_ism_current_bit = 0;
+ LOG("%s write start %s %s floppy=%p\n", machine().time().to_string(), m_ism_setup & 0x40 ? "gcr" : "mfm", m_ism_setup & 0x08 ? "fclk/2" : "fclk", m_floppy);
+ m_flux_write_start = m_last_sync;
+ m_flux_write_count = 0;
+
+ } else if((prev_mode & 0x18) == 0x18 && (m_ism_mode & 0x18) != 0x18) {
+ // Exiting write mode
+ flush_write();
+ m_flux_write_start = 0;
+ m_ism_current_bit = 0xff;
+ m_ism_half_cycles_before_change = 0;
+ LOG("%s write end\n", machine().time().to_string());
+ }
+
+ if((m_ism_mode & 0x18) == 0x08 && ((prev_mode & 0x18) != 0x08)) {
+ // Entering read mode
+ m_ism_current_bit = 0;
+ m_ism_sr = 0;
+ m_ism_latest_edge = m_last_sync;
+ m_ism_prev_ls = (1<<2) | 1;
+ m_ism_csm_state = m_ism_setup & 0x04 ? CSM_SYNCHRONIZED : CSM_INIT;
+ m_ism_csm_error_counter[0] = m_ism_csm_error_counter[1] = 0;
+ m_ism_correction_factor[0] = m_ism_correction_factor[1] = 0;
+ m_ism_csm_pair_side = 0;
+ m_ism_csm_min_count = 0;
+
+ LOG("%s read start %s %s floppy=%p\n", machine().time().to_string(), m_ism_setup & 0x04 ? "gcr" : "mfm", m_ism_setup & 0x08 ? "fclk/2" : "fclk", m_floppy);
+
+ } else if((prev_mode & 0x18) == 0x08 && (m_ism_mode & 0x18) != 0x08) {
+ // Exiting read mode
+ flush_write();
+ m_ism_current_bit = 0xff;
+ m_ism_half_cycles_before_change = 0;
+ LOG("%s read end\n", machine().time().to_string());
+ }
+}
+
+TIMER_CALLBACK_MEMBER(swim1_device::update)
+{
+ if(m_iwm_active == MODE_DELAY) {
+ flush_write();
+ m_iwm_active = MODE_IDLE;
+ m_iwm_rw = MODE_IDLE;
+ m_iwm_rw_state = S_IDLE;
+ if(!(m_ism_mode & 0x40))
+ m_devsel_cb(0);
+ m_iwm_devsel = 0;
+ m_iwm_status &= ~0x20;
+ m_iwm_whd &= ~0x40;
+ }
+}
+
+void swim1_device::flush_write(u64 when)
+{
+ if(!m_flux_write_start)
+ return;
+
+ if(!when)
+ when = m_last_sync;
+
+ if(when > m_flux_write_start) {
+ bool last_on_edge = m_flux_write_count && m_flux_write[m_flux_write_count-1] == when;
+ if(last_on_edge)
+ m_flux_write_count--;
+
+ attotime start = cycles_to_time(m_flux_write_start);
+ attotime end = cycles_to_time(when);
+ std::vector<attotime> fluxes(m_flux_write_count);
+ for(u32 i=0; i != m_flux_write_count; i++)
+ fluxes[i] = cycles_to_time(m_flux_write[i]);
+
+ if(m_floppy)
+ m_floppy->write_flux(start, end, m_flux_write_count, m_flux_write_count ? &fluxes[0] : nullptr);
+
+ m_flux_write_count = 0;
+ if(last_on_edge)
+ m_flux_write[m_flux_write_count++] = when;
+ m_flux_write_start = when;
+
+ } else
+ m_flux_write_count = 0;
+}
+
+void swim1_device::iwm_control(int offset, u8 data)
+{
+ iwm_sync();
+
+ u8 prev_iwm_to_ism_counter = m_iwm_to_ism_counter;
+
+ if(offset < 8) {
+ if(offset & 1)
+ m_phases |= 1 << (offset >> 1);
+ else
+ m_phases &= ~(1 << (offset >> 1));
+ update_phases();
+ } else {
+ if(offset & 1)
+ m_iwm_control |= 1 << (offset >> 1);
+ else
+ m_iwm_control &= ~(1 << (offset >> 1));
+ }
+
+ if(m_iwm_control & 0x10) {
+ if(m_iwm_active != MODE_ACTIVE) {
+ m_iwm_active = MODE_ACTIVE;
+ m_iwm_status |= 0x20;
+ if(m_floppy)
+ m_floppy->mon_w(false);
+ }
+
+ if((m_iwm_control & 0x80) == 0x00) {
+ if(m_iwm_rw != MODE_READ) {
+ if(m_iwm_rw == MODE_WRITE) {
+ flush_write();
+ m_flux_write_start = 0;
+ }
+ m_iwm_rw = MODE_READ;
+ m_iwm_rw_state = S_IDLE;
+ m_iwm_next_state_change = 0;
+ m_iwm_sync_update = 0;
+ m_iwm_async_update = 0;
+ m_iwm_data = 0x00;
+ }
+
+ } else {
+ if(m_iwm_rw != MODE_WRITE) {
+ m_iwm_rw = MODE_WRITE;
+ m_iwm_rw_state = S_IDLE;
+ m_iwm_whd |= 0x40;
+ m_iwm_next_state_change = 0;
+ m_flux_write_start = m_last_sync;
+ m_flux_write_count = 0;
+ if(m_floppy)
+ m_floppy->set_write_splice(cycles_to_time(m_flux_write_start));
+ }
+ }
+ } else {
+ if(m_iwm_active == MODE_ACTIVE) {
+ flush_write();
+ if(m_iwm_mode & 0x04) {
+ m_flux_write_start = 0;
+ m_iwm_active = MODE_IDLE;
+ m_iwm_rw = MODE_IDLE;
+ m_iwm_rw_state = S_IDLE;
+ m_iwm_status &= ~0x20;
+ m_iwm_whd &= ~0x40;
+ if(m_floppy)
+ m_floppy->mon_w(true);
+ } else {
+ m_devsel_cb(m_iwm_control & 0x20 ? 2 : 1);
+ m_iwm_active = MODE_DELAY;
+ m_timer->adjust(cycles_to_time(8388608));
+ }
+ }
+ }
+
+ u8 devsel = m_iwm_active != MODE_IDLE ? m_iwm_control & 0x20 ? 2 : 1 : 0;
+ if(devsel != m_iwm_devsel) {
+ m_iwm_devsel = devsel;
+ m_devsel_cb(devsel);
+ }
+
+ if(0) {
+ u8 s = m_iwm_control & 0xc0;
+ const char *slot = "?";
+ if(s == 0x00 && !m_iwm_active)
+ slot = "idle / ff";
+ if(s == 0x00 && m_iwm_active)
+ slot = "read / read data";
+ if(s == 0x40)
+ slot = "wp sense / read status";
+ if(s == 0x80)
+ slot = "write / read whd";
+ if(s == 0xc0 && !m_iwm_active)
+ slot = "mode set / write mode";
+ if(s == 0xc0 && m_iwm_active)
+ slot = "write load / write data";
+
+ LOG("%s control %c%c %c%c %c%c%c%c (%s) [%s, %s] whd=%02x data=%02x\n",
+ machine().time().to_string(),
+ m_iwm_control & 0x80 ? '1' : '0',
+ m_iwm_control & 0x40 ? '1' : '0',
+ m_iwm_control & 0x20 ? 'b' : 'a',
+ m_iwm_control & 0x10 ? '#' : '.',
+ m_phases & 0x08 ? '#' : '.',
+ m_phases & 0x04 ? '#' : '.',
+ m_phases & 0x02 ? '#' : '.',
+ m_phases & 0x01 ? '#' : '.',
+ slot,
+ m_iwm_active == MODE_IDLE ? "idle" : m_iwm_active == MODE_DELAY ? "delay" : "active",
+ m_iwm_rw == MODE_IDLE ? "idle" : m_iwm_rw == MODE_READ ? "read" : "write",
+ m_iwm_whd, m_iwm_data);
+ }
+
+ if(m_iwm_active && !(m_iwm_control & 0x80) && !iwm_is_sync() && (m_iwm_data & 0x80))
+ m_iwm_async_update = m_last_sync + 14;
+
+ if(offset == 0xf) {
+ switch(m_iwm_to_ism_counter) {
+ case 0: case 2:
+ if(data & 0x40)
+ m_iwm_to_ism_counter++;
+ break;
+ case 1:
+ if(!(data & 0x40))
+ m_iwm_to_ism_counter++;
+ break;
+ case 3:
+ if(data & 0x40) {
+ m_ism_mode |= 0x40;
+ LOG("switch to ism\n");
+ u8 ism_devsel = m_ism_mode & 0x80 ? (m_ism_mode >> 1) & 3 : 0;
+ if(ism_devsel != m_iwm_devsel)
+ m_devsel_cb(ism_devsel);
+ }
+ break;
+ }
+ }
+ if(m_iwm_to_ism_counter != prev_iwm_to_ism_counter+1)
+ m_iwm_to_ism_counter = 0;
+ else
+ LOG("iwm counter = %d\n", m_iwm_to_ism_counter);
+
+ if((m_iwm_control & 0xc0) == 0xc0 && (offset & 1))
+ {
+ if(m_iwm_active)
+ iwm_data_w(data);
+ else
+ iwm_mode_w(data);
+ }
}
+void swim1_device::ism_crc_clear()
+{
+ m_ism_crc = 0xcdb4;
+}
+
+void swim1_device::ism_crc_update(int bit)
+{
+ if((m_ism_crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ m_ism_crc = (m_ism_crc << 1) ^ 0x1021;
+ else
+ m_ism_crc = m_ism_crc << 1;
+
+}
+
+// The ism part of the swim1 works in half-clocks
+u64 swim1_device::time_to_cycles(const attotime &tm) const
+{
+ return tm.as_ticks(2*clock());
+}
+
+attotime swim1_device::cycles_to_time(u64 cycles) const
+{
+ return attotime::from_ticks(cycles, 2*clock());
+}
+
+void swim1_device::ism_fifo_clear()
+{
+ m_ism_fifo_pos = 0;
+ m_dat1byte_cb((m_ism_mode & 0x10) ? 1 : 0);
+ ism_crc_clear();
+}
+
+bool swim1_device::ism_fifo_push(u16 data)
+{
+ if(m_ism_fifo_pos == 2)
+ return true;
+ m_ism_fifo[m_ism_fifo_pos ++] = data;
+ if(m_ism_mode & 0x10) {
+ // write
+ if(m_ism_fifo_pos == 2)
+ m_dat1byte_cb(0);
+ } else {
+ // read
+ if(m_ism_fifo_pos == 1)
+ m_dat1byte_cb(1);
+ }
+ return false;
+}
+
+u16 swim1_device::ism_fifo_pop()
+{
+ if(m_ism_fifo_pos == 0)
+ return 0xffff;
+ u16 r = m_ism_fifo[0];
+ m_ism_fifo[0] = m_ism_fifo[1];
+ m_ism_fifo_pos --;
+ if(m_ism_mode & 0x10) {
+ // write
+ if(m_ism_fifo_pos == 1)
+ m_dat1byte_cb(1);
+ } else {
+ // read
+ if(m_ism_fifo_pos == 0)
+ m_dat1byte_cb(0);
+ }
+ return r;
+}
+
+void swim1_device::iwm_mode_w(u8 data)
+{
+ m_iwm_mode = data;
+ m_iwm_status = (m_iwm_status & 0xe0) | (data & 0x1f);
+ LOG("mode %02x%s%s%s%s%s%s%s\n", m_iwm_mode,
+ m_iwm_mode & 0x80 ? " b7" : "",
+ m_iwm_mode & 0x40 ? " mz-reset" : "",
+ m_iwm_mode & 0x20 ? " test" : " normal",
+ m_iwm_mode & 0x10 ? " 8MHz" : " 7MHz",
+ m_iwm_mode & 0x08 ? " fast" : " slow",
+ m_iwm_mode & 0x04 ? "" : " timer",
+ m_iwm_mode & 0x02 ? " async" : " sync",
+ m_iwm_mode & 0x01 ? " latched" : "");
+}
+
+void swim1_device::iwm_data_w(u8 data)
+{
+ m_iwm_data = data;
+ if(iwm_is_sync() && m_iwm_rw == MODE_WRITE)
+ m_iwm_wsh = data;
+ if(m_iwm_mode & 0x01)
+ m_iwm_whd &= 0x7f;
+}
+
+bool swim1_device::iwm_is_sync() const
+{
+ return m_iwm_mode & 0x02 ? false : true;
+}
+
+u64 swim1_device::iwm_half_window_size() const
+{
+ switch(m_iwm_mode & 0x18) {
+ case 0x00: return 2*14;
+ case 0x08: return 2* 7;
+ case 0x10: return 2*16;
+ case 0x18: return 2* 8;
+ }
+ abort();
+}
+
+u64 swim1_device::iwm_window_size() const
+{
+ switch(m_iwm_mode & 0x18) {
+ case 0x00: return 2*28;
+ case 0x08: return 2*14;
+ case 0x10: return 2*36;
+ case 0x18: return 2*16;
+ }
+ abort();
+}
+
+u64 swim1_device::iwm_read_register_update_delay() const
+{
+ return m_iwm_mode & 0x08 ? 4 : 8;
+}
+
+void swim1_device::iwm_sync()
+{
+ if(!m_iwm_active)
+ return;
+
+ u64 next_sync = time_to_cycles(machine().time());
+ switch(m_iwm_rw) {
+ case MODE_IDLE:
+ m_last_sync = next_sync;
+ break;
+
+ case MODE_READ: {
+ u64 next_flux_change = 0;
+ while(next_sync > m_last_sync) {
+ if(next_flux_change <= m_last_sync) {
+ attotime flux = m_floppy ? m_floppy->get_next_transition(cycles_to_time(m_last_sync+1)) : attotime::never;
+ next_flux_change = flux.is_never() ? u64(-1) : time_to_cycles(flux);
+ if(next_flux_change <= m_last_sync)
+ next_flux_change = m_last_sync+1;
+ }
+ if(next_sync < m_iwm_next_state_change) {
+ m_last_sync = next_sync;
+ break;
+ }
+ if(m_last_sync < m_iwm_next_state_change)
+ m_last_sync = m_iwm_next_state_change;
+ switch(m_iwm_rw_state) {
+ case S_IDLE:
+ m_iwm_rsh = 0x00;
+ m_iwm_rw_state = SR_WINDOW_EDGE_0;
+ m_iwm_next_state_change = m_last_sync + iwm_window_size();
+ m_iwm_sync_update = 0;
+ m_iwm_async_update = 0;
+ break;
+
+ case SR_WINDOW_EDGE_0:
+ case SR_WINDOW_EDGE_1: {
+ u64 endw = m_iwm_next_state_change + (m_iwm_rw_state == SR_WINDOW_EDGE_0 ? iwm_window_size() : iwm_half_window_size());
+ if(m_iwm_rw_state == SR_WINDOW_EDGE_0 && endw >= next_flux_change && next_sync >= next_flux_change) {
+ m_last_sync = m_iwm_next_state_change = next_flux_change;
+ m_iwm_rw_state = SR_WINDOW_EDGE_1;
+ break;
+ }
+ if(next_sync < endw) {
+ m_last_sync = next_sync;
+ break;
+ }
+ m_iwm_rsh = (m_iwm_rsh << 1) | (m_iwm_rw_state == SR_WINDOW_EDGE_1 ? 1 : 0);
+ m_iwm_next_state_change = m_last_sync = endw;
+ m_iwm_rw_state = SR_WINDOW_EDGE_0;
+ if(iwm_is_sync()) {
+ if(m_iwm_rsh >= 0x80) {
+ m_iwm_data = m_iwm_rsh;
+ m_iwm_rsh = 0;
+ } else if(m_iwm_rsh >= 0x04) {
+ m_iwm_data = m_iwm_rsh;
+ m_iwm_sync_update = 0;
+ } else if(m_iwm_rsh >= 0x02)
+ m_iwm_sync_update = m_last_sync + iwm_read_register_update_delay();
+
+ } else if(m_iwm_rsh >= 0x80) {
+ m_iwm_data = m_iwm_rsh;
+ m_iwm_async_update = 0;
+ m_iwm_rsh = 0;
+ }
+ break;
+ }
+ }
+ }
+ if(m_iwm_sync_update && m_iwm_sync_update <= m_last_sync) {
+ if(iwm_is_sync())
+ m_iwm_data = m_iwm_rsh;
+ m_iwm_sync_update = 0;
+ }
+ if(m_iwm_async_update && m_iwm_async_update <= m_last_sync) {
+ if(!iwm_is_sync())
+ m_iwm_data = 0;
+ m_iwm_async_update = 0;
+ }
+ break;
+ }
+
+ case MODE_WRITE: {
+ while(next_sync > m_last_sync) {
+ if(next_sync < m_iwm_next_state_change || !(m_iwm_whd & 0x40)) {
+ m_last_sync = next_sync;
+ break;
+ }
+ if(m_last_sync < m_iwm_next_state_change)
+ m_last_sync = m_iwm_next_state_change;
+ switch(m_iwm_rw_state) {
+ case S_IDLE:
+ m_flux_write_count = 0;
+ if(m_iwm_mode & 0x02) {
+ m_iwm_rw_state = SW_WINDOW_LOAD;
+ m_iwm_rw_bit_count = 8;
+ m_iwm_next_state_change = m_last_sync + 7;
+ } else {
+ m_iwm_wsh = m_iwm_data;
+ m_iwm_rw_state = SW_WINDOW_MIDDLE;
+ m_iwm_next_state_change = m_last_sync + iwm_half_window_size();
+ }
+ break;
+
+ case SW_WINDOW_LOAD:
+ if(m_iwm_whd & 0x80) {
+ LOG("underrun\n");
+ flush_write();
+ m_flux_write_start = 0;
+ m_iwm_whd &= ~0x40;
+ m_last_sync = next_sync;
+ m_iwm_rw_state = SW_UNDERRUN;
+
+ } else {
+ m_iwm_wsh = m_iwm_data;
+ m_iwm_rw_state = SW_WINDOW_MIDDLE;
+ m_iwm_whd |= 0x80;
+ m_iwm_next_state_change = m_last_sync + iwm_half_window_size() - 7;
+ }
+ break;
+
+ case SW_WINDOW_MIDDLE:
+ if(m_iwm_wsh & 0x80)
+ m_flux_write[m_flux_write_count++] = m_last_sync;
+ m_iwm_wsh <<= 1;
+ m_iwm_rw_state = SW_WINDOW_END;
+ m_iwm_next_state_change = m_last_sync + iwm_half_window_size();
+ break;
+
+ case SW_WINDOW_END:
+ if(m_flux_write_count == m_flux_write.size())
+ flush_write();
+ if(m_iwm_mode & 0x02) {
+ m_iwm_rw_bit_count --;
+ if(m_iwm_rw_bit_count == 0) {
+ m_iwm_rw_state = SW_WINDOW_LOAD;
+ m_iwm_rw_bit_count = 8;
+ m_iwm_next_state_change = m_last_sync + 7;
+ } else {
+ m_iwm_rw_state = SW_WINDOW_MIDDLE;
+ m_iwm_next_state_change = m_last_sync + iwm_half_window_size();
+ }
+ } else {
+ m_iwm_next_state_change = m_last_sync + iwm_half_window_size();
+ m_iwm_rw_state = SW_WINDOW_MIDDLE;
+ }
+ break;
+
+ case SW_UNDERRUN:
+ m_last_sync = next_sync;
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void swim1_device::ism_sync()
+{
+ u64 next_sync = time_to_cycles(machine().time());
+ if(!(m_ism_mode & 0x08)) {
+ m_last_sync = next_sync;
+ return;
+ }
+
+ if(m_ism_mode & 0x10) {
+ u32 cycles = next_sync - m_last_sync;
+
+ // Write mode
+ while(cycles) {
+ if(m_ism_half_cycles_before_change) {
+ if(cycles >= m_ism_half_cycles_before_change) {
+ cycles -= m_ism_half_cycles_before_change;
+ m_ism_half_cycles_before_change = 0;
+ } else {
+ m_ism_half_cycles_before_change -= cycles;
+ cycles = 0;
+ break;
+ }
+ }
+
+ if(m_ism_tss_output & 0xc) {
+ bool bit;
+ if(m_ism_tss_output & 8) {
+ bit = (m_ism_tss_output >> 1) & 1;
+ m_ism_tss_output &= ~0xa;
+ } else {
+ bit = m_ism_tss_output & 1;
+ m_ism_tss_output = 0;
+ }
+ if(bit) {
+ if(m_flux_write_count == m_flux_write.size())
+ flush_write(next_sync - cycles);
+ m_flux_write[m_flux_write_count ++] = next_sync - cycles;
+ m_ism_half_cycles_before_change = m_ism_param[P_TIME1] + 2*2;
+ } else
+ m_ism_half_cycles_before_change = m_ism_param[P_TIME0] + 2*2;
+ if(m_ism_setup & 8)
+ m_ism_half_cycles_before_change <<= 1;
+ continue;
+ }
+ if(m_ism_current_bit == 0xff)
+ fatalerror("Sequence break on write\n");
+
+ if(m_ism_current_bit == 0) {
+ if(m_ism_sr & M_CRC)
+ m_ism_sr = m_ism_crc >> 8;
+ else {
+ u16 r = ism_fifo_pop();
+ if(r == 0xffff && !m_ism_error) {
+ m_ism_error |= 0x01;
+ flush_write();
+ m_ism_current_bit = 0xff;
+ m_ism_half_cycles_before_change = 0;
+ m_ism_mode &= ~8;
+ LOG("write end on underrun\n");
+ break;
+ }
+ if(r & M_CRC)
+ m_ism_sr = M_CRC | (m_ism_crc >> 8);
+ else
+ m_ism_sr = r & (M_MARK | M_CRC | 0xff);
+ }
+ m_ism_current_bit = 8;
+ if(m_ism_sr & M_MARK)
+ ism_crc_clear();
+ }
+ m_ism_current_bit --;
+ int bit = (m_ism_sr >> m_ism_current_bit) & 1;
+ if(!(m_ism_sr & M_MARK))
+ ism_crc_update(bit);
+ m_ism_tss_sr = (m_ism_tss_sr << 1) | bit;
+ if(m_ism_setup & 0x40)
+ m_ism_tss_output = 4 | bit;
+ else {
+ static const u8 tss[4] = { 5, 0xd, 4, 5 };
+ if((m_ism_sr & M_MARK) && ((m_ism_tss_sr & 0xf) == 8))
+ m_ism_tss_output = 0xc;
+ else
+ m_ism_tss_output = tss[m_ism_tss_sr & 3];
+ }
+
+ continue;
+ }
+ } else {
+ while(m_last_sync < next_sync) {
+ // Find when in the future the next edge happens
+ u64 cycles_to_next;
+ bool will_hit_edge;
+ if(!m_floppy) {
+ cycles_to_next = next_sync - m_ism_latest_edge;
+ will_hit_edge = false;
+ } else {
+ auto when = m_floppy->get_next_transition(cycles_to_time(m_ism_latest_edge+2));
+ if(when == attotime::never || when > cycles_to_time(next_sync)) {
+ cycles_to_next = next_sync - m_ism_latest_edge;
+ will_hit_edge = false;
+ } else {
+ cycles_to_next = time_to_cycles(when) - m_ism_latest_edge;
+ will_hit_edge = true;
+ }
+ }
+
+ // Pick up the current rescaling factor
+ int scale = m_ism_correction_factor[m_ism_csm_pair_side];
+ if(scale < 192)
+ scale |= 256;
+
+ // Count the number of cells in the L and the S hypothesis
+ u32 sct, lct;
+ if(m_ism_prev_ls == 0x5) {
+ // Previous was a short
+ if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2)) >> 8)
+ sct = 0;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_SSS] + 2*2)) >> 8)
+ sct = 1;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_SSS] + 2*2 + m_ism_param[P_SLS] + 2*2)) >> 8)
+ sct = 2;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_SSS] + 2*2 + m_ism_param[P_SLS] + 2*2 + m_ism_param[P_RPT] + 2*2)) >> 8)
+ sct = 3;
+ else
+ sct = 4;
+ if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2)) >> 8)
+ lct = 0;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_SSL] + 2*2)) >> 8)
+ lct = 1;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_SSL] + 2*2 + m_ism_param[P_SLL] + 2*2)) >> 8)
+ lct = 2;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_SSL] + 2*2 + m_ism_param[P_SLL] + 2*2 + m_ism_param[P_RPT] + 2*2)) >> 8)
+ lct = 3;
+ else
+ lct = 4;
+
+ } else if(m_ism_prev_ls == 0x6 || m_ism_prev_ls == 0x7 || m_ism_prev_ls == 0x9 || m_ism_prev_ls == 0xd) {
+ // Previous was marginal
+ if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2)) >> 8)
+ sct = 0;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSS] + 2*2)) >> 8)
+ sct = 1;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSS] + 2*2 + m_ism_param[P_CSLS] + 2*2)) >> 8)
+ sct = 2;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSS] + 2*2 + m_ism_param[P_CSLS] + 2*2 + m_ism_param[P_RPT] + 2*2)) >> 8)
+ sct = 3;
+ else
+ sct = 4;
+ if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2)) >> 8)
+ lct = 0;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSL] + 2*2)) >> 8)
+ lct = 1;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSL] + 2*2 + m_ism_param[P_CSLS] + 2*2)) >> 8)
+ lct = 2;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSL] + 2*2 + m_ism_param[P_CSLS] + 2*2 + m_ism_param[P_RPT] + 2*2)) >> 8)
+ lct = 3;
+ else
+ lct = 4;
+
+ } else {
+ // Previous was long
+ if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2)) >> 8)
+ sct = 0;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSS] + 2*2)) >> 8)
+ sct = 1;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSS] + 2*2 + m_ism_param[P_LLS] + 2*2)) >> 8)
+ sct = 2;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSS] + 2*2 + m_ism_param[P_LLS] + 2*2 + m_ism_param[P_RPT] + 2*2)) >> 8)
+ sct = 3;
+ else
+ sct = 4;
+ if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2)) >> 8)
+ lct = 0;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSL] + 2*2)) >> 8)
+ lct = 1;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSL] + 2*2 + m_ism_param[P_LLL] + 2*2)) >> 8)
+ lct = 2;
+ else if(cycles_to_next <= (scale * (m_ism_param[P_MINCT] + 3*2 + m_ism_param[P_LSL] + 2*2 + m_ism_param[P_LLL] + 2*2 + m_ism_param[P_RPT] + 2*2)) >> 8)
+ lct = 3;
+ else
+ lct = 4;
+ }
+
+ // Actually resolve the cell lengths according to the counts
+ int resolved_ls_count = 0;
+ int resolved_ls_type[2] = { 0, 0 };
+ if((sct == 4 || lct == 4) && !m_ism_error)
+ m_ism_error |= 0x20;
+
+ if(will_hit_edge) {
+ if(sct == 0) {
+ // Don't do the short cell error, write splices often trigger it and the physical media
+ // probably doesn't actually allow for it.
+ sct = lct = 1;
+ }
+ if(sct == 4)
+ sct = 3;
+ if(lct == 4)
+ lct = 3;
+
+ bool previous_marginal = m_ism_prev_ls == 0x6 || m_ism_prev_ls == 0x7 || m_ism_prev_ls == 0x9 || m_ism_prev_ls == 0xd;
+ bool current_marginal = (sct == 1 && lct > 1) || (lct == 1 && sct > 1);
+
+ if(previous_marginal && current_marginal) {
+ if(!m_ism_error)
+ m_ism_error |= 0x40;
+ resolved_ls_count = 2;
+ resolved_ls_type[0] = (m_ism_prev_ls >> 2) & 3;
+ resolved_ls_type[1] = lct;
+ } else {
+ if(previous_marginal) {
+ if(sct == 1)
+ resolved_ls_type[resolved_ls_count++] = m_ism_prev_ls & 3;
+ else
+ resolved_ls_type[resolved_ls_count++] = (m_ism_prev_ls >> 2) & 3;
+ }
+ if(!current_marginal) {
+ if(sct == 1)
+ resolved_ls_type[resolved_ls_count++] = sct;
+ else
+ resolved_ls_type[resolved_ls_count++] = lct;
+ }
+ }
+
+ m_ism_prev_ls = (lct << 2) | sct;
+ }
+
+ // If we have cell lengths, run the Correction State Machine and the Trans-Space Machine appropriately
+ for(int i=0; i != resolved_ls_count; i++) {
+ int type = resolved_ls_type[i];
+ bool drop_one_bit = false;
+ switch(m_ism_csm_state) {
+ case CSM_INIT:
+ m_ism_csm_error_counter[0] = m_ism_csm_error_counter[1] = 0;
+ m_ism_csm_pair_side = 0;
+ m_ism_csm_min_count = 0;
+ m_ism_csm_state = CSM_COUNT_MIN;
+ break;
+
+ case CSM_COUNT_MIN:
+ if(type != 1) {
+ m_ism_csm_state = CSM_INIT;
+ break;
+ }
+ m_ism_csm_error_counter[m_ism_csm_pair_side] += m_ism_param[P_MULT] * (cycles_to_next >> 1);
+ m_ism_csm_min_count ++;
+ if(m_ism_csm_min_count == 64) {
+ for(int i=0; i != 2; i++) {
+ m_ism_correction_factor[i] = m_ism_csm_error_counter[i] >> 8;
+ if(!m_ism_error && (m_ism_csm_error_counter[i] < 0xc000 || m_ism_csm_error_counter[i] >= 0x1c000))
+ m_ism_error |= 0x08;
+ }
+ m_ism_csm_state = CSM_WAIT_NON_MIN;
+ }
+ break;
+
+ case CSM_WAIT_NON_MIN:
+ if(type == 1) {
+ break;
+ }
+ m_ism_csm_state = CSM_CHECK_MARK;
+ m_ism_tsm_out = 0;
+ m_ism_tsm_mark = false;
+ m_ism_tsm_bits = 0;
+ ism_crc_clear();
+ drop_one_bit = true;
+ [[fallthrough]];
+
+ // 2 1 3 1 3 2 2 2 1
+ // 2 3 2 3 2
+
+ case CSM_CHECK_MARK:
+ case CSM_SYNCHRONIZED:
+ if(m_ism_setup & 0x04) {
+ for(int i=0; i != type; i++) {
+ int bit = (i+1 == type) ? 1 : 0;
+ m_ism_tsm_out = (m_ism_tsm_out << 1) | bit;
+ if(m_ism_tsm_out & 0x80) {
+ if(ism_fifo_push(m_ism_tsm_out) && !m_ism_error)
+ m_ism_error |= 0x01;
+ m_ism_tsm_out = 0;
+ }
+ }
+ } else {
+ static u32 nb[6] = { 1, 1, 2, 1, 2, 2 };
+ static u32 bb[6] = { 1, 0, 1, 0, 1, 0 };
+ int idx = (m_ism_tsm_out & 1 ? 0 : 3) + type - 1;
+ int nbc = nb[idx];
+ int bbc = bb[idx];
+ if(drop_one_bit) {
+ nbc--;
+ drop_one_bit = false;
+ }
+ if(idx == 5)
+ m_ism_tsm_mark = true;
+ for(int i=0; i != nbc; i++) {
+ int bit = (bbc >> (nbc-1-i)) & 1;
+ m_ism_tsm_out = (m_ism_tsm_out << 1) | bit;
+ m_ism_tsm_bits ++;
+ ism_crc_update(bit);
+
+ if(m_ism_tsm_bits == 8) {
+ if(m_ism_csm_state == CSM_CHECK_MARK) {
+ if(!m_ism_tsm_mark) {
+ m_ism_csm_state = CSM_INIT;
+ break;
+ }
+ m_ism_csm_state = CSM_SYNCHRONIZED;
+ }
+ u16 val = m_ism_tsm_out & 0xff;
+ if(m_ism_tsm_mark) {
+ m_ism_tsm_mark = false;
+ val |= M_MARK;
+ ism_crc_clear();
+ }
+ if(!m_ism_crc)
+ val |= M_CRC0;
+ if(ism_fifo_push(val) && !m_ism_error)
+ m_ism_error |= 0x01;
+ m_ism_tsm_bits = 0;
+ }
+ }
+ }
+ break;
+ }
+
+ m_ism_csm_pair_side = !m_ism_csm_pair_side;
+ }
+
+
+ // Go to the next sync point
+ if(will_hit_edge) {
+ m_ism_latest_edge += cycles_to_next;
+ m_last_sync = m_ism_latest_edge;
+ } else
+ m_last_sync = next_sync;
+ }
+ }
+
+ m_last_sync = next_sync;
+}
+
+void swim1_device::sync()
+{
+ if(m_ism_mode & 0x40)
+ return ism_sync();
+ else
+ return iwm_sync();
+}
diff --git a/src/devices/machine/swim1.h b/src/devices/machine/swim1.h
index 86d064a19ae..dd0b372d54f 100644
--- a/src/devices/machine/swim1.h
+++ b/src/devices/machine/swim1.h
@@ -30,17 +30,110 @@ public:
virtual void set_floppy(floppy_image_device *floppy) override;
virtual floppy_image_device *get_floppy() const override;
+ virtual void sync() override;
+
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update);
private:
+ enum {
+ MODE_IDLE,
+ MODE_ACTIVE, MODE_DELAY, // m_iwm_active modes
+ MODE_READ, MODE_WRITE // m_iwm_rw modes
+ };
+
+ // iwm state machine states
+ enum {
+ S_IDLE,
+ SR_WINDOW_EDGE_0,
+ SR_WINDOW_EDGE_1,
+ SW_WINDOW_LOAD,
+ SW_WINDOW_MIDDLE,
+ SW_WINDOW_END,
+ SW_UNDERRUN,
+ };
+
+ // ism buffered byte marks
+ enum {
+ M_MARK = 0x100,
+ M_CRC = 0x200,
+ M_CRC0 = 0x400
+ };
+
+ // parameter ram addresses
+ enum {
+ P_MINCT, P_MULT, P_SSL, P_SSS, P_SLL, P_SLS, P_RPT, P_CSLS,
+ P_LSL, P_LSS, P_LLL, P_LLS, P_LATE, P_TIME0, P_EARLY, P_TIME1
+ };
+
+ // CSM states
+ enum {
+ CSM_INIT,
+ CSM_COUNT_MIN,
+ CSM_WAIT_NON_MIN,
+ CSM_CHECK_MARK,
+ CSM_SYNCHRONIZED
+ };
+
floppy_image_device *m_floppy;
- u8 m_param[4];
- u8 m_mode, m_setup, m_param_idx;
+ emu_timer *m_timer;
+
+ u64 m_flux_write_start;
+ std::array<u64, 32> m_flux_write;
+ u32 m_flux_write_count;
+ u64 m_last_sync;
+
+ u8 m_ism_param[16];
+ u8 m_ism_mode, m_ism_setup;
+ u8 m_ism_error;
+ u8 m_ism_param_idx, m_ism_fifo_pos;
+ u8 m_ism_tss_sr, m_ism_tss_output, m_ism_current_bit;
+ u16 m_ism_fifo[2];
+ u16 m_ism_sr;
+ u16 m_ism_crc;
+ u32 m_ism_half_cycles_before_change;
+ u8 m_ism_correction_factor[2];
+
+ u64 m_ism_latest_edge;
+ u8 m_ism_prev_ls;
+ u8 m_ism_csm_state;
+ u32 m_ism_csm_error_counter[2];
+ u8 m_ism_csm_pair_side, m_ism_csm_min_count;
+ u8 m_ism_tsm_out, m_ism_tsm_bits;
+ bool m_ism_tsm_mark;
+
+ u64 m_iwm_next_state_change, m_iwm_sync_update, m_iwm_async_update;
+ int m_iwm_active, m_iwm_rw, m_iwm_rw_state;
+ u8 m_iwm_data, m_iwm_whd, m_iwm_mode, m_iwm_status, m_iwm_control, m_iwm_rw_bit_count;
+ u8 m_iwm_rsh, m_iwm_wsh;
+ u8 m_iwm_to_ism_counter;
+ u8 m_iwm_devsel;
+
+ u64 time_to_cycles(const attotime &tm) const;
+ attotime cycles_to_time(u64 cycles) const;
+ void flush_write(u64 when = 0);
+
+ u64 iwm_window_size() const;
+ u64 iwm_half_window_size() const;
+ u64 iwm_read_register_update_delay() const;
+ inline bool iwm_is_sync() const;
+ void iwm_mode_w(u8 data);
+ void iwm_data_w(u8 data);
+ void iwm_control(int offset, u8 data);
+ void iwm_sync();
- void show_mode() const;
+ void ism_fifo_clear();
+ bool ism_fifo_push(u16 data);
+ u16 ism_fifo_pop();
+ void ism_show_mode() const;
+ void ism_crc_update(int bit);
+ void ism_crc_clear();
+ u8 ism_read(offs_t offset);
+ void ism_write(offs_t offset, u8 data);
+ void ism_sync();
};
DECLARE_DEVICE_TYPE(SWIM1, swim1_device)
diff --git a/src/devices/machine/swim2.cpp b/src/devices/machine/swim2.cpp
index 79e6bc4f8fa..70a1950bbbd 100644
--- a/src/devices/machine/swim2.cpp
+++ b/src/devices/machine/swim2.cpp
@@ -9,10 +9,19 @@
#include "emu.h"
#include "swim2.h"
+#define LOG_SETUP (1U << 1)
+#define LOG_MODE (1U << 2)
+#define VERBOSE 0
+#include "logmacro.h"
+
+#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
+#define LOGMODE(...) LOGMASKED(LOG_MODE, __VA_ARGS__)
+
DEFINE_DEVICE_TYPE(SWIM2, swim2_device, "swim2", "Apple SWIM2 (Sander/Wozniak Integrated Machine) version 2 floppy controller")
swim2_device::swim2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- applefdintf_device(mconfig, SWIM2, tag, owner, clock)
+ applefdintf_device(mconfig, SWIM2, tag, owner, clock),
+ m_floppy(nullptr)
{
}
@@ -24,6 +33,20 @@ void swim2_device::device_start()
save_item(NAME(m_setup));
save_item(NAME(m_param_idx));
save_item(NAME(m_param));
+ save_item(NAME(m_last_sync));
+ save_item(NAME(m_crc));
+ save_item(NAME(m_fifo));
+ save_item(NAME(m_fifo_pos));
+ save_item(NAME(m_error));
+ save_item(NAME(m_half_cycles_before_change));
+ save_item(NAME(m_current_bit));
+ save_item(NAME(m_tss_sr));
+ save_item(NAME(m_tss_output));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_mfm_sync_counter));
+ save_item(NAME(m_flux_write_start));
+ save_item(NAME(m_flux_write));
+ save_item(NAME(m_flux_write_count));
}
void swim2_device::device_reset()
@@ -35,14 +58,25 @@ void swim2_device::device_reset()
m_param_idx = 0;
memset(m_param, 0, sizeof(m_param));
m_floppy = nullptr;
-
+ m_crc = 0xffff;
+ m_fifo[0] = m_fifo[1] = 0;
+ m_fifo_pos = 0;
+ m_error = 0;
+ m_half_cycles_before_change = 0;
+ m_current_bit = 0;
+ m_tss_sr = 0;
+ m_tss_output = 0;
+ m_sr = 0;
+ m_mfm_sync_counter = 0;
m_devsel_cb(0);
m_sel35_cb(true);
m_hdsel_cb(false);
-}
+ m_dat1byte_cb(0);
+ m_flux_write_start = 0;
+ m_flux_write_count = 0;
+ std::fill(m_flux_write.begin(), m_flux_write.end(), 0);
-void swim2_device::device_timer(emu_timer &, device_timer_id, int, void *)
-{
+ m_last_sync = machine().time().as_ticks(clock());
}
void swim2_device::set_floppy(floppy_image_device *floppy)
@@ -50,12 +84,12 @@ void swim2_device::set_floppy(floppy_image_device *floppy)
if(m_floppy == floppy)
return;
- if(m_floppy)
- m_floppy->mon_w(true);
+ sync();
+ flush_write();
+
m_floppy = floppy;
- if(m_mode & 0x80)
- m_floppy->mon_w(false);
update_phases();
+ m_hdsel_cb((m_mode >> 5) & 1);
}
floppy_image_device *swim2_device::get_floppy() const
@@ -63,40 +97,125 @@ floppy_image_device *swim2_device::get_floppy() const
return m_floppy;
}
+void swim2_device::flush_write(u64 when)
+{
+ if(!m_flux_write_start)
+ return;
+
+ if(!when)
+ when = m_last_sync;
+
+ if(m_floppy && when > m_flux_write_start) {
+ bool last_on_edge = m_flux_write_count && m_flux_write[m_flux_write_count-1] == when;
+ if(last_on_edge)
+ m_flux_write_count--;
+
+ attotime start = cycles_to_time(m_flux_write_start);
+ attotime end = cycles_to_time(when);
+ std::vector<attotime> fluxes(m_flux_write_count);
+ for(u32 i=0; i != m_flux_write_count; i++)
+ fluxes[i] = cycles_to_time(m_flux_write[i]);
+ m_floppy->write_flux(start, end, m_flux_write_count, m_flux_write_count ? &fluxes[0] : nullptr);
+
+ m_flux_write_count = 0;
+ if(last_on_edge)
+ m_flux_write[m_flux_write_count++] = when;
+ m_flux_write_start = when;
+ } else
+ m_flux_write_count = 0;
+}
+
void swim2_device::show_mode() const
{
- logerror("mode%s %s hdsel=%c %c%s %c%c%s\n",
+ LOGMODE("mode%s hdsel=%c %c%s %c%c%s\n",
m_mode & 0x80 ? " motoron" : "",
- m_mode & 0x40 ? "ism" : "iwm",
m_mode & 0x20 ? '1' : '0',
m_mode & 0x10 ? 'w' : 'r',
m_mode & 0x08 ? " action" : "",
- m_mode & 0x04 ? 'a' : '-',
- m_mode & 0x02 ? 'b' : '-',
+ m_mode & 0x04 ? 'b' : '-',
+ m_mode & 0x02 ? 'a' : '-',
m_mode & 0x01 ? " clear" : "");
}
u8 swim2_device::read(offs_t offset)
{
+ sync();
+
static const char *const names[] = {
- "?0", "?1", "?2", "?3", "?4", "?5", "?6", "?7",
"data", "mark", "crc", "param", "phases", "setup", "status", "handshake"
};
- switch(offset) {
- case 0x3: case 0xb: {
+ switch(offset & 7) {
+ case 0x0: { // data
+ u16 r = fifo_pop();
+ if(!m_error) {
+ if(r == 0xffff)
+ m_error |= 4;
+ else if(r & M_MARK)
+ m_error |= 2;
+ }
+ return r;
+ }
+
+ case 0x1: { // mark
+ u16 r = fifo_pop();
+ if(!m_error && r == 0xffff)
+ m_error |= 4;
+ return r;
+ }
+
+ case 0x2: { // error
+ u8 err = m_error;
+ m_error = 0;
+ return err;
+ }
+
+ case 0x3: { // param
u8 r = m_param[m_param_idx];
- m_param_idx = (m_param_idx + 1) & 15;
+ m_param_idx = (m_param_idx + 1) & 3;
return r;
}
- case 0x4: case 0xc:
+
+ case 0x4: // phases
return m_phases;
- case 0x5: case 0xd:
+
+ case 0x5: // setup
return m_setup;
- case 0xe:
+
+ case 0x6: // mode
return m_mode;
+
+ case 0x7: { // handshake
+ u8 h = 0;
+ if(m_fifo_pos > 0) {
+ if(m_fifo[m_fifo_pos - 1] & M_MARK)
+ h |= 0x01;
+ if(!(m_fifo[m_fifo_pos - 1] & M_CRC0))
+ h |= 0x02;
+ }
+ // rddata on 4
+ if(!m_floppy || m_floppy->wpt_r())
+ h |= 0x08;
+ if(m_error)
+ h |= 0x20;
+ if(m_mode & 0x10) {
+ // write
+ if(m_fifo_pos == 0)
+ h |= 0xc0;
+ else if(m_fifo_pos == 1)
+ h |= 0x80;
+ } else {
+ // read
+ if(m_fifo_pos == 2)
+ h |= 0xc0;
+ else if(m_fifo_pos == 1)
+ h |= 0x80;
+ }
+ return h;
+ }
+
default:
- logerror("read %s\n", names[offset & 15]);
+ LOG("read %s\n", names[offset & 7]);
break;
}
return 0xff;
@@ -104,72 +223,347 @@ u8 swim2_device::read(offs_t offset)
void swim2_device::write(offs_t offset, u8 data)
{
- machine().debug_break();
+ sync();
+
+ u8 prev_mode = m_mode;
+
static const char *const names[] = {
"data", "mark", "crc", "param", "phases", "setup", "mode0", "mode1",
- "?8", "?9", "?a", "?b", "?c", "?d", "?e", "?f"
};
- switch(offset) {
- case 0x3: case 0xb: {
-#if 0
- static const char *const pname[16] = {
- "minct", "mult", "ssl", "sss", "sll", "sls", "rpt", "csls",
- "lsl", "lss", "lll", "lls", "late", "time0", "early", "time1"
- };
-#endif
+
+ switch(offset & 7) {
+ case 0:
+ if(fifo_push(data) && !m_error)
+ m_error |= 0x04;
+ break;
+
+ case 1:
+ if(fifo_push(M_MARK | data) && !m_error)
+ m_error |= 0x04;
+ break;
+
+ case 2:
+ if(fifo_push(M_CRC) && !m_error)
+ m_error |= 0x04;
+ break;
+
+ case 3: { // param
static const char *const pname[4] = {
"late", "time0", "early", "time1"
};
- logerror("param[%s] = %02x\n", pname[m_param_idx], data);
+ LOG("param[%s] = %02x\n", pname[m_param_idx], data);
m_param[m_param_idx] = data;
m_param_idx = (m_param_idx + 1) & 3;
break;
}
- case 0x4: {
+ case 4: { // phases
m_phases = data;
update_phases();
break;
}
- case 0x5: case 0xd:
+ case 5: // setup
m_setup = data;
-#if 0
- logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
- m_setup & 0x80 ? "on" : "off",
- m_setup & 0x40 ? "off" : "on",
+ m_sel35_cb((m_setup >> 1) & 1);
+ LOGSETUP("setup write=%s %s test=%s %s %s 3.5=%s %s\n",
+ m_setup & 0x40 ? "gcr" : "mfm",
m_setup & 0x20 ? "ibm" : "apple",
m_setup & 0x10 ? "on" : "off",
m_setup & 0x08 ? "fclk/2" : "fclk",
m_setup & 0x04 ? "gcr" : "mfm",
m_setup & 0x02 ? "off" : "on",
- m_setup & 0x01 ? "hdsel" : "q3");
-#endif
- logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
- m_setup & 0x80 ? "on" : "off",
- m_setup & 0x40 ? "off" : "on",
- m_setup & 0x20 ? "ibm" : "apple",
- m_setup & 0x10 ? "on" : "off",
- m_setup & 0x08 ? "fclk/2" : "fclk",
- m_setup & 0x04 ? "gcr" : "mfm",
- m_setup & 0x02 ? "off" : "on",
- m_setup & 0x01 ? "hdsel" : "q3");
+ m_setup & 0x01 ? "wrinvert" : "wrdirect");
break;
- case 0x6:
+ case 6: // mode clear
m_mode &= ~data;
m_mode |= 0x40;
m_param_idx = 0;
show_mode();
+ if(data & 0x10)
+ m_dat1byte_cb((m_fifo_pos != 0) ? 1 : 0);
break;
- case 0x7:
+ case 7: // mode set
m_mode |= data;
show_mode();
+ if(data & 0x10)
+ m_dat1byte_cb((m_fifo_pos != 2) ? 1 : 0);
break;
default:
- logerror("write %s, %02x\n", names[offset], data);
+ LOG("write %s, %02x\n", names[offset & 7], data);
break;
}
+
+ if(m_mode & 0x01)
+ fifo_clear();
+
+ if((m_mode ^ prev_mode) & 0x86)
+ m_devsel_cb(m_mode & 0x80 ? (m_mode >> 1) & 3 : 0);
+ if((m_mode ^ prev_mode) & 0x20)
+ m_hdsel_cb((m_mode >> 5) & 1);
+
+ if((m_mode & 0x18) == 0x18 && ((prev_mode & 0x18) != 0x18)) {
+ // Entering write mode
+ m_current_bit = 0;
+ LOG("%s write start %s %s floppy=%p\n", machine().time().to_string(), m_setup & 0x40 ? "gcr" : "mfm", m_setup & 0x08 ? "fclk/2" : "fclk", m_floppy);
+ m_flux_write_start = m_last_sync;
+ m_flux_write_count = 0;
+
+ } else if((prev_mode & 0x18) == 0x18 && (m_mode & 0x18) != 0x18) {
+ // Exiting write mode
+ flush_write();
+ m_flux_write_start = 0;
+ m_current_bit = 0xff;
+ m_half_cycles_before_change = 0;
+ LOG("%s write end\n", machine().time().to_string());
+ }
+
+ if((m_mode & 0x18) == 0x08 && ((prev_mode & 0x18) != 0x08)) {
+ // Entering read mode
+ m_current_bit = 0;
+ m_sr = 0;
+ m_mfm_sync_counter = 0;
+ LOG("%s read start %s %s floppy=%p\n", machine().time().to_string(), m_setup & 0x04 ? "gcr" : "mfm", m_setup & 0x08 ? "fclk/2" : "fclk", m_floppy);
+
+ m_pll.reset(machine().time());
+ static const int cycles_per_cell[4] = { 16, 31, 31, 63 };
+
+ m_pll.set_clock(attotime::from_ticks(cycles_per_cell[(m_setup >> 2) & 3], clock()));
+ LOG("PLL read clock %s\n", attotime::from_ticks(cycles_per_cell[(m_setup >> 2) & 3], clock()).to_string());
+
+ } else if((prev_mode & 0x18) == 0x08 && (m_mode & 0x18) != 0x08) {
+ // Exiting read mode
+ flush_write();
+ m_current_bit = 0xff;
+ m_half_cycles_before_change = 0;
+ LOG("%s read end\n", machine().time().to_string());
+ }
+}
+
+void swim2_device::crc_clear()
+{
+ m_crc = 0xcdb4;
}
+void swim2_device::crc_update(int bit)
+{
+ if((m_crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ m_crc = (m_crc << 1) ^ 0x1021;
+ else
+ m_crc = m_crc << 1;
+
+}
+
+u64 swim2_device::time_to_cycles(const attotime &tm) const
+{
+ return tm.as_ticks(clock());
+}
+
+attotime swim2_device::cycles_to_time(u64 cycles) const
+{
+ return attotime::from_ticks(cycles, clock());
+}
+
+void swim2_device::fifo_clear()
+{
+ m_fifo_pos = 0;
+ m_dat1byte_cb((m_mode & 0x10) ? 1 : 0);
+ crc_clear();
+}
+
+bool swim2_device::fifo_push(u16 data)
+{
+ if(m_fifo_pos == 2)
+ return true;
+ m_fifo[m_fifo_pos ++] = data;
+ if(m_mode & 0x10) {
+ // write
+ if(m_fifo_pos == 2)
+ m_dat1byte_cb(0);
+ } else {
+ // read
+ if(m_fifo_pos == 1)
+ m_dat1byte_cb(1);
+ }
+ return false;
+}
+
+u16 swim2_device::fifo_pop()
+{
+ if(m_fifo_pos == 0)
+ return 0xffff;
+ u16 r = m_fifo[0];
+ m_fifo[0] = m_fifo[1];
+ m_fifo_pos --;
+ if(m_mode & 0x10) {
+ // write
+ if(m_fifo_pos == 1)
+ m_dat1byte_cb(1);
+ } else {
+ // read
+ if(m_fifo_pos == 0)
+ m_dat1byte_cb(0);
+ }
+ return r;
+}
+
+void swim2_device::sync()
+{
+ u64 next_sync = time_to_cycles(machine().time());
+ if(!(m_mode & 0x08)) {
+ m_last_sync = next_sync;
+ return;
+ }
+
+ if(m_mode & 0x10) {
+ // We count in half-cycles but only toggle write on full cycles
+ u32 cycles = (next_sync - m_last_sync) << 1;
+
+ // Write mode
+ while(cycles) {
+ if(m_half_cycles_before_change) {
+ if(cycles >= m_half_cycles_before_change) {
+ cycles -= m_half_cycles_before_change;
+ m_half_cycles_before_change = 0;
+ } else {
+ m_half_cycles_before_change -= cycles;
+ cycles = 0;
+ break;
+ }
+ }
+
+ if(m_tss_output & 0xc) {
+ bool bit;
+ if(m_tss_output & 8) {
+ bit = (m_tss_output >> 1) & 1;
+ m_tss_output &= ~0xa;
+ } else {
+ bit = m_tss_output & 1;
+ m_tss_output = 0;
+ }
+ if(bit) {
+ if(m_flux_write_count == m_flux_write.size())
+ flush_write(next_sync - (cycles >> 1));
+ m_flux_write[m_flux_write_count ++] = next_sync - (cycles >> 1);
+ m_half_cycles_before_change = 63;
+ } else
+ m_half_cycles_before_change = m_setup & 0x40 ? 63 : 31;
+ if(m_setup & 8)
+ m_half_cycles_before_change <<= 1;
+ continue;
+ }
+ if(m_current_bit == 0xff)
+ fatalerror("Sequence break on write\n");
+
+ if(m_current_bit == 0) {
+ if(m_sr & M_CRC)
+ m_sr = m_crc >> 8;
+ else {
+ u16 r = fifo_pop();
+ if(r == 0xffff && !m_error) {
+ m_error |= 0x01;
+ flush_write();
+ m_current_bit = 0xff;
+ m_half_cycles_before_change = 0;
+ m_mode &= ~8;
+ logerror("write end on underrun\n");
+ break;
+ }
+ if(r & M_CRC)
+ m_sr = M_CRC | (m_crc >> 8);
+ else
+ m_sr = r & (M_MARK | M_CRC | 0xff);
+ }
+ m_current_bit = 8;
+ if(m_sr & M_MARK)
+ crc_clear();
+ }
+ m_current_bit --;
+ int bit = (m_sr >> m_current_bit) & 1;
+ if(!(m_sr & M_MARK))
+ crc_update(bit);
+ m_tss_sr = (m_tss_sr << 1) | bit;
+ if(m_setup & 0x40)
+ m_tss_output = 4 | bit;
+ else {
+ static const u8 tss[4] = { 5, 0xd, 4, 5 };
+ if((m_sr & M_MARK) && ((m_tss_sr & 0xf) == 8))
+ m_tss_output = 0xc;
+ else
+ m_tss_output = tss[m_tss_sr & 3];
+ }
+
+ continue;
+ }
+ } else {
+ attotime limit = machine().time();
+ if(m_setup & 0x04) {
+ // GCR mode
+ for(;;) {
+ attotime when;
+ int bit = m_pll.get_next_bit(when, m_floppy, limit);
+ if(bit == -1)
+ break;
+ m_sr = ((m_sr << 1) | bit) & 0xff;
+ if(m_sr & 0x80) {
+ if(fifo_push(m_sr) && !m_error)
+ m_error |= 0x01;
+ m_sr = 0;
+ }
+ }
+ } else {
+ // MFM mode
+ for(;;) {
+ attotime when;
+ int bit = m_pll.get_next_bit(when, m_floppy, limit);
+ if(bit == -1)
+ break;
+ if(m_mfm_sync_counter < 64) {
+ if(bit != (m_mfm_sync_counter & 1))
+ m_mfm_sync_counter ++;
+ else
+ m_mfm_sync_counter = 0;
+ } else {
+ if(m_mfm_sync_counter == 64 && bit)
+ m_mfm_sync_counter --;
+ else {
+ if(m_mfm_sync_counter == 65 || m_mfm_sync_counter == 81) {
+ m_tss_sr = 0xff;
+ m_sr = 0;
+ }
+ if(m_mfm_sync_counter & 1) {
+ m_sr |= bit << (((96 - m_mfm_sync_counter) >> 1) & 7);
+ crc_update(bit);
+ }
+ m_tss_sr = (m_tss_sr << 1) | bit;
+ if((m_tss_sr & 0xf) == 1 && !(m_mfm_sync_counter & 1))
+ m_sr |= M_MARK;
+
+ m_mfm_sync_counter ++;
+ if(m_mfm_sync_counter == 80) {
+ if(!(m_sr & M_MARK))
+ m_mfm_sync_counter = 0;
+ else {
+ crc_clear();
+ if(fifo_push(m_sr) && !m_error)
+ m_error |= 0x01;
+ }
+ } else if(m_mfm_sync_counter == 96) {
+ m_mfm_sync_counter -= 16;
+ if(m_sr & M_MARK)
+ crc_clear();
+ else if(!m_crc)
+ m_sr |= M_CRC0;
+ if(fifo_push(m_sr) && !m_error)
+ m_error |= 0x01;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_last_sync = next_sync;
+}
diff --git a/src/devices/machine/swim2.h b/src/devices/machine/swim2.h
index dc729fe533e..bab440e4ec9 100644
--- a/src/devices/machine/swim2.h
+++ b/src/devices/machine/swim2.h
@@ -11,6 +11,7 @@
#pragma once
#include "applefdintf.h"
+#include "fdc_pll.h"
//**************************************************************************
@@ -30,17 +31,44 @@ public:
virtual void set_floppy(floppy_image_device *floppy) override;
virtual floppy_image_device *get_floppy() const override;
+ virtual void sync() override;
+
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
+ enum {
+ M_MARK = 0x100,
+ M_CRC = 0x200,
+ M_CRC0 = 0x400
+ };
+
floppy_image_device *m_floppy;
u8 m_param[4];
- u8 m_mode, m_setup, m_param_idx;
+ u8 m_mode, m_setup, m_error, m_param_idx, m_fifo_pos, m_tss_sr, m_tss_output, m_current_bit;
+ u16 m_fifo[2], m_sr;
+ u16 m_crc, m_mfm_sync_counter;
+ u32 m_half_cycles_before_change;
+
+ u64 m_last_sync;
+ u64 m_flux_write_start;
+ std::array<u64, 32> m_flux_write;
+ u32 m_flux_write_count;
+ fdc_pll_t m_pll;
+
+ u64 time_to_cycles(const attotime &tm) const;
+ attotime cycles_to_time(u64 cycles) const;
+
+ void fifo_clear();
+ bool fifo_push(u16 data);
+ u16 fifo_pop();
+ void flush_write(u64 when = 0);
void show_mode() const;
+
+ void crc_update(int bit);
+ void crc_clear();
};
DECLARE_DEVICE_TYPE(SWIM2, swim2_device)
diff --git a/src/devices/machine/swim3.cpp b/src/devices/machine/swim3.cpp
index e194deb2f17..129f0f4a261 100644
--- a/src/devices/machine/swim3.cpp
+++ b/src/devices/machine/swim3.cpp
@@ -12,48 +12,83 @@
DEFINE_DEVICE_TYPE(SWIM3, swim3_device, "swim3", "Apple SWIM3 (Sander/Wozniak Integrated Machine) version 3 floppy controller")
swim3_device::swim3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- applefdintf_device(mconfig, SWIM3, tag, owner, clock)
+ applefdintf_device(mconfig, SWIM3, tag, owner, clock),
+ m_irq_cb(*this),
+ m_drq_cb(*this)
{
}
void swim3_device::device_start()
{
applefdintf_device::device_start();
+
+ m_timer = timer_alloc(FUNC(swim3_device::update), this);
+
save_item(NAME(m_mode));
save_item(NAME(m_setup));
- save_item(NAME(m_param_idx));
save_item(NAME(m_param));
+ save_item(NAME(m_irq));
+ save_item(NAME(m_imask));
+ save_item(NAME(m_state));
+ save_item(NAME(m_step));
+ save_item(NAME(m_error));
+ save_item(NAME(m_cur_track));
+ save_item(NAME(m_cur_sector));
+ save_item(NAME(m_cur_format));
+ save_item(NAME(m_sect1));
+ save_item(NAME(m_xfer));
+ save_item(NAME(m_fifo));
+ save_item(NAME(m_fifo_pos));
+ save_item(NAME(m_drq_write));
}
void swim3_device::device_reset()
{
applefdintf_device::device_reset();
- m_mode = 0x40;
- m_setup = 0x00;
- m_param_idx = 0;
- memset(m_param, 0, sizeof(m_param));
m_floppy = nullptr;
+ m_cur_live.state = L_IDLE;
+ m_cur_live.tm = attotime::never;
+
+ m_mode = 0x00;
+ m_setup = 0x00;
+ m_param = 0x77;
+ m_irq = 0;
+ m_imask = 0;
+ m_state = S_IDLE;
+ m_step = 0;
+ m_error = 0;
+ m_cur_track = 0;
+ m_cur_sector = 0;
+ m_cur_format = 0;
+ m_sect1 = 0xff;
+ m_xfer = 0;
+
+ m_fifo[0] = m_fifo[1] = 0;
+ m_fifo_pos = 0;
+ m_drq_write = false;
+
m_devsel_cb(0);
m_sel35_cb(true);
m_hdsel_cb(false);
}
-void swim3_device::device_timer(emu_timer &, device_timer_id, int, void *)
-{
-}
-
void swim3_device::set_floppy(floppy_image_device *floppy)
{
if(m_floppy == floppy)
return;
if(m_floppy)
- m_floppy->mon_w(true);
+ m_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
+
+ logerror("floppy %s\n", floppy ? floppy->tag() : "-");
+
m_floppy = floppy;
- if(m_mode & 0x80)
- m_floppy->mon_w(false);
update_phases();
+ m_hdsel_cb((m_mode >> 5) & 1);
+
+ if(m_floppy)
+ m_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&swim3_device::index_callback, this));
}
floppy_image_device *swim3_device::get_floppy() const
@@ -63,36 +98,77 @@ floppy_image_device *swim3_device::get_floppy() const
void swim3_device::show_mode() const
{
- logerror("mode%s %s hdsel=%c %c%s %c%c%s\n",
- m_mode & 0x80 ? " motoron" : "",
- m_mode & 0x40 ? "ism" : "iwm",
+ logerror("mode%s%s hdsel=%c %c%s %c%c%s\n",
+ m_mode & 0x80 ? " step" : "",
+ m_mode & 0x40 ? " format" : "",
m_mode & 0x20 ? '1' : '0',
m_mode & 0x10 ? 'w' : 'r',
- m_mode & 0x08 ? " action" : "",
- m_mode & 0x04 ? 'a' : '-',
- m_mode & 0x02 ? 'b' : '-',
- m_mode & 0x01 ? " clear" : "");
+ m_mode & 0x08 ? " go" : "",
+ m_mode & 0x04 ? 'b' : '-',
+ m_mode & 0x02 ? 'a' : '-',
+ m_mode & 0x01 ? " irq" : "");
}
u8 swim3_device::read(offs_t offset)
{
static const char *const names[] = {
- "?0", "?1", "?2", "?3", "?4", "?5", "?6", "?7",
- "data", "mark", "crc", "param", "phases", "setup", "status", "handshake"
+ "data", "timer", "error", "param", "phases", "setup", "?6", "handshake",
+ "interrupt", "step", "track", "sector", "format", "sect1", "xfer", "imask"
};
+
switch(offset) {
- case 0x3: case 0xb: {
- u8 r = m_param[m_param_idx];
- m_param_idx = (m_param_idx + 1) & 15;
+ case 0x2: { // error
+ u8 r = m_error;
+ m_error = 0;
return r;
}
- case 0x4: case 0xc:
- return m_phases;
- case 0x5: case 0xd:
+
+ case 0x3: // param
+ return m_param;
+
+ case 0x4: // phases
+ return m_phases & 0xf;
+
+ case 0x5: // setup
return m_setup;
- case 0xe:
+
+ case 0x6: // mode
return m_mode;
+
+ case 0x7: { // handshake
+ u8 h = 0;
+ if(!m_floppy || m_floppy->wpt_r())
+ h |= 0x0c;
+ logerror("hand %02x\n", h);
+ return h;
+ };
+
+ case 0x8: {
+ u8 res = m_irq;
+ m_irq = 0;
+ update_irq();
+ return res;
+ }
+
+ case 0xa:
+ return m_cur_track;
+
+ case 0xb:
+ return m_cur_sector;
+
+ case 0xc:
+ return m_cur_format;
+
+ case 0xd:
+ return m_sect1;
+
+ case 0xe:
+ return m_xfer;
+
+ case 0xf:
+ return m_imask;
+
default:
logerror("read %s\n", names[offset & 15]);
break;
@@ -102,72 +178,553 @@ u8 swim3_device::read(offs_t offset)
void swim3_device::write(offs_t offset, u8 data)
{
- machine().debug_break();
+ u8 prev_mode = m_mode;
+
static const char *const names[] = {
- "data", "mark", "crc", "param", "phases", "setup", "mode0", "mode1",
- "?8", "?9", "?a", "?b", "?c", "?d", "?e", "?f"
+ "data", "timer", "error", "param", "phases", "setup", "mode0", "mode1",
+ "?8", "step", "track", "sector", "gap", "sect1", "xfer", "imask"
};
switch(offset) {
- case 0x3: case 0xb: {
-#if 0
- static const char *const pname[16] = {
- "minct", "mult", "ssl", "sss", "sll", "sls", "rpt", "csls",
- "lsl", "lss", "lll", "lls", "late", "time0", "early", "time1"
- };
-#endif
- static const char *const pname[4] = {
- "late", "time0", "early", "time1"
- };
- logerror("param[%s] = %02x\n", pname[m_param_idx], data);
- m_param[m_param_idx] = data;
- m_param_idx = (m_param_idx + 1) & 3;
+ case 0x3: // param
+ m_param = data;
+ logerror("precompensation late=%x early=%x\n", m_param >> 4, m_param & 0xf);
break;
- }
- case 0x4: {
- m_phases = data;
+
+ case 0x4: { // phases
+ m_phases = data | 0xf0;
update_phases();
break;
}
- case 0x5: case 0xd:
+ case 0x5: // setup
m_setup = data;
-#if 0
- logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
- m_setup & 0x80 ? "on" : "off",
- m_setup & 0x40 ? "off" : "on",
- m_setup & 0x20 ? "ibm" : "apple",
- m_setup & 0x10 ? "on" : "off",
- m_setup & 0x08 ? "fclk/2" : "fclk",
- m_setup & 0x04 ? "gcr" : "mfm",
- m_setup & 0x02 ? "off" : "on",
- m_setup & 0x01 ? "hdsel" : "q3");
-#endif
- logerror("setup timer=%s tsm=%s %s ecm=%s %s %s 3.5=%s %s\n",
- m_setup & 0x80 ? "on" : "off",
- m_setup & 0x40 ? "off" : "on",
+ m_sel35_cb((m_setup >> 1) & 1);
+ logerror("setup write=%s %s nogcrconv=%s %s %s%s %s\n",
+ m_setup & 0x40 ? "gcr" : "mfm",
m_setup & 0x20 ? "ibm" : "apple",
m_setup & 0x10 ? "on" : "off",
m_setup & 0x08 ? "fclk/2" : "fclk",
m_setup & 0x04 ? "gcr" : "mfm",
- m_setup & 0x02 ? "off" : "on",
- m_setup & 0x01 ? "hdsel" : "q3");
+ m_setup & 0x02 ? " copy" : "",
+ m_setup & 0x01 ? "wrinvert" : "wrdirect");
break;
- case 0x6:
+ case 0x6: // mode clear
m_mode &= ~data;
- m_mode |= 0x40;
- m_param_idx = 0;
show_mode();
break;
- case 0x7:
+ case 0x7: // mode set
m_mode |= data;
show_mode();
break;
+ case 0x9: // step
+ logerror("load step %02x\n", data);
+ m_step = data;
+ break;
+
+ case 0xc:
+ m_gap = data;
+ break;
+
+ case 0xd:
+ m_sect1 = data;
+ break;
+
+ case 0xe:
+ m_xfer = data;
+ break;
+
+ case 0xf:
+ m_imask = data;
+ logerror("imask%s%s%s%s%s\n",
+ m_imask & 0x10 ? " sense" : " -",
+ m_imask & 0x08 ? " sector" : " -",
+ m_imask & 0x04 ? " id" : " -",
+ m_imask & 0x02 ? " step" : " -",
+ m_imask & 0x01 ? " timer" : " -");
+ update_irq();
+ break;
+
default:
logerror("write %s, %02x\n", names[offset], data);
break;
}
+
+ if((m_mode ^ prev_mode) & 0x86)
+ m_devsel_cb((m_mode >> 1) & 3);
+ if((m_mode ^ prev_mode) & 0x20)
+ m_hdsel_cb((m_mode >> 5) & 1);
+
+ if((m_mode & 0x80) && m_state == S_IDLE) {
+ logerror("%s stepping start count=%02x floppy=%s\n", machine().time().to_string(), m_step, m_floppy ? m_floppy->tag() : "-");
+ m_state = S_STEP;
+ run(false, false);
+ }
+
+ if((m_mode & 0x08) && m_state == S_IDLE) {
+ logerror("%s read start %s %s s1=%02x xfer=%d floppy=%s\n", machine().time().to_string(), m_setup & 0x04 ? "gcr" : "mfm", m_setup & 0x08 ? "fclk/2" : "fclk", m_sect1, m_xfer, m_floppy ? m_floppy->tag() : "-");
+ m_state = S_ID;
+ run(false, false);
+ }
+
+ if(!(m_mode & 0x88) && m_state != S_IDLE) {
+ logerror("%s read/step stopped\n", machine().time().to_string());
+ m_drq_write = false;
+ live_abort();
+ m_state = S_IDLE;
+ }
+}
+
+void swim3_device::update_irq()
+{
+ logerror("irq %02x m %02x -> %02x\n", m_irq, m_imask, m_irq & m_imask);
+ m_irq_cb((m_irq & m_imask) != 0);
+}
+
+void swim3_device::update_drq()
+{
+ if(m_drq_write)
+ m_drq_cb(m_fifo_pos != 2);
+ else
+ m_drq_cb(m_fifo_pos != 0);
+}
+
+void swim3_device::index_callback(floppy_image_device *floppy, int state)
+{
+ if(state) {
+ sync();
+ run(false, true);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(swim3_device::update)
+{
+ sync();
+ run(true, false);
+}
+
+void swim3_device::delay(int cycles)
+{
+ m_timer->adjust(attotime::from_ticks(cycles, clock()));
+}
+
+void swim3_device::run(bool timeout, bool index)
+{
+ for(;;) {
+ if(m_cur_live.state != L_IDLE) {
+ live_run();
+ if(m_cur_live.state != L_IDLE)
+ return;
+ }
+
+ switch(m_state) {
+ case S_IDLE:
+ return;
+
+ case S_STEP:
+ if(!m_step) {
+ m_state = S_STEP_DONE;
+ break;
+ }
+
+ m_phases ^= 8;
+ update_phases();
+ m_state = S_STEP_1;
+ delay(4);
+ break;
+
+ case S_STEP_1:
+ if(!timeout)
+ return;
+
+ m_phases ^= 8;
+ update_phases();
+ m_state = S_STEP_0;
+ delay(2502);
+ break;
+
+ case S_STEP_0:
+ if(!timeout)
+ return;
+
+ m_step --;
+ m_state = S_STEP;
+ break;
+
+ case S_STEP_DONE:
+ m_state = S_IDLE;
+ m_mode &= 0x7f;
+ m_irq |= 0x02;
+ update_irq();
+ break;
+
+ case S_ID:
+ live_start(m_setup & 0x04 ? L_GCR_SEARCH_ID : L_MFM_SEARCH_ID);
+ return;
+ }
+ }
+}
+
+void swim3_device::checkpoint()
+{
+ m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
+ m_checkpoint_live = m_cur_live;
+}
+
+void swim3_device::rollback()
+{
+ m_cur_live = m_checkpoint_live;
}
+void swim3_device::live_delay(int state)
+{
+ m_cur_live.next_state = state;
+ m_timer->adjust(m_cur_live.tm - machine().time());
+}
+
+void swim3_device::sync()
+{
+ if(m_cur_live.state != L_IDLE && !m_cur_live.tm.is_never()) {
+ if(m_cur_live.tm > machine().time()) {
+ if(0)
+ logerror("%s: Rolling back and replaying (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
+ rollback();
+ live_run(machine().time());
+ m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
+ } else {
+ if(0)
+ logerror("%s: Committing (%s)\n", machine().time().to_string(), m_cur_live.tm.to_string());
+ m_cur_live.pll.commit(m_floppy, m_cur_live.tm);
+ if(m_cur_live.next_state != -1) {
+ m_cur_live.state = m_cur_live.next_state;
+ m_cur_live.next_state = -1;
+ }
+ if(m_cur_live.state == L_IDLE) {
+ m_cur_live.pll.stop_writing(m_floppy, m_cur_live.tm);
+ m_cur_live.tm = attotime::never;
+ }
+ }
+ m_cur_live.next_state = -1;
+ checkpoint();
+ }
+}
+
+
+void swim3_device::live_abort()
+{
+ if(!m_cur_live.tm.is_never() && m_cur_live.tm > machine().time()) {
+ rollback();
+ live_run(machine().time());
+ }
+
+ m_cur_live.pll.stop_writing(m_floppy, m_cur_live.tm);
+ m_cur_live.tm = attotime::never;
+ m_cur_live.state = L_IDLE;
+ m_cur_live.next_state = -1;
+}
+
+bool swim3_device::read_one_bit(const attotime &limit)
+{
+ int bit = m_cur_live.pll.get_next_bit(m_cur_live.tm, m_floppy, limit);
+ if(bit < 0)
+ return true;
+ m_cur_live.shift_reg = (m_cur_live.shift_reg << 1) | bit;
+ m_cur_live.bit_counter++;
+ if(m_cur_live.data_separator_phase) {
+ m_cur_live.data_reg = (m_cur_live.data_reg << 1) | bit;
+ if((m_cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ m_cur_live.crc = (m_cur_live.crc << 1) ^ 0x1021;
+ else
+ m_cur_live.crc = m_cur_live.crc << 1;
+ }
+ m_cur_live.data_separator_phase = !m_cur_live.data_separator_phase;
+ return false;
+}
+
+bool swim3_device::write_one_bit(const attotime &limit)
+{
+ bool bit = m_cur_live.shift_reg & 0x8000;
+ if(m_cur_live.pll.write_next_bit(bit, m_cur_live.tm, m_floppy, limit))
+ return true;
+ if(m_cur_live.bit_counter & 1) {
+ if((m_cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ m_cur_live.crc = (m_cur_live.crc << 1) ^ 0x1021;
+ else
+ m_cur_live.crc = m_cur_live.crc << 1;
+ }
+ m_cur_live.shift_reg = m_cur_live.shift_reg << 1;
+ m_cur_live.bit_counter--;
+ return false;
+}
+
+
+void swim3_device::live_start(int state, bool start_writing)
+{
+ m_cur_live.tm = machine().time();
+ m_cur_live.state = state;
+ m_cur_live.next_state = -1;
+ m_cur_live.shift_reg = 0;
+ m_cur_live.crc = 0xffff;
+ m_cur_live.bit_counter = 0;
+ m_cur_live.data_separator_phase = false;
+ m_cur_live.data_reg = 0;
+
+ static const int cycles_per_cell[4] = { 16, 31, 31, 63 };
+ m_cur_live.pll.reset(m_cur_live.tm);
+ m_cur_live.pll.set_clock(attotime::from_ticks(cycles_per_cell[(m_setup >> 2) & 3], clock()));
+ if(start_writing)
+ m_cur_live.pll.start_writing(machine().time());
+
+ logerror("PLL %s clock %s\n", start_writing ? "write" : "read", attotime::from_ticks(cycles_per_cell[(m_setup >> 2) & 3], clock()).to_string());
+
+ m_checkpoint_live = m_cur_live;
+
+ live_run();
+}
+
+u8 swim3_device::dma_r()
+{
+ if(m_fifo_pos == 0) {
+ m_error |= 0x04;
+ live_abort();
+ m_state = S_IDLE;
+ return 0;
+ }
+ u8 r = m_fifo[0];
+ m_fifo[0] = m_fifo[1];
+ m_fifo_pos--;
+ update_drq();
+ return r;
+}
+
+void swim3_device::fifo_push(u8 data)
+{
+ if(m_fifo_pos == 2) {
+ m_error |= 0x01;
+ live_abort();
+ m_state = S_IDLE;
+ } else {
+ m_fifo[m_fifo_pos++] = data;
+ update_drq();
+ }
+}
+
+void swim3_device::live_run(attotime limit)
+{
+ if(m_cur_live.state == L_IDLE || m_cur_live.next_state != -1)
+ return;
+
+ if(limit == attotime::never) {
+ if(m_floppy)
+ limit = m_floppy->time_next_index();
+ if(limit == attotime::never) {
+ // Happens when there's no disk or if the swim3 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);
+ m_timer->adjust(attotime::from_msec(1));
+ }
+ }
+
+ for(;;) {
+ switch(m_cur_live.state) {
+ case L_MFM_SEARCH_ID:
+ if(read_one_bit(limit))
+ return;
+
+ if((m_cur_live.bit_counter & 1) != (m_cur_live.shift_reg & 1)) {
+ if(m_cur_live.bit_counter < 64) {
+ m_cur_live.bit_counter = 0;
+ m_cur_live.data_separator_phase = false;
+ } else {
+ m_cur_live.bit_counter = 1;
+ m_cur_live.state = L_MFM_SCAN_ID;
+ break;
+ }
+ }
+ if(!(m_cur_live.bit_counter & 1))
+ m_cur_live.crc = 0xffff;
+
+ // logerror("pre counter %02d sr %04x data %02x crc %04x\n", m_cur_live.bit_counter, m_cur_live.shift_reg, m_cur_live.data_reg, m_cur_live.crc);
+ break;
+
+ case L_MFM_SCAN_ID:
+ if(read_one_bit(limit))
+ return;
+ if((m_cur_live.bit_counter == 16 || m_cur_live.bit_counter == 32 || m_cur_live.bit_counter == 48) && m_cur_live.shift_reg != 0x4489) {
+ m_cur_live.bit_counter = 0;
+ m_cur_live.state = L_MFM_SEARCH_ID;
+ break;
+ }
+ if(m_cur_live.bit_counter == 64 && m_cur_live.shift_reg != 0x5554) { // fe
+ m_cur_live.bit_counter = 0;
+ m_cur_live.state = L_MFM_SEARCH_ID;
+ break;
+ }
+
+ if(m_cur_live.bit_counter == 64) {
+ m_cur_live.bit_counter = 0;
+ live_delay(L_MFM_READ_ID);
+ return;
+ }
+
+ // logerror("post counter %02d sr %04x data %02x crc %04x\n", m_cur_live.bit_counter, m_cur_live.shift_reg, m_cur_live.data_reg, m_cur_live.crc);
+ break;
+
+ case L_MFM_READ_ID:
+ if(!m_cur_live.bit_counter)
+ m_cur_sector &= 0x7f;
+
+ if(read_one_bit(limit))
+ return;
+
+ if(!(m_cur_live.bit_counter & 0xf)) {
+ live_delay(L_MFM_READ_ID_BYTE);
+ return;
+ }
+ break;
+
+ case L_MFM_READ_ID_BYTE:
+ m_cur_live.state = L_MFM_READ_ID;
+ switch(m_cur_live.bit_counter >> 4) {
+ case 1:
+ m_cur_track = m_cur_live.data_reg & 0x7f;
+ break;
+ case 2:
+ m_cur_track |= (m_cur_live.data_reg & 1) << 7;
+ break;
+ case 3:
+ m_cur_sector = m_cur_live.data_reg & 0x3f;
+ break;
+ case 4:
+ m_cur_format = m_cur_live.data_reg;
+ break;
+ case 6:
+ m_cur_live.bit_counter = 0;
+ m_cur_live.state = L_MFM_SEARCH_ID;
+ if(m_cur_live.crc == 0) {
+ logerror("sector id found, track=%02d head=%d sector=%02d\n", m_cur_track & 0x7f, m_cur_track >> 7, m_cur_sector & 0x3f);
+ m_cur_sector |= 0x80;
+ m_irq |= 0x04;
+ update_irq();
+ if(!(m_sect1 & 0x80) && ((m_sect1 & 0x40) || (m_sect1 & 0x3f) == (m_cur_sector & 0x3f))) {
+ logerror("sector matches, reading data\n");
+ m_cur_live.state = L_MFM_SEARCH_DATA;
+ }
+ } else {
+ checkpoint();
+ m_error |= 0x40;
+ live_abort();
+ m_state = S_IDLE;
+ return;
+ }
+ checkpoint();
+ break;
+ }
+ break;
+
+ case L_MFM_SEARCH_DATA:
+ if(read_one_bit(limit))
+ return;
+
+ if((m_cur_live.bit_counter & 1) != (m_cur_live.shift_reg & 1)) {
+ if(m_cur_live.bit_counter < 64) {
+ m_cur_live.bit_counter = 0;
+ m_cur_live.data_separator_phase = false;
+ } else {
+ m_cur_live.bit_counter = 1;
+ m_cur_live.state = L_MFM_SCAN_DATA;
+ break;
+ }
+ }
+ if(!(m_cur_live.bit_counter & 1))
+ m_cur_live.crc = 0xffff;
+
+ // logerror("pre counter %02d sr %04x data %02x crc %04x\n", m_cur_live.bit_counter, m_cur_live.shift_reg, m_cur_live.data_reg, m_cur_live.crc);
+ break;
+
+ case L_MFM_SCAN_DATA:
+ if(read_one_bit(limit))
+ return;
+ if((m_cur_live.bit_counter == 16 || m_cur_live.bit_counter == 32 || m_cur_live.bit_counter == 48) && m_cur_live.shift_reg != 0x4489) {
+ m_cur_live.bit_counter = 0;
+ m_cur_live.state = L_MFM_SEARCH_DATA;
+ break;
+ }
+
+ if(m_cur_live.bit_counter == 64 && m_cur_live.shift_reg != 0x5545) { // fb
+ m_cur_live.bit_counter = 0;
+ m_cur_live.state = L_MFM_SEARCH_DATA;
+ break;
+ }
+
+ if(m_cur_live.bit_counter == 64) {
+ m_cur_live.bit_counter = 0;
+ live_delay(L_MFM_READ_DATA);
+ return;
+ }
+
+ // logerror("post counter %02d sr %04x data %02x crc %04x\n", m_cur_live.bit_counter, m_cur_live.shift_reg, m_cur_live.data_reg, m_cur_live.crc);
+ break;
+
+ case L_MFM_READ_DATA:
+ if(!m_cur_live.bit_counter)
+ m_cur_sector &= 0x7f;
+
+ if(read_one_bit(limit))
+ return;
+
+ if(!(m_cur_live.bit_counter & 0xf)) {
+ live_delay(L_MFM_READ_DATA_BYTE);
+ return;
+ }
+ break;
+
+ case L_MFM_READ_DATA_BYTE:
+ m_cur_live.state = L_MFM_READ_DATA;
+
+ if(m_cur_live.bit_counter <= 512*16) {
+ fifo_push(m_cur_live.data_reg);
+ if(m_error)
+ return;
+ }
+
+ if(m_cur_live.bit_counter == 514*16) {
+ if(m_cur_live.crc == 0) {
+ logerror("sector read done, crc ok\n");
+ m_xfer --;
+ if(m_xfer == 0) {
+ m_irq |= 0x08;
+ m_mode &= ~8;
+ live_abort();
+ m_state = S_IDLE;
+ update_irq();
+ return;
+ }
+
+ m_cur_live.state = L_MFM_SEARCH_DATA;
+
+ } else {
+ checkpoint();
+ m_error |= 0x80;
+ m_mode &= ~8;
+ live_abort();
+ m_state = S_IDLE;
+ return;
+ }
+ checkpoint();
+ break;
+ }
+ break;
+
+ case L_GCR_SEARCH_ID:
+ logerror("gcr search id\n");
+ exit(0);
+ }
+ }
+}
diff --git a/src/devices/machine/swim3.h b/src/devices/machine/swim3.h
index 6e353dc9740..61e280850e0 100644
--- a/src/devices/machine/swim3.h
+++ b/src/devices/machine/swim3.h
@@ -11,7 +11,7 @@
#pragma once
#include "applefdintf.h"
-
+#include "machine/fdc_pll.h"
//**************************************************************************
// TYPE DEFINITIONS
@@ -24,21 +24,97 @@ public:
// construction/destruction
swim3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ auto irq_cb() { return m_irq_cb.bind(); }
+ auto drq_cb() { return m_drq_cb.bind(); }
+
virtual u8 read(offs_t offset) override;
virtual void write(offs_t offset, u8 data) override;
+ // For direct dma access
+ u8 dma_r();
+ void dma_w(u8 data);
+
virtual void set_floppy(floppy_image_device *floppy) override;
virtual floppy_image_device *get_floppy() const override;
+ virtual void sync() override;
+
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update);
private:
+ enum {
+ S_IDLE,
+
+ S_STEP,
+ S_STEP_1,
+ S_STEP_0,
+ S_STEP_DONE,
+
+ S_ID,
+ };
+
+ enum {
+ L_IDLE,
+
+ L_GCR_SEARCH_ID,
+
+ L_MFM_SEARCH_ID,
+ L_MFM_SCAN_ID,
+ L_MFM_READ_ID,
+ L_MFM_READ_ID_BYTE,
+
+ L_MFM_SEARCH_DATA,
+ L_MFM_SCAN_DATA,
+ L_MFM_READ_DATA,
+ L_MFM_READ_DATA_BYTE,
+ };
+
+ struct live_info {
+ attotime tm;
+ fdc_pll_t pll;
+ int state, next_state;
+ u16 shift_reg;
+ u16 crc;
+ int bit_counter;
+ bool data_separator_phase, data_bit_context;
+ uint8_t data_reg;
+ };
+
+ devcb_write_line m_irq_cb, m_drq_cb;
+ emu_timer *m_timer;
floppy_image_device *m_floppy;
- u8 m_param[4];
- u8 m_mode, m_setup, m_param_idx;
+
+ live_info m_cur_live, m_checkpoint_live;
+
+ u8 m_param;
+ u8 m_mode, m_setup, m_irq, m_imask, m_step, m_error;
+ u8 m_cur_track, m_cur_sector, m_cur_format;
+ u8 m_gap, m_sect1, m_xfer, m_fifo[2], m_fifo_pos;
+
+ bool m_drq_write;
+
+ int m_state;
+
+ void update_irq();
+ void update_drq();
+ void index_callback(floppy_image_device *floppy, int state);
+ void run(bool timeout, bool index);
+ void delay(int);
+ void checkpoint();
+ void rollback();
+ void live_abort();
+ void live_delay(int state);
+ bool read_one_bit(const attotime &limit);
+ bool write_one_bit(const attotime &limit);
+ void live_start(int state, bool start_writing = false);
+ void live_run(attotime limit = attotime::never);
+
+ void fifo_push(u8 data);
+ u8 fifo_pop();
void show_mode() const;
};
diff --git a/src/devices/machine/swtpc8212.cpp b/src/devices/machine/swtpc8212.cpp
index fffd6eefe7f..e7e739b4373 100644
--- a/src/devices/machine/swtpc8212.cpp
+++ b/src/devices/machine/swtpc8212.cpp
@@ -136,8 +136,10 @@ swtp|ct8212|southwest technical products ct8212,
****************************************************************************/
#include "emu.h"
-#include "machine/swtpc8212.h"
+#include "swtpc8212.h"
+
#include "machine/input_merger.h"
+
#include "screen.h"
#include "speaker.h"
@@ -271,12 +273,6 @@ void swtpc8212_device::pia1_pa_w(uint8_t data)
m_printer_data = data;
}
-int swtpc8212_device::pia1_ca1_r()
-{
- // External parallel printer busy input.
- return 0;
-}
-
void swtpc8212_device::pia1_ca2_w(int state)
{
// External parallel printer data ready.
@@ -329,14 +325,9 @@ MC6845_UPDATE_ROW(swtpc8212_device::update_row)
}
}
-void swtpc8212_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(swtpc8212_device::bell_off)
{
- switch (id)
- {
- case BELL_TIMER_ID:
- m_beeper->set_state(0);
- break;
- }
+ m_beeper->set_state(0);
}
void swtpc8212_device::rs232_conn_dcd_w(int state)
@@ -379,16 +370,9 @@ void swtpc8212_device::write_rts(int state)
m_rs232_conn_rts_handler(state);
}
-void swtpc8212_device::device_resolve_objects()
-{
- m_rs232_conn_dtr_handler.resolve_safe();
- m_rs232_conn_rts_handler.resolve_safe();
- m_rs232_conn_txd_handler.resolve_safe();
-}
-
void swtpc8212_device::device_start()
{
- m_bell_timer = timer_alloc(BELL_TIMER_ID);
+ m_bell_timer = timer_alloc(FUNC(swtpc8212_device::bell_off), this);
save_item(NAME(m_latch_data));
save_item(NAME(m_keyboard_data));
@@ -441,22 +425,22 @@ INPUT_PORTS_START(swtpc8212)
PORT_BIT(0x0002U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("7 / Form") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
PORT_BIT(0x0004U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("8 / Xmit") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
PORT_BIT(0x0001U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("9 / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
- PORT_BIT(0x0008U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("\xC3\xB7 / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
+ PORT_BIT(0x0008U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"÷ / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
PORT_BIT(0x0200U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("4 / Scroll Up") PORT_CODE(KEYCODE_PGDN) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
- PORT_BIT(0x0400U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("5 / \xE2\x86\x91") PORT_CODE(KEYCODE_UP) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
+ PORT_BIT(0x0400U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"5 / \u2191") PORT_CODE(KEYCODE_UP) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0) // U+2191 = ↑
PORT_BIT(0x0100U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("6 / Insert") PORT_CODE(KEYCODE_0_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
- PORT_BIT(0x0800U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("\xC3\x97 / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
- PORT_BIT(0x0020U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("1 / \xE2\x86\x90") PORT_CODE(KEYCODE_LEFT) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
+ PORT_BIT(0x0800U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"× / ??") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
+ PORT_BIT(0x0020U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"1 / \u2190") PORT_CODE(KEYCODE_LEFT) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0) // U+2190 = ←
PORT_BIT(0x0040U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("2 / Home") PORT_CODE(KEYCODE_HOME) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
- PORT_BIT(0x0010U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("3 / \xE2\x86\x92") PORT_CODE(KEYCODE_RIGHT) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
+ PORT_BIT(0x0010U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"3 / \u2192") PORT_CODE(KEYCODE_RIGHT) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0) // U+2192 = →
PORT_BIT(0x0080U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("- / LF") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
PORT_BIT(0x2000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("0 / Scroll Down") PORT_CODE(KEYCODE_PGUP) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
- PORT_BIT(0x4000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("0 / \xE2\x86\x93") PORT_CODE(KEYCODE_DOWN) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
+ PORT_BIT(0x4000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(u8"0 / \u2193") PORT_CODE(KEYCODE_DOWN) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0) // U+2193 = ↓
PORT_BIT(0x1000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME(". / Delete") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
PORT_BIT(0x8000U, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("+ / CR") PORT_CHANGED_MEMBER(DEVICE_SELF, swtpc8212_device, keypad_changed, 0)
PORT_START("DIP_SWITCHES")
- PORT_DIPNAME(0x1f, 0x19, "Baud Rate") PORT_DIPLOCATION("DIP:4,3,2,1,0")
+ PORT_DIPNAME(0x1f, 0x19, "Baud Rate") PORT_DIPLOCATION("DIP:5,4,3,2,1")
PORT_DIPSETTING(0x04, "110")
PORT_DIPSETTING(0x0a, "300")
PORT_DIPSETTING(0x0d, "600")
@@ -467,13 +451,13 @@ INPUT_PORTS_START(swtpc8212)
PORT_DIPSETTING(0x19, "9600")
PORT_DIPSETTING(0x1c, "19200")
PORT_DIPSETTING(0x1f, "38400")
- PORT_DIPNAME(0x20, 0x00, "Mode switch") PORT_DIPLOCATION("DIP:5")
+ PORT_DIPNAME(0x20, 0x00, "Mode switch") PORT_DIPLOCATION("DIP:6")
PORT_DIPSETTING(0x00, "Conversational")
PORT_DIPSETTING(0x20, "Page edit")
- PORT_DIPNAME(0x40, 0x00, "No Parity") PORT_DIPLOCATION("DIP:6")
+ PORT_DIPNAME(0x40, 0x00, "No Parity") PORT_DIPLOCATION("DIP:7")
PORT_DIPSETTING(0x00, "No Parity")
PORT_DIPSETTING(0x40, "Parity")
- PORT_DIPNAME(0x80, 0x00, "Parity Select") PORT_DIPLOCATION("DIP:7")
+ PORT_DIPNAME(0x80, 0x00, "Parity Select") PORT_DIPLOCATION("DIP:8")
PORT_DIPSETTING(0x00, "Odd or Mark")
PORT_DIPSETTING(0x80, "Even or Space")
@@ -538,7 +522,7 @@ void swtpc8212_device::device_add_mconfig(machine_config &config)
// CB2 - Handshake output?
PIA6821(config, m_pia1);
m_pia1->writepa_handler().set(FUNC(swtpc8212_device::pia1_pa_w));
- m_pia1->readca1_handler().set(FUNC(swtpc8212_device::pia1_ca1_r));
+ m_pia1->ca1_w(0); // External parallel printer busy input.
m_pia1->ca2_handler().set(FUNC(swtpc8212_device::pia1_ca2_w));
m_pia1->readpb_handler().set_ioport("DIP_SWITCHES");
diff --git a/src/devices/machine/swtpc8212.h b/src/devices/machine/swtpc8212.h
index 343d182de4b..1a59160d342 100644
--- a/src/devices/machine/swtpc8212.h
+++ b/src/devices/machine/swtpc8212.h
@@ -36,21 +36,16 @@ public:
protected:
swtpc8212_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
virtual const tiny_rom_entry *device_rom_region() const override;
-private:
- enum
- {
- BELL_TIMER_ID = 1
- };
+ TIMER_CALLBACK_MEMBER(bell_off);
+private:
void mem_map(address_map &map);
required_device<m6802_cpu_device> m_maincpu;
@@ -82,7 +77,6 @@ private:
void pia0_ca2_w(int state);
void pia1_pa_w(uint8_t data);
- int pia1_ca1_r();
void pia1_ca2_w(int state);
uint8_t m_keyboard_data;
diff --git a/src/devices/machine/t10mmc.cpp b/src/devices/machine/t10mmc.cpp
index 68b86907c21..bc3d6d0a95c 100644
--- a/src/devices/machine/t10mmc.cpp
+++ b/src/devices/machine/t10mmc.cpp
@@ -3,7 +3,9 @@
#include "emu.h"
#include "t10mmc.h"
-static int to_msf(int frame)
+#include "multibyte.h"
+
+static int to_msf_raw(int frame)
{
int m = frame / (75 * 60);
int s = (frame / 75) % 60;
@@ -12,6 +14,29 @@ static int to_msf(int frame)
return (m << 16) | (s << 8) | f;
}
+static int to_msf(int frame)
+{
+ int adjusted_frame = frame + 150;
+ if (frame <= -151)
+ adjusted_frame += 450000;
+ return to_msf_raw(adjusted_frame);
+}
+
+static int to_lba(int msf)
+{
+ int lba = cdrom_file::msf_to_lba(msf) - 150;
+ if (BIT(msf, 16, 8) >= 90) // 90:00:00 and later
+ lba -= 450000;
+ return lba;
+}
+
+void t10mmc::set_model(std::string model_name)
+{
+ m_model_name = model_name;
+ while(m_model_name.size() < 28)
+ m_model_name += ' ';
+}
+
void t10mmc::t10_start(device_t &device)
{
m_device = &device;
@@ -24,14 +49,14 @@ void t10mmc::t10_start(device_t &device)
device.save_item(NAME(m_cur_subblock));
device.save_item(NAME(m_audio_sense));
device.save_item(NAME(m_sotc));
+ device.save_item(NAME(m_read_cd_flags));
}
void t10mmc::t10_reset()
{
t10spc::t10_reset();
- SetDevice( m_image->get_cdrom_file() );
- if( !m_cdrom )
+ if( !m_image->exists() )
{
m_device->logerror( "T10MMC %s: no CD found!\n", m_image->tag() );
}
@@ -44,6 +69,7 @@ void t10mmc::t10_reset()
m_cur_subblock = 0;
m_audio_sense = 0;
m_sotc = 0;
+ m_read_cd_flags = 0;
}
// scsicd_exec_command
@@ -72,7 +98,7 @@ t10mmc::toc_format_t t10mmc::toc_format()
int t10mmc::toc_tracks()
{
int start_track = command[6];
- int end_track = cdrom_get_last_track(m_cdrom);
+ int end_track = m_image->get_last_track();
if (start_track == 0)
{
@@ -156,8 +182,22 @@ void t10mmc::ExecCommand()
m_transfer_length = 8;
break;
+ case T10MMC_CMD_READ_DISC_STRUCTURE:
+ m_phase = SCSI_PHASE_DATAIN;
+ m_status_code = SCSI_STATUS_CODE_GOOD;
+ m_transfer_length = get_u16be(&command[8]);
+ break;
+
case T10SBC_CMD_READ_10:
- m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
+ m_lba = get_u32be(&command[2]);
m_blocks = SCSILengthFromUINT16( &command[7] );
//m_device->logerror("T10MMC: READ(10) at LBA %x for %d blocks (%d bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes);
@@ -180,6 +220,14 @@ void t10mmc::ExecCommand()
break;
case T10MMC_CMD_READ_SUB_CHANNEL:
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
//m_device->logerror("T10MMC: READ SUB-CHANNEL type %d\n", command[3]);
m_phase = SCSI_PHASE_DATAIN;
m_status_code = SCSI_STATUS_CODE_GOOD;
@@ -188,6 +236,14 @@ void t10mmc::ExecCommand()
case T10MMC_CMD_READ_TOC_PMA_ATIP:
{
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
int length;
switch (toc_format())
@@ -221,13 +277,26 @@ void t10mmc::ExecCommand()
break;
}
case T10MMC_CMD_PLAY_AUDIO_10:
- m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
+ m_lba = get_u32be(&command[2]);
m_blocks = SCSILengthFromUINT16( &command[7] );
- // special cases: lba of 0 means MSF of 00:02:00
if (m_lba == 0)
{
- m_lba = 150;
+ // A request for LBA 0 will return something different depending on the type of media being played.
+ // For data and mixed media, LBA 0 is assigned to MSF 00:02:00 (= LBA 150).
+ // For audio media, LBA 0 is assigned to the actual starting address of track 1.
+ if (m_image->get_track_type(0) == cdrom_file::CD_TRACK_AUDIO)
+ m_lba = m_image->get_track_start(0);
+ else
+ m_lba = 150;
}
else if (m_lba == 0xffffffff)
{
@@ -236,9 +305,9 @@ void t10mmc::ExecCommand()
//m_device->logerror("T10MMC: PLAY AUDIO(10) at LBA %x for %x blocks\n", m_lba, m_blocks);
- trk = cdrom_get_track(m_cdrom, m_lba);
+ trk = m_image->get_track(m_lba);
- if (cdrom_get_track_type(m_cdrom, trk) == CD_TRACK_AUDIO)
+ if (m_image->get_track_type(trk) == cdrom_file::CD_TRACK_AUDIO)
{
m_cdda->start_audio(m_lba, m_blocks);
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
@@ -255,72 +324,134 @@ void t10mmc::ExecCommand()
break;
case T10MMC_CMD_PLAY_AUDIO_MSF:
- m_lba = (command[5] % 75) + ((command[4] * 75) % (60*75)) + (command[3] * (75*60));
- m_blocks = (command[8] % 75) + ((command[7] * 75) % (60*75)) + (command[6] * (75*60)) - m_lba;
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_transfer_length = 0;
- // special cases: lba of 0 means MSF of 00:02:00
- if (m_lba == 0)
+ if (!m_image->exists())
{
- m_lba = 150;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ break;
}
- else if (m_lba == 0xffffffff)
+
+ const uint32_t msf_start = get_u24be(&command[3]);
+ const uint32_t msf_end = get_u24be(&command[6]);
+
+ int32_t lba_start = to_lba(msf_start);
+ int32_t lba_end = to_lba(msf_end);
+
+ // LBA valid range is technically -45150 to 404849 but negatives are not handled anywhere
+ if (lba_start < 0 || lba_end < 0)
{
- m_device->logerror("T10MMC: play audio from current not implemented!\n");
+ m_device->logerror("T10MMC: tried playing audio from lba %d to %d\n", lba_start, lba_end);
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE);
+ break;
}
- //m_device->logerror("T10MMC: PLAY AUDIO MSF at LBA %x for %x blocks (MSF %i:%i:%i - %i:%i:%i)\n",
- //m_lba, m_blocks, command[3], command[4], command[5], command[6], command[7], command[8]);
+ m_lba = lba_start;
+ m_blocks = lba_end - lba_start;
- trk = cdrom_get_track(m_cdrom, m_lba);
+ if (m_lba == 0)
+ {
+ if (m_image->get_track_type(0) == cdrom_file::CD_TRACK_AUDIO)
+ m_lba = m_image->get_track_start(0);
+ else
+ m_lba = 150;
+ }
+
+ trk = m_image->get_track(m_lba);
+
+ //m_device->logerror("T10MMC: PLAY AUDIO MSF at LBA %x (track %d) for %x blocks (MSF %02d:%02d:%02d - %02d:%02d:%02d)\n",
+ //m_lba, trk + 1, m_blocks, command[3], command[4], command[5], command[6], command[7], command[8]);
- if (cdrom_get_track_type(m_cdrom, trk) == CD_TRACK_AUDIO)
+ if (msf_start == msf_end)
{
- m_cdda->start_audio(m_lba, m_blocks);
- m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
+ // audio start operation does not happen but also isn't an error
+ m_device->logerror("T10MMC: track is not played\n");
+ m_status_code = SCSI_STATUS_CODE_GOOD;
+ m_audio_sense = SCSI_SENSE_ASC_ASCQ_NO_SENSE;
}
- else
+ else if (msf_start == 0xffffff)
+ {
+ // when start MSF is set to all FFs, the starting address becomes the current optical head location
+ m_device->logerror("T10MMC: play audio from current not implemented!\n");
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR);
+ }
+ else if (msf_start > msf_end)
+ {
+ m_device->logerror("T10MMC: track starts after requested end time!\n");
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_FIELD_IN_CDB);
+ }
+ else if (m_image->get_track_type(trk) != cdrom_file::CD_TRACK_AUDIO)
{
m_device->logerror("T10MMC: track is NOT audio!\n");
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
}
+ else
+ {
+ m_cdda->start_audio(m_lba, m_blocks);
+ m_status_code = SCSI_STATUS_CODE_GOOD;
+ m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
+ }
- m_phase = SCSI_PHASE_STATUS;
- m_status_code = SCSI_STATUS_CODE_GOOD;
- m_transfer_length = 0;
break;
+ }
case T10MMC_CMD_PLAY_AUDIO_TRACK_INDEX:
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
+ // [4] track start
+ // [5] index start
+ // [7] track end
+ // [8] index end
if (command[4] > command[7])
{
// TODO: check error
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR);
m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+
+ m_device->logerror("Error: start TNO (%d,%d) > end TNO (%d,%d)\n", command[4], command[5], command[7], command[8]);
}
else
{
// be careful: tracks here are zero-based, but the SCSI command
// uses the real CD track number which is 1-based!
//m_device->logerror("T10MMC: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], m_blocks);
- int end_track = cdrom_get_last_track(m_cdrom);
+ int end_track = m_image->get_last_track();
if (end_track > command[7])
end_track = command[7];
- // HACK: assume index 0 & 1 means beginning of track and anything else means end of track
- if (command[8] <= 1)
- end_track--;
+ // konamigv lacrazyc just sends same track start/end
+ if (command[4] != command[7] && command[5] != command[8])
+ {
+ // HACK: assume index 0 & 1 means beginning of track and anything else means end of track
+ if (command[8] <= 1)
+ end_track--;
- if (m_sotc)
- end_track = command[4];
+ if (m_sotc)
+ end_track = command[4];
+ }
- m_lba = cdrom_get_track_start(m_cdrom, command[4] - 1);
- m_blocks = cdrom_get_track_start(m_cdrom, end_track) - m_lba;
- trk = cdrom_get_track(m_cdrom, m_lba);
+ m_lba = m_image->get_track_start(command[4] - 1);
+ m_blocks = m_image->get_track_start(end_track) - m_lba;
+ trk = m_image->get_track(m_lba);
- if (cdrom_get_track_type(m_cdrom, trk) == CD_TRACK_AUDIO)
+ if (m_image->get_track_type(trk) == cdrom_file::CD_TRACK_AUDIO)
{
m_cdda->start_audio(m_lba, m_blocks);
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
m_status_code = SCSI_STATUS_CODE_GOOD;
+ m_device->logerror("Starting audio TNO %d LBA %d blocks %d\n", trk, m_lba, m_blocks);
}
else
{
@@ -336,7 +467,7 @@ void t10mmc::ExecCommand()
break;
case T10MMC_CMD_PAUSE_RESUME:
- if (m_cdrom)
+ if (m_image)
{
m_cdda->pause_audio((command[8] & 0x01) ^ 0x01);
}
@@ -357,7 +488,7 @@ void t10mmc::ExecCommand()
break;
case T10SPC_CMD_MODE_SELECT_10:
- //m_device->logerror("T10MMC: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]);
+ //m_device->logerror("T10MMC: MODE SELECT length %x control %x\n", get_u16be(&command[7]), command[1]);
m_phase = SCSI_PHASE_DATAOUT;
m_status_code = SCSI_STATUS_CODE_GOOD;
m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] );
@@ -370,13 +501,23 @@ void t10mmc::ExecCommand()
break;
case T10MMC_CMD_PLAY_AUDIO_12:
- m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
- m_blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9];
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
+ m_lba = get_u32be(&command[2]);
+ m_blocks = get_u32be(&command[6]);
- // special cases: lba of 0 means MSF of 00:02:00
if (m_lba == 0)
{
- m_lba = 150;
+ if (m_image->get_track_type(0) == cdrom_file::CD_TRACK_AUDIO)
+ m_lba = m_image->get_track_start(0);
+ else
+ m_lba = 150;
}
else if (m_lba == 0xffffffff)
{
@@ -385,9 +526,9 @@ void t10mmc::ExecCommand()
//m_device->logerror("T10MMC: PLAY AUDIO(12) at LBA %x for %x blocks\n", m_lba, m_blocks);
- trk = cdrom_get_track(m_cdrom, m_lba);
+ trk = m_image->get_track(m_lba);
- if (cdrom_get_track_type(m_cdrom, trk) == CD_TRACK_AUDIO)
+ if (m_image->get_track_type(trk) == cdrom_file::CD_TRACK_AUDIO)
{
m_cdda->start_audio(m_lba, m_blocks);
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
@@ -404,8 +545,16 @@ void t10mmc::ExecCommand()
break;
case T10SBC_CMD_READ_12:
- m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
- m_blocks = command[7]<<16 | command[8]<<8 | command[9];
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
+ m_lba = get_u32be(&command[2]);
+ m_blocks = get_u24be(&command[7]);
//m_device->logerror("T10MMC: READ(12) at LBA %x for %x blocks (%x bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes);
@@ -427,7 +576,244 @@ void t10mmc::ExecCommand()
break;
case T10MMC_CMD_SET_CD_SPEED:
- m_device->logerror("T10MMC: SET CD SPEED to %d kbytes/sec.\n", command[2]<<8 | command[3]);
+ m_device->logerror("T10MMC: SET CD SPEED to %d kbytes/sec.\n", get_u16be(&command[2]));
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_GOOD;
+ m_transfer_length = 0;
+ break;
+
+ case T10MMC_CMD_READ_CD:
+ {
+ if (!m_image->exists())
+ {
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ break;
+ }
+
+ m_lba = get_u32be(&command[2]);
+ m_blocks = get_u24be(&command[6]);
+ m_read_cd_flags = command[9];
+ m_transfer_length = 0;
+
+ // m_device->logerror("T10MMC: READ CD start_lba[%08x] block_len[%06x] %02x %02x %02x %02x\n", m_lba, m_blocks, command[1], command[9], command[10], command[11]);
+
+ if (command[10] != 0)
+ m_device->logerror("T10MMC: READ CD requested sub-channel data which is not implemented %02x\n", command[10]);
+
+ const int expected_sector_type = BIT(command[1], 2, 3);
+ int last_track_type = -1;
+ uint8_t last_read_cd_flags = 0;
+ for (int lba = m_lba; lba < m_lba + m_blocks; lba++)
+ {
+ auto trk = m_image->get_track(lba);
+ auto track_type = m_image->get_track_type(trk);
+
+ // If there's a transition between CD data and CD audio anywhere in the requested range then return an error
+ if ((last_track_type == cdrom_file::CD_TRACK_AUDIO && track_type != cdrom_file::CD_TRACK_AUDIO)
+ || (last_track_type != cdrom_file::CD_TRACK_AUDIO && track_type == cdrom_file::CD_TRACK_AUDIO))
+ {
+ set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
+
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ return;
+ }
+
+ // Must read the subheader to figure out what sector type it is exactly when dealing with these specific track types
+ int mode2_form = 0;
+ if (track_type == cdrom_file::CD_TRACK_MODE2_RAW || track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
+ {
+ uint8_t tmp_buffer[2352];
+ const int submode_offset = track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX ? 2 : 0x12;
+
+ if (!m_image->read_data(lba, tmp_buffer, cdrom_file::CD_TRACK_RAW_DONTCARE))
+ {
+ m_device->logerror("T10MMC: CD read error! (%08x)\n", lba);
+ return;
+ }
+
+ mode2_form = BIT(tmp_buffer[submode_offset], 5) + 1;
+ }
+
+ // If the expected sector type field is set then all tracks within the specified range must be the same
+ if ((expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_CDDA && track_type != cdrom_file::CD_TRACK_AUDIO)
+ || (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1_RAW)
+ || (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE2 && track_type != cdrom_file::CD_TRACK_MODE2)
+ || (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM1 && track_type != cdrom_file::CD_TRACK_MODE2_FORM1 && mode2_form != 1)
+ || (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM2 && track_type != cdrom_file::CD_TRACK_MODE2_FORM2 && mode2_form != 2))
+ {
+ set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
+
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ return;
+ }
+
+ // No fields selected is a valid request but none of the rest of the verification code is required in that case
+ if (m_read_cd_flags == 0)
+ {
+ last_track_type = track_type;
+ continue;
+ }
+
+ // Check for illegal combinations
+ // t10 mmc spec gives a table which shows illegal combinations and combinations that get demoted
+ auto read_cd_flags = m_read_cd_flags & 0xf8;
+
+ // CDDA tracks can only ever be user data or no data (0), requesting other fields is not illegal but will be demoted to just user data
+ if (track_type == cdrom_file::CD_TRACK_AUDIO)
+ read_cd_flags = read_cd_flags ? T10MMC_READ_CD_FIELD_USER_DATA : 0;
+
+ // All of these combinations will be illegal for all tracks besides CDDA tracks
+ bool is_illegal_combo = (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_USER_DATA))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_USER_DATA))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC));
+
+ // Mode 2 form 1/2 sectors have additional restrictions that CDDA, mode 1, and mode 2 formless tracks don't
+ if (!is_illegal_combo && (track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || mode2_form > 0))
+ {
+ is_illegal_combo = (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA))
+ || (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC));
+ }
+
+ // Mask out flags that can't be used for specific track types
+ if (track_type == cdrom_file::CD_TRACK_MODE1 || track_type == cdrom_file::CD_TRACK_MODE1_RAW)
+ {
+ // Sub header only is valid but will return 0 bytes, otherwise subheader is always demoted
+ if (read_cd_flags != T10MMC_READ_CD_FIELD_SUBHEADER)
+ read_cd_flags &= ~T10MMC_READ_CD_FIELD_SUBHEADER;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2)
+ {
+ // Mode 2 formless
+ // No EDC/ECC data
+ read_cd_flags &= ~T10MMC_READ_CD_FIELD_ECC;
+
+ // Sub header only is valid but will return 0 bytes, otherwise subheader is always demoted
+ if (read_cd_flags != T10MMC_READ_CD_FIELD_SUBHEADER)
+ read_cd_flags &= ~T10MMC_READ_CD_FIELD_SUBHEADER;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || mode2_form == 2)
+ {
+ // No EDC/ECC data
+ read_cd_flags &= ~T10MMC_READ_CD_FIELD_ECC;
+ }
+
+ // Requested fields must be valid for all tracks within the selected range
+ if (is_illegal_combo || (last_track_type != -1 && read_cd_flags != last_read_cd_flags))
+ {
+ m_device->logerror("T10MMC: READ CD called with invalid data request for given track type %d %02x\n", track_type, command[9]);
+ set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_FIELD_IN_CDB);
+ m_phase = SCSI_PHASE_STATUS;
+ m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
+ m_transfer_length = 0;
+ return;
+ }
+
+ // The actual transfer size must be calculated for every possible valid requested data
+ const int c2_error_codes = BIT(m_read_cd_flags, 1, 2);
+ const bool requested_c2 = c2_error_codes == T10MMC_READ_CD_C2_ONLY;
+ const bool requested_c2_error_block = c2_error_codes == T10MMC_READ_CD_C2_BLOCK;
+
+ const bool requested_edc_ecc = (read_cd_flags & T10MMC_READ_CD_FIELD_ECC) != 0;
+ const bool requested_user_data = (read_cd_flags & T10MMC_READ_CD_FIELD_USER_DATA) != 0;
+ const bool requested_header = (read_cd_flags & T10MMC_READ_CD_FIELD_HEADER) != 0;
+ const bool requested_subheader = (read_cd_flags & T10MMC_READ_CD_FIELD_SUBHEADER) != 0;
+ const bool requested_sync = (read_cd_flags & T10MMC_READ_CD_FIELD_SYNC) != 0;
+
+ if (requested_c2 || requested_c2_error_block)
+ m_transfer_length += 294;
+
+ if (requested_c2_error_block)
+ m_transfer_length += 2;
+
+ if (track_type == cdrom_file::CD_TRACK_AUDIO)
+ {
+ if (requested_user_data)
+ m_transfer_length += 2352;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE1 || track_type == cdrom_file::CD_TRACK_MODE1_RAW)
+ {
+ if (requested_sync)
+ m_transfer_length += 12;
+ if (requested_header)
+ m_transfer_length += 4;
+ if (requested_user_data)
+ m_transfer_length += 2048;
+ if (requested_edc_ecc)
+ m_transfer_length += 288;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2)
+ {
+ if (requested_sync)
+ m_transfer_length += 12;
+ if (requested_header)
+ m_transfer_length += 4;
+ if (requested_user_data)
+ m_transfer_length += 2336;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || mode2_form == 1)
+ {
+ if (requested_sync)
+ m_transfer_length += 12;
+ if (requested_header)
+ m_transfer_length += 4;
+ if (requested_subheader)
+ m_transfer_length += 8;
+ if (requested_user_data)
+ m_transfer_length += 2048;
+ if (requested_edc_ecc)
+ m_transfer_length += 280;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || mode2_form == 2)
+ {
+ if (requested_sync)
+ m_transfer_length += 12;
+ if (requested_header)
+ m_transfer_length += 4;
+ if (requested_subheader)
+ m_transfer_length += 8;
+ if (requested_user_data)
+ m_transfer_length += 2328;
+ }
+
+ last_track_type = track_type;
+ last_read_cd_flags = read_cd_flags;
+ }
+
+ // Only worry about SGI block extension stuff if it ever becomes an issue
+ if (m_num_subblocks > 1)
+ m_device->logerror("T10MMC: READ CD does not handle sub blocks currently\n");
+
+ // All fields were matched between all tracks, so store the simplified version
+ m_read_cd_flags = last_read_cd_flags | (m_read_cd_flags & ~0xf8);
+
+ m_cur_subblock = 0;
+ m_phase = SCSI_PHASE_DATAIN;
+ m_status_code = SCSI_STATUS_CODE_GOOD;
+ break;
+ }
+
+ case T10SBC_CMD_SEEK_10:
+ m_lba = get_u32be(&command[2]);
+
+ m_device->logerror("T10SBC: SEEK EXTENDED to LBA %x\n", m_lba);
+
m_phase = SCSI_PHASE_STATUS;
m_status_code = SCSI_STATUS_CODE_GOOD;
m_transfer_length = 0;
@@ -445,7 +831,7 @@ void t10mmc::ExecCommand()
void t10mmc::ReadData( uint8_t *data, int dataLength )
{
uint32_t temp;
- uint8_t tmp_buffer[2048];
+ uint8_t tmp_buffer[2352];
switch ( command[0] )
{
@@ -458,38 +844,32 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
data[5] = 0;
data[6] = 0;
data[7] = 0;
- memset(&data[8], ' ', 28);
- memcpy(&data[8], "MAME", 4);
- memcpy(&data[16], "Virtual CDROM", 13);
- memcpy(&data[32], "1.0", 3);
+ memcpy(&data[8], m_model_name.data(), 28);
break;
case T10SBC_CMD_READ_CAPACITY:
m_device->logerror("T10MMC: READ CAPACITY\n");
- temp = cdrom_get_track_start(m_cdrom, 0xaa);
+ temp = m_image->get_track_start(0xaa);
temp--; // return the last used block on the disc
- data[0] = (temp>>24) & 0xff;
- data[1] = (temp>>16) & 0xff;
- data[2] = (temp>>8) & 0xff;
- data[3] = (temp & 0xff);
+ put_u32be(&data[0], temp);
data[4] = 0;
data[5] = 0;
- data[6] = (m_sector_bytes>>8)&0xff;
- data[7] = (m_sector_bytes & 0xff);
+ put_u16be(&data[6], m_sector_bytes);
break;
case T10SBC_CMD_READ_10:
case T10SBC_CMD_READ_12:
- //m_device->logerror("T10MMC: read %x dataLength, \n", dataLength);
- if ((m_cdrom) && (m_blocks))
+ //m_device->logerror("T10MMC: read %x dataLength lba=%x\n", dataLength, m_lba);
+ if ((m_image) && (m_blocks))
{
while (dataLength > 0)
{
- if (!cdrom_read_data(m_cdrom, m_lba, tmp_buffer, CD_TRACK_MODE1))
+ if (!m_image->read_data(m_lba, tmp_buffer, cdrom_file::CD_TRACK_MODE1))
{
- m_device->logerror("T10MMC: CD read error!\n");
+ m_device->logerror("T10MMC: CD read error! (%08x)\n", m_lba);
+ return;
}
//m_device->logerror("True LBA: %d, buffer half: %d\n", m_lba, m_cur_subblock * m_sector_bytes);
@@ -512,12 +892,244 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
}
break;
+ case T10MMC_CMD_READ_CD:
+ //m_device->logerror("T10MMC: read CD %x dataLength lba=%x\n", dataLength, m_lba);
+ if ((m_image) && (m_blocks))
+ {
+ const int c2_error_codes = BIT(m_read_cd_flags, 1, 2);
+ const bool requested_c2 = c2_error_codes == T10MMC_READ_CD_C2_ONLY;
+ const bool requested_c2_error_block = c2_error_codes == T10MMC_READ_CD_C2_BLOCK;
+
+ const bool requested_edc_ecc = (m_read_cd_flags & T10MMC_READ_CD_FIELD_ECC) != 0;
+ const bool requested_user_data = (m_read_cd_flags & T10MMC_READ_CD_FIELD_USER_DATA) != 0;
+ const bool requested_header = (m_read_cd_flags & T10MMC_READ_CD_FIELD_HEADER) != 0;
+ const bool requested_subheader = (m_read_cd_flags & T10MMC_READ_CD_FIELD_SUBHEADER) != 0;
+ const bool requested_sync = (m_read_cd_flags & T10MMC_READ_CD_FIELD_SYNC) != 0;
+
+ // m_device->logerror("T10MMC: read CD flags c2[%d] c2block[%d] edc/ecc[%d] user[%d] header[%d] subheader[%d] sync[%d]\n", requested_c2, requested_c2_error_block, requested_edc_ecc, requested_user_data, requested_header, requested_subheader, requested_sync);
+
+ if (m_read_cd_flags == 0)
+ {
+ // No data is supposed to be returned
+ if (dataLength > 0)
+ memset(data, 0, dataLength);
+
+ data += dataLength;
+ dataLength = 0;
+ }
+
+ while (dataLength > 0)
+ {
+ int data_idx = 0;
+ auto trk = m_image->get_track(m_lba);
+ auto track_type = m_image->get_track_type(trk);
+
+ // Some CHDs don't have the required data so just log the error and return zeros as required
+ // CD_TRACK_MODE1: Only has user data
+ // CD_TRACK_MODE1_RAW: Has all fields required
+ // CD_TRACK_MODE2: Only has user data
+ // CD_TRACK_MODE2_FORM1: ?
+ // CD_TRACK_MODE2_FORM2: ?
+ // CD_TRACK_MODE2_FORM_MIX: Subheader data + user data + EDC/ECC data
+ // CD_TRACK_MODE2_RAW: Has all fields required
+ // CD_TRACK_AUDIO: Only returns user data
+
+ auto read_track_type = track_type;
+ if (track_type == cdrom_file::CD_TRACK_MODE1)
+ read_track_type = cdrom_file::CD_TRACK_MODE1_RAW; // mode1 has code for partial promotion to mode1_raw so make use of it
+
+ if (!m_image->read_data(m_lba, tmp_buffer, read_track_type))
+ {
+ m_device->logerror("T10MMC: CD read error! (%08x)\n", m_lba);
+ return;
+ }
+
+ int mode2_form = 0;
+ if (track_type == cdrom_file::CD_TRACK_MODE2_RAW)
+ mode2_form = BIT(tmp_buffer[0x12], 5) + 1;
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
+ mode2_form = BIT(tmp_buffer[2], 5) + 1;
+
+ if (requested_sync)
+ {
+ if (track_type == cdrom_file::CD_TRACK_MODE2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
+ {
+ m_device->logerror("T10MMC: sync data is not available for track type %d, inserting fake sync data\n", track_type);
+ constexpr uint8_t sync_field[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+ memcpy(data + data_idx, sync_field, std::size(sync_field));
+ }
+ else
+ memcpy(data + data_idx, tmp_buffer, 12);
+
+ data_idx += 12;
+ }
+
+ if (requested_header)
+ {
+ if (track_type == cdrom_file::CD_TRACK_MODE2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
+ {
+ m_device->logerror("T10MMC: header data is not available for track type %d, inserting fake header data\n", track_type);
+
+ uint32_t msf = to_msf(m_lba);
+ put_u24be(&data[data_idx], msf);
+ data[data_idx+3] = 2; // mode 2
+ }
+ else
+ memcpy(data + data_idx, tmp_buffer + 12, 4);
+
+ data_idx += 4;
+ }
+
+ if (requested_subheader)
+ {
+ if (track_type == cdrom_file::CD_TRACK_MODE2_RAW)
+ {
+ memcpy(data + data_idx, tmp_buffer + 16, 8);
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
+ {
+ // Only been able to verify 1 CHD for form mix, appears to have the 8 subheader bytes at the top of the sector
+ memcpy(data + data_idx, tmp_buffer, 8);
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
+ {
+ // It's not possible to generate a fake subheader for mode 2 tracks because the submode byte contains detailed info
+ // about what actual data is inside the block
+ m_device->logerror("T10MMC: subheader data is not available for track type %d\n", track_type);
+ memset(data + data_idx, 0, 8);
+
+ if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
+ data[data_idx+2] = data[data_idx+6] = 1 << 5; // The form 2 flag can at least be set accurately
+ }
+
+ // Mode 1 and mode 2 formless return 0 bytes
+ if (track_type != cdrom_file::CD_TRACK_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1_RAW && track_type != cdrom_file::CD_TRACK_MODE2)
+ data_idx += 8;
+ }
+
+ if (requested_user_data)
+ {
+ int buffer_offset = 0;
+ int data_len = 0;
+
+ if (track_type == cdrom_file::CD_TRACK_AUDIO)
+ {
+ buffer_offset = 0;
+ data_len = 2352;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE1 || track_type == cdrom_file::CD_TRACK_MODE1_RAW)
+ {
+ buffer_offset = 16;
+ data_len = 2048;
+ }
+ else if ((track_type == cdrom_file::CD_TRACK_MODE2_RAW && mode2_form == 1))
+ {
+ buffer_offset = 24;
+ data_len = 2048;
+ }
+ else if ((track_type == cdrom_file::CD_TRACK_MODE2_RAW && mode2_form == 2))
+ {
+ buffer_offset = 24;
+ data_len = 2328;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX && mode2_form == 1)
+ {
+ buffer_offset = 8;
+ data_len = 2048;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX && mode2_form == 2)
+ {
+ buffer_offset = 8;
+ data_len = 2328;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2)
+ {
+ // Untested
+ buffer_offset = 0;
+ data_len = 2336;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM1)
+ {
+ // Untested
+ m_device->logerror("T10MMC: reading user data from untested mode 2 form 1 track\n");
+ buffer_offset = 0;
+ data_len = 2048;
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
+ {
+ // Untested
+ m_device->logerror("T10MMC: reading user data from untested mode 2 form 2 track\n");
+ buffer_offset = 0;
+ data_len = 2324;
+ }
+
+ memcpy(data + data_idx, tmp_buffer + buffer_offset, data_len);
+ data_idx += data_len;
+
+ if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
+ {
+ // Untested, but the sector size of 2324 as noted in cdrom.h
+ // implies the lack of the last 4 bytes for the (optional) CRC
+ memset(data + data_idx, 0, 4);
+ data_idx += 4;
+ }
+ }
+
+ if (requested_edc_ecc)
+ {
+ if (track_type == cdrom_file::CD_TRACK_MODE1_RAW)
+ {
+ // Includes the 8 bytes of padding
+ memcpy(data + data_idx, tmp_buffer + 16 + 2048, 288);
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_RAW && mode2_form == 1)
+ {
+ memcpy(data + data_idx, tmp_buffer + 24 + 2048, 280);
+ }
+ else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX && mode2_form == 1)
+ {
+ memcpy(data + data_idx, tmp_buffer + 8 + 2048, 280);
+ }
+ else
+ {
+ m_device->logerror("T10MMC: EDC/ECC data is not available for track type %d\n", track_type);
+ memset(data + data_idx, 0, 280);
+ }
+
+ data_idx += 280;
+ }
+
+ if (requested_c2 || requested_c2_error_block)
+ {
+ m_device->logerror("T10MMC: C2 field is not supported, returning zero data\n");
+ memset(data + data_idx, 0, 294);
+ data_idx += 294;
+ }
+
+ if (requested_c2_error_block)
+ {
+ m_device->logerror("T10MMC: error block field is not supported, returning zero data\n");
+ memset(data + data_idx, 0, 2);
+ data_idx += 2;
+ }
+
+ m_lba++;
+ m_blocks--;
+
+ m_last_lba = m_lba;
+ dataLength -= data_idx;
+ data += data_idx;
+ data_idx = 0;
+ }
+ }
+ break;
+
case T10MMC_CMD_READ_SUB_CHANNEL:
switch (command[3])
{
case 1: // return current position
{
- if (!m_cdrom)
+ if (!m_image)
{
return;
}
@@ -562,7 +1174,7 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
data[3] = 12; // data length
data[4] = 0x01; // sub-channel format code
data[5] = 0x10 | (audio_active ? 0 : 4);
- data[6] = cdrom_get_track(m_cdrom, m_last_lba) + 1; // track
+ data[6] = m_image->get_track(m_last_lba) + 1; // track
data[7] = 0; // index
uint32_t frame = m_last_lba;
@@ -572,22 +1184,17 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
frame = to_msf(frame);
}
- data[8] = (frame>>24)&0xff;
- data[9] = (frame>>16)&0xff;
- data[10] = (frame>>8)&0xff;
- data[11] = frame&0xff;
+ put_u32be(&data[8], frame);
- frame -= cdrom_get_track_start(m_cdrom, data[6] - 1);
+ frame = m_last_lba - m_image->get_track_start(data[6] - 1);
if (msf)
{
- frame = to_msf(frame);
+ // this is relative so don't adjust the LBA when converting to MSF
+ frame = to_msf_raw(frame);
}
- data[12] = (frame>>24)&0xff;
- data[13] = (frame>>16)&0xff;
- data[14] = (frame>>8)&0xff;
- data[15] = frame&0xff;
+ put_u32be(&data[12], frame);
}
else
{
@@ -622,10 +1229,10 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
// the returned TOC DATA LENGTH must be the full amount,
// regardless of how much we're able to pass back due to in_len
int dptr = 0;
- data[dptr++] = (len>>8) & 0xff;
- data[dptr++] = (len & 0xff);
+ put_u16be(&data[dptr], len);
+ dptr += 2;
data[dptr++] = 1;
- data[dptr++] = cdrom_get_last_track(m_cdrom);
+ data[dptr++] = m_image->get_last_track();
int first_track = command[6];
if (first_track == 0)
@@ -649,21 +1256,19 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
}
data[dptr++] = 0;
- data[dptr++] = cdrom_get_adr_control(m_cdrom, cdrom_track);
+ data[dptr++] = m_image->get_adr_control(cdrom_track);
data[dptr++] = track;
data[dptr++] = 0;
- uint32_t tstart = cdrom_get_track_start(m_cdrom, cdrom_track);
+ uint32_t tstart = m_image->get_track_start(cdrom_track);
if (msf)
{
- tstart = to_msf(tstart+150);
+ tstart = to_msf(tstart);
}
- data[dptr++] = (tstart>>24) & 0xff;
- data[dptr++] = (tstart>>16) & 0xff;
- data[dptr++] = (tstart>>8) & 0xff;
- data[dptr++] = (tstart & 0xff);
+ put_u32be(&data[dptr], tstart);
+ dptr += 4;
}
}
break;
@@ -673,27 +1278,25 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
int len = 2 + (8 * 1);
int dptr = 0;
- data[dptr++] = (len>>8) & 0xff;
- data[dptr++] = (len & 0xff);
+ put_u16be(&data[dptr], len);
+ dptr += 2;
data[dptr++] = 1;
data[dptr++] = 1;
data[dptr++] = 0;
- data[dptr++] = cdrom_get_adr_control(m_cdrom, 0);
+ data[dptr++] = m_image->get_adr_control(0);
data[dptr++] = 1;
data[dptr++] = 0;
- uint32_t tstart = cdrom_get_track_start(m_cdrom, 0);
+ uint32_t tstart = m_image->get_track_start(0);
if (msf)
{
- tstart = to_msf(tstart+150);
+ tstart = to_msf(tstart);
}
- data[dptr++] = (tstart>>24) & 0xff;
- data[dptr++] = (tstart>>16) & 0xff;
- data[dptr++] = (tstart>>8) & 0xff;
- data[dptr++] = (tstart & 0xff);
+ put_u32be(&data[dptr], tstart);
+ dptr += 4;
}
break;
@@ -706,52 +1309,80 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
case T10SPC_CMD_MODE_SENSE_6:
case T10SPC_CMD_MODE_SENSE_10:
- m_device->logerror("T10MMC: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6);
-
- memset(data, 0, SCSILengthFromUINT16( &command[ 7 ] ));
-
- switch (command[2] & 0x3f)
+ // m_device->logerror("T10MMC: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6);
{
- case 0xe: // CD Audio control page
- data[1] = 0x0e;
- data[0] = 0x8e; // page E, parameter is savable
- data[1] = 0x0e; // page length
- data[2] = (1 << 2) | (m_sotc << 1); // IMMED = 1
- data[3] = data[4] = data[5] = data[6] = data[7] = 0; // reserved
+ memset(data, 0, SCSILengthFromUINT16( &command[ 7 ] ));
+
+ const uint8_t page = command[2] & 0x3f;
+ int ptr = 0;
+
+ if ((page == 0xe) || (page == 0x3f))
+ { // CD Audio control page
+ data[ptr++] = 0x8e; // page E, parameter is savable
+ data[ptr++] = 0x0e; // page length
+ data[ptr++] = (1 << 2) | (m_sotc << 1); // IMMED = 1
+ ptr += 5; // skip reserved bytes
+ // connect each audio channel to 1 output port and indicate max volume
+ data[ptr++] = 1;
+ data[ptr++] = 0xff;
+ data[ptr++] = 2;
+ data[ptr++] = 0xff;
+ data[ptr++] = 4;
+ data[ptr++] = 0xff;
+ data[ptr++] = 8;
+ data[ptr++] = 0xff;
+ }
- // connect each audio channel to 1 output port
- data[8] = 1;
- data[10] = 2;
- data[12] = 4;
- data[14] = 8;
+ if ((page == 0x0d) || (page == 0x3f))
+ { // CD page
+ data[ptr++] = 0x0d;
+ data[ptr++] = 6; // page length
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 60;
+ data[ptr++] = 0;
+ data[ptr++] = 75;
+ }
- // indicate max volume
- data[9] = data[11] = data[13] = data[15] = 0xff;
- break;
- case 0x2a: // Page capabilities
- data[1] = 0x14;
- data[0] = 0x2a;
- data[1] = 0x14; // page length
- data[2] = 0x00; data[3] = 0x00; // CD-R only
- data[4] = 0x01; // can play audio
- data[5] = 0;
- data[6] = 0;
- data[7] = 0;
- data[8] = 0x02; data[9] = 0xc0; // 4x speed
- data[10] = 0x01; data[11] = 0x00; // 256 volume levels supported
- data[12] = 0x00; data[13] = 0x00; // buffer
- data[14] = 0x02; data[15] = 0xc0; // 4x read speed
- data[16] = 0;
- data[17] = 0;
- data[18] = 0;
- data[19] = 0;
- data[20] = 0;
- data[21] = 0;
- break;
+ if ((page == 0x2a) || (page == 0x3f))
+ { // Page capabilities
+ data[ptr++] = 0x2a;
+ data[ptr++] = 0x14; // page length
+ data[ptr++] = 0x00;
+ data[ptr++] = 0x00; // CD-R only
+ data[ptr++] = 0x01; // can play audio
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 0x02;
+ data[ptr++] = 0xc0; // 4x speed
+ data[ptr++] = 0x01;
+ data[ptr++] = 0x00; // 256 volume levels supported
+ data[ptr++] = 0x00;
+ data[ptr++] = 0x00; // buffer
+ data[ptr++] = 0x02;
+ data[ptr++] = 0xc0; // 4x read speed
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ data[ptr++] = 0;
+ }
+ }
+ break;
- default:
- m_device->logerror("T10MMC: MODE SENSE unknown page %x\n", command[2] & 0x3f);
- break;
+ case T10MMC_CMD_READ_DISC_STRUCTURE:
+ m_device->logerror("T10MMC: READ DISC STRUCTURE, data\n");
+ data[0] = data[1] = 0;
+ data[2] = data[3] = 0;
+
+ if((command[1] & 0x0f) == 0 && command[7] == 0x04) // DVD / DVD disc manufacturing information
+ {
+ data[1] = 0xe;
+ for(int i=4; i != 0xe; i++)
+ data[i] = 0;
}
break;
@@ -796,8 +1427,11 @@ void t10mmc::WriteData( uint8_t *data, int dataLength )
m_device->logerror("Ch 1 route: %x vol: %x\n", data[10], data[11]);
m_device->logerror("Ch 2 route: %x vol: %x\n", data[12], data[13]);
m_device->logerror("Ch 3 route: %x vol: %x\n", data[14], data[15]);
- m_cdda->set_output_gain(0, data[17] / 255.0f);
- m_cdda->set_output_gain(1, data[19] / 255.0f);
+
+ // TODO: CDDA audio channels and output port should be separate
+ // The actual audio channel that gets sent to the output port is configurable and more than one audio channel can go to an output port
+ m_cdda->set_output_gain(0, data[9] / 255.0f);
+ m_cdda->set_output_gain(1, data[11] / 255.0f);
break;
}
break;
@@ -807,14 +1441,3 @@ void t10mmc::WriteData( uint8_t *data, int dataLength )
break;
}
}
-
-void t10mmc::GetDevice( void **_cdrom )
-{
- *(cdrom_file **)_cdrom = m_cdrom;
-}
-
-void t10mmc::SetDevice( void *_cdrom )
-{
- m_cdrom = (cdrom_file *)_cdrom;
- m_cdda->set_cdrom(m_cdrom);
-}
diff --git a/src/devices/machine/t10mmc.h b/src/devices/machine/t10mmc.h
index 351454cb2b6..9b84e929c29 100644
--- a/src/devices/machine/t10mmc.h
+++ b/src/devices/machine/t10mmc.h
@@ -12,23 +12,23 @@ t10mmc.h
#pragma once
#include "t10spc.h"
-#include "imagedev/chd_cd.h"
+#include "imagedev/cdromimg.h"
#include "sound/cdda.h"
class t10mmc : public virtual t10spc
{
public:
t10mmc()
- : t10spc(), m_image(nullptr), m_cdda(nullptr), m_cdrom(nullptr), m_lba(0), m_blocks(0), m_last_lba(0), m_num_subblocks(0), m_cur_subblock(0), m_audio_sense(0), m_device(nullptr)
+ : t10spc(), m_image(nullptr), m_cdda(nullptr), m_model_name("MAME Virtual CDROM 1.0 "), m_lba(0), m_blocks(0), m_last_lba(0), m_num_subblocks(0), m_cur_subblock(0), m_audio_sense(0), m_device(nullptr)
{
}
- virtual void SetDevice( void *device ) override;
- virtual void GetDevice( void **device ) override;
virtual void ExecCommand() override;
virtual void WriteData( uint8_t *data, int dataLength ) override;
virtual void ReadData( uint8_t *data, int dataLength ) override;
+ void set_model(std::string model_name);
+
protected:
virtual void t10_start(device_t &device) override;
virtual void t10_reset() override;
@@ -43,7 +43,29 @@ protected:
T10MMC_CMD_PAUSE_RESUME = 0x4b,
T10MMC_CMD_STOP_PLAY_SCAN = 0x4e,
T10MMC_CMD_PLAY_AUDIO_12 = 0xa5,
- T10MMC_CMD_SET_CD_SPEED = 0xbb
+ T10MMC_CMD_READ_DISC_STRUCTURE = 0xad,
+ T10MMC_CMD_SET_CD_SPEED = 0xbb,
+ T10MMC_CMD_READ_CD = 0xbe
+ };
+
+ enum
+ {
+ T10MMC_READ_CD_SECTOR_TYPE_ANY = 0,
+ T10MMC_READ_CD_SECTOR_TYPE_CDDA = 1,
+ T10MMC_READ_CD_SECTOR_TYPE_MODE1 = 2,
+ T10MMC_READ_CD_SECTOR_TYPE_MODE2 = 3,
+ T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM1 = 4,
+ T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM2 = 5,
+
+ // These shouldn't be treated as masks, 3 is a reserved value
+ T10MMC_READ_CD_C2_ONLY = 1, // C2 error bits (294 bytes)
+ T10MMC_READ_CD_C2_BLOCK = 2, // C2 error bits (294 bytes) + block error byte (logical OR of all the C2 error bit bytes) + 1 padding byte
+
+ T10MMC_READ_CD_FIELD_ECC = 0x08, // EDC/ECC
+ T10MMC_READ_CD_FIELD_USER_DATA = 0x10,
+ T10MMC_READ_CD_FIELD_HEADER = 0x20,
+ T10MMC_READ_CD_FIELD_SUBHEADER = 0x40,
+ T10MMC_READ_CD_FIELD_SYNC = 0x80,
};
enum toc_format_t
@@ -58,7 +80,8 @@ protected:
cdrom_image_device *m_image;
cdda_device *m_cdda;
- cdrom_file *m_cdrom;
+
+ std::string m_model_name;
uint32_t m_lba;
uint32_t m_blocks;
@@ -67,6 +90,7 @@ protected:
uint32_t m_cur_subblock;
int m_audio_sense;
int m_sotc;
+ uint8_t m_read_cd_flags;
device_t *m_device;
};
diff --git a/src/devices/machine/t10sbc.cpp b/src/devices/machine/t10sbc.cpp
index 4b81c5a4a9c..47f4daa0795 100644
--- a/src/devices/machine/t10sbc.cpp
+++ b/src/devices/machine/t10sbc.cpp
@@ -3,6 +3,8 @@
#include "emu.h"
#include "t10sbc.h"
+#include "multibyte.h"
+
void t10sbc::t10_start(device_t &device)
{
m_device = &device;
@@ -20,16 +22,14 @@ void t10sbc::t10_reset()
m_blocks = 0;
m_sector_bytes = 512;
- m_disk = m_image->get_hard_disk_file();
- if (!m_disk)
+ if (!m_image->exists())
{
m_device->logerror("T10SBC %s: no HD found!\n", m_image->owner()->tag());
}
else
{
// get hard disk sector size from CHD metadata
- const hard_disk_info *hdinfo = hard_disk_get_info(m_disk);
- m_sector_bytes = hdinfo->sectorbytes;
+ m_sector_bytes = m_image->get_info().sectorbytes;
}
}
@@ -45,7 +45,7 @@ void t10sbc::ExecCommand()
break;
case T10SBC_CMD_SEEK_6:
- m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3];
+ m_lba = get_u24be(&command[1])&0x1fffff;
m_device->logerror("S1410: SEEK to LBA %x\n", m_lba);
@@ -54,7 +54,7 @@ void t10sbc::ExecCommand()
break;
case T10SBC_CMD_READ_6:
- m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3];
+ m_lba = get_u24be(&command[1])&0x1fffff;
m_blocks = SCSILengthFromUINT8( &command[4] );
m_device->logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks);
@@ -65,7 +65,7 @@ void t10sbc::ExecCommand()
break;
case T10SBC_CMD_WRITE_6:
- m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3];
+ m_lba = get_u24be(&command[1])&0x1fffff;
m_blocks = SCSILengthFromUINT8( &command[4] );
m_device->logerror("T10SBC: WRITE to LBA %x for %x blocks\n", m_lba, m_blocks);
@@ -101,7 +101,7 @@ void t10sbc::ExecCommand()
break;
case T10SBC_CMD_READ_10:
- m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ m_lba = get_u32be(&command[2]);
m_blocks = SCSILengthFromUINT16( &command[7] );
m_device->logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks);
@@ -112,7 +112,7 @@ void t10sbc::ExecCommand()
break;
case T10SBC_CMD_WRITE_10:
- m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
+ m_lba = get_u32be(&command[2]);
m_blocks = SCSILengthFromUINT16( &command[7] );
m_device->logerror("T10SBC: WRITE to LBA %x for %x blocks\n", m_lba, m_blocks);
@@ -123,8 +123,8 @@ void t10sbc::ExecCommand()
break;
case T10SBC_CMD_READ_12:
- m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
- m_blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9];
+ m_lba = get_u32be(&command[2]);
+ m_blocks = get_u32be(&command[6]);
m_device->logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks);
@@ -142,7 +142,7 @@ void t10sbc::ExecCommand()
void t10sbc::ReadData( uint8_t *data, int dataLength )
{
// if we're a drive without a disk, return all zeroes
- if (!m_disk)
+ if (!m_image->exists())
{
memset(data, 0, dataLength);
return;
@@ -273,12 +273,12 @@ void t10sbc::ReadData( uint8_t *data, int dataLength )
case T10SBC_CMD_READ_6:
case T10SBC_CMD_READ_10:
case T10SBC_CMD_READ_12:
- if ((m_disk) && (m_blocks))
+ if (m_image->exists() && (m_blocks))
{
m_device->logerror("T10SBC: Reading %d bytes from HD\n", dataLength);
while (dataLength > 0)
{
- if (!hard_disk_read(m_disk, m_lba, data))
+ if (!m_image->read(m_lba, data))
{
m_device->logerror("T10SBC: HD read error!\n");
}
@@ -303,7 +303,7 @@ void t10sbc::ReadData( uint8_t *data, int dataLength )
void t10sbc::WriteData( uint8_t *data, int dataLength )
{
- if (!m_disk)
+ if (!m_image->exists())
{
return;
}
@@ -315,12 +315,12 @@ void t10sbc::WriteData( uint8_t *data, int dataLength )
case T10SBC_CMD_WRITE_6:
case T10SBC_CMD_WRITE_10:
- if ((m_disk) && (m_blocks))
+ if (m_image->exists() && (m_blocks))
{
m_device->logerror("T10SBC: Writing %d bytes to HD\n", dataLength);
while (dataLength > 0)
{
- if (!hard_disk_write(m_disk, m_lba, data))
+ if (!m_image->write(m_lba, data))
{
m_device->logerror("T10SBC: HD write error!\n");
}
@@ -338,58 +338,42 @@ void t10sbc::WriteData( uint8_t *data, int dataLength )
}
}
-void t10sbc::GetDevice( void **_disk )
-{
- *(hard_disk_file **)_disk = m_disk;
-}
-
-void t10sbc::SetDevice( void *_disk )
-{
- m_disk = (hard_disk_file *)_disk;
-}
-
void t10sbc::GetFormatPage( format_page_t *page )
{
- hard_disk_info *info = hard_disk_get_info(m_disk);
+ const auto &info = m_image->get_info();
memset(page, 0, sizeof(format_page_t));
page->m_page_code = 0x03;
page->m_page_length = 0x16;
- page->m_sectors_per_track_msb = (uint8_t)(info->sectors >> 8);
- page->m_sectors_per_track_lsb = (uint8_t)info->sectors;
- page->m_bytes_per_sector_msb = (uint8_t)(info->sectorbytes >> 8);
- page->m_bytes_per_sector_lsb = (uint8_t)info->sectorbytes;
+ page->m_sectors_per_track_msb = (uint8_t)(info.sectors >> 8);
+ page->m_sectors_per_track_lsb = (uint8_t)info.sectors;
+ page->m_bytes_per_sector_msb = (uint8_t)(info.sectorbytes >> 8);
+ page->m_bytes_per_sector_lsb = (uint8_t)info.sectorbytes;
page->m_format = 0x80; // SSEC, Soft-Sectored
}
void t10sbc::GetGeometryPage( geometry_page_t *page )
{
- hard_disk_info *info = hard_disk_get_info(m_disk);
+ const auto &info = m_image->get_info();
memset(page, 0, sizeof(geometry_page_t));
page->m_page_code = 0x04;
page->m_page_length = 0x16;
- page->m_num_cylinders_msb = (uint8_t)(info->cylinders >> 16);
- page->m_num_cylinders_2nd = (uint8_t)(info->cylinders >> 8);
- page->m_num_cylinders_lsb = (uint8_t)info->cylinders;
- page->m_num_heads = (uint8_t)info->heads;
+ page->m_num_cylinders_msb = (uint8_t)(info.cylinders >> 16);
+ page->m_num_cylinders_2nd = (uint8_t)(info.cylinders >> 8);
+ page->m_num_cylinders_lsb = (uint8_t)info.cylinders;
+ page->m_num_heads = (uint8_t)info.heads;
page->m_rot_rate_msb = (uint8_t)(3600 >> 8);
page->m_rot_rate_lsb = (uint8_t)3600;
}
void t10sbc::ReadCapacity( uint8_t *data )
{
- hard_disk_info *info = hard_disk_get_info(m_disk);
+ const auto &info = m_image->get_info();
// get # of sectors
- uint32_t temp = info->cylinders * info->heads * info->sectors - 1;
-
- data[0] = (temp>>24) & 0xff;
- data[1] = (temp>>16) & 0xff;
- data[2] = (temp>>8) & 0xff;
- data[3] = (temp & 0xff);
- data[4] = (info->sectorbytes>>24)&0xff;
- data[5] = (info->sectorbytes>>16)&0xff;
- data[6] = (info->sectorbytes>>8)&0xff;
- data[7] = (info->sectorbytes & 0xff);
+ uint32_t temp = info.cylinders * info.heads * info.sectors - 1;
+
+ put_u32be(&data[0], temp);
+ put_u32be(&data[4], info.sectorbytes);
}
diff --git a/src/devices/machine/t10sbc.h b/src/devices/machine/t10sbc.h
index e9a3ce0cec9..b385f9664b5 100644
--- a/src/devices/machine/t10sbc.h
+++ b/src/devices/machine/t10sbc.h
@@ -18,12 +18,10 @@ class t10sbc : public virtual t10spc
{
public:
t10sbc()
- : t10spc(), m_image(nullptr), m_lba(0), m_blocks(0), m_disk(nullptr), m_device(nullptr)
+ : t10spc(), m_image(nullptr), m_lba(0), m_blocks(0), m_device(nullptr)
{
}
- virtual void SetDevice( void *device ) override;
- virtual void GetDevice( void **device ) override;
virtual void ExecCommand() override;
virtual void WriteData( uint8_t *data, int dataLength ) override;
virtual void ReadData( uint8_t *data, int dataLength ) override;
@@ -94,7 +92,6 @@ protected:
uint32_t m_lba;
uint32_t m_blocks;
- hard_disk_file *m_disk;
device_t *m_device;
};
diff --git a/src/devices/machine/t10spc.cpp b/src/devices/machine/t10spc.cpp
index ecea2802511..e5f636edf74 100644
--- a/src/devices/machine/t10spc.cpp
+++ b/src/devices/machine/t10spc.cpp
@@ -3,6 +3,8 @@
#include "emu.h"
#include "t10spc.h"
+#include "multibyte.h"
+
void t10spc::t10_start(device_t &device)
{
m_device = &device;
@@ -95,19 +97,14 @@ void t10spc::ReadData( uint8_t *data, int dataLength )
if (command[4] == 0)
{
data[0] = m_sense_asc & 0x7f;
- data[1] = (m_sense_information >> 16) & 0x1f;
- data[2] = (m_sense_information >> 8) & 0xff;
- data[3] = (m_sense_information >> 0) & 0xff;
+ put_u24be(&data[1], m_sense_information & 0x1fffff);
}
else
{
data[0] = 0x70;
data[1] = 0;
data[2] = m_sense_key & 0xf;
- data[3] = (m_sense_information >> 24) & 0xff;
- data[4] = (m_sense_information >> 16) & 0xff;
- data[5] = (m_sense_information >> 8) & 0xff;
- data[6] = (m_sense_information >> 0) & 0xff;
+ put_u32be(&data[3], m_sense_information);
data[7] = 10;
data[8] = 0;
data[9] = 0;
diff --git a/src/devices/machine/t10spc.h b/src/devices/machine/t10spc.h
index 254ce87a4c0..7140b2016c8 100644
--- a/src/devices/machine/t10spc.h
+++ b/src/devices/machine/t10spc.h
@@ -20,8 +20,6 @@ public:
}
virtual ~t10spc() { }
- virtual void SetDevice( void *device ) = 0;
- virtual void GetDevice( void **device ) = 0;
virtual void SetCommand( uint8_t *command, int commandLength );
virtual void ExecCommand();
@@ -52,6 +50,8 @@ protected:
SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_PAUSED = 0x0012,
SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_SUCCESSFULLY_COMPLETED = 0x0013,
SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR = 0x0014,
+ SCSI_SENSE_ASC_ASCQ_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE = 0x2100,
+ SCSI_SENSE_ASC_ASCQ_ILLEGAL_FIELD_IN_CDB = 0x2400,
SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK = 0x6400
};
diff --git a/src/devices/machine/tc009xlvc.cpp b/src/devices/machine/tc009xlvc.cpp
index 1b0a779f3fd..c0c5e41fed4 100644
--- a/src/devices/machine/tc009xlvc.cpp
+++ b/src/devices/machine/tc009xlvc.cpp
@@ -13,7 +13,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/tc009xlvc.h"
+#include "tc009xlvc.h"
#include "emupal.h"
#include "screen.h"
@@ -31,17 +31,17 @@ void tc0090lvc_device::vram_w(offs_t offset, u8 data)
if (offset >= 0x8000 && offset < 0x9000) // 0x8000-0x9000 bg 0
{
offset -= 0x8000;
- bg_tilemap[0]->mark_tile_dirty(offset/2);
+ m_bg_tilemap[0]->mark_tile_dirty(offset/2);
}
else if (offset >= 0x9000 && offset < 0xa000) // 0x9000-0xa000 bg 1
{
offset -= 0x9000;
- bg_tilemap[1]->mark_tile_dirty(offset/2);
+ m_bg_tilemap[1]->mark_tile_dirty(offset/2);
}
else if (offset >= 0xa000 && offset < 0xb000) // 0xa000-0xb000 text
{
offset -= 0xa000;
- tx_tilemap->mark_tile_dirty(offset/2);
+ m_tx_tilemap->mark_tile_dirty(offset/2);
}
// 0xb000-0xb3ff sprites
}
@@ -50,19 +50,13 @@ void tc0090lvc_device::vregs_w(offs_t offset, u8 data)
{
if ((offset & 0xfc) == 0)
{
- bg_tilemap[0]->mark_all_dirty();
- bg_tilemap[1]->mark_all_dirty();
+ m_bg_tilemap[0]->mark_all_dirty();
+ m_bg_tilemap[1]->mark_all_dirty();
}
m_vregs[offset] = data;
}
-void tc0090lvc_device::ram_bank_w(offs_t offset, u8 data)
-{
- m_ram_bank[offset] = data;
- m_bankdev[offset]->set_bank(m_ram_bank[offset]);
-}
-
static const gfx_layout layout_8x8 =
{
8, 8,
@@ -100,15 +94,12 @@ void tc0090lvc_device::cpu_map(address_map &map)
// 0x8000-0xbfff External mappable area
// 0xc000-0xfdff RAM banks (Connected in VRAMs, 4KB boundary)
- map(0xc000, 0xcfff).m(m_bankdev[0], FUNC(address_map_bank_device::amap8));
- map(0xd000, 0xdfff).m(m_bankdev[1], FUNC(address_map_bank_device::amap8));
- map(0xe000, 0xefff).m(m_bankdev[2], FUNC(address_map_bank_device::amap8));
- map(0xf000, 0xfdff).m(m_bankdev[3], FUNC(address_map_bank_device::amap8));
+ map(0xc000, 0xfdff).rw(FUNC(tc0090lvc_device::banked_vram_r), FUNC(tc0090lvc_device::banked_vram_w));
// 0xfe00-0xffff Internal functions
}
-void tc0090lvc_device::banked_map(address_map &map)
+void tc0090lvc_device::vram_map(address_map &map)
{
map(0x010000, 0x01ffff).readonly().share("vram");
// note, the way tiles are addressed suggests that 0x0000-0x3fff of this might be usable,
@@ -124,14 +115,16 @@ tc0090lvc_device::tc0090lvc_device(const machine_config &mconfig, const char *ta
}
tc0090lvc_device::tc0090lvc_device(const machine_config &mconfig, device_type &type, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, type, tag, owner, clock)
+ : z80_device(mconfig, type, tag, owner, clock)
, device_gfx_interface(mconfig, *this, gfxinfo, "palette")
+ , m_program_space_config("program", ENDIANNESS_LITTLE, 8, 16, 0, address_map_constructor(FUNC(tc0090lvc_device::cpu_map), this))
+ , m_vram_space_config("vram_space", ENDIANNESS_LITTLE, 8, 20, 0, address_map_constructor(FUNC(tc0090lvc_device::vram_map), this))
+ , m_io_space_config("io", ENDIANNESS_LITTLE, 8, 16, 0) // TODO: IO space exists like original Z80?
, m_tilemap_xoffs(0)
, m_tilemap_yoffs(0)
, m_tilemap_flipped_xoffs(0)
, m_tilemap_flipped_yoffs(0)
, m_irq_enable(0)
- , m_bankdev(*this, "bankdev_%u", 0U)
, m_vram(*this, "vram")
, m_bitmap_ram(*this, "bitmap_ram")
, m_rom(*this, DEVICE_SELF)
@@ -144,6 +137,15 @@ tc0091lvc_device::tc0091lvc_device(const machine_config &mconfig, const char *ta
{
}
+device_memory_interface::space_config_vector tc0090lvc_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_space_config),
+ std::make_pair(AS_DATA, &m_vram_space_config),
+ std::make_pair(AS_IO, &m_io_space_config)
+ };
+}
+
/*
Scroll Tilemap format (2 bytes per tiles, 64x32 tilemap)
@@ -163,8 +165,7 @@ TILE_GET_INFO_MEMBER(tc0090lvc_device::get_tile_info)
| ((attr & 0x03) << 8)
| ((tilebank((attr & 0xc) >> 2)) << 10);
- if (!m_tile_cb.isnull())
- m_tile_cb(code);
+ m_tile_cb(code);
tileinfo.set(0,
code,
@@ -197,18 +198,13 @@ TILE_GET_INFO_MEMBER(tc0090lvc_device::get_tx_tile_info)
void tc0090lvc_device::device_add_mconfig(machine_config &config)
{
- for (int i = 0; i < 4; i++)
- {
- ADDRESS_MAP_BANK(config, m_bankdev[i]).set_map(&tc0090lvc_device::banked_map).set_options(ENDIANNESS_LITTLE, 8, 20, 0x1000);
- }
PALETTE(config, "palette", palette_device::BLACK).set_format(palette_device::xBGRBBBBGGGGRRRR_bit0, 0x100);
}
void tc0090lvc_device::device_post_load()
{
- for (int i = 0; i < 4; i++)
- m_bankdev[i]->set_bank(m_ram_bank[i]);
+ gfx(2)->mark_all_dirty();
}
@@ -217,32 +213,34 @@ void tc0090lvc_device::device_start()
// rom_r assumes it can make a mask with (m_rom.length() - 1)
assert(!(m_rom.length() & (m_rom.length() - 1)));
- m_tile_cb.resolve();
+ z80_device::device_start();
+
+ space(AS_DATA).specific(m_vram_space);
+
+ m_tile_cb.resolve_safe();
std::fill_n(&m_vram[0], m_vram.bytes(), 0);
std::fill_n(&m_bitmap_ram[0], m_bitmap_ram.bytes(), 0);
std::fill(std::begin(m_ram_bank), std::end(m_ram_bank), 0);
- for (int i = 0; i < 4; i++)
- m_bankdev[i]->set_bank(m_ram_bank[i]);
m_vregs = make_unique_clear<u8[]>(0x100);
m_sprram_buffer = make_unique_clear<u8[]>(0x400);
- tx_tilemap = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(tc0090lvc_device::get_tx_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
- bg_tilemap[0] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(tc0090lvc_device::get_tile_info<0x8000>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
- bg_tilemap[1] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(tc0090lvc_device::get_tile_info<0x9000>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
+ m_tx_tilemap = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(tc0090lvc_device::get_tx_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
+ m_bg_tilemap[0] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(tc0090lvc_device::get_tile_info<0x8000>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
+ m_bg_tilemap[1] = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(tc0090lvc_device::get_tile_info<0x9000>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
- tx_tilemap->set_transparent_pen(0);
- bg_tilemap[0]->set_transparent_pen(0);
- bg_tilemap[1]->set_transparent_pen(0);
+ m_tx_tilemap->set_transparent_pen(0);
+ m_bg_tilemap[0]->set_transparent_pen(0);
+ m_bg_tilemap[1]->set_transparent_pen(0);
- tx_tilemap->set_scrolldx((-8) + m_tilemap_xoffs, (-8) + m_tilemap_flipped_xoffs);
- bg_tilemap[0]->set_scrolldx(28 + m_tilemap_xoffs, (-11) + m_tilemap_flipped_xoffs);
- bg_tilemap[1]->set_scrolldx(38 + m_tilemap_xoffs, (-21) + m_tilemap_flipped_xoffs);
+ m_tx_tilemap->set_scrolldx((-8) + m_tilemap_xoffs, (-8) + m_tilemap_flipped_xoffs);
+ m_bg_tilemap[0]->set_scrolldx(28 + m_tilemap_xoffs, (-11) + m_tilemap_flipped_xoffs);
+ m_bg_tilemap[1]->set_scrolldx(38 + m_tilemap_xoffs, (-21) + m_tilemap_flipped_xoffs);
- tx_tilemap->set_scrolldy(m_tilemap_yoffs, m_tilemap_flipped_yoffs);
- bg_tilemap[0]->set_scrolldy(m_tilemap_yoffs, m_tilemap_flipped_yoffs);
- bg_tilemap[1]->set_scrolldy(m_tilemap_yoffs, m_tilemap_flipped_yoffs);
+ m_tx_tilemap->set_scrolldy(m_tilemap_yoffs, m_tilemap_flipped_yoffs);
+ m_bg_tilemap[0]->set_scrolldy(m_tilemap_yoffs, m_tilemap_flipped_yoffs);
+ m_bg_tilemap[1]->set_scrolldy(m_tilemap_yoffs, m_tilemap_flipped_yoffs);
save_item(NAME(m_bg_scroll));
save_item(NAME(m_irq_vector));
@@ -262,22 +260,21 @@ void tc0090lvc_device::device_reset()
m_irq_enable = 0;
for (int i = 0; i < 4; i++)
- {
m_ram_bank[i] = 0x80;
- m_bankdev[i]->set_bank(m_ram_bank[i]);
- }
m_rom_bank = 0;
+ z80_device::device_reset();
+
/* video related */
m_vregs[0] = m_vregs[1] = m_vregs[2] = m_vregs[3] = m_vregs[4] = 0;
}
void tc0090lvc_device::mark_all_layer_dirty()
{
- tx_tilemap->mark_all_dirty();
- bg_tilemap[0]->mark_all_dirty();
- bg_tilemap[1]->mark_all_dirty();
+ m_tx_tilemap->mark_all_dirty();
+ m_bg_tilemap[0]->mark_all_dirty();
+ m_bg_tilemap[1]->mark_all_dirty();
}
/*
@@ -312,13 +309,10 @@ void tc0090lvc_device::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap,
int fx = m_sprram_buffer[count + 3] & 0x1;
int fy = m_sprram_buffer[count + 3] & 0x2;
- if (!m_tile_cb.isnull())
- {
- // each sprite is 4 8x8 tile group, actually tile number for each tile is << 2 of real address
- code <<= 2;
- m_tile_cb(code);
- code >>= 2;
- }
+ // each sprite is 4 8x8 tile group, actually tile number for each tile is << 2 of real address
+ code <<= 2;
+ m_tile_cb(code);
+ code >>= 2;
if (global_flip())
{
@@ -365,31 +359,32 @@ u32 tc0090lvc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
if (global_flip()) { dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf; }
int dy = m_bg_scroll[0][2];
- bg_tilemap[0]->set_scrollx(0, -dx);
- bg_tilemap[0]->set_scrolly(0, -dy);
+ m_bg_tilemap[0]->set_scrollx(0, -dx);
+ m_bg_tilemap[0]->set_scrolly(0, -dy);
dx = m_bg_scroll[1][0] | (m_bg_scroll[1][1] << 8);
if (global_flip()) { dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf; }
dy = m_bg_scroll[1][2];
- bg_tilemap[1]->set_scrollx(0, -dx);
- bg_tilemap[1]->set_scrolly(0, -dy);
+ m_bg_tilemap[1]->set_scrollx(0, -dx);
+ m_bg_tilemap[1]->set_scrolly(0, -dy);
screen.priority().fill(0, cliprect);
- bg_tilemap[1]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0); // TODO: opaque?
- bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, (bg0_pri()) ? 0 : 1);
+ m_bg_tilemap[1]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0); // TODO: opaque flag?
+ m_bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, (bg0_pri()) ? 0 : 1);
draw_sprites(screen, bitmap, cliprect);
- tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
}
return 0;
}
u32 tc0091lvc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- bitmap.fill(palette().black_pen(), cliprect);
-
if (!screen_enable())
+ {
+ bitmap.fill(palette().black_pen(), cliprect);
return 0;
+ }
if (bitmap_mode()) // 8bpp bitmap enabled
{
@@ -414,21 +409,21 @@ u32 tc0091lvc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
if (global_flip()) { dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf; }
int dy = m_bg_scroll[0][2];
- bg_tilemap[0]->set_scrollx(0, -dx);
- bg_tilemap[0]->set_scrolly(0, -dy);
+ m_bg_tilemap[0]->set_scrollx(0, -dx);
+ m_bg_tilemap[0]->set_scrolly(0, -dy);
dx = m_bg_scroll[1][0] | (m_bg_scroll[1][1] << 8);
if (global_flip()) { dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf; }
dy = m_bg_scroll[1][2];
- bg_tilemap[1]->set_scrollx(0, -dx);
- bg_tilemap[1]->set_scrolly(0, -dy);
+ m_bg_tilemap[1]->set_scrollx(0, -dx);
+ m_bg_tilemap[1]->set_scrolly(0, -dy);
screen.priority().fill(0, cliprect);
- bg_tilemap[1]->draw(screen, bitmap, cliprect, 0, 0); // not opaque?
- bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, (bg0_pri()) ? 0 : 1);
+ m_bg_tilemap[1]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0); // TODO: opaque flag?
+ m_bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, (bg0_pri()) ? 0 : 1);
draw_sprites(screen, bitmap, cliprect);
- tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
}
return 0;
}
diff --git a/src/devices/machine/tc009xlvc.h b/src/devices/machine/tc009xlvc.h
index 367e47eaadd..c4be5989a78 100644
--- a/src/devices/machine/tc009xlvc.h
+++ b/src/devices/machine/tc009xlvc.h
@@ -11,10 +11,10 @@
#pragma once
-#include "machine/bankdev.h"
+#include "cpu/z80/z80.h"
#include "tilemap.h"
-class tc0090lvc_device : public device_t, public device_gfx_interface
+class tc0090lvc_device : public z80_device, public device_gfx_interface
{
public:
typedef device_delegate<void (u32 &code)> tc009xlvc_cb_delegate;
@@ -37,7 +37,7 @@ public:
u8 irq_enable_r() { return m_irq_enable; }
void irq_enable_w(u8 data) { m_irq_enable = data; }
u8 ram_bank_r(offs_t offset) { return m_ram_bank[offset]; }
- void ram_bank_w(offs_t offset, u8 data);
+ void ram_bank_w(offs_t offset, u8 data) { m_ram_bank[offset] = data; }
u8 rom_bank_r() { return m_rom_bank; }
void rom_bank_w(u8 data) { m_rom_bank = data; }
@@ -56,11 +56,28 @@ public:
protected:
tc0090lvc_device(const machine_config &mconfig, device_type &type, const char *tag, device_t *owner, u32 clock);
+ // device-level overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_post_load() override;
virtual void device_start() override;
virtual void device_reset() override;
+ // device_config_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // address space configurations
+ const address_space_config m_program_space_config;
+ const address_space_config m_vram_space_config;
+ const address_space_config m_io_space_config;
+
+ memory_access<20, 0, 0, ENDIANNESS_LITTLE>::specific m_vram_space;
+
+ // vram space handlers
+ const inline offs_t vram_addr(offs_t offset) { return (m_ram_bank[BIT(offset, 12, 2)] << 12) | (offset & 0xfff); }
+
+ u8 banked_vram_r(offs_t offset) { return m_vram_space.read_byte(vram_addr(offset)); }
+ void banked_vram_w(offs_t offset, u8 data) { m_vram_space.write_byte(vram_addr(offset), data); }
+
void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void update_scroll(u8 *ram);
@@ -69,12 +86,12 @@ protected:
template<unsigned Offset> TILE_GET_INFO_MEMBER(get_tile_info);
TILE_GET_INFO_MEMBER(get_tx_tile_info);
- void banked_map(address_map &map);
+ void vram_map(address_map &map);
u8 m_bg_scroll[2][4];
- tilemap_t *bg_tilemap[2];
- tilemap_t *tx_tilemap;
+ tilemap_t *m_bg_tilemap[2];
+ tilemap_t *m_tx_tilemap;
DECLARE_GFXDECODE_MEMBER(gfxinfo);
@@ -96,7 +113,6 @@ protected:
std::unique_ptr<u8[]> m_vregs;
std::unique_ptr<u8[]> m_sprram_buffer;
- required_device_array<address_map_bank_device, 4> m_bankdev;
required_shared_ptr<u8> m_vram;
required_shared_ptr<u8> m_bitmap_ram;
required_region_ptr<u8> m_rom;
diff --git a/src/devices/machine/tc9223.cpp b/src/devices/machine/tc9223.cpp
new file mode 100644
index 00000000000..b13859cfbad
--- /dev/null
+++ b/src/devices/machine/tc9223.cpp
@@ -0,0 +1,75 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// TC9223P/TC9223F PLL-based frequency synthesizer
+
+// Minimal implementation, logs the commands
+
+#include "emu.h"
+#include "tc9223.h"
+
+DEFINE_DEVICE_TYPE(TC9223, tc9223_device, "tc9223", "TC9223P/F frequency synthesizer")
+
+tc9223_device::tc9223_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, TC9223, tag, owner, clock)
+{
+}
+
+void tc9223_device::device_start()
+{
+ save_item(NAME(m_shift));
+ save_item(NAME(m_stb));
+ save_item(NAME(m_clk));
+ save_item(NAME(m_dat));
+}
+
+void tc9223_device::device_reset()
+{
+ m_shift = 0;
+ m_stb = 0;
+ m_clk = 0;
+ m_dat = 0;
+}
+
+void tc9223_device::stb_w(int state)
+{
+ if(state == m_stb)
+ return;
+ m_stb = state;
+ if(!m_stb)
+ return;
+ switch(m_shift >> 14) {
+ case 0:
+ logerror("gpio=%s lock=%s\n",
+ m_shift & 0x1000 ? "1" : "0",
+ m_shift & 0x2000 ? "unlocked" : "normal");
+ break;
+ case 1:
+ logerror("a=%d n=%d\n", m_shift & 0x3f, (m_shift >> 6) & 0x7ff);
+ break;
+ case 2:
+ logerror("divider %d\n", m_shift & 0x3fff);
+ break;
+ case 3:
+ logerror("%s %s\n",
+ m_shift & 0x1000 ? "falling" : "rising",
+ m_shift & 0x2000 ? "non-inverting" : "inverting");
+ break;
+ }
+}
+
+void tc9223_device::clk_w(int state)
+{
+ if(state == m_clk)
+ return;
+ m_clk = state;
+ if(!m_clk)
+ return;
+
+ m_shift = (m_shift >> 1) | (m_dat ? 0x8000 : 0);
+}
+
+void tc9223_device::dat_w(int state)
+{
+ m_dat = state;
+}
diff --git a/src/devices/machine/tc9223.h b/src/devices/machine/tc9223.h
new file mode 100644
index 00000000000..bac0d07d691
--- /dev/null
+++ b/src/devices/machine/tc9223.h
@@ -0,0 +1,30 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// TC9223P/TC9223F PLL-based frequency synthesizer
+#ifndef MAME_MACHINE_TC9223_H
+#define MAME_MACHINE_TC9223_H
+
+#pragma once
+
+class tc9223_device : public device_t
+{
+public:
+ tc9223_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ void stb_w(int state);
+ void dat_w(int state);
+ void clk_w(int state);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ u16 m_shift;
+ u8 m_stb, m_clk, m_dat;
+};
+
+DECLARE_DEVICE_TYPE(TC9223, tc9223_device)
+
+#endif // MAME_MACHINE_TC9223_H
diff --git a/src/devices/machine/tdc1008.cpp b/src/devices/machine/tdc1008.cpp
index 33966e08063..598c30a24e3 100644
--- a/src/devices/machine/tdc1008.cpp
+++ b/src/devices/machine/tdc1008.cpp
@@ -75,11 +75,6 @@ void tdc1008_device::device_start()
save_item(NAME(m_x.u));
save_item(NAME(m_y.u));
save_item(NAME(m_p_out.u));
-
- m_xtp.resolve_safe();
- m_msp.resolve_safe();
- m_lsp.resolve_safe();
- m_p.resolve_safe();
}
void tdc1008_device::device_reset()
@@ -121,21 +116,21 @@ void tdc1008_device::y_w(uint8_t data)
m_y_in = data;
}
-WRITE_LINE_MEMBER(tdc1008_device::tsx_w)
+void tdc1008_device::tsx_w(int state)
{
m_tsx = (bool)state;
if (m_prel && m_tsx)
m_p_out.u = (m_p_out.u & 0x0ffff) | (m_xtp_in << 16);
}
-WRITE_LINE_MEMBER(tdc1008_device::tsm_w)
+void tdc1008_device::tsm_w(int state)
{
m_tsm = (bool)state;
if (m_prel && m_tsm)
m_p_out.u = (m_p_out.u & 0x700ff) | (m_msp_in << 8);
}
-WRITE_LINE_MEMBER(tdc1008_device::tsl_w)
+void tdc1008_device::tsl_w(int state)
{
m_tsl = (bool)state;
if (m_prel && m_tsl)
@@ -168,7 +163,7 @@ void tdc1008_device::output_w(uint32_t data)
m_p_in = data;
}
-WRITE_LINE_MEMBER(tdc1008_device::clk_x_w)
+void tdc1008_device::clk_x_w(int state)
{
bool old = m_clk_x;
m_clk_x = (bool)state;
@@ -179,7 +174,7 @@ WRITE_LINE_MEMBER(tdc1008_device::clk_x_w)
}
}
-WRITE_LINE_MEMBER(tdc1008_device::clk_y_w)
+void tdc1008_device::clk_y_w(int state)
{
bool old = m_clk_y;
m_clk_y = (bool)state;
@@ -190,7 +185,7 @@ WRITE_LINE_MEMBER(tdc1008_device::clk_y_w)
}
}
-WRITE_LINE_MEMBER(tdc1008_device::clk_p_w)
+void tdc1008_device::clk_p_w(int state)
{
bool old = m_clk_p;
m_clk_p = (bool)state;
@@ -245,7 +240,7 @@ WRITE_LINE_MEMBER(tdc1008_device::clk_p_w)
}
}
-WRITE_LINE_MEMBER(tdc1008_device::prel_w)
+void tdc1008_device::prel_w(int state)
{
m_prel = (bool)state;
if (m_prel)
@@ -259,22 +254,22 @@ WRITE_LINE_MEMBER(tdc1008_device::prel_w)
}
}
-WRITE_LINE_MEMBER(tdc1008_device::rnd_w)
+void tdc1008_device::rnd_w(int state)
{
m_rnd_in = (bool)state;
}
-WRITE_LINE_MEMBER(tdc1008_device::tc_w)
+void tdc1008_device::tc_w(int state)
{
m_tc_in = (bool)state;
}
-WRITE_LINE_MEMBER(tdc1008_device::acc_w)
+void tdc1008_device::acc_w(int state)
{
m_acc_in = (bool)state;
}
-WRITE_LINE_MEMBER(tdc1008_device::sub_w)
+void tdc1008_device::sub_w(int state)
{
m_sub_in = (bool)state;
}
diff --git a/src/devices/machine/tdc1008.h b/src/devices/machine/tdc1008.h
index dcb8d21c9d5..a9a98c420be 100644
--- a/src/devices/machine/tdc1008.h
+++ b/src/devices/machine/tdc1008.h
@@ -26,17 +26,17 @@ public:
void x_w(uint8_t data);
void y_w(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(tsx_w);
- DECLARE_WRITE_LINE_MEMBER(tsm_w);
- DECLARE_WRITE_LINE_MEMBER(tsl_w);
- DECLARE_WRITE_LINE_MEMBER(clk_x_w);
- DECLARE_WRITE_LINE_MEMBER(clk_y_w);
- DECLARE_WRITE_LINE_MEMBER(clk_p_w);
- DECLARE_WRITE_LINE_MEMBER(prel_w);
- DECLARE_WRITE_LINE_MEMBER(rnd_w);
- DECLARE_WRITE_LINE_MEMBER(tc_w);
- DECLARE_WRITE_LINE_MEMBER(acc_w);
- DECLARE_WRITE_LINE_MEMBER(sub_w);
+ void tsx_w(int state);
+ void tsm_w(int state);
+ void tsl_w(int state);
+ void clk_x_w(int state);
+ void clk_y_w(int state);
+ void clk_p_w(int state);
+ void prel_w(int state);
+ void rnd_w(int state);
+ void tc_w(int state);
+ void acc_w(int state);
+ void sub_w(int state);
// Output preloads by group
void xtp_w(uint8_t data);
diff --git a/src/devices/machine/te7750.cpp b/src/devices/machine/te7750.cpp
index 58fd60cc49c..94376c6dafb 100644
--- a/src/devices/machine/te7750.cpp
+++ b/src/devices/machine/te7750.cpp
@@ -170,13 +170,14 @@
**********************************************************************/
#include "emu.h"
-#include "machine/te7750.h"
+#include "te7750.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
DEFINE_DEVICE_TYPE(TE7750, te7750_device, "te7750", "TE7750 Super I/O Expander")
+DEFINE_DEVICE_TYPE(TE7751, te7751_device, "te7751", "TE7751 Super I/O Expander")
DEFINE_DEVICE_TYPE(TE7752, te7752_device, "te7752", "TE7752 Super I/O Expander")
//**************************************************************************
@@ -189,9 +190,9 @@ DEFINE_DEVICE_TYPE(TE7752, te7752_device, "te7752", "TE7752 Super I/O Expander")
te7750_device::te7750_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
- , m_input_cb(*this)
+ , m_input_cb(*this, 0xff)
, m_output_cb(*this)
- , m_ios_cb(*this)
+ , m_ios_cb(*this, 0) // assume soft mode unless specified
{
std::fill(std::begin(m_data_dir), std::end(m_data_dir), 0xff);
}
@@ -202,6 +203,15 @@ te7750_device::te7750_device(const machine_config &mconfig, const char *tag, dev
}
//-------------------------------------------------
+// te7751_device - constructor
+//-------------------------------------------------
+
+te7751_device::te7751_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : te7750_device(mconfig, TE7751, tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
// te7752_device - constructor
//-------------------------------------------------
@@ -216,13 +226,6 @@ te7752_device::te7752_device(const machine_config &mconfig, const char *tag, dev
void te7750_device::device_start()
{
- // resolve port callbacks
- m_input_cb.resolve_all_safe(0xff);
- m_output_cb.resolve_all_safe();
-
- // resolve IOS (assume soft mode unless specified)
- m_ios_cb.resolve_safe(0);
-
// save state
save_item(NAME(m_data_latch));
save_item(NAME(m_data_dir));
diff --git a/src/devices/machine/te7750.h b/src/devices/machine/te7750.h
index fea02f2b4c1..8417fbce51a 100644
--- a/src/devices/machine/te7750.h
+++ b/src/devices/machine/te7750.h
@@ -73,6 +73,14 @@ private:
u8 m_data_dir[9];
};
+// ======================> te7751_device
+
+class te7751_device : public te7750_device
+{
+public:
+ te7751_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+};
+
// ======================> te7752_device
class te7752_device : public te7750_device
@@ -83,6 +91,7 @@ public:
// device type definitions
DECLARE_DEVICE_TYPE(TE7750, te7750_device)
+DECLARE_DEVICE_TYPE(TE7751, te7751_device)
DECLARE_DEVICE_TYPE(TE7752, te7752_device)
#endif // MAME_MACHINE_TE7750_H
diff --git a/src/devices/machine/terminal.cpp b/src/devices/machine/terminal.cpp
index ed1dd4d001f..b367a12857b 100644
--- a/src/devices/machine/terminal.cpp
+++ b/src/devices/machine/terminal.cpp
@@ -1,7 +1,8 @@
// license:BSD-3-Clause
// copyright-holders:Miodrag Milanovic
#include "emu.h"
-#include "machine/terminal.h"
+#include "terminal.h"
+
#include "screen.h"
#include "speaker.h"
@@ -346,8 +347,8 @@ void generic_terminal_device::device_add_mconfig(machine_config &config)
void generic_terminal_device::device_start()
{
m_buffer = std::make_unique<uint8_t []>(m_width * m_height);
- m_bell_timer = timer_alloc(BELL_TIMER_ID);
- m_keyboard_cb.resolve();
+ m_bell_timer = timer_alloc(FUNC(generic_terminal_device::bell_off), this);
+ m_keyboard_cb.resolve_safe();
save_pointer(NAME(m_buffer), m_width * m_height);
save_item(NAME(m_x_pos));
save_item(NAME(m_framecnt));
@@ -361,14 +362,9 @@ void generic_terminal_device::device_reset()
m_framecnt = 0;
}
-void generic_terminal_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(generic_terminal_device::bell_off)
{
- switch (id)
- {
- case BELL_TIMER_ID:
- m_beeper->set_state(0);
- break;
- }
+ m_beeper->set_state(0);
}
/*
diff --git a/src/devices/machine/terminal.h b/src/devices/machine/terminal.h
index aa98c91dc62..098d776e5e0 100644
--- a/src/devices/machine/terminal.h
+++ b/src/devices/machine/terminal.h
@@ -34,17 +34,16 @@ public:
void kbd_put(u8 data);
protected:
- enum { BELL_TIMER_ID = 20'000 };
-
generic_terminal_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, unsigned w, unsigned h);
virtual void term_write(uint8_t data);
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual ioport_constructor device_input_ports() const override;
virtual void device_add_mconfig(machine_config &config) override;
- virtual void send_key(uint8_t code) { if (!m_keyboard_cb.isnull()) m_keyboard_cb(code); }
+ virtual void send_key(uint8_t code) { m_keyboard_cb(code); }
+
+ TIMER_CALLBACK_MEMBER(bell_off);
required_ioport m_io_term_conf;
diff --git a/src/devices/machine/ticket.cpp b/src/devices/machine/ticket.cpp
index 8cf8e3fddf0..92e5f316819 100644
--- a/src/devices/machine/ticket.cpp
+++ b/src/devices/machine/ticket.cpp
@@ -2,14 +2,14 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- ticket.c
+ ticket.cpp
Generic ticket dispensing device.
***************************************************************************/
#include "emu.h"
-#include "machine/ticket.h"
+#include "ticket.h"
//**************************************************************************
@@ -17,7 +17,9 @@
//**************************************************************************
#define DEBUG_TICKET 0
-#define LOG(x) do { if (DEBUG_TICKET) logerror x; } while (0)
+
+#define VERBOSE (DEBUG_TICKET)
+#include "logmacro.h"
@@ -52,6 +54,7 @@ ticket_dispenser_device::ticket_dispenser_device(const machine_config &mconfig,
, m_power(0)
, m_timer(nullptr)
, m_output(*this, tag) // TODO: change to "tag:status"
+ , m_dispense_handler(*this) // TODO: can we use m_output for this?
{
}
@@ -82,7 +85,7 @@ ticket_dispenser_device::~ticket_dispenser_device()
// line_r - read the status line
//-------------------------------------------------
-READ_LINE_MEMBER( ticket_dispenser_device::line_r )
+int ticket_dispenser_device::line_r()
{
return m_status ? 1 : 0;
}
@@ -92,14 +95,14 @@ READ_LINE_MEMBER( ticket_dispenser_device::line_r )
// motor_w - write the control line
//-------------------------------------------------
-WRITE_LINE_MEMBER( ticket_dispenser_device::motor_w )
+void ticket_dispenser_device::motor_w(int state)
{
// On an activate signal, start dispensing!
if (bool(state) == m_motoron)
{
if (!m_power)
{
- LOG(("%s: Ticket Power On\n", machine().describe_context()));
+ LOG("%s: Ticket Power On\n", machine().describe_context());
m_timer->adjust(m_period);
m_power = true;
m_status = m_ticketnotdispensed;
@@ -111,7 +114,7 @@ WRITE_LINE_MEMBER( ticket_dispenser_device::motor_w )
{
if (m_hopper_type == false || m_status == m_ticketnotdispensed)
{
- LOG(("%s: Ticket Power Off\n", machine().describe_context()));
+ LOG("%s: Ticket Power Off\n", machine().describe_context());
m_timer->adjust(attotime::never);
m_output = 0;
}
@@ -135,7 +138,7 @@ void ticket_dispenser_device::device_start()
m_ticketdispensed = (m_status_sense == TICKET_STATUS_ACTIVE_HIGH);
m_ticketnotdispensed = !m_ticketdispensed;
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(ticket_dispenser_device::update_output_state), this);
m_output.resolve();
@@ -156,22 +159,22 @@ void ticket_dispenser_device::device_reset()
//-------------------------------------------------
-// device_timer - handle timer callbacks
+// update_output_state -
//-------------------------------------------------
-void ticket_dispenser_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ticket_dispenser_device::update_output_state)
{
// if we still have power, keep toggling ticket states
if (m_power)
{
m_status = !m_status;
- LOG(("Ticket Status Changed to %02X\n", m_status));
+ LOG("Ticket Status Changed to %02X\n", m_status);
m_timer->adjust(m_period);
}
else if (m_hopper_type)
{
m_status = !m_status;
- LOG(("%s: Ticket Power Off\n", machine().describe_context()));
+ LOG("%s: Ticket Power Off\n", machine().describe_context());
m_timer->adjust(attotime::never);
m_output = 0;
}
@@ -179,10 +182,14 @@ void ticket_dispenser_device::device_timer(emu_timer &timer, device_timer_id id,
// update output status
m_output = m_status == m_ticketdispensed;
+ if (m_hopper_type)
+ {
+ m_dispense_handler(m_status);
+ }
// if we just dispensed, increment global count
if (m_status == m_ticketdispensed)
{
machine().bookkeeping().increment_dispensed_tickets(1);
- LOG(("Ticket Dispensed\n"));
+ LOG("Ticket Dispensed\n");
}
}
diff --git a/src/devices/machine/ticket.h b/src/devices/machine/ticket.h
index 7330ad3cb74..797fac5bd4e 100644
--- a/src/devices/machine/ticket.h
+++ b/src/devices/machine/ticket.h
@@ -61,17 +61,20 @@ public:
m_hopper_type = hopper_type;
}
+ auto dispense_handler() { return m_dispense_handler.bind(); }
+
// read/write handlers
- DECLARE_READ_LINE_MEMBER( line_r );
- DECLARE_WRITE_LINE_MEMBER( motor_w );
+ int line_r();
+ void motor_w(int state);
protected:
ticket_dispenser_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0);
// device-level overrides
- virtual void device_start() override ATTR_COLD;
- virtual void device_reset() override ATTR_COLD;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ TIMER_CALLBACK_MEMBER(update_output_state);
// configuration state
uint8_t m_motor_sense;
@@ -88,6 +91,7 @@ protected:
bool m_power;
emu_timer *m_timer;
output_finder<> m_output;
+ devcb_write_line m_dispense_handler;
};
class hopper_device : public ticket_dispenser_device
@@ -101,6 +105,9 @@ public:
set_senses(motor_sense, status_sense, true);
}
hopper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+private:
+
};
#endif // MAME_MACHINE_TICKET_H
diff --git a/src/devices/machine/timekpr.cpp b/src/devices/machine/timekpr.cpp
index 5128ef1ac62..c5ed19a3330 100644
--- a/src/devices/machine/timekpr.cpp
+++ b/src/devices/machine/timekpr.cpp
@@ -15,10 +15,10 @@
***************************************************************************/
#include "emu.h"
-#include "machine/timekpr.h"
+#include "timekpr.h"
+
#include "machine/timehelp.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_TICKS (1U << 1)
#define VERBOSE (0)
@@ -31,6 +31,7 @@ DEFINE_DEVICE_TYPE(M48T37, m48t37_device, "m48t37", "M48T37 Timekeeper")
DEFINE_DEVICE_TYPE(M48T58, m48t58_device, "m48t58", "M48T58 Timekeeper")
DEFINE_DEVICE_TYPE(MK48T08, mk48t08_device, "mk48t08", "MK48T08 Timekeeper")
DEFINE_DEVICE_TYPE(MK48T12, mk48t12_device, "mk48t12", "MK48T12 Timekeeper")
+DEFINE_DEVICE_TYPE(DS1643, ds1643_device, "ds1643", "DS1643 Nonvolatile Timekeeping RAM")
/***************************************************************************
@@ -48,12 +49,12 @@ DEFINE_DEVICE_TYPE(MK48T12, mk48t12_device, "mk48t12", "MK48T12 Timekeeper")
#define CONTROL_W (0x80)
#define CONTROL_R (0x40)
-#define CONTROL_S (0x20) /* not emulated */
-#define CONTROL_CALIBRATION (0x1f) /* not emulated */
+#define CONTROL_S (0x20) /* not emulated - unused on DS1643 */
+#define CONTROL_CALIBRATION (0x1f) /* not emulated - unused on DS1643 */
#define SECONDS_ST (0x80)
-#define DAY_FT (0x40) /* M48T37 - not emulated */
+#define DAY_FT (0x40) /* M48T37/DS1643 - not emulated */
#define DAY_CEB (0x20) /* M48T35/M48T58 */
#define DAY_CB (0x10) /* M48T35/M48T58 */
@@ -91,6 +92,7 @@ inline int counter_from_ram(u8 const *data, s32 offset, u8 unmap = 0)
timekeeper_device::timekeeper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 size)
: device_t(mconfig, type, tag, owner, clock)
, device_nvram_interface(mconfig, *this)
+ , device_rtc_interface(mconfig, *this)
, m_reset_cb(*this)
, m_irq_cb(*this)
, m_default_data(*this, DEVICE_SELF)
@@ -162,6 +164,11 @@ m48t58_device::m48t58_device(const machine_config &mconfig, const char *tag, dev
m_offset_flags = -1;
}
+m48t58_device::m48t58_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : timekeeper_device(mconfig, type, tag, owner, clock, 0x2000)
+{
+}
+
mk48t08_device::mk48t08_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: timekeeper_device(mconfig, MK48T08, tag, owner, clock, 0x2000)
{
@@ -193,6 +200,11 @@ mk48t12_device::mk48t12_device(const machine_config &mconfig, const char *tag, d
m_offset_century = -1;
}
+ds1643_device::ds1643_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : m48t58_device(mconfig, DS1643, tag, owner, clock)
+{
+}
+
//-------------------------------------------------
// device_start - device-specific startup
@@ -200,19 +212,7 @@ mk48t12_device::mk48t12_device(const machine_config &mconfig, const char *tag, d
void timekeeper_device::device_start()
{
- system_time systime;
-
- machine().base_datetime(systime);
-
m_control = 0;
- m_seconds = time_helper::make_bcd(systime.local_time.second);
- m_minutes = time_helper::make_bcd(systime.local_time.minute);
- m_hours = time_helper::make_bcd(systime.local_time.hour);
- m_day = time_helper::make_bcd(systime.local_time.weekday + 1);
- m_date = time_helper::make_bcd(systime.local_time.mday);
- m_month = time_helper::make_bcd(systime.local_time.month + 1);
- m_year = time_helper::make_bcd(systime.local_time.year % 100);
- m_century = time_helper::make_bcd(systime.local_time.year / 100);
m_data.resize(m_size);
save_item(NAME(m_control));
@@ -227,20 +227,32 @@ void timekeeper_device::device_start()
save_item(NAME(m_data));
save_item(NAME(m_watchdog_delay));
- emu_timer *timer = timer_alloc();
+ emu_timer *timer = timer_alloc(FUNC(timekeeper_device::timer_tick), this);
timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
- m_watchdog_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(timekeeper_device::watchdog_callback), this));
+ m_watchdog_timer = timer_alloc(FUNC(timekeeper_device::watchdog_callback), this);
m_watchdog_timer->adjust(attotime::never);
- m_reset_cb.resolve_safe();
- m_irq_cb.resolve_safe();
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
-void timekeeper_device::device_reset() { }
+void timekeeper_device::device_reset()
+{
+}
+
+void timekeeper_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ m_seconds = time_helper::make_bcd(second);
+ m_minutes = time_helper::make_bcd(minute);
+ m_hours = time_helper::make_bcd(hour);
+ m_day = time_helper::make_bcd(day_of_week);
+ m_date = time_helper::make_bcd(day);
+ m_month = time_helper::make_bcd(month);
+ m_year = time_helper::make_bcd(year % 100);
+ m_century = time_helper::make_bcd(year / 100);
+}
void timekeeper_device::counters_to_ram()
{
@@ -268,7 +280,7 @@ void timekeeper_device::counters_from_ram()
m_century = counter_from_ram(&m_data[0], m_offset_century);
}
-void timekeeper_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(timekeeper_device::timer_tick)
{
LOGMASKED(LOG_TICKS, "Tick\n");
if ((m_seconds & SECONDS_ST) != 0 ||
@@ -366,7 +378,7 @@ void timekeeper_device::watchdog_write(u8 data)
void timekeeper_device::write(offs_t offset, u8 data)
{
- LOGMASKED(LOG_GENERAL, "timekeeper_device::write: %04x = %02x\n", offset, data);
+ LOG("timekeeper_device::write: %04x = %02x\n", offset, data);
if (offset == m_offset_control)
{
if ((m_control & CONTROL_W) != 0 &&
@@ -426,7 +438,7 @@ u8 timekeeper_device::read(offs_t offset)
m_reset_cb(CLEAR_LINE);
m_irq_cb(CLEAR_LINE);
}
- LOGMASKED(LOG_GENERAL, "timekeeper_device::read: %04x (%02x)\n", offset, result);
+ LOG("timekeeper_device::read: %04x (%02x)\n", offset, result);
return result;
}
@@ -457,11 +469,14 @@ void timekeeper_device::nvram_default()
// .nv file
//-------------------------------------------------
-void timekeeper_device::nvram_read(emu_file &file)
+bool timekeeper_device::nvram_read(util::read_stream &file)
{
- file.read(&m_data[0], m_size);
+ auto const [err, actual] = util::read(file, &m_data[0], m_size);
+ if (err || (actual != m_size))
+ return false;
counters_to_ram();
+ return true;
}
@@ -470,7 +485,8 @@ void timekeeper_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void timekeeper_device::nvram_write(emu_file &file)
+bool timekeeper_device::nvram_write(util::write_stream &file)
{
- file.write(&m_data[0], m_size);
+ auto const [err, actual] = util::write(file, &m_data[0], m_size);
+ return !err;
}
diff --git a/src/devices/machine/timekpr.h b/src/devices/machine/timekpr.h
index def60c02059..365d1f07a86 100644
--- a/src/devices/machine/timekpr.h
+++ b/src/devices/machine/timekpr.h
@@ -12,6 +12,9 @@
- MK48T08
- MK48T12
+ Dallas clones that have the same functional interface:
+ - DS1643
+
***************************************************************************/
#ifndef MAME_MACHINE_TIMEKPR_H
@@ -19,7 +22,7 @@
#pragma once
-
+#include "dirtc.h"
//**************************************************************************
@@ -29,7 +32,7 @@
// ======================> timekeeper_device
-class timekeeper_device : public device_t, public device_nvram_interface
+class timekeeper_device : public device_t, public device_nvram_interface, public device_rtc_interface
{
public:
void write(offs_t offset, u8 data);
@@ -46,13 +49,18 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() const override { return m_offset_century != -1; }
+ virtual bool rtc_feature_leap_year() const override { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+ TIMER_CALLBACK_MEMBER(timer_tick);
TIMER_CALLBACK_MEMBER(watchdog_callback);
devcb_write_line m_reset_cb;
devcb_write_line m_irq_cb;
@@ -114,6 +122,9 @@ class m48t58_device : public timekeeper_device
{
public:
m48t58_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+protected:
+ m48t58_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
};
class mk48t08_device : public timekeeper_device
@@ -128,6 +139,12 @@ public:
mk48t12_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
};
+class ds1643_device : public m48t58_device
+{
+public:
+ ds1643_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+};
+
// device type definition
DECLARE_DEVICE_TYPE(M48T02, m48t02_device)
DECLARE_DEVICE_TYPE(M48T35, m48t35_device)
@@ -135,5 +152,6 @@ DECLARE_DEVICE_TYPE(M48T37, m48t37_device)
DECLARE_DEVICE_TYPE(M48T58, m48t58_device)
DECLARE_DEVICE_TYPE(MK48T08, mk48t08_device)
DECLARE_DEVICE_TYPE(MK48T12, mk48t12_device)
+DECLARE_DEVICE_TYPE(DS1643, ds1643_device)
#endif // MAME_MACHINE_TIMEKPR_H
diff --git a/src/devices/machine/timer.cpp b/src/devices/machine/timer.cpp
index 2461fb4da30..f2dc8464578 100644
--- a/src/devices/machine/timer.cpp
+++ b/src/devices/machine/timer.cpp
@@ -9,7 +9,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/timer.h"
+#include "timer.h"
/***************************************************************************
@@ -33,19 +33,18 @@ DEFINE_DEVICE_TYPE(TIMER, timer_device, "timer", "Timer")
// timer_device - constructor
//-------------------------------------------------
-timer_device::timer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, TIMER, tag, owner, clock),
- m_type(TIMER_TYPE_GENERIC),
- m_callback(*this),
- m_ptr(nullptr),
- m_start_delay(attotime::zero),
- m_period(attotime::zero),
- m_param(0),
- m_screen(*this, finder_base::DUMMY_TAG),
- m_first_vpos(0),
- m_increment(0),
- m_timer(nullptr),
- m_first_time(true)
+timer_device::timer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, TIMER, tag, owner, clock),
+ m_type(TIMER_TYPE_GENERIC),
+ m_callback(*this),
+ m_start_delay(attotime::zero),
+ m_period(attotime::zero),
+ m_param(0),
+ m_screen(*this, finder_base::DUMMY_TAG),
+ m_first_vpos(0),
+ m_increment(0),
+ m_timer(nullptr),
+ m_first_time(true)
{
}
@@ -103,8 +102,10 @@ void timer_device::device_validity_check(validity_checker &valid) const
void timer_device::device_start()
{
- // allocate the timer
- m_timer = timer_alloc();
+ if (m_type == TIMER_TYPE_SCANLINE)
+ m_timer = timer_alloc(FUNC(timer_device::scanline_tick), this);
+ else
+ m_timer = timer_alloc(FUNC(timer_device::generic_tick), this);
m_callback.resolve();
@@ -154,44 +155,31 @@ void timer_device::device_reset()
}
-//-------------------------------------------------
-// device_timer - handle timer expiration events
-//-------------------------------------------------
-
-void timer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(timer_device::generic_tick)
{
- switch (m_type)
- {
- // general periodic timers just call through
- case TIMER_TYPE_GENERIC:
- case TIMER_TYPE_PERIODIC:
- if (!m_callback.isnull())
- (m_callback)(*this, m_ptr, param);
- break;
-
- // scanline timers have to do some additional bookkeeping
- case TIMER_TYPE_SCANLINE:
- {
- // by default, we fire at the first position
- int next_vpos = m_first_vpos;
+ if (!m_callback.isnull())
+ (m_callback)(*this, param);
+}
- // the first time through we just go with the default position
- if (!m_first_time)
- {
- // call the real callback
- int vpos = m_screen->vpos();
- if (!m_callback.isnull())
- (m_callback)(*this, m_ptr, vpos);
-
- // advance by the increment only if we will still be within the screen bounds
- if (m_increment != 0 && (vpos + m_increment) < m_screen->height())
- next_vpos = vpos + m_increment;
- }
- m_first_time = false;
+TIMER_CALLBACK_MEMBER(timer_device::scanline_tick)
+{
+ // by default, we fire at the first position
+ int next_vpos = m_first_vpos;
- // adjust the timer
- m_timer->adjust(m_screen->time_until_pos(next_vpos));
- break;
- }
+ // the first time through we just go with the default position
+ if (!m_first_time)
+ {
+ // call the real callback
+ int vpos = m_screen->vpos();
+ if (!m_callback.isnull())
+ (m_callback)(*this, vpos);
+
+ // advance by the increment only if we will still be within the screen bounds
+ if (m_increment != 0 && (vpos + m_increment) < m_screen->height())
+ next_vpos = vpos + m_increment;
}
+ m_first_time = false;
+
+ // adjust the timer
+ m_timer->adjust(m_screen->time_until_pos(next_vpos));
}
diff --git a/src/devices/machine/timer.h b/src/devices/machine/timer.h
index 04d0f192325..965235c7b6f 100644
--- a/src/devices/machine/timer.h
+++ b/src/devices/machine/timer.h
@@ -20,7 +20,7 @@
//**************************************************************************
// macros for a timer callback functions
-#define TIMER_DEVICE_CALLBACK_MEMBER(name) void name(timer_device &timer, void *ptr, s32 param)
+#define TIMER_DEVICE_CALLBACK_MEMBER(name) void name(timer_device &timer, s32 param)
//**************************************************************************
// TYPE DEFINITIONS
@@ -32,7 +32,7 @@ class timer_device : public device_t
{
public:
// a timer callbacks look like this
- typedef device_delegate<void (timer_device &, void *, s32)> expired_delegate;
+ typedef device_delegate<void (timer_device &, s32)> expired_delegate;
// construction/destruction
timer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
@@ -77,16 +77,14 @@ public:
template <typename... T> void set_callback(T &&... args) { m_callback.set(std::forward<T>(args)...); }
void set_start_delay(const attotime &delay) { m_start_delay = delay; }
- void config_param(int param) { m_param = param; }
+ void config_param(s32 param) { m_param = param; }
// property getters
- int param() const { return m_timer->param(); }
- void *ptr() const { return m_ptr; }
+ s32 param() const { return m_timer->param(); }
bool enabled() const { return m_timer->enabled(); }
// property setters
- void set_param(int param) const { if(m_type != TIMER_TYPE_GENERIC) fatalerror("Cannot change parameter on a non-generic timer.\n"); m_timer->set_param(param); }
- void set_ptr(void *ptr) { m_ptr = ptr; }
+ void set_param(s32 param) const { if(m_type != TIMER_TYPE_GENERIC) fatalerror("Cannot change parameter on a non-generic timer.\n"); m_timer->set_param(param); }
void enable(bool enable = true) const { m_timer->enable(enable); }
// adjustments
@@ -99,10 +97,10 @@ public:
}
// timing information
- attotime time_elapsed() const { return m_timer->elapsed(); }
- attotime time_left() const { return m_timer->remaining(); }
- attotime start_time() const { return m_timer->start(); }
- attotime fire_time() const { return m_timer->expire(); }
+ attotime elapsed() const { return m_timer->elapsed(); }
+ attotime remaining() const { return m_timer->remaining(); }
+ attotime start() const { return m_timer->start(); }
+ attotime expire() const { return m_timer->expire(); }
attotime period() const { return m_timer ? m_timer->period() : m_period; }
private:
@@ -110,7 +108,9 @@ private:
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(generic_tick);
+ TIMER_CALLBACK_MEMBER(scanline_tick);
// timer types
enum timer_type
@@ -123,7 +123,6 @@ private:
// configuration data
timer_type m_type; // type of timer
expired_delegate m_callback; // the timer's callback function
- void * m_ptr; // the pointer parameter passed to the timer callback
// periodic timers only
attotime m_start_delay; // delay before the timer fires for the first time
diff --git a/src/devices/machine/tmc0430.cpp b/src/devices/machine/tmc0430.cpp
index 76e53c88ded..8264830817a 100644
--- a/src/devices/machine/tmc0430.cpp
+++ b/src/devices/machine/tmc0430.cpp
@@ -94,13 +94,13 @@
#include "emu.h"
#include "tmc0430.h"
-#define LOG_DETAIL (1U<<1) // More detail
-#define LOG_ADDRESS (1U<<2) // Address bus
-#define LOG_CLOCK (1U<<3) // Clock line
-#define LOG_READY (1U<<4) // Ready line
-#define LOG_LINES (1U<<5) // Select/mode lines
+#define LOG_DETAIL (1U << 1) // More detail
+#define LOG_ADDRESS (1U << 2) // Address bus
+#define LOG_CLOCK (1U << 3) // Clock line
+#define LOG_READY (1U << 4) // Ready line
+#define LOG_LINES (1U << 5) // Select/mode lines
-#define VERBOSE ( LOG_GENERAL )
+#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
@@ -135,7 +135,7 @@ tmc0430_device::tmc0430_device(const machine_config &mconfig, const char *tag, d
/*
Direction. When ASSERTed, GROM is set to be read by CPU.
*/
-WRITE_LINE_MEMBER( tmc0430_device::m_line )
+void tmc0430_device::m_line(int state)
{
m_read_mode = (state==ASSERT_LINE);
LOGMASKED(LOG_LINES, "GROM %d dir %s\n", m_ident>>13, m_read_mode? "READ" : "WRITE");
@@ -144,7 +144,7 @@ WRITE_LINE_MEMBER( tmc0430_device::m_line )
/*
Mode. When ASSERTed, the address counter will be accessed (read or write).
*/
-WRITE_LINE_MEMBER( tmc0430_device::mo_line )
+void tmc0430_device::mo_line(int state)
{
m_address_mode = (state==ASSERT_LINE);
LOGMASKED(LOG_LINES, "GROM %d mode %s\n", m_ident>>13, m_address_mode? "ADDR" : "DATA");
@@ -153,7 +153,7 @@ WRITE_LINE_MEMBER( tmc0430_device::mo_line )
/*
Select. When ASSERTed, the read/write operation is started.
*/
-WRITE_LINE_MEMBER( tmc0430_device::gsq_line )
+void tmc0430_device::gsq_line(int state)
{
if (state==ASSERT_LINE && !m_selected) // check for edge
{
@@ -197,7 +197,7 @@ void tmc0430_device::set_lines(line_state mline, line_state moline, line_state g
For the emulation we may assume that all GROMs at the same clock line
raise their outputs synchronously.
*/
-WRITE_LINE_MEMBER( tmc0430_device::gclock_in )
+void tmc0430_device::gclock_in(int state)
{
int bank = 0;
uint16_t baddr = 0;
@@ -334,7 +334,6 @@ void tmc0430_device::write(uint8_t data)
void tmc0430_device::device_start()
{
- m_gromready.resolve_safe();
save_item(NAME(m_current_clock_level));
save_item(NAME(m_current_ident));
save_item(NAME(m_phase));
diff --git a/src/devices/machine/tmc0430.h b/src/devices/machine/tmc0430.h
index 09800f2f514..2e8e58d506b 100644
--- a/src/devices/machine/tmc0430.h
+++ b/src/devices/machine/tmc0430.h
@@ -41,10 +41,10 @@ public:
void write(uint8_t data);
void set_lines(line_state mline, line_state moline, line_state gsq);
- DECLARE_WRITE_LINE_MEMBER(m_line);
- DECLARE_WRITE_LINE_MEMBER(mo_line);
- DECLARE_WRITE_LINE_MEMBER(gsq_line);
- DECLARE_WRITE_LINE_MEMBER(gclock_in);
+ void m_line(int state);
+ void mo_line(int state);
+ void gsq_line(int state);
+ void gclock_in(int state);
void set_region_and_ident(const char *regionname, int offset, int ident)
{
diff --git a/src/devices/machine/tmc0999.cpp b/src/devices/machine/tmc0999.cpp
new file mode 100644
index 00000000000..e40426e61d8
--- /dev/null
+++ b/src/devices/machine/tmc0999.cpp
@@ -0,0 +1,97 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+Texas Instruments TMC0999 256x4 RAM
+
+It's not a standard RAM chip, it has separate pins for input and output
+and an internal address latch.
+
+TODO:
+- no official documentation is known to exist, unknown if anything is missing
+- pin names are unknown
+
+*/
+
+#include "emu.h"
+#include "tmc0999.h"
+
+
+DEFINE_DEVICE_TYPE(TMC0999, tmc0999_device, "tmc0999", "TI TMC0999 RAM")
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+tmc0999_device::tmc0999_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, TMC0999, tag, owner, clock)
+{ }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tmc0999_device::device_start()
+{
+ // zerofill
+ m_data = 0;
+ m_wr = 0;
+ m_rd = 0;
+ m_adr_strobe = 0;
+ m_ram_address = 0;
+ memset(m_ram, 0, sizeof(m_ram));
+
+ // register for savestates
+ save_item(NAME(m_data));
+ save_item(NAME(m_wr));
+ save_item(NAME(m_rd));
+ save_item(NAME(m_adr_strobe));
+ save_item(NAME(m_ram_address));
+ save_item(NAME(m_ram));
+}
+
+
+//-------------------------------------------------
+// handlers
+//-------------------------------------------------
+
+void tmc0999_device::di_w(u8 data)
+{
+ m_data = data & 0xf;
+}
+
+u8 tmc0999_device::do_r()
+{
+ u8 data = m_rd ? m_ram[m_ram_address] : 0;
+ return data & 0xf;
+}
+
+void tmc0999_device::wr_w(int state)
+{
+ state = state ? 1 : 0;
+
+ // write to RAM on rising edge
+ if (state && !m_wr)
+ m_ram[m_ram_address] = m_data;
+ m_wr = state;
+}
+
+void tmc0999_device::rd_w(int state)
+{
+ // enable data outputs
+ m_rd = state ? 1 : 0;
+}
+
+void tmc0999_device::adr_w(int state)
+{
+ state = state ? 1 : 0;
+
+ // set RAM address lo on rising edge
+ // set RAM address hi on falling edge
+ if (state && !m_adr_strobe)
+ m_ram_address = (m_ram_address & 0xf0) | m_data;
+ else if (!state && m_adr_strobe)
+ m_ram_address = (m_ram_address & 0x0f) | m_data << 4;
+ m_adr_strobe = state;
+}
diff --git a/src/devices/machine/tmc0999.h b/src/devices/machine/tmc0999.h
new file mode 100644
index 00000000000..24305b8d8ee
--- /dev/null
+++ b/src/devices/machine/tmc0999.h
@@ -0,0 +1,57 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+/*
+
+ Texas Instruments TMC0999 256x4 RAM
+
+*/
+
+#ifndef MAME_MACHINE_TMC0999_H
+#define MAME_MACHINE_TMC0999_H
+
+#pragma once
+
+/*
+
+quick pinout reference (18-pin DIP)
+
+17,18,1,2: data outputs (do_r)
+3-6: data inputs (di_w)
+7: address latch strobe (adr_w)
+13: data input strobe (wr_w)
+14: data output enable (rd_w)
+
+*/
+
+
+class tmc0999_device : public device_t
+{
+public:
+ tmc0999_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ void di_w(u8 data);
+ u8 do_r();
+ void wr_w(int state);
+ void rd_w(int state);
+ void adr_w(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+private:
+ // input pins state
+ u8 m_data;
+ int m_wr;
+ int m_rd;
+ int m_adr_strobe;
+
+ // internal state
+ u8 m_ram_address;
+ u8 m_ram[0x100];
+};
+
+
+DECLARE_DEVICE_TYPE(TMC0999, tmc0999_device)
+
+#endif // MAME_MACHINE_TMC0999_H
diff --git a/src/devices/machine/tmc208k.cpp b/src/devices/machine/tmc208k.cpp
index fe275fd693c..5d138b7ba98 100644
--- a/src/devices/machine/tmc208k.cpp
+++ b/src/devices/machine/tmc208k.cpp
@@ -69,10 +69,6 @@ void tmc208_base_device<RegType, OutType>::device_start()
save_item(NAME(m_clk_r));
save_item(NAME(m_rnd_in));
save_item(NAME(m_rnd));
-
- m_msp.resolve_safe();
- m_lsp.resolve_safe();
- m_r.resolve_safe();
}
template <typename RegType, typename OutType>
diff --git a/src/devices/machine/tmp68301.cpp b/src/devices/machine/tmp68301.cpp
deleted file mode 100644
index f6cd84dd318..00000000000
--- a/src/devices/machine/tmp68301.cpp
+++ /dev/null
@@ -1,380 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Luca Elia, AJR
-/***************************************************************************
-
- TMP68301 basic emulation + Interrupt Handling
-
- The Toshiba TMP68301 is a 68HC000 + serial I/O, parallel I/O,
- 3 timers, address decoder, wait generator, interrupt controller,
- all integrated in a single chip.
-
- TODO:
- - Interrupt generation: edge detection, input expansion (INT3-INT9)
- - Parallel port: handle timing latency
- - Serial port: not done at all
- - (and many other things)
-
-***************************************************************************/
-
-#include "emu.h"
-#include "machine/tmp68301.h"
-
-DEFINE_DEVICE_TYPE(TMP68301, tmp68301_device, "tmp68301", "Toshiba TMP68301")
-
-void tmp68301_device::tmp68301_regs(address_map &map)
-{
- map(0x000, 0x3ff).rw(FUNC(tmp68301_device::regs_r), FUNC(tmp68301_device::regs_w));
-
- map(0x080, 0x093).rw(FUNC(tmp68301_device::icr_r), FUNC(tmp68301_device::icr_w)).umask16(0x00ff);
-
- map(0x094, 0x095).rw(FUNC(tmp68301_device::imr_r), FUNC(tmp68301_device::imr_w));
- map(0x096, 0x097).rw(FUNC(tmp68301_device::ipr_r), FUNC(tmp68301_device::ipr_w));
- map(0x098, 0x099).rw(FUNC(tmp68301_device::iisr_r), FUNC(tmp68301_device::iisr_w));
-
- /* Parallel Port */
- map(0x100, 0x101).rw(FUNC(tmp68301_device::pdir_r), FUNC(tmp68301_device::pdir_w));
- map(0x10a, 0x10b).rw(FUNC(tmp68301_device::pdr_r), FUNC(tmp68301_device::pdr_w));
-
- /* Serial Port */
- map(0x18e, 0x18f).rw(FUNC(tmp68301_device::scr_r), FUNC(tmp68301_device::scr_w));
-}
-
-// IRQ Mask register
-uint16_t tmp68301_device::imr_r()
-{
- return m_imr;
-}
-
-void tmp68301_device::imr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
-{
- COMBINE_DATA(&m_imr);
- update_ipl();
-}
-
-// IRQ Pending Register
-uint16_t tmp68301_device::ipr_r()
-{
- return m_ipr;
-}
-
-void tmp68301_device::ipr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
-{
- // software writes only clear bits
- m_ipr &= data | ~mem_mask;
- update_ipl();
-}
-
-// IRQ In-Service Register
-uint16_t tmp68301_device::iisr_r()
-{
- return m_iisr;
-}
-
-void tmp68301_device::iisr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
-{
- // software writes only clear bits
- m_iisr &= data | ~mem_mask;
-}
-
-// Serial Control Register (TODO: 8-bit wide)
-uint16_t tmp68301_device::scr_r()
-{
- return m_scr;
-}
-
-void tmp68301_device::scr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
-{
- /*
- *--- ---- CKSE
- --*- ---- RES
- ---- ---* INTM
- */
-
- COMBINE_DATA(&m_scr);
- m_scr &= 0xa1;
-}
-
-/* Parallel direction: 1 = output, 0 = input */
-uint16_t tmp68301_device::pdir_r()
-{
- return m_pdir;
-}
-
-void tmp68301_device::pdir_w(offs_t offset, uint16_t data, uint16_t mem_mask)
-{
- COMBINE_DATA(&m_pdir);
-}
-
-uint16_t tmp68301_device::pdr_r()
-{
- return (m_in_parallel_cb(0) & ~m_pdir) | (m_pdr & m_pdir);
-}
-
-void tmp68301_device::pdr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
-{
- uint16_t old = m_pdr;
- COMBINE_DATA(&m_pdr);
- m_pdr = (old & ~m_pdir) | (m_pdr & m_pdir);
- m_out_parallel_cb(0, m_pdr, mem_mask);
-}
-
-uint8_t tmp68301_device::icr_r(offs_t offset)
-{
- return m_icr[offset];
-}
-
-void tmp68301_device::icr_w(offs_t offset, uint8_t data)
-{
-/*
- --x- ---- Vector number is autogenerated if 1, else use external source
- ---x x--- 00 falling edge, 01 low level, 10 rising edge, 11 high level
- ^ applies only to external irqs (offset 0 to 2)
- ---- -xxx irq level
-*/
- m_icr[offset] = data;
-}
-
-tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : m68000_device(mconfig, TMP68301, tag, owner, clock),
- m_in_parallel_cb(*this),
- m_out_parallel_cb(*this),
- m_ipl(0),
- m_imr(0),
- m_ipr(0),
- m_iisr(0),
- m_scr(0),
- m_pdir(0),
- m_pdr(0)
-{
- memset(m_regs, 0, sizeof(m_regs));
- memset(m_icr, 0, sizeof(m_icr));
- m_cpu_space_config.m_internal_map = address_map_constructor(FUNC(tmp68301_device::internal_vectors_r), this);
-}
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void tmp68301_device::device_start()
-{
- m68000_device::device_start();
-
- for (int i = 0; i < 3; i++)
- m_tmp68301_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tmp68301_device::timer_callback), this));
-
- m_in_parallel_cb.resolve_safe(0);
- m_out_parallel_cb.resolve_safe();
-
- m_program->install_device(0xfffc00, 0xffffff, *this, &tmp68301_device::tmp68301_regs);
-
- save_item(NAME(m_regs));
- save_item(NAME(m_icr));
- save_item(NAME(m_ipl));
- save_item(NAME(m_imr));
- save_item(NAME(m_ipr));
- save_item(NAME(m_iisr));
- save_item(NAME(m_scr));
- save_item(NAME(m_pdir));
- save_item(NAME(m_pdr));
-}
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void tmp68301_device::device_reset()
-{
- m68000_device::device_reset();
-
- m_ipr = 0;
- m_iisr = 0;
- m_imr = 0x7f7; // mask all irqs
- std::fill(std::begin(m_icr), std::end(m_icr), 0x07);
- update_ipl();
-}
-
-//**************************************************************************
-// INLINE HELPERS
-//**************************************************************************
-
-void tmp68301_device::internal_vectors_r(address_map &map)
-{
- map(0xfffff0, 0xffffff).r(FUNC(tmp68301_device::irq_callback)).umask16(0x00ff);
-}
-
-
-uint8_t tmp68301_device::irq_callback(offs_t offset)
-{
- uint8_t IVNR = m_regs[0x9a/2] & 0xe0; // Interrupt Vector Number Register (IVNR)
-
- for (int src : { 0, 7, 3, 1, 8, 4, 5, 9, 2 })
- {
- // check if the IPL matches
- if (offset == (m_icr[src] & 0x07))
- {
- // check if interrupt is pending and not masked out
- u16 mask = (src > 2 ? 2 : 1) << src;
- if ((m_ipr & mask) != 0 && (m_imr & mask) == 0)
- {
- if (!machine().side_effects_disabled())
- {
- // add cause to interrupt in-service register
- m_iisr |= mask;
-
- // no longer pending
- m_ipr &= ~mask;
- update_ipl();
- }
-
- // vary vector number by type
- if (src > 6)
- return IVNR | (src - 3);
- else if (src > 2)
- return IVNR | (src - 1) << 2 | serial_interrupt_cause(src - 3);
- else /*if (BIT(m_icr[src], 5))*/ // TODO: use external vector otherwise
- return IVNR | src;
- }
- }
- }
-
- // default vector
- return IVNR | 0x1f;
-}
-
-TIMER_CALLBACK_MEMBER(tmp68301_device::timer_callback)
-{
- int i = param;
- uint16_t TCR = m_regs[(0x200 + i * 0x20)/2];
-
-// logerror("s: callback timer %04X, j = %d\n",machine().describe_context(),i,tcount);
-
- if (TCR & 0x0004) // INT
- {
- m_ipr |= 0x100 << i;
- update_ipl();
- }
-
- if (TCR & 0x0080) // N/1
- {
- // Repeat
- update_timer(i);
- }
- else
- {
- // One Shot
- }
-}
-
-void tmp68301_device::update_timer(int i)
-{
- uint16_t TCR = m_regs[(0x200 + i * 0x20)/2];
- uint16_t MAX1 = m_regs[(0x204 + i * 0x20)/2];
- uint16_t MAX2 = m_regs[(0x206 + i * 0x20)/2];
-
- int max = 0;
- attotime duration = attotime::zero;
-
- m_tmp68301_timer[i]->adjust(attotime::never,i);
-
- // timers 1&2 only
- switch( (TCR & 0x0030)>>4 ) // MR2..1
- {
- case 1:
- max = MAX1;
- break;
- case 2:
- max = MAX2;
- break;
- }
-
- switch ( (TCR & 0xc000)>>14 ) // CK2..1
- {
- case 0: // System clock (CLK)
- if (max)
- {
- int scale = (TCR & 0x3c00)>>10; // P4..1
- if (scale > 8) scale = 8;
- duration = attotime::from_hz(unscaled_clock()) * ((1 << scale) * max);
- }
- break;
- }
-
-// logerror("%s: TMP68301 Timer %d, duration %lf, max %04X\n",machine().describe_context(),i,duration,max);
-
- if (!(TCR & 0x0002)) // CS
- {
- if (duration != attotime::zero)
- m_tmp68301_timer[i]->adjust(duration,i);
- else
- logerror("%s: TMP68301 error, timer %d duration is 0\n",machine().describe_context(),i);
- }
-}
-
-/* Update the IRQ state based on all possible causes */
-void tmp68301_device::update_ipl()
-{
- uint8_t new_ipl = 0;
-
- for (int src = 0; src < 10; src++)
- {
- u16 mask = (src > 2 ? 2 : 1) << src;
- if ((m_ipr & mask) != 0 && (m_imr & mask) == 0 && new_ipl < (m_icr[src] & 0x07))
- new_ipl = m_icr[src] & 0x07;
- }
-
- if (new_ipl != m_ipl)
- {
- if (m_ipl != 0)
- set_input_line(m_ipl, CLEAR_LINE);
- if (new_ipl != 0)
- set_input_line(new_ipl, ASSERT_LINE);
-
- m_ipl = new_ipl;
- }
-}
-
-uint8_t tmp68301_device::serial_interrupt_cause(int channel)
-{
- /*
- * 00 error occurred
- * 01 receive completed
- * 10 transmit ready
- * 11 interrupt cause cleared while interrupt pending
- */
- (void)channel;
- return 3;
-}
-
-
-uint16_t tmp68301_device::regs_r(offs_t offset)
-{
- return m_regs[offset];
-}
-
-void tmp68301_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
-{
- COMBINE_DATA(&m_regs[offset]);
-
- if (!ACCESSING_BITS_0_7) return;
-
-// logerror("CPU #0 PC %06X: TMP68301 Reg %04X<-%04X & %04X\n", >pc(),offset*2,data,mem_mask^0xffff);
-
- switch( offset * 2 )
- {
- // Timers
- case 0x200:
- case 0x220:
- case 0x240:
- {
- int i = ((offset*2) >> 5) & 3;
-
- update_timer( i );
- }
- break;
- }
-}
-
-void tmp68301_device::external_interrupt_0() { m_ipr |= EXT_IRQ0; update_ipl(); }
-void tmp68301_device::external_interrupt_1() { m_ipr |= EXT_IRQ1; update_ipl(); }
-void tmp68301_device::external_interrupt_2() { m_ipr |= EXT_IRQ2; update_ipl(); }
diff --git a/src/devices/machine/tmp68301.h b/src/devices/machine/tmp68301.h
deleted file mode 100644
index 060519ebd1b..00000000000
--- a/src/devices/machine/tmp68301.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Luca Elia
-#ifndef MAME_MACHINE_TMP68301_H
-#define MAME_MACHINE_TMP68301_H
-
-#pragma once
-
-#include "cpu/m68000/m68000.h"
-
-/* TODO: serial ports, frequency & hook it up with m68k */
-
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-
-
-class tmp68301_device : public m68000_device
-{
-public:
- tmp68301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- auto in_parallel_callback() { return m_in_parallel_cb.bind(); }
- auto out_parallel_callback() { return m_out_parallel_cb.bind(); }
-
- // Interrupts
- void external_interrupt_0();
- void external_interrupt_1();
- void external_interrupt_2();
-
-private:
- uint16_t imr_r();
- void imr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- uint16_t ipr_r();
- void ipr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- uint16_t iisr_r();
- void iisr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- uint16_t scr_r();
- void scr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- uint16_t pdr_r();
- void pdr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- uint16_t pdir_r();
- void pdir_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- uint8_t icr_r(offs_t offset);
- void icr_w(offs_t offset, uint8_t data);
-
- // Hardware Registers
- uint16_t regs_r(offs_t offset);
- void regs_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
-
- void tmp68301_regs(address_map &map);
-
-protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
-
-private:
- TIMER_CALLBACK_MEMBER(timer_callback);
- void update_timer(int i);
- void update_ipl();
- uint8_t serial_interrupt_cause(int channel);
-
- static constexpr uint16_t EXT_IRQ0 = 1 << 0;
- static constexpr uint16_t EXT_IRQ1 = 1 << 1;
- static constexpr uint16_t EXT_IRQ2 = 1 << 2;
- static constexpr uint16_t SERIAL_IRQ_CH0 = 1 << 4;
- static constexpr uint16_t SERIAL_IRQ_CH1 = 1 << 5;
- static constexpr uint16_t SERIAL_IRQ_CH2 = 1 << 6;
- static constexpr uint16_t PARALLEL_IRQ = 1 << 7;
- static constexpr uint16_t TIMER0_IRQ = 1 << 8;
- static constexpr uint16_t TIMER1_IRQ = 1 << 9;
- static constexpr uint16_t TIMER2_IRQ = 1 << 10;
-
- devcb_read16 m_in_parallel_cb;
- devcb_write16 m_out_parallel_cb;
-
- // internal state
- uint16_t m_regs[0x400];
-
- emu_timer *m_tmp68301_timer[3]; // 3 Timers
-
- uint8_t m_ipl; // internal interrupt level
-
- uint16_t m_imr;
- uint16_t m_ipr;
- uint16_t m_iisr;
- uint16_t m_scr;
- uint16_t m_pdir;
- uint16_t m_pdr;
- uint8_t m_icr[10];
-
- void internal_vectors_r(address_map &map);
- uint8_t irq_callback(offs_t offset);
-};
-
-DECLARE_DEVICE_TYPE(TMP68301, tmp68301_device)
-
-#endif // MAME_MACHINE_TMP68301_H
diff --git a/src/devices/machine/tms1024.cpp b/src/devices/machine/tms1024.cpp
index 7c509b03c3d..63de6583e3a 100644
--- a/src/devices/machine/tms1024.cpp
+++ b/src/devices/machine/tms1024.cpp
@@ -8,18 +8,18 @@
is available for pin-compatible Mitsubishi M50780SP/M50781SP.
Other than more port pins, TMS1025 is assumed to be same as TMS1024.
- TODO:
- - x
-
*/
#include "emu.h"
-#include "machine/tms1024.h"
+#include "tms1024.h"
+#define VERBOSE 0
+#include "logmacro.h"
DEFINE_DEVICE_TYPE(TMS1024, tms1024_device, "tms1024", "TMS1024 I/O Expander")
DEFINE_DEVICE_TYPE(TMS1025, tms1025_device, "tms1025", "TMS1025 I/O Expander")
+
//-------------------------------------------------
// constructor
//-------------------------------------------------
@@ -27,7 +27,7 @@ DEFINE_DEVICE_TYPE(TMS1025, tms1025_device, "tms1025", "TMS1025 I/O Expander")
tms1024_device::tms1024_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, m_h(0), m_s(0), m_std(0), m_ms(0)
- , m_read_port(*this)
+ , m_read_port(*this, 0)
, m_write_port(*this)
{
}
@@ -43,17 +43,12 @@ tms1025_device::tms1025_device(const machine_config &mconfig, const char *tag, d
}
-
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void tms1024_device::device_start()
{
- // resolve callbacks (there is no port 0)
- m_read_port.resolve_all_safe(0);
- m_write_port.resolve_all_safe();
-
// register for savestates
save_item(NAME(m_h));
save_item(NAME(m_s));
@@ -62,7 +57,6 @@ void tms1024_device::device_start()
}
-
//-------------------------------------------------
// handlers
//-------------------------------------------------
@@ -79,7 +73,10 @@ u8 tms1024_device::read_h()
{
// read selected port data
if (m_s != 0)
+ {
m_h = (m_read_port[m_s-1])((offs_t)(m_s-1)) & 0xf;
+ LOG("%s: Read %d%d%d%d from P%d\n", machine().describe_context(), BIT(m_h, 3), BIT(m_h, 2), BIT(m_h, 1), BIT(m_h, 0), m_s);
+ }
// high-impedance otherwise
}
@@ -101,11 +98,15 @@ void tms1024_device::write_std(int state)
if (m_ms && !state && m_std)
{
if (m_s != 0)
+ {
+ LOG("%s: Write %d%d%d%d to P%d\n", machine().describe_context(), BIT(m_h, 3), BIT(m_h, 2), BIT(m_h, 1), BIT(m_h, 0), m_s);
(m_write_port[m_s-1])((offs_t)(m_s-1), m_h);
+ }
else
{
// reset all ports
+ LOG("%s: Reset all ports\n", machine().describe_context());
for (int i = PORT1; i <= PORT7; i++)
(m_write_port[i])(offs_t(i), 0);
}
diff --git a/src/devices/machine/tms5501.cpp b/src/devices/machine/tms5501.cpp
index 6f115084d70..9004c8b3167 100644
--- a/src/devices/machine/tms5501.cpp
+++ b/src/devices/machine/tms5501.cpp
@@ -60,7 +60,7 @@ tms5501_device::tms5501_device(const machine_config &mconfig, const char *tag, d
device_serial_interface(mconfig, *this),
m_write_int(*this),
m_write_xmt(*this),
- m_read_xi(*this),
+ m_read_xi(*this, 0),
m_write_xo(*this),
m_irq(IRQ_TB),
m_rb(0),
@@ -81,18 +81,12 @@ tms5501_device::tms5501_device(const machine_config &mconfig, const char *tag, d
void tms5501_device::device_start()
{
- // resolve callbacks
- m_write_int.resolve_safe();
- m_write_xmt.resolve_safe();
- m_read_xi.resolve_safe(0);
- m_write_xo.resolve_safe();
-
// create timers
- m_timer[TIMER_1] = timer_alloc(TIMER_1);
- m_timer[TIMER_2] = timer_alloc(TIMER_2);
- m_timer[TIMER_3] = timer_alloc(TIMER_3);
- m_timer[TIMER_4] = timer_alloc(TIMER_4);
- m_timer[TIMER_5] = timer_alloc(TIMER_5);
+ m_timer[TIMER_1] = timer_alloc(FUNC(tms5501_device::timer_expired), this);
+ m_timer[TIMER_2] = timer_alloc(FUNC(tms5501_device::timer_expired), this);
+ m_timer[TIMER_3] = timer_alloc(FUNC(tms5501_device::timer_expired), this);
+ m_timer[TIMER_4] = timer_alloc(FUNC(tms5501_device::timer_expired), this);
+ m_timer[TIMER_5] = timer_alloc(FUNC(tms5501_device::timer_expired), this);
// state saving
save_item(NAME(m_rb));
@@ -122,38 +116,22 @@ void tms5501_device::device_reset()
//-------------------------------------------------
-// device_timer - handle timer events
+// timer_expired -
//-------------------------------------------------
-void tms5501_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(tms5501_device::timer_expired)
{
- switch (id)
+ if (param == TIMER_5)
{
- case TIMER_1:
- set_interrupt(IRQ_TMR1);
- break;
-
- case TIMER_2:
- set_interrupt(IRQ_TMR2);
- break;
-
- case TIMER_3:
- set_interrupt(IRQ_TMR3);
- break;
-
- case TIMER_4:
- set_interrupt(IRQ_TMR4);
- break;
-
- case TIMER_5:
if (!(m_cmd & CMD_XI7))
{
set_interrupt(IRQ_TMR5);
}
- break;
-
- default:
- break;
+ }
+ else
+ {
+ static uint8_t const s_irq_ids[4] = { IRQ_TMR1, IRQ_TMR2, IRQ_TMR3, IRQ_TMR4 };
+ set_interrupt(s_irq_ids[param]);
}
}
@@ -406,7 +384,7 @@ void tms5501_device::tmr_w(offs_t offset, uint8_t data)
{
if (LOG) logerror("TMS5501 '%s' Timer %u %02x\n", tag(), offset, data);
- m_timer[offset]->adjust(attotime::from_double((double) data / (clock() / 128.0)));
+ m_timer[offset]->adjust(attotime::from_double((double) data / (clock() / 128.0)), (int)offset);
}
diff --git a/src/devices/machine/tms5501.h b/src/devices/machine/tms5501.h
index 74fae77b586..e916141d12c 100644
--- a/src/devices/machine/tms5501.h
+++ b/src/devices/machine/tms5501.h
@@ -80,13 +80,14 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_serial_interface overrides
virtual void tra_callback() override;
virtual void tra_complete() override;
virtual void rcv_complete() override;
+ TIMER_CALLBACK_MEMBER(timer_expired);
+
private:
enum
{
diff --git a/src/devices/machine/tms9901.cpp b/src/devices/machine/tms9901.cpp
index 64250f7079a..46779cd13c0 100644
--- a/src/devices/machine/tms9901.cpp
+++ b/src/devices/machine/tms9901.cpp
@@ -33,7 +33,8 @@ Reference: [1] TMS9901 Programmable Systems Interface Data Manual, July 1977
Overview:
TMS9901 is a support chip for TMS9900. It handles interrupts, provides
several I/O pins, and a timer, which is a register which
- decrements regularly and can generate an interrupt when it reaches 0.
+ decrements continuously and can be set to generate an interrupt when it
+ reaches 0.
It communicates with the TMS9900 with the CRU bus, and with the rest of the
world with a number of parallel I/O pins.
@@ -79,7 +80,8 @@ Interrupt inputs (group 1 and 2)
The interrupt inputs (INT1*-INT15*) are sampled on each falling edge of
the phi* clock. An interrupt mask is applied to mask away levels that
shall not trigger an interrupt. The mask can be set using the SBO/SBZ
- commands (1=arm, 0=disarm) on each of the 15 bits.
+ commands (1=arm, 0=disarm) on each of the 15 bits. A disarmed interrupt
+ input can still be read like a normal input port via CRU access.
After each clock cycle, the TMS9901 latches the state of INT1*-INT15*
(except those pins which are set as output pins).
@@ -98,8 +100,7 @@ Group 2 pins (shared I/O and INT*)
and triggers an interrupt at level 7 when asserted.
In contrast, when writing to bit 31, P15 (same pin) is configured as an
- output, and the written value appears on the pin. When the port is set
- as output, the interrupt input on the shared pin is deactivated.
+ output, and the written value appears on the pin.
According to [1], the interrupt mask should be set to 0 for those group 2
pins that are used as input/output pins so that no unwanted interrupts are
@@ -108,16 +109,20 @@ Group 2 pins (shared I/O and INT*)
Clock mode:
The "clock mode" is entered by setting bit 0 to 1; setting to 0 enters
"interrupt mode". The internal clock is a 14-bit decrementer that
- counts down by 1 every 64 clock ticks. On entering clock mode, the current
- value of the decrementer is copied to the clock read register and can be
- read by the CRU bits 1 to 14. Writing to these CRU bits modifies the
- respective bit of the clock register that serves as the start value. Every
- time a bit is written, the decrementer is loaded with the current clock
- register value.
+ counts down by 1 every 64 clock ticks. On every update, the value is copied
+ into the read register, but only in interrupt mode. In clock mode, the read
+ register is locked so that it can be read without being changed.
+ Whenever the counter reaches 0, it is reloaded from the clock register on
+ the next update.
+ Setting the clock register is possible via CRU addresses 1 to 14 in clock
+ mode, with bit 1 being the LSB and bit 14 being the MSB. On each bit write
+ operation, the current state of the clock register is copied into the counter.
+
+
Interrupt
^
|
- [Clock register] -> [Decrementer] -> [Clock read register]
+ [Clock register] -> [Decrementer] -> [Read register]
^ |
| v
+--<--- CRU write CRU read---<---+
@@ -126,7 +131,7 @@ Clock mode:
and "the clock is disabled by RST1* or by writing a zero value into the clock register".
Tests show that when a 0 has been written, the chip still counts down from
0x3FFF to 0. However, no interrupt is raised when reaching 0, so "enable"
- or "disable" most likely refer to the interrupt.
+ or "disable" most likely refers to the interrupt.
When enabled, the clock raises an interrupt level 3 when reaching 0,
overriding the input from the INT3* input. CRU bit 3 is the mask bit for
@@ -149,14 +154,13 @@ Clock mode:
#include <cmath>
-#define LOG_GENERAL (1U << 0)
#define LOG_PINS (1U << 1)
#define LOG_MASK (1U << 2)
#define LOG_MODE (1U << 3)
#define LOG_INT (1U << 4)
#define LOG_CLOCK (1U << 5)
-#define VERBOSE ( LOG_GENERAL )
+#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
/*
@@ -171,7 +175,7 @@ tms9901_device::tms9901_device(const machine_config &mconfig, const char *tag, d
m_poll_lines(false),
m_clockdiv(0),
m_timer_int_pending(false),
- m_read_port(*this),
+ m_read_port(*this, 0),
m_write_p(*this),
m_interrupt(*this)
{
@@ -261,14 +265,12 @@ void tms9901_device::signal_int()
if (m_int_pending)
{
LOGMASKED(LOG_INT, "Triggering interrupt, level %d\n", m_int_level);
- if (!m_interrupt.isnull())
- m_interrupt(ASSERT_LINE);
+ m_interrupt(ASSERT_LINE);
}
else
{
LOGMASKED(LOG_INT, "Clear all interrupts\n");
- if (!m_interrupt.isnull())
- m_interrupt(CLEAR_LINE); //Spec: INTREQ*=1 <=> IC0,1,2,3 = 1111
+ m_interrupt(CLEAR_LINE); //Spec: INTREQ*=1 <=> IC0,1,2,3 = 1111
}
}
@@ -334,8 +336,8 @@ bool tms9901_device::read_bit(int bit)
else
{
// Positive logic; should be 0 if there is no connection.
- if (m_read_port.isnull()) return false;
- return m_read_port((crubit<=P6)? crubit : P6+P0-crubit)!=0;
+ if (m_read_port.isunset()) return false;
+ return m_read_port((crubit<=P6) ? crubit : P6+P0-crubit)!=0;
}
}
@@ -345,7 +347,7 @@ bool tms9901_device::read_bit(int bit)
if (crubit == 15) // bit 15 in clock mode = /INTREQ
return !m_int_pending;
- return BIT(m_clock_read_register, crubit-1)!=0;
+ return BIT(m_clock_read_register, crubit-1) != 0;
}
else
{
@@ -357,7 +359,7 @@ bool tms9901_device::read_bit(int bit)
if (crubit>INT6 && is_output(22-crubit))
return output_value(22-crubit);
else
- return m_read_port.isnull()? true : (m_read_port(crubit)!=0);
+ return m_read_port.isunset() ? true : (m_read_port(crubit)!=0);
}
}
@@ -394,14 +396,6 @@ void tms9901_device::write_bit(int offset, bool data)
// Write to control bit (CB)
m_clock_mode = (data!=0);
LOGMASKED(LOG_MODE, "Enter %s mode\n", m_clock_mode? "clock" : "interrupt");
-
- if (m_clock_mode)
- {
- // we are switching to clock mode: latch the current value of
- // the decrementer register
- m_clock_read_register = m_decrementer_value;
- LOGMASKED(LOG_MODE, "Clock setting = %d\n", m_clock_read_register);
- }
break;
case 15:
@@ -449,17 +443,34 @@ void tms9901_device::write_bit(int offset, bool data)
}
/*
- Timer callback
+ Update clock line. This is not a real connection to the 9901; it represents
+ the effect of setting selection line S0 to 1. Since we use a separate
+ I/O address space, and in the real machine, the same address lines as for
+ memory access are used, and one of the address lines is connected to S0,
+ we have settings of S0 even in situations when there is no I/O access but
+ ordinary memory access.
+
+ Offering a method explicitly for S0 looks inconsistent with the way of
+ addressing the bits in this chip (that is, we should then offer S1 to S4 as
+ well).
+
+ Drivers may use this line for higher emulation precision concerning the
+ clock.
+*/
+void tms9901_device::update_clock()
+{
+ m_clock_read_register = m_decrementer_value;
+}
+
+/*
+ decrement_tick
Decrementer counts down the value set in clock mode; when it reaches 0,
raises an interrupt and resets to the start value
*/
-void tms9901_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(tms9901_device::decrement_tick)
{
- if (id==DECREMENTER) // we have only that one
- {
- timer_clock_in(ASSERT_LINE);
- timer_clock_in(CLEAR_LINE);
- }
+ timer_clock_in(ASSERT_LINE);
+ timer_clock_in(CLEAR_LINE);
}
void tms9901_device::timer_clock_in(line_state clk)
@@ -467,6 +478,10 @@ void tms9901_device::timer_clock_in(line_state clk)
if (clk == ASSERT_LINE)
{
m_decrementer_value = (m_decrementer_value - 1) & 0x3FFF;
+
+ if (!m_clock_mode)
+ m_clock_read_register = m_decrementer_value;
+
LOGMASKED(LOG_CLOCK, "Clock = %04x\n", m_decrementer_value);
if (m_decrementer_value==0)
{
@@ -496,6 +511,9 @@ void tms9901_device::phi_line(int state)
{
timer_clock_in(ASSERT_LINE);
+ if (!m_clock_mode)
+ m_clock_read_register = m_decrementer_value;
+
// We signal the interrupt in sync with the clock line
signal_int();
@@ -603,14 +621,10 @@ void tms9901_device::device_start()
// Allow for using asynchronous and synchronous clocks
if (clock() != 0)
{
- m_decrementer = timer_alloc(DECREMENTER);
+ m_decrementer = timer_alloc(FUNC(tms9901_device::decrement_tick), this);
m_decrementer->adjust(attotime::from_hz(clock() / 64.), 0, attotime::from_hz(clock() / 64.));
}
- m_read_port.resolve();
- m_write_p.resolve_all_safe();
- m_interrupt.resolve();
-
m_clock_register = 0;
save_item(NAME(m_int_line));
diff --git a/src/devices/machine/tms9901.h b/src/devices/machine/tms9901.h
index 7947845601a..3d4808654a3 100644
--- a/src/devices/machine/tms9901.h
+++ b/src/devices/machine/tms9901.h
@@ -86,15 +86,16 @@ public:
void set_poll_int_lines(bool poll) { m_poll_lines = poll; }
+ void update_clock();
+
private:
- static constexpr device_timer_id DECREMENTER = 0;
+ virtual void device_start() override;
+ virtual void device_stop() override;
+ virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- void soft_reset();
+ TIMER_CALLBACK_MEMBER(decrement_tick);
- void device_start() override;
- void device_stop() override;
- void device_reset() override;
+ void soft_reset();
// Common method for device_reset and rst1_line
void do_reset();
diff --git a/src/devices/machine/tms9902.cpp b/src/devices/machine/tms9902.cpp
index b6f8e4279c9..bb8bb175cf4 100644
--- a/src/devices/machine/tms9902.cpp
+++ b/src/devices/machine/tms9902.cpp
@@ -43,7 +43,6 @@
#include <cmath>
-#define LOG_GENERAL (1U << 0)
#define LOG_LINES (1U << 1)
#define LOG_CRU (1U << 2)
#define LOG_DETAIL (1U << 3)
@@ -54,7 +53,6 @@
#define VERBOSE (LOG_ERROR)
#include "logmacro.h"
-#define LOGGENERAL(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__)
#define LOGLINES(...) LOGMASKED(LOG_LINES, __VA_ARGS__)
#define LOGCRU(...) LOGMASKED(LOG_CRU, __VA_ARGS__)
#define LOGDETAIL(...) LOGMASKED(LOG_DETAIL, __VA_ARGS__)
@@ -63,13 +61,6 @@
#define LOGSETTING(...) LOGMASKED(LOG_SETTING, __VA_ARGS__)
-enum
-{
- DECTIMER,
- RECVTIMER,
- SENDTIMER
-};
-
// Polling frequency. We use a much higher value to allow for line state changes
// happening between character transmissions (which happen in parallel in real
// communications but which must be serialized here)
@@ -254,39 +245,36 @@ void tms9902_device::rcv_break(bool value)
//------------------------------------------------
/*
- Timer callback
+ Timer callbacks
*/
-void tms9902_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+
+TIMER_CALLBACK_MEMBER(tms9902_device::decrementer_expired)
{
- switch (id)
- {
- // This call-back is called by the MESS timer system when the decrementer
- // reaches 0.
- case DECTIMER:
- m_TIMERR = m_TIMELP;
- m_TIMELP = true;
- field_interrupts();
- break;
+ // This call-back is called when the decrementer reaches 0.
+ m_TIMERR = m_TIMELP;
+ m_TIMELP = true;
+ field_interrupts();
+}
+TIMER_CALLBACK_MEMBER(tms9902_device::recv_tick)
+{
// Callback for the autonomous operations of the chip. This is normally
// controlled by an external clock of 3-4 MHz, internally divided by 3 or 4,
// depending on CLK4M. With this timer, reception of characters becomes
// possible.
- case RECVTIMER:
- m_rcv_cb(ASSERT_LINE);
- break;
+ m_rcv_cb(ASSERT_LINE);
+}
- case SENDTIMER:
- // Byte has been sent
- m_XSRE = true;
+TIMER_CALLBACK_MEMBER(tms9902_device::send_tick)
+{
+ // Byte has been sent
+ m_XSRE = true;
- // In the meantime, the CPU may have pushed a new byte into the XBR
- // so we loop until all data are transferred
- if (!m_XBRE && m_CTSin)
- {
- initiate_transmit();
- }
- break;
+ // In the meantime, the CPU may have pushed a new byte into the XBR
+ // so we loop until all data are transferred
+ if (!m_XBRE && m_CTSin)
+ {
+ initiate_transmit();
}
}
@@ -297,10 +285,8 @@ void tms9902_device::reload_interval_timer()
{
if (m_TMR)
{ /* reset clock interval */
- m_dectimer->adjust(
- attotime::from_double((double) m_TMR / (m_clock_rate / ((m_CLK4M) ? 4. : 3.) / 64.)),
- 0,
- attotime::from_double((double) m_TMR / (m_clock_rate / ((m_CLK4M) ? 4. : 3.) / 64.)));
+ attotime rate = attotime::from_double((double) m_TMR / (m_clock_rate / ((m_CLK4M) ? 4. : 3.) / 64.));
+ m_dectimer->adjust(rate, 0, rate);
}
else
{ /* clock interval == 0 -> no timer */
@@ -920,14 +906,9 @@ void tms9902_device::device_start()
{
m_clock_rate = clock();
- m_int_cb.resolve_safe();
- m_rcv_cb.resolve_safe();
- m_xmit_cb.resolve_safe();
- m_ctrl_cb.resolve_safe();
-
- m_dectimer = timer_alloc(DECTIMER);
- m_recvtimer = timer_alloc(RECVTIMER);
- m_sendtimer = timer_alloc(SENDTIMER);
+ m_dectimer = timer_alloc(FUNC(tms9902_device::decrementer_expired), this);
+ m_recvtimer = timer_alloc(FUNC(tms9902_device::recv_tick), this);
+ m_sendtimer = timer_alloc(FUNC(tms9902_device::send_tick), this);
save_item(NAME(m_LDCTRL));
save_item(NAME(m_LDIR));
diff --git a/src/devices/machine/tms9902.h b/src/devices/machine/tms9902.h
index 3d203c59709..c784687bbe8 100644
--- a/src/devices/machine/tms9902.h
+++ b/src/devices/machine/tms9902.h
@@ -73,11 +73,14 @@ public:
void cruwrite(offs_t offset, uint8_t data);
protected:
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_stop() override;
+ TIMER_CALLBACK_MEMBER(decrementer_expired);
+ TIMER_CALLBACK_MEMBER(recv_tick);
+ TIMER_CALLBACK_MEMBER(send_tick);
+
private:
void field_interrupts();
void reload_interval_timer();
@@ -172,7 +175,7 @@ private:
uint8_t m_TMR; /* interval timer */
/* clock registers */
- emu_timer *m_dectimer; /* MESS timer, used to emulate the decrementer register */
+ emu_timer *m_dectimer; /* MAME timer, used to emulate the decrementer register */
emu_timer *m_recvtimer;
emu_timer *m_sendtimer;
diff --git a/src/devices/machine/tms9914.cpp b/src/devices/machine/tms9914.cpp
index b8d7b05e4a4..ffab008c777 100644
--- a/src/devices/machine/tms9914.cpp
+++ b/src/devices/machine/tms9914.cpp
@@ -20,11 +20,13 @@
// Debugging
#define LOG_NOISY_MASK (LOG_GENERAL << 1)
-#define LOG_NOISY(...) LOGMASKED(LOG_NOISY_MASK, __VA_ARGS__)
#define LOG_REG_MASK (LOG_NOISY_MASK << 1)
-#define LOG_REG(...) LOGMASKED(LOG_REG_MASK, __VA_ARGS__)
#define LOG_INT_MASK (LOG_REG_MASK << 1)
+
+#define LOG_NOISY(...) LOGMASKED(LOG_NOISY_MASK, __VA_ARGS__)
+#define LOG_REG(...) LOGMASKED(LOG_REG_MASK, __VA_ARGS__)
#define LOG_INT(...) LOGMASKED(LOG_INT_MASK, __VA_ARGS__)
+
//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
@@ -172,64 +174,64 @@ constexpr uint8_t IFCMD_UNT = 0x5f; // Untalk
DEFINE_DEVICE_TYPE(TMS9914, tms9914_device, "tms9914", "TMS9914 GPIB Controller")
// Constructors
-tms9914_device::tms9914_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig , TMS9914 , tag , owner , clock),
- m_dio_read_func(*this),
- m_dio_write_func(*this),
- m_signal_wr_fns(*this),
- m_int_write_func(*this),
- m_accrq_write_func(*this),
- m_int_line{false},
- m_accrq_line{false},
- m_dio{0},
- m_signals{false},
- m_ext_signals{false},
- m_no_reflection{false},
- m_ext_state_change{false},
- m_reg_int0_status{0},
- m_reg_int0_mask{0},
- m_reg_int1_status{0},
- m_reg_int1_mask{0},
- m_reg_address{0},
- m_reg_serial_p{0},
- m_reg_2nd_serial_p{0},
- m_reg_parallel_p{0},
- m_reg_2nd_parallel_p{0},
- m_reg_di{0},
- m_reg_do{0},
- m_reg_ulpa{false},
- m_swrst{false},
- m_hdfa{false},
- m_hdfe{false},
- m_rtl{false},
- m_gts{false},
- m_rpp{false},
- m_sic{false},
- m_sre{false},
- m_dai{false},
- m_pts{false},
- m_stdl{false},
- m_shdw{false},
- m_vstdl{false},
- m_rsvd2{false},
- m_ah_state{FSM_AH_AIDS},
- m_ah_adhs{false},
- m_ah_anhs{false},
- m_ah_aehs{false},
- m_sh_state{FSM_SH_SIDS},
- m_sh_shfs{false},
- m_sh_vsts{false},
- m_t_state{FSM_T_TIDS},
- m_t_tpas{false},
- m_t_spms{false},
- m_t_eoi_state{FSM_T_ENIS},
- m_l_state{FSM_L_LIDS},
- m_l_lpas{false},
- m_sr_state{FSM_SR_NPRS},
- m_rl_state{FSM_RL_LOCS},
- m_pp_ppas{false},
- m_c_state{FSM_C_CIDS},
- m_next_eoi{false}
+tms9914_device::tms9914_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig , TMS9914 , tag , owner , clock),
+ m_dio_read_func(*this, 0xff),
+ m_dio_write_func(*this),
+ m_signal_wr_fns(*this),
+ m_int_write_func(*this),
+ m_accrq_write_func(*this),
+ m_int_line{false},
+ m_accrq_line{false},
+ m_dio{0},
+ m_signals{false},
+ m_ext_signals{false},
+ m_no_reflection{false},
+ m_ext_state_change{false},
+ m_reg_int0_status{0},
+ m_reg_int0_mask{0},
+ m_reg_int1_status{0},
+ m_reg_int1_mask{0},
+ m_reg_address{0},
+ m_reg_serial_p{0},
+ m_reg_2nd_serial_p{0},
+ m_reg_parallel_p{0},
+ m_reg_2nd_parallel_p{0},
+ m_reg_di{0},
+ m_reg_do{0},
+ m_reg_ulpa{false},
+ m_swrst{false},
+ m_hdfa{false},
+ m_hdfe{false},
+ m_rtl{false},
+ m_gts{false},
+ m_rpp{false},
+ m_sic{false},
+ m_sre{false},
+ m_dai{false},
+ m_pts{false},
+ m_stdl{false},
+ m_shdw{false},
+ m_vstdl{false},
+ m_rsvd2{false},
+ m_ah_state{FSM_AH_AIDS},
+ m_ah_adhs{false},
+ m_ah_anhs{false},
+ m_ah_aehs{false},
+ m_sh_state{FSM_SH_SIDS},
+ m_sh_shfs{false},
+ m_sh_vsts{false},
+ m_t_state{FSM_T_TIDS},
+ m_t_tpas{false},
+ m_t_spms{false},
+ m_t_eoi_state{FSM_T_ENIS},
+ m_l_state{FSM_L_LIDS},
+ m_l_lpas{false},
+ m_sr_state{FSM_SR_NPRS},
+ m_rl_state{FSM_RL_LOCS},
+ m_pp_ppas{false},
+ m_c_state{FSM_C_CIDS},
+ m_next_eoi{false}
{
// Silence compiler complaints about unused variables
(void)REG_INT1_IFC_BIT;
@@ -237,32 +239,32 @@ tms9914_device::tms9914_device(const machine_config &mconfig, const char *tag, d
}
// Signal inputs
-WRITE_LINE_MEMBER(tms9914_device::eoi_w)
+void tms9914_device::eoi_w(int state)
{
set_ext_signal(IEEE_488_EOI , state);
}
-WRITE_LINE_MEMBER(tms9914_device::dav_w)
+void tms9914_device::dav_w(int state)
{
set_ext_signal(IEEE_488_DAV , state);
}
-WRITE_LINE_MEMBER(tms9914_device::nrfd_w)
+void tms9914_device::nrfd_w(int state)
{
set_ext_signal(IEEE_488_NRFD , state);
}
-WRITE_LINE_MEMBER(tms9914_device::ndac_w)
+void tms9914_device::ndac_w(int state)
{
set_ext_signal(IEEE_488_NDAC , state);
}
-WRITE_LINE_MEMBER(tms9914_device::ifc_w)
+void tms9914_device::ifc_w(int state)
{
set_ext_signal(IEEE_488_IFC , state);
}
-WRITE_LINE_MEMBER(tms9914_device::srq_w)
+void tms9914_device::srq_w(int state)
{
bool prev_srq = get_signal(IEEE_488_SRQ);
set_ext_signal(IEEE_488_SRQ , state);
@@ -271,12 +273,12 @@ WRITE_LINE_MEMBER(tms9914_device::srq_w)
}
}
-WRITE_LINE_MEMBER(tms9914_device::atn_w)
+void tms9914_device::atn_w(int state)
{
set_ext_signal(IEEE_488_ATN , state);
}
-WRITE_LINE_MEMBER(tms9914_device::ren_w)
+void tms9914_device::ren_w(int state)
{
set_ext_signal(IEEE_488_REN , state);
}
@@ -465,7 +467,7 @@ uint8_t tms9914_device::read(offs_t offset)
return res;
}
-READ_LINE_MEMBER(tms9914_device::cont_r)
+int tms9914_device::cont_r()
{
return m_c_state != FSM_C_CIDS && m_c_state != FSM_C_CADS;
}
@@ -524,15 +526,9 @@ void tms9914_device::device_start()
save_item(NAME(m_c_state));
save_item(NAME(m_next_eoi));
- m_dio_read_func.resolve_safe(0xff);
- m_dio_write_func.resolve_safe();
- m_signal_wr_fns.resolve_all_safe();
- m_int_write_func.resolve_safe();
- m_accrq_write_func.resolve_safe();
-
- m_sh_dly_timer = timer_alloc(SH_DELAY_TMR_ID);
- m_ah_dly_timer = timer_alloc(AH_DELAY_TMR_ID);
- m_c_dly_timer = timer_alloc(C_DELAY_TMR_ID);
+ m_sh_dly_timer = timer_alloc(FUNC(tms9914_device::fsm_tick), this);
+ m_ah_dly_timer = timer_alloc(FUNC(tms9914_device::fsm_tick), this);
+ m_c_dly_timer = timer_alloc(FUNC(tms9914_device::fsm_tick), this);
}
void tms9914_device::device_reset()
@@ -593,9 +589,8 @@ void tms9914_device::device_reset()
update_ren();
}
-void tms9914_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(tms9914_device::fsm_tick)
{
- LOG_NOISY("tmr %d\n" , id);
update_fsm();
}
diff --git a/src/devices/machine/tms9914.h b/src/devices/machine/tms9914.h
index 2c766f0dfc3..e5d1cb7a5ba 100644
--- a/src/devices/machine/tms9914.h
+++ b/src/devices/machine/tms9914.h
@@ -74,27 +74,28 @@ public:
// Set write callback for ACCRQ signal
auto accrq_write_cb() { return m_accrq_write_func.bind(); }
- 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);
+ void eoi_w(int state);
+ void dav_w(int state);
+ void nrfd_w(int state);
+ void ndac_w(int state);
+ void ifc_w(int state);
+ void srq_w(int state);
+ void atn_w(int state);
+ void ren_w(int state);
// Register access
void write(offs_t offset, uint8_t data);
uint8_t read(offs_t offset);
// CONT output: true when 9914 is current controller-in-charge
- DECLARE_READ_LINE_MEMBER(cont_r);
+ int cont_r();
private:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(fsm_tick);
devcb_read8 m_dio_read_func;
devcb_write8 m_dio_write_func;
@@ -239,12 +240,6 @@ private:
int m_c_state;
// Timers
- enum {
- SH_DELAY_TMR_ID,
- AH_DELAY_TMR_ID,
- C_DELAY_TMR_ID
- };
-
emu_timer *m_sh_dly_timer;
emu_timer *m_ah_dly_timer;
emu_timer *m_c_dly_timer;
diff --git a/src/devices/machine/tsb12lv01a.cpp b/src/devices/machine/tsb12lv01a.cpp
index b893eafeefe..8c352e16032 100644
--- a/src/devices/machine/tsb12lv01a.cpp
+++ b/src/devices/machine/tsb12lv01a.cpp
@@ -12,10 +12,10 @@
#include "emu.h"
#include "tsb12lv01a.h"
-#define LOG_READS (1 << 1)
-#define LOG_WRITES (1 << 2)
-#define LOG_UNKNOWNS (1 << 3)
-#define LOG_IRQS (1 << 4)
+#define LOG_READS (1U << 1)
+#define LOG_WRITES (1U << 2)
+#define LOG_UNKNOWNS (1U << 3)
+#define LOG_IRQS (1U << 4)
#define LOG_ALL (LOG_READS | LOG_WRITES | LOG_UNKNOWNS | LOG_IRQS)
#define VERBOSE (LOG_ALL)
@@ -26,7 +26,7 @@ DEFINE_DEVICE_TYPE(TSB12LV01A, tsb12lv01a_device, "tsb12lv01a", "TSB12LV01A IEEE
tsb12lv01a_device::tsb12lv01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, TSB12LV01A, tag, owner, clock)
, m_int_cb(*this)
- , m_phy_read_cb(*this)
+ , m_phy_read_cb(*this, 0x00)
, m_phy_write_cb(*this)
{
}
@@ -46,10 +46,6 @@ void tsb12lv01a_device::device_start()
save_item(NAME(m_atf_status));
save_item(NAME(m_itf_status));
save_item(NAME(m_grf_status));
-
- m_int_cb.resolve_safe();
- m_phy_read_cb.resolve_safe(0x00);
- m_phy_write_cb.resolve_safe();
}
void tsb12lv01a_device::device_reset()
@@ -69,7 +65,7 @@ void tsb12lv01a_device::device_reset()
m_grf_status = 0x00000000;
}
-WRITE_LINE_MEMBER(tsb12lv01a_device::phy_reset_w)
+void tsb12lv01a_device::phy_reset_w(int state)
{
if (state)
{
diff --git a/src/devices/machine/tsb12lv01a.h b/src/devices/machine/tsb12lv01a.h
index 4f47fd31815..cec65a2c40c 100644
--- a/src/devices/machine/tsb12lv01a.h
+++ b/src/devices/machine/tsb12lv01a.h
@@ -26,7 +26,7 @@ public:
auto phy_read() { return m_phy_read_cb.bind(); }
auto phy_write() { return m_phy_write_cb.bind(); }
- DECLARE_WRITE_LINE_MEMBER(phy_reset_w);
+ void phy_reset_w(int state);
private:
// device-level overrides
diff --git a/src/devices/machine/tube.cpp b/src/devices/machine/tube.cpp
index de197a34c7d..74093398c33 100644
--- a/src/devices/machine/tube.cpp
+++ b/src/devices/machine/tube.cpp
@@ -13,7 +13,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/tube.h"
+#include "tube.h"
@@ -34,6 +34,7 @@ tube_device::tube_device(const machine_config &mconfig, const char *tag, device_
, m_hirq_handler(*this)
, m_pnmi_handler(*this)
, m_pirq_handler(*this)
+ , m_prst_handler(*this)
, m_drq_handler(*this)
{
}
@@ -45,12 +46,6 @@ tube_device::tube_device(const machine_config &mconfig, const char *tag, device_
void tube_device::device_start()
{
- // resolve callbacks
- m_hirq_handler.resolve_safe();
- m_pnmi_handler.resolve_safe();
- m_pirq_handler.resolve_safe();
- m_drq_handler.resolve_safe();
-
// register for state saving
save_item(NAME(m_ph1));
save_item(NAME(m_ph2));
@@ -75,9 +70,14 @@ void tube_device::device_start()
void tube_device::device_reset()
{
+ m_r1stat = 0;
+ soft_reset();
+}
+
+void tube_device::soft_reset()
+{
m_ph1pos = m_hp3pos = 0;
m_ph3pos = 1;
- m_r1stat = 0;
m_hstat[0] = m_hstat[1] = m_hstat[3] = 0x40;
m_hstat[2] = 0xc0;
m_pstat[0] = m_pstat[1] = m_pstat[2] = m_pstat[3] = 0x40;
@@ -167,11 +167,23 @@ void tube_device::host_w(offs_t offset, uint8_t data)
switch (offset & 0x07)
{
case 0: /* Status flags */
+ m_hstat[0] = (m_hstat[0] & 0xc0) | (data & 0x3f);
if (BIT(data, 7))
+ {
m_r1stat |= (data & 0x3f);
+ if (BIT(data, 6))
+ {
+ soft_reset();
+ }
+ }
else
+ {
m_r1stat &= ~(data & 0x3f);
- m_hstat[0] = (m_hstat[0] & 0xc0) | (data & 0x3f);
+ }
+ if (BIT(data, 5))
+ {
+ m_prst_handler(BIT(data, 7) ? ASSERT_LINE : CLEAR_LINE);
+ }
break;
case 1: /* Register 1 (1 byte write only) */
diff --git a/src/devices/machine/tube.h b/src/devices/machine/tube.h
index 384cf29b8d9..079c89cf86d 100644
--- a/src/devices/machine/tube.h
+++ b/src/devices/machine/tube.h
@@ -30,6 +30,7 @@ public:
auto hirq_handler() { return m_hirq_handler.bind(); }
auto pnmi_handler() { return m_pnmi_handler.bind(); }
auto pirq_handler() { return m_pirq_handler.bind(); }
+ auto prst_handler() { return m_prst_handler.bind(); }
auto drq_handler() { return m_drq_handler.bind(); }
uint8_t host_r(offs_t offset);
@@ -58,11 +59,13 @@ private:
int m_ph3pos;
int m_hp3pos;
+ void soft_reset();
void update_interrupts();
devcb_write_line m_hirq_handler;
devcb_write_line m_pnmi_handler;
devcb_write_line m_pirq_handler;
+ devcb_write_line m_prst_handler;
devcb_write_line m_drq_handler;
};
diff --git a/src/devices/machine/ucb1200.cpp b/src/devices/machine/ucb1200.cpp
new file mode 100644
index 00000000000..636e223ea1d
--- /dev/null
+++ b/src/devices/machine/ucb1200.cpp
@@ -0,0 +1,370 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Philips UCB1200 Advanced modem/audio analog front-end skeleton
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ucb1200.h"
+
+#define LOG_UNKNOWN (1U << 1)
+#define LOG_READS (1U << 2)
+#define LOG_WRITES (1U << 3)
+#define LOG_ALL (LOG_UNKNOWN | LOG_READS | LOG_WRITES)
+
+#define VERBOSE (LOG_ALL)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(UCB1200, ucb1200_device, "ucb1200", "Philips UCB1200 modem/audio codec")
+
+ucb1200_device::ucb1200_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, UCB1200, tag, owner, clock)
+ , m_gpio_out(*this)
+ , m_audio_out(*this)
+ , m_telecom_out(*this)
+ , m_irq_out(*this)
+ , m_adc_in(*this, 0xffff)
+{
+}
+
+void ucb1200_device::device_start()
+{
+ save_item(NAME(m_gpio_out_latch));
+ save_item(NAME(m_gpio_in_latch));
+ save_item(NAME(m_gpio_dir));
+ save_item(NAME(m_rising_int_en));
+ save_item(NAME(m_falling_int_en));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_telecom_ctrl_a));
+ save_item(NAME(m_telecom_ctrl_b));
+ save_item(NAME(m_audio_ctrl_a));
+ save_item(NAME(m_audio_ctrl_b));
+ save_item(NAME(m_touch_ctrl));
+ save_item(NAME(m_adc_ctrl));
+ save_item(NAME(m_adc_data));
+ save_item(NAME(m_id));
+ save_item(NAME(m_mode));
+}
+
+void ucb1200_device::device_reset()
+{
+ m_gpio_out_latch = 0;
+ m_gpio_in_latch = 0;
+ m_gpio_dir = 0;
+ m_rising_int_en = 0;
+ m_falling_int_en = 0;
+ m_int_status = 0;
+ m_telecom_ctrl_a = 0x10 << TEL_DIV_BIT;
+ m_telecom_ctrl_b = 0;
+ m_audio_ctrl_a = 0x06 << AUD_DIV_BIT;
+ m_audio_ctrl_b = 0;
+ m_touch_ctrl = 0;
+ m_adc_ctrl = 0;
+ m_adc_data = 0;
+ m_id = 0x1004;
+ m_mode = 0;
+}
+
+void ucb1200_device::gpio_in(const uint16_t line, const int state)
+{
+ const uint16_t mask = (1 << line);
+ const uint16_t old_latch = m_gpio_in_latch;
+ m_gpio_in_latch &= ~mask;
+ m_gpio_in_latch |= (state << line);
+
+ const bool old_irq = (m_int_status != 0);
+ if (old_latch != m_gpio_in_latch && !BIT(m_gpio_dir, line))
+ {
+ if (state && BIT(m_rising_int_en, line))
+ m_int_status |= mask;
+ else if (!state && BIT(m_falling_int_en, line))
+ m_int_status |= mask;
+ }
+
+ if (!old_irq && m_int_status != 0)
+ m_irq_out(1);
+}
+
+void ucb1200_device::update_gpio_direction(const uint16_t old_dir)
+{
+ const uint16_t new_outputs = ~old_dir & m_gpio_dir;
+ if (new_outputs)
+ {
+ for (uint32_t line = 0; line < 10; line++)
+ {
+ if (BIT(new_outputs, line))
+ {
+ m_gpio_out[line](BIT(m_gpio_out_latch, line));
+ }
+ }
+ }
+
+ // TODO: Do we need to check rising/falling edges based on the transition from output to input?
+}
+
+void ucb1200_device::update_gpio_outputs(const uint16_t old_latch, const uint16_t changed)
+{
+ uint16_t remaining_changed = changed;
+
+ for (uint32_t line = 0; line < 10 && remaining_changed != 0; line++)
+ {
+ if (BIT(remaining_changed, line))
+ {
+ m_gpio_out[line](BIT(m_gpio_out_latch, line));
+ remaining_changed &= ~(1 << line);
+ }
+ }
+}
+
+void ucb1200_device::audio_sample_in(const uint16_t sample)
+{
+ // TODO: Handle incoming audio samples
+}
+
+void ucb1200_device::telecom_sample_in(const uint16_t sample)
+{
+ // TODO: Handle incoming telecom samples
+}
+
+void ucb1200_device::adc_begin_conversion()
+{
+ const uint16_t adc_input = (m_adc_ctrl & ADC_INPUT_MASK) >> ADC_INPUT_BIT;
+ switch (adc_input)
+ {
+ case ADC_INPUT_TSPX:
+ case ADC_INPUT_TSMX:
+ case ADC_INPUT_TSPY:
+ case ADC_INPUT_TSMY:
+ default:
+ m_adc_data = 0;
+ break;
+ case ADC_INPUT_AD0:
+ case ADC_INPUT_AD1:
+ case ADC_INPUT_AD2:
+ case ADC_INPUT_AD3:
+ m_adc_data = m_adc_in[adc_input - ADC_INPUT_AD0]();
+ m_adc_data <<= ADC_DATA_BIT;
+ m_adc_data &= ADC_DATA_MASK;
+ break;
+ }
+
+ m_adc_data |= (1 << ADC_DAT_VAL_BIT);
+}
+
+uint16_t ucb1200_device::read(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0:
+ {
+ const uint16_t data = (m_gpio_out_latch & m_gpio_dir) | (m_gpio_in_latch & ~m_gpio_dir);
+ LOGMASKED(LOG_READS, "%s: read: GPIO Data Register: %04x\n", machine().describe_context(), data);
+ return data;
+ }
+ case 1:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Direction Register: %04x\n", machine().describe_context(), m_gpio_dir);
+ return m_gpio_dir;
+ case 2:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Rising-Edge Interrupt Enable Register: %04x\n", machine().describe_context(), m_rising_int_en);
+ return m_rising_int_en;
+ case 3:
+ LOGMASKED(LOG_READS, "%s: read: GPIO Falling-Edge Interrupt Enable Register: %04x\n", machine().describe_context(), m_falling_int_en);
+ return m_falling_int_en;
+ case 4:
+ LOGMASKED(LOG_READS, "%s: read: Interrupt Clear/Status Register: %04x\n", machine().describe_context(), m_int_status);
+ return m_int_status;
+ case 5:
+ LOGMASKED(LOG_READS, "%s: read: Telecom Control Register A: %04x\n", machine().describe_context(), m_telecom_ctrl_a);
+ return m_telecom_ctrl_a;
+ case 6:
+ LOGMASKED(LOG_READS, "%s: read: Telecom Control Register B: %04x\n", machine().describe_context(), m_telecom_ctrl_b);
+ return m_telecom_ctrl_b;
+ case 7:
+ LOGMASKED(LOG_READS, "%s: read: Audio Control Register A: %04x\n", machine().describe_context(), m_audio_ctrl_a);
+ return m_audio_ctrl_a;
+ case 8:
+ LOGMASKED(LOG_READS, "%s: read: Audio Control Register B: %04x\n", machine().describe_context(), m_audio_ctrl_b);
+ return m_audio_ctrl_b;
+ case 9:
+ LOGMASKED(LOG_READS, "%s: read: Touchscreen Control Register: %04x\n", machine().describe_context(), m_touch_ctrl);
+ return m_touch_ctrl;
+ case 10:
+ LOGMASKED(LOG_READS, "%s: read: ADC Control Register: %04x\n", machine().describe_context(), m_adc_ctrl);
+ return m_adc_ctrl;
+ case 11:
+ LOGMASKED(LOG_READS, "%s: read: ADC Data Register: %04x\n", machine().describe_context(), m_adc_data);
+ return m_adc_data;
+ case 12:
+ LOGMASKED(LOG_READS, "%s: read: ID Register: %04x\n", machine().describe_context(), m_id);
+ return m_id;
+ case 13:
+ LOGMASKED(LOG_READS, "%s: read: Mode Register: %04x\n", machine().describe_context(), m_mode);
+ return m_mode;
+ case 14:
+ LOGMASKED(LOG_READS, "%s: read: Reserved Register: %04x\n", machine().describe_context(), 0);
+ return 0;
+ case 15:
+ LOGMASKED(LOG_READS, "%s: read: NULL Register: %04x\n", machine().describe_context(), 0xffff);
+ return 0xffff;
+ default:
+ LOGMASKED(LOG_READS | LOG_UNKNOWN, "%s: read: Unknown Register: %d\n", machine().describe_context(), offset);
+ return 0;
+ }
+}
+
+void ucb1200_device::write(offs_t offset, uint16_t data)
+{
+ switch (offset)
+ {
+ case 0:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Data Register: %04x\n", machine().describe_context(), data);
+ const uint16_t old = m_gpio_out_latch;
+ m_gpio_out_latch = data;
+ const uint16_t changed = (old ^ m_gpio_out_latch) & m_gpio_dir;
+ if (changed)
+ update_gpio_outputs(old, changed);
+ break;
+ }
+ case 1:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Direction Register: %04x\n", machine().describe_context(), data);
+ const uint16_t old = m_gpio_dir;
+ m_gpio_dir = data;
+ if (old != m_gpio_dir)
+ update_gpio_direction(old);
+ break;
+ }
+ case 2:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Rising-Edge Interrupt Enable Register: %04x\n", machine().describe_context(), data);
+ m_rising_int_en = data;
+ break;
+ case 3:
+ LOGMASKED(LOG_WRITES, "%s: write: GPIO Falling-Edge Interrupt Enable Register: %04x\n", machine().describe_context(), data);
+ m_falling_int_en = data;
+ break;
+ case 4:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: Interrupt Clear/Status Register: %04x\n", machine().describe_context(), data);
+ const uint16_t old = m_int_status;
+ m_int_status &= ~data;
+ if (old != 0 && m_int_status == 0)
+ m_irq_out(0);
+ break;
+ }
+ case 5:
+ LOGMASKED(LOG_WRITES, "%s: write: Telecom Control Register A: %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_WRITES, "%s: Telecom Codec Sample Rate Divisor: %02x\n", machine().describe_context(), (data & TEL_DIV_MASK) >> TEL_DIV_BIT);
+ LOGMASKED(LOG_WRITES, "%s: Telecom Codec Loopback: %d\n", machine().describe_context(), BIT(data, TEL_LOOP_BIT));
+ m_telecom_ctrl_a = data;
+ break;
+ case 6:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: Telecom Control Register B: %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_WRITES, "%s: Telecom Voice Band Filter: %d\n", machine().describe_context(), BIT(data, TEL_VOICE_ENA_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Telecom Clip Detect Clear: %d\n", machine().describe_context(), BIT(data, TEL_CLIP_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Telecom Input Attenuation: %d\n", machine().describe_context(), BIT(data, TEL_ATT_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Telecom Sidetone Suppression: %d\n", machine().describe_context(), BIT(data, TEL_SIDE_ENA_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Telecom Output Mute: %d\n", machine().describe_context(), BIT(data, TEL_MUTE_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Telecom Input Enable: %d\n", machine().describe_context(), BIT(data, TEL_IN_ENA_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Telecom Output Enable: %d\n", machine().describe_context(), BIT(data, TEL_OUT_ENA_BIT));
+
+ const uint16_t old_clip = m_telecom_ctrl_b & (1 << TEL_CLIP_BIT);
+ const uint16_t new_clip = data & (1 << TEL_CLIP_BIT);
+
+ m_telecom_ctrl_b = data;
+
+ if (new_clip)
+ m_telecom_ctrl_b &= ~(1 << TEL_CLIP_BIT);
+ else if (old_clip)
+ m_telecom_ctrl_b |= (1 << TEL_CLIP_BIT);
+ break;
+ }
+ case 7:
+ LOGMASKED(LOG_WRITES, "%s: write: Audio Control Register A: %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_WRITES, "%s: Audio Codec Sample Rate Divisor: %02x\n", machine().describe_context(), (data & AUD_DIV_MASK) >> AUD_DIV_BIT);
+ LOGMASKED(LOG_WRITES, "%s: Audio Input Gain: %02x\n", machine().describe_context(), (data & AUD_GAIN_MASK) >> AUD_GAIN_BIT);
+ m_audio_ctrl_a = data;
+ break;
+ case 8:
+ {
+ LOGMASKED(LOG_WRITES, "%s: write: Audio Control Register B: %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_WRITES, "%s: Audio Output Attenuation: %02x\n", machine().describe_context(), (data & AUD_ATT_MASK) >> AUD_ATT_BIT);
+ LOGMASKED(LOG_WRITES, "%s: Audio Clip Detect Clear: %d\n", machine().describe_context(), BIT(data, AUD_CLIP_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Audio Codec Loopback: %d\n", machine().describe_context(), BIT(data, AUD_LOOP_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Audio Output Mute: %d\n", machine().describe_context(), BIT(data, AUD_MUTE_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Audio Input Enable: %d\n", machine().describe_context(), BIT(data, AUD_IN_ENA_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Audio Output Enable: %d\n", machine().describe_context(), BIT(data, AUD_OUT_ENA_BIT));
+
+ const uint16_t old_clip = m_audio_ctrl_b & (1 << AUD_CLIP_BIT);
+ const uint16_t new_clip = data & (1 << AUD_CLIP_BIT);
+
+ m_audio_ctrl_b = data;
+
+ if (new_clip)
+ m_audio_ctrl_b &= ~(1 << AUD_CLIP_BIT);
+ else if (old_clip)
+ m_audio_ctrl_b |= (1 << AUD_CLIP_BIT);
+ break;
+ }
+ case 9:
+ {
+ static const char *const s_tsc_modes[4] = { "Interrupt", "Pressure", "Position [2]", "Position [3]" };
+ LOGMASKED(LOG_WRITES, "%s: write: Touchscreen Control Register: %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_WRITES, "%s: TSMX Pin Powered: %d\n", machine().describe_context(), BIT(data, TSMX_POW_BIT));
+ LOGMASKED(LOG_WRITES, "%s: TSPX Pin Powered: %d\n", machine().describe_context(), BIT(data, TSPX_POW_BIT));
+ LOGMASKED(LOG_WRITES, "%s: TSMY Pin Powered: %d\n", machine().describe_context(), BIT(data, TSMY_POW_BIT));
+ LOGMASKED(LOG_WRITES, "%s: TSPY Pin Powered: %d\n", machine().describe_context(), BIT(data, TSPY_POW_BIT));
+ LOGMASKED(LOG_WRITES, "%s: TSMX Pin Grounded: %d\n", machine().describe_context(), BIT(data, TSMX_GND_BIT));
+ LOGMASKED(LOG_WRITES, "%s: TSPX Pin Grounded: %d\n", machine().describe_context(), BIT(data, TSPX_GND_BIT));
+ LOGMASKED(LOG_WRITES, "%s: TSMY Pin Grounded: %d\n", machine().describe_context(), BIT(data, TSMY_GND_BIT));
+ LOGMASKED(LOG_WRITES, "%s: TSPY Pin Grounded: %d\n", machine().describe_context(), BIT(data, TSPY_GND_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Touch Screen Mode: %s\n", machine().describe_context(), s_tsc_modes[(data & TSC_MODE_MASK) >> TSC_MODE_BIT]);
+ LOGMASKED(LOG_WRITES, "%s: Touch Screen Bias Circuit Active: %d\n", machine().describe_context(), BIT(data, TSC_BIAS_ENA_BIT));
+ m_touch_ctrl &= ~TOUCH_WRITE_MASK;
+ m_touch_ctrl |= data & TOUCH_WRITE_MASK;
+ break;
+ }
+ case 10:
+ {
+ static const char *const s_adc_inputs[8] = { "TSPX", "TSMX", "TSPY", "TSMY", "AD0", "AD1", "AD2", "AD3" };
+ LOGMASKED(LOG_WRITES, "%s: write: ADC Control Register: %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_WRITES, "%s: ADC Sync Mode: %d\n", machine().describe_context(), BIT(data, ADC_SYNC_ENA_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Connect Internal Vref to VREFBYP Pin: %d\n", machine().describe_context(), BIT(data, VREFBYP_CON_BIT));
+ LOGMASKED(LOG_WRITES, "%s: ADC Input Select: %s\n", machine().describe_context(), s_adc_inputs[(data & ADC_INPUT_MASK) >> ADC_INPUT_BIT]);
+ LOGMASKED(LOG_WRITES, "%s: Apply External Voltage to VREFBYP Pin: %d\n", machine().describe_context(), BIT(data, EXT_REF_ENA_BIT));
+ LOGMASKED(LOG_WRITES, "%s: ADC Conversion Start: %d\n", machine().describe_context(), BIT(data, ADC_START_BIT));
+ LOGMASKED(LOG_WRITES, "%s: ADC Enabled: %d\n", machine().describe_context(), BIT(data, ADC_ENA_BIT));
+ const uint16_t old = m_adc_ctrl;
+ m_adc_ctrl = data;
+ if (!BIT(old, ADC_START_BIT) && BIT(data, ADC_START_BIT) && BIT(data, ADC_ENA_BIT))
+ adc_begin_conversion();
+ break;
+ }
+ case 11:
+ LOGMASKED(LOG_WRITES, "%s: write: ADC Data Register (ignored): %04x\n", machine().describe_context(), data);
+ break;
+ case 12:
+ LOGMASKED(LOG_WRITES, "%s: write: ID Register (ignored): %04x\n", machine().describe_context(), data);
+ break;
+ case 13:
+ LOGMASKED(LOG_WRITES, "%s: write: Mode Register: %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_WRITES, "%s: Analog Audio Test Mode: %d\n", machine().describe_context(), BIT(data, AUD_TEST_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Analog Telecom Test Mode: %d\n", machine().describe_context(), BIT(data, TEL_TEST_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Production Test Mode: %02x\n", machine().describe_context(), (data & PROD_TEST_MODE_MASK) >> PROD_TEST_MODE_BIT);
+ LOGMASKED(LOG_WRITES, "%s: Dynamic Data Valid Flag Mode: %d\n", machine().describe_context(), BIT(data, DYN_VFLAG_ENA_BIT));
+ LOGMASKED(LOG_WRITES, "%s: Audio Offset-Cancelling: %d\n", machine().describe_context(), BIT(data, AUD_OFF_CAN_BIT));
+ break;
+ case 14:
+ LOGMASKED(LOG_WRITES, "%s: write: Reserved Register (ignored): %04x\n", machine().describe_context(), data);
+ break;
+ case 15:
+ LOGMASKED(LOG_WRITES, "%s: write: NULL Register (ignored): %04x\n", machine().describe_context(), data);
+ break;
+ default:
+ LOGMASKED(LOG_WRITES | LOG_UNKNOWN, "%s: write: Unknown Register: %d = %04x\n", machine().describe_context(), offset, data);
+ break;
+ }
+}
diff --git a/src/devices/machine/ucb1200.h b/src/devices/machine/ucb1200.h
new file mode 100644
index 00000000000..19cf474917b
--- /dev/null
+++ b/src/devices/machine/ucb1200.h
@@ -0,0 +1,147 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ Philips UCB1200 Advanced modem/audio analog front-end skeleton
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_UCB1200
+#define MAME_MACHINE_UCB1200
+
+#pragma once
+
+class ucb1200_device : public device_t
+{
+public:
+ ucb1200_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ template <unsigned Line> auto gpio_out() { return m_gpio_out[Line].bind(); }
+ template <unsigned Line> void gpio_in(int state) { gpio_in((uint16_t)Line, state); }
+ template <unsigned N> auto adc_in() { return m_adc_in[N].bind(); }
+ auto audio_sample_out() { return m_audio_out.bind(); }
+ auto telecom_sample_out() { return m_telecom_out.bind(); }
+ auto irq_out() { return m_irq_out.bind(); }
+
+ void audio_sample_in(const uint16_t sample);
+ void telecom_sample_in(const uint16_t sample);
+
+ uint16_t read(offs_t offset);
+ void write(offs_t offset, uint16_t data);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void gpio_in(const uint16_t line, const int state);
+ void update_gpio_direction(const uint16_t old_dir);
+ void update_gpio_outputs(const uint16_t old_latch, const uint16_t changed);
+
+ void adc_begin_conversion();
+
+ // register contents
+ enum : uint16_t
+ {
+ SIB_ZERO_BIT = 15,
+
+ IO_INT0_BIT = 0,
+ ADC_INT_BIT = 11,
+ TSPX_INT_BIT = 12,
+ TSMX_INT_BIT = 13,
+ TCLIP_INT_BIT = 14,
+ ACLIP_INT_BIT = 15,
+
+ TEL_DIV_BIT = 0,
+ TEL_DIV_MASK = 0x007f,
+ TEL_LOOP_BIT = 7,
+
+ TEL_VOICE_ENA_BIT = 3,
+ TEL_CLIP_BIT = 4,
+ TEL_ATT_BIT = 6,
+ TEL_SIDE_ENA_BIT = 11,
+ TEL_MUTE_BIT = 13,
+ TEL_IN_ENA_BIT = 14,
+ TEL_OUT_ENA_BIT = 15,
+
+ AUD_DIV_BIT = 0,
+ AUD_DIV_MASK = 0x007f,
+ AUD_GAIN_BIT = 7,
+ AUD_GAIN_MASK = 0x0f80,
+
+ AUD_ATT_BIT = 0,
+ AUD_ATT_MASK = 0x001f,
+ AUD_CLIP_BIT = 6,
+ AUD_LOOP_BIT = 8,
+ AUD_MUTE_BIT = 13,
+ AUD_IN_ENA_BIT = 14,
+ AUD_OUT_ENA_BIT = 15,
+
+ TSMX_POW_BIT = 0,
+ TSPX_POW_BIT = 1,
+ TSMY_POW_BIT = 2,
+ TSPY_POW_BIT = 3,
+ TSMX_GND_BIT = 4,
+ TSPX_GND_BIT = 5,
+ TSMY_GND_BIT = 6,
+ TSPY_GND_BIT = 7,
+ TSC_MODE_BIT = 8,
+ TSC_MODE_MASK = 0x0300,
+ TSC_BIAS_ENA_BIT = 11,
+ TSPX_LOW_BIT = 12,
+ TSMX_LOW_BIT = 13,
+ TOUCH_WRITE_MASK = 0x0fff,
+
+ ADC_SYNC_ENA_BIT = 0,
+ VREFBYP_CON_BIT = 1,
+ ADC_INPUT_BIT = 2,
+ ADC_INPUT_MASK = 0x001c,
+ ADC_INPUT_TSPX = 0,
+ ADC_INPUT_TSMX = 1,
+ ADC_INPUT_TSPY = 2,
+ ADC_INPUT_TSMY = 3,
+ ADC_INPUT_AD0 = 4,
+ ADC_INPUT_AD1 = 5,
+ ADC_INPUT_AD2 = 6,
+ ADC_INPUT_AD3 = 7,
+ EXT_REF_ENA_BIT = 5,
+ ADC_START_BIT = 7,
+ ADC_ENA_BIT = 15,
+
+ ADC_DATA_BIT = 5,
+ ADC_DATA_MASK = 0x7fe0,
+ ADC_DAT_VAL_BIT = 15,
+
+ AUD_TEST_BIT = 0,
+ TEL_TEST_BIT = 1,
+ PROD_TEST_MODE_BIT = 2,
+ PROD_TEST_MODE_MASK = 0x003c,
+ DYN_VFLAG_ENA_BIT = 12,
+ AUD_OFF_CAN_BIT = 13
+ };
+
+ uint16_t m_gpio_out_latch;
+ uint16_t m_gpio_in_latch;
+ uint16_t m_gpio_dir;
+ uint16_t m_rising_int_en;
+ uint16_t m_falling_int_en;
+ uint16_t m_int_status;
+ uint16_t m_telecom_ctrl_a;
+ uint16_t m_telecom_ctrl_b;
+ uint16_t m_audio_ctrl_a;
+ uint16_t m_audio_ctrl_b;
+ uint16_t m_touch_ctrl;
+ uint16_t m_adc_ctrl;
+ uint16_t m_adc_data;
+ uint16_t m_id;
+ uint16_t m_mode;
+
+ devcb_write_line::array<10> m_gpio_out;
+ devcb_write16 m_audio_out;
+ devcb_write16 m_telecom_out;
+ devcb_write_line m_irq_out;
+ devcb_read16::array<4> m_adc_in;
+};
+
+DECLARE_DEVICE_TYPE(UCB1200, ucb1200_device)
+
+#endif // MAME_MACHINE_UCB1200
diff --git a/src/devices/machine/upc82c710.cpp b/src/devices/machine/upc82c710.cpp
new file mode 100644
index 00000000000..9fb2ea89ac2
--- /dev/null
+++ b/src/devices/machine/upc82c710.cpp
@@ -0,0 +1,411 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ Universal Peripheral Controller 82C710 emulation
+
+**********************************************************************/
+
+#include "emu.h"
+#include "upc82c710.h"
+
+#define LOG_CFG (1U << 1)
+#define LOG_FDC (1U << 2)
+#define LOG_IDE (1U << 3)
+#define LOG_LPT (1U << 4)
+#define LOG_SER (1U << 5)
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(UPC82C710, upc82c710_device, "upc82c710", "Universal Peripheral Controller 82C710")
+
+
+upc82c710_device::upc82c710_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, UPC82C710, tag, owner, clock)
+ , m_ide(*this, "ide")
+ , m_fdc(*this, "fdc")
+ , m_lpt(*this, "parallel")
+ , m_serial(*this, "serial")
+ , m_fintr_callback(*this)
+ , m_fdrq_callback(*this)
+ , m_pintr_callback(*this)
+ , m_sintr_callback(*this)
+ , m_txd_callback(*this)
+ , m_dtr_callback(*this)
+ , m_rts_callback(*this)
+ , m_cfg_mode(0)
+{
+}
+
+
+void upc82c710_device::device_add_mconfig(machine_config &config)
+{
+ // ide interface
+ ATA_INTERFACE(config, m_ide);
+
+ // floppy disc controller
+ UPD765A(config, m_fdc, clock() / 3, false, false); // uPD72065B
+ m_fdc->intrq_wr_callback().set(FUNC(upc82c710_device::fdc_irq_w));
+ m_fdc->drq_wr_callback().set(FUNC(upc82c710_device::fdc_drq_w));
+
+ // parallel port
+ PC_LPT(config, m_lpt);
+ m_lpt->irq_handler().set([this](int state) { m_pintr_callback(state); });
+
+ // serial port
+ NS16450(config, m_serial, clock() / 13);
+ m_serial->out_int_callback().set([this](int state) { m_sintr_callback(state); });
+ m_serial->out_tx_callback().set([this](int state) { m_txd_callback(state); });
+ m_serial->out_dtr_callback().set([this](int state) { m_dtr_callback(state); });
+ m_serial->out_rts_callback().set([this](int state) { m_rts_callback(state); });
+}
+
+
+void upc82c710_device::device_start()
+{
+ for (int i=0; i<4; i++)
+ {
+ char name[2] = {static_cast<char>('0'+i), 0};
+ floppy_connector *conn = m_fdc->subdevice<floppy_connector>(name);
+ floppy[i] = conn ? conn->get_device() : nullptr;
+ }
+
+ irq = drq = false;
+ fdc_irq = fdc_drq = false;
+
+ // default addresses
+ device_address[DEVICE_CFG] = 0x390;
+ device_address[DEVICE_IDE] = 0x1f0;
+ device_address[DEVICE_FDC] = 0x3f0;
+ device_address[DEVICE_LPT] = 0x278;
+ device_address[DEVICE_SER] = 0x3f8;
+
+ const u8 cfg_regs_defaults[] = { 0x0e, 0x00, 0x08, 0x00, 0xfe, 0xbe, 0x9e, 0x00, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ // Set the value first and then use write_config because some flags
+ // rely on other flags being initialized properly first
+ std::copy(std::begin(cfg_regs_defaults), std::end(cfg_regs_defaults), std::begin(m_cfg_regs));
+ for (int i = 0; i < std::size(cfg_regs_defaults); i++)
+ {
+ write_cfg(i, cfg_regs_defaults[i]);
+ }
+
+ save_item(NAME(m_cfg_regs));
+ save_item(NAME(m_cfg_indx));
+ save_item(NAME(m_cfg_mode));
+}
+
+void upc82c710_device::device_reset()
+{
+ dor_w(0x00);
+}
+
+
+u16 upc82c710_device::io_r(offs_t offset, u16 mem_mask)
+{
+ u16 data = 0xffff;
+
+ // configuration
+ if (offset == 0x391 && m_cfg_mode == 5)
+ {
+ data = m_cfg_regs[m_cfg_indx];
+ LOGMASKED(LOG_CFG, "CFG read %04x -> %02x\n", offset, data);
+ }
+
+ // ide
+ if (device_enabled[DEVICE_IDE] && (offset & ~7) == 0x1f0)
+ {
+ data = m_ide->cs0_r(offset & 7);
+ LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data);
+ }
+ if (device_enabled[DEVICE_IDE] && offset == 0x3f6)
+ {
+ data = m_ide->cs1_r(offset & 7);
+ LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data);
+ }
+
+ // fdc
+ if (device_enabled[DEVICE_FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6)
+ {
+ switch (offset & 7)
+ {
+ case 3:
+ data = 0x20;
+ break;
+ case 4:
+ data = m_fdc->msr_r();
+ break;
+ case 5:
+ data = m_fdc->fifo_r();
+ break;
+ case 7:
+ data = m_fdc->dir_r() | (m_ide->cs1_r(7) & 0x7f);
+ break;
+ }
+ LOGMASKED(LOG_FDC, "FDC read %04x -> %02x\n", offset, data);
+ }
+
+ // parallel
+ if (device_enabled[DEVICE_LPT] && (offset & ~3) == device_address[DEVICE_LPT])
+ {
+ data = m_lpt->read(offset & 3);
+ LOGMASKED(LOG_LPT, "LPT read %04x -> %02x\n", offset, data);
+ }
+
+ // serial
+ if (device_enabled[DEVICE_SER] && (offset & ~7) == device_address[DEVICE_SER])
+ {
+ data = m_serial->ins8250_r(offset & 7);
+ LOGMASKED(LOG_SER, "SER read %04x -> %02x\n", offset, data);
+ }
+
+ return data;
+}
+
+void upc82c710_device::io_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ switch (m_cfg_mode)
+ {
+ case 0:
+ if (offset == 0x2fa && data == 0x55)
+ {
+ m_cfg_mode++;
+ LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data);
+ }
+ break;
+ case 1:
+ if (offset == 0x3fa && data == 0xaa)
+ {
+ m_cfg_mode++;
+ LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data);
+ }
+ break;
+ case 2:
+ if (offset == 0x3fa && data == 0x36)
+ {
+ m_cfg_mode++;
+ LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data);
+ }
+ break;
+ case 3:
+ if (offset == 0x3fa)
+ {
+ m_cfg_mode++;
+ LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data);
+ m_cfg_regs[0x0f] = data;
+ device_address[DEVICE_CFG] = data << 2;
+ LOGMASKED(LOG_CFG, "CFG address %04x\n", device_address[DEVICE_CFG]);
+ }
+ break;
+ case 4:
+ // enter configuration
+ if (offset == 0x2fa && data == (~m_cfg_regs[0x0f] & 0xff))
+ {
+ m_cfg_mode++;
+ LOGMASKED(LOG_CFG, "CFG step %d write %04x <- %02x\n", m_cfg_mode, offset, data);
+ LOGMASKED(LOG_CFG, "CFG -- mode on --\n");
+ }
+ break;
+ }
+
+ // configuration
+ if (offset == device_address[DEVICE_CFG])
+ {
+ LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data);
+ if (m_cfg_mode == 5)
+ {
+ m_cfg_indx = data & 0x0f;
+ }
+ else
+ {
+ m_cfg_mode = 0;
+ }
+ }
+ else if (offset == device_address[DEVICE_CFG] + 1)
+ {
+ LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data);
+ if (m_cfg_mode == 5)
+ {
+ write_cfg(m_cfg_indx, data);
+ }
+ else
+ {
+ m_cfg_mode = 0;
+ }
+ }
+
+ // ide
+ if (device_enabled[DEVICE_IDE] && (offset & ~7) == 0x1f0)
+ {
+ m_ide->cs0_w(offset & 7, data);
+ LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data);
+ }
+ if (device_enabled[DEVICE_IDE] && offset == 0x3f6)
+ {
+ m_ide->cs1_w(offset & 7, data);
+ LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data);
+ }
+
+ // fdc
+ if (device_enabled[DEVICE_FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6)
+ {
+ switch (offset & 7)
+ {
+ case 2:
+ dor_w(data);
+ break;
+ case 5:
+ m_fdc->fifo_w(data);
+ break;
+ case 7:
+ m_fdc->ccr_w(data);
+ break;
+ }
+ LOGMASKED(LOG_FDC, "FDC write %04x <- %02x\n", offset, data);
+ }
+
+ // parallel
+ if (device_enabled[DEVICE_LPT] && (offset & ~3) == device_address[DEVICE_LPT])
+ {
+ m_lpt->write(offset & 3, data);
+ LOGMASKED(LOG_LPT, "LPT write %04x <- %02x\n", offset, data);
+ }
+
+ // serial
+ if (device_enabled[DEVICE_SER] && (offset & ~7) == device_address[DEVICE_SER])
+ {
+ m_serial->ins8250_w(offset & 7, data);
+ LOGMASKED(LOG_SER, "SER write %04x <- %02x\n", offset, data);
+ }
+}
+
+
+u8 upc82c710_device::dack_r()
+{
+ return m_fdc->dma_r();
+}
+
+void upc82c710_device::dack_w(u8 data)
+{
+ m_fdc->dma_w(data);
+}
+
+void upc82c710_device::tc_w(bool state)
+{
+ m_fdc->tc_w(state);
+}
+
+
+void upc82c710_device::dor_w(uint8_t data)
+{
+ dor = data;
+
+ for (int i=0; i<4; i++)
+ if (floppy[i])
+ floppy[i]->mon_w(!(dor & (0x10 << i)));
+
+ int fid = dor & 3;
+ if (dor & (0x10 << fid))
+ m_fdc->set_floppy(floppy[fid]);
+ else
+ m_fdc->set_floppy(nullptr);
+
+ check_irq();
+ check_drq();
+ m_fdc->reset_w(!BIT(dor, 2));
+}
+
+void upc82c710_device::fdc_irq_w(int state)
+{
+ fdc_irq = state;
+ check_irq();
+}
+
+void upc82c710_device::fdc_drq_w(int state)
+{
+ fdc_drq = state;
+ check_drq();
+}
+
+void upc82c710_device::check_irq()
+{
+ bool pirq = irq;
+ irq = fdc_irq && (dor & 4) && (dor & 8);
+ if (irq != pirq)
+ m_fintr_callback(irq);
+}
+
+void upc82c710_device::check_drq()
+{
+ bool pdrq = drq;
+ drq = fdc_drq && (dor & 4) && (dor & 8);
+ if (drq != pdrq)
+ m_fdrq_callback(drq);
+}
+
+
+void upc82c710_device::write_cfg(int index, u8 data)
+{
+ m_cfg_regs[index] = data;
+ LOGMASKED(LOG_CFG, "CR[%02x] = %02x\n", index, data);
+
+ switch (index)
+ {
+ case 0x00: // Chip Selects and Enable
+ device_enabled[DEVICE_LPT]= BIT(m_cfg_regs[index], 3);
+ device_enabled[DEVICE_SER]= BIT(m_cfg_regs[index], 2);
+ LOGMASKED(LOG_CFG, "LPT %s\n", device_enabled[DEVICE_LPT] ? "enabled" : "disabled");
+ LOGMASKED(LOG_CFG, "SER %s\n", device_enabled[DEVICE_SER] ? "enabled" : "disabled");
+ break;
+
+ case 0x04: // Serial Port Address
+ device_address[DEVICE_SER] = (data & 0xfe) << 2;
+ LOGMASKED(LOG_CFG, "SER address %04x\n", device_address[DEVICE_SER]);
+ break;
+
+ case 0x06: // Parallel Port Address
+ device_address[DEVICE_LPT] = data << 2;
+ LOGMASKED(LOG_CFG, "LPT address %04x\n", device_address[DEVICE_LPT]);
+ break;
+
+ case 0x0c:
+ device_enabled[DEVICE_IDE] = BIT(m_cfg_regs[index], 7);
+ device_enabled[DEVICE_FDC] = BIT(m_cfg_regs[index], 5);
+ LOGMASKED(LOG_CFG, "IDE %s\n", device_enabled[DEVICE_IDE] ? "enabled" : "disabled");
+ LOGMASKED(LOG_CFG, "FDC %s\n", device_enabled[DEVICE_FDC] ? "enabled" : "disabled");
+ break;
+
+ case 0x0f:
+ m_cfg_mode = 0;
+ LOGMASKED(LOG_CFG, "CFG -- mode off --\n");
+ break;
+ }
+}
+
+
+void upc82c710_device::rxd_w(int state)
+{
+ m_serial->rx_w(state);
+}
+
+void upc82c710_device::dcd_w(int state)
+{
+ m_serial->dcd_w(state);
+}
+
+void upc82c710_device::dsr_w(int state)
+{
+ m_serial->dsr_w(state);
+}
+
+void upc82c710_device::ri_w(int state)
+{
+ m_serial->ri_w(state);
+}
+
+void upc82c710_device::cts_w(int state)
+{
+ m_serial->cts_w(state);
+}
diff --git a/src/devices/machine/upc82c710.h b/src/devices/machine/upc82c710.h
new file mode 100644
index 00000000000..1c609678dab
--- /dev/null
+++ b/src/devices/machine/upc82c710.h
@@ -0,0 +1,109 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ Universal Peripheral Controller 82C710 emulation
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_UPC82C710_H
+#define MAME_MACHINE_UPC82C710_H
+
+#pragma once
+
+#include "machine/ins8250.h"
+#include "machine/pc_lpt.h"
+#include "machine/upd765.h"
+#include "machine/idectrl.h"
+#include "imagedev/floppy.h"
+
+
+class upc82c710_device : public device_t
+{
+public:
+ // construction/destruction
+ upc82c710_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ u16 io_r(offs_t offset, u16 mem_mask = ~0);
+ void io_w(offs_t offset, u16 data, u16 mem_mask = ~0);
+ u8 dack_r();
+ void dack_w(u8 data);
+ void tc_w(bool state);
+
+ u8 dack_tc0_r() { tc_w(false); return dack_r(); }
+ void dack_tc0_w(u8 data) { tc_w(false); dack_w(data); }
+ u8 dack_tc1_r() { tc_w(true); return dack_r(); }
+ void dack_tc1_w(u8 data) { tc_w(true); dack_w(data); }
+
+ auto fintr() { return m_fintr_callback.bind(); }
+ auto fdrq() { return m_fdrq_callback.bind(); }
+ auto pintr() { return m_pintr_callback.bind(); }
+ auto sintr() { return m_sintr_callback.bind(); }
+ auto txd() { return m_txd_callback.bind(); }
+ auto dtr() { return m_dtr_callback.bind(); }
+ auto rts() { return m_rts_callback.bind(); }
+
+ // chip pins for uarts
+ void rxd_w(int state);
+ void dcd_w(int state);
+ void dsr_w(int state);
+ void ri_w(int state);
+ void cts_w(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ required_device<ata_interface_device> m_ide;
+ required_device<upd765_family_device> m_fdc;
+ required_device<pc_lpt_device> m_lpt;
+ required_device<ns16450_device> m_serial;
+
+ void dor_w(u8 data);
+ void fdc_irq_w(int state);
+ void fdc_drq_w(int state);
+
+ bool irq, drq, fdc_drq, fdc_irq;
+ u8 dor;
+
+ floppy_image_device *floppy[4];
+
+ void check_irq();
+ void check_drq();
+
+ devcb_write_line m_fintr_callback;
+ devcb_write_line m_fdrq_callback;
+ devcb_write_line m_pintr_callback;
+ devcb_write_line m_sintr_callback;
+
+ devcb_write_line m_txd_callback;
+ devcb_write_line m_dtr_callback;
+ devcb_write_line m_rts_callback;
+
+ void write_cfg(int index, u8 data);
+
+ enum
+ {
+ DEVICE_CFG = 0,
+ DEVICE_FDC,
+ DEVICE_IDE,
+ DEVICE_LPT,
+ DEVICE_SER,
+ DEVICE_TOTAL
+ };
+
+ bool device_enabled[DEVICE_TOTAL];
+ u16 device_address[DEVICE_TOTAL];
+
+ int m_cfg_mode;
+ u8 m_cfg_regs[16];
+ u8 m_cfg_indx;
+};
+
+
+DECLARE_DEVICE_TYPE(UPC82C710, upc82c710_device)
+
+#endif // MAME_MACHINE_UPC82C710_H
diff --git a/src/devices/machine/upc82c711.cpp b/src/devices/machine/upc82c711.cpp
new file mode 100644
index 00000000000..7e9e88d992b
--- /dev/null
+++ b/src/devices/machine/upc82c711.cpp
@@ -0,0 +1,466 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ Universal Peripheral Controller 82C711 emulation
+
+**********************************************************************/
+
+#include "emu.h"
+#include "upc82c711.h"
+
+#define LOG_CFG (1U << 1)
+#define LOG_FDC (1U << 2)
+#define LOG_IDE (1U << 3)
+#define LOG_LPT (1U << 4)
+#define LOG_SER (1U << 5)
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(UPC82C711, upc82c711_device, "upc82c711", "Universal Peripheral Controller 82C711")
+
+
+upc82c711_device::upc82c711_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, UPC82C711, tag, owner, clock)
+ , m_ide(*this, "ide")
+ , m_fdc(*this, "fdc")
+ , m_lpt(*this, "parallel")
+ , m_serial(*this, "serial%u", 1U)
+ , m_fintr_callback(*this)
+ , m_fdrq_callback(*this)
+ , m_pintr_callback(*this)
+ , m_irq3_callback(*this)
+ , m_irq4_callback(*this)
+ , m_txd1_callback(*this)
+ , m_dtr1_callback(*this)
+ , m_rts1_callback(*this)
+ , m_txd2_callback(*this)
+ , m_dtr2_callback(*this)
+ , m_rts2_callback(*this)
+ , m_cfg_mode(0)
+{
+}
+
+
+void upc82c711_device::device_add_mconfig(machine_config &config)
+{
+ // ide interface
+ ATA_INTERFACE(config, m_ide);
+
+ // floppy disc controller
+ UPD765A(config, m_fdc, clock() / 3, false, false); // uPD72065B
+ m_fdc->intrq_wr_callback().set(FUNC(upc82c711_device::fdc_irq_w));
+ m_fdc->drq_wr_callback().set(FUNC(upc82c711_device::fdc_drq_w));
+
+ // parallel port
+ PC_LPT(config, m_lpt);
+ m_lpt->irq_handler().set([this](int state) { m_pintr_callback(state); });
+
+ // serial ports
+ NS16450(config, m_serial[0], clock() / 13);
+ m_serial[0]->out_int_callback().set([this](int state) { m_irq4_callback(state); });
+ m_serial[0]->out_tx_callback().set([this](int state) { m_txd1_callback(state); });
+ m_serial[0]->out_dtr_callback().set([this](int state) { m_dtr1_callback(state); });
+ m_serial[0]->out_rts_callback().set([this](int state) { m_rts1_callback(state); });
+
+ NS16450(config, m_serial[1], clock() / 13);
+ m_serial[1]->out_int_callback().set([this](int state) { m_irq3_callback(state); });
+ m_serial[1]->out_tx_callback().set([this](int state) { m_txd2_callback(state); });
+ m_serial[1]->out_dtr_callback().set([this](int state) { m_dtr2_callback(state); });
+ m_serial[1]->out_rts_callback().set([this](int state) { m_rts2_callback(state); });
+}
+
+
+void upc82c711_device::device_start()
+{
+ for (int i=0; i<4; i++)
+ {
+ char name[2] = {static_cast<char>('0'+i), 0};
+ floppy_connector *conn = m_fdc->subdevice<floppy_connector>(name);
+ floppy[i] = conn ? conn->get_device() : nullptr;
+ }
+
+ irq = drq = false;
+ fdc_irq = fdc_drq = false;
+
+ // default addresses
+ com_address[0] = 0x3f8;
+ com_address[1] = 0x2f8;
+ com_address[2] = 0x338;
+ com_address[3] = 0x238;
+
+ device_address[DEVICE_IDE] = 0x1f0;
+ device_address[DEVICE_FDC] = 0x3f0;
+ device_address[DEVICE_LPT] = 0x278;
+ device_address[DEVICE_SER1] = com_address[0];
+ device_address[DEVICE_SER2] = com_address[1];
+
+ const u8 cfg_regs_defaults[] = { 0x3f, 0x9f, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ // Set the value first and then use write_config because some flags
+ // rely on other flags being initialized properly first
+ std::copy(std::begin(cfg_regs_defaults), std::end(cfg_regs_defaults), std::begin(m_cfg_regs));
+ for (int i = 0; i < std::size(cfg_regs_defaults); i++)
+ {
+ write_cfg(i, cfg_regs_defaults[i]);
+ }
+
+ save_item(NAME(m_cfg_regs));
+ save_item(NAME(m_cfg_indx));
+ save_item(NAME(m_cfg_mode));
+}
+
+void upc82c711_device::device_reset()
+{
+ dor_w(0x00);
+}
+
+
+u16 upc82c711_device::io_r(offs_t offset, u16 mem_mask)
+{
+ u16 data = 0xffff;
+
+ // configuration
+ if (offset == 0x3f1 && m_cfg_mode == 2)
+ {
+ data = m_cfg_regs[m_cfg_indx];
+ LOGMASKED(LOG_CFG, "CFG read %04x -> %02x\n", offset, data);
+ }
+
+ // ide
+ if (device_enabled[DEVICE_IDE] && (offset & ~7) == 0x1f0)
+ {
+ data = m_ide->cs0_r(offset & 7);
+ LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data);
+ }
+ if (device_enabled[DEVICE_IDE] && offset == 0x3f6)
+ {
+ data = m_ide->cs1_r(offset & 7);
+ LOGMASKED(LOG_IDE, "IDE read %04x -> %04x\n", offset, data);
+ }
+
+ // fdc
+ if (device_enabled[DEVICE_FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6)
+ {
+ switch (offset & 7)
+ {
+ case 3:
+ data = 0x20;
+ break;
+ case 4:
+ data = m_fdc->msr_r();
+ break;
+ case 5:
+ data = m_fdc->fifo_r();
+ break;
+ case 7:
+ data = m_fdc->dir_r() | (m_ide->cs1_r(7) & 0x7f);
+ break;
+ }
+ LOGMASKED(LOG_FDC, "FDC read %04x -> %02x\n", offset, data);
+ }
+
+ // parallel
+ if (device_enabled[DEVICE_LPT] && (offset & ~3) == device_address[DEVICE_LPT])
+ {
+ data = m_lpt->read(offset & 3);
+ LOGMASKED(LOG_LPT, "LPT read %04x -> %02x\n", offset, data);
+ }
+
+ // serial 1
+ if (device_enabled[DEVICE_SER1] && (offset & ~7) == device_address[DEVICE_SER1])
+ {
+ data = m_serial[0]->ins8250_r(offset & 7);
+ LOGMASKED(LOG_SER, "SER1 read %04x -> %02x\n", offset, data);
+ }
+
+ // serial 2
+ if (device_enabled[DEVICE_SER2] && (offset & ~7) == device_address[DEVICE_SER2])
+ {
+ data = m_serial[1]->ins8250_r(offset & 7);
+ LOGMASKED(LOG_SER, "SER2 read %04x -> %02x\n", offset, data);
+ }
+
+ return data;
+}
+
+void upc82c711_device::io_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ // configuration
+ if (offset == 0x3f0)
+ {
+ LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data);
+ if (m_cfg_mode == 2)
+ {
+ if (data == 0xaa) // escape configuration
+ {
+ m_cfg_mode = 0;
+ LOGMASKED(LOG_CFG, "CFG -- mode off --\n");
+ }
+ else
+ {
+ m_cfg_indx = data & 0x0f;
+ }
+ }
+ else
+ {
+ if (data == 0x55) // enter configuration
+ {
+ m_cfg_mode++;
+ if (m_cfg_mode == 2)
+ LOGMASKED(LOG_CFG, "CFG -- mode on --\n");
+ }
+ else
+ {
+ m_cfg_mode = 0;
+ }
+ }
+ }
+ else if (offset == 0x3f1)
+ {
+ LOGMASKED(LOG_CFG, "CFG write %04x <- %02x\n", offset, data);
+ if (m_cfg_mode == 2)
+ {
+ write_cfg(m_cfg_indx, data);
+ }
+ }
+
+ // ide
+ if (device_enabled[DEVICE_IDE] && (offset & ~7) == 0x1f0)
+ {
+ m_ide->cs0_w(offset & 7, data);
+ LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data);
+ }
+ if (device_enabled[DEVICE_IDE] && offset == 0x3f6)
+ {
+ m_ide->cs1_w(offset & 7, data);
+ LOGMASKED(LOG_IDE, "IDE write %04x <- %04x\n", offset, data);
+ }
+
+ // fdc
+ if (device_enabled[DEVICE_FDC] && (offset & ~7) == 0x3f0 && offset != 0x3f0 && offset != 0x3f1 && offset != 0x3f6)
+ {
+ switch (offset & 7)
+ {
+ case 2:
+ dor_w(data);
+ break;
+ case 5:
+ m_fdc->fifo_w(data);
+ break;
+ case 7:
+ m_fdc->ccr_w(data);
+ break;
+ }
+ LOGMASKED(LOG_FDC, "FDC write %04x <- %02x\n", offset, data);
+ }
+
+ // parallel
+ if (device_enabled[DEVICE_LPT] && (offset & ~3) == device_address[DEVICE_LPT])
+ {
+ m_lpt->write(offset & 3, data);
+ LOGMASKED(LOG_LPT, "LPT write %04x <- %02x\n", offset, data);
+ }
+
+ // serial 1
+ if (device_enabled[DEVICE_SER1] && (offset & ~7) == device_address[DEVICE_SER1])
+ {
+ m_serial[0]->ins8250_w(offset & 7, data);
+ LOGMASKED(LOG_SER, "SER1 write %04x <- %02x\n", offset, data);
+ }
+
+ // serial 2
+ if (device_enabled[DEVICE_SER2] && (offset & ~7) == device_address[DEVICE_SER2])
+ {
+ m_serial[1]->ins8250_w(offset & 7, data);
+ LOGMASKED(LOG_SER, "SER2 write %04x <- %02x\n", offset, data);
+ }
+}
+
+
+u8 upc82c711_device::dack_r()
+{
+ return m_fdc->dma_r();
+}
+
+void upc82c711_device::dack_w(u8 data)
+{
+ m_fdc->dma_w(data);
+}
+
+void upc82c711_device::tc_w(bool state)
+{
+ m_fdc->tc_w(state);
+}
+
+
+void upc82c711_device::dor_w(uint8_t data)
+{
+ dor = data;
+
+ for (int i=0; i<4; i++)
+ if (floppy[i])
+ floppy[i]->mon_w(!(dor & (0x10 << i)));
+
+ int fid = dor & 3;
+ if (dor & (0x10 << fid))
+ m_fdc->set_floppy(floppy[fid]);
+ else
+ m_fdc->set_floppy(nullptr);
+
+ check_irq();
+ check_drq();
+ m_fdc->reset_w(!BIT(dor, 2));
+}
+
+void upc82c711_device::fdc_irq_w(int state)
+{
+ fdc_irq = state;
+ check_irq();
+}
+
+void upc82c711_device::fdc_drq_w(int state)
+{
+ fdc_drq = state;
+ check_drq();
+}
+
+void upc82c711_device::check_irq()
+{
+ bool pirq = irq;
+ irq = fdc_irq && (dor & 4) && (dor & 8);
+ if (irq != pirq)
+ m_fintr_callback(irq);
+}
+
+void upc82c711_device::check_drq()
+{
+ bool pdrq = drq;
+ drq = fdc_drq && (dor & 4) && (dor & 8);
+ if (drq != pdrq)
+ m_fdrq_callback(drq);
+}
+
+
+void upc82c711_device::write_cfg(int index, u8 data)
+{
+ m_cfg_regs[index] = data;
+ LOGMASKED(LOG_CFG, "CR[%02x] = %02x\n", index, data);
+
+ switch (index)
+ {
+ case 0x00:
+ device_enabled[DEVICE_IDE] = BIT(m_cfg_regs[index], 0);
+ device_enabled[DEVICE_FDC] = BIT(m_cfg_regs[index], 3) && BIT(m_cfg_regs[index], 4);
+ LOGMASKED(LOG_CFG, "IDE %s\n", device_enabled[DEVICE_IDE] ? "enabled" : "disabled");
+ LOGMASKED(LOG_CFG, "FDC %s\n", device_enabled[DEVICE_FDC] ? "enabled" : "disabled");
+ break;
+
+ case 0x01:
+ {
+ device_enabled[DEVICE_LPT] = BIT(m_cfg_regs[index], 2);
+
+ auto lpt_port = BIT(m_cfg_regs[index], 0, 2);
+ switch (lpt_port)
+ {
+ case 0: // Disabled
+ device_enabled[DEVICE_LPT] = false;
+ break;
+ case 1:
+ device_address[DEVICE_LPT] = 0x3bc;
+ break;
+ case 2:
+ device_address[DEVICE_LPT] = 0x378;
+ break;
+ case 3: // Default
+ device_address[DEVICE_LPT] = 0x278;
+ break;
+ }
+ LOGMASKED(LOG_CFG, "LPT %04x %s\n", device_address[DEVICE_LPT], device_enabled[DEVICE_LPT] ? "enabled" : "disabled");
+ auto com34 = BIT(m_cfg_regs[index], 5, 2);
+ switch (com34)
+ {
+ case 0: // Default
+ com_address[2] = 0x338;
+ com_address[3] = 0x238;
+ break;
+ case 1:
+ com_address[2] = 0x3e8;
+ com_address[3] = 0x2e8;
+ break;
+ case 2:
+ com_address[2] = 0x2e8;
+ com_address[3] = 0x2e0;
+ break;
+ case 3:
+ com_address[2] = 0x220;
+ com_address[3] = 0x228;
+ break;
+ }
+ break;
+ }
+ case 0x02:
+ device_enabled[DEVICE_SER1] = BIT(m_cfg_regs[index], 2) && BIT(m_cfg_regs[index], 3);
+ device_address[DEVICE_SER1] = com_address[BIT(m_cfg_regs[index], 0, 2)];
+
+ device_enabled[DEVICE_SER2] = BIT(m_cfg_regs[index], 6) && BIT(m_cfg_regs[index], 7);
+ device_address[DEVICE_SER2] = com_address[BIT(m_cfg_regs[index], 4, 2)];
+
+ LOGMASKED(LOG_CFG, "SER1 %04x %s\n", device_address[DEVICE_SER1], device_enabled[DEVICE_SER1] ? "enabled" : "disabled");
+ LOGMASKED(LOG_CFG, "SER2 %04x %s\n", device_address[DEVICE_SER2], device_enabled[DEVICE_SER2] ? "enabled" : "disabled");
+ break;
+ }
+}
+
+
+void upc82c711_device::rxd1_w(int state)
+{
+ m_serial[0]->rx_w(state);
+}
+
+void upc82c711_device::dcd1_w(int state)
+{
+ m_serial[0]->dcd_w(state);
+}
+
+void upc82c711_device::dsr1_w(int state)
+{
+ m_serial[0]->dsr_w(state);
+}
+
+void upc82c711_device::ri1_w(int state)
+{
+ m_serial[0]->ri_w(state);
+}
+
+void upc82c711_device::cts1_w(int state)
+{
+ m_serial[0]->cts_w(state);
+}
+
+void upc82c711_device::rxd2_w(int state)
+{
+ m_serial[1]->rx_w(state);
+}
+
+void upc82c711_device::dcd2_w(int state)
+{
+ m_serial[1]->dcd_w(state);
+}
+
+void upc82c711_device::dsr2_w(int state)
+{
+ m_serial[1]->dsr_w(state);
+}
+
+void upc82c711_device::ri2_w(int state)
+{
+ m_serial[1]->ri_w(state);
+}
+
+void upc82c711_device::cts2_w(int state)
+{
+ m_serial[1]->cts_w(state);
+}
diff --git a/src/devices/machine/upc82c711.h b/src/devices/machine/upc82c711.h
new file mode 100644
index 00000000000..9138b3b7cc5
--- /dev/null
+++ b/src/devices/machine/upc82c711.h
@@ -0,0 +1,127 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ Universal Peripheral Controller 82C711 emulation
+
+**********************************************************************/
+
+#ifndef MAME_MACHINE_UPC82C711_H
+#define MAME_MACHINE_UPC82C711_H
+
+#pragma once
+
+#include "machine/ins8250.h"
+#include "machine/pc_lpt.h"
+#include "machine/upd765.h"
+#include "bus/ata/ataintf.h"
+#include "imagedev/floppy.h"
+
+
+// ======================> upc82c710_device
+
+class upc82c711_device : public device_t
+{
+public:
+ // construction/destruction
+ upc82c711_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ u16 io_r(offs_t offset, u16 mem_mask = ~0);
+ void io_w(offs_t offset, u16 data, u16 mem_mask = ~0);
+
+ u8 dack_r();
+ void dack_w(u8 data);
+ void tc_w(bool state);
+
+ u8 dack_tc0_r() { tc_w(false); return dack_r(); }
+ void dack_tc0_w(u8 data) { tc_w(false); dack_w(data); }
+ u8 dack_tc1_r() { tc_w(true); return dack_r(); }
+ void dack_tc1_w(u8 data) { tc_w(true); dack_w(data); }
+
+ auto fintr() { return m_fintr_callback.bind(); }
+ auto fdrq() { return m_fdrq_callback.bind(); }
+ auto pintr() { return m_pintr_callback.bind(); }
+ auto irq3() { return m_irq3_callback.bind(); }
+ auto irq4() { return m_irq4_callback.bind(); }
+ auto txd1() { return m_txd1_callback.bind(); }
+ auto dtr1() { return m_dtr1_callback.bind(); }
+ auto rts1() { return m_rts1_callback.bind(); }
+ auto txd2() { return m_txd2_callback.bind(); }
+ auto dtr2() { return m_dtr2_callback.bind(); }
+ auto rts2() { return m_rts2_callback.bind(); }
+
+ // chip pins for uarts
+ void rxd1_w(int state);
+ void dcd1_w(int state);
+ void dsr1_w(int state);
+ void ri1_w(int state);
+ void cts1_w(int state);
+ void rxd2_w(int state);
+ void dcd2_w(int state);
+ void dsr2_w(int state);
+ void ri2_w(int state);
+ void cts2_w(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ required_device<ata_interface_device> m_ide;
+ required_device<upd765_family_device> m_fdc;
+ required_device<pc_lpt_device> m_lpt;
+ required_device_array<ns16450_device, 2> m_serial;
+
+ void dor_w(u8 data);
+ void fdc_irq_w(int state);
+ void fdc_drq_w(int state);
+
+ bool irq, drq, fdc_drq, fdc_irq;
+ u8 dor;
+
+ floppy_image_device *floppy[4];
+
+ void check_irq();
+ void check_drq();
+
+ devcb_write_line m_fintr_callback;
+ devcb_write_line m_fdrq_callback;
+ devcb_write_line m_pintr_callback;
+ devcb_write_line m_irq3_callback; // Serial Port COM1/COM3
+ devcb_write_line m_irq4_callback; // Serial Port COM2/COM4
+
+ devcb_write_line m_txd1_callback;
+ devcb_write_line m_dtr1_callback;
+ devcb_write_line m_rts1_callback;
+ devcb_write_line m_txd2_callback;
+ devcb_write_line m_dtr2_callback;
+ devcb_write_line m_rts2_callback;
+
+ void write_cfg(int index, u8 data);
+
+ enum
+ {
+ DEVICE_FDC = 0,
+ DEVICE_IDE,
+ DEVICE_LPT,
+ DEVICE_SER1,
+ DEVICE_SER2,
+ DEVICE_TOTAL
+ };
+
+ bool device_enabled[DEVICE_TOTAL];
+ u16 device_address[DEVICE_TOTAL];
+
+ u16 com_address[4];
+
+ int m_cfg_mode;
+ u8 m_cfg_regs[16];
+ u8 m_cfg_indx;
+};
+
+
+DECLARE_DEVICE_TYPE(UPC82C711, upc82c711_device)
+
+#endif // MAME_MACHINE_UPC82C711_H
diff --git a/src/devices/machine/upd1990a.cpp b/src/devices/machine/upd1990a.cpp
index 6b14f95c123..3110da57013 100644
--- a/src/devices/machine/upd1990a.cpp
+++ b/src/devices/machine/upd1990a.cpp
@@ -73,9 +73,6 @@ bool upd1990a_device::is_serial_mode()
void upd1990a_device::device_start()
{
(void)m_variant;
- // resolve callbacks
- m_write_data.resolve_safe();
- m_write_tp.resolve_safe();
for (auto & elem : m_shift_reg)
elem = 0;
@@ -92,11 +89,11 @@ void upd1990a_device::device_start()
m_testmode = false;
// allocate timers
- m_timer_clock = timer_alloc(TIMER_CLOCK);
+ m_timer_clock = timer_alloc(FUNC(upd1990a_device::clock_tick), this);
m_timer_clock->adjust(attotime::from_hz(clock() / 32768.0), 0, attotime::from_hz(clock() / 32768.0)); // 1 second on XTAL(32'768)
- m_timer_tp = timer_alloc(TIMER_TP);
- m_timer_data_out = timer_alloc(TIMER_DATA_OUT);
- m_timer_test_mode = timer_alloc(TIMER_TEST_MODE);
+ m_timer_tp = timer_alloc(FUNC(upd1990a_device::tp_tick), this);
+ m_timer_data_out = timer_alloc(FUNC(upd1990a_device::data_out_tick), this);
+ m_timer_test_mode = timer_alloc(FUNC(upd1990a_device::test_tick), this);
// state saving
save_item(NAME(m_time_counter));
@@ -130,58 +127,55 @@ void upd1990a_device::rtc_clock_updated(int year, int month, int day, int day_of
//-------------------------------------------------
-// device_timer - handler timer events
+// timer handlers
//-------------------------------------------------
-void upd1990a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(upd1990a_device::clock_tick)
{
- switch (id)
- {
- case TIMER_CLOCK:
- advance_seconds();
- break;
+ advance_seconds();
+}
- case TIMER_TP:
- m_tp = !m_tp;
- m_write_tp(m_tp);
- break;
+TIMER_CALLBACK_MEMBER(upd1990a_device::tp_tick)
+{
+ m_tp = !m_tp;
+ m_write_tp(m_tp);
+}
+
+TIMER_CALLBACK_MEMBER(upd1990a_device::data_out_tick)
+{
+ m_data_out = !m_data_out;
+ m_write_data(get_data_out());
+}
- case TIMER_DATA_OUT:
- m_data_out = !m_data_out;
+TIMER_CALLBACK_MEMBER(upd1990a_device::test_tick)
+{
+ if (m_oe)
+ {
+ /* TODO: completely untested */
+ /* time counter is advanced from "Second" counter input */
+ int max_shift = is_serial_mode() ? 6 : 5;
+ m_data_out = (m_time_counter[max_shift - 1] == 0);
m_write_data(get_data_out());
- break;
- case TIMER_TEST_MODE:
- if (m_oe)
+ for (int i = 0; i < max_shift; i++)
{
- /* TODO: completely untested */
- /* time counter is advanced from "Second" counter input */
- int max_shift = is_serial_mode() ? 6 : 5;
- m_data_out = (m_time_counter[max_shift - 1] == 0);
- m_write_data(get_data_out());
-
- for (int i = 0; i < max_shift; i++)
- {
- m_time_counter[i]++;
- if (m_time_counter[i] != 0)
- return;
- }
+ m_time_counter[i]++;
+ if (m_time_counter[i] != 0)
+ return;
}
- else
- {
- /* each counter is advanced in parallel, overflow carry does not affect next counter */
- m_data_out = 0;
+ }
+ else
+ {
+ /* each counter is advanced in parallel, overflow carry does not affect next counter */
+ m_data_out = 0;
- int max_shift = is_serial_mode() ? 6 : 5;
- for (int i = 0; i < max_shift; i++)
- {
- m_time_counter[i]++;
- m_data_out |= (m_time_counter[i] == 0);
- }
- m_write_data(get_data_out());
+ int max_shift = is_serial_mode() ? 6 : 5;
+ for (int i = 0; i < max_shift; i++)
+ {
+ m_time_counter[i]++;
+ m_data_out |= (m_time_counter[i] == 0);
}
-
- break;
+ m_write_data(get_data_out());
}
}
@@ -190,7 +184,7 @@ void upd1990a_device::device_timer(emu_timer &timer, device_timer_id id, int par
// stb_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( upd1990a_device::stb_w )
+void upd1990a_device::stb_w(int state)
{
if (!m_cs)
return;
@@ -376,7 +370,7 @@ WRITE_LINE_MEMBER( upd1990a_device::stb_w )
// clk_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( upd1990a_device::clk_w )
+void upd1990a_device::clk_w(int state)
{
if (!m_cs)
return;
@@ -423,14 +417,14 @@ WRITE_LINE_MEMBER( upd1990a_device::clk_w )
// misc input pins
//-------------------------------------------------
-WRITE_LINE_MEMBER( upd1990a_device::cs_w )
+void upd1990a_device::cs_w(int state)
{
// chip select
LOG("uPD1990A CS %u\n", state);
m_cs = state;
}
-WRITE_LINE_MEMBER( upd1990a_device::oe_w )
+void upd1990a_device::oe_w(int state)
{
// output enable
LOG("uPD1990A OE %u\n", state);
@@ -442,25 +436,25 @@ WRITE_LINE_MEMBER( upd1990a_device::oe_w )
m_write_data(get_data_out());
}
-WRITE_LINE_MEMBER( upd1990a_device::c0_w )
+void upd1990a_device::c0_w(int state)
{
LOG("uPD1990A C0 %u\n", state);
m_c_unlatched = (m_c_unlatched & 0x06) | state;
}
-WRITE_LINE_MEMBER( upd1990a_device::c1_w )
+void upd1990a_device::c1_w(int state)
{
LOG("uPD1990A C1 %u\n", state);
m_c_unlatched = (m_c_unlatched & 0x05) | (state << 1);
}
-WRITE_LINE_MEMBER( upd1990a_device::c2_w )
+void upd1990a_device::c2_w(int state)
{
LOG("uPD1990A C2 %u\n", state);
m_c_unlatched = (m_c_unlatched & 0x03) | (state << 2);
}
-WRITE_LINE_MEMBER( upd1990a_device::data_in_w )
+void upd1990a_device::data_in_w(int state)
{
// data input
LOG("uPD1990A DATA IN %u\n", state);
@@ -479,12 +473,12 @@ int upd1990a_device::get_data_out()
}
-READ_LINE_MEMBER( upd1990a_device::data_out_r )
+int upd1990a_device::data_out_r()
{
return get_data_out();
}
-READ_LINE_MEMBER( upd1990a_device::tp_r )
+int upd1990a_device::tp_r()
{
return m_tp;
}
diff --git a/src/devices/machine/upd1990a.h b/src/devices/machine/upd1990a.h
index fbd26e6dfb4..ea12da708bb 100644
--- a/src/devices/machine/upd1990a.h
+++ b/src/devices/machine/upd1990a.h
@@ -39,27 +39,31 @@ public:
auto data_callback() { return m_write_data.bind(); }
auto tp_callback() { return m_write_tp.bind(); }
- DECLARE_WRITE_LINE_MEMBER( oe_w );
- DECLARE_WRITE_LINE_MEMBER( cs_w );
- DECLARE_WRITE_LINE_MEMBER( stb_w );
- DECLARE_WRITE_LINE_MEMBER( clk_w );
- DECLARE_WRITE_LINE_MEMBER( c0_w );
- DECLARE_WRITE_LINE_MEMBER( c1_w );
- DECLARE_WRITE_LINE_MEMBER( c2_w );
- DECLARE_WRITE_LINE_MEMBER( data_in_w );
- DECLARE_READ_LINE_MEMBER( data_out_r );
- DECLARE_READ_LINE_MEMBER( tp_r );
+ void oe_w(int state);
+ void cs_w(int state);
+ void stb_w(int state);
+ void clk_w(int state);
+ void c0_w(int state);
+ void c1_w(int state);
+ void c2_w(int state);
+ void data_in_w(int state);
+ int data_out_r();
+ int tp_r();
protected:
// device-level overrides
upd1990a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// 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) override;
+ TIMER_CALLBACK_MEMBER(clock_tick);
+ TIMER_CALLBACK_MEMBER(tp_tick);
+ TIMER_CALLBACK_MEMBER(data_out_tick);
+ TIMER_CALLBACK_MEMBER(test_tick);
+
enum
{
TYPE_1990A = 0,
@@ -69,14 +73,6 @@ protected:
private:
enum
{
- TIMER_CLOCK,
- TIMER_TP,
- TIMER_DATA_OUT,
- TIMER_TEST_MODE
- };
-
- enum
- {
MODE_REGISTER_HOLD = 0,
MODE_SHIFT,
MODE_TIME_SET,
diff --git a/src/devices/machine/upd4701.cpp b/src/devices/machine/upd4701.cpp
index 6a053a41063..728c7e5e2e8 100644
--- a/src/devices/machine/upd4701.cpp
+++ b/src/devices/machine/upd4701.cpp
@@ -28,12 +28,14 @@ upd4701_device::upd4701_device(const machine_config &mconfig, const char *tag, d
, m_starty(0)
, m_x(0)
, m_y(0)
+ , m_last_x_read(0)
+ , m_last_y_read(0)
, m_switches(0)
, m_latchswitches(0)
, m_cf(true)
, m_cf_cb(*this)
, m_sf_cb(*this)
- , m_open_bus_cb(*this)
+ , m_open_bus_cb(*this, 0)
{
}
@@ -43,11 +45,6 @@ upd4701_device::upd4701_device(const machine_config &mconfig, const char *tag, d
void upd4701_device::device_start()
{
- // resolve callbacks
- m_cf_cb.resolve_safe();
- m_sf_cb.resolve_safe();
- m_open_bus_cb.resolve_safe(0);
-
// register state for saving
save_item(NAME(m_cs));
save_item(NAME(m_xy));
@@ -60,20 +57,22 @@ void upd4701_device::device_start()
save_item(NAME(m_starty));
save_item(NAME(m_x));
save_item(NAME(m_y));
+ save_item(NAME(m_last_x_read));
+ save_item(NAME(m_last_y_read));
save_item(NAME(m_switches));
save_item(NAME(m_latchswitches));
save_item(NAME(m_cf));
- // register special callback for analog inputs
+ // register special callback for inputs
if (m_portx.found() || m_porty.found())
- machine().add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(&upd4701_device::analog_update, this));
+ machine().add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(&upd4701_device::update, this));
}
//-------------------------------------------------
// ul_w - write to counter select line
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::ul_w)
+void upd4701_device::ul_w(int state)
{
m_ul = state;
}
@@ -82,7 +81,7 @@ WRITE_LINE_MEMBER(upd4701_device::ul_w)
// xy_w - write to byte select line
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::xy_w)
+void upd4701_device::xy_w(int state)
{
m_xy = state;
}
@@ -91,7 +90,7 @@ WRITE_LINE_MEMBER(upd4701_device::xy_w)
// cs_w - write to chip select line
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::cs_w)
+void upd4701_device::cs_w(int state)
{
if (m_cs != state)
{
@@ -120,7 +119,7 @@ WRITE_LINE_MEMBER(upd4701_device::cs_w)
// resetx_w - write to X counter reset line
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::resetx_w)
+void upd4701_device::resetx_w(int state)
{
if (m_resetx != state)
{
@@ -135,7 +134,7 @@ WRITE_LINE_MEMBER(upd4701_device::resetx_w)
// resety_w - write to Y counter reset line
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::resety_w)
+void upd4701_device::resety_w(int state)
{
if (m_resety != state)
{
@@ -211,15 +210,36 @@ void upd4701_device::reset_xy_w(u8 data)
}
//-------------------------------------------------
-// analog_update - per-frame input update
+// update - per-frame input update
+//-------------------------------------------------
+
+void upd4701_device::update()
+{
+ if (m_portx.found())
+ {
+ u16 x = m_portx->read() & MASK_COUNTER;
+ x_add(x - m_last_x_read);
+ m_last_x_read = x;
+ }
+ if (m_porty.found())
+ {
+ u16 y = m_porty->read() & MASK_COUNTER;
+ y_add(y - m_last_y_read);
+ m_last_y_read = y;
+ }
+}
+
+//-------------------------------------------------
+// recalibrate - refresh saved X & Y inputs
+// (to be used if the input source changes)
//-------------------------------------------------
-void upd4701_device::analog_update()
+void upd4701_device::recalibrate()
{
if (m_portx.found())
- x_add(m_portx->read() & MASK_COUNTER);
+ m_last_x_read = m_portx->read() & MASK_COUNTER;
if (m_porty.found())
- y_add(m_porty->read() & MASK_COUNTER);
+ m_last_y_read = m_porty->read() & MASK_COUNTER;
}
//-------------------------------------------------
@@ -288,7 +308,7 @@ void upd4701_device::switch_update(u8 mask, bool state)
// left_w - update left switch state
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::left_w)
+void upd4701_device::left_w(int state)
{
switch_update(4, state);
}
@@ -297,7 +317,7 @@ WRITE_LINE_MEMBER(upd4701_device::left_w)
// right_w - update right switch state
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::right_w)
+void upd4701_device::right_w(int state)
{
switch_update(2, state);
}
@@ -306,7 +326,7 @@ WRITE_LINE_MEMBER(upd4701_device::right_w)
// middle_w - update middle switch state
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd4701_device::middle_w)
+void upd4701_device::middle_w(int state)
{
switch_update(1, state);
}
@@ -369,7 +389,7 @@ u8 upd4701_device::read_xy(offs_t offset)
// sf_r - read switch flag
//-------------------------------------------------
-READ_LINE_MEMBER(upd4701_device::sf_r)
+int upd4701_device::sf_r()
{
if (m_switches != 0)
return 0;
@@ -381,7 +401,7 @@ READ_LINE_MEMBER(upd4701_device::sf_r)
// cf_r - read counter flag
//-------------------------------------------------
-READ_LINE_MEMBER(upd4701_device::cf_r)
+int upd4701_device::cf_r()
{
return m_cf;
}
diff --git a/src/devices/machine/upd4701.h b/src/devices/machine/upd4701.h
index bfc77a00fc3..cecc34c3984 100644
--- a/src/devices/machine/upd4701.h
+++ b/src/devices/machine/upd4701.h
@@ -39,14 +39,14 @@ public:
auto sf_cb() { return m_sf_cb.bind(); }
auto open_bus_cb() { return m_open_bus_cb.bind(); }
- void x_add(s16 data);
- void y_add(s16 data);
-
- DECLARE_WRITE_LINE_MEMBER(cs_w);
- DECLARE_WRITE_LINE_MEMBER(xy_w);
- DECLARE_WRITE_LINE_MEMBER(ul_w);
- DECLARE_WRITE_LINE_MEMBER(resetx_w);
- DECLARE_WRITE_LINE_MEMBER(resety_w);
+ void update();
+ void recalibrate();
+
+ void cs_w(int state);
+ void xy_w(int state);
+ void ul_w(int state);
+ void resetx_w(int state);
+ void resety_w(int state);
u8 reset_x_r();
void reset_x_w(u8 data);
u8 reset_y_r();
@@ -59,12 +59,12 @@ public:
u8 read_y(offs_t offset);
u8 read_xy(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER(left_w);
- DECLARE_WRITE_LINE_MEMBER(right_w);
- DECLARE_WRITE_LINE_MEMBER(middle_w);
+ void left_w(int state);
+ void right_w(int state);
+ void middle_w(int state);
- DECLARE_READ_LINE_MEMBER(cf_r);
- DECLARE_READ_LINE_MEMBER(sf_r);
+ int cf_r();
+ int sf_r();
protected:
// device-level overrides
@@ -72,7 +72,8 @@ protected:
private:
// internal helpers
- void analog_update();
+ void x_add(s16 data);
+ void y_add(s16 data);
void switch_update(u8 mask, bool state);
// control lines
@@ -91,6 +92,8 @@ private:
s16 m_starty;
s16 m_x;
s16 m_y;
+ u16 m_last_x_read;
+ u16 m_last_y_read;
// switch state
u8 m_switches;
diff --git a/src/devices/machine/upd4991a.cpp b/src/devices/machine/upd4991a.cpp
new file mode 100644
index 00000000000..c58fcfef159
--- /dev/null
+++ b/src/devices/machine/upd4991a.cpp
@@ -0,0 +1,135 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ NEC uPD4991/uPD4991a parallel RTC
+
+ uPD4991 should be very similar but with "30% more power consumption" (cit.)
+
+ TODO:
+ - bare minimum to make PC98HA happy;
+ - set clock regs;
+ - alarm & timer pulse;
+ - AM/PM hour mode;
+ - leap year;
+ - busy flag;
+ - adjust/clock stop/clock wait mechanisms;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "upd4991a.h"
+
+
+//*************************************************************************************************
+// GLOBAL VARIABLES
+//*************************************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(UPD4991A, upd4991a_device, "upd4991a", "NEC uPD4991a parallel RTC")
+
+
+//*************************************************************************************************
+// LIVE DEVICE
+//*************************************************************************************************
+
+//-------------------------------------------------
+// upd4991a_device - constructor
+//-------------------------------------------------
+
+upd4991a_device::upd4991a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, UPD4991A, tag, owner, clock)
+ , device_rtc_interface(mconfig, *this)
+ , m_timer_clock(nullptr)
+{
+ std::fill(std::begin(m_rtc_regs), std::end(m_rtc_regs), 0);
+}
+
+
+//-------------------------------------------------
+// device_validity_check - perform validity checks
+// on this device
+//-------------------------------------------------
+
+void upd4991a_device::device_validity_check(validity_checker &valid) const
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void upd4991a_device::device_start()
+{
+ m_timer_clock = timer_alloc(FUNC(upd4991a_device::clock_tick), this);
+ m_timer_clock->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
+
+ save_item(NAME(m_address));
+}
+
+
+TIMER_CALLBACK_MEMBER(upd4991a_device::clock_tick)
+{
+ advance_seconds();
+}
+
+//-------------------------------------------------
+// rtc_clock_updated -
+//-------------------------------------------------
+
+void upd4991a_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+/*
+[0-1]
+xxxx xxxx seconds
+[2-3]
+xxxx xxxx minutes
+[4-5]
+xxxx xxxx hour
+[6-7]
+---- xxxx date digit (weekday?)
+xxxx ---- 1 day digit
+[8-9]
+---- xxxx 10 day digit
+xxxx ---- 1 month digit
+[a-b]
+---- xxxx 10 month digit
+xxxx ---- 1 year digit
+[c-d]
+---- xxxx 10 year digit
+xxxx ---- control register 1 (write only)
+[e-f]
+---- xxxx control register 2 (read/write)
+xxxx ---- mode register (write only)
+*/
+ m_rtc_regs[0] = convert_to_bcd(second);
+ m_rtc_regs[1] = convert_to_bcd(minute);
+ m_rtc_regs[2] = convert_to_bcd(hour);
+ const u8 bcd_day = convert_to_bcd(day);
+ const u8 bcd_month = convert_to_bcd(month);
+ const u8 bcd_year = convert_to_bcd(year);
+ m_rtc_regs[3] = (day_of_week-1) | ((bcd_day & 0x0f) << 4);
+ m_rtc_regs[4] = ((bcd_day & 0xf0) >> 4) | ((bcd_month & 0x0f) << 4);
+ m_rtc_regs[5] = ((bcd_month & 0xf0) >> 4) | ((bcd_year & 0x0f) << 4);
+ m_rtc_regs[6] = ((bcd_year & 0xf0) >> 4);
+}
+
+//*************************************************************************************************
+// READ/WRITE HANDLERS
+//*************************************************************************************************
+
+u8 upd4991a_device::data_r(offs_t offset)
+{
+ return m_rtc_regs[m_address >> 1] >> ((m_address & 1) ? 4 : 0);
+}
+
+void upd4991a_device::data_w(offs_t offset, u8 data)
+{
+ // ...
+}
+
+void upd4991a_device::address_w(offs_t offset, u8 data)
+{
+ m_address = data & 0xf;
+}
diff --git a/src/devices/machine/upd4991a.h b/src/devices/machine/upd4991a.h
new file mode 100644
index 00000000000..9a9da912279
--- /dev/null
+++ b/src/devices/machine/upd4991a.h
@@ -0,0 +1,52 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+/***************************************************************************
+
+ uPD4991a RTC
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_UPD4991A_H
+#define MAME_MACHINE_UPD4991A_H
+
+#pragma once
+
+#include "dirtc.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> upd4991a_device
+
+class upd4991a_device : public device_t, public device_rtc_interface
+{
+public:
+ // construction/destruction
+ upd4991a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ // I/O operations
+ void address_w(offs_t offset, u8 data);
+ u8 data_r(offs_t offset);
+ void data_w(offs_t offset, u8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_validity_check(validity_checker &valid) const override;
+ virtual void device_start() override;
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
+
+ TIMER_CALLBACK_MEMBER(clock_tick);
+
+private:
+ emu_timer *m_timer_clock;
+ u8 m_rtc_regs[8];
+ u8 m_address;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(UPD4991A, upd4991a_device)
+
+#endif // MAME_MACHINE_UPD4991A_H
diff --git a/src/devices/machine/upd4992.cpp b/src/devices/machine/upd4992.cpp
index 60a2eece92b..79f23784c82 100644
--- a/src/devices/machine/upd4992.cpp
+++ b/src/devices/machine/upd4992.cpp
@@ -13,8 +13,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/upd4992.h"
-
+#include "upd4992.h"
//**************************************************************************
@@ -58,19 +57,14 @@ void upd4992_device::device_validity_check(validity_checker &valid) const
void upd4992_device::device_start()
{
- m_timer_clock = timer_alloc(TIMER_CLOCK);
+ m_timer_clock = timer_alloc(FUNC(upd4992_device::clock_tick), this);
m_timer_clock->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
}
-void upd4992_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(upd4992_device::clock_tick)
{
- switch (id)
- {
- case TIMER_CLOCK:
- advance_seconds();
- break;
- }
+ advance_seconds();
}
//-------------------------------------------------
diff --git a/src/devices/machine/upd4992.h b/src/devices/machine/upd4992.h
index 7ceb831410b..3151aa12eaa 100644
--- a/src/devices/machine/upd4992.h
+++ b/src/devices/machine/upd4992.h
@@ -34,18 +34,11 @@ protected:
// device-level overrides
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
-private:
- enum
- {
- TIMER_CLOCK
- //TIMER_TP,
- //TIMER_DATA_OUT,
- //TIMER_TEST_MODE
- };
+ TIMER_CALLBACK_MEMBER(clock_tick);
+private:
emu_timer *m_timer_clock;
u8 m_rtc_regs[8];
};
diff --git a/src/devices/machine/upd7001.cpp b/src/devices/machine/upd7001.cpp
index d4607e7a479..9f0c63de2d4 100644
--- a/src/devices/machine/upd7001.cpp
+++ b/src/devices/machine/upd7001.cpp
@@ -40,7 +40,7 @@ DEFINE_DEVICE_TYPE(UPD7001, upd7001_device, "upd7001", "NEC uPD7001 A/D Converte
upd7001_device::upd7001_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, UPD7001, tag, owner, clock)
- , m_an_callback(*this)
+ , m_an_callback(*this, 0)
, m_eoc_callback(*this)
, m_res(0.0)
, m_cap(0.0)
@@ -61,18 +61,6 @@ upd7001_device::upd7001_device(const machine_config &mconfig, const char *tag, d
//-------------------------------------------------
-// device_resolve_objects -
-//-------------------------------------------------
-
-void upd7001_device::device_resolve_objects()
-{
- // resolve callbacks
- m_an_callback.resolve_all_safe(0);
- m_eoc_callback.resolve_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -85,8 +73,8 @@ void upd7001_device::device_start()
m_fck_rc = attotime::from_double(m_res * m_cap * 1.97);
// initialize timers
- m_conv_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(upd7001_device::conversion_done), this));
- m_scsk_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(upd7001_device::output_enabled), this));
+ m_conv_timer = timer_alloc(FUNC(upd7001_device::conversion_done), this);
+ m_scsk_timer = timer_alloc(FUNC(upd7001_device::output_enabled), this);
// save state
save_item(NAME(m_cs_active));
@@ -105,7 +93,7 @@ void upd7001_device::device_start()
// cs_w - active-low chip select
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd7001_device::cs_w)
+void upd7001_device::cs_w(int state)
{
if (!state && !m_cs_active)
{
@@ -166,7 +154,7 @@ TIMER_CALLBACK_MEMBER(upd7001_device::output_enabled)
// sck_w - shift data out of and into register
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd7001_device::sck_w)
+void upd7001_device::sck_w(int state)
{
if (m_cs_active)
{
@@ -196,7 +184,7 @@ WRITE_LINE_MEMBER(upd7001_device::sck_w)
// select input to convert
//-------------------------------------------------
-WRITE_LINE_MEMBER(upd7001_device::dl_w)
+void upd7001_device::dl_w(int state)
{
if (state && !m_dl && m_cs_active)
m_mpx = m_sr & 3;
diff --git a/src/devices/machine/upd7001.h b/src/devices/machine/upd7001.h
index afc4b632293..5494c3d8962 100644
--- a/src/devices/machine/upd7001.h
+++ b/src/devices/machine/upd7001.h
@@ -53,17 +53,16 @@ public:
void set_rc(double res, double cap) { assert(!configured()); m_res = res; m_cap = cap; }
// serial interface
- DECLARE_WRITE_LINE_MEMBER(cs_w);
- DECLARE_WRITE_LINE_MEMBER(sck_w);
- DECLARE_WRITE_LINE_MEMBER(si_w) { m_si = state; }
- DECLARE_WRITE_LINE_MEMBER(dl_w);
- DECLARE_READ_LINE_MEMBER(so_r) { return m_oe ? m_so : 1; }
- DECLARE_READ_LINE_MEMBER(eoc_r) { return m_eoc_active ? 0 : 1; }
- DECLARE_READ_LINE_MEMBER(eoc_so_r) { return eoc_r() && so_r(); }
+ void cs_w(int state);
+ void sck_w(int state);
+ void si_w(int state) { m_si = state; }
+ void dl_w(int state);
+ int so_r() { return m_oe ? m_so : 1; }
+ int eoc_r() { return m_eoc_active ? 0 : 1; }
+ int eoc_so_r() { return eoc_r() && so_r(); }
protected:
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
private:
diff --git a/src/devices/machine/upd7002.cpp b/src/devices/machine/upd7002.cpp
index 2d4d2ad4bc6..ab97f46b4b3 100644
--- a/src/devices/machine/upd7002.cpp
+++ b/src/devices/machine/upd7002.cpp
@@ -1,12 +1,8 @@
// license:BSD-3-Clause
// copyright-holders:Gordon Jefferyes
/******************************************************************************
- uPD7002 Analogue to Digital Converter
-
- MESS Driver By:
- Gordon Jefferyes
- mess_bbc@gjeffery.dircon.co.uk
+ uPD7002 Analogue to Digital Converter
******************************************************************************/
@@ -36,8 +32,9 @@ upd7002_device::upd7002_device(const machine_config &mconfig, const char *tag, d
void upd7002_device::device_start()
{
+ m_conversion_timer = timer_alloc(FUNC(upd7002_device::conversion_complete), this);
m_get_analogue_cb.resolve();
- m_eoc_cb.resolve();
+ m_eoc_cb.resolve_safe();
// register for state saving
save_item(NAME(m_status));
@@ -66,37 +63,27 @@ void upd7002_device::device_reset()
*****************************************************************************/
-READ_LINE_MEMBER( upd7002_device::eoc_r )
+int upd7002_device::eoc_r()
{
return BIT(m_status, 7);
}
-void upd7002_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(upd7002_device::conversion_complete)
{
- switch (id)
+ if (param == m_conversion_counter)
{
- case TIMER_CONVERSION_COMPLETE:
- {
- int counter_value = param;
- if (counter_value == m_conversion_counter)
- {
- // this really always does a 12 bit conversion
- m_data1 = m_digitalvalue >> 8;
- m_data0 = m_digitalvalue & 0xf0;
-
- // set the status register with top 2 MSB, not busy and conversion complete
- m_status = (m_status & 0x0f) | ((m_data1 & 0xc0) >> 2) | 0x40;
-
- // call the EOC function with EOC from status
- // eoc_r(0) this has just been set to 0
- if (!m_eoc_cb.isnull()) m_eoc_cb(0);
- m_conversion_counter=0;
- }
- }
- break;
- default:
- throw emu_fatalerror("Unknown id in upd7002_device::device_timer");
+ // this really always does a 12 bit conversion
+ m_data1 = m_digitalvalue >> 8;
+ m_data0 = m_digitalvalue & 0xf0;
+
+ // set the status register with top 2 MSB, not busy and conversion complete
+ m_status = (m_status & 0x0f) | ((m_data1 & 0xc0) >> 2) | 0x40;
+
+ // call the EOC function with EOC from status
+ // eoc_r(0) this has just been set to 0
+ m_eoc_cb(0);
+ m_conversion_counter = 0;
}
}
@@ -145,7 +132,7 @@ void upd7002_device::write(offs_t offset, uint8_t data)
// call the EOC function with EOC from status
// eoc_r(0) this has just been set to 1
- if (!m_eoc_cb.isnull()) m_eoc_cb(1);
+ m_eoc_cb(1);
/* the uPD7002 works by sampling the analogue value at the start of the conversion
so it is read hear and stored until the end of the A to D conversion */
@@ -159,12 +146,12 @@ void upd7002_device::write(offs_t offset, uint8_t data)
if (m_status & 0x08)
{
// 12 bit conversion takes 10ms
- timer_set(attotime::from_msec(10), TIMER_CONVERSION_COMPLETE, m_conversion_counter);
+ m_conversion_timer->adjust(attotime::from_msec(10), m_conversion_counter);
}
else
{
// 8 bit conversion takes 4ms
- timer_set(attotime::from_msec(4), TIMER_CONVERSION_COMPLETE, m_conversion_counter);
+ m_conversion_timer->adjust(attotime::from_msec(4), m_conversion_counter);
}
break;
diff --git a/src/devices/machine/upd7002.h b/src/devices/machine/upd7002.h
index 5f9e88928c7..aed7e0bd3f2 100644
--- a/src/devices/machine/upd7002.h
+++ b/src/devices/machine/upd7002.h
@@ -30,7 +30,7 @@ public:
template <typename... T> void set_get_analogue_callback(T &&... args) { m_get_analogue_cb.set(std::forward<T>(args)...); }
template <typename... T> void set_eoc_callback(T &&... args) { m_eoc_cb.set(std::forward<T>(args)...); }
- DECLARE_READ_LINE_MEMBER(eoc_r);
+ int eoc_r();
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
@@ -38,7 +38,8 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(conversion_complete);
private:
// internal state
@@ -77,10 +78,7 @@ private:
get_analogue_delegate m_get_analogue_cb;
eoc_delegate m_eoc_cb;
- enum
- {
- TIMER_CONVERSION_COMPLETE
- };
+ emu_timer *m_conversion_timer;
};
DECLARE_DEVICE_TYPE(UPD7002, upd7002_device)
diff --git a/src/devices/machine/upd7004.cpp b/src/devices/machine/upd7004.cpp
index e3cfb911864..8fcb49e9c62 100644
--- a/src/devices/machine/upd7004.cpp
+++ b/src/devices/machine/upd7004.cpp
@@ -40,7 +40,7 @@ ALLOW_SAVE_TYPE(upd7004_device::state);
upd7004_device::upd7004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, UPD7004, tag, owner, clock),
m_eoc_cb(*this), m_eoc_ff_cb(*this),
- m_in_cb(*this),
+ m_in_cb(*this, 0x3ff),
m_state(STATE_IDLE),
m_cycle_timer(nullptr),
m_div(1), m_code(false), m_address(0), m_sar(0x3ff)
@@ -53,13 +53,8 @@ upd7004_device::upd7004_device(const machine_config &mconfig, const char *tag, d
void upd7004_device::device_start()
{
- // resolve callbacks
- m_eoc_cb.resolve_safe();
- m_eoc_ff_cb.resolve_safe();
- m_in_cb.resolve_all_safe(0x3ff);
-
// allocate timers
- m_cycle_timer = timer_alloc();
+ m_cycle_timer = timer_alloc(FUNC(upd7004_device::update_state), this);
m_cycle_timer->adjust(attotime::never);
// register for save states
@@ -71,10 +66,10 @@ void upd7004_device::device_start()
}
//-------------------------------------------------
-// device_timer - handler timer events
+// update_state -
//-------------------------------------------------
-void upd7004_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(upd7004_device::update_state)
{
switch (m_state)
{
diff --git a/src/devices/machine/upd7004.h b/src/devices/machine/upd7004.h
index 11b311b60f2..78d7eae559c 100644
--- a/src/devices/machine/upd7004.h
+++ b/src/devices/machine/upd7004.h
@@ -49,7 +49,8 @@ public:
// device-level overrides
virtual void device_start() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_state);
private:
// callbacks
diff --git a/src/devices/machine/upd71071.cpp b/src/devices/machine/upd71071.cpp
index de46ffe53c5..a23b859e3c7 100644
--- a/src/devices/machine/upd71071.cpp
+++ b/src/devices/machine/upd71071.cpp
@@ -88,7 +88,7 @@
*/
#include "emu.h"
-#include "machine/upd71071.h"
+#include "upd71071.h"
DEFINE_DEVICE_TYPE(UPD71071, upd71071_device, "upd71071", "NEC uPD71071 DMA Controller")
@@ -98,7 +98,7 @@ upd71071_device::upd71071_device(const machine_config &mconfig, const char *tag,
, m_upd_clock(0)
, m_out_hreq_cb(*this)
, m_out_eop_cb(*this)
- , m_dma_read_cb(*this)
+ , m_dma_read_cb(*this, 0)
, m_dma_write_cb(*this)
, m_out_dack_cb(*this)
, m_cpu(*this, finder_base::DUMMY_TAG)
@@ -111,19 +111,16 @@ upd71071_device::upd71071_device(const machine_config &mconfig, const char *tag,
void upd71071_device::device_start()
{
- m_out_hreq_cb.resolve_safe();
- m_out_eop_cb.resolve_safe();
- m_dma_read_cb.resolve_all_safe(0);
- m_dma_write_cb.resolve_all_safe();
- m_out_dack_cb.resolve_all_safe();
for (auto &elem : m_timer)
- elem = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(upd71071_device::dma_transfer_timer), this));
+ elem = timer_alloc(FUNC(upd71071_device::dma_transfer_timer), this);
m_selected_channel = 0;
m_reg.device_control = 0;
m_reg.mask = 0x0f; // mask all channels
- for (int x = 0; x < 4; x++)
- m_reg.mode_control[x] = 0;
+
+ std::fill(std::begin(m_reg.address_current), std::end(m_reg.address_current), 0);
+ std::fill(std::begin(m_reg.count_current), std::end(m_reg.count_current), 0);
+ std::fill(std::begin(m_reg.mode_control), std::end(m_reg.mode_control), 0);
save_item(NAME(m_reg.initialise));
save_item(NAME(m_reg.channel));
@@ -166,7 +163,7 @@ TIMER_CALLBACK_MEMBER(upd71071_device::dma_transfer_timer)
case 1:
case 2:
case 3:
- if (!m_dma_read_cb[channel].isnull())
+ if (!m_dma_read_cb[channel].isunset())
data = m_dma_read_cb[channel](0);
break;
}
@@ -221,8 +218,7 @@ TIMER_CALLBACK_MEMBER(upd71071_device::dma_transfer_timer)
case 1:
case 2:
case 3:
- if (!m_dma_write_cb[channel].isnull())
- m_dma_write_cb[channel](offs_t(0), data);
+ m_dma_write_cb[channel](offs_t(0), data);
break;
}
if (m_reg.mode_control[channel] & 0x20) // Address direction
@@ -472,7 +468,7 @@ void upd71071_device::write(offs_t offset, uint8_t data)
}
}
-WRITE_LINE_MEMBER(upd71071_device::set_hreq)
+void upd71071_device::set_hreq(int state)
{
if (m_hreq != state)
{
@@ -481,7 +477,7 @@ WRITE_LINE_MEMBER(upd71071_device::set_hreq)
}
}
-WRITE_LINE_MEMBER(upd71071_device::set_eop)
+void upd71071_device::set_eop(int state)
{
if (m_eop != state)
{
diff --git a/src/devices/machine/upd7261.cpp b/src/devices/machine/upd7261.cpp
new file mode 100644
index 00000000000..02f45c96065
--- /dev/null
+++ b/src/devices/machine/upd7261.cpp
@@ -0,0 +1,733 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * NEC μPD7261A/μPD7261B Hard-Disk Controller
+ *
+ * Sources:
+ * - μPD7261A/μPD7261B Hard-Disk Controllers, © NEC Electronics Inc.
+ *
+ * TODO:
+ * - unemulated commands
+ * - hard sectored drives
+ * - concurrent recalibrate/seek commands
+ * - terminal count
+ * - drive/head mapping for 3b2
+ */
+
+#include "emu.h"
+#include "upd7261.h"
+
+#define LOG_GENERAL (1U << 0)
+#define LOG_REGR (1U << 1)
+#define LOG_REGW (1U << 2)
+#define LOG_COMMAND (1U << 3)
+#define LOG_STATE (1U << 4)
+#define LOG_DMA (1U << 5)
+
+//#define VERBOSE (LOG_GENERAL|LOG_COMMAND)
+#include "logmacro.h"
+
+unsigned constexpr BUF_SIZE = 4096;
+
+enum state : u32
+{
+ IDLE = 0,
+
+ EXECUTE_READ,
+ EXECUTE_WRITE,
+
+ SEEK_POLLED0, // recalibrate/seek with polling
+ SEEK_POLLED1, // recalibrate/seek with polling
+
+ RESULTS_4, // detect error
+ RESULTS_56, // results: recalibrate, seek
+ RESULTS_bcdef, // results: read data, check, scan, verify data, write data
+ RESULTS_789, // results: format, verify id, read id
+
+ COMPLETE,
+ ERROR,
+};
+
+enum status_mask : u8
+{
+ S_DRQ = 0x01, // data request
+ S_NCI = 0x02, // not coincident
+ S_IER = 0x04, // ID error
+ S_RRQ = 0x08, // reset request
+ S_SRQ = 0x10, // sense interrupt status request
+ S_CEL = 0x20, // command end lo
+ S_CEH = 0x40, // command end hi
+ S_CB = 0x80, // controller busy
+};
+
+enum ist_mask : u8
+{
+ IST_UA = 0x07, // unit address
+ IST_NR = 0x08, // not ready
+ IST_EQC = 0x10, // equipment check
+ IST_SER = 0x20, // seek error
+ IST_RC = 0x40, // ready change
+ IST_SEN = 0x80, // seek end
+};
+
+enum ust_mask : u8
+{
+ UST_D0 = 0x01, // fault/write fault
+ UST_D1 = 0x02, // seek error/ready
+ UST_D2 = 0x04, // on cylinder/track 000
+ UST_D3 = 0x08, // unit ready/seek complete
+ UST_D4 = 0x10, // -/drive selected
+ UST_D5 = 0x20, // write protected/-
+ UST_D6 = 0x40, // seek end/-
+ UST_D7 = 0x80, // unit selected/-
+};
+
+enum est_mask : u8
+{
+ EST_MAM = 0x01, // missing address mark
+ EST_NWR = 0x02, // not writable
+ EST_ND = 0x04, // no data
+ EST_NR = 0x08, // not ready
+ EST_EQC = 0x10, // equipment check
+ EST_DER = 0x20, // data error
+ EST_OVR = 0x40, // overrun
+ EST_ENC = 0x80, // end of cylinder
+};
+
+enum specify_mode_mask : u8
+{
+ SM_STP = 0x0f, // stepping rate
+ SM_SSEC = 0x10, // soft-sector disk
+ SM_CRCS = 0x20, // generator polynomial
+ SM_ECC = 0x40, // ecc is appended in data field
+};
+
+enum specify_dtlh_mask : u8
+{
+ DTLH_DTLH = 0x0f, // data length high bits
+ DTLH_NPOL = 0x10, // non-polling mode
+ DTLH_PAD = 0x20, // ID/data pad (0=0x00, 1=0x4e)
+ DTLH_CRC = 0x40, // initial polynomial counter
+};
+
+DEFINE_DEVICE_TYPE(UPD7261, upd7261_device, "upd7261", "NEC uPD7261 Hard-Disk Controller")
+
+upd7261_device::upd7261_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, UPD7261, tag, owner, clock)
+ , m_drive(*this, "%u", 0)
+ , m_dreq(*this)
+ , m_int(*this)
+ , m_head(0)
+ , m_specify{}
+ , m_transfer{}
+ , m_dreq_state(false)
+ , m_int_state(false)
+ , m_tc_state(false)
+{
+}
+
+void upd7261_device::device_start()
+{
+ save_item(NAME(m_state));
+ save_item(NAME(m_head));
+
+ save_item(NAME(m_status));
+ save_item(NAME(m_est));
+ save_item(NAME(m_ist));
+ save_item(NAME(m_ua));
+ save_item(NAME(m_pcn));
+
+ save_item(STRUCT_MEMBER(m_specify, mode));
+ save_item(STRUCT_MEMBER(m_specify, dtlh));
+ save_item(STRUCT_MEMBER(m_specify, dtll));
+ save_item(STRUCT_MEMBER(m_specify, etn));
+ save_item(STRUCT_MEMBER(m_specify, esn));
+ save_item(STRUCT_MEMBER(m_specify, gpl2));
+ save_item(STRUCT_MEMBER(m_specify, rwch));
+ save_item(STRUCT_MEMBER(m_specify, rwcl));
+
+ save_item(STRUCT_MEMBER(m_transfer, phn));
+ save_item(STRUCT_MEMBER(m_transfer, lcnh));
+ save_item(STRUCT_MEMBER(m_transfer, lcnl));
+ save_item(STRUCT_MEMBER(m_transfer, lhn));
+ save_item(STRUCT_MEMBER(m_transfer, lsn));
+ save_item(STRUCT_MEMBER(m_transfer, scnt));
+
+ save_item(NAME(m_buf_index));
+ save_item(NAME(m_buf_count));
+ save_pointer(NAME(m_buf), BUF_SIZE);
+
+ save_item(NAME(m_dreq_state));
+ save_item(NAME(m_int_state));
+ save_item(NAME(m_tc_state));
+
+ m_state_timer = timer_alloc(timer_expired_delegate(FUNC(upd7261_device::state_timer), this));
+
+ m_buf = std::make_unique<u8[]>(BUF_SIZE);
+}
+
+void upd7261_device::device_reset()
+{
+ m_state = IDLE;
+
+ m_status = 0;
+ m_est = 0;
+ m_ist = 0;
+ m_ua = 0;
+
+ for (u16 &pcn : m_pcn)
+ pcn = 0;
+
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ set_dreq(false);
+ set_int(false);
+}
+
+void upd7261_device::map(address_map &map)
+{
+ map(0x0, 0x0).rw(FUNC(upd7261_device::data_r), FUNC(upd7261_device::data_w));
+ map(0x1, 0x1).rw(FUNC(upd7261_device::status_r), FUNC(upd7261_device::command_w));
+}
+
+void upd7261_device::set_dreq(int state)
+{
+ if (state != m_dreq_state)
+ {
+ LOGMASKED(LOG_STATE, "dreq %d\n", state);
+
+ if (state)
+ {
+ m_status |= S_DRQ;
+ m_buf_count = m_specify.dtl();
+ }
+ else
+ {
+ m_status &= ~S_DRQ;
+ m_buf_count = 0;
+ }
+
+ m_dreq_state = state;
+ m_dreq(m_dreq_state);
+ }
+}
+
+void upd7261_device::set_int(bool state)
+{
+ if (state != m_int_state)
+ {
+ LOGMASKED(LOG_STATE, "int %d\n", state);
+ m_int_state = state;
+ m_int(m_int_state);
+ }
+}
+
+void upd7261_device::tc_w(int state)
+{
+ LOGMASKED(LOG_STATE, "tc %d\n", state);
+
+ m_tc_state = !state;
+}
+
+u8 upd7261_device::data_r()
+{
+ if (m_buf_index == m_buf_count)
+ fatalerror("%s: buffer underrun\n", tag());
+
+ u8 const data = m_buf[m_buf_index++];
+
+ if (m_status & S_DRQ)
+ LOGMASKED(LOG_DMA, "data_r 0x%02x (dma)\n", data);
+ else
+ LOGMASKED(LOG_REGR, "data_r 0x%02x (%s)\n", data, machine().describe_context());
+
+ if ((m_status & S_DRQ) && (m_buf_index == m_buf_count))
+ m_state_timer->adjust(attotime::zero);
+
+ return data;
+}
+
+void upd7261_device::data_w(u8 data)
+{
+ if (m_status & S_DRQ)
+ LOGMASKED(LOG_DMA, "data_w 0x%02x (dma)\n", data);
+ else
+ LOGMASKED(LOG_REGW, "data_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ if (m_buf_index == BUF_SIZE)
+ fatalerror("%s: buffer overrun\n", tag());
+
+ m_buf[m_buf_index++] = data;
+
+ if ((m_status & S_DRQ) && (m_buf_index == m_buf_count))
+ m_state_timer->adjust(attotime::zero);
+}
+
+u8 upd7261_device::status_r()
+{
+ u8 data = m_status;
+
+ LOGMASKED(LOG_REGR, "status_r 0x%02x (%s)\n", data, machine().describe_context());
+
+ return data;
+}
+
+void upd7261_device::command_w(u8 data)
+{
+ LOGMASKED(LOG_REGW, "command_w 0x%02x (%s)\n", data, machine().describe_context());
+ static constexpr attotime execute = attotime::from_nsec(400);
+
+ if (BIT(data, 4, 4))
+ {
+ m_status &= ~(S_CEH | S_CEL);
+ m_status |= S_CB;
+
+ m_ua = BIT(data, 0, (m_specify.mode & SM_SSEC) ? 2 : 3);
+
+ m_est = 0;
+
+ switch (BIT(data, 4, 4))
+ {
+ case 0x1: // sense interrupt status
+ LOGMASKED(LOG_COMMAND, "sense interrupt status 0x%02x\n", m_ist);
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ if (m_status & S_SRQ)
+ {
+ m_buf[m_buf_count++] = m_ist;
+ m_status &= ~S_SRQ;
+ m_state = COMPLETE;
+ }
+ else
+ m_state = ERROR;
+
+ m_ist = 0;
+ m_state_timer->adjust(execute);
+ break;
+ case 0x2: // specify
+ m_specify.mode = m_buf[0];
+ m_specify.dtlh = m_buf[1];
+ m_specify.dtll = m_buf[2];
+ m_specify.etn = m_buf[3];
+ m_specify.esn = m_buf[4];
+ m_specify.gpl2 = m_buf[5];
+ m_specify.rwch = m_buf[6];
+ m_specify.rwcl = m_buf[7];
+
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ LOGMASKED(LOG_COMMAND, "specify mode 0x%02x dtl 0x%04x etn 0x%02x esn 0x%02x gpl2 0x%02x rwch 0x%02x rwcl 0x%02x\n",
+ m_specify.mode, m_specify.dtl(), m_specify.etn, m_specify.esn, m_specify.gpl2, m_specify.rwch, m_specify.rwcl);
+
+ if (!(m_specify.mode & SM_SSEC))
+ fatalerror("%s: hard sectored mode is not emulated\n", tag());
+
+ m_state = COMPLETE;
+ m_state_timer->adjust(execute);
+ break;
+ case 0x3: // sense unit status
+ LOGMASKED(LOG_COMMAND, "sense unit status\n");
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ if (m_drive[m_ua] && m_drive[m_ua]->exists())
+ m_buf[m_buf_count++] = UST_D4 | UST_D1;
+ else
+ m_buf[m_buf_count++] = 0;
+
+ m_state = COMPLETE;
+ m_state_timer->adjust(execute);
+ break;
+ case 0x4: // detect error
+ LOGMASKED(LOG_COMMAND, "detect error (not emulated)\n");
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ m_state = RESULTS_4;
+ m_state_timer->adjust(execute);
+ break;
+ case 0x5: // recalibrate
+ LOGMASKED(LOG_COMMAND, "recalibrate (%s mode with polling %s)\n",
+ BIT(data, 3) ? "buffered" : "normal", (m_specify.dtlh & DTLH_NPOL) ? "disabled" : "enabled");
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ if (m_specify.mode & SM_SSEC)
+ {
+ if (m_specify.dtlh & DTLH_NPOL)
+ {
+ // non-polled mode
+ m_buf[m_buf_count++] = IST_SEN | m_ua;
+ m_state = COMPLETE;
+
+ m_state_timer->adjust(attotime::from_ticks(m_specify.stp(m_pcn[m_ua]), clock()));
+ m_pcn[m_ua] = 0;
+ }
+ else
+ {
+ // polled mode
+ m_state = SEEK_POLLED0;
+ m_state_timer->adjust(execute, 0);
+ }
+ }
+ break;
+ case 0x6: // seek
+ LOGMASKED(LOG_COMMAND, "seek pcn 0x%04x (%s mode with polling %s)\n",
+ u16(m_buf[0]) << 8 | m_buf[1], BIT(data, 3) ? "buffered" : "normal",
+ (m_specify.dtlh & DTLH_NPOL) ? "disabled" : "enabled");
+
+ m_buf_index = 0;
+ m_buf_count = 0;
+ if (m_specify.mode & SM_SSEC)
+ {
+ u16 const pcn = u16(m_buf[0]) << 8 | m_buf[1];
+
+ if (m_specify.dtlh & DTLH_NPOL)
+ {
+ // non-polled mode
+ m_buf[m_buf_count++] = IST_SEN | m_ua;
+ m_state = COMPLETE;
+
+ m_state_timer->adjust(attotime::from_ticks(m_specify.stp((pcn > m_pcn[m_ua]) ? pcn - m_pcn[m_ua] : m_pcn[m_ua] - pcn), clock()));
+ m_pcn[m_ua] = pcn;
+ }
+ else
+ {
+ m_state = SEEK_POLLED0;
+ m_state_timer->adjust(execute, pcn);
+ }
+ }
+ break;
+ case 0x7: // format
+ LOGMASKED(LOG_COMMAND, "format (not emulated)\n");
+ break;
+ case 0x8: // verify id
+ LOGMASKED(LOG_COMMAND, "verify id (not emulated)\n");
+ break;
+ case 0x9: // read id
+ LOGMASKED(LOG_COMMAND, "read id (not emulated)\n");
+ break;
+ case 0xa: // read diagnostic
+ LOGMASKED(LOG_COMMAND, "read diagnostic (not emulated)\n");
+ break;
+ case 0xb: // read data
+ if (m_specify.mode & SM_SSEC)
+ {
+ m_transfer.phn = m_buf[0];
+ m_transfer.lcnh = m_buf[1];
+ m_transfer.lcnl = m_buf[2];
+ m_transfer.lhn = m_buf[3];
+ m_transfer.lsn = m_buf[4];
+ m_transfer.scnt = m_buf[5];
+
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ LOGMASKED(LOG_COMMAND, "read data phn 0x%02x lcn 0x%04x lhn 0x%02x lsn 0x%02x scnt 0x%02x\n",
+ m_transfer.phn, m_transfer.lcn(), m_transfer.lhn, m_transfer.lsn, m_transfer.scnt);
+
+ m_state = EXECUTE_READ;
+ m_state_timer->adjust(execute);
+ }
+ break;
+ case 0xc: // check
+ LOGMASKED(LOG_COMMAND, "check (not emulated)\n");
+ break;
+ case 0xd: // scan
+ LOGMASKED(LOG_COMMAND, "scan (not emulated)\n");
+ break;
+ case 0xe: // verify data
+ LOGMASKED(LOG_COMMAND, "verify data (not emulated)\n");
+ break;
+ case 0xf: // write data
+ if (m_specify.mode & SM_SSEC)
+ {
+ m_transfer.phn = m_buf[0];
+ m_transfer.lcnh = m_buf[1];
+ m_transfer.lcnl = m_buf[2];
+ m_transfer.lhn = m_buf[3];
+ m_transfer.lsn = m_buf[4];
+ m_transfer.scnt = m_buf[5];
+
+ m_buf_index = 0;
+ m_buf_count = 0;
+
+ LOGMASKED(LOG_COMMAND, "write data phn 0x%02x lcn 0x%04x lhn 0x%02x lsn 0x%02x scnt 0x%02x\n",
+ m_transfer.phn, m_transfer.lcn(), m_transfer.lhn, m_transfer.lsn, m_transfer.scnt);
+
+ m_state = EXECUTE_WRITE;
+ set_dreq(true);
+ }
+ break;
+ }
+ }
+ else
+ {
+ u8 mask = (S_CEH | S_CEL | S_SRQ);
+
+ LOGMASKED(LOG_COMMAND, "auxiliary command%s%s%s%s\n",
+ BIT(data, 0) ? ", chip reset" : "",
+ BIT(data, 1) ? ", clear data" : "",
+ BIT(data, 2) ? ", clear srq" : "",
+ BIT(data, 3) ? ", clear ce" : "");
+
+ if (BIT(data, 0))
+ reset();
+ if (BIT(data, 1))
+ {
+ m_buf_index = 0;
+ m_buf_count = 0;
+ }
+ if (BIT(data, 2))
+ mask &= ~S_SRQ;
+ if (BIT(data, 3))
+ m_status &= ~(S_CEH | S_CEL);
+
+ set_int(m_status & mask);
+ }
+}
+
+void upd7261_device::state_timer(s32 param)
+{
+ // step state machine
+ attotime const delay = state_step(param);
+
+ // check for data stall
+ if (delay.is_never())
+ return;
+
+ // repeat until idle
+ if (m_state != IDLE)
+ m_state_timer->adjust(delay);
+}
+
+attotime upd7261_device::state_step(s32 param)
+{
+ attotime delay = attotime::zero;
+
+ switch (m_state)
+ {
+ case IDLE:
+ break;
+
+ case EXECUTE_READ:
+ // check unit address is valid
+ if (!m_drive[m_ua] && m_drive[m_ua]->exists())
+ m_est |= EST_NR;
+
+ if (m_transfer.scnt && !m_est)
+ {
+ // HACK: The MG-1 has an additional external head select bit, and
+ // expects the controller to report "no data" when the sector to be
+ // transferred can't be found on the track. This hack uses a fake
+ // external head register to check whether the current head matches
+ // before reading the disk.
+ if (m_transfer.lhn == ((m_head & ~7) | (m_transfer.lhn & 7)))
+ {
+ // read a sector
+ harddisk_image_device &hid(*m_drive[m_ua]);
+ hard_disk_file::info const &i = hid.get_info();
+
+ u32 const lba = ((m_transfer.lcn() * i.heads) + m_transfer.lhn) * i.sectors + m_transfer.lsn;
+
+ hid.read(lba, m_buf.get());
+ m_buf_index = 0;
+
+ m_transfer.scnt--;
+
+ if (m_transfer.lsn++ == m_specify.esn)
+ {
+ m_transfer.lsn = 0;
+
+ if (m_transfer.lhn++ == m_specify.etn)
+ {
+ m_transfer.lhn = 0;
+ m_transfer.lcnl++;
+ if (m_transfer.lcnl == 0)
+ m_transfer.lcnh++;
+
+ if (m_transfer.scnt)
+ m_est |= EST_ENC;
+ }
+ }
+
+ delay = attotime::never;
+ }
+ else
+ {
+ m_est = EST_ND;
+ m_state = RESULTS_bcdef;
+ m_buf_index = 0;
+ }
+ }
+ else
+ {
+ m_state = RESULTS_bcdef;
+ m_buf_index = 0;
+ }
+
+ set_dreq(m_state == EXECUTE_READ);
+ break;
+
+ case EXECUTE_WRITE:
+ // check unit address is valid
+ if (!m_drive[m_ua] && m_drive[m_ua]->exists())
+ m_est |= EST_NR;
+
+ if (m_transfer.scnt && !m_est)
+ {
+ // HACK: as above for reading
+ if (m_transfer.lhn == ((m_head & ~7) | (m_transfer.lhn & 7)))
+ {
+ // write a sector
+ harddisk_image_device &hid(*m_drive[m_ua]);
+ hard_disk_file::info const &i = hid.get_info();
+
+ u32 const lba = ((m_transfer.lcn() * i.heads) + m_transfer.lhn) * i.sectors + m_transfer.lsn;
+
+ hid.write(lba, m_buf.get());
+ m_buf_index = 0;
+
+ m_transfer.scnt--;
+
+ if (m_transfer.lsn++ == m_specify.esn)
+ {
+ m_transfer.lsn = 0;
+
+ if (m_transfer.lhn++ == m_specify.etn)
+ {
+ m_transfer.lhn = 0;
+ m_transfer.lcnl++;
+ if (m_transfer.lcnl == 0)
+ m_transfer.lcnh++;
+
+ if (m_transfer.scnt)
+ {
+ m_est |= EST_ENC;
+ m_state = RESULTS_bcdef;
+ }
+ }
+ }
+
+ if (!m_transfer.scnt)
+ m_state = RESULTS_bcdef;
+
+ if (m_state == EXECUTE_WRITE)
+ delay = attotime::never;
+ }
+ else
+ {
+ m_est = EST_ND;
+ m_state = RESULTS_bcdef;
+ m_buf_index = 0;
+ }
+ }
+ else
+ {
+ m_state = RESULTS_bcdef;
+ m_buf_index = 0;
+ }
+
+ set_dreq(m_state == EXECUTE_WRITE);
+ break;
+
+ case SEEK_POLLED0:
+ m_status &= ~S_CB;
+ m_status |= S_CEH;
+ m_state = SEEK_POLLED1;
+
+ delay = attotime::from_ticks(m_specify.stp(std::abs(m_pcn[m_ua] - param)), clock());
+ m_pcn[m_ua] = param;
+
+ set_int(true);
+ break;
+
+ case SEEK_POLLED1:
+ m_ist |= IST_SEN | m_ua;
+ m_status |= S_SRQ;
+ m_state = IDLE;
+
+ set_int(true);
+ break;
+
+ case RESULTS_4:
+ m_buf[m_buf_count++] = 0; // eadh
+ m_buf[m_buf_count++] = 0; // eadl
+ m_buf[m_buf_count++] = 0; // ept1
+ m_buf[m_buf_count++] = 0; // ept2
+ m_buf[m_buf_count++] = 0; // ept3
+
+ m_state = COMPLETE;
+ break;
+
+ case RESULTS_789:
+ m_buf[m_buf_count++] = m_est;
+ m_buf[m_buf_count++] = m_transfer.scnt;
+
+ m_state = COMPLETE;
+ break;
+
+ case RESULTS_bcdef:
+ m_buf[m_buf_count++] = m_est;
+ m_buf[m_buf_count++] = m_transfer.phn;
+ // (flag)
+ m_buf[m_buf_count++] = m_transfer.lcnh;
+ m_buf[m_buf_count++] = m_transfer.lcnl;
+ m_buf[m_buf_count++] = m_transfer.lhn;
+ m_buf[m_buf_count++] = m_transfer.lsn;
+ m_buf[m_buf_count++] = m_transfer.scnt;
+
+ m_state = COMPLETE;
+ break;
+
+ case COMPLETE:
+ if (m_est)
+ m_status |= S_CEL;
+ else
+ m_status |= S_CEH;
+ m_status &= ~S_CB;
+
+ set_int(true);
+
+ m_state = IDLE;
+ break;
+
+ case ERROR:
+ m_status |= S_CEH | S_CEL;
+ m_status &= ~S_CB;
+
+ set_int(true);
+
+ m_state = IDLE;
+ break;
+ }
+
+ return delay;
+}
+
+u16 upd7261_device::specify::dtl() const
+{
+ return u16(dtlh & DTLH_DTLH) << 8 | dtll;
+}
+
+u16 upd7261_device::transfer::lcn() const
+{
+ return u16(lcnh) << 8 | lcnl;
+}
+
+unsigned upd7261_device::specify::stp(unsigned cylinders) const
+{
+ /*
+ * Datasheet formula for ST506 interface stepping is given as:
+ *
+ * (16 - stp) * 2110 * tCY
+ *
+ * Example for a 10MHz clock gives a range of stepping values from
+ * 2.11ms to 33.76ms; formula seems incorrect by a factor of 10?
+ */
+ return (16 - (mode & SM_STP)) * 21100 * cylinders;
+}
diff --git a/src/devices/machine/upd7261.h b/src/devices/machine/upd7261.h
new file mode 100644
index 00000000000..d2c10691950
--- /dev/null
+++ b/src/devices/machine/upd7261.h
@@ -0,0 +1,104 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_UPD7261_H
+#define MAME_MACHINE_UPD7261_H
+
+#pragma once
+
+#include "imagedev/harddriv.h"
+
+class upd7261_device
+ : public device_t
+{
+public:
+ upd7261_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // output lines
+ auto out_dreq() { return m_dreq.bind(); }
+ auto out_int() { return m_int.bind(); }
+
+ // input lines
+ void tc_w(int state);
+ void head_w(u8 data) { m_head = data; }
+
+ void map(address_map &map);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void set_dreq(int state);
+ void set_int(bool state);
+
+ u8 data_r();
+ u8 status_r();
+ void data_w(u8 data);
+ void command_w(u8 data);
+
+ void state_timer(s32 param);
+ attotime state_step(s32 param);
+
+private:
+ optional_device_array<harddisk_image_device, 8> m_drive;
+
+ devcb_write_line m_dreq;
+ devcb_write_line m_int;
+
+ emu_timer *m_state_timer;
+
+ u32 m_state;
+ u8 m_head; // head number (extended)
+
+ u8 m_status; // status register
+ u8 m_est; // error status byte
+ u8 m_ist; // interrupt status byte
+ u8 m_ua; // unit address
+ u16 m_pcn[4]; // physical cylinder number
+
+ struct specify
+ {
+ // data transfer length
+ u16 dtl() const;
+
+ // step time in ticks
+ unsigned stp(unsigned cylinders) const;
+
+ u8 mode; // operation mode
+ u8 dtlh; // data transfer length (high byte)
+ u8 dtll; // data transfer length (low byte)
+ u8 etn; // ending track number
+ u8 esn; // ending sector number
+ u8 gpl2; // gap length 2
+ u8 rwch; // reduced write current cylinder (high byte)
+ u8 rwcl; // reduced write current cylinder (low byte)
+ }
+ m_specify;
+ struct transfer
+ {
+ // logical cylinder number
+ u16 lcn() const;
+
+ u8 phn; // physical head number
+ u8 lcnh; // logical cylinder number (high byte)
+ u8 lcnl; // logical cylinder number (low byte)
+ u8 lhn; // logical head number
+ u8 lsn; // logical sector number
+ u8 scnt; // sector count
+ }
+ m_transfer;
+
+ // data buffer
+ u32 m_buf_index;
+ u32 m_buf_count;
+ std::unique_ptr<u8[]> m_buf;
+
+ // i/o line state
+ bool m_dreq_state;
+ bool m_int_state;
+ bool m_tc_state;
+};
+
+DECLARE_DEVICE_TYPE(UPD7261, upd7261_device)
+
+#endif // MAME_MACHINE_UPD7261_H
diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp
index f2eff71730e..694a32b0999 100644
--- a/src/devices/machine/upd765.cpp
+++ b/src/devices/machine/upd765.cpp
@@ -20,7 +20,7 @@
#define LOG_LIVE (1U << 12) // Live states
#define LOG_DONE (1U << 13) // Command done
-#define VERBOSE (LOG_GENERAL | LOG_WARN )
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
#include "logmacro.h"
@@ -53,9 +53,11 @@ DEFINE_DEVICE_TYPE(N82077AA, n82077aa_device, "n82077aa", "Int
DEFINE_DEVICE_TYPE(PC_FDC_SUPERIO, pc_fdc_superio_device, "pc_fdc_superio", "Winbond PC FDC Super I/O")
DEFINE_DEVICE_TYPE(DP8473, dp8473_device, "dp8473", "National Semiconductor DP8473 FDC")
DEFINE_DEVICE_TYPE(PC8477A, pc8477a_device, "pc8477a", "National Semiconductor PC8477A FDC")
+DEFINE_DEVICE_TYPE(PC8477B, pc8477b_device, "pc8477b", "National Semiconductor PC8477B FDC")
DEFINE_DEVICE_TYPE(WD37C65C, wd37c65c_device, "wd37c65c", "Western Digital WD37C65C FDC")
DEFINE_DEVICE_TYPE(MCS3201, mcs3201_device, "mcs3201", "Motorola MCS3201 FDC")
DEFINE_DEVICE_TYPE(TC8566AF, tc8566af_device, "tc8566af", "Toshiba TC8566AF FDC")
+DEFINE_DEVICE_TYPE(HD63266F, hd63266f_device, "hd63266f", "Hitachi HD63266F FDC")
void upd765a_device::map(address_map &map)
{
@@ -139,6 +141,19 @@ void pc8477a_device::map(address_map &map)
map(0x7, 0x7).rw(FUNC(pc8477a_device::dir_r), FUNC(pc8477a_device::ccr_w));
}
+void pc8477b_device::map(address_map &map)
+{
+ if(mode != mode_t::AT) {
+ map(0x0, 0x0).r(FUNC(pc8477b_device::sra_r));
+ map(0x1, 0x1).r(FUNC(pc8477b_device::srb_r));
+ }
+ map(0x2, 0x2).rw(FUNC(pc8477b_device::dor_r), FUNC(pc8477b_device::dor_w));
+ map(0x3, 0x3).rw(FUNC(pc8477b_device::tdr_r), FUNC(pc8477b_device::tdr_w));
+ map(0x4, 0x4).rw(FUNC(pc8477b_device::msr_r), FUNC(pc8477b_device::dsr_w));
+ map(0x5, 0x5).rw(FUNC(pc8477b_device::fifo_r), FUNC(pc8477b_device::fifo_w));
+ map(0x7, 0x7).rw(FUNC(pc8477b_device::dir_r), FUNC(pc8477b_device::ccr_w));
+}
+
void wd37c65c_device::map(address_map &map)
{
// NOTE: this map only covers registers defined by CS.
@@ -201,22 +216,13 @@ void ps2_fdc_device::set_mode(mode_t _mode)
mode = _mode;
}
-void upd765_family_device::device_resolve_objects()
-{
- intrq_cb.resolve_safe();
- drq_cb.resolve_safe();
- hdl_cb.resolve_safe();
- idx_cb.resolve_safe();
- us_cb.resolve_safe();
-}
-
void upd765_family_device::device_start()
{
save_item(NAME(selected_drive));
for(int i=0; i != 4; i++) {
char name[2];
- flopi[i].tm = timer_alloc(i);
+ flopi[i].tm = timer_alloc(FUNC(upd765_family_device::update_floppy), this);
flopi[i].id = i;
if(select_connected) {
name[0] = '0'+i;
@@ -257,7 +263,7 @@ void upd765_family_device::device_start()
cur_live.fi = nullptr;
if(ready_polled) {
- poll_timer = timer_alloc(TIMER_DRIVE_READY_POLLING);
+ poll_timer = timer_alloc(FUNC(upd765_family_device::run_drive_ready_polling), this);
poll_timer->adjust(attotime::from_usec(100), 0, attotime::from_usec(1024));
} else
poll_timer = nullptr;
@@ -286,8 +292,7 @@ void upd765_family_device::soft_reset()
flopi[i].st0_filled = false;
}
clr_drive_busy();
- data_irq = false;
- other_irq = false;
+ irq = false;
internal_drq = false;
fifo_pos = 0;
command_pos = 0;
@@ -343,7 +348,7 @@ bool upd765_family_device::get_ready(int fid)
return !external_ready;
}
-WRITE_LINE_MEMBER(upd765_family_device::reset_w)
+void upd765_family_device::reset_w(int state)
{
// This implementation is not valid for devices with DOR and possibly other extra registers.
// The working assumption is that no need to manipulate the RESET line directly when software can use DOR instead.
@@ -396,8 +401,7 @@ void upd765_family_device::set_floppy(floppy_image_device *flop)
uint8_t ps2_fdc_device::sra_r()
{
uint8_t sra = 0;
- int fid = dor & 3;
- floppy_info &fi = flopi[fid];
+ floppy_info &fi = flopi[dor & 3];
if(fi.dir)
sra |= 0x01;
if(fi.index)
@@ -408,17 +412,38 @@ uint8_t ps2_fdc_device::sra_r()
sra |= 0x10;
if(fi.main_state == SEEK_WAIT_STEP_SIGNAL_TIME)
sra |= 0x20;
- sra |= 0x40;
if(cur_irq)
sra |= 0x80;
if(mode == mode_t::M30)
+ {
sra ^= 0x1f;
+ if(drq)
+ sra |= 0x40;
+ }
+ else
+ {
+ if(!flopi[1].dev)
+ sra |= 0x40;
+ }
return sra;
}
uint8_t ps2_fdc_device::srb_r()
{
- return 0;
+ uint8_t srb = 0;
+ // TODO: rddata, wrdata, write enable bits
+ if(mode == mode_t::M30)
+ {
+ const uint8_t ds[4] = { 0x43, 0x23, 0x62, 0x61 };
+ srb = ds[dor & 3];
+ if(!flopi[1].dev)
+ srb |= 0x80;
+ }
+ else
+ {
+ srb = 0xc0 | ((dor & 1) << 6) | ((dor & 0x30) >> 4);
+ }
+ return srb;
}
uint8_t upd765_family_device::dor_r()
@@ -458,7 +483,7 @@ void upd765_family_device::tdr_w(uint8_t data)
uint8_t upd765_family_device::msr_r()
{
- uint32_t msr = 0;
+ uint8_t msr = 0;
switch(main_phase) {
case PHASE_CMD:
msr |= MSR_RQM;
@@ -487,11 +512,6 @@ uint8_t upd765_family_device::msr_r()
}
msr |= get_drive_busy();
- if(data_irq && !machine().side_effects_disabled()) {
- data_irq = false;
- check_irq();
- }
-
return msr;
}
@@ -512,13 +532,25 @@ void upd765_family_device::set_rate(int rate)
uint8_t upd765_family_device::fifo_r()
{
uint8_t r = 0xff;
+ if(!machine().side_effects_disabled())
+ {
+ irq = false;
+ check_irq();
+ }
switch(main_phase) {
+ case PHASE_CMD:
+ if(machine().side_effects_disabled())
+ return 0xff;
+ if(command_pos)
+ fifo_w(0xff);
+ LOGFIFO("fifo_r in command phase\n");
+ break;
case PHASE_EXEC:
if(machine().side_effects_disabled())
return fifo[0];
if(internal_drq)
return fifo_pop(false);
- LOGFIFO("fifo_r in phase %d\n", main_phase);
+ LOGFIFO("fifo_r in execution phase\n");
break;
case PHASE_RESULT:
@@ -550,11 +582,12 @@ void upd765_family_device::fifo_w(uint8_t data)
if(!BIT(dor, 2))
LOGWARN("%s: fifo_w(%02x) in reset\n", machine().describe_context(), data);
+ irq = false;
+ check_irq();
+
switch(main_phase) {
case PHASE_CMD: {
command[command_pos++] = data;
- other_irq = false;
- check_irq();
int cmd = check_command();
if(cmd == C_INCOMPLETE)
break;
@@ -574,7 +607,7 @@ void upd765_family_device::fifo_w(uint8_t data)
fifo_push(data, false);
return;
}
- LOGFIFO("fifo_w in phase %d\n", main_phase);
+ LOGFIFO("fifo_w in execution phase\n");
break;
default:
@@ -619,11 +652,10 @@ void upd765_family_device::enable_transfer()
check_irq();
}
- } else {
- // DMA
- if(!drq)
- set_drq(true);
}
+ // DMA
+ if(!drq)
+ set_drq(true);
}
void upd765_family_device::disable_transfer()
@@ -631,8 +663,8 @@ void upd765_family_device::disable_transfer()
if(spec & SPEC_ND) {
internal_drq = false;
check_irq();
- } else
- set_drq(false);
+ }
+ set_drq(false);
}
void upd765_family_device::fifo_push(uint8_t data, bool internal)
@@ -679,8 +711,8 @@ uint8_t upd765_family_device::fifo_pop(bool internal)
memmove(fifo, fifo+1, fifo_pos);
if(!fifo_write && !fifo_pos)
disable_transfer();
- int thr = fifocfg & 15;
- if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & 0x20)))
+ int thr = fifocfg & FIF_THR;
+ if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & FIF_DIS)))
enable_transfer();
return r;
}
@@ -743,7 +775,7 @@ void upd765_family_device::live_delay(int state)
{
cur_live.next_state = state;
if(cur_live.tm != machine().time())
- cur_live.fi->tm->adjust(cur_live.tm - machine().time());
+ cur_live.fi->tm->adjust(cur_live.tm - machine().time(), cur_live.fi->id);
else
live_sync();
}
@@ -807,7 +839,7 @@ void upd765_family_device::live_run(attotime limit)
// infinity looking for data too.
limit = machine().time() + attotime::from_msec(1);
- cur_live.fi->tm->adjust(attotime::from_msec(1));
+ cur_live.fi->tm->adjust(attotime::from_msec(1), cur_live.fi->id);
}
}
@@ -977,6 +1009,13 @@ void upd765_family_device::live_run(attotime limit)
return;
}
+ if (
+ ((command[0] & 0x08) == 0 && cur_live.data_reg == 0xf8) // Encountered deleted sector during read data
+ || ((command[0] & 0x08) != 0 && cur_live.data_reg == 0xfb) // Encountered normal sector during read deleted data
+ ) {
+ st2 |= ST2_CM;
+ }
+
cur_live.bit_counter = 0;
cur_live.state = READ_SECTOR_DATA;
break;
@@ -1294,17 +1333,31 @@ int upd765_family_device::check_command()
// MSDOS 6.22 format uses 0xcd to format a track, which makes one
// think only the bottom 5 bits are decoded.
+ // The real 765 completely decodes the commands that don't have
+ // variable upper bits. Some later superio chips don't.
+ // The MCS Powerview depends on this.
- switch(command[0] & 0x1f) {
- case 0x02:
- return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE;
-
+ switch(command[0]) {
case 0x03:
return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE;
case 0x04:
return command_pos == 2 ? C_SENSE_DRIVE_STATUS : C_INCOMPLETE;
+ case 0x07:
+ return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE;
+
+ case 0x08:
+ return C_SENSE_INTERRUPT_STATUS;
+
+ case 0x0f:
+ return command_pos == 3 ? C_SEEK : C_INCOMPLETE;
+ }
+
+ switch(command[0] & 0x1f) {
+ case 0x02:
+ return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE;
+
case 0x05:
case 0x09:
return command_pos == 9 ? C_WRITE_DATA : C_INCOMPLETE;
@@ -1313,21 +1366,12 @@ int upd765_family_device::check_command()
case 0x0c:
return command_pos == 9 ? C_READ_DATA : C_INCOMPLETE;
- case 0x07:
- return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE;
-
- case 0x08:
- return C_SENSE_INTERRUPT_STATUS;
-
case 0x0a:
return command_pos == 2 ? C_READ_ID : C_INCOMPLETE;
case 0x0d:
return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE;
- case 0x0f:
- return command_pos == 3 ? C_SEEK : C_INCOMPLETE;
-
case 0x11:
return command_pos == 9 ? C_SCAN_EQUAL : C_INCOMPLETE;
@@ -1457,8 +1501,6 @@ void upd765_family_device::execute_command(int cmd)
LOGCOMMAND("command sense interrupt status (fid=%d %02x %02x) (%s)\n", fid, result[0], result[1], machine().describe_context());
result_pos = 2;
- other_irq = false;
- check_irq();
break;
}
@@ -1542,12 +1584,9 @@ void upd765_family_device::command_end(floppy_info &fi, bool data_completion)
{
LOGDONE("command done (%s) - %s\n", data_completion ? "data" : "seek", results());
fi.main_state = fi.sub_state = IDLE;
- if(data_completion)
- data_irq = true;
- else {
- other_irq = true;
+ irq = true;
+ if(!data_completion)
fi.st0_filled = true;
- }
check_irq();
}
@@ -1587,9 +1626,9 @@ void upd765_family_device::seek_start(floppy_info &fi)
seek_continue(fi);
}
-void upd765_family_device::delay_cycles(emu_timer *tm, int cycles)
+void upd765_family_device::delay_cycles(floppy_info &fi, int cycles)
{
- tm->adjust(attotime::from_double(double(cycles)/cur_rate));
+ fi.tm->adjust(attotime::from_double(double(cycles)/cur_rate), fi.id);
}
void upd765_family_device::seek_continue(floppy_info &fi)
@@ -1603,7 +1642,7 @@ void upd765_family_device::seek_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -1622,7 +1661,7 @@ void upd765_family_device::seek_continue(floppy_info &fi)
fi.pcn++;
}
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*(16-(spec >> 12)));
+ delay_cycles(fi, 500*(16-(spec >> 12)));
return;
case SEEK_WAIT_STEP_TIME:
@@ -1653,7 +1692,7 @@ void upd765_family_device::seek_continue(floppy_info &fi)
if(done) {
fi.sub_state = SEEK_WAIT_DONE;
// recalibrate and seek takes some time, even if we don't move
- fi.tm->adjust(attotime::from_nsec((fi.main_state == RECALIBRATE) ? 20000 : 10000));
+ fi.tm->adjust(attotime::from_nsec((fi.main_state == RECALIBRATE) ? 20000 : 10000), fi.id);
return;
}
fi.sub_state = SEEK_MOVE;
@@ -1765,12 +1804,12 @@ void upd765_family_device::read_data_continue(floppy_info &fi)
switch(fi.sub_state) {
case HEAD_LOAD:
LOGSTATE("HEAD_LOAD\n");
- delay_cycles(fi.tm, 500*(spec & 0x00fe));
+ delay_cycles(fi, 500*(spec & 0x00fe));
fi.sub_state = HEAD_LOAD_DONE;
break;
case HEAD_LOAD_DONE:
LOGSTATE("HEAD_LOAD_DONE\n");
- if(fi.pcn == command[2] || !(fifocfg & 0x40)) {
+ if(fi.pcn == command[2] || !(fifocfg & FIF_EIS)) {
fi.sub_state = SEEK_DONE;
break;
}
@@ -1780,7 +1819,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -1793,7 +1832,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi)
fi.dev->stp_w(1);
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*(16-(spec >> 12)));
+ delay_cycles(fi, 500*(16-(spec >> 12)));
return;
case SEEK_WAIT_STEP_TIME:
@@ -1847,6 +1886,7 @@ void upd765_family_device::read_data_continue(floppy_info &fi)
return;
}
st1 &= ~ST1_ND;
+ st2 &= ~ST2_WC;
LOGRW("reading sector %02x %02x %02x %02x\n",
cur_live.idbuf[0],
cur_live.idbuf[1],
@@ -1878,10 +1918,19 @@ void upd765_family_device::read_data_continue(floppy_info &fi)
if(cur_live.crc) {
fi.st0 |= ST0_FAIL;
st1 |= ST1_DE;
- st2 |= ST2_CM;
+ st2 |= ST2_DD;
fi.sub_state = COMMAND_DONE;
break;
}
+
+ if ((st2 & ST2_CM) && !(command[0] & 0x20)) {
+ // Encountered terminating sector while in non-skip mode.
+ // This will stop reading when a normal data sector is encountered during read deleted data,
+ // or when a deleted sector is encountered during a read data command.
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+
bool done = tc_done;
if(command[4] == command[6]) {
if(command[0] & 0x80) {
@@ -1969,6 +2018,14 @@ void upd765_family_device::write_data_start(floppy_info &fi)
write_data_continue(fi);
return;
}
+ else if(fi.dev && fi.dev->wpt_r()) {
+ fi.st0 |= ST0_FAIL;
+ fi.sub_state = COMMAND_DONE;
+ st1 = ST1_NW;
+ st2 = 0;
+ write_data_continue(fi);
+ return;
+ }
write_data_continue(fi);
}
@@ -1979,7 +2036,7 @@ void upd765_family_device::write_data_continue(floppy_info &fi)
switch(fi.sub_state) {
case HEAD_LOAD:
LOGSTATE("HEAD_LOAD\n");
- delay_cycles(fi.tm, 500*(spec & 0x00fe));
+ delay_cycles(fi, 500*(spec & 0x00fe));
fi.sub_state = HEAD_LOAD_DONE;
break;
case HEAD_LOAD_DONE:
@@ -2120,12 +2177,12 @@ void upd765_family_device::read_track_continue(floppy_info &fi)
switch(fi.sub_state) {
case HEAD_LOAD:
LOGSTATE("HEAD_LOAD\n");
- delay_cycles(fi.tm, 500*(spec & 0x00fe));
+ delay_cycles(fi, 500*(spec & 0x00fe));
fi.sub_state = HEAD_LOAD_DONE;
break;
case HEAD_LOAD_DONE:
LOGSTATE("HEAD_LOAD_DONE\n");
- if(fi.pcn == command[2] || !(fifocfg & 0x40)) {
+ if(fi.pcn == command[2] || !(fifocfg & FIF_EIS)) {
fi.sub_state = SEEK_DONE;
break;
}
@@ -2135,7 +2192,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi)
fi.dev->stp_w(0);
}
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
- fi.tm->adjust(attotime::from_nsec(2500));
+ fi.tm->adjust(attotime::from_nsec(2500), fi.id);
return;
case SEEK_WAIT_STEP_SIGNAL_TIME:
@@ -2148,7 +2205,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi)
fi.dev->stp_w(1);
fi.sub_state = SEEK_WAIT_STEP_TIME;
- delay_cycles(fi.tm, 500*(16-(spec >> 12)));
+ delay_cycles(fi, 500*(16-(spec >> 12)));
return;
case SEEK_WAIT_STEP_TIME:
@@ -2197,7 +2254,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi)
else
st1 &= ~ST1_ND;
- sector_size = calc_sector_size(cur_live.idbuf[3]);
+ sector_size = calc_sector_size(command[5]);
fifo_expect(sector_size, false);
fi.sub_state = SECTOR_READ;
LOGSTATE("SEARCH_ADDRESS_MARK_DATA\n");
@@ -2220,7 +2277,7 @@ void upd765_family_device::read_track_continue(floppy_info &fi)
}
if(cur_live.crc) {
st1 |= ST1_DE;
- st2 |= ST2_CM;
+ st2 |= ST2_DD;
}
bool done = tc_done;
sectors_read++;
@@ -2279,12 +2336,21 @@ void upd765_family_device::format_track_start(floppy_info &fi)
set_ds(command[1] & 3);
fi.ready = get_ready(command[1] & 3);
+ st1 = 0;
+ st2 = 0;
if(!fi.ready) {
fi.st0 = (command[1] & 7) | ST0_NR | ST0_FAIL;
fi.sub_state = TRACK_DONE;
format_track_continue(fi);
return;
}
+ else if(fi.dev && fi.dev->wpt_r()) {
+ fi.st0 = (command[1] & 7) | ST0_FAIL;
+ fi.sub_state = TRACK_DONE;
+ st1 = ST1_NW;
+ format_track_continue(fi);
+ return;
+ }
fi.st0 = command[1] & 7;
if(fi.dev)
@@ -2300,7 +2366,7 @@ void upd765_family_device::format_track_continue(floppy_info &fi)
switch(fi.sub_state) {
case HEAD_LOAD:
LOGSTATE("HEAD_LOAD\n");
- delay_cycles(fi.tm, 500*(spec & 0x00fe));
+ delay_cycles(fi, 500*(spec & 0x00fe));
fi.sub_state = HEAD_LOAD_DONE;
break;
case HEAD_LOAD_DONE:
@@ -2324,8 +2390,8 @@ void upd765_family_device::format_track_continue(floppy_info &fi)
LOGSTATE("TRACK_DONE\n");
main_phase = PHASE_RESULT;
result[0] = fi.st0;
- result[1] = 0;
- result[2] = 0;
+ result[1] = st1;
+ result[2] = st2;
result[3] = 0;
result[4] = 0;
result[5] = 0;
@@ -2385,7 +2451,7 @@ void upd765_family_device::read_id_continue(floppy_info &fi)
switch(fi.sub_state) {
case HEAD_LOAD:
LOGSTATE("HEAD_LOAD\n");
- delay_cycles(fi.tm, 500*(spec & 0x00fe));
+ delay_cycles(fi, 500*(spec & 0x00fe));
fi.sub_state = HEAD_LOAD_DONE;
break;
case HEAD_LOAD_DONE:
@@ -2436,7 +2502,7 @@ void upd765_family_device::read_id_continue(floppy_info &fi)
void upd765_family_device::check_irq()
{
bool old_irq = cur_irq;
- cur_irq = data_irq || other_irq || internal_drq;
+ cur_irq = irq || internal_drq;
cur_irq = cur_irq && (dor & 4) && (mode != mode_t::AT || (dor & 8));
if(cur_irq != old_irq) {
LOGTCIRQ("irq = %d\n", cur_irq);
@@ -2469,16 +2535,11 @@ std::string upd765_family_device::ttsn() const
return machine().time().to_string();
}
-void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(upd765_family_device::update_floppy)
{
- if(id == TIMER_DRIVE_READY_POLLING) {
- run_drive_ready_polling();
- return;
- }
-
live_sync();
- floppy_info &fi = flopi[id];
+ floppy_info &fi = flopi[param];
switch(fi.sub_state) {
case SEEK_WAIT_STEP_SIGNAL_TIME:
fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE;
@@ -2491,7 +2552,7 @@ void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, in
general_continue(fi);
}
-void upd765_family_device::run_drive_ready_polling()
+TIMER_CALLBACK_MEMBER(upd765_family_device::run_drive_ready_polling)
{
if(main_phase != PHASE_CMD || (fifocfg & FIF_POLL) || command_pos)
return;
@@ -2504,7 +2565,7 @@ void upd765_family_device::run_drive_ready_polling()
if(!flopi[fid].st0_filled) {
flopi[fid].st0 = ST0_ABRT | fid;
flopi[fid].st0_filled = true;
- other_irq = true;
+ irq = true;
}
}
}
@@ -3079,6 +3140,14 @@ dp8473_device::dp8473_device(const machine_config &mconfig, const char *tag, dev
recalibrate_steps = 77; // TODO: 3917 in extended track range mode
}
+void dp8473_device::soft_reset()
+{
+ upd765_family_device::soft_reset();
+
+ // "interrupt is generated when ... Internal Ready signal changes state immediately after a hardware or software reset"
+ irq = true;
+}
+
pc8477a_device::pc8477a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ps2_fdc_device(mconfig, PC8477A, tag, owner, clock)
{
ready_polled = true;
@@ -3088,6 +3157,15 @@ pc8477a_device::pc8477a_device(const machine_config &mconfig, const char *tag, d
recalibrate_steps = 85; // TODO: may also be programmed as 255, 3925 or 4095 by (unemulated) mode command
}
+pc8477b_device::pc8477b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ps2_fdc_device(mconfig, PC8477B, tag, owner, clock)
+{
+ ready_polled = true;
+ ready_connected = false;
+ select_connected = true;
+ select_multiplexed = false;
+ recalibrate_steps = 85; // TODO: may also be programmed as 255, 3925 or 4095 by (unemulated) mode command
+}
+
wd37c65c_device::wd37c65c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
upd765_family_device(mconfig, WD37C65C, tag, owner, clock),
m_clock2(0)
@@ -3113,7 +3191,7 @@ uint8_t wd37c65c_device::get_st3(floppy_info &fi)
mcs3201_device::mcs3201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
upd765_family_device(mconfig, MCS3201, tag, owner, clock),
- m_input_handler(*this)
+ m_input_handler(*this, 0)
{
has_dor = true;
ready_polled = false;
@@ -3122,12 +3200,6 @@ mcs3201_device::mcs3201_device(const machine_config &mconfig, const char *tag, d
select_multiplexed = false;
}
-void mcs3201_device::device_start()
-{
- upd765_family_device::device_start();
- m_input_handler.resolve_safe(0);
-}
-
uint8_t mcs3201_device::input_r()
{
return m_input_handler();
@@ -3207,3 +3279,185 @@ void upd72067_device::auxcmd_w(uint8_t data)
break;
}
}
+
+void upd72069_device::auxcmd_w(uint8_t data)
+{
+ switch(data) {
+ case 0x36: // reset
+ soft_reset();
+ break;
+ case 0x1e: // motor on, probably
+ for(unsigned i = 0; i < 4; i++)
+ if(flopi[i].dev)
+ flopi[i].dev->mon_w(!BIT(data, i + 4));
+ main_phase = PHASE_RESULT;
+ result[0] = ST0_UNK;
+ result_pos = 1;
+ break;
+ }
+}
+
+
+hd63266f_device::hd63266f_device(const machine_config& mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : upd765_family_device(mconfig, HD63266F, tag, owner, clock)
+ , inp_cb(*this, 0)
+{
+ has_dor = false;
+}
+
+void hd63266f_device::map(address_map &map)
+{
+ map(0x0, 0x0).rw(FUNC(hd63266f_device::msr_r), FUNC(hd63266f_device::abort_w));
+ map(0x1, 0x1).rw(FUNC(hd63266f_device::fifo_r), FUNC(hd63266f_device::fifo_w));
+ map(0x2, 0x2).r(FUNC(hd63266f_device::extstat_r));
+}
+
+void hd63266f_device::soft_reset()
+{
+ upd765_family_device::soft_reset();
+ delayed_command = 0;
+ motor_state = 0;
+ for(int i = 0; i < 4; i++)
+ if(flopi[i].dev) flopi[i].dev->mon_w(1);
+}
+
+void hd63266f_device::abort_w(u8 data)
+{
+ if(data == 0xff) {
+ soft_reset();
+ LOGCOMMAND("abort\n");
+ }
+}
+
+int hd63266f_device::check_command()
+{
+ switch(command[0]) {
+ case 0x0e:
+ return C_SLEEP;
+ case 0x0b:
+ case 0x2b:
+ return command_pos == 4 ? C_SPECIFY : C_INCOMPLETE;
+ case 0x4b:
+ case 0x6b:
+ return command_pos == 7 ? C_SPECIFY2 : C_INCOMPLETE;
+ }
+ return upd765_family_device::check_command();
+}
+
+void hd63266f_device::execute_command(int cmd)
+{
+ switch(cmd)
+ {
+ case C_SLEEP:
+ for(int i = 0; i < 4; i++) {
+ if(flopi[i].dev) flopi[i].dev->mon_w(1);
+ }
+ main_phase = PHASE_CMD;
+ motor_state = 0;
+ LOGCOMMAND("sleep\n");
+ break;
+ case C_SPECIFY2:
+ spec = (command[1] << 8) | command[2];
+ LOGCOMMAND("command specify2 %02x %02x: step_rate=%d ms, head_unload=%d ms, head_load=%d ms, non_dma=%s\n",
+ command[1], command[2], 16-(command[1]>>4), (command[1]&0x0f)<<4, command[2]&0xfe, ((command[2]&1)==1)? "true":"false");
+ main_phase = PHASE_CMD;
+ break;
+ case C_SENSE_DRIVE_STATUS:
+ upd765_family_device::execute_command(cmd);
+ if(!inp_cb.isunset())
+ result[0] = (result[0] & ~ST3_TS) | (inp_cb() ? 0 : 8);
+ break;
+ default:
+ upd765_family_device::execute_command(cmd);
+ break;
+ }
+}
+
+u8 hd63266f_device::extstat_r()
+{
+ return (irq << 6) | motor_state;
+}
+
+// no documentation for motor control so borrow some of 82072
+void hd63266f_device::start_command(int cmd)
+{
+ // check if the command specifies a target drive
+ switch(cmd) {
+ case C_READ_TRACK:
+ case C_WRITE_DATA:
+ case C_READ_DATA:
+ case C_RECALIBRATE:
+ //case C_WRITE_DELETED_DATA:
+ case C_READ_ID:
+ //case C_READ_DELETED_DATA:
+ case C_FORMAT_TRACK:
+ case C_SEEK:
+ // start the motor
+ motor_control(command[1] & 0x3, true);
+ break;
+ default:
+ motor_on_counter = 0;
+ break;
+ }
+
+ // execute the command immediately if there's no motor on delay
+ if(motor_on_counter == 0) {
+ upd765_family_device::start_command(cmd);
+ } else
+ delayed_command = cmd;
+}
+
+void hd63266f_device::motor_control(int fid, bool start_motor)
+{
+ floppy_info &fi = flopi[fid];
+
+ if(start_motor) {
+ // if we are selecting a different drive, stop the motor on the previously selected drive
+ if(selected_drive != fid && flopi[selected_drive].dev && flopi[selected_drive].dev->mon_r() == 0)
+ flopi[selected_drive].dev->mon_w(1);
+
+ // start the motor on the selected drive
+ if(fi.dev && fi.dev->mon_r() == 1) {
+ LOGCOMMAND("motor_control: switching on motor for drive %d\n", fid);
+
+ // select the drive and enable the motor
+ set_ds(fid);
+ fi.dev->mon_w(0);
+ motor_on_counter = 3;
+ motor_state |= 1 << fid;
+ }
+ } else {
+ // motor off timer only applies to the selected drive
+ if(selected_drive != fid)
+ return;
+
+ logerror("motor_on_counter %d\n", motor_on_counter);
+ // decrement motor on counter
+ if(motor_on_counter)
+ motor_on_counter--;
+
+ // execute the command if the motor on counter has expired
+ if(motor_on_counter == 0 && main_phase == PHASE_CMD && delayed_command) {
+ upd765_family_device::start_command(delayed_command);
+
+ delayed_command = 0;
+
+ return;
+ }
+ }
+}
+
+void hd63266f_device::index_callback(floppy_image_device *floppy, int state)
+{
+ if(state) {
+ for(floppy_info &fi : flopi) {
+ if(fi.dev != floppy)
+ continue;
+
+ // update motor on/off counters and stop motor if necessary
+ motor_control(fi.id, false);
+ }
+ }
+ upd765_family_device::index_callback(floppy, state);
+}
+
diff --git a/src/devices/machine/upd765.h b/src/devices/machine/upd765.h
index 0ba8aa6d1c7..3de0f392691 100644
--- a/src/devices/machine/upd765.h
+++ b/src/devices/machine/upd765.h
@@ -48,8 +48,8 @@ public:
void tc_w(bool val);
void ready_w(bool val);
- DECLARE_WRITE_LINE_MEMBER(tc_line_w) { tc_w(state == ASSERT_LINE); }
- DECLARE_WRITE_LINE_MEMBER(reset_w);
+ void tc_line_w(int state) { tc_w(state == ASSERT_LINE); }
+ void reset_w(int state);
void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled
@@ -61,14 +61,10 @@ public:
protected:
upd765_family_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- enum {
- TIMER_DRIVE_READY_POLLING = 4
- };
+ TIMER_CALLBACK_MEMBER(update_floppy);
enum {
PHASE_CMD, PHASE_EXEC, PHASE_RESULT
@@ -244,12 +240,12 @@ protected:
live_info cur_live, checkpoint_live;
devcb_write_line intrq_cb, drq_cb, hdl_cb, idx_cb;
devcb_write8 us_cb;
- bool cur_irq, other_irq, data_irq, drq, internal_drq, tc, tc_done, locked, mfm, scan_done;
+ bool cur_irq, irq, drq, internal_drq, tc, tc_done, locked, mfm, scan_done;
floppy_info flopi[4];
int fifo_pos, fifo_expected, command_pos, result_pos, sectors_read;
bool fifo_write;
- uint8_t dor, dsr, msr, fifo[16], command[16], result[16];
+ uint8_t dor, dsr, fifo[16], command[16], result[16];
uint8_t st1, st2, st3;
uint8_t fifocfg;
uint8_t precomp;
@@ -283,6 +279,9 @@ protected:
C_SCAN_HIGH,
C_MOTOR_ONOFF,
C_VERSION,
+ C_SLEEP,
+ C_ABORT,
+ C_SPECIFY2,
C_INVALID,
C_INCOMPLETE
@@ -290,7 +289,7 @@ protected:
void end_reset();
- void delay_cycles(emu_timer *tm, int cycles);
+ void delay_cycles(floppy_info &fi, int cycles);
void check_irq();
void fifo_expect(int size, bool write);
void fifo_push(uint8_t data, bool internal);
@@ -303,7 +302,7 @@ protected:
void disable_transfer();
int calc_sector_size(uint8_t size);
- void run_drive_ready_polling();
+ TIMER_CALLBACK_MEMBER(run_drive_ready_polling);
virtual int check_command();
virtual void start_command(int cmd);
@@ -351,7 +350,7 @@ protected:
bool write_one_bit(const attotime &limit);
virtual u8 get_drive_busy() const { return 0; }
- virtual void clr_drive_busy() { };
+ virtual void clr_drive_busy() { }
};
class upd765a_device : public upd765_family_device {
@@ -419,8 +418,8 @@ protected:
virtual void execute_command(int cmd) override;
virtual void command_end(floppy_info &fi, bool data_completion) override;
virtual void index_callback(floppy_image_device *floppy, int state) override;
- virtual u8 get_drive_busy() const override { return drive_busy; };
- virtual void clr_drive_busy() override { drive_busy = 0; };
+ virtual u8 get_drive_busy() const override { return drive_busy; }
+ virtual void clr_drive_busy() override { drive_busy = 0; }
void motor_control(int fid, bool start_motor);
@@ -486,6 +485,8 @@ public:
class upd72069_device : public upd72065_device {
public:
upd72069_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void auxcmd_w(uint8_t data) override;
};
class n82077aa_device : public ps2_fdc_device {
@@ -512,6 +513,9 @@ public:
dp8473_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual void map(address_map &map) override;
+
+protected:
+ virtual void soft_reset() override;
};
class pc8477a_device : public ps2_fdc_device {
@@ -526,6 +530,18 @@ public:
virtual void map(address_map &map) override;
};
+class pc8477b_device : public ps2_fdc_device {
+public:
+ pc8477b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, mode_t mode)
+ : pc8477b_device(mconfig, tag, owner, clock)
+ {
+ set_mode(mode);
+ }
+ pc8477b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+};
+
class wd37c65c_device : public upd765_family_device {
public:
wd37c65c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -557,9 +573,6 @@ public:
virtual void map(address_map &map) override;
uint8_t input_r();
-protected:
- virtual void device_start() override;
-
private:
devcb_read8 m_input_handler;
};
@@ -579,6 +592,33 @@ private:
uint8_t m_cr1;
};
+class hd63266f_device : public upd765_family_device {
+public:
+ hd63266f_device(const machine_config &mconfig, const char *tag, device_t* owner, uint32_t clock);
+
+ virtual void map(address_map &map) override;
+ auto inp_rd_callback() { return inp_cb.bind(); } // this is really the ts signal
+
+ void rate_w(u8 state) { state ? set_rate(500000) : set_rate(250000); }
+ void abort_w(u8 data);
+ u8 extstat_r();
+
+protected:
+ virtual void soft_reset() override;
+
+private:
+ virtual int check_command() override;
+ virtual void execute_command(int cmd) override;
+ virtual void start_command(int cmd) override;
+ void motor_control(int fid, bool start_motor);
+ virtual void index_callback(floppy_image_device *floppy, int state) override;
+
+ u8 motor_on_counter;
+ int delayed_command;
+ u8 motor_state;
+ devcb_read_line inp_cb;
+};
+
DECLARE_DEVICE_TYPE(UPD765A, upd765a_device)
DECLARE_DEVICE_TYPE(UPD765B, upd765b_device)
DECLARE_DEVICE_TYPE(I8272A, i8272a_device)
@@ -591,8 +631,10 @@ DECLARE_DEVICE_TYPE(N82077AA, n82077aa_device)
DECLARE_DEVICE_TYPE(PC_FDC_SUPERIO, pc_fdc_superio_device)
DECLARE_DEVICE_TYPE(DP8473, dp8473_device)
DECLARE_DEVICE_TYPE(PC8477A, pc8477a_device)
+DECLARE_DEVICE_TYPE(PC8477B, pc8477b_device)
DECLARE_DEVICE_TYPE(WD37C65C, wd37c65c_device)
DECLARE_DEVICE_TYPE(MCS3201, mcs3201_device)
DECLARE_DEVICE_TYPE(TC8566AF, tc8566af_device)
+DECLARE_DEVICE_TYPE(HD63266F, hd63266f_device)
#endif // MAME_DEVICES_MACHINE_UPD765_H
diff --git a/src/devices/machine/v3021.cpp b/src/devices/machine/v3021.cpp
index 559a617340a..82386e216f7 100644
--- a/src/devices/machine/v3021.cpp
+++ b/src/devices/machine/v3021.cpp
@@ -95,7 +95,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/v3021.h"
+#include "v3021.h"
//**************************************************************************
@@ -153,7 +153,7 @@ void v3021_device::device_validity_check(validity_checker &valid) const
void v3021_device::device_start()
{
/* let's call the timer callback every second */
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(v3021_device::timer_callback), this));
+ m_timer = timer_alloc(FUNC(v3021_device::timer_callback), this);
m_timer->adjust(attotime::from_hz(clock() / XTAL(32'768)), 0, attotime::from_hz(clock() / XTAL(32'768)));
copy_clock_to_ram();
@@ -224,7 +224,7 @@ void v3021_device::write(u8 data)
// cs_w - CS pin handler
//-------------------------------------------------
-WRITE_LINE_MEMBER(v3021_device::cs_w)
+void v3021_device::cs_w(int state)
{
if (m_cs != state)
{
@@ -275,7 +275,7 @@ WRITE_LINE_MEMBER(v3021_device::cs_w)
// io_w - I/O pin write handler
//-------------------------------------------------
-WRITE_LINE_MEMBER(v3021_device::io_w)
+void v3021_device::io_w(int state)
{
m_io = state;
}
@@ -284,7 +284,7 @@ WRITE_LINE_MEMBER(v3021_device::io_w)
// io_r - I/O pin read handler
//-------------------------------------------------
-READ_LINE_MEMBER(v3021_device::io_r)
+int v3021_device::io_r()
{
return m_data & 1;
}
diff --git a/src/devices/machine/v3021.h b/src/devices/machine/v3021.h
index cac5c6884d4..d66e6f29792 100644
--- a/src/devices/machine/v3021.h
+++ b/src/devices/machine/v3021.h
@@ -34,9 +34,9 @@ public:
u8 read();
// serial interface
- DECLARE_WRITE_LINE_MEMBER(cs_w);
- DECLARE_WRITE_LINE_MEMBER(io_w);
- DECLARE_READ_LINE_MEMBER(io_r);
+ void cs_w(int state);
+ void io_w(int state);
+ int io_r();
TIMER_CALLBACK_MEMBER(timer_callback);
diff --git a/src/devices/machine/vic_pl192.cpp b/src/devices/machine/vic_pl192.cpp
index 5c37d03abee..c2c47549556 100644
--- a/src/devices/machine/vic_pl192.cpp
+++ b/src/devices/machine/vic_pl192.cpp
@@ -1,61 +1,122 @@
// license:BSD-3-Clause
-// copyright-holders:Melissa Goad
+// copyright-holders:Devin Acker, Melissa Goad
-// ARM PrimeCell PL192 VIC emulation
+// ARM PrimeCell PL190/PL192 VIC emulation
#include "emu.h"
-#include "machine/bankdev.h"
-#include "machine/vic_pl192.h"
-
-#define LOG_GENERAL (1U << 0)
+#include "vic_pl192.h"
#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
-void vic_pl192_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+DEFINE_DEVICE_TYPE(PL190_VIC, vic_pl190_device, "vic_pl190", "ARM PL190 VIC")
+DEFINE_DEVICE_TYPE(UPD800468_VIC, vic_upd800468_device, "vic_upd800468", "NEC uPD800468 VIC")
+DEFINE_DEVICE_TYPE(PL192_VIC, vic_pl192_device, "vic_pl192", "ARM PL192 VIC")
+
+vic_pl190_device::vic_pl190_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , num_vectors(16)
+ , periph_id{0x92, 0x11, 0x04, 0x00}
+ , pcell_id{0x0d, 0xf0, 0x05, 0xb1}
+ , m_irq_sync_timer(nullptr)
+ , m_mmio_config("mmio", ENDIANNESS_LITTLE, 32, 32, 0)
+ , m_out_irq_func(*this)
+ , m_out_fiq_func(*this)
{
- if(u32 intrs = (raw_intr | soft_intr) & intr_en)
- {
- if(intrs & intr_select) m_out_fiq_func(1);
- else m_out_fiq_func(0);
+}
- if(intrs & ~intr_select) m_out_irq_func(1);
- else m_out_irq_func(0);
- }
+vic_pl190_device::vic_pl190_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : vic_pl190_device(mconfig, PL190_VIC, tag, owner, clock)
+{
}
-void vic_pl192_device::set_irq_line(int irq, int state)
+vic_upd800468_device::vic_upd800468_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : vic_pl190_device(mconfig, UPD800468_VIC, tag, owner, clock)
{
- u32 mask = (1 << irq);
+ num_vectors = 32;
+}
+
+vic_pl192_device::vic_pl192_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : vic_pl190_device(mconfig, PL192_VIC, tag, owner, clock)
+{
+ num_vectors = 32;
+}
+
+void vic_pl190_device::device_start()
+{
+ save_item(NAME(raw_intr));
+ save_item(NAME(intr_select));
+ save_item(NAME(intr_en));
+ save_item(NAME(soft_intr));
+ save_item(NAME(vectaddr));
+ save_item(NAME(defaddress));
+ save_item(NAME(vicaddress));
+ save_item(NAME(priority_mask));
+ save_item(NAME(priority));
+ save_item(NAME(protection));
+
+ m_irq_sync_timer = timer_alloc(FUNC(vic_pl190_device::irq_sync_tick), this);
+}
+
+void vic_pl192_device::device_start()
+{
+ vic_pl190_device::device_start();
+
+ save_item(NAME(sw_priority_mask));
+ save_item(NAME(daisy_priority));
+}
+
+void vic_pl190_device::device_reset()
+{
+ raw_intr = intr_select = intr_en = soft_intr = 0;
+ defaddress = vicaddress = protection = 0;
+
+ priority_mask = ~0;
+ priority = ~0;
- if(state)
+ for(int i = 0; i < 32; i++)
{
- raw_intr |= mask;
+ vectaddr[i] = 0;
+ vectctl[i] = 0;
}
- else
+}
+
+void vic_pl192_device::device_reset()
+{
+ vic_pl190_device::device_reset();
+
+ sw_priority_mask = 0xffff;
+ daisy_priority = 0xf;
+
+ for (int i = 0; i < 32; i++)
{
- raw_intr &= ~mask;
+ vectctl[i] = 0xf;
}
+}
- timer_set(attotime::zero, TIMER_CHECK_IRQ);
+device_memory_interface::space_config_vector vic_pl190_device::memory_space_config() const
+{
+ return space_config_vector{
+ std::make_pair(0, &m_mmio_config)
+ };
}
-void vic_pl192_device::map(address_map &map)
+void vic_pl190_device::map(address_map &map)
{
- map(0x000, 0x003).lr32([this](offs_t offset){ return raw_intr & ~intr_select; }, "irq_status"); //IRQ_STATUS
- map(0x004, 0x007).lr32([this](offs_t offset){ return raw_intr & intr_select; }, "fiq_status"); //FIQ_STATUS
- map(0x008, 0x00b).lr32([this](offs_t offset){ return raw_intr; }, "raw_intr");
- map(0x00c, 0x00f).lrw32(NAME([this](offs_t offset){ return intr_select; }), NAME([this](offs_t offset, u32 data){ intr_select = data; timer_set(attotime::zero, TIMER_CHECK_IRQ); }));
- map(0x010, 0x013).lrw32(NAME([this](offs_t offset){ return intr_en; }), NAME([this](offs_t offset, u32 data){ intr_en = data; timer_set(attotime::zero, TIMER_CHECK_IRQ); }));
- map(0x014, 0x017).lw32([this](u32 data){ intr_en &= ~data; }, "intr_en_clear");
- map(0x018, 0x01b).lrw32(NAME([this](offs_t offset){ return soft_intr; }), NAME([this](offs_t offset, u32 data){ soft_intr = data; timer_set(attotime::zero, TIMER_CHECK_IRQ); }));
- map(0x01c, 0x01f).lw32([this](u32 data){ soft_intr &= ~data; }, "soft_intr_clear");
- map(0x020, 0x020).lrw8(NAME([this](offs_t offset){ return protection; }), NAME([this](offs_t offset, u8 data){ protection = data & 1; })).umask32(0x000000ff);
- map(0x024, 0x025).lrw8(NAME([this](offs_t offset){ return sw_priority_mask; }), NAME([this](offs_t offset, u16 data){ sw_priority_mask = data; })).umask32(0x0000ffff);
- map(0x028, 0x028).lrw8(NAME([this](offs_t offset){ return daisy_priority; }), NAME([this](offs_t offset, u8 data){ daisy_priority = data & 0xf; })).umask32(0x000000ff);
- map(0x100, 0x17f).lrw32(NAME([this](offs_t offset){ return vectaddr[(offset & 0x7c) >> 2]; }), NAME([this](offs_t offset, u32 data){ vectaddr[(offset & 0x7c) >> 2] = data; }));
- map(0x200, 0x27f).lrw8(NAME([this](offs_t offset){ return vectprio[(offset & 0x7c) >> 2]; }), NAME([this](offs_t offset, u32 data){ vectprio[(offset & 0x7c) >> 2] = data & 0xf; }));
- map(0xf00, 0xf03).lrw32(NAME([this](offs_t offset){ return vicaddress; }), NAME([this](offs_t offset, u32 data){ vectaddr[(offset & 0x7c) >> 2] = data; }));
+ map(0x000, 0x003).r(FUNC(vic_pl190_device::irq_status_r));
+ map(0x004, 0x007).r(FUNC(vic_pl190_device::fiq_status_r));
+ map(0x008, 0x00b).r(FUNC(vic_pl190_device::raw_intr_r));
+ map(0x00c, 0x00f).rw(FUNC(vic_pl190_device::int_select_r), FUNC(vic_pl190_device::int_select_w));
+ map(0x010, 0x013).rw(FUNC(vic_pl190_device::int_enable_r), FUNC(vic_pl190_device::int_enable_w));
+ map(0x014, 0x017).w(FUNC(vic_pl190_device::int_en_clear_w));
+ map(0x018, 0x01b).rw(FUNC(vic_pl190_device::soft_int_r), FUNC(vic_pl190_device::soft_int_w));
+ map(0x01c, 0x01f).w(FUNC(vic_pl190_device::soft_int_clear_w));
+ map(0x020, 0x020).rw(FUNC(vic_pl190_device::protection_r), FUNC(vic_pl190_device::protection_w)).umask32(0x000000ff);
+ map(0x030, 0x033).rw(FUNC(vic_pl190_device::cur_vect_addr_r), FUNC(vic_pl190_device::cur_vect_addr_w));
+ map(0x034, 0x037).rw(FUNC(vic_pl190_device::def_vect_addr_r), FUNC(vic_pl190_device::def_vect_addr_w));
+ map(0x100, 0x13f).rw(FUNC(vic_pl190_device::vect_addr_r), FUNC(vic_pl190_device::vect_addr_w));
+ map(0x200, 0x23f).rw(FUNC(vic_pl190_device::vect_ctl_r), FUNC(vic_pl190_device::vect_ctl_w));
map(0xfe0, 0xfe0).lr8([this](offs_t offset){ return periph_id[0]; }, "periph_id0").umask32(0x000000ff);
map(0xfe4, 0xfe4).lr8([this](offs_t offset){ return periph_id[1]; }, "periph_id1").umask32(0x000000ff);
map(0xfe8, 0xfe8).lr8([this](offs_t offset){ return periph_id[2]; }, "periph_id2").umask32(0x000000ff);
@@ -66,65 +127,276 @@ void vic_pl192_device::map(address_map &map)
map(0xffc, 0xffc).lr8([this](offs_t offset){ return pcell_id[3]; }, "pcell_id3").umask32(0x000000ff);
}
-device_memory_interface::space_config_vector vic_pl192_device::memory_space_config() const
+void vic_upd800468_device::map(address_map &map)
{
- return space_config_vector{
- std::make_pair(0, &m_mmio_config)
- };
+ vic_pl190_device::map(map);
+
+ map(0x100, 0x17f).rw(FUNC(vic_pl190_device::vect_addr_r), FUNC(vic_pl190_device::vect_addr_w));
+ map(0x200, 0x27f).rw(FUNC(vic_pl190_device::vect_ctl_r), FUNC(vic_pl190_device::vect_ctl_w));
+ map(0x2c8, 0x2cb).w(FUNC(vic_upd800468_device::int_clear_w));
}
-void vic_pl192_device::device_resolve_objects()
+void vic_pl192_device::map(address_map &map)
{
- // resolve callbacks
- m_out_irq_func.resolve_safe();
- m_out_fiq_func.resolve_safe();
+ map(0x000, 0x003).r(FUNC(vic_pl190_device::irq_status_r));
+ map(0x004, 0x007).r(FUNC(vic_pl190_device::fiq_status_r));
+ map(0x008, 0x00b).r(FUNC(vic_pl190_device::raw_intr_r));
+ map(0x00c, 0x00f).rw(FUNC(vic_pl190_device::int_select_r), FUNC(vic_pl190_device::int_select_w));
+ map(0x010, 0x013).rw(FUNC(vic_pl190_device::int_enable_r), FUNC(vic_pl190_device::int_enable_w));
+ map(0x014, 0x017).w(FUNC(vic_pl190_device::int_en_clear_w));
+ map(0x018, 0x01b).rw(FUNC(vic_pl190_device::soft_int_r), FUNC(vic_pl190_device::soft_int_w));
+ map(0x01c, 0x01f).w(FUNC(vic_pl190_device::soft_int_clear_w));
+ map(0x020, 0x020).rw(FUNC(vic_pl190_device::protection_r), FUNC(vic_pl190_device::protection_w)).umask32(0x000000ff);
+ map(0x024, 0x025).rw(FUNC(vic_pl192_device::sw_priority_r), FUNC(vic_pl192_device::sw_priority_w)).umask32(0x0000ffff);
+ map(0x028, 0x028).rw(FUNC(vic_pl192_device::daisy_priority_r), FUNC(vic_pl192_device::daisy_priority_w)).umask32(0x000000ff);
+ map(0x100, 0x17f).rw(FUNC(vic_pl190_device::vect_addr_r), FUNC(vic_pl190_device::vect_addr_w));
+ map(0x200, 0x27f).rw(FUNC(vic_pl190_device::vect_ctl_r), FUNC(vic_pl190_device::vect_ctl_w));
+ map(0xf00, 0xf03).rw(FUNC(vic_pl190_device::cur_vect_addr_r), FUNC(vic_pl190_device::cur_vect_addr_w));
+ map(0xfe0, 0xfe0).lr8([this](offs_t offset) { return periph_id[0]; }, "periph_id0").umask32(0x000000ff);
+ map(0xfe4, 0xfe4).lr8([this](offs_t offset) { return periph_id[1]; }, "periph_id1").umask32(0x000000ff);
+ map(0xfe8, 0xfe8).lr8([this](offs_t offset) { return periph_id[2]; }, "periph_id2").umask32(0x000000ff);
+ map(0xfec, 0xfec).lr8([this](offs_t offset) { return periph_id[3]; }, "periph_id3").umask32(0x000000ff);
+ map(0xff0, 0xff0).lr8([this](offs_t offset) { return pcell_id[0]; }, "pcell_id0").umask32(0x000000ff);
+ map(0xff4, 0xff4).lr8([this](offs_t offset) { return pcell_id[1]; }, "pcell_id1").umask32(0x000000ff);
+ map(0xff8, 0xff8).lr8([this](offs_t offset) { return pcell_id[2]; }, "pcell_id2").umask32(0x000000ff);
+ map(0xffc, 0xffc).lr8([this](offs_t offset) { return pcell_id[3]; }, "pcell_id3").umask32(0x000000ff);
}
-void vic_pl192_device::device_start()
+TIMER_CALLBACK_MEMBER(vic_pl190_device::irq_sync_tick)
{
- save_item(NAME(raw_intr));
- save_item(NAME(intr_select));
- save_item(NAME(intr_en));
- save_item(NAME(soft_intr));
- save_item(NAME(vectaddr));
- save_item(NAME(vicaddress));
- save_item(NAME(protection));
- save_item(NAME(sw_priority_mask));
- save_item(NAME(daisy_priority));
- save_item(NAME(vectprio));
+ u32 intrs = (raw_intr | soft_intr) & intr_en;
+
+ if (intrs & intr_select)
+ m_out_fiq_func(1);
+ else
+ m_out_fiq_func(0);
+
+ if (intrs & ~intr_select & priority_mask)
+ m_out_irq_func(1);
+ else
+ m_out_irq_func(0);
}
-void vic_pl192_device::device_reset()
+void vic_pl190_device::set_irq_line(int irq, int state)
{
- raw_intr = intr_select = intr_en = soft_intr = vicaddress = protection = 0;
- sw_priority_mask = 0xffff;
- daisy_priority = 0xf;
+ u32 mask = (1 << irq);
- for(int i = 0; i < 32; i++)
- {
- vectaddr[i] = 0;
- }
+ if (state)
+ raw_intr |= mask;
+ else
+ raw_intr &= ~mask;
- for(int i = 0; i < 32; i++)
+
+ m_irq_sync_timer->adjust(attotime::zero);
+}
+
+u32 vic_pl190_device::irq_status_r()
+{
+ return raw_intr & ~intr_select;
+}
+
+u32 vic_pl190_device::fiq_status_r()
+{
+ return raw_intr & intr_select;
+}
+
+u32 vic_pl190_device::raw_intr_r()
+{
+ return raw_intr;
+}
+
+u32 vic_pl190_device::int_select_r()
+{
+ return intr_select;
+}
+
+void vic_pl190_device::int_select_w(u32 data)
+{
+ intr_select = data;
+ m_irq_sync_timer->adjust(attotime::zero);
+}
+
+u32 vic_pl190_device::int_enable_r()
+{
+ return intr_en;
+}
+
+void vic_pl190_device::int_enable_w(u32 data)
+{
+ intr_en |= data;
+ m_irq_sync_timer->adjust(attotime::zero);
+}
+
+void vic_pl190_device::int_en_clear_w(u32 data)
+{
+ intr_en &= ~data;
+ m_irq_sync_timer->adjust(attotime::zero);
+}
+
+u32 vic_pl190_device::soft_int_r()
+{
+ return soft_intr;
+}
+
+void vic_pl190_device::soft_int_w(u32 data)
+{
+ soft_intr |= data;
+ m_irq_sync_timer->adjust(attotime::zero);
+}
+
+void vic_pl190_device::soft_int_clear_w(u32 data)
+{
+ soft_intr &= ~data;
+ m_irq_sync_timer->adjust(attotime::zero);
+}
+
+u8 vic_pl190_device::protection_r()
+{
+ return protection;
+}
+
+void vic_pl190_device::protection_w(u8 data)
+{
+ protection = BIT(data, 0);
+}
+
+u32 vic_pl190_device::cur_vect_addr_r()
+{
+ if (!machine().side_effects_disabled())
+ update_vector();
+
+ return vicaddress;
+}
+
+void vic_pl190_device::cur_vect_addr_w(u32 data)
+{
+ priority_mask = ~0;
+ priority = ~0;
+ m_irq_sync_timer->adjust(attotime::zero);
+}
+
+u32 vic_pl190_device::def_vect_addr_r()
+{
+ return defaddress;
+}
+
+void vic_pl190_device::def_vect_addr_w(u32 data)
+{
+ defaddress = data;
+}
+
+u32 vic_pl190_device::vect_addr_r(offs_t offset)
+{
+ return vectaddr[offset];
+}
+
+void vic_pl190_device::vect_addr_w(offs_t offset, u32 data)
+{
+ vectaddr[offset] = data;
+}
+
+u32 vic_pl190_device::vect_ctl_r(offs_t offset)
+{
+ return vectctl[offset];
+}
+
+void vic_pl190_device::vect_ctl_w(offs_t offset, u32 data)
+{
+ vectctl[offset] = data;
+}
+
+void vic_pl190_device::update_vector()
+{
+ u32 intrs = (raw_intr | soft_intr) & intr_en & ~intr_select;
+ u32 newmask = 0;
+
+ for (u8 i = 0; i < std::min(priority, num_vectors); i++)
{
- vectprio[i] = 0xf;
+ u8 irq = vectctl[i] & 0x1f;
+
+ if (!BIT(vectctl[i], 5))
+ {
+ // vector is disabled
+ continue;
+ }
+ else if (BIT(intrs, irq))
+ {
+ // this interrupt is enabled and pending
+ // take it and update priority_mask to only allow higher priority interrupts
+ priority_mask = newmask;
+ priority = i;
+ vicaddress = vectaddr[i];
+ return;
+ }
+ else
+ {
+ // interrupt isn't pending, but it's higher priority
+ // allow it to be taken later
+ newmask |= (1 << irq);
+ }
}
+
+ // no vectored interrupt taken, use the default
+ priority_mask = ~0;
+ priority = ~0;
+ vicaddress = defaddress;
}
-DEFINE_DEVICE_TYPE(PL192_VIC, vic_pl192_device, "vic_pl192", "ARM PL192 VIC")
+void vic_upd800468_device::int_clear_w(u32 data)
+{
+ raw_intr &= ~data;
+ m_irq_sync_timer->adjust(attotime::zero);
+}
-vic_pl192_device::vic_pl192_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock)
- , device_memory_interface(mconfig, *this)
- , m_mmio_config("mmio", ENDIANNESS_LITTLE, 32, 32, 0)
- , m_out_irq_func(*this)
- , m_out_fiq_func(*this)
- , periph_id{0x92, 0x11, 0x04, 0x00}
- , pcell_id{0x0d, 0xf0, 0x05, 0xb1}
+
+
+
+
+u16 vic_pl192_device::sw_priority_r()
{
+ return sw_priority_mask;
}
-vic_pl192_device::vic_pl192_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : vic_pl192_device(mconfig, PL192_VIC, tag, owner, clock)
+void vic_pl192_device::sw_priority_w(u16 data)
+{
+ sw_priority_mask = data;
+}
+
+u8 vic_pl192_device::daisy_priority_r()
{
+ return daisy_priority;
+}
+
+void vic_pl192_device::daisy_priority_w(u8 data)
+{
+ daisy_priority = data & 0xf;
+}
+
+void vic_pl192_device::update_vector()
+{
+ u32 intrs = (raw_intr | soft_intr) & intr_en & ~intr_select;
+ u32 newmask = 0;
+
+ // see if there's a higher priority active interrupt to take
+ for (u8 i = 0; i < num_vectors; i++)
+ {
+ u8 new_prio = vectctl[i] & 0xf;
+ if (BIT(sw_priority_mask, new_prio) && BIT(intrs, i) && new_prio < priority)
+ {
+ // this interrupt is enabled and pending, take it
+ priority = new_prio;
+ vicaddress = vectaddr[i];
+ }
+ }
+
+ // update priority_mask to only allow higher priority interrupts
+ for (u8 i = 0; i < num_vectors; i++)
+ {
+ u8 new_prio = vectctl[i] & 0xf;
+ if (BIT(sw_priority_mask, new_prio) && new_prio < priority)
+ {
+ newmask |= (1 << i);
+ }
+ }
+ priority_mask = newmask;
}
diff --git a/src/devices/machine/vic_pl192.h b/src/devices/machine/vic_pl192.h
index 9936b369fb6..600ad27ba56 100644
--- a/src/devices/machine/vic_pl192.h
+++ b/src/devices/machine/vic_pl192.h
@@ -1,51 +1,126 @@
// license:BSD-3-Clause
-// copyright-holders:Melissa Goad
+// copyright-holders:Devin Acker, Melissa Goad
-// ARM PrimeCell PL192 VIC emulation
+// ARM PrimeCell PL910/PL192 VIC emulation
#ifndef MAME_MACHINE_VIC_PL192_H
#define MAME_MACHINE_VIC_PL192_H
-class vic_pl192_device : public device_t, public device_memory_interface
+class vic_pl190_device : public device_t, public device_memory_interface
{
public:
- vic_pl192_device(const machine_config &mconfig, const char* tag, device_t *owner, uint32_t clock = 0);
+ vic_pl190_device(const machine_config &mconfig, const char* tag, device_t *owner, uint32_t clock = 0);
auto out_irq_cb() { return m_out_irq_func.bind(); }
auto out_fiq_cb() { return m_out_fiq_func.bind(); }
template<unsigned IRQ>
- DECLARE_WRITE_LINE_MEMBER( irq_w ) { set_irq_line(IRQ, state); }
+ void irq_w(int state) { set_irq_line(IRQ, state); }
void map(address_map &map);
+ u32 irq_status_r();
+ u32 fiq_status_r();
+ u32 raw_intr_r();
+
+ u32 int_select_r();
+ void int_select_w(u32 data);
+
+ u32 int_enable_r();
+ void int_enable_w(u32 data);
+ void int_en_clear_w(u32 data);
+
+ u32 soft_int_r();
+ void soft_int_w(u32 data);
+ void soft_int_clear_w(u32 data);
+
+ u8 protection_r();
+ void protection_w(u8 data);
+
+ u32 cur_vect_addr_r();
+ void cur_vect_addr_w(u32 data);
+
+ u32 def_vect_addr_r();
+ void def_vect_addr_w(u32 data);
+
+ u32 vect_addr_r(offs_t offset);
+ void vect_addr_w(offs_t offset, u32 data);
+
+ u32 vect_ctl_r(offs_t offset);
+ void vect_ctl_w(offs_t offset, u32 data);
+
protected:
- vic_pl192_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+ vic_pl190_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual space_config_vector memory_space_config() const override;
-private:
- static constexpr device_timer_id TIMER_CHECK_IRQ = 0;
+ virtual void update_vector();
+ TIMER_CALLBACK_MEMBER(irq_sync_tick);
+
+ u8 num_vectors; // number of available vectored interrupts
+
+ u32 raw_intr, intr_select, intr_en, soft_intr;
+ u32 vectaddr[32], vectctl[32], defaddress, vicaddress;
+ int protection;
+
+ u32 priority_mask; // mask for interrupts which can take priority over the current one
+ u8 priority; // priority level of the current interrupt, if any
+ u8 periph_id[4], pcell_id[4];
+
+ emu_timer *m_irq_sync_timer;
+
+private:
void set_irq_line(int irq, int state);
address_space_config m_mmio_config;
devcb_write_line m_out_irq_func;
devcb_write_line m_out_fiq_func;
- u32 raw_intr, intr_select, intr_en, soft_intr, vectaddr[32], vicaddress;
- int protection;
+};
+
+class vic_upd800468_device : public vic_pl190_device
+{
+public:
+ vic_upd800468_device(const machine_config &mconfig, const char* tag, device_t *owner, uint32_t clock = 0);
+
+ void map(address_map &map);
+
+ void int_clear_w(u32 data);
+};
+
+class vic_pl192_device : public vic_pl190_device
+{
+public:
+ vic_pl192_device(const machine_config &mconfig, const char* tag, device_t *owner, uint32_t clock = 0);
+
+ void map(address_map &map);
+
+ u16 sw_priority_r();
+ void sw_priority_w(u16 data);
+
+ u8 daisy_priority_r();
+ void daisy_priority_w(u8 data);
+
+protected:
+
+ virtual void update_vector() override;
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
u16 sw_priority_mask;
- u8 daisy_priority, vectprio[32];
- u8 periph_id[4], pcell_id[4];
+ u8 daisy_priority;
};
+DECLARE_DEVICE_TYPE(PL190_VIC, vic_pl190_device)
+DECLARE_DEVICE_TYPE(UPD800468_VIC, vic_upd800468_device)
DECLARE_DEVICE_TYPE(PL192_VIC, vic_pl192_device)
#endif // MAME_MACHINE_VIC_PL192_H
diff --git a/src/devices/machine/vrc4373.cpp b/src/devices/machine/vrc4373.cpp
index d0dbb96e55a..e4105c88ab6 100644
--- a/src/devices/machine/vrc4373.cpp
+++ b/src/devices/machine/vrc4373.cpp
@@ -3,7 +3,6 @@
#include "emu.h"
#include "vrc4373.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_NILE (1U << 1)
#define LOG_NILE_MASTER (1U << 2)
#define LOG_NILE_TARGET (1U << 3)
@@ -117,8 +116,7 @@ void vrc4373_device::device_start()
pci_host_device::device_start();
m_cpu_space = &m_cpu->space(AS_PCI_CONFIG);
- memory_space = &space(AS_PCI_MEM);
- io_space = &space(AS_PCI_IO);
+ set_spaces(&space(AS_PCI_MEM), &space(AS_PCI_IO));
is_multifunction_device = false;
std::fill(std::begin(m_cpu_regs), std::end(m_cpu_regs), 0);
@@ -131,8 +129,6 @@ void vrc4373_device::device_start()
io_offset = 0x00000000;
status = 0x0280;
- m_irq_cb.resolve();
-
// Reserve 8M for ram
m_ram.reserve(0x00800000 / 4);
m_ram.resize(m_ram_size);
@@ -151,7 +147,7 @@ void vrc4373_device::device_start()
m_cpu->add_fastram(0x1fc00000, 0x1fcfffff, true, m_romRegion->base());
// DMA timer
- m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vrc4373_device::dma_transfer), this));
+ m_dma_timer = timer_alloc(FUNC(vrc4373_device::dma_transfer), this);
// Leave the timer disabled.
m_dma_timer->adjust(attotime::never, 0, DMA_TIMER_PERIOD);
@@ -417,7 +413,7 @@ TIMER_CALLBACK_MEMBER (vrc4373_device::dma_transfer)
m_cpu_regs[NREG_DMACR1 + which * 0xc] &= ~DMA_GO;
// Set the interrupt
if (m_cpu_regs[NREG_DMACR1 + which * 0xc] & DMA_INT_EN) {
- if (!m_irq_cb.isnull()) {
+ if (!m_irq_cb.isunset()) {
m_irq_cb(ASSERT_LINE);
} else {
logerror("vrc4373_device::dma_transfer Error: DMA configured to trigger interrupt but no interrupt line configured\n");
@@ -524,7 +520,7 @@ void vrc4373_device::cpu_if_w(offs_t offset, uint32_t data, uint32_t mem_mask)
case NREG_ICSR:
// TODO: Check and clear individual interrupts
if (data & 0xff000000) {
- if (!m_irq_cb.isnull())
+ if (!m_irq_cb.isunset())
m_irq_cb(CLEAR_LINE);
}
break;
diff --git a/src/devices/machine/vrc4373.h b/src/devices/machine/vrc4373.h
index 7d47d572940..7717a979e23 100644
--- a/src/devices/machine/vrc4373.h
+++ b/src/devices/machine/vrc4373.h
@@ -28,8 +28,8 @@ public:
auto irq_cb() { return m_irq_cb.bind(); }
template <typename T> void set_cpu_tag(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
- void set_ram_size(int size) { m_ram_size = size; };
- void set_simm0_size(int size) { m_simm0_size = size; };
+ void set_ram_size(int size) { m_ram_size = size; }
+ void set_simm0_size(int size) { m_simm0_size = size; }
virtual void config_map(address_map &map) override;
diff --git a/src/devices/machine/vrc5074.cpp b/src/devices/machine/vrc5074.cpp
index a2e1c0ea061..2bddcaa54a9 100644
--- a/src/devices/machine/vrc5074.cpp
+++ b/src/devices/machine/vrc5074.cpp
@@ -3,14 +3,21 @@
#include "emu.h"
#include "vrc5074.h"
-#define LOG_NILE (0)
-#define LOG_NILE_IRQS (0)
-#define LOG_PCI (0)
-#define LOG_TIMERS (0)
-#define LOG_MAP (0)
-#define LOG_NILE_MASTER (0)
-#define LOG_NILE_TARGET (0)
-#define PRINTF_SERIAL (0)
+#define LOG_NILE (1U << 1)
+#define LOG_NILE_IRQS (1U << 2)
+#define LOG_TIMERS (1U << 3)
+#define LOG_MAP (1U << 4)
+#define LOG_NILE_MASTER (1U << 5)
+#define LOG_NILE_TARGET (1U << 6)
+#define LOG_SERIAL_READS (1U << 7)
+#define LOG_SERIAL_WRITES (1U << 8)
+#define LOG_SERIAL_DATA (1U << 9)
+#define LOG_SDRAM (1U << 10)
+#define LOG_ERRORS (1U << 11)
+#define LOG_UNKNOWNS (1U << 12)
+#define LOG_DMACTRL (1U << 13)
+#define VERBOSE (0)
+#include "logmacro.h"
/* NILE 4 registers 0x000-0x0ff */
#define NREG_SDRAM0 (0x000/4)
@@ -196,8 +203,7 @@ void vrc5074_device::device_start()
{
pci_host_device::device_start();
m_cpu_space = &m_cpu->space(AS_PROGRAM);
- memory_space = &space(AS_DATA);
- io_space = &space(AS_IO);
+ set_spaces(&space(AS_DATA), &space(AS_IO));
memory_window_start = 0;
memory_window_end = 0xffffffff;
@@ -216,8 +222,7 @@ void vrc5074_device::device_start()
if (m_updateRegion) {
romSize = m_updateRegion->bytes();
m_cpu_space->install_rom(0x1fd00000, 0x1fd00000 + romSize - 1, m_updateRegion->base());
- if (LOG_NILE)
- logerror("%s: vrc5074_device::device_start UPDATE Mapped size: 0x%08X start: 0x1fd00000 end: %08X\n", tag(), romSize, 0x1fd00000 + romSize - 1);
+ LOGMASKED(LOG_NILE, "%s: vrc5074_device::device_start UPDATE Mapped size: 0x%08X start: 0x1fd00000 end: %08X\n", tag(), romSize, 0x1fd00000 + romSize - 1);
}
// Nile cpu register mapppings
m_cpu_space->install_device(0x1fa00000, 0x1fa001ff, *static_cast<vrc5074_device *>(this), &vrc5074_device::cpu_map);
@@ -230,14 +235,14 @@ void vrc5074_device::device_start()
m_cpu->add_fastram(0x1fc00000, 0x1fcfffff, true, m_romRegion->base());
// DMA timer
- m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vrc5074_device::dma_transfer), this));
+ m_dma_timer = timer_alloc(FUNC(vrc5074_device::dma_transfer), this);
// Leave the timer disabled.
m_dma_timer->adjust(attotime::never, 0, DMA_TIMER_PERIOD);
/* allocate timers for the NILE */
m_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate());
m_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate());
- m_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vrc5074_device::nile_timer_callback), this));
- m_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vrc5074_device::nile_timer_callback), this));
+ m_timer[2] = timer_alloc(FUNC(vrc5074_device::nile_timer_callback), this);
+ m_timer[3] = timer_alloc(FUNC(vrc5074_device::nile_timer_callback), this);
// Save states
// m_sdram
@@ -300,8 +305,7 @@ void vrc5074_device::map_cpu_space()
m_cpu_space->install_ram(winStart, winStart + winSize - 1, m_sdram[index].data());
m_cpu->add_fastram(winStart, winStart + winSize - 1, false, m_sdram[index].data());
}
- if (LOG_NILE | LOG_MAP)
- logerror("map_cpu_space ram_size=%08X ram_base=%08X\n", winSize, winStart);
+ LOGMASKED(LOG_NILE | LOG_MAP, "map_cpu_space ram_size=%08X ram_base=%08X\n", winSize, winStart);
}
}
@@ -317,8 +321,7 @@ void vrc5074_device::map_cpu_space()
if (winSize > 0 && m_cs_devices[index - 2] != nullptr) {
m_cpu_space->install_device_delegate(winStart, winStart + winSize - 1, *m_cs_devices[index - 2], m_cs_maps[index - 2]);
}
- if (LOG_NILE | LOG_MAP)
- logerror("map_cpu_space cs%d_size=%08X cs%d_base=%08X\n", index, winSize, index, winStart);
+ LOGMASKED(LOG_NILE | LOG_MAP, "map_cpu_space cs%d_size=%08X cs%d_base=%08X\n", index, winSize, index, winStart);
}
}
@@ -341,8 +344,7 @@ void vrc5074_device::map_cpu_space()
m_cpu_space->install_write_handler(winStart, winStart + winSize - 1, write32s_delegate(*this, FUNC(vrc5074_device::pci1_w)));
}
}
- if (LOG_NILE | LOG_MAP)
- logerror("map_cpu_space pci%d_size=%08X pci%d_base=%08X\n", index, winSize, index, winStart);
+ LOGMASKED(LOG_NILE | LOG_MAP, "map_cpu_space pci%d_size=%08X pci%d_base=%08X\n", index, winSize, index, winStart);
}
}
}
@@ -364,8 +366,7 @@ void vrc5074_device::map_extra(uint64_t memory_window_start, uint64_t memory_win
winEnd = winStart + winSize -1;
memory_space->install_read_handler(winStart, winEnd, read32s_delegate(*this, FUNC(vrc5074_device::target1_r)));
memory_space->install_write_handler(winStart, winEnd, write32s_delegate(*this, FUNC(vrc5074_device::target1_w)));
- if (LOG_NILE | LOG_MAP)
- logerror("%s: map_extra Target Window 1 start=%08X end=%08X size=%08X\n", tag(), winStart, winEnd, winSize);
+ LOGMASKED(LOG_NILE | LOG_MAP, "%s: map_extra Target Window 1 start=%08X end=%08X size=%08X\n", tag(), winStart, winEnd, winSize);
}
//// PCI Target Window 2
//if (m_cpu_regs[NREG_PCITW2]&0x1000) {
@@ -374,8 +375,7 @@ void vrc5074_device::map_extra(uint64_t memory_window_start, uint64_t memory_win
// winSize = winEnd - winStart + 1;
// memory_space->install_read_handler(winStart, winEnd, read32s_delegate(*this, FUNC(vrc5074_device::target2_r)));
// memory_space->install_write_handler(winStart, winEnd, write32s_delegate(*this, FUNC(vrc5074_device::target2_w)));
- // if (LOG_NILE)
- // logerror("%s: map_extra Target Window 2 start=%08X end=%08X size=%08X laddr=%08X\n", tag(), winStart, winEnd, winSize, m_target2_laddr);
+ // LOGMASKED(LOG_NILE, "%s: map_extra Target Window 2 start=%08X end=%08X size=%08X laddr=%08X\n", tag(), winStart, winEnd, winSize, m_target2_laddr);
//}
}
@@ -395,7 +395,7 @@ void vrc5074_device::sdram_addr_w(offs_t offset, uint32_t data, uint32_t mem_mas
m_sdram_addr[0] = data;
else if (offset == 2)
m_sdram_addr[1] = data;
- logerror("sdram_addr_w: offset: %08X data: %08X mem_mask: %08X\n", offset*4, data, mem_mask);
+ LOGMASKED(LOG_SDRAM, "sdram_addr_w: offset: %08X data: %08X mem_mask: %08X\n", offset*4, data, mem_mask);
}
void vrc5074_device::setup_pci_space()
@@ -405,9 +405,8 @@ void vrc5074_device::setup_pci_space()
m_pci_mask[index] = (1 << (36 - mask)) - 1;
m_pci_laddr[index] = m_cpu_regs[NREG_PCIINIT0 + index * 2] & (~m_pci_mask[index]);
m_pci_type[index] = m_cpu_regs[NREG_PCIINIT0 + index * 2] & 0xe;
- if (1 && LOG_NILE)
- logerror("setup_pci_space: mask_sel=%x pci_type=%x pci_mask[%d]=%08X pci_laddr[%d]=%08X\n",
- mask, m_pci_type[index], index, m_pci_mask[index], index, m_pci_laddr[index]);
+ LOGMASKED(LOG_NILE, "setup_pci_space: mask_sel=%x pci_type=%x pci_mask[%d]=%08X pci_laddr[%d]=%08X\n",
+ mask, m_pci_type[index], index, m_pci_mask[index], index, m_pci_laddr[index]);
}
}
// PCI Master Window 0
@@ -442,11 +441,10 @@ uint32_t vrc5074_device::pci0_r(offs_t offset, uint32_t mem_mask)
}
break;
default:
- logerror("Unknown PCI type\n");
+ LOGMASKED(LOG_UNKNOWNS, "Unknown PCI type\n");
break;
}
- if (LOG_NILE_MASTER)
- logerror("%s nile pci0_r offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, result, mem_mask);
+ LOGMASKED(LOG_NILE_MASTER, "%s nile pci0_r offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, result, mem_mask);
return result;
}
void vrc5074_device::pci0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -480,12 +478,11 @@ void vrc5074_device::pci0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
}
break;
default:
- logerror("Unknown PCI type\n");
+ LOGMASKED(LOG_UNKNOWNS, "Unknown PCI type\n");
break;
}
//this->space(AS_DATA).write_dword(m_pci0_laddr | (offset*4), data, mem_mask);
- if (LOG_NILE_MASTER)
- logerror("%s nile pci0_w offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, data, mem_mask);
+ LOGMASKED(LOG_NILE_MASTER, "%s nile pci0_w offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, data, mem_mask);
}
// PCI Master Window 1
@@ -520,11 +517,10 @@ uint32_t vrc5074_device::pci1_r(offs_t offset, uint32_t mem_mask)
}
break;
default:
- logerror("Unknown PCI type\n");
+ LOGMASKED(LOG_UNKNOWNS, "Unknown PCI type\n");
break;
}
- if (LOG_NILE_MASTER)
- logerror("%s nile pci1_r offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, result, mem_mask);
+ LOGMASKED(LOG_NILE_MASTER, "%s nile pci1_r offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, result, mem_mask);
return result;
}
void vrc5074_device::pci1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -557,20 +553,18 @@ void vrc5074_device::pci1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
}
break;
default:
- logerror("Unknown PCI type\n");
+ LOGMASKED(LOG_UNKNOWNS, "Unknown PCI type\n");
break;
}
//this->space(AS_DATA).write_dword(m_pci0_laddr | (offset*4), data, mem_mask);
- if (LOG_NILE_MASTER)
- logerror("%s nile pci1_w offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, data, mem_mask);
+ LOGMASKED(LOG_NILE_MASTER, "%s nile pci1_w offset %08X = %08X & %08X\n", machine().describe_context(), pci_addr, data, mem_mask);
}
// PCI Target Window 1
uint32_t vrc5074_device::target1_r(offs_t offset, uint32_t mem_mask)
{
uint32_t result = m_sdram[0][offset];
- if (LOG_NILE_TARGET)
- logerror("%s nile target1 read from offset %02X = %08X & %08X\n", machine().describe_context(), offset*4, result, mem_mask);
+ LOGMASKED(LOG_NILE_TARGET, "%s nile target1 read from offset %02X = %08X & %08X\n", machine().describe_context(), offset*4, result, mem_mask);
return result;
}
void vrc5074_device::target1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -578,8 +572,7 @@ void vrc5074_device::target1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
//m_cpu->space(AS_PROGRAM).write_dword(m_target1_laddr | (offset*4), data, mem_mask);
COMBINE_DATA(&m_sdram[0][offset]);
//m_sdram[0][offset] = data;
- if (LOG_NILE_TARGET)
- logerror("%s nile target1 write to offset %02X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask);
+ LOGMASKED(LOG_NILE_TARGET, "%s nile target1 write to offset %02X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask);
}
// DMA Transfer
@@ -589,8 +582,7 @@ TIMER_CALLBACK_MEMBER (vrc5074_device::dma_transfer)
//// Check for dma suspension
//if (m_cpu_regs[NREG_DMACR1 + which * 0xc] & DMA_SUS) {
- // if (LOG_NILE)
- // logerror("%s nile DMA Suspended PCI: %08X MEM: %08X Words: %X\n", machine().describe_context(), m_cpu_regs[NREG_DMA_CPAR], m_cpu_regs[NREG_DMA_CMAR], m_cpu_regs[NREG_DMA_REM]);
+ // LOGMASKED(LOG_NILE, "%s nile DMA Suspended PCI: %08X MEM: %08X Words: %X\n", machine().describe_context(), m_cpu_regs[NREG_DMA_CPAR], m_cpu_regs[NREG_DMA_CMAR], m_cpu_regs[NREG_DMA_REM]);
// return;
//}
@@ -638,7 +630,7 @@ TIMER_CALLBACK_MEMBER (vrc5074_device::dma_transfer)
// if (m_irq_num != -1) {
// m_cpu->set_input_line(m_irq_num, ASSERT_LINE);
// } else {
- // logerror("vrc5074_device::dma_transfer Error: DMA configured to trigger interrupt but no interrupt line configured\n");
+ // LOGMASKED(LOG_ERRORS, "vrc5074_device::dma_transfer Error: DMA configured to trigger interrupt but no interrupt line configured\n");
// }
// }
// // Turn off the timer
@@ -651,19 +643,19 @@ TIMER_CALLBACK_MEMBER (vrc5074_device::dma_transfer)
* nile timers & interrupts
*
*************************************/
-WRITE_LINE_MEMBER(vrc5074_device::pci_intr_a) {
+void vrc5074_device::pci_intr_a(int state) {
update_pci_irq(0, state);
}
-WRITE_LINE_MEMBER(vrc5074_device::pci_intr_b) {
+void vrc5074_device::pci_intr_b(int state) {
update_pci_irq(1, state);
}
-WRITE_LINE_MEMBER(vrc5074_device::pci_intr_c) {
+void vrc5074_device::pci_intr_c(int state) {
update_pci_irq(2, state);
}
-WRITE_LINE_MEMBER(vrc5074_device::pci_intr_d) {
+void vrc5074_device::pci_intr_d(int state) {
update_pci_irq(3, state);
}
-WRITE_LINE_MEMBER(vrc5074_device::pci_intr_e) {
+void vrc5074_device::pci_intr_e(int state) {
update_pci_irq(4, state);
}
@@ -671,8 +663,7 @@ void vrc5074_device::update_pci_irq(const int index, const int state)
{
m_nile_irq_state &= ~(1 << (index + 8));
m_nile_irq_state |= state << (index + 8);
- if (LOG_NILE_IRQS)
- logerror("update_pci_irq: m_nile_irq_state: %04x index=%d state=%d\n", m_nile_irq_state, index, state);
+ LOGMASKED(LOG_NILE_IRQS, "update_pci_irq: m_nile_irq_state: %04x index=%d state=%d\n", m_nile_irq_state, index, state);
update_nile_irqs();
}
@@ -722,10 +713,10 @@ void vrc5074_device::update_nile_irqs()
/* push out the state */
uint8_t change = m_irq_pins ^ irq;
- if (LOG_NILE_IRQS) logerror("NILE IRQs:");
+ LOGMASKED(LOG_NILE_IRQS, "NILE IRQs:");
for (i = 0; i < 6; i++)
{
- if (LOG_NILE_IRQS) logerror(" %d", (irq & (1 << i)) ? 1 : 0);
+ LOGMASKED(LOG_NILE_IRQS, " %d", (irq & (1 << i)) ? 1 : 0);
if (change & (1 << i)) {
if (irq & (1 << i))
{
@@ -738,7 +729,7 @@ void vrc5074_device::update_nile_irqs()
}
}
m_irq_pins = irq;
- if (LOG_NILE_IRQS) logerror("\n");
+ LOGMASKED(LOG_NILE_IRQS, "\n");
}
@@ -746,7 +737,7 @@ TIMER_CALLBACK_MEMBER(vrc5074_device::nile_timer_callback)
{
int which = param;
- if (LOG_TIMERS | LOG_NILE_IRQS) logerror("timer %d fired period: %e\n", which, m_timer_period[which]);
+ LOGMASKED(LOG_TIMERS | LOG_NILE_IRQS, "timer %d fired period: %e\n", which, m_timer_period[which]);
/* adjust the timer to fire again */
{
@@ -780,38 +771,38 @@ uint32_t vrc5074_device::cpu_reg_r(offs_t offset)
{
case NREG_CPUSTAT + 0: /* CPU status */
case NREG_CPUSTAT + 1: /* CPU status */
- if (LOG_NILE) logerror("%s NILE READ: CPU status(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
+ LOGMASKED(LOG_NILE, "%s NILE READ: CPU status(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
logit = 0;
break;
case NREG_INTCTRL + 0: /* Interrupt control */
case NREG_INTCTRL + 1: /* Interrupt control */
- if (LOG_NILE) logerror("%s NILE READ: interrupt control(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
+ LOGMASKED(LOG_NILE, "%s NILE READ: interrupt control(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
//update_nile_irqs();
logit = 0;
break;
case NREG_INTSTAT0 + 0: /* Interrupt status 0 */
case NREG_INTSTAT0 + 1: /* Interrupt status 0 */
- if (LOG_NILE | LOG_NILE_IRQS) logerror("%s NILE READ: interrupt status 0(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
+ LOGMASKED(LOG_NILE | LOG_NILE_IRQS, "%s NILE READ: interrupt status 0(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
logit = 0;
break;
case NREG_INTSTAT1 + 0: /* Interrupt status 1 */
case NREG_INTSTAT1 + 1: /* Interrupt status 1 */
- if (LOG_NILE | LOG_NILE_IRQS) logerror("%s NILE READ: interrupt status 1/enable(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
+ LOGMASKED(LOG_NILE | LOG_NILE_IRQS, "%s NILE READ: interrupt status 1/enable(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
logit = 0;
break;
case NREG_INTCLR + 0: /* Interrupt clear */
case NREG_INTCLR + 1: /* Interrupt clear */
- if (LOG_NILE) logerror("%s NILE READ: interrupt clear(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
+ LOGMASKED(LOG_NILE, "%s NILE READ: interrupt clear(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
logit = 0;
break;
case NREG_INTPPES + 0: /* PCI Interrupt control */
case NREG_INTPPES + 1: /* PCI Interrupt control */
- if (LOG_NILE) logerror("%s NILE READ: PCI interrupt ppes(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
+ LOGMASKED(LOG_NILE, "%s NILE READ: PCI interrupt ppes(%03X) = %08X\n", machine().describe_context(), offset * 4, result);
logit = 0;
break;
@@ -837,12 +828,12 @@ uint32_t vrc5074_device::cpu_reg_r(offs_t offset)
result = m_cpu_regs[offset] = m_timer[which]->remaining().as_double() * clock();
}
- if (LOG_TIMERS) logerror("%s NILE READ: timer %d counter(%03X) = %08X\n", machine().describe_context(), which, offset * 4, result);
+ LOGMASKED(LOG_TIMERS, "%s NILE READ: timer %d counter(%03X) = %08X\n", machine().describe_context(), which, offset * 4, result);
logit = 0;
break;
}
- if (LOG_NILE && logit)
- logerror("%s cpu_reg_r offset %03X = %08X\n", machine().describe_context(), offset * 4, result);
+ if (logit)
+ LOGMASKED(LOG_NILE, "%s cpu_reg_r offset %03X = %08X\n", machine().describe_context(), offset * 4, result);
return result;
}
@@ -885,34 +876,34 @@ void vrc5074_device::cpu_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
if (data & 0x2) logerror("cpu_reg_w: CPU Warm Reset\n");
[[fallthrough]];
case NREG_CPUSTAT + 1: /* CPU status */
- if (LOG_NILE) logerror("%s NILE WRITE: CPU status(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ LOGMASKED(LOG_NILE, "%s NILE WRITE: CPU status(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
logit = 0;
break;
case NREG_INTCTRL + 0: /* Interrupt control */
case NREG_INTCTRL + 1: /* Interrupt control */
- if (LOG_NILE | LOG_NILE_IRQS) logerror("%s NILE WRITE: interrupt control(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ LOGMASKED(LOG_NILE | LOG_NILE_IRQS, "%s NILE WRITE: interrupt control(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
logit = 0;
update_nile_irqs();
break;
case NREG_INTSTAT0 + 0: /* Interrupt status 0 */
case NREG_INTSTAT0 + 1: /* Interrupt status 0 */
- if (LOG_NILE | LOG_NILE_IRQS) logerror("%s NILE WRITE: interrupt status 0/1(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ LOGMASKED(LOG_NILE | LOG_NILE_IRQS, "%s NILE WRITE: interrupt status 0/1(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
logit = 0;
//update_nile_irqs();
break;
case NREG_INTSTAT1 + 0: /* Interrupt status 1 */
case NREG_INTSTAT1 + 1: /* Interrupt status 1 */
- if (LOG_NILE | LOG_NILE_IRQS) logerror("%s NILE WRITE: interrupt status 0/1 enable(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ LOGMASKED(LOG_NILE | LOG_NILE_IRQS, "%s NILE WRITE: interrupt status 0/1 enable(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
logit = 0;
//update_nile_irqs();
break;
case NREG_INTCLR + 0: /* Interrupt clear */
//case NREG_INTCLR + 1: /* Interrupt clear */
- if (LOG_NILE | LOG_NILE_IRQS) logerror("%s NILE WRITE: interrupt clear(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ LOGMASKED(LOG_NILE | LOG_NILE_IRQS, "%s NILE WRITE: interrupt clear(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
logit = 0;
// Only edge triggered interrupts are cleared
// TODO: Check which are edge triggered for midway vegas it is only the lower (non-pci) interrupts
@@ -922,7 +913,7 @@ void vrc5074_device::cpu_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
case NREG_INTPPES + 0: /* PCI Interrupt control */
case NREG_INTPPES + 1: /* PCI Interrupt control */
- if (LOG_NILE) logerror("%s NILE WRITE: PCI interrupt ppes(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ LOGMASKED(LOG_NILE, "%s NILE WRITE: PCI interrupt ppes(%03X) = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
logit = 0;
break;
@@ -946,7 +937,7 @@ void vrc5074_device::cpu_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
case NREG_DMACTRL0:
case NREG_DMACTRL1:
which = (offset - NREG_DMACTRL0) / 6;
- logerror("%s NILE WRITE: DMACTRL %d = %08X\n", machine().describe_context(), which, data);
+ LOGMASKED(LOG_DMACTRL, "%s NILE WRITE: DMACTRL %d = %08X\n", machine().describe_context(), which, data);
logit = 0;
break;
case NREG_T0CTRL + 1: /* SDRAM timer control (control bits) */
@@ -954,20 +945,20 @@ void vrc5074_device::cpu_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
case NREG_T2CTRL + 1: /* general purpose timer control (control bits) */
case NREG_T3CTRL + 1: /* watchdog timer control (control bits) */
which = (offset - NREG_T0CTRL) / 4;
- if (LOG_NILE | LOG_TIMERS) logerror("%s NILE WRITE: timer %d control(%03X) = %08X & %08X\n", machine().describe_context(), which, offset * 4, data, mem_mask);
+ LOGMASKED(LOG_NILE | LOG_TIMERS, "%s NILE WRITE: timer %d control(%03X) = %08X & %08X\n", machine().describe_context(), which, offset * 4, data, mem_mask);
logit = 0;
m_timer_period[which] = (uint64_t(m_cpu_regs[NREG_T0CTRL + which * 4]) + 1) * attotime::from_hz(clock()).as_double();
if (m_cpu_regs[offset] & 2) {
// Cascade timer
uint32_t scaleSrc = (m_cpu_regs[offset] >> 2) & 0x3;
m_timer_period[which] += (uint64_t(m_cpu_regs[NREG_T0CTRL + scaleSrc * 4]) + 1) * attotime::from_hz(clock()).as_double();
- logerror("Timer scale: timer %d is scaled by %08X\n", which, m_cpu_regs[NREG_T0CTRL + which * 4]);
+ LOGMASKED(LOG_TIMERS, "Timer scale: timer %d is scaled by %08X\n", which, m_cpu_regs[NREG_T0CTRL + which * 4]);
}
/* timer just enabled? */
if (!(olddata & 1) && (m_cpu_regs[offset] & 1))
{
m_timer[which]->adjust(attotime::from_hz(clock()) * m_cpu_regs[NREG_T0CNTR + which * 4], which);
- if (LOG_TIMERS) logerror("Starting timer %d at a rate of %f Hz\n", which, attotime::from_double(m_timer_period[which]).as_hz());
+ LOGMASKED(LOG_TIMERS, "Starting timer %d at a rate of %f Hz\n", which, attotime::from_double(m_timer_period[which]).as_hz());
}
/* timer disabled? */
@@ -983,7 +974,7 @@ void vrc5074_device::cpu_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
case NREG_T2CNTR: /* general purpose timer control (counter) */
case NREG_T3CNTR: /* watchdog timer control (counter) */
which = (offset - NREG_T0CNTR) / 4;
- if (LOG_TIMERS) logerror("%s NILE WRITE: timer %d counter(%03X) = %08X & %08X\n", machine().describe_context(), which, offset * 4, data, mem_mask);
+ LOGMASKED(LOG_TIMERS, "%s NILE WRITE: timer %d counter(%03X) = %08X & %08X\n", machine().describe_context(), which, offset * 4, data, mem_mask);
logit = 0;
if (m_cpu_regs[offset - 1] & 1)
@@ -993,17 +984,16 @@ void vrc5074_device::cpu_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
break;
}
- if (LOG_NILE && logit)
- logerror("%s cpu_reg_w offset %03X = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
+ if (logit)
+ LOGMASKED(LOG_NILE, "%s cpu_reg_w offset %03X = %08X & %08X\n", machine().describe_context(), offset * 4, data, mem_mask);
}
-WRITE_LINE_MEMBER(vrc5074_device::uart_irq_callback)
+void vrc5074_device::uart_irq_callback(int state)
{
if (state ^ m_uart_irq) {
m_uart_irq = state;
update_nile_irqs();
- if (LOG_NILE | LOG_NILE_IRQS)
- logerror("uart_irq_callback: state = %d\n", state);
+ LOGMASKED(LOG_NILE_IRQS, "uart_irq_callback: state = %d\n", state);
}
}
@@ -1011,17 +1001,16 @@ uint32_t vrc5074_device::serial_r(offs_t offset)
{
uint32_t result = m_uart->ins8250_r(offset>>1);
- if (0 && LOG_NILE)
- logerror("%s serial_r offset %03X = %08X (%08x)\n", machine().describe_context(), offset>>1, result, offset*4);
+ LOGMASKED(LOG_SERIAL_READS, "%s serial_r offset %03X = %08X (%08x)\n", machine().describe_context(), offset>>1, result, offset*4);
return result;
}
void vrc5074_device::serial_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
m_uart->ins8250_w(offset>>1, data);
- if (PRINTF_SERIAL && offset == NREG_UARTTHR) {
+ if ((VERBOSE & LOG_SERIAL_DATA) && offset == NREG_UARTTHR) {
static std::string debugStr;
- printf("%c", data);
+ logerror("%c", data);
if (data == 0xd || debugStr.length()>=80) {
logerror("%s", debugStr.c_str());
debugStr.clear();
@@ -1030,6 +1019,5 @@ void vrc5074_device::serial_w(offs_t offset, uint32_t data, uint32_t mem_mask)
debugStr += char(data);
}
}
- if (0 && LOG_NILE)
- logerror("%s serial_w offset %03X = %08X & %08X (%08x)\n", machine().describe_context(), offset>>1, data, mem_mask, offset*4);
+ LOGMASKED(LOG_SERIAL_WRITES, "%s serial_w offset %03X = %08X & %08X (%08x)\n", machine().describe_context(), offset>>1, data, mem_mask, offset*4);
}
diff --git a/src/devices/machine/vrc5074.h b/src/devices/machine/vrc5074.h
index 02bafd8d73d..1bcbf68ab2f 100644
--- a/src/devices/machine/vrc5074.h
+++ b/src/devices/machine/vrc5074.h
@@ -31,7 +31,7 @@ public:
virtual void device_post_load() override;
template <typename T> void set_cpu_tag(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
- void set_sdram_size(int index, int size) { m_sdram_size[index] = size; };
+ void set_sdram_size(int index, int size) { m_sdram_size[index] = size; }
void set_map(int id, const address_map_constructor &map, device_t *device);
@@ -40,11 +40,11 @@ public:
void sdram_addr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
// PCI interrupts
- DECLARE_WRITE_LINE_MEMBER(pci_intr_a);
- DECLARE_WRITE_LINE_MEMBER(pci_intr_b);
- DECLARE_WRITE_LINE_MEMBER(pci_intr_c);
- DECLARE_WRITE_LINE_MEMBER(pci_intr_d);
- DECLARE_WRITE_LINE_MEMBER(pci_intr_e);
+ void pci_intr_a(int state);
+ void pci_intr_b(int state);
+ void pci_intr_c(int state);
+ void pci_intr_d(int state);
+ void pci_intr_e(int state);
void update_pci_irq(const int index, const int state);
//cpu bus registers
@@ -65,7 +65,7 @@ public:
void target1_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
// Serial port
- DECLARE_WRITE_LINE_MEMBER(uart_irq_callback);
+ void uart_irq_callback(int state);
protected:
address_space *m_cpu_space;
diff --git a/src/devices/machine/vrender0.cpp b/src/devices/machine/vrender0.cpp
index c97a40a5736..81ffdea1af0 100644
--- a/src/devices/machine/vrender0.cpp
+++ b/src/devices/machine/vrender0.cpp
@@ -130,10 +130,8 @@ void vrender0soc_device::device_add_mconfig(machine_config &config)
m_screen->screen_vblank().set(FUNC(vrender0soc_device::screen_vblank));
m_screen->set_palette(m_palette);
- VIDEO_VRENDER0(config, m_vr0vid, 14318180);
-#ifdef IDLE_LOOP_SPEEDUP
- m_vr0vid->idleskip_cb().set(FUNC(vrender0soc_device::idle_skip_speedup_w));
-#endif
+ // runs at double speed wrt of the CPU clock
+ VIDEO_VRENDER0(config, m_vr0vid, DERIVED_CLOCK(2, 1));
PALETTE(config, m_palette, palette_device::RGB_565);
@@ -164,10 +162,10 @@ void vrender0soc_device::device_start()
if (this->clock() == 0)
fatalerror("%s: bus clock not setup properly",this->tag());
- for (int i = 0; i < 4; i++)
- m_Timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vrender0soc_device::Timercb),this), (void*)(uintptr_t)i);
-
- write_tx.resolve_all_safe();
+ m_Timer[0] = timer_alloc(FUNC(vrender0soc_device::Timercb<0>), this);
+ m_Timer[1] = timer_alloc(FUNC(vrender0soc_device::Timercb<1>), this);
+ m_Timer[2] = timer_alloc(FUNC(vrender0soc_device::Timercb<2>), this);
+ m_Timer[3] = timer_alloc(FUNC(vrender0soc_device::Timercb<3>), this);
for (int i = 0; i < 2; i++)
{
@@ -190,10 +188,6 @@ void vrender0soc_device::device_start()
save_item(NAME(m_dma[1].src));
save_item(NAME(m_dma[1].dst));
save_item(NAME(m_dma[1].size));
-
-#ifdef IDLE_LOOP_SPEEDUP
- save_item(NAME(m_FlipCntRead));
-#endif
}
void vrender0soc_device::write_line_tx(int port, uint8_t value)
@@ -224,10 +218,6 @@ void vrender0soc_device::device_reset()
m_timer_control[i] = 0xff << 8;
m_Timer[i]->adjust(attotime::never);
}
-
-#ifdef IDLE_LOOP_SPEEDUP
- m_FlipCntRead = 0;
-#endif
}
@@ -316,10 +306,6 @@ void vrender0soc_device::IntReq( int num )
m_intst |= (1 << num);
m_host_cpu->set_input_line(SE3208_INT, ASSERT_LINE);
}
-
-#ifdef IDLE_LOOP_SPEEDUP
- idle_skip_resume_w(ASSERT_LINE);
-#endif
}
@@ -336,7 +322,7 @@ uint8_t vrender0soc_device::irq_callback()
}
-WRITE_LINE_MEMBER(vrender0soc_device::soundirq_cb)
+void vrender0soc_device::soundirq_cb(int state)
{
if (state)
{
@@ -362,17 +348,17 @@ void vrender0soc_device::TimerStart(int which)
// printf("timer %d start, PD = %x TCV = %x period = %s\n", which, PD, TCV, period.as_string());
}
+template<int Which>
TIMER_CALLBACK_MEMBER(vrender0soc_device::Timercb)
{
- int which = (int)(uintptr_t)ptr;
static const int num[] = { 0, 1, 9, 10 };
- if (m_timer_control[which] & 2)
- TimerStart(which);
+ if (m_timer_control[Which] & 2)
+ TimerStart(Which);
else
- m_timer_control[which] &= ~1;
+ m_timer_control[Which] &= ~1;
- IntReq(num[which]);
+ IntReq(num[Which]);
}
template<int Which>
@@ -720,35 +706,15 @@ uint32_t vrender0soc_device::screen_update(screen_device &screen, bitmap_ind16 &
return 0;
}
-WRITE_LINE_MEMBER(vrender0soc_device::screen_vblank)
+void vrender0soc_device::screen_vblank(int state)
{
// rising edge
if (state)
{
if (crt_active_vblank_irq() == true)
+ {
IntReq(24); //VRender0 VBlank
-
- m_vr0vid->execute_flipping();
+ m_vr0vid->execute_flipping();
+ }
}
}
-
-/*
- *
- * Hacks
- *
- */
-
-#ifdef IDLE_LOOP_SPEEDUP
-WRITE_LINE_MEMBER(vrender0soc_device::idle_skip_resume_w)
-{
- m_FlipCntRead = 0;
- m_host_cpu->resume(SUSPEND_REASON_SPIN);
-}
-
-WRITE_LINE_MEMBER(vrender0soc_device::idle_skip_speedup_w)
-{
- m_FlipCntRead++;
- if (m_FlipCntRead >= 16 && irq_pending() == false && state == ASSERT_LINE)
- m_host_cpu->suspend(SUSPEND_REASON_SPIN, 1);
-}
-#endif
diff --git a/src/devices/machine/vrender0.h b/src/devices/machine/vrender0.h
index 1d11acbacab..10bb28e8aac 100644
--- a/src/devices/machine/vrender0.h
+++ b/src/devices/machine/vrender0.h
@@ -20,14 +20,6 @@
#include "diserial.h"
//**************************************************************************
-// INTERFACE CONFIGURATION MACROS
-//**************************************************************************
-
-#define IDLE_LOOP_SPEEDUP
-
-
-
-//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@@ -103,7 +95,7 @@ public:
bool irq_pending() { return m_intst; }
void write_line_tx(int port, uint8_t value);
template <int Port> auto tx_callback() { return write_tx[Port].bind(); }
- template <int Port> DECLARE_WRITE_LINE_MEMBER(rx_w) { m_uart[Port]->rx_w((uint8_t)state); }
+ template <int Port> void rx_w(int state) { m_uart[Port]->rx_w((uint8_t)state); }
protected:
// device-level overrides
@@ -143,14 +135,14 @@ private:
uint32_t intst_r();
void intst_w(uint32_t data);
- DECLARE_WRITE_LINE_MEMBER(soundirq_cb);
+ void soundirq_cb(int state);
// Timer
template<int Which> void tmcon_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
template<int Which> uint32_t tmcon_r();
template<int Which> void tmcnt_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
template<int Which> uint16_t tmcnt_r();
- TIMER_CALLBACK_MEMBER(Timercb);
+ template<int Which> TIMER_CALLBACK_MEMBER(Timercb);
uint32_t m_timer_control[4] = { 0, 0, 0, 0 };
uint16_t m_timer_count[4] = { 0, 0, 0, 0 };
@@ -185,19 +177,12 @@ private:
uint32_t cfgr_r();
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- DECLARE_WRITE_LINE_MEMBER(screen_vblank);
+ void screen_vblank(int state);
uint16_t textureram_r(offs_t offset);
void textureram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t frameram_r(offs_t offset);
void frameram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
-
- // Hacks
-#ifdef IDLE_LOOP_SPEEDUP
- uint8_t m_FlipCntRead = 0;
- DECLARE_WRITE_LINE_MEMBER(idle_skip_resume_w);
- DECLARE_WRITE_LINE_MEMBER(idle_skip_speedup_w);
-#endif
};
diff --git a/src/devices/machine/vt8231_isa.cpp b/src/devices/machine/vt8231_isa.cpp
new file mode 100644
index 00000000000..9fa17c6144b
--- /dev/null
+++ b/src/devices/machine/vt8231_isa.cpp
@@ -0,0 +1,226 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ VIA VT8231 South Bridge - PCI to ISA Bridge
+
+***************************************************************************/
+
+#include "emu.h"
+#include "vt8231_isa.h"
+
+#define LOG_MAPPING (1U << 1)
+#define LOG_REG (1U << 2)
+#define LOG_SUPERIO (1U << 3)
+
+#define VERBOSE (LOG_GENERAL | LOG_MAPPING | LOG_REG | LOG_SUPERIO)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(VT8231_ISA, vt8231_isa_device, "vt8231_isa", "VT8231 South Bridge - PCI to ISA Bridge")
+
+vt8231_isa_device::vt8231_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ pci_device(mconfig, VT8231_ISA, tag, owner, clock),
+ m_com1(*this, "com1"),
+ m_com1_txd_cb(*this), m_com1_dtr_cb(*this), m_com1_rts_cb(*this),
+ m_initialized(false)
+{
+ set_ids(0x11068231, 0x00, 0x060100, 0x00000000);
+}
+
+void vt8231_isa_device::device_add_mconfig(machine_config &config)
+{
+ NS16550(config, m_com1, 1'843'200);
+ m_com1->out_tx_callback().set(FUNC(vt8231_isa_device::com1_txd_w));
+ m_com1->out_dtr_callback().set(FUNC(vt8231_isa_device::com1_dtr_w));
+ m_com1->out_rts_callback().set(FUNC(vt8231_isa_device::com1_rts_w));
+}
+
+void vt8231_isa_device::device_start()
+{
+ pci_device::device_start();
+
+ // register for save states (TODO)
+}
+
+void vt8231_isa_device::device_reset()
+{
+ pci_device::device_reset();
+
+ // setup superio configuration defaults
+ std::fill_n(m_superio_cfg, 0x10, 0x00);
+ m_superio_cfg[0x00] = 0x3c; // device id
+ m_superio_cfg[0x01] = 0x01; // revision
+ m_superio_cfg[0x02] = 0x03; // function select
+ m_superio_cfg[0x04] = 0xfe; // serial port base address (3f8)
+ m_superio_cfg[0x06] = 0xde; // parallel port base address (378)
+ m_superio_cfg[0x07] = 0xfc; // floppy controller base address (3f0)
+
+ m_baud_divisor = 0x01; // 115200 baud
+
+ m_initialized = true;
+ remap_cb();
+}
+
+void vt8231_isa_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+ if (!m_initialized)
+ return;
+
+ io_space->install_device(0x000, 0x7ff, *this, &vt8231_isa_device::io_map);
+
+ // serial port enabled?
+ if (BIT(m_superio_cfg[0x02], 2) == 1)
+ {
+ uint16_t com1_base = m_superio_cfg[0x04] << 2;
+ LOGMASKED(LOG_MAPPING, "Mapping COM1 from %04x to %04x\n", com1_base, com1_base + 0x0f);
+ io_space->install_device(com1_base, com1_base + 0x0f, *this, &vt8231_isa_device::com1_map);
+ }
+}
+
+void vt8231_isa_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+ map(0x50, 0x50).rw(FUNC(vt8231_isa_device::function_control_1_r), FUNC(vt8231_isa_device::function_control_1_w));
+}
+
+uint8_t vt8231_isa_device::function_control_1_r()
+{
+ // 7------- mc97 enable
+ // -6------ ac97 enable
+ // --5----- usb enable
+ // ---4---- usb enable
+ // ----3--- ide enable
+ // -----2-- super io configuration enable
+ // ------1- super io enable
+ // -------0 internal audio enable
+
+ return 0x00;
+}
+
+void vt8231_isa_device::function_control_1_w(uint8_t data)
+{
+ LOGMASKED(LOG_REG, "function_control_1_w: %02x\n", data);
+}
+
+void vt8231_isa_device::io_map(address_map &map)
+{
+ map(0x3f0, 0x3f0).rw(FUNC(vt8231_isa_device::superio_cfg_idx_r), FUNC(vt8231_isa_device::superio_cfg_idx_w));
+ map(0x3f1, 0x3f1).rw(FUNC(vt8231_isa_device::superio_cfg_data_r), FUNC(vt8231_isa_device::superio_cfg_data_w));
+}
+
+
+//**************************************************************************
+// SUPER IO
+//**************************************************************************
+
+uint8_t vt8231_isa_device::superio_cfg_idx_r()
+{
+ return m_superio_cfg_idx;
+}
+
+void vt8231_isa_device::superio_cfg_idx_w(uint8_t data)
+{
+ LOGMASKED(LOG_SUPERIO, "superio_cfg_idx_w: %02x\n", data);
+ m_superio_cfg_idx = data & 0x0f;
+}
+
+uint8_t vt8231_isa_device::superio_cfg_data_r()
+{
+ return m_superio_cfg[m_superio_cfg_idx];
+}
+
+void vt8231_isa_device::superio_cfg_data_w(uint8_t data)
+{
+ LOGMASKED(LOG_SUPERIO, "superio_cfg_data_w: %02x\n", data);
+
+ // first two registers are read-only
+ if (m_superio_cfg_idx < 2)
+ return;
+
+ m_superio_cfg[m_superio_cfg_idx] = data;
+ remap_cb();
+
+ switch (m_superio_cfg_idx)
+ {
+ case 0x02:
+ // 765----- reserved
+ // ---4---- floppy controller enable
+ // ----3--- reserved
+ // -----2-- serial port enable
+ // ------10 parellel port enable/mode
+ LOGMASKED(LOG_SUPERIO, "SuperIO function select\n");
+ break;
+
+ case 0x03:
+ LOGMASKED(LOG_SUPERIO, "SuperIO power down control\n");
+ break;
+
+ case 0x04:
+ LOGMASKED(LOG_SUPERIO, "SuperIO serial port i/o base address\n");
+ break;
+
+ case 0x06:
+ LOGMASKED(LOG_SUPERIO, "SuperIO parallel port i/o base address\n");
+ break;
+
+ case 0x07:
+ LOGMASKED(LOG_SUPERIO, "SuperIO floppy controller base address\n");
+ break;
+
+ case 0x09:
+ LOGMASKED(LOG_SUPERIO, "SuperIO serial port control\n");
+ break;
+
+ case 0x0a:
+ LOGMASKED(LOG_SUPERIO, "SuperIO parallel port control\n");
+ break;
+
+ case 0x0b:
+ LOGMASKED(LOG_SUPERIO, "SuperIO floppy controller control\n");
+ break;
+
+ case 0x0c:
+ LOGMASKED(LOG_SUPERIO, "SuperIO floppy controller drive type\n");
+ break;
+
+ case 0x0e:
+ LOGMASKED(LOG_SUPERIO, "SuperIO test mode a\n");
+ break;
+
+ case 0x0f:
+ LOGMASKED(LOG_SUPERIO, "SuperIO test mode b\n");
+ break;
+
+ default:
+ LOGMASKED(LOG_SUPERIO, "SuperIO reserved register\n");
+ break;
+ }
+}
+
+
+//**************************************************************************
+// SERIAL PORT
+//**************************************************************************
+
+void vt8231_isa_device::com1_map(address_map &map)
+{
+ map(0x00, 0x07).rw("com1", FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
+ map(0x08, 0x09).rw(FUNC(vt8231_isa_device::com1_baud_r), FUNC(vt8231_isa_device::com1_baud_w));
+}
+
+uint16_t vt8231_isa_device::com1_baud_r()
+{
+ return m_baud_divisor;
+}
+
+void vt8231_isa_device::com1_baud_w(uint16_t data)
+{
+ logerror("com1_baud_w: %04x\n", data);
+ m_baud_divisor = data;
+
+ // TODO: setting this to 0 might disable it?
+ if (data > 0)
+ m_com1->set_clock_scale(1.0 / data);
+}
diff --git a/src/devices/machine/vt8231_isa.h b/src/devices/machine/vt8231_isa.h
new file mode 100644
index 00000000000..d9564420fe6
--- /dev/null
+++ b/src/devices/machine/vt8231_isa.h
@@ -0,0 +1,84 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ VIA VT8231 South Bridge - PCI to ISA Bridge
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_VT8231_ISA_H
+#define MAME_MACHINE_VT8231_ISA_H
+
+#pragma once
+
+#include "pci.h"
+#include "machine/ins8250.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vt8231_isa_device
+
+class vt8231_isa_device : public pci_device
+{
+public:
+ vt8231_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto com1_txd_cb() { return m_com1_txd_cb.bind(); }
+ auto com1_dtr_cb() { return m_com1_dtr_cb.bind(); }
+ auto com1_rts_cb() { return m_com1_rts_cb.bind(); }
+
+ void com1_rxd_w(int state) { m_com1->rx_w(state); };
+ void com1_dcd_w(int state) { m_com1->dcd_w(state); };
+ void com1_dsr_w(int state) { m_com1->dsr_w(state); };
+ void com1_ri_w(int state) { m_com1->ri_w(state); };
+ void com1_cts_w(int state) { m_com1->cts_w(state); };
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+private:
+ uint8_t function_control_1_r();
+ void function_control_1_w(uint8_t data);
+
+ void io_map(address_map &map);
+
+ uint8_t superio_cfg_idx_r();
+ void superio_cfg_idx_w(uint8_t data);
+ uint8_t superio_cfg_data_r();
+ void superio_cfg_data_w(uint8_t data);
+
+ void com1_map(address_map &map);
+ uint16_t com1_baud_r();
+ void com1_baud_w(uint16_t data);
+
+ void com1_txd_w(int state) { m_com1_txd_cb(state); };
+ void com1_dtr_w(int state) { m_com1_dtr_cb(state); };
+ void com1_rts_w(int state) { m_com1_rts_cb(state); };
+
+ required_device<ns16550_device> m_com1;
+
+ devcb_write_line m_com1_txd_cb;
+ devcb_write_line m_com1_dtr_cb;
+ devcb_write_line m_com1_rts_cb;
+
+ uint8_t m_superio_cfg[0x10];
+ uint8_t m_superio_cfg_idx;
+ uint16_t m_baud_divisor;
+
+ bool m_initialized;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(VT8231_ISA, vt8231_isa_device)
+
+#endif // MAME_MACHINE_VT8231_ISA_H
diff --git a/src/devices/machine/w83787f.cpp b/src/devices/machine/w83787f.cpp
new file mode 100644
index 00000000000..751766294a0
--- /dev/null
+++ b/src/devices/machine/w83787f.cpp
@@ -0,0 +1,345 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+Winbond W83787IF / W83787F
+
+'F is the base, 'IF adds IrDA.
+Looks similar in design to National PC87306 (including similar reg names)
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "w83787f.h"
+
+#define LOG_WARN (1U << 1)
+
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(W83787F, w83787f_device, "w83787f", "National Semiconductor W83787F Super I/O Enhanced Sidewinder Lite")
+
+w83787f_device::w83787f_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, W83787F, tag, owner, clock)
+ , device_isa16_card_interface(mconfig, *this)
+ , device_memory_interface(mconfig, *this)
+ , m_space_config("superio_config_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(w83787f_device::config_map), this))
+ , m_pc_com(*this, "uart%d", 0U)
+ , m_pc_lpt(*this, "lpta")
+ , m_irq1_callback(*this)
+ , m_irq8_callback(*this)
+ , m_irq9_callback(*this)
+ , m_txd1_callback(*this)
+ , m_ndtr1_callback(*this)
+ , m_nrts1_callback(*this)
+ , m_txd2_callback(*this)
+ , m_ndtr2_callback(*this)
+ , m_nrts2_callback(*this)
+{ }
+
+
+void w83787f_device::device_start()
+{
+ set_isa_device();
+ //m_isa->set_dma_channel(0, this, true);
+ //m_isa->set_dma_channel(1, this, true);
+ //m_isa->set_dma_channel(2, this, true);
+ //m_isa->set_dma_channel(3, this, true);
+ remap(AS_IO, 0, 0x400);
+}
+
+void w83787f_device::device_reset()
+{
+ m_locked_state = true;
+ m_cr1 = 0;
+}
+
+device_memory_interface::space_config_vector w83787f_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+void w83787f_device::device_add_mconfig(machine_config &config)
+{
+ PC_LPT(config, m_pc_lpt);
+ m_pc_lpt->irq_handler().set(FUNC(w83787f_device::irq_parallel_w));
+
+ NS16550(config, m_pc_com[0], XTAL(1'843'200));
+ m_pc_com[0]->out_int_callback().set(FUNC(w83787f_device::irq_serial1_w));
+ m_pc_com[0]->out_tx_callback().set(FUNC(w83787f_device::txd_serial1_w));
+ m_pc_com[0]->out_dtr_callback().set(FUNC(w83787f_device::dtr_serial1_w));
+ m_pc_com[0]->out_rts_callback().set(FUNC(w83787f_device::rts_serial1_w));
+
+ NS16550(config, m_pc_com[1], XTAL(1'843'200));
+ m_pc_com[1]->out_int_callback().set(FUNC(w83787f_device::irq_serial2_w));
+ m_pc_com[1]->out_tx_callback().set(FUNC(w83787f_device::txd_serial2_w));
+ m_pc_com[1]->out_dtr_callback().set(FUNC(w83787f_device::dtr_serial2_w));
+ m_pc_com[1]->out_rts_callback().set(FUNC(w83787f_device::rts_serial2_w));
+}
+
+void w83787f_device::remap(int space_id, offs_t start, offs_t end)
+{
+ if (space_id == AS_IO)
+ {
+ m_isa->install_device(0x0250, 0x0252, read8sm_delegate(*this, FUNC(w83787f_device::read)), write8sm_delegate(*this, FUNC(w83787f_device::write)));
+
+ //if (BIT(m_fer, 0))
+ const u8 lpt_setting = (m_cr1 >> 4) & 3;
+ if (lpt_setting != 3)
+ {
+ const u16 lpt_port[3] = { 0x3bc, 0x278, 0x378 };
+ const u16 lpt_addr = lpt_port[lpt_setting & 3];
+ LOG("Map LPT1 to I/O port %04x-%04x\n", lpt_addr, lpt_addr + 3);
+
+ m_isa->install_device(lpt_addr, lpt_addr + 3, read8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::read)), write8sm_delegate(*m_pc_lpt, FUNC(pc_lpt_device::write)));
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ const u8 uart_setting = (BIT(m_cr1, 2 + i) >> 1) | (BIT(m_cr1, i));
+ if (uart_setting != 3)
+ {
+ const u16 uart_port[3] = { 0x2e8, 0x3e8, 0x3f8 };
+ const u16 uart_addr = uart_port[uart_setting & 3] ^ (i ? 0x100 : 0x000);
+ LOG("Map UART%c to I/O port %04x-%04x\n", i ? 'A' : 'B', uart_addr, uart_addr + 7);
+ m_isa->install_device(uart_addr, uart_addr + 7, read8sm_delegate(*m_pc_com[i], FUNC(ns16450_device::ins8250_r)), write8sm_delegate(*m_pc_com[i], FUNC(ns16450_device::ins8250_w)));
+ }
+ }
+ }
+}
+
+u8 w83787f_device::read(offs_t offset)
+{
+ if (offset != 2 && !machine().side_effects_disabled())
+ {
+ LOGWARN("Invalid %s access read\n", offset & 1 ? "EFIR" : "EFIR");
+ return space().unmap();
+ }
+
+ if (m_locked_state)
+ return space().unmap();
+
+ return space().read_byte(m_index);
+}
+
+void w83787f_device::write(offs_t offset, u8 data)
+{
+ switch (offset)
+ {
+ // EFER
+ // TODO: 0x89 with GMRD# pin
+ case 0: m_locked_state = (data != 0x88); break;
+ // EFIR
+ case 1: m_index = data; break;
+ // EFDR
+ case 2:
+ if (!m_locked_state)
+ space().write_byte(m_index, data);
+ break;
+ }
+}
+
+// none of these regs have a real naming, they are all CR*
+void w83787f_device::config_map(address_map &map)
+{
+// map(0x00, 0x00) IDE & FDC
+ map(0x01, 0x01).lrw8(
+ NAME([this] (offs_t offset) {
+ return m_cr1;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_cr1 = data;
+ remap(AS_IO, 0, 0x400);
+ })
+ );
+// map(0x02, 0x02) extension adapter mode
+// map(0x03, 0x03) game port, UART clocks
+// map(0x04, 0x04) game port, UARTA/B power-down tristate
+// map(0x05, 0x05) ECP FIFO threshold
+// map(0x06, 0x06) 2x / x4 FDD select, FDC power-down tristate, IDE power-down tristate
+// map(0x07, 0x07) FDDs type
+// map(0x08, 0x08) automatic power-down, FDD write protect
+// map(0x09, 0x09) CHIP ID, lock alias, operating mode
+// map(0x0a, 0x0a) LPT pins
+// map(0x0c, 0x0c) UARTA/B clock source, lock select
+// map(0x0d, 0x0d) IrDA select
+// map(0x0e, 0x0f) <reserved for test>
+// map(0x10, 0x10) GIO0 address select 7-0
+// map(0x11, 0x11) GIO0 address select 10-8, GI0 address MODE0-1
+// map(0x12, 0x12) GIO1 address select 7-0
+// map(0x13, 0x13) GIO1 address select 10-8, GI0 address MODE0-1
+// map(0x14, 0x14) GIO0 ddr/mode
+// map(0x15, 0x15) GIO1 ddr/mode
+}
+
+/*
+ * Serial
+ */
+
+void w83787f_device::irq_serial1_w(int state)
+{
+ if ((m_cr1 & 0x05) == 0x05)
+ return;
+ request_irq(3, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void w83787f_device::irq_serial2_w(int state)
+{
+ if ((m_cr1 & 0x0a) == 0x0a)
+ return;
+ request_irq(4, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void w83787f_device::txd_serial1_w(int state)
+{
+ if ((m_cr1 & 0x05) == 0x05)
+ return;
+ m_txd1_callback(state);
+}
+
+void w83787f_device::txd_serial2_w(int state)
+{
+ if ((m_cr1 & 0x0a) == 0x0a)
+ return;
+ m_txd2_callback(state);
+}
+
+void w83787f_device::dtr_serial1_w(int state)
+{
+ if ((m_cr1 & 0x05) == 0x05)
+ return;
+ m_ndtr1_callback(state);
+}
+
+void w83787f_device::dtr_serial2_w(int state)
+{
+ if ((m_cr1 & 0x0a) == 0x0a)
+ return;
+ m_ndtr2_callback(state);
+}
+
+void w83787f_device::rts_serial1_w(int state)
+{
+ if ((m_cr1 & 0x05) == 0x05)
+ return;
+ m_nrts1_callback(state);
+}
+
+void w83787f_device::rts_serial2_w(int state)
+{
+ if ((m_cr1 & 0x0a) == 0x0a)
+ return;
+ m_nrts2_callback(state);
+}
+
+void w83787f_device::rxd1_w(int state)
+{
+ m_pc_com[0]->rx_w(state);
+}
+
+void w83787f_device::ndcd1_w(int state)
+{
+ m_pc_com[0]->dcd_w(state);
+}
+
+void w83787f_device::ndsr1_w(int state)
+{
+ m_pc_com[0]->dsr_w(state);
+}
+
+void w83787f_device::nri1_w(int state)
+{
+ m_pc_com[0]->ri_w(state);
+}
+
+void w83787f_device::ncts1_w(int state)
+{
+ m_pc_com[0]->cts_w(state);
+}
+
+void w83787f_device::rxd2_w(int state)
+{
+ m_pc_com[1]->rx_w(state);
+}
+
+void w83787f_device::ndcd2_w(int state)
+{
+ m_pc_com[1]->dcd_w(state);
+}
+
+void w83787f_device::ndsr2_w(int state)
+{
+ m_pc_com[1]->dsr_w(state);
+}
+
+void w83787f_device::nri2_w(int state)
+{
+ m_pc_com[1]->ri_w(state);
+}
+
+void w83787f_device::ncts2_w(int state)
+{
+ m_pc_com[1]->cts_w(state);
+}
+
+/*
+ * Parallel
+ */
+
+void w83787f_device::irq_parallel_w(int state)
+{
+ if ((m_cr1 & 0x30) == 0x30)
+ return;
+ request_irq(5, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void w83787f_device::request_irq(int irq, int state)
+{
+ switch (irq)
+ {
+ case 1:
+ m_irq1_callback(state);
+ break;
+ case 3:
+ m_isa->irq3_w(state);
+ break;
+ case 4:
+ m_isa->irq4_w(state);
+ break;
+ case 5:
+ m_isa->irq5_w(state);
+ break;
+ case 6:
+ m_isa->irq6_w(state);
+ break;
+ case 7:
+ m_isa->irq7_w(state);
+ break;
+ case 8:
+ m_irq8_callback(state);
+ break;
+ case 9:
+ m_irq9_callback(state);
+ break;
+ case 10:
+ m_isa->irq10_w(state);
+ break;
+ case 11:
+ m_isa->irq11_w(state);
+ break;
+ case 12:
+ m_isa->irq12_w(state);
+ break;
+ case 14:
+ m_isa->irq14_w(state);
+ break;
+ case 15:
+ m_isa->irq15_w(state);
+ break;
+ }
+}
diff --git a/src/devices/machine/w83787f.h b/src/devices/machine/w83787f.h
new file mode 100644
index 00000000000..ed0123153a2
--- /dev/null
+++ b/src/devices/machine/w83787f.h
@@ -0,0 +1,95 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_W83787F_H
+#define MAME_MACHINE_W83787F_H
+
+#pragma once
+
+#include "bus/isa/isa.h"
+#include "machine/ins8250.h"
+#include "machine/pc_lpt.h"
+
+class w83787f_device : public device_t,
+ public device_isa16_card_interface,
+ public device_memory_interface
+{
+public:
+ w83787f_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~w83787f_device() {}
+
+ void remap(int space_id, offs_t start, offs_t end) override;
+
+// auto gp20_reset() { return m_gp20_reset_callback.bind(); }
+// auto gp25_gatea20() { return m_gp25_gatea20_callback.bind(); }
+ auto irq1() { return m_irq1_callback.bind(); }
+ auto irq8() { return m_irq8_callback.bind(); }
+ auto irq9() { return m_irq9_callback.bind(); }
+ auto txd1() { return m_txd1_callback.bind(); }
+ auto ndtr1() { return m_ndtr1_callback.bind(); }
+ auto nrts1() { return m_nrts1_callback.bind(); }
+ auto txd2() { return m_txd2_callback.bind(); }
+ auto ndtr2() { return m_ndtr2_callback.bind(); }
+ auto nrts2() { return m_nrts2_callback.bind(); }
+
+ void rxd1_w(int state);
+ void ndcd1_w(int state);
+ void ndsr1_w(int state);
+ void nri1_w(int state);
+ void ncts1_w(int state);
+ void rxd2_w(int state);
+ void ndcd2_w(int state);
+ void ndsr2_w(int state);
+ void nri2_w(int state);
+ void ncts2_w(int state);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual space_config_vector memory_space_config() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ const address_space_config m_space_config;
+
+ required_device_array<ns16550_device, 2> m_pc_com;
+ required_device<pc_lpt_device> m_pc_lpt;
+
+ devcb_write_line m_irq1_callback;
+ devcb_write_line m_irq8_callback;
+ devcb_write_line m_irq9_callback;
+ devcb_write_line m_txd1_callback;
+ devcb_write_line m_ndtr1_callback;
+ devcb_write_line m_nrts1_callback;
+ devcb_write_line m_txd2_callback;
+ devcb_write_line m_ndtr2_callback;
+ devcb_write_line m_nrts2_callback;
+
+ void request_irq(int irq, int state);
+
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+ void config_map(address_map &map);
+
+ void irq_parallel_w(int state);
+
+ void irq_serial1_w(int state);
+ void txd_serial1_w(int state);
+ void dtr_serial1_w(int state);
+ void rts_serial1_w(int state);
+ void irq_serial2_w(int state);
+ void txd_serial2_w(int state);
+ void dtr_serial2_w(int state);
+ void rts_serial2_w(int state);
+
+ u8 m_index = 0;
+
+ bool m_locked_state = true;
+ u8 m_cr1 = 0;
+};
+
+DECLARE_DEVICE_TYPE(W83787F, w83787f_device);
+
+#endif // MAME_MACHINE_W83787F_H
diff --git a/src/devices/machine/w83977tf.cpp b/src/devices/machine/w83977tf.cpp
new file mode 100644
index 00000000000..2a5131210e5
--- /dev/null
+++ b/src/devices/machine/w83977tf.cpp
@@ -0,0 +1,535 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+Winbond W83977TF
+
+TODO:
+- PoC for a generic (LPC) Super I/O type, consider abstracting common points with fdc37c93x;
+- savquest (in pciagp) fails keyboard self test
+ \- bp e140c,1,{eax&=~1;g} bit 0 stuck high from port $64, "receives" while essentially reading
+ status only three times (and port $61 is claimed by PIIX4 for PCI SERR# read only)
+- DRQ (savquest enables DRQ3 for LPT)
+- Hookup LPT modes;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "w83977tf.h"
+
+//#include "machine/ds128x.h"
+#include "machine/pckeybrd.h"
+
+#include <algorithm>
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(W83977TF, w83977tf_device, "w83977tf", "Winbond W83977TF Super I/O")
+
+w83977tf_device::w83977tf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, W83977TF, tag, owner, clock)
+ , device_isa16_card_interface(mconfig, *this)
+ , device_memory_interface(mconfig, *this)
+ , m_space_config("superio_config_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(w83977tf_device::config_map), this))
+ , m_kbdc(*this, "pc_kbdc")
+ , m_rtc(*this, "rtc")
+ , m_lpt(*this, "lpt")
+ , m_logical_view(*this, "logical_view")
+ , m_gp20_reset_callback(*this)
+ , m_gp25_gatea20_callback(*this)
+ , m_irq1_callback(*this)
+ , m_irq8_callback(*this)
+ , m_irq9_callback(*this)
+// , m_txd1_callback(*this)
+// , m_ndtr1_callback(*this)
+// , m_nrts1_callback(*this)
+// , m_txd2_callback(*this)
+// , m_ndtr2_callback(*this)
+// , m_nrts2_callback(*this)
+ , m_index(0)
+ , m_logical_index(0)
+ , m_hefras(0)
+ , m_lockreg(0)
+ , m_lock_sequence(0)
+ , m_keyb_irq_line(0)
+ , m_mouse_irq_line(0)
+ , m_rtc_irq_line(0)
+ , m_keyb_address{ 0, 0 }
+{
+ std::fill(std::begin(m_activate), std::end(m_activate), false);
+}
+
+w83977tf_device::~w83977tf_device()
+{
+}
+
+void w83977tf_device::device_start()
+{
+ set_isa_device();
+ //m_isa->set_dma_channel(0, this, true);
+ //m_isa->set_dma_channel(1, this, true);
+ //m_isa->set_dma_channel(2, this, true);
+ //m_isa->set_dma_channel(3, this, true);
+ remap(AS_IO, 0, 0x400);
+
+}
+
+void w83977tf_device::device_reset()
+{
+ m_index = 0;
+ m_hefras = 0;
+ m_lock_sequence = 2;
+ // TODO: these are initialized by /PNPCSV = 0 at POR
+ m_keyb_address[0] = 0x60;
+ m_keyb_address[1] = 0x64;
+ m_lpt_address = 0x0378;
+ m_lpt_irq_line = 7;
+ m_lpt_drq_line = 4; // disabled
+ m_lpt_mode = 0x3f;
+}
+
+device_memory_interface::space_config_vector w83977tf_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
+}
+
+void w83977tf_device::device_add_mconfig(machine_config &config)
+{
+ PC_LPT(config, m_lpt);
+ m_lpt->irq_handler().set(FUNC(w83977tf_device::irq_parallel_w));
+
+ // TODO: exact type, mentions being 8042/PC87911 compatible
+ // (which is kbd + rtc in one)
+ DS12885(config, m_rtc, 32.768_kHz_XTAL);
+ m_rtc->irq().set(FUNC(w83977tf_device::irq_rtc_w));
+ m_rtc->set_century_index(0x32);
+
+ // TODO: W83C435 controller
+ KBDC8042(config, m_kbdc);
+ m_kbdc->set_keyboard_type(kbdc8042_device::KBDC8042_PS2);
+ m_kbdc->set_interrupt_type(kbdc8042_device::KBDC8042_DOUBLE);
+ m_kbdc->system_reset_callback().set(FUNC(w83977tf_device::kbdp20_gp20_reset_w));
+ m_kbdc->gate_a20_callback().set(FUNC(w83977tf_device::kbdp21_gp25_gatea20_w));
+ m_kbdc->input_buffer_full_callback().set(FUNC(w83977tf_device::irq_keyboard_w));
+ m_kbdc->input_buffer_full_mouse_callback().set(FUNC(w83977tf_device::irq_mouse_w));
+ m_kbdc->set_keyboard_tag("at_keyboard");
+
+ at_keyboard_device &at_keyb(AT_KEYB(config, "at_keyboard", pc_keyboard_device::KEYBOARD_TYPE::AT, 1));
+ at_keyb.keypress().set(m_kbdc, FUNC(kbdc8042_device::keyboard_w));
+}
+
+
+void w83977tf_device::remap(int space_id, offs_t start, offs_t end)
+{
+ if (space_id == AS_IO)
+ {
+ u16 superio_base = m_hefras ? 0x370 : 0x3f0;
+ m_isa->install_device(superio_base, superio_base + 3, read8sm_delegate(*this, FUNC(w83977tf_device::read)), write8sm_delegate(*this, FUNC(w83977tf_device::write)));
+
+ // can't map below 0x100
+ if (m_activate[1] & 1 && m_lpt_address & 0xf00)
+ {
+ m_isa->install_device(m_lpt_address, m_lpt_address + 3, read8sm_delegate(*m_lpt, FUNC(pc_lpt_device::read)), write8sm_delegate(*m_lpt, FUNC(pc_lpt_device::write)));
+ }
+
+ if (m_activate[5] & 1)
+ {
+ m_isa->install_device(m_keyb_address[0], m_keyb_address[0], read8sm_delegate(*m_kbdc, FUNC(kbdc8042_device::data_r)), write8sm_delegate(*m_kbdc, FUNC(kbdc8042_device::data_w)));
+ m_isa->install_device(m_keyb_address[1], m_keyb_address[1], read8sm_delegate(*this, FUNC(w83977tf_device::keybc_status_r)), write8sm_delegate(*this, FUNC(w83977tf_device::keybc_command_w)));
+ }
+
+ if (m_activate[8] & 1)
+ {
+ // TODO: from port
+ m_isa->install_device(0x70, 0x7f, read8sm_delegate(*this, FUNC(w83977tf_device::rtc_r)), write8sm_delegate(*this, FUNC(w83977tf_device::rtc_w)));
+ }
+ }
+}
+
+uint8_t w83977tf_device::read(offs_t offset)
+{
+ if (m_lock_sequence)
+ return 0;
+
+ if (offset == 0)
+ return m_index;
+
+ return space().read_byte(m_index);
+}
+
+void w83977tf_device::write(offs_t offset, u8 data)
+{
+ if (offset == 0)
+ {
+ if (m_lock_sequence)
+ {
+ if (data == 0x87)
+ {
+ m_lock_sequence --;
+ //if (m_lock_sequence == 0)
+ // LOG("Config unlocked\n");
+ }
+ }
+ else
+ {
+ if (data == 0xaa)
+ {
+ //LOG("Config locked\n");
+ m_lock_sequence = 2;
+ return;
+ }
+ m_index = data;
+ }
+ }
+ else
+ {
+ if (!m_lock_sequence)
+ space().write_byte(m_index, data);
+ }
+}
+
+void w83977tf_device::config_map(address_map &map)
+{
+// map(0x02, 0x02) configuration control (bit 0 soft reset)
+ map(0x07, 0x07).lr8(NAME([this] () { return m_logical_index; })).w(FUNC(w83977tf_device::logical_device_select_w));
+ map(0x20, 0x20).lr8(NAME([] () { return 0x97; })); // device ID
+ map(0x21, 0x21).lr8(NAME([] () { return 0x73; })); // revision
+// map(0x22, 0x22) device power down control
+// map(0x23, 0x23) global immediate power down
+// map(0x24, 0x24)
+// map(0x25, 0x25)
+ map(0x26, 0x26).rw(FUNC(w83977tf_device::cr26_r), FUNC(w83977tf_device::cr26_w));
+// map(0x28, 0x28)
+// map(0x2a, 0x2a)
+// map(0x2b, 0x2b)
+// map(0x2c, 0x2c)
+// map(0x2d, 0x2f) Test Modes
+
+ map(0x30, 0xff).view(m_logical_view);
+ // FDC
+ m_logical_view[0](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<0>), FUNC(w83977tf_device::activate_w<0>));
+ m_logical_view[0](0x31, 0xff).unmaprw();
+ // LPT
+ m_logical_view[1](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<1>), FUNC(w83977tf_device::activate_w<1>));
+ m_logical_view[1](0x60, 0x61).lrw8(
+ NAME([this] (offs_t offset) {
+ return (m_lpt_address >> (offset * 8)) & 0xff;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ const u8 shift = offset * 8;
+ m_lpt_address &= 0xff << shift;
+ m_lpt_address |= data << (shift ^ 8);
+ LOG("LD1 (LPT): remap %04x ([%d] %02x)\n", m_lpt_address, offset, data);
+
+ remap(AS_IO, 0, 0x400);
+ })
+ );
+ m_logical_view[1](0x70, 0x70).lrw8(
+ NAME([this] () {
+ return m_lpt_irq_line;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_lpt_irq_line = data & 0xf;
+ LOG("LD1 (LPT): irq routed to %02x\n", m_lpt_irq_line);
+ })
+ );
+ m_logical_view[1](0x74, 0x74).lrw8(
+ NAME([this] () {
+ return m_lpt_drq_line;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_lpt_drq_line = data & 0x7;
+ LOG("LD1 (LPT): drq %s (%02x)\n", BIT(m_lpt_drq_line, 2) ? "disabled" : "enabled", data);
+ })
+ );
+/*
+ * x--- ---- PP Interrupt Type
+ * 0--- ---- IRQ follows /ACK
+ * 1--- ---- Pulsed Low, released to high-Z (?)
+ * -xxx x--- ECP FIFO Threshold
+ * ---- -xxx Parallel Port Mode
+ * ---- -000 SPP
+ * ---- -001 EPP 1.9/SPP
+ * ---- -010 ECP
+ * ---- -011 ECP/EPP 1.9
+ * ---- -100 Printer Mode
+ * ---- -101 EPP 1.7/SPP
+ * ---- -110 <reserved>
+ * ---- -111 ECP/EPP 1.7
+ */
+ m_logical_view[1](0xf0, 0xf0).lrw8(
+ NAME([this] () {
+ LOG("LD1 (LPT): mode read\n");
+ return m_lpt_mode;
+ }),
+ NAME([this] (offs_t offset, u8 data) {
+ m_lpt_mode = data;
+ LOG("LD1 (LPT): mode write %02x\n", m_lpt_mode);
+ // TODO: interface with LPT adapter
+ // pciagp/savquest sets 0x07 from BIOS (ECP and EPP) + DRQ3
+ })
+ );
+ // UART1
+ m_logical_view[2](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<2>), FUNC(w83977tf_device::activate_w<2>));
+ m_logical_view[2](0x31, 0xff).unmaprw();
+ // UART2
+ m_logical_view[3](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<3>), FUNC(w83977tf_device::activate_w<3>));
+ m_logical_view[3](0x31, 0xff).unmaprw();
+ // <reserved>
+ m_logical_view[4](0x30, 0xff).unmaprw();
+ // KBC
+ m_logical_view[5](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<5>), FUNC(w83977tf_device::activate_w<5>));
+ m_logical_view[5](0x60, 0x63).rw(FUNC(w83977tf_device::keyb_io_address_r), FUNC(w83977tf_device::keyb_io_address_w));
+ m_logical_view[5](0x70, 0x70).rw(FUNC(w83977tf_device::keyb_irq_r), FUNC(w83977tf_device::keyb_irq_w));
+ m_logical_view[5](0x72, 0x72).rw(FUNC(w83977tf_device::mouse_irq_r), FUNC(w83977tf_device::mouse_irq_w));
+ m_logical_view[5](0xf0, 0xf0).lw8(
+ NAME([this] (offs_t offset, u8 data) {
+ // xx-- ---- KBC clock rate (00 = 6 MHz, 01 = 8 MHz, 10 = 12 MHz, 11 16 MHz)
+ // ---- -x-- Enable port $92
+ // ---- --xx Enables HW A20/reset from port $92
+ LOG("LD5 (KBDC): keyboard_hwcontrol_w %02x\n", data);
+ if (BIT(data, 2))
+ popmessage("w83977tf: warning PnP KBDC enabled I/O $92");
+ })
+ );
+ // <reserved>
+ m_logical_view[6](0x30, 0xff).unmaprw();
+ // GPIO1
+ m_logical_view[7](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<7>), FUNC(w83977tf_device::activate_w<7>));
+ m_logical_view[7](0x31, 0xff).unmaprw();
+ // GPIO2
+ // doc doesn't explicitly mention this being at logical dev 8, assume from intialization
+ m_logical_view[8](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<8>), FUNC(w83977tf_device::activate_w<8>));
+ m_logical_view[8](0x70, 0x70).rw(FUNC(w83977tf_device::rtc_irq_r), FUNC(w83977tf_device::rtc_irq_w));
+ // GPIO3
+ m_logical_view[9](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<9>), FUNC(w83977tf_device::activate_w<9>));
+ m_logical_view[9](0x31, 0xff).unmaprw();
+ // ACPI
+ m_logical_view[0xa](0x30, 0x30).rw(FUNC(w83977tf_device::activate_r<0xa>), FUNC(w83977tf_device::activate_w<0xa>));
+ m_logical_view[0xa](0x31, 0xff).unmaprw();
+}
+
+/*
+ * Global register space
+ */
+
+void w83977tf_device::logical_device_select_w(offs_t offset, u8 data)
+{
+ m_logical_index = data;
+ if (m_logical_index <= 0xa)
+ m_logical_view.select(m_logical_index);
+ else
+ LOG("Attempt to select an unmapped device with %02x\n", data);
+}
+
+u8 w83977tf_device::cr26_r()
+{
+ return m_hefras << 6 | m_lockreg << 5;
+}
+
+void w83977tf_device::cr26_w(offs_t offset, u8 data)
+{
+ m_hefras = BIT(data, 6);
+ // TODO: disable R/W on logical devices?
+ m_lockreg = BIT(data, 5);
+}
+
+template <unsigned N> u8 w83977tf_device::activate_r(offs_t offset)
+{
+ return m_activate[N];
+}
+
+template <unsigned N> void w83977tf_device::activate_w(offs_t offset, u8 data)
+{
+ m_activate[N] = data & 1;
+ LOG("%d Device %s\n", N, data & 1 ? "enabled" : "disabled");
+ remap(AS_IO, 0, 0x400);
+}
+
+void w83977tf_device::request_irq(int irq, int state)
+{
+ switch (irq)
+ {
+ case 1:
+ m_irq1_callback(state);
+ break;
+ case 3:
+ m_isa->irq3_w(state);
+ break;
+ case 4:
+ m_isa->irq4_w(state);
+ break;
+ case 5:
+ m_isa->irq5_w(state);
+ break;
+ case 6:
+ m_isa->irq6_w(state);
+ break;
+ case 7:
+ m_isa->irq7_w(state);
+ break;
+ case 8:
+ m_irq8_callback(state);
+ break;
+ case 9:
+ m_irq9_callback(state);
+ break;
+ case 10:
+ m_isa->irq10_w(state);
+ break;
+ case 11:
+ m_isa->irq11_w(state);
+ break;
+ case 12:
+ m_isa->irq12_w(state);
+ break;
+ case 14:
+ m_isa->irq14_w(state);
+ break;
+ case 15:
+ m_isa->irq15_w(state);
+ break;
+ }
+}
+
+/*
+ * Device #1 (Parallel)
+ */
+
+void w83977tf_device::irq_parallel_w(int state)
+{
+ if (m_activate[1] == false)
+ return;
+ request_irq(m_lpt_irq_line, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+/*
+ * Device #5 (Keyboard)
+ */
+
+void w83977tf_device::kbdp21_gp25_gatea20_w(int state)
+{
+ if (m_activate[5] == false)
+ return;
+ m_gp25_gatea20_callback(state);
+}
+
+void w83977tf_device::kbdp20_gp20_reset_w(int state)
+{
+ if (m_activate[5] == false)
+ return;
+ m_gp20_reset_callback(state);
+}
+
+void w83977tf_device::irq_keyboard_w(int state)
+{
+ if (m_activate[5] == false)
+ return;
+ request_irq(m_keyb_irq_line, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void w83977tf_device::irq_mouse_w(int state)
+{
+ if (m_activate[5] == false)
+ return;
+ request_irq(m_mouse_irq_line, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+u8 w83977tf_device::keyb_irq_r(offs_t offset)
+{
+ return m_keyb_irq_line;
+}
+
+void w83977tf_device::keyb_irq_w(offs_t offset, u8 data)
+{
+ m_keyb_irq_line = data & 0xf;
+ LOG("LD5 (KBDC): keyb irq routed to %02x\n", m_keyb_irq_line);
+}
+
+u8 w83977tf_device::mouse_irq_r(offs_t offset)
+{
+ return m_mouse_irq_line;
+}
+
+void w83977tf_device::mouse_irq_w(offs_t offset, u8 data)
+{
+ m_mouse_irq_line = data & 0xf;
+ LOG("LD5 (KBDC): mouse irq routed to %02x\n", m_mouse_irq_line);
+}
+
+u8 w83977tf_device::keybc_status_r(offs_t offset)
+{
+ return (m_kbdc->data_r(4) & 0xff);
+}
+
+void w83977tf_device::keybc_command_w(offs_t offset, u8 data)
+{
+ m_kbdc->data_w(4, data);
+}
+
+// $60-$61 selects data port, $62-$63 command port
+u8 w83977tf_device::keyb_io_address_r(offs_t offset)
+{
+ return m_keyb_address[(offset & 2) >> 1] >> ((offset & 1) ? 0 : 8) & 0xff;
+}
+
+void w83977tf_device::keyb_io_address_w(offs_t offset, u8 data)
+{
+ const u8 which = (offset & 2) >> 1;
+ if (offset & 1)
+ {
+ m_keyb_address[which] &= 0xff00;
+ m_keyb_address[which] |= data;
+ LOG("LD5 (KBDC): keyb_io_address_w[1] %04x (%04x & 0x00ff)\n", which, m_keyb_address[which], data);
+ }
+ else
+ {
+ m_keyb_address[which] &= 0xff;
+ m_keyb_address[which] |= data << 8;
+ LOG("LD5 (KBDC): keyb_io_address_w[0] %04x (%04x & 0xff00)\n", which, m_keyb_address[which], data << 8);
+ }
+ remap(AS_IO, 0, 0x400);
+}
+
+/*
+ * Device #8 (RTC)
+ */
+
+u8 w83977tf_device::rtc_r(offs_t offset)
+{
+ if (BIT(offset, 0))
+ return m_rtc->data_r();
+ else
+ return m_rtc->get_address();
+}
+
+void w83977tf_device::rtc_w(offs_t offset, u8 data)
+{
+ if (BIT(offset, 0))
+ m_rtc->data_w(data);
+ else
+ m_rtc->address_w(data);
+}
+
+void w83977tf_device::irq_rtc_w(int state)
+{
+ if (m_activate[8] == false)
+ return;
+ request_irq(m_rtc_irq_line, state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+u8 w83977tf_device::rtc_irq_r(offs_t offset)
+{
+ return m_rtc_irq_line;
+}
+
+void w83977tf_device::rtc_irq_w(offs_t offset, u8 data)
+{
+ m_rtc_irq_line = data & 0xf;
+ LOG("LD9 (GPIO2): RTC irq routed to %02x\n", m_rtc_irq_line);
+}
diff --git a/src/devices/machine/w83977tf.h b/src/devices/machine/w83977tf.h
new file mode 100644
index 00000000000..5b4b8034ff6
--- /dev/null
+++ b/src/devices/machine/w83977tf.h
@@ -0,0 +1,120 @@
+// license:BSD-3-Clause
+// copyright-holders: Angelo Salese
+#ifndef MAME_MACHINE_W83977TF_H
+#define MAME_MACHINE_W83977TF_H
+
+#pragma once
+
+#include "bus/isa/isa.h"
+#include "machine/8042kbdc.h"
+#include "machine/ds128x.h"
+#include "machine/pc_lpt.h"
+
+class w83977tf_device : public device_t,
+ public device_isa16_card_interface,
+ public device_memory_interface
+{
+public:
+ w83977tf_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual ~w83977tf_device();
+
+ void remap(int space_id, offs_t start, offs_t end) override;
+
+ auto gp20_reset() { return m_gp20_reset_callback.bind(); }
+ auto gp25_gatea20() { return m_gp25_gatea20_callback.bind(); }
+ auto irq1() { return m_irq1_callback.bind(); }
+ auto irq8() { return m_irq8_callback.bind(); }
+ auto irq9() { return m_irq9_callback.bind(); }
+// auto txd1() { return m_txd1_callback.bind(); }
+// auto ndtr1() { return m_ndtr1_callback.bind(); }
+// auto nrts1() { return m_nrts1_callback.bind(); }
+// auto txd2() { return m_txd2_callback.bind(); }
+// auto ndtr2() { return m_ndtr2_callback.bind(); }
+// auto nrts2() { return m_nrts2_callback.bind(); }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual space_config_vector memory_space_config() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+private:
+ const address_space_config m_space_config;
+
+ required_device<kbdc8042_device> m_kbdc;
+ required_device<ds12885_device> m_rtc;
+ required_device<pc_lpt_device> m_lpt;
+ memory_view m_logical_view;
+
+ devcb_write_line m_gp20_reset_callback;
+ devcb_write_line m_gp25_gatea20_callback;
+ devcb_write_line m_irq1_callback;
+ devcb_write_line m_irq8_callback;
+ devcb_write_line m_irq9_callback;
+// devcb_write_line m_txd1_callback;
+// devcb_write_line m_ndtr1_callback;
+// devcb_write_line m_nrts1_callback;
+// devcb_write_line m_txd2_callback;
+// devcb_write_line m_ndtr2_callback;
+// devcb_write_line m_nrts2_callback;
+
+ u8 m_index;
+ u8 m_logical_index;
+ bool m_activate[0xb];
+
+ u8 m_hefras;
+ u8 m_lockreg;
+ u8 m_lock_sequence;
+ u8 m_keyb_irq_line;
+ u8 m_mouse_irq_line;
+ u8 m_rtc_irq_line;
+ u8 m_lpt_irq_line;
+ u8 m_lpt_drq_line;
+ u8 m_lpt_mode;
+ u16 m_keyb_address[2];
+ u16 m_lpt_address;
+
+ uint8_t read(offs_t offset);
+ void write(offs_t offset, u8 data);
+ u8 cr26_r();
+ void cr26_w(offs_t offset, u8 data);
+
+ void config_map(address_map &map);
+
+ void logical_device_select_w(offs_t offset, u8 data);
+ template <unsigned N> u8 activate_r(offs_t offset);
+ template <unsigned N> void activate_w(offs_t offset, u8 data);
+
+ u8 keyb_irq_r(offs_t offset);
+ void keyb_irq_w(offs_t offset, u8 data);
+
+ u8 mouse_irq_r(offs_t offset);
+ void mouse_irq_w(offs_t offset, u8 data);
+
+ u8 keybc_status_r(offs_t offset);
+ void keybc_command_w(offs_t offset, u8 data);
+
+ u8 keyb_io_address_r(offs_t offset);
+ void keyb_io_address_w(offs_t offset, u8 data);
+
+ void kbdp21_gp25_gatea20_w(int state);
+ void kbdp20_gp20_reset_w(int state);
+
+ u8 rtc_r(offs_t offset);
+ void rtc_w(offs_t offset, u8 data);
+
+ u8 rtc_irq_r(offs_t offset);
+ void rtc_irq_w(offs_t offset, u8 data);
+
+ void irq_keyboard_w(int state);
+ void irq_mouse_w(int state);
+ void irq_rtc_w(int state);
+ void irq_parallel_w(int state);
+
+ void request_irq(int irq, int state);
+};
+
+DECLARE_DEVICE_TYPE(W83977TF, w83977tf_device);
+
+#endif // MAME_MACHINE_W83977TF_H
diff --git a/src/devices/machine/watchdog.cpp b/src/devices/machine/watchdog.cpp
index 7829709abff..ad0dba7b5be 100644
--- a/src/devices/machine/watchdog.cpp
+++ b/src/devices/machine/watchdog.cpp
@@ -2,8 +2,6 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- watchdog.c
-
Watchdog timer device.
***************************************************************************/
@@ -30,6 +28,9 @@ watchdog_timer_device::watchdog_timer_device(const machine_config &mconfig, cons
, m_vblank_count(0)
, m_time(attotime::zero)
, m_screen(*this, finder_base::DUMMY_TAG)
+ , m_enabled(false)
+ , m_reset_line(0)
+ , m_counter(0)
{
}
@@ -52,15 +53,13 @@ void watchdog_timer_device::device_validity_check(validity_checker &valid) const
//-------------------------------------------------
-// device_start - perform device-specific
-// startup
+// device_start - perform device-specific startup
//-------------------------------------------------
void watchdog_timer_device::device_start()
{
// initialize the watchdog
- m_counter = 0;
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(watchdog_timer_device::watchdog_expired), this);
if (m_vblank_count != 0)
{
@@ -68,7 +67,9 @@ void watchdog_timer_device::device_start()
if (m_screen)
m_screen->register_vblank_callback(vblank_state_delegate(&watchdog_timer_device::watchdog_vblank, this));
}
+
save_item(NAME(m_enabled));
+ save_item(NAME(m_reset_line));
save_item(NAME(m_counter));
}
@@ -87,10 +88,10 @@ void watchdog_timer_device::device_reset()
//-------------------------------------------------
-// device_timer - handle timer expiration events
+// watchdog_expired - handle expired timer
//-------------------------------------------------
-void watchdog_timer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(watchdog_timer_device::watchdog_expired)
{
watchdog_fired();
}
@@ -121,11 +122,13 @@ void watchdog_timer_device::watchdog_reset()
//-------------------------------------------------
-// watchdog_enable - reset the watchdog timer
+// watchdog_enable - enable the watchdog timer
//-------------------------------------------------
-void watchdog_timer_device::watchdog_enable(bool enable)
+void watchdog_timer_device::watchdog_enable(int state)
{
+ const bool enable = bool(state);
+
// when re-enabled, we reset our state
if (m_enabled != enable)
{
@@ -180,21 +183,67 @@ void watchdog_timer_device::watchdog_vblank(screen_device &screen, bool vblank_s
// 8-bit reset read/write handlers
//-------------------------------------------------
-void watchdog_timer_device::reset_w(u8 data) { watchdog_reset(); }
-u8 watchdog_timer_device::reset_r(address_space &space) { watchdog_reset(); return space.unmap(); }
+void watchdog_timer_device::reset_w(u8 data)
+{
+ watchdog_reset();
+}
+
+u8 watchdog_timer_device::reset_r(address_space &space)
+{
+ if (!machine().side_effects_disabled())
+ watchdog_reset();
+
+ return space.unmap();
+}
//-------------------------------------------------
// 16-bit reset read/write handlers
//-------------------------------------------------
-void watchdog_timer_device::reset16_w(u16 data) { watchdog_reset(); }
-u16 watchdog_timer_device::reset16_r(address_space &space) { watchdog_reset(); return space.unmap(); }
+void watchdog_timer_device::reset16_w(u16 data)
+{
+ watchdog_reset();
+}
+
+u16 watchdog_timer_device::reset16_r(address_space &space)
+{
+ if (!machine().side_effects_disabled())
+ watchdog_reset();
+
+ return space.unmap();
+}
//-------------------------------------------------
// 32-bit reset read/write handlers
//-------------------------------------------------
-void watchdog_timer_device::reset32_w(u32 data) { watchdog_reset(); }
-u32 watchdog_timer_device::reset32_r(address_space &space) { watchdog_reset(); return space.unmap(); }
+void watchdog_timer_device::reset32_w(u32 data)
+{
+ watchdog_reset();
+}
+
+u32 watchdog_timer_device::reset32_r(address_space &space)
+{
+ if (!machine().side_effects_disabled())
+ watchdog_reset();
+
+ return space.unmap();
+}
+
+
+//-------------------------------------------------
+// reset writeline handler
+//-------------------------------------------------
+
+void watchdog_timer_device::reset_line_w(int state)
+{
+ state = state ? 1 : 0;
+
+ // reset watchdog on rising edge
+ if (state && !m_reset_line)
+ watchdog_reset();
+
+ m_reset_line = state;
+}
diff --git a/src/devices/machine/watchdog.h b/src/devices/machine/watchdog.h
index 0c93a62ac01..56714bc4b9e 100644
--- a/src/devices/machine/watchdog.h
+++ b/src/devices/machine/watchdog.h
@@ -26,10 +26,10 @@ public:
// watchdog control
void watchdog_reset();
- void watchdog_enable(bool enable = true);
+ void watchdog_enable(int state = 1);
int32_t get_vblank_counter() const { return m_counter; }
- // read/write handlers
+ // watchdog reset read/write handlers (strobe on R/W pin)
void reset_w(u8 data = 0);
u8 reset_r(address_space &space);
void reset16_w(u16 data = 0);
@@ -37,12 +37,16 @@ public:
void reset32_w(u32 data = 0);
u32 reset32_r(address_space &space);
+ // watchdog reset writeline strobe
+ void reset_line_w(int state);
+
protected:
// device-level overrides
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(watchdog_expired);
private:
// internal helpers
@@ -56,6 +60,7 @@ private:
// internal state
bool m_enabled; // is the watchdog enabled?
+ int m_reset_line; // watchdog reset writeline state
int32_t m_counter; // counter for VBLANK tracking
emu_timer * m_timer; // timer for triggering reset
};
diff --git a/src/devices/machine/wd1000.cpp b/src/devices/machine/wd1000.cpp
index f8c879ef20e..109a3776df4 100644
--- a/src/devices/machine/wd1000.cpp
+++ b/src/devices/machine/wd1000.cpp
@@ -7,7 +7,7 @@
***************************************************************************/
#include "emu.h"
-#include "machine/wd1000.h"
+#include "wd1000.h"
//**************************************************************************
// DEVICE DEFINITIONS
@@ -57,13 +57,9 @@ void wd1000_device::set_sector_base(uint32_t base)
void wd1000_device::device_start()
{
- // Resolve callbacks
- m_intrq_cb.resolve();
- m_drq_cb.resolve();
-
// Allocate timers
- m_seek_timer = timer_alloc(TIMER_SEEK);
- m_drq_timer = timer_alloc(TIMER_DRQ);
+ m_seek_timer = timer_alloc(FUNC(wd1000_device::update_seek), this);
+ m_drq_timer = timer_alloc(FUNC(wd1000_device::delayed_drq), this);
// Empty buffer.
m_buffer_index = 0;
@@ -111,49 +107,47 @@ void wd1000_device::device_reset()
}
//-------------------------------------------------
-// device_timer - device-specific timer
+// update_seek -
//-------------------------------------------------
-void wd1000_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(wd1000_device::update_seek)
{
- switch (tid)
- {
- case TIMER_SEEK:
-
- m_drive_cylinder[drive()] = param;
- m_status |= S_SC;
-
- switch (m_command >> 4)
- {
- case CMD_RESTORE:
- cmd_restore();
- break;
-
- case CMD_SEEK:
- cmd_seek();
- break;
+ m_drive_cylinder[drive()] = param;
+ m_status |= S_SC;
- case CMD_READ_SECTOR:
- cmd_read_sector();
- break;
+ switch (m_command >> 4)
+ {
+ case CMD_RESTORE:
+ cmd_restore();
+ break;
- case CMD_WRITE_SECTOR:
- cmd_write_sector();
- break;
+ case CMD_SEEK:
+ cmd_seek();
+ break;
- case CMD_WRITE_FORMAT:
- cmd_format_sector();
- break;
- }
+ case CMD_READ_SECTOR:
+ cmd_read_sector();
+ break;
+ case CMD_WRITE_SECTOR:
+ cmd_write_sector();
break;
- case TIMER_DRQ:
- set_drq();
+ case CMD_WRITE_FORMAT:
+ cmd_format_sector();
break;
}
}
+//-------------------------------------------------
+// delayed_drq - set DRQ after a necessary delay
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(wd1000_device::delayed_drq)
+{
+ set_drq();
+}
+
void wd1000_device::set_error(int error)
{
if (error)
@@ -187,8 +181,7 @@ void wd1000_device::set_drq()
if ((m_status & S_DRQ) == 0)
{
m_status |= S_DRQ;
- if (!m_drq_cb.isnull())
- m_drq_cb(true);
+ m_drq_cb(true);
}
}
@@ -197,8 +190,7 @@ void wd1000_device::drop_drq()
if (m_status & S_DRQ)
{
m_status &= ~S_DRQ;
- if (!m_drq_cb.isnull())
- m_drq_cb(false);
+ m_drq_cb(false);
}
}
@@ -240,36 +232,36 @@ void wd1000_device::end_command()
int wd1000_device::get_lbasector()
{
- hard_disk_file *file = m_drives[drive()]->get_hard_disk_file();
- hard_disk_info *info = hard_disk_get_info(file);
+ harddisk_image_device *file = m_drives[drive()];
+ const auto &info = file->get_info();
int lbasector;
- if (m_cylinder > info->cylinders)
+ if (m_cylinder > info.cylinders)
{
- logerror("%s: Unexpected cylinder %d for range 0 to %d\n", machine().describe_context(), m_cylinder, info->cylinders - 1);
+ logerror("%s: Unexpected cylinder %d for range 0 to %d\n", machine().describe_context(), m_cylinder, info.cylinders - 1);
}
- if (head() >= info->heads)
+ if (head() >= info.heads)
{
- logerror("%s: Unexpected head %d for range 0 to %d\n", machine().describe_context(), head(), info->heads - 1);
+ logerror("%s: Unexpected head %d for range 0 to %d\n", machine().describe_context(), head(), info.heads - 1);
}
int16_t sector = m_sector_number - m_sector_base;
- if (sector < 0 || sector >= info->sectors)
+ if (sector < 0 || sector >= info.sectors)
{
- logerror("%s: Unexpected sector number %d for range %d to %d\n", machine().describe_context(), m_sector_number, m_sector_base, info->sectors + m_sector_base);
+ logerror("%s: Unexpected sector number %d for range %d to %d\n", machine().describe_context(), m_sector_number, m_sector_base, info.sectors + m_sector_base);
}
- if (sector_bytes() != info->sectorbytes)
+ if (sector_bytes() != info.sectorbytes)
{
- logerror("%s: Unexpected sector bytes %d, expected %d\n", machine().describe_context(), sector_bytes(), info->sectorbytes);
+ logerror("%s: Unexpected sector bytes %d, expected %d\n", machine().describe_context(), sector_bytes(), info.sectorbytes);
}
lbasector = m_cylinder;
- lbasector *= info->heads;
+ lbasector *= info.heads;
lbasector += head();
- lbasector *= info->sectors;
+ lbasector *= info.sectors;
lbasector += sector;
return lbasector;
@@ -575,10 +567,10 @@ void wd1000_device::cmd_restore()
// so it is not necessary to guard that case in these functions.
void wd1000_device::cmd_read_sector()
{
- hard_disk_file *file = m_drives[drive()]->get_hard_disk_file();
+ harddisk_image_device *file = m_drives[drive()];
uint8_t dma = BIT(m_command, 3);
- hard_disk_read(file, get_lbasector(), m_buffer);
+ file->read(get_lbasector(), m_buffer);
m_buffer_index = 0;
m_buffer_end = 512;
@@ -596,21 +588,21 @@ void wd1000_device::cmd_read_sector()
void wd1000_device::cmd_write_sector()
{
- hard_disk_file *file = m_drives[drive()]->get_hard_disk_file();
+ harddisk_image_device *file = m_drives[drive()];
if (m_buffer_index != sector_bytes())
{
logerror("%s: Unexpected unfilled buffer on write, only %d or %d bytes filled\n", machine().describe_context(), m_buffer_index, sector_bytes());
}
- hard_disk_write(file, get_lbasector(), m_buffer);
+ file->write(get_lbasector(), m_buffer);
end_command();
}
void wd1000_device::cmd_format_sector()
{
- hard_disk_file *file = m_drives[drive()]->get_hard_disk_file();
+ harddisk_image_device *file = m_drives[drive()];
uint8_t buffer[512];
// The m_buffer appears to be loaded with an interleave table which is
@@ -619,7 +611,7 @@ void wd1000_device::cmd_format_sector()
for (int i = 0; i < m_sector_count; i++)
{
std::fill(std::begin(buffer), std::end(buffer), 0);
- hard_disk_write(file, get_lbasector(), buffer);
+ file->write(get_lbasector(), buffer);
}
m_sector_count = 0;
diff --git a/src/devices/machine/wd1000.h b/src/devices/machine/wd1000.h
index ac2219e8425..4e2882ee81c 100644
--- a/src/devices/machine/wd1000.h
+++ b/src/devices/machine/wd1000.h
@@ -45,7 +45,9 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_seek);
+ TIMER_CALLBACK_MEMBER(delayed_drq);
private:
enum
@@ -77,12 +79,6 @@ private:
CMD_SEEK = 7
};
- enum
- {
- TIMER_SEEK,
- TIMER_DRQ,
- };
-
void set_error(int error);
void set_intrq(int state);
void set_drq();
diff --git a/src/devices/machine/wd1010.cpp b/src/devices/machine/wd1010.cpp
index a330d6c7671..5a01446c946 100644
--- a/src/devices/machine/wd1010.cpp
+++ b/src/devices/machine/wd1010.cpp
@@ -9,12 +9,11 @@
#include "emu.h"
#include "wd1010.h"
-//#define LOG_GENERAL (1U << 0)
-#define LOG_CMD (1U << 1)
-#define LOG_INT (1U << 2)
-#define LOG_SEEK (1U << 3)
-#define LOG_REGS (1U << 4)
-#define LOG_DATA (1U << 5)
+#define LOG_CMD (1U << 1)
+#define LOG_INT (1U << 2)
+#define LOG_SEEK (1U << 3)
+#define LOG_REGS (1U << 4)
+#define LOG_DATA (1U << 5)
#define VERBOSE (LOG_CMD | LOG_INT | LOG_SEEK | LOG_REGS | LOG_DATA)
//#define LOG_OUTPUT_STREAM std::cout
@@ -51,7 +50,7 @@ wd1010_device::wd1010_device(const machine_config &mconfig, const char *tag, dev
m_out_bcr_cb(*this),
m_out_dirin_cb(*this),
m_out_wg_cb(*this),
- m_in_data_cb(*this),
+ m_in_data_cb(*this, 0),
m_out_data_cb(*this),
m_intrq(0),
m_brdy(0),
@@ -85,20 +84,10 @@ void wd1010_device::device_start()
m_drives[i].sector = 0;
}
- // resolve callbacks
- m_out_intrq_cb.resolve_safe();
- m_out_bdrq_cb.resolve_safe();
- m_out_bcs_cb.resolve_safe();
- m_out_bcr_cb.resolve_safe();
- m_out_dirin_cb.resolve_safe();
- m_out_wg_cb.resolve_safe();
- m_in_data_cb.resolve_safe(0);
- m_out_data_cb.resolve_safe();
-
// allocate timer
- m_seek_timer = timer_alloc(TIMER_SEEK);
- m_read_timer = timer_alloc(TIMER_READ);
- m_write_timer = timer_alloc(TIMER_WRITE);
+ m_seek_timer = timer_alloc(FUNC(wd1010_device::update_seek), this);
+ m_read_timer = timer_alloc(FUNC(wd1010_device::delayed_read), this);
+ m_write_timer = timer_alloc(FUNC(wd1010_device::delayed_write), this);
// register for save states
save_item(NAME(m_intrq));
@@ -112,6 +101,7 @@ void wd1010_device::device_start()
save_item(NAME(m_cylinder));
save_item(NAME(m_sdh));
save_item(NAME(m_status));
+ save_item(NAME(m_head));
}
//-------------------------------------------------
@@ -123,59 +113,62 @@ void wd1010_device::device_reset()
}
//-------------------------------------------------
-// device_timer - device-specific timer
+// update_seek -
//-------------------------------------------------
-void wd1010_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(wd1010_device::update_seek)
{
- switch (tid)
+ if ((m_command >> 4) != CMD_SCAN_ID)
{
- case TIMER_SEEK:
-
- if ((m_command >> 4) != CMD_SCAN_ID)
- {
- LOGSEEK("Seek complete\n");
- m_drives[drive()].cylinder = param;
- m_status |= STATUS_SC;
- }
+ LOGSEEK("Seek complete\n");
+ m_drives[drive()].cylinder = param;
+ m_status |= STATUS_SC;
+ }
- switch (m_command >> 4)
- {
- case CMD_RESTORE:
- cmd_restore();
- break;
-
- case CMD_SEEK:
- cmd_seek();
- break;
-
- case CMD_READ_SECTOR:
- cmd_read_sector();
- break;
-
- case CMD_WRITE_SECTOR:
- case CMD_WRITE_FORMAT:
- cmd_write_sector();
- break;
-
- case CMD_SCAN_ID:
- cmd_scan_id();
- break;
- }
+ switch (m_command >> 4)
+ {
+ case CMD_RESTORE:
+ cmd_restore();
+ break;
+ case CMD_SEEK:
+ cmd_seek();
break;
- case TIMER_READ:
+ case CMD_READ_SECTOR:
cmd_read_sector();
break;
- case TIMER_WRITE:
+ case CMD_WRITE_SECTOR:
+ case CMD_WRITE_FORMAT:
cmd_write_sector();
break;
+
+ case CMD_SCAN_ID:
+ cmd_scan_id();
+ break;
}
}
//-------------------------------------------------
+// delayed_read -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(wd1010_device::delayed_read)
+{
+ cmd_read_sector();
+}
+
+//-------------------------------------------------
+// delayed_write -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(wd1010_device::delayed_write)
+{
+ cmd_write_sector();
+}
+
+//-------------------------------------------------
// set_error - set error and adjust status
//-------------------------------------------------
@@ -301,14 +294,14 @@ void wd1010_device::end_command()
int wd1010_device::get_lbasector()
{
- hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file();
- hard_disk_info *info = hard_disk_get_info(file);
+ harddisk_image_device *file = m_drives[drive()].drive;
+ const auto &info = file->get_info();
int lbasector;
lbasector = m_cylinder;
- lbasector *= info->heads;
+ lbasector *= info.heads;
lbasector += head();
- lbasector *= info->sectors;
+ lbasector *= info.sectors;
lbasector += m_sector_number;
return lbasector;
@@ -332,6 +325,14 @@ void wd1010_device::brdy_w(int state)
m_brdy = state;
}
+void wd1010_device::sc_w(int state)
+{
+ if (state)
+ m_status |= STATUS_SC;
+ else
+ m_status &= ~STATUS_SC;
+}
+
int wd1010_device::sc_r()
{
return m_status & STATUS_SC ? 1 : 0;
@@ -525,11 +526,11 @@ void wd1010_device::cmd_read_sector()
}
}
- hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file();
- hard_disk_info *info = hard_disk_get_info(file);
+ harddisk_image_device *file = m_drives[drive()].drive;
+ const auto &info = file->get_info();
// verify that we can read
- if (head() > info->heads)
+ if (head() > info.heads)
{
// out of range
LOG("--> Head out of range, aborting\n");
@@ -548,7 +549,7 @@ void wd1010_device::cmd_read_sector()
LOGDATA("--> Transferring sector to buffer (lba = %08x)\n", get_lbasector());
- hard_disk_read(file, get_lbasector(), buffer);
+ file->read(get_lbasector(), buffer);
for (int i = 0; i < 512; i++)
m_out_data_cb(buffer[i]);
@@ -593,7 +594,7 @@ void wd1010_device::cmd_write_sector()
return;
}
- hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file();
+ harddisk_image_device *file = m_drives[drive()].drive;
uint8_t buffer[512];
set_bdrq(0);
@@ -617,7 +618,7 @@ void wd1010_device::cmd_write_sector()
buffer[i] = m_in_data_cb();
}
- hard_disk_write(file, get_lbasector(), buffer);
+ file->write(get_lbasector(), buffer);
// save last read head and sector number
m_drives[drive()].head = head();
diff --git a/src/devices/machine/wd1010.h b/src/devices/machine/wd1010.h
index 268ab3a63ca..70d8a687163 100644
--- a/src/devices/machine/wd1010.h
+++ b/src/devices/machine/wd1010.h
@@ -40,16 +40,24 @@ public:
void drdy_w(int state);
void brdy_w(int state);
+ void sc_w(int state);
// actually inputs to the controller from the drive
int sc_r();
int tk000_r();
+ // HACK: head selection is not actually controlled by the wd1010, but this emulation currently
+ // works as if it does; this function allows heads beyond the 3-bit range of the sdh register.
+ void head_w(uint8_t head) { m_head = head; }
+
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_seek);
+ TIMER_CALLBACK_MEMBER(delayed_read);
+ TIMER_CALLBACK_MEMBER(delayed_write);
private:
enum
@@ -86,13 +94,6 @@ private:
CMD_SEEK = 7
};
- enum
- {
- TIMER_SEEK,
- TIMER_READ,
- TIMER_WRITE
- };
-
void set_error(int error);
void set_intrq(int state);
void set_bdrq(int state);
@@ -102,7 +103,7 @@ private:
int get_lbasector();
// extract values from sdh
- int head() { return (m_sdh >> 0) & 0x07; }
+ int head() { return m_head; }
int drive() { return (m_sdh >> 3) & 0x03; }
int sector_size()
{
@@ -151,6 +152,7 @@ private:
uint16_t m_cylinder;
uint8_t m_sdh;
uint8_t m_status;
+ uint8_t m_head;
};
// device type definition
diff --git a/src/devices/machine/wd11c00_17.cpp b/src/devices/machine/wd11c00_17.cpp
index 981672a70d9..79cbd4f4ef2 100644
--- a/src/devices/machine/wd11c00_17.cpp
+++ b/src/devices/machine/wd11c00_17.cpp
@@ -7,7 +7,7 @@
**********************************************************************/
#include "emu.h"
-#include "machine/wd11c00_17.h"
+#include "wd11c00_17.h"
#define VERBOSE 1
#include "logmacro.h"
@@ -183,10 +183,10 @@ wd11c00_17_device::wd11c00_17_device(const machine_config &mconfig, const char *
, m_out_busy_cb(*this)
, m_out_req_cb(*this)
, m_out_ra3_cb(*this)
- , m_in_rd322_cb(*this)
- , m_in_ramcs_cb(*this)
+ , m_in_rd322_cb(*this, 0)
+ , m_in_ramcs_cb(*this, 0)
, m_out_ramwr_cb(*this)
- , m_in_cs1010_cb(*this)
+ , m_in_cs1010_cb(*this, 0)
, m_out_cs1010_cb(*this)
, m_status(0)
, m_ra(0)
@@ -205,18 +205,6 @@ wd11c00_17_device::wd11c00_17_device(const machine_config &mconfig, const char *
void wd11c00_17_device::device_start()
{
- // resolve callbacks
- m_out_irq5_cb.resolve_safe();
- m_out_drq3_cb.resolve_safe();
- m_out_mr_cb.resolve_safe();
- m_out_busy_cb.resolve_safe();
- m_out_req_cb.resolve_safe();
- m_out_ra3_cb.resolve_safe();
- m_in_rd322_cb.resolve_safe(0);
- m_in_ramcs_cb.resolve_safe(0);
- m_out_ramwr_cb.resolve_safe();
- m_in_cs1010_cb.resolve_safe(0);
- m_out_cs1010_cb.resolve_safe();
}
diff --git a/src/devices/machine/wd2010.cpp b/src/devices/machine/wd2010.cpp
index 486d22b47f0..28f7b8ebbc3 100644
--- a/src/devices/machine/wd2010.cpp
+++ b/src/devices/machine/wd2010.cpp
@@ -36,7 +36,7 @@ UNIMPLEMENTED FEATURES :
**********************************************************************/
#include "emu.h"
-#include "machine/wd2010.h"
+#include "wd2010.h"
#define VERBOSE 1
#include "logmacro.h"
@@ -158,18 +158,18 @@ wd2010_device::wd2010_device(const machine_config &mconfig, const char *tag, dev
, m_out_intrq_cb(*this)
, m_out_bdrq_cb(*this)
, m_out_bcr_cb(*this)
- , m_in_bcs_cb(*this)
- , m_in_brdy_cb(*this)
+ , m_in_bcs_cb(*this, 0)
+ , m_in_brdy_cb(*this, 0)
, m_out_bcs_cb(*this)
, m_out_dirin_cb(*this)
, m_out_step_cb(*this)
, m_out_rwc_cb(*this)
, m_out_wg_cb(*this)
- , m_in_drdy_cb(*this)
- , m_in_index_cb(*this)
- , m_in_wf_cb(*this)
- , m_in_tk000_cb(*this)
- , m_in_sc_cb(*this)
+ , m_in_drdy_cb(*this, 0)
+ , m_in_index_cb(*this, 0)
+ , m_in_wf_cb(*this, 0)
+ , m_in_tk000_cb(*this, 0)
+ , m_in_sc_cb(*this, 0)
, m_status(0)
, m_error(0)
{
@@ -182,38 +182,13 @@ wd2010_device::wd2010_device(const machine_config &mconfig, const char *tag, dev
void wd2010_device::device_start()
{
- // resolve callbacks
- m_out_intrq_cb.resolve_safe();
- m_out_bdrq_cb.resolve_safe();
- m_out_bcr_cb.resolve_safe();
- m_in_bcs_cb.resolve_safe(0);
-
- m_in_brdy_cb.resolve_safe(0);
-
- m_out_bcs_cb.resolve_safe();
- m_out_dirin_cb.resolve_safe();
- m_out_step_cb.resolve_safe();
- m_out_rwc_cb.resolve_safe();
- m_out_wg_cb.resolve_safe();
- m_in_drdy_cb.resolve_safe(0);
- m_in_index_cb.resolve_safe(0);
- m_in_wf_cb.resolve_safe(0);
- m_in_tk000_cb.resolve_safe(0);
- m_in_sc_cb.resolve_safe(0);
-
- /* allocate a timer for commands */
- cmd_timer = timer_alloc(0);
- complete_write_when_buffer_ready_high = timer_alloc(1);
- deassert_write_when_buffer_ready_low = timer_alloc(2);
- deassert_read_when_buffer_ready_high = timer_alloc(3);
+ // allocate a timer for commands
+ m_cmd_timer = timer_alloc(FUNC(wd2010_device::command_complete), this);
+ m_complete_write_timer = timer_alloc(FUNC(wd2010_device::complete_write), this);
+ m_deassert_write_timer = timer_alloc(FUNC(wd2010_device::deassert_write), this);
+ m_deassert_read_timer = timer_alloc(FUNC(wd2010_device::deassert_read), this);
}
-// timers
-#define COMMAND_TIMER 0
-#define COMPLETE_WRITE_SECTOR 1
-#define DE_ASSERT_WRITE 2
-#define DE_ASSERT_READ 3
-
//-------------------------------------------------
// device_reset - device-specific reset
@@ -430,7 +405,7 @@ void wd2010_device::restore(uint8_t data)
// NOTE: calculation needs 'data' (extracted from command register)
float step_ms = SETTLING_MS + LATENCY_MS + ( (float)sqrt(1.0 * step_pulses) * STEP_RATE_MS );
- cmd_timer->adjust(attotime::from_usec(1000 * step_ms), newstatus);
+ m_cmd_timer->adjust(attotime::from_usec(1000 * step_ms), newstatus);
return;
}
@@ -532,7 +507,7 @@ void wd2010_device::seek(uint8_t data)
m_task_file[TASK_FILE_CYLINDER_LOW] = (m_present_cylinder - ((m_task_file[TASK_FILE_CYLINDER_HIGH] << 8) )) & 0xff;
//LOGERROR("SEEK (END) - m_present_cylinder = %u SDH CYL L/H %02x / %02x\n", m_present_cylinder,m_task_file[TASK_FILE_CYLINDER_LOW],m_task_file[TASK_FILE_CYLINDER_HIGH]);
- cmd_timer->adjust(attotime::from_usec(1000 * step_ms), newstatus);
+ m_cmd_timer->adjust(attotime::from_usec(1000 * step_ms), newstatus);
}
//-------------------------------------------------
@@ -644,7 +619,7 @@ void wd2010_device::read_sector(uint8_t data)
// NOTE : (intrq_at_end = 0) - INTRQ occurs when the command is completed
newstatus |= (m_status & ~(STATUS_CIP | STATUS_DRQ)) | intrq_at_end; // de-assert CIP + DRQ (BSY already reset)
- deassert_read_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus); // complete command ON *RISING EDGE * OF BUFFER_READY
+ m_deassert_read_timer->adjust(attotime::from_usec(1), newstatus); // complete command ON *RISING EDGE * OF BUFFER_READY
}
@@ -671,7 +646,7 @@ void wd2010_device::write_sector(uint8_t data)
m_out_bdrq_cb(1);
// WAIT UNTIL BRDY ASSERTED (-> timer):
- complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), data); // 1 usec
+ m_complete_write_timer->adjust(attotime::from_usec(1), data); // 1 usec
}
@@ -728,7 +703,7 @@ void wd2010_device::complete_write_sector(uint8_t data)
} // --------------------------------------------------------
// 'complete_cmd' ON THE FALLING EDGE OF _BUFFER_READY_ ( set by WRITE_SECTOR ) !
- deassert_write_when_buffer_ready_low->adjust(attotime::from_usec(1), newstatus);
+ m_deassert_write_timer->adjust(attotime::from_usec(1), newstatus);
}
// ******************************************************
@@ -862,7 +837,7 @@ void wd2010_device::format(uint8_t data)
m_out_wg_cb(0); // (transition from WG 1 -> 0). Actual write.
// ** DELAY INTRQ UNTIL WRITE IS COMPLETE :
- complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus | STATUS_DRQ); // 1 USECs
+ m_complete_write_timer->adjust(attotime::from_usec(1), newstatus | STATUS_DRQ); // 1 USECs
}
@@ -875,65 +850,63 @@ void wd2010_device::buffer_ready(bool state)
}
-void wd2010_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(wd2010_device::command_complete)
{
- switch (tid)
- {
- case COMMAND_TIMER:
- cmd_timer->adjust(attotime::never);
- complete_immediate(param);
- break;
-
- case COMPLETE_WRITE_SECTOR: // when BUFFER_READY -> HIGH
- if (is_buffer_ready)
- {
- complete_write_when_buffer_ready_high->adjust(attotime::never);
- complete_write_sector(param);
- }
- else
- {
- complete_write_when_buffer_ready_high->reset();
- complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
- }
- break;
+ m_cmd_timer->adjust(attotime::never);
+ complete_immediate(param);
+}
- case DE_ASSERT_WRITE: // waiting for BUFFER_READY -> LOW
- if (!(is_buffer_ready))
- {
- deassert_write_when_buffer_ready_low->adjust(attotime::never);
- complete_immediate(param);
- }
- else
- {
- deassert_write_when_buffer_ready_low->reset();
- deassert_write_when_buffer_ready_low->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
- }
- break;
+TIMER_CALLBACK_MEMBER(wd2010_device::complete_write)
+{
+ // when BUFFER_READY -> HIGH
+ if (is_buffer_ready)
+ {
+ m_complete_write_timer->adjust(attotime::never);
+ complete_write_sector(param);
+ }
+ else
+ {
+ m_complete_write_timer->reset();
+ m_complete_write_timer->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
+ }
+}
- case DE_ASSERT_READ: // when BUFFER_READY -> HIGH
- if (is_buffer_ready)
- {
- deassert_read_when_buffer_ready_high->adjust(attotime::never);
+TIMER_CALLBACK_MEMBER(wd2010_device::deassert_write)
+{
+ // waiting for BUFFER_READY -> LOW
+ if (!(is_buffer_ready))
+ {
+ m_deassert_write_timer->adjust(attotime::never);
+ complete_immediate(param);
+ }
+ else
+ {
+ m_deassert_write_timer->reset();
+ m_deassert_write_timer->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
+ }
+}
- m_error &= ~ERROR_ID;
- param &= ~STATUS_ERR;
+TIMER_CALLBACK_MEMBER(wd2010_device::deassert_read)
+{
+ // when BUFFER_READY -> HIGH
+ if (is_buffer_ready)
+ {
+ m_deassert_read_timer->adjust(attotime::never);
- m_out_bdrq_cb(0);
- complete_immediate(param);
- }
- else
- {
- deassert_read_when_buffer_ready_high->reset();
- deassert_read_when_buffer_ready_high->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
- }
- break;
+ m_error &= ~ERROR_ID;
+ param &= ~STATUS_ERR;
- default:
- break;
+ m_out_bdrq_cb(0);
+ complete_immediate(param);
+ }
+ else
+ {
+ m_deassert_read_timer->reset();
+ m_deassert_read_timer->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
}
}
-// Called by 'device_timer' -
+// Called by timer callbacks -
void wd2010_device::complete_immediate(uint8_t status)
{
// re-evaluate external signals at end of command
@@ -964,5 +937,5 @@ void wd2010_device::complete_immediate(uint8_t status)
void wd2010_device::complete_cmd(uint8_t status)
{
- cmd_timer->adjust(attotime::from_msec(1), status);
+ m_cmd_timer->adjust(attotime::from_msec(1), status);
}
diff --git a/src/devices/machine/wd2010.h b/src/devices/machine/wd2010.h
index 1617f886ed6..a39935326ba 100644
--- a/src/devices/machine/wd2010.h
+++ b/src/devices/machine/wd2010.h
@@ -50,7 +50,10 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ TIMER_CALLBACK_MEMBER(command_complete);
+ TIMER_CALLBACK_MEMBER(complete_write);
+ TIMER_CALLBACK_MEMBER(deassert_write);
+ TIMER_CALLBACK_MEMBER(deassert_read);
private:
void compute_correction(uint8_t data);
@@ -84,10 +87,10 @@ private:
uint8_t m_error;
uint8_t m_task_file[8];
- emu_timer *cmd_timer;
- emu_timer *complete_write_when_buffer_ready_high;
- emu_timer *deassert_write_when_buffer_ready_low;
- emu_timer *deassert_read_when_buffer_ready_high;
+ emu_timer *m_cmd_timer;
+ emu_timer *m_complete_write_timer;
+ emu_timer *m_deassert_write_timer;
+ emu_timer *m_deassert_read_timer;
void complete_write_sector(uint8_t status);
void complete_cmd(uint8_t status);
diff --git a/src/devices/machine/wd33c9x.cpp b/src/devices/machine/wd33c9x.cpp
index 89d89e30051..a8aec27d45d 100644
--- a/src/devices/machine/wd33c9x.cpp
+++ b/src/devices/machine/wd33c9x.cpp
@@ -18,14 +18,14 @@
#include "emu.h"
#include "wd33c9x.h"
-#define LOG_READS (1 << 0)
-#define LOG_WRITES (1 << 1)
-#define LOG_COMMANDS (1 << 2)
-#define LOG_ERRORS (1 << 3)
-#define LOG_MISC (1 << 4)
-#define LOG_LINES (1 << 5)
-#define LOG_STATE (1 << 6)
-#define LOG_STEP (1 << 7)
+#define LOG_READS (1U << 1)
+#define LOG_WRITES (1U << 2)
+#define LOG_COMMANDS (1U << 3)
+#define LOG_ERRORS (1U << 4)
+#define LOG_MISC (1U << 5)
+#define LOG_LINES (1U << 6)
+#define LOG_STATE (1U << 7)
+#define LOG_STEP (1U << 8)
#define LOG_REGS (LOG_READS | LOG_WRITES)
#define LOG_ALL (LOG_REGS | LOG_COMMANDS | LOG_ERRORS | LOG_MISC | LOG_LINES | LOG_STATE | LOG_STEP)
@@ -388,9 +388,7 @@ wd33c9x_base_device::wd33c9x_base_device(const machine_config &mconfig, device_t
void wd33c9x_base_device::device_start()
{
- m_irq_cb.resolve_safe();
- m_drq_cb.resolve_safe();
- m_timer = timer_alloc(0);
+ m_timer = timer_alloc(FUNC(wd33c9x_base_device::update_step), this);
save_item(NAME(m_addr));
save_item(NAME(m_regs));
save_item(NAME(m_command_length));
@@ -443,10 +441,10 @@ void wd33c9x_base_device::device_reset()
//-------------------------------------------------
-// device_timer - device-specific timer handler
+// update_step -
//-------------------------------------------------
-void wd33c9x_base_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(wd33c9x_base_device::update_step)
{
step(true);
}
@@ -670,7 +668,7 @@ void wd33c9x_base_device::indir_reg_w(uint8_t data)
// reset - Host reset line handler
//-------------------------------------------------
-WRITE_LINE_MEMBER(wd33c9x_base_device::reset_w)
+void wd33c9x_base_device::reset_w(int state)
{
if (state) {
LOGMASKED(LOG_LINES, "Reset via MR line\n");
@@ -1344,7 +1342,7 @@ void wd33c9x_base_device::step(bool timeout)
if (sat && m_xfr_phase == S_PHASE_MSG_IN) {
if (m_regs[COMMAND_PHASE] <= COMMAND_PHASE_CP_BYTES_C) {
switch (m_last_message) {
- case SM_SAVE_DATA_PTR:
+ case SM_SAVE_DATA_POINTER:
set_scsi_state(FINISHED);
irq_fifo_push(SCSI_STATUS_SAVE_DATA_POINTERS);
m_regs[COMMAND_PHASE] = COMMAND_PHASE_SAVE_DATA_POINTER;
diff --git a/src/devices/machine/wd33c9x.h b/src/devices/machine/wd33c9x.h
index bdfb84fe8d9..012c4f5921f 100644
--- a/src/devices/machine/wd33c9x.h
+++ b/src/devices/machine/wd33c9x.h
@@ -32,7 +32,7 @@ public:
void indir_reg_w(uint8_t data);
// Master Reset (MR) Interface
- DECLARE_WRITE_LINE_MEMBER(reset_w);
+ void reset_w(int state);
// DMA Interface (for use with DRQ)
uint8_t dma_r();
@@ -43,7 +43,8 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(update_step);
virtual void scsi_ctrl_changed() override;
diff --git a/src/devices/machine/wd7600.cpp b/src/devices/machine/wd7600.cpp
index e1f81e0282b..226520e1dc7 100644
--- a/src/devices/machine/wd7600.cpp
+++ b/src/devices/machine/wd7600.cpp
@@ -13,7 +13,7 @@
*/
#include "emu.h"
-#include "machine/wd7600.h"
+#include "wd7600.h"
#define VERBOSE 1
#include "logmacro.h"
@@ -81,7 +81,7 @@ void wd7600_device::device_add_mconfig(machine_config & config)
wd7600_device::wd7600_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, WD7600, tag, owner, clock),
- m_read_ior(*this),
+ m_read_ior(*this, 0),
m_write_iow(*this),
m_write_tc(*this),
m_write_hold(*this),
@@ -121,17 +121,6 @@ void wd7600_device::device_start()
if (!m_ram->started())
throw device_missing_dependencies();
- // resolve callbacks
- m_read_ior.resolve_safe(0);
- m_write_iow.resolve_safe();
- m_write_tc.resolve_safe();
- m_write_hold.resolve_safe();
- m_write_nmi.resolve_safe();
- m_write_intr.resolve_safe();
- m_write_cpureset.resolve_safe();
- m_write_a20m.resolve_safe();
- m_write_spkr.resolve_safe();
-
m_space = &m_cpu->space(AS_PROGRAM);
m_space_io = &m_cpu->space(AS_IO);
@@ -165,7 +154,8 @@ void wd7600_device::device_start()
m_space_io->install_readwrite_handler(0x0060, 0x0061, read8smo_delegate(*this, FUNC(wd7600_device::keyb_data_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_data_w)), 0x00ff);
m_space_io->install_readwrite_handler(0x0060, 0x0061, read8smo_delegate(*this, FUNC(wd7600_device::portb_r)), write8smo_delegate(*this, FUNC(wd7600_device::portb_w)), 0xff00);
m_space_io->install_readwrite_handler(0x0064, 0x0065, read8smo_delegate(*this, FUNC(wd7600_device::keyb_status_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_cmd_w)), 0x00ff);
- m_space_io->install_readwrite_handler(0x0070, 0x007f, read8sm_delegate(*m_rtc, FUNC(mc146818_device::read)), write8sm_delegate(*this, FUNC(wd7600_device::rtc_w)), 0xffff);
+ m_space_io->install_write_handler(0x0070, 0x007f, write8smo_delegate(*this, FUNC(wd7600_device::rtc_nmi_w)), 0x00ff);
+ m_space_io->install_readwrite_handler(0x0070, 0x007f, read8smo_delegate(*m_rtc, FUNC(mc146818_device::data_r)), write8smo_delegate(*m_rtc, FUNC(mc146818_device::data_w)), 0xff00);
m_space_io->install_readwrite_handler(0x0080, 0x008f, read8sm_delegate(*this, FUNC(wd7600_device::dma_page_r)), write8sm_delegate(*this, FUNC(wd7600_device::dma_page_w)), 0xffff);
m_space_io->install_readwrite_handler(0x0092, 0x0093, read8smo_delegate(*this, FUNC(wd7600_device::a20_reset_r)), write8smo_delegate(*this, FUNC(wd7600_device::a20_reset_w)), 0x00ff);
m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8sm_delegate(*m_pic2, FUNC(pic8259_device::read)), write8sm_delegate(*m_pic2, FUNC(pic8259_device::write)), 0xffff);
@@ -187,7 +177,8 @@ void wd7600_device::device_start()
m_space_io->install_readwrite_handler(0x0060, 0x0063, read8smo_delegate(*this, FUNC(wd7600_device::keyb_data_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_data_w)), 0x000000ff);
m_space_io->install_readwrite_handler(0x0060, 0x0063, read8smo_delegate(*this, FUNC(wd7600_device::portb_r)), write8smo_delegate(*this, FUNC(wd7600_device::portb_w)), 0x0000ff00);
m_space_io->install_readwrite_handler(0x0064, 0x0067, read8smo_delegate(*this, FUNC(wd7600_device::keyb_status_r)), write8smo_delegate(*this, FUNC(wd7600_device::keyb_cmd_w)), 0x000000ff);
- m_space_io->install_readwrite_handler(0x0070, 0x007f, read8sm_delegate(*m_rtc, FUNC(mc146818_device::read)), write8sm_delegate(*this, FUNC(wd7600_device::rtc_w)), 0x0000ffff);
+ m_space_io->install_write_handler(0x0070, 0x007f, write8smo_delegate(*this, FUNC(wd7600_device::rtc_nmi_w)), 0x000000ff);
+ m_space_io->install_readwrite_handler(0x0070, 0x007f, read8smo_delegate(*m_rtc, FUNC(mc146818_device::data_r)), write8smo_delegate(*m_rtc, FUNC(mc146818_device::data_w)), 0x0000ff00);
m_space_io->install_readwrite_handler(0x0080, 0x008f, read8sm_delegate(*this, FUNC(wd7600_device::dma_page_r)), write8sm_delegate(*this, FUNC(wd7600_device::dma_page_w)), 0xffffffff);
m_space_io->install_readwrite_handler(0x0090, 0x0093, read8smo_delegate(*this, FUNC(wd7600_device::a20_reset_r)), write8smo_delegate(*this, FUNC(wd7600_device::a20_reset_w)), 0x00ff0000);
m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8sm_delegate(*m_pic2, FUNC(pic8259_device::read)), write8sm_delegate(*m_pic2, FUNC(pic8259_device::write)), 0x0000ffff);
@@ -219,7 +210,7 @@ void wd7600_device::device_reset()
}
-WRITE_LINE_MEMBER( wd7600_device::iochck_w )
+void wd7600_device::iochck_w(int state)
{
if (BIT(m_portb, 3) == 0)
{
@@ -255,15 +246,12 @@ void wd7600_device::keyboard_gatea20(int state)
a20m();
}
-void wd7600_device::rtc_w(offs_t offset, uint8_t data)
+void wd7600_device::rtc_nmi_w(uint8_t data)
{
- if (offset == 0)
- {
- m_nmi_mask = !BIT(data, 7);
- data &= 0x7f;
- }
+ m_nmi_mask = !BIT(data, 7);
+ data &= 0x7f;
- m_rtc->write(offset, data);
+ m_rtc->address_w(data);
}
uint8_t wd7600_device::pic1_slave_ack_r(offs_t offset)
@@ -275,13 +263,13 @@ uint8_t wd7600_device::pic1_slave_ack_r(offs_t offset)
}
// Timer outputs
-WRITE_LINE_MEMBER( wd7600_device::ctc_out1_w )
+void wd7600_device::ctc_out1_w(int state)
{
m_refresh_toggle ^= state;
m_portb = (m_portb & 0xef) | (m_refresh_toggle << 4);
}
-WRITE_LINE_MEMBER( wd7600_device::ctc_out2_w )
+void wd7600_device::ctc_out2_w(int state)
{
m_write_spkr(!(state));
m_portb = (m_portb & 0xdf) | (state << 5);
@@ -387,12 +375,12 @@ void wd7600_device::dma_write_word(offs_t offset, uint8_t data)
m_space->write_word((page_offset() & 0xfe0000) | (offset << 1), (m_dma_high_byte << 8) | data);
}
-WRITE_LINE_MEMBER( wd7600_device::dma2_dack0_w )
+void wd7600_device::dma2_dack0_w(int state)
{
m_dma1->hack_w(state ? 0 : 1); // inverted?
}
-WRITE_LINE_MEMBER( wd7600_device::dma1_eop_w )
+void wd7600_device::dma1_eop_w(int state)
{
m_dma_eop = state;
if (m_dma_channel != -1)
@@ -420,12 +408,12 @@ void wd7600_device::set_dma_channel(int channel, bool state)
}
}
-WRITE_LINE_MEMBER( wd7600_device::gatea20_w )
+void wd7600_device::gatea20_w(int state)
{
keyboard_gatea20(state);
}
-WRITE_LINE_MEMBER( wd7600_device::kbrst_w )
+void wd7600_device::kbrst_w(int state)
{
// convert to active low signal (gets inverted in at_keybc.c)
state = (state == ASSERT_LINE ? 0 : 1);
diff --git a/src/devices/machine/wd7600.h b/src/devices/machine/wd7600.h
index 43ddb00b038..6e81862ed48 100644
--- a/src/devices/machine/wd7600.h
+++ b/src/devices/machine/wd7600.h
@@ -50,30 +50,30 @@ public:
template <typename T> void set_ramtag(T &&tag) { m_ram.set_tag(std::forward<T>(tag)); }
// input lines
- DECLARE_WRITE_LINE_MEMBER( irq01_w ) { m_pic1->ir1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq03_w ) { m_pic1->ir3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq04_w ) { m_pic1->ir4_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq05_w ) { m_pic1->ir5_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq06_w ) { m_pic1->ir6_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq07_w ) { m_pic1->ir7_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq09_w ) { m_pic2->ir1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq10_w ) { m_pic2->ir2_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq11_w ) { m_pic2->ir3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq12_w ) { m_pic2->ir4_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq13_w ) { m_pic2->ir5_w(state); } // also FERR#
- DECLARE_WRITE_LINE_MEMBER( irq14_w ) { m_pic2->ir6_w(state); }
- DECLARE_WRITE_LINE_MEMBER( irq15_w ) { m_pic2->ir7_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq0_w ) { m_dma1->dreq0_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq1_w ) { m_dma1->dreq1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq2_w ) { m_dma1->dreq2_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq3_w ) { m_dma1->dreq3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq5_w ) { m_dma2->dreq1_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq6_w ) { m_dma2->dreq2_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dreq7_w ) { m_dma2->dreq3_w(state); }
- DECLARE_WRITE_LINE_MEMBER( hlda_w ) { m_dma2->hack_w(state); }
- DECLARE_WRITE_LINE_MEMBER( iochck_w );
- DECLARE_WRITE_LINE_MEMBER( gatea20_w );
- DECLARE_WRITE_LINE_MEMBER( kbrst_w );
+ void irq01_w(int state) { m_pic1->ir1_w(state); }
+ void irq03_w(int state) { m_pic1->ir3_w(state); }
+ void irq04_w(int state) { m_pic1->ir4_w(state); }
+ void irq05_w(int state) { m_pic1->ir5_w(state); }
+ void irq06_w(int state) { m_pic1->ir6_w(state); }
+ void irq07_w(int state) { m_pic1->ir7_w(state); }
+ void irq09_w(int state) { m_pic2->ir1_w(state); }
+ void irq10_w(int state) { m_pic2->ir2_w(state); }
+ void irq11_w(int state) { m_pic2->ir3_w(state); }
+ void irq12_w(int state) { m_pic2->ir4_w(state); }
+ void irq13_w(int state) { m_pic2->ir5_w(state); } // also FERR#
+ void irq14_w(int state) { m_pic2->ir6_w(state); }
+ void irq15_w(int state) { m_pic2->ir7_w(state); }
+ void dreq0_w(int state) { m_dma1->dreq0_w(state); }
+ void dreq1_w(int state) { m_dma1->dreq1_w(state); }
+ void dreq2_w(int state) { m_dma1->dreq2_w(state); }
+ void dreq3_w(int state) { m_dma1->dreq3_w(state); }
+ void dreq5_w(int state) { m_dma2->dreq1_w(state); }
+ void dreq6_w(int state) { m_dma2->dreq2_w(state); }
+ void dreq7_w(int state) { m_dma2->dreq3_w(state); }
+ void hlda_w(int state) { m_dma2->hack_w(state); }
+ void iochck_w(int state);
+ void gatea20_w(int state);
+ void kbrst_w(int state);
uint16_t refresh_r();
void refresh_w(uint16_t data);
@@ -100,11 +100,11 @@ protected:
virtual void device_add_mconfig(machine_config &config) override;
private:
- DECLARE_WRITE_LINE_MEMBER( pic1_int_w ) { m_write_intr(state); }
+ void pic1_int_w(int state) { m_write_intr(state); }
uint8_t pic1_slave_ack_r(offs_t offset);
- DECLARE_WRITE_LINE_MEMBER( ctc_out1_w );
- DECLARE_WRITE_LINE_MEMBER( ctc_out2_w );
- void rtc_w(offs_t offset, uint8_t data);
+ void ctc_out1_w(int state);
+ void ctc_out2_w(int state);
+ void rtc_nmi_w(uint8_t data);
void keyb_cmd_w(uint8_t data);
void keyb_data_w(uint8_t data);
uint8_t keyb_data_r();
@@ -119,7 +119,7 @@ private:
void dma_write_byte(offs_t offset, uint8_t data);
uint8_t dma_read_word(offs_t offset);
void dma_write_word(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( dma1_eop_w );
+ void dma1_eop_w(int state);
uint8_t dma1_ior0_r() { return m_read_ior(0); }
uint8_t dma1_ior1_r() { return m_read_ior(1); }
uint8_t dma1_ior2_r() { return m_read_ior(2); }
@@ -134,15 +134,15 @@ private:
void dma2_iow1_w(uint8_t data) { m_write_iow(5, (m_dma_high_byte << 8) | data, 0xffff); }
void dma2_iow2_w(uint8_t data) { m_write_iow(6, (m_dma_high_byte << 8) | data, 0xffff); }
void dma2_iow3_w(uint8_t data) { m_write_iow(7, (m_dma_high_byte << 8) | data, 0xffff); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack0_w ) { set_dma_channel(0, state); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack1_w ) { set_dma_channel(1, state); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack2_w ) { set_dma_channel(2, state); }
- DECLARE_WRITE_LINE_MEMBER( dma1_dack3_w ) { set_dma_channel(3, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_dack0_w );
- DECLARE_WRITE_LINE_MEMBER( dma2_dack1_w ) { set_dma_channel(5, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_dack2_w ) { set_dma_channel(6, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_dack3_w ) { set_dma_channel(7, state); }
- DECLARE_WRITE_LINE_MEMBER( dma2_hreq_w ) { m_write_hold(state); }
+ void dma1_dack0_w(int state) { set_dma_channel(0, state); }
+ void dma1_dack1_w(int state) { set_dma_channel(1, state); }
+ void dma1_dack2_w(int state) { set_dma_channel(2, state); }
+ void dma1_dack3_w(int state) { set_dma_channel(3, state); }
+ void dma2_dack0_w(int state);
+ void dma2_dack1_w(int state) { set_dma_channel(5, state); }
+ void dma2_dack2_w(int state) { set_dma_channel(6, state); }
+ void dma2_dack3_w(int state) { set_dma_channel(7, state); }
+ void dma2_hreq_w(int state) { m_write_hold(state); }
devcb_read16 m_read_ior;
devcb_write16 m_write_iow;
diff --git a/src/devices/machine/wd_fdc.cpp b/src/devices/machine/wd_fdc.cpp
index ecdfb7850b9..4e4f03bb6e9 100644
--- a/src/devices/machine/wd_fdc.cpp
+++ b/src/devices/machine/wd_fdc.cpp
@@ -5,10 +5,7 @@
#include "imagedev/floppy.h"
-#include "debugger.h"
-
-//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already
-#define LOG_SETUP (1U << 1) // Shows register setup
+#define LOG_DATA (1U << 1) // Shows data reads and writes
#define LOG_SHIFT (1U << 2) // Shows shift register contents
#define LOG_COMP (1U << 3) // Shows operations on the CPU side
#define LOG_COMMAND (1U << 4) // Shows command invocation
@@ -22,13 +19,15 @@
#define LOG_STATE (1U << 12) // Show state machine
#define LOG_LIVE (1U << 13) // Live states
#define LOG_FUNC (1U << 14) // Function calls
+#define LOG_CRC (1U << 15) // CRC errors
-#define VERBOSE (LOG_GENERAL)
+#define VERBOSE (LOG_DESC)
+//#define VERBOSE (LOG_DESC | LOG_COMMAND | LOG_MATCH | LOG_WRITE | LOG_STATE | LOG_LINES | LOG_COMP | LOG_CRC )
//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
-#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
+#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__)
#define LOGSHIFT(...) LOGMASKED(LOG_SHIFT, __VA_ARGS__)
#define LOGCOMP(...) LOGMASKED(LOG_COMP, __VA_ARGS__)
#define LOGCOMMAND(...) LOGMASKED(LOG_COMMAND, __VA_ARGS__)
@@ -42,6 +41,7 @@
#define LOGSTATE(...) LOGMASKED(LOG_STATE, __VA_ARGS__)
#define LOGLIVE(...) LOGMASKED(LOG_LIVE, __VA_ARGS__)
#define LOGFUNC(...) LOGMASKED(LOG_FUNC, __VA_ARGS__)
+#define LOGCRC(...) LOGMASKED(LOG_CRC, __VA_ARGS__)
#ifdef _MSC_VER
#define FUNCNAME __func__
@@ -79,6 +79,70 @@ DEFINE_DEVICE_TYPE(WD1770, wd1770_device, "wd1770", "Western Digital
DEFINE_DEVICE_TYPE(WD1772, wd1772_device, "wd1772", "Western Digital WD1772 FDC")
DEFINE_DEVICE_TYPE(WD1773, wd1773_device, "wd1773", "Western Digital WD1773 FDC")
+static const char *const states[] =
+{
+ "IDLE",
+ "RESTORE",
+ "SEEK",
+ "STEP",
+ "READ_SECTOR",
+ "READ_TRACK",
+ "READ_ID",
+ "WRITE_TRACK",
+ "WRITE_SECTOR",
+ "SPINUP",
+ "SPINUP_WAIT",
+ "SPINUP_DONE",
+ "SETTLE_WAIT",
+ "SETTLE_DONE",
+ "WRITE_PROTECT_WAIT",
+ "WRITE_PROTECT_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",
+ "INITIAL_RESTORE",
+ "DUMMY",
+ "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"
+};
+
+template <unsigned B> inline uint32_t wd_fdc_device_base::live_info::shift_reg_low() const
+{
+ return shift_reg & make_bitmask<uint32_t>(B);
+}
+
+inline uint8_t wd_fdc_device_base::live_info::shift_reg_data() const
+{
+ return bitswap<8>(shift_reg, 14, 12, 10, 8, 6, 4, 2, 0);
+}
+
wd_fdc_device_base::wd_fdc_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
intrq_cb(*this),
@@ -87,12 +151,13 @@ wd_fdc_device_base::wd_fdc_device_base(const machine_config &mconfig, device_typ
enp_cb(*this),
sso_cb(*this),
ready_cb(*this), // actually output by the drive, not by the FDC
- enmf_cb(*this),
+ enmf_cb(*this, 0),
mon_cb(*this)
{
force_ready = false;
disable_motor_control = false;
spinup_on_interrupt = false;
+ extended_ddam = false;
hlt = true; // assume tied to VCC
}
@@ -108,22 +173,13 @@ void wd_fdc_device_base::set_disable_motor_control(bool _disable_motor_control)
void wd_fdc_device_base::device_start()
{
- intrq_cb.resolve();
- drq_cb.resolve();
- hld_cb.resolve();
- enp_cb.resolve();
- sso_cb.resolve();
- ready_cb.resolve();
- enmf_cb.resolve();
- mon_cb.resolve_safe();
-
- if (!has_enmf && !enmf_cb.isnull())
+ if (!has_enmf && !enmf_cb.isunset())
logerror("Warning, this chip doesn't have an ENMF line.\n");
- t_gen = timer_alloc(TM_GEN);
- t_cmd = timer_alloc(TM_CMD);
- t_track = timer_alloc(TM_TRACK);
- t_sector = timer_alloc(TM_SECTOR);
+ t_gen = timer_alloc(FUNC(wd_fdc_device_base::generic_tick), this);
+ t_cmd = timer_alloc(FUNC(wd_fdc_device_base::cmd_w_tick), this);
+ t_track = timer_alloc(FUNC(wd_fdc_device_base::track_w_tick), this);
+ t_sector = timer_alloc(FUNC(wd_fdc_device_base::sector_w_tick), this);
dden = disable_mfm;
enmf = false;
floppy = nullptr;
@@ -132,6 +188,8 @@ void wd_fdc_device_base::device_start()
track = 0x00;
mr = true;
+ delay_int = false;
+
save_item(NAME(status));
save_item(NAME(command));
save_item(NAME(main_state));
@@ -167,7 +225,7 @@ void wd_fdc_device_base::soft_reset()
}
}
-WRITE_LINE_MEMBER(wd_fdc_device_base::mr_w)
+void wd_fdc_device_base::mr_w(int state)
{
if(mr && !state) {
command = 0x03;
@@ -183,19 +241,16 @@ WRITE_LINE_MEMBER(wd_fdc_device_base::mr_w)
mr = false;
// gnd == enmf enabled, otherwise disabled (default)
- if (!enmf_cb.isnull() && has_enmf)
+ if (!enmf_cb.isunset() && has_enmf)
enmf = enmf_cb() ? false : true;
intrq = false;
- if (!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
drq = false;
- if (!drq_cb.isnull())
- drq_cb(drq);
+ drq_cb(drq);
if(head_control) {
hld = false;
- if(!hld_cb.isnull())
- hld_cb(hld);
+ hld_cb(hld);
}
mon_cb(1); // Clear the MON* line
@@ -245,7 +300,7 @@ void wd_fdc_device_base::set_floppy(floppy_image_device *_floppy)
ready_callback(floppy, next_ready);
}
-WRITE_LINE_MEMBER(wd_fdc_device_base::dden_w)
+void wd_fdc_device_base::dden_w(int state)
{
if(disable_mfm) {
logerror("Error, this chip does not have a dden line\n");
@@ -258,18 +313,35 @@ WRITE_LINE_MEMBER(wd_fdc_device_base::dden_w)
}
}
-void wd_fdc_device_base::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::generic_tick)
{
- LOGEVENT("Event fired for timer %s\n", (id==TM_GEN)? "TM_GEN" : (id==TM_CMD)? "TM_CMD" : (id==TM_TRACK)? "TM_TRACK" : "TM_SECTOR");
+ LOGEVENT("Event fired for TM_GEN\n");
live_sync();
+ do_generic();
+ general_continue();
+}
- 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;
- }
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::cmd_w_tick)
+{
+ LOGEVENT("Event fired for TM_CMD\n");
+ live_sync();
+ do_cmd_w();
+ general_continue();
+}
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::track_w_tick)
+{
+ LOGEVENT("Event fired for TM_TRACK\n");
+ live_sync();
+ do_track_w();
+ general_continue();
+}
+
+TIMER_CALLBACK_MEMBER(wd_fdc_device_base::sector_w_tick)
+{
+ LOGEVENT("Event fired for TM_SECTOR\n");
+ live_sync();
+ do_sector_w();
general_continue();
}
@@ -279,11 +351,12 @@ void wd_fdc_device_base::command_end()
main_state = sub_state = IDLE;
motor_timeout = 0;
- if(!drq && (status & S_BUSY)) {
- status &= ~S_BUSY;
+ if(status & S_BUSY) {
+ if (!t_cmd->enabled()) {
+ status &= ~S_BUSY;
+ }
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
}
@@ -435,6 +508,7 @@ void wd_fdc_device_base::seek_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
+ LOGCRC("CRC error in seek\n");
return;
}
command_end();
@@ -484,7 +558,6 @@ void wd_fdc_device_base::read_sector_start()
main_state = READ_SECTOR;
status &= ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM);
- drop_drq();
update_sso();
set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
@@ -540,6 +613,7 @@ void wd_fdc_device_base::read_sector_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
+ LOGCRC("CRC error in readsector\n");
return;
}
sector_size = calc_sector_size(cur_live.idbuf[3], command);
@@ -555,8 +629,10 @@ void wd_fdc_device_base::read_sector_continue()
case SECTOR_READ:
LOGSTATE("SECTOR_READ\n");
- if(cur_live.crc)
+ if(cur_live.crc) {
status |= S_CRC;
+ LOGCRC("CRC error in readsector %04X\n",cur_live.crc);
+ }
if(command & 0x10 && !(status & S_RNF)) {
sector++;
@@ -585,7 +661,6 @@ void wd_fdc_device_base::read_track_start()
main_state = READ_TRACK;
status &= ~(S_LOST|S_RNF);
- drop_drq();
update_sso();
set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
@@ -664,7 +739,6 @@ void wd_fdc_device_base::read_id_start()
main_state = READ_ID;
status &= ~(S_WP|S_DDM|S_LOST|S_RNF);
- drop_drq();
update_sso();
set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
@@ -741,7 +815,6 @@ void wd_fdc_device_base::write_track_start()
main_state = WRITE_TRACK;
status &= ~(S_WP|S_DDM|S_LOST|S_RNF);
- drop_drq();
update_sso();
set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
@@ -790,8 +863,8 @@ void wd_fdc_device_base::write_track_continue()
LOGSTATE("SETTLE_DONE\n");
if (floppy && floppy->wpt_r()) {
LOGSTATE("WRITE_PROT\n");
- status |= S_WP;
- command_end();
+ sub_state = WRITE_PROTECT_WAIT;
+ delay_cycles(t_gen, 145);
return;
}
set_drq();
@@ -799,6 +872,16 @@ void wd_fdc_device_base::write_track_continue()
delay_cycles(t_gen, 192);
return;
+ case WRITE_PROTECT_WAIT:
+ LOGSTATE("WRITE_PROTECT_WAIT\n");
+ return;
+
+ case WRITE_PROTECT_DONE:
+ LOGSTATE("WRITE_PROTECT_DONE\n");
+ status |= S_WP;
+ command_end();
+ return;
+
case DATA_LOAD_WAIT:
LOGSTATE("DATA_LOAD_WAIT\n");
return;
@@ -830,9 +913,9 @@ void wd_fdc_device_base::write_track_continue()
if(format_last_byte_count) {
char buf[32];
if(format_last_byte_count > 1)
- sprintf(buf, "%dx%02x", format_last_byte_count, format_last_byte);
+ snprintf(buf, 32, "%dx%02x", format_last_byte_count, format_last_byte);
else
- sprintf(buf, "%02x", format_last_byte);
+ snprintf(buf, 32, "%02x", format_last_byte);
format_description_string += buf;
}
LOGDESC("track description %s\n", format_description_string.c_str());
@@ -858,7 +941,6 @@ void wd_fdc_device_base::write_sector_start()
main_state = WRITE_SECTOR;
status &= ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM);
- drop_drq();
update_sso();
set_hld();
sub_state = motor_control ? SPINUP : SPINUP_DONE;
@@ -902,8 +984,8 @@ void wd_fdc_device_base::write_sector_continue()
LOGSTATE("SETTLE_DONE\n");
if (floppy && floppy->wpt_r()) {
LOGSTATE("WRITE_PROT\n");
- status |= S_WP;
- command_end();
+ sub_state = WRITE_PROTECT_WAIT;
+ delay_cycles(t_gen, 145);
return;
}
sub_state = SCAN_ID;
@@ -911,6 +993,16 @@ void wd_fdc_device_base::write_sector_continue()
live_start(SEARCH_ADDRESS_MARK_HEADER);
return;
+ case WRITE_PROTECT_WAIT:
+ LOGSTATE("WRITE_PROTECT_WAIT\n");
+ return;
+
+ case WRITE_PROTECT_DONE:
+ LOGSTATE("WRITE_PROTECT_DONE\n");
+ status |= S_WP;
+ command_end();
+ return;
+
case SCAN_ID:
LOGSTATE("SCAN_ID\n");
if(!sector_matches()) {
@@ -920,6 +1012,7 @@ void wd_fdc_device_base::write_sector_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
+ LOGCRC("CRC error in writesector\n");
return;
}
sector_size = calc_sector_size(cur_live.idbuf[3], command);
@@ -957,36 +1050,46 @@ void wd_fdc_device_base::interrupt_start()
LOGCOMMAND("cmd: forced interrupt (c=%02x)\n", command);
+ // If writing a byte to a sector, then wait until it's written before terminating
+ // This behavior is required by the RM nimbus driver, otherwise the forced interrupt
+ // at the end of a multiple sector write occasionally prevents the CRC byte being
+ // written, causing the disk to be corrupted.
+ if(/*((main_state == READ_SECTOR) && (cur_live.state == READ_SECTOR_DATA)) ||*/
+ ((main_state == WRITE_SECTOR) && (cur_live.state == WRITE_BYTE))) {
+ delay_int = true;
+ return;
+ } else {
+ delay_int = false;
+ }
+
+ //logerror("main_state=%s, cur_live.state=%s\n",states[main_state],states[cur_live.state]);
+
if(status & S_BUSY) {
main_state = sub_state = cur_live.state = IDLE;
cur_live.tm = attotime::never;
status &= ~S_BUSY;
- drop_drq();
motor_timeout = 0;
- }
- else
- {
+ } else {
// when a force interrupt command is issued and there is no
// currently running command, return the status type 1 bits
status_type_1 = true;
+ drop_drq();
}
intrq_cond = command & 0x0f;
if(!intrq && (command & I_IMM)) {
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
- if (spinup_on_interrupt) // see notes in FD1771 and WD1772 constructors, might be true for other FDC types as well.
- {
+ if(spinup_on_interrupt) { // see notes in FD1771 and WD1772 constructors, might be true for other FDC types as well.
motor_timeout = 0;
if (head_control)
set_hld();
- if (motor_control) {
+ if(motor_control) {
status |= S_MON | S_SPIN;
mon_cb(0);
@@ -1048,6 +1151,10 @@ void wd_fdc_device_base::do_generic()
sub_state = SETTLE_DONE;
break;
+ case WRITE_PROTECT_WAIT:
+ sub_state = WRITE_PROTECT_DONE;
+ break;
+
case SEEK_WAIT_STEP_TIME:
sub_state = SEEK_WAIT_STEP_TIME_DONE;
break;
@@ -1075,7 +1182,8 @@ void wd_fdc_device_base::do_generic()
void wd_fdc_device_base::do_cmd_w()
{
// it is actually possible to send another command even while in busy state.
- // currently we simply accept any commands, but chip logic probably more complex (presumable it is possible change command of the same type only).
+ // currently we simply accept any commands, but chip logic is probably more complex
+ // (presumably it is only possible change to a command of the same type).
#if 0
// Only available command when busy is interrupt
if(main_state != IDLE && (cmd_buffer & 0xf0) != 0xd0) {
@@ -1138,7 +1246,7 @@ void wd_fdc_device_base::do_cmd_w()
void wd_fdc_device_base::cmd_w(uint8_t val)
{
- if (inverted_bus) val ^= 0xff;
+ val ^= bus_invert_value;
if (!mr) {
logerror("Not initiating command %02x during master reset\n", val);
return;
@@ -1146,10 +1254,17 @@ void wd_fdc_device_base::cmd_w(uint8_t val)
LOGCOMP("Initiating command %02x\n", val);
+ // INTRQ flip-flop logic from die schematics:
+ // Reset conditions:
+ // - Command register write
+ // - Status register read
+ // Setting conditions:
+ // - While command register contain Dx (interrupt cmd) and one or more I0-I3 conditions met
+ // - Command-specific based on PLL microprogram
+ // No other logic present in real chips, descriptions of "Forced interrupt" (Dx) command in datasheets are wrong.
if (intrq) {
intrq = false;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
// No more than one write in flight, but interrupts take priority
@@ -1166,6 +1281,7 @@ void wd_fdc_device_base::cmd_w(uint8_t val)
else
{
intrq_cond = 0;
+ drop_drq();
// set busy, then set a timer to process the command
status |= S_BUSY;
delay_cycles(t_cmd, dden ? delay_command_commit*2 : delay_command_commit);
@@ -1176,8 +1292,7 @@ uint8_t wd_fdc_device_base::status_r()
{
if(intrq && !(intrq_cond & I_IMM) && !machine().side_effects_disabled()) {
intrq = false;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
if(status_type_1) {
@@ -1217,8 +1332,9 @@ uint8_t wd_fdc_device_base::status_r()
status &= ~S_NRDY;
}
- uint8_t val = status;
- if (inverted_bus) val ^= 0xff;
+ uint8_t val = status ^ bus_invert_value;
+
+ LOGCOMP("Status value: %02X\n",val);
return val;
}
@@ -1231,22 +1347,17 @@ void wd_fdc_device_base::do_track_w()
void wd_fdc_device_base::track_w(uint8_t val)
{
- if (inverted_bus) val ^= 0xff;
-
// No more than one write in flight
if(track_buffer != -1 || !mr)
return;
- track_buffer = val;
+ track_buffer = val ^ bus_invert_value;
delay_cycles(t_track, dden ? delay_register_commit*2 : delay_register_commit);
}
uint8_t wd_fdc_device_base::track_r()
{
- uint8_t val = track;
- if (inverted_bus) val ^= 0xff;
-
- return val;
+ return track ^ bus_invert_value;
}
void wd_fdc_device_base::do_sector_w()
@@ -1259,15 +1370,13 @@ void wd_fdc_device_base::sector_w(uint8_t val)
{
if (!mr) return;
- if (inverted_bus) val ^= 0xff;
-
// No more than one write in flight
// C1581 accesses this register with an INC opcode,
// i.e. write old value, write new value, and the new value gets ignored by this
//if(sector_buffer != -1)
// return;
- sector_buffer = val;
+ sector_buffer = val ^ bus_invert_value;
// set a timer to write the new value to the register, but only if we aren't in
// the middle of an already occurring update
@@ -1277,31 +1386,27 @@ void wd_fdc_device_base::sector_w(uint8_t val)
uint8_t wd_fdc_device_base::sector_r()
{
- uint8_t val = sector;
- if (inverted_bus) val ^= 0xff;
-
- return val;
+ return sector ^ bus_invert_value;
}
void wd_fdc_device_base::data_w(uint8_t val)
{
if (!mr) return;
- if (inverted_bus) val ^= 0xff;
-
- data = val;
+ data = val ^ bus_invert_value;
+ LOGDATA("%s: Write %02X to data register (DRQ=%d)\n", machine().describe_context(), data, drq);
drop_drq();
}
uint8_t wd_fdc_device_base::data_r()
{
if (!machine().side_effects_disabled())
+ {
+ LOGDATA("%s: Read %02X from data register (DRQ=%d)\n", machine().describe_context(), data, drq);
drop_drq();
+ }
- uint8_t val = data;
- if (inverted_bus) val ^= 0xff;
-
- return val;
+ return data ^ bus_invert_value;
}
void wd_fdc_device_base::write(offs_t reg, uint8_t val)
@@ -1349,8 +1454,7 @@ void wd_fdc_device_base::spinup()
void wd_fdc_device_base::ready_callback(floppy_image_device *floppy, int state)
{
- if(!ready_cb.isnull())
- ready_cb(state);
+ ready_cb(state);
// why is this even possible?
if (!floppy)
@@ -1362,8 +1466,7 @@ void wd_fdc_device_base::ready_callback(floppy_image_device *floppy, int state)
if(!intrq && (((intrq_cond & I_RDY) && !state) || ((intrq_cond & I_NRDY) && state))) {
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
}
@@ -1394,8 +1497,7 @@ void wd_fdc_device_base::index_callback(floppy_image_device *floppy, int state)
if(!intrq && (intrq_cond & I_IDX)) {
intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
+ intrq_cb(intrq);
}
break;
@@ -1414,6 +1516,8 @@ void wd_fdc_device_base::index_callback(floppy_image_device *floppy, int state)
case SPINUP_DONE:
case SETTLE_WAIT:
case SETTLE_DONE:
+ case WRITE_PROTECT_WAIT:
+ case WRITE_PROTECT_DONE:
case DATA_LOAD_WAIT:
case DATA_LOAD_WAIT_DONE:
case SEEK_MOVE:
@@ -1455,27 +1559,27 @@ void wd_fdc_device_base::index_callback(floppy_image_device *floppy, int state)
general_continue();
}
-READ_LINE_MEMBER(wd_fdc_device_base::intrq_r)
+int wd_fdc_device_base::intrq_r()
{
return intrq;
}
-READ_LINE_MEMBER(wd_fdc_device_base::drq_r)
+int wd_fdc_device_base::drq_r()
{
return drq;
}
-READ_LINE_MEMBER(wd_fdc_device_base::hld_r)
+int wd_fdc_device_base::hld_r()
{
return hld;
}
-WRITE_LINE_MEMBER(wd_fdc_device_base::hlt_w)
+void wd_fdc_device_base::hlt_w(int state)
{
hlt = bool(state);
}
-READ_LINE_MEMBER(wd_fdc_device_base::enp_r)
+int wd_fdc_device_base::enp_r()
{
return enp;
}
@@ -1495,7 +1599,7 @@ void wd_fdc_device_base::live_start(int state)
cur_live.data_bit_context = false;
cur_live.byte_counter = 0;
- if (!enmf_cb.isnull() && has_enmf)
+ if (!enmf_cb.isunset() && has_enmf)
enmf = enmf_cb() ? false : true;
pll_reset(dden, enmf, cur_live.tm);
@@ -1581,6 +1685,14 @@ bool wd_fdc_device_base::read_one_bit(const attotime &limit)
return false;
}
+void wd_fdc_device_base::reset_data_sync()
+{
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 0;
+
+ cur_live.data_reg = cur_live.shift_reg_data();
+}
+
bool wd_fdc_device_base::write_one_bit(const attotime &limit)
{
bool bit = cur_live.shift_reg & 0x8000;
@@ -1664,28 +1776,19 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d\n", cur_live.tm.to_string(), 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),
+ LOGSHIFT("%s: shift = %08x data=%02x c=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter);
- if(!dden && cur_live.shift_reg == 0x4489) {
+ if(!dden && cur_live.shift_reg_low<16>() == 0x4489) {
cur_live.crc = 0x443b;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
cur_live.state = READ_HEADER_BLOCK_HEADER;
}
- if(dden && cur_live.shift_reg == 0xf57e) {
+ if(dden && cur_live.shift_reg_low<23>() == 0x2af57e) {
cur_live.crc = 0xef21;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
if(main_state == READ_ID)
cur_live.state = READ_ID_BLOCK_TO_DMA;
else
@@ -1698,15 +1801,8 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", cur_live.tm.to_string(), 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),
+ LOGSHIFT("%s: shift = %08x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter);
if(cur_live.bit_counter & 15)
@@ -1715,7 +1811,7 @@ void wd_fdc_device_base::live_run(attotime limit)
int slot = cur_live.bit_counter >> 4;
if(slot < 3) {
- if(cur_live.shift_reg != 0x4489)
+ if(cur_live.shift_reg_low<16>() != 0x4489)
cur_live.state = SEARCH_ADDRESS_MARK_HEADER;
break;
}
@@ -1769,6 +1865,7 @@ void wd_fdc_device_base::live_run(attotime limit)
if(cur_live.bit_counter == 16*6) {
if(cur_live.crc) {
status |= S_CRC;
+ LOGCRC("CRC error in live_run\n");
}
// Already synchronous
@@ -1785,15 +1882,8 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d.%x\n", cur_live.tm.to_string(), 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),
+ LOGSHIFT("%s: shift = %08x data=%02x c=%d.%x\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter >> 4, cur_live.bit_counter & 15);
if(!dden) {
@@ -1802,10 +1892,9 @@ void wd_fdc_device_base::live_run(attotime limit)
return;
}
- if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) {
+ if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg_low<16>() == 0x4489) {
cur_live.crc = 0x443b;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
cur_live.state = READ_DATA_BLOCK_HEADER;
}
} else {
@@ -1814,19 +1903,24 @@ void wd_fdc_device_base::live_run(attotime limit)
return;
}
- if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg == 0xf56a || cur_live.shift_reg == 0xf56b ||
- cur_live.shift_reg == 0xf56e || cur_live.shift_reg == 0xf56f)) {
+ if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg_low<16>() == 0xf56a || cur_live.shift_reg_low<16>() == 0xf56b ||
+ cur_live.shift_reg_low<16>() == 0xf56e || cur_live.shift_reg_low<16>() == 0xf56f)) {
cur_live.crc =
- cur_live.shift_reg == 0xf56a ? 0x8fe7 :
- cur_live.shift_reg == 0xf56b ? 0x9fc6 :
- cur_live.shift_reg == 0xf56e ? 0xafa5 :
+ cur_live.shift_reg_low<16>() == 0xf56a ? 0x8fe7 :
+ cur_live.shift_reg_low<16>() == 0xf56b ? 0x9fc6 :
+ cur_live.shift_reg_low<16>() == 0xf56e ? 0xafa5 :
0xbf84;
- if((cur_live.data_reg & 0xfe) == 0xf8)
+ reset_data_sync();
+
+ if(extended_ddam) {
+ if(!(cur_live.data_reg & 1))
+ status |= S_DDM;
+ if(!(cur_live.data_reg & 2))
+ status |= S_DDM << 1;
+ } else if((cur_live.data_reg & 0xfe) == 0xf8)
status |= S_DDM;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
cur_live.state = READ_SECTOR_DATA;
}
}
@@ -1837,15 +1931,8 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", cur_live.tm.to_string(), 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),
+ LOGSHIFT("%s: shift = %08x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
+ cur_live.shift_reg_data(),
cur_live.bit_counter);
if(cur_live.bit_counter & 15)
@@ -1854,7 +1941,7 @@ void wd_fdc_device_base::live_run(attotime limit)
int slot = cur_live.bit_counter >> 4;
if(slot < 3) {
- if(cur_live.shift_reg != 0x4489) {
+ if(cur_live.shift_reg_low<16>() != 0x4489) {
live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED);
return;
}
@@ -1893,7 +1980,12 @@ void wd_fdc_device_base::live_run(attotime limit)
} else if(slot < sector_size+2) {
// CRC
if(slot == sector_size+1) {
- live_delay(IDLE);
+ // act on delayed interrupt if active
+/* if(delay_int) {
+ interrupt_start();
+ return;
+ }
+*/ live_delay(IDLE);
return;
}
}
@@ -1913,14 +2005,26 @@ void wd_fdc_device_base::live_run(attotime limit)
if(read_one_bit(limit))
return;
+ if(dden) {
+ //FM Prefix match
+ if(cur_live.shift_reg_low<17>() == 0xabd5) { // 17-bit match
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 5*2; // prefix is 5 of 8 bits
+ cur_live.data_reg = 0xff;
+ break;
+ } else if(cur_live.bit_counter == 16) {
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 0;
+ live_delay(READ_TRACK_DATA_BYTE);
+ return;
+ }
+ break;
+ }
+ // !dden
if(cur_live.bit_counter != 16
// MFM resyncs
- && !(!dden && (cur_live.shift_reg == 0x4489
- || cur_live.shift_reg == 0x5224))
- // FM resyncs
- && !(dden && (cur_live.shift_reg == 0xf57e // FM IDAM
- || cur_live.shift_reg == 0xf56f // FM DAM
- || cur_live.shift_reg == 0xf56a)) // FM DDAM
+ && !((cur_live.shift_reg_low<16>() == 0x4489
+ || cur_live.shift_reg_low<16>() == 0x5224))
)
break;
@@ -1937,8 +2041,7 @@ void wd_fdc_device_base::live_run(attotime limit)
// MZ: TI99 "DISkASSEMBLER" copy protection requires a threshold of 8
bool output_byte = cur_live.bit_counter > 8;
- cur_live.data_separator_phase = false;
- cur_live.bit_counter = 0;
+ reset_data_sync();
if(output_byte) {
live_delay(READ_TRACK_DATA_BYTE);
@@ -1964,9 +2067,9 @@ void wd_fdc_device_base::live_run(attotime limit)
if(format_last_byte_count) {
char buf[32];
if(format_last_byte_count > 1)
- sprintf(buf, "%dx%02x ", format_last_byte_count, format_last_byte);
+ snprintf(buf, 32, "%dx%02x ", format_last_byte_count, format_last_byte);
else
- sprintf(buf, "%02x ", format_last_byte);
+ snprintf(buf, 32, "%02x ", format_last_byte);
format_description_string += buf;
}
format_last_byte = data;
@@ -2087,7 +2190,11 @@ void wd_fdc_device_base::live_run(attotime limit)
live_write_fm(0x00);
else if(cur_live.byte_counter < 7) {
cur_live.crc = 0xffff;
- live_write_raw(command & 1 ? 0xf56a : 0xf56f);
+ if(extended_ddam) {
+ static const uint16_t dam[4] = { 0xf56f, 0xf56e, 0xf56b, 0xf56a };
+ live_write_raw(dam[command & 3]);
+ } else
+ live_write_raw(command & 1 ? 0xf56a : 0xf56f);
} else if(cur_live.byte_counter < sector_size + 7-1) {
if(drq) {
status |= S_LOST;
@@ -2108,6 +2215,11 @@ void wd_fdc_device_base::live_run(attotime limit)
else {
pll_stop_writing(floppy, cur_live.tm);
cur_live.state = IDLE;
+
+ // Act on delayed interrupt if set.
+ if(delay_int)
+ interrupt_start();
+
return;
}
@@ -2137,9 +2249,15 @@ void wd_fdc_device_base::live_run(attotime limit)
live_write_mfm(cur_live.crc >> 8);
else if(cur_live.byte_counter < sector_size + 16+3)
live_write_mfm(0xff);
+// live_write_mfm(0x4e);
else {
pll_stop_writing(floppy, cur_live.tm);
cur_live.state = IDLE;
+
+ // Act on delayed interrupt if set.
+ if(delay_int)
+ interrupt_start();
+
return;
}
}
@@ -2222,13 +2340,9 @@ void wd_fdc_device_base::set_drq()
{
if(drq) {
status |= S_LOST;
- drq = false;
- if(!drq_cb.isnull())
- drq_cb(false);
} else if(!(status & S_LOST)) {
drq = true;
- if(!drq_cb.isnull())
- drq_cb(true);
+ drq_cb(true);
}
}
@@ -2236,14 +2350,7 @@ void wd_fdc_device_base::drop_drq()
{
if(drq) {
drq = false;
- if(!drq_cb.isnull())
- drq_cb(false);
- if(main_state == IDLE && (status & S_BUSY)) {
- status &= ~S_BUSY;
- intrq = true;
- if(!intrq_cb.isnull())
- intrq_cb(intrq);
- }
+ drq_cb(false);
}
}
@@ -2253,8 +2360,7 @@ void wd_fdc_device_base::set_hld()
hld = true;
int temp = sub_state;
sub_state = DUMMY;
- if(!hld_cb.isnull())
- hld_cb(hld);
+ hld_cb(hld);
sub_state = temp;
}
}
@@ -2265,8 +2371,7 @@ void wd_fdc_device_base::drop_hld()
hld = false;
int temp = sub_state;
sub_state = DUMMY;
- if(!hld_cb.isnull())
- hld_cb(hld);
+ hld_cb(hld);
sub_state = temp;
}
}
@@ -2283,7 +2388,7 @@ void wd_fdc_device_base::update_sso()
// If a SSO callback is defined then it is assumed that this callback
// will update the floppy side if that is the connection. There are
// some machines that use the SSO output for other purposes.
- if(!sso_cb.isnull()) {
+ if(!sso_cb.isunset()) {
sso_cb(side);
return;
}
@@ -2540,7 +2645,7 @@ bool wd_fdc_digital_device_base::digital_pll_t::write_next_bit(bool bit, attotim
uint16_t pre_counter = counter;
counter += increment;
if(bit && !(pre_counter & 0x400) && (counter & 0x400))
- if(write_position < ARRAY_LENGTH(write_buffer))
+ if(write_position < std::size(write_buffer))
write_buffer[write_position++] = etime;
slot++;
tm = etime;
@@ -2575,7 +2680,7 @@ fd1771_device::fd1771_device(const machine_config &mconfig, const char *tag, dev
delay_register_commit = 16/2; // will became x2 later due to FM
delay_command_commit = 20/2; // same as above
disable_mfm = true;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = false;
head_control = true;
@@ -2583,6 +2688,7 @@ fd1771_device::fd1771_device(const machine_config &mconfig, const char *tag, dev
motor_control = false;
ready_hooked = true;
spinup_on_interrupt = true; // ZX-Spectrum Beta-disk V2 require this, or ReadSector command should set HLD before RDY check
+ extended_ddam = true;
}
int fd1771_device::calc_sector_size(uint8_t size, uint8_t command) const
@@ -2601,7 +2707,7 @@ fd1781_device::fd1781_device(const machine_config &mconfig, const char *tag, dev
delay_register_commit = 16;
delay_command_commit = 12;
disable_mfm = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = false;
head_control = true;
@@ -2628,7 +2734,7 @@ fd1791_device::fd1791_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
@@ -2644,7 +2750,7 @@ fd1792_device::fd1792_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = true;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
@@ -2660,7 +2766,7 @@ fd1793_device::fd1793_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
@@ -2676,7 +2782,7 @@ kr1818vg93_device::kr1818vg93_device(const machine_config &mconfig, const char *
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
@@ -2692,7 +2798,7 @@ fd1794_device::fd1794_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = true;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
@@ -2708,7 +2814,7 @@ fd1795_device::fd1795_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = true;
side_compare = false;
head_control = true;
@@ -2732,7 +2838,7 @@ fd1797_device::fd1797_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = true;
side_compare = false;
head_control = true;
@@ -2756,7 +2862,7 @@ mb8866_device::mb8866_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
@@ -2772,7 +2878,7 @@ mb8876_device::mb8876_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
@@ -2788,7 +2894,7 @@ mb8877_device::mb8877_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
@@ -2804,7 +2910,7 @@ fd1761_device::fd1761_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
@@ -2820,7 +2926,7 @@ fd1763_device::fd1763_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
@@ -2836,7 +2942,7 @@ fd1765_device::fd1765_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = true;
side_compare = false;
head_control = true;
@@ -2860,7 +2966,7 @@ fd1767_device::fd1767_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = true;
side_compare = false;
head_control = true;
@@ -2884,7 +2990,7 @@ wd2791_device::wd2791_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = true;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = false;
side_compare = true;
head_control = true;
@@ -2896,11 +3002,12 @@ wd2791_device::wd2791_device(const machine_config &mconfig, const char *tag, dev
wd2793_device::wd2793_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, WD2793, tag, owner, clock)
{
step_times = fd179x_step_times;
+
delay_register_commit = 16;
delay_command_commit = 12;
disable_mfm = false;
has_enmf = true;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = true;
@@ -2916,7 +3023,7 @@ wd2795_device::wd2795_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = true;
+ bus_invert_value = 0xff;
side_control = true;
side_compare = false;
head_control = true;
@@ -2940,7 +3047,7 @@ wd2797_device::wd2797_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 12;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = true;
side_compare = false;
head_control = true;
@@ -2964,7 +3071,7 @@ wd1770_device::wd1770_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 36; // official 48 is too high for oric jasmin boot
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = false;
head_control = false;
@@ -2982,7 +3089,7 @@ wd1772_device::wd1772_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 48;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = false;
head_control = false;
@@ -3008,7 +3115,7 @@ wd1773_device::wd1773_device(const machine_config &mconfig, const char *tag, dev
delay_command_commit = 48;
disable_mfm = false;
has_enmf = false;
- inverted_bus = false;
+ bus_invert_value = 0x00;
side_control = false;
side_compare = true;
head_control = false;
diff --git a/src/devices/machine/wd_fdc.h b/src/devices/machine/wd_fdc.h
index d681abd2d03..22239b0dea3 100644
--- a/src/devices/machine/wd_fdc.h
+++ b/src/devices/machine/wd_fdc.h
@@ -61,7 +61,7 @@ public:
void soft_reset();
- DECLARE_WRITE_LINE_MEMBER(dden_w);
+ void dden_w(int state);
void set_floppy(floppy_image_device *floppy);
void set_force_ready(bool force_ready);
void set_disable_motor_control(bool _disable_motor_control);
@@ -81,18 +81,17 @@ public:
void write(offs_t reg, uint8_t val);
uint8_t read(offs_t reg);
- DECLARE_READ_LINE_MEMBER(intrq_r);
- DECLARE_READ_LINE_MEMBER(drq_r);
+ int intrq_r();
+ int drq_r();
- DECLARE_READ_LINE_MEMBER(hld_r);
- DECLARE_WRITE_LINE_MEMBER(hlt_w);
+ int hld_r();
+ void hlt_w(int state);
- DECLARE_READ_LINE_MEMBER(enp_r);
+ int enp_r();
- DECLARE_WRITE_LINE_MEMBER(mr_w);
+ void mr_w(int state);
void index_callback(floppy_image_device *floppy, int state);
-
protected:
wd_fdc_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@@ -100,7 +99,7 @@ protected:
bool disable_mfm;
bool enmf;
bool has_enmf;
- bool inverted_bus;
+ uint8_t bus_invert_value;
bool side_control;
bool side_compare;
bool head_control;
@@ -112,13 +111,13 @@ protected:
int delay_register_commit;
int delay_command_commit;
bool spinup_on_interrupt;
+ bool extended_ddam;
static constexpr int fd179x_step_times[4] = { 6000, 12000, 20000, 30000 };
static constexpr int fd176x_step_times[4] = { 12000, 24000, 40000, 60000 };
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual int calc_sector_size(uint8_t size, uint8_t command) const;
virtual int settle_time() const;
@@ -132,9 +131,12 @@ protected:
virtual void pll_save_checkpoint() = 0;
virtual void pll_retrieve_checkpoint() = 0;
-private:
- enum { TM_GEN, TM_CMD, TM_TRACK, TM_SECTOR };
+ TIMER_CALLBACK_MEMBER(generic_tick);
+ TIMER_CALLBACK_MEMBER(cmd_w_tick);
+ TIMER_CALLBACK_MEMBER(track_w_tick);
+ TIMER_CALLBACK_MEMBER(sector_w_tick);
+private:
// State machine general behaviour:
//
// There are three levels of state.
@@ -198,6 +200,9 @@ private:
SETTLE_WAIT,
SETTLE_DONE,
+ WRITE_PROTECT_WAIT,
+ WRITE_PROTECT_DONE,
+
DATA_LOAD_WAIT,
DATA_LOAD_WAIT_DONE,
@@ -242,17 +247,21 @@ private:
WRITE_SECTOR_PRE_BYTE
};
+
+
struct live_info {
enum { PT_NONE, PT_CRC_1, PT_CRC_2 };
attotime tm;
int state, next_state;
- uint16_t shift_reg;
+ uint32_t shift_reg;
uint16_t crc;
int bit_counter, byte_counter, previous_type;
bool data_separator_phase, data_bit_context;
uint8_t data_reg;
uint8_t idbuf[6];
+ template <unsigned B> uint32_t shift_reg_low() const;
+ uint8_t shift_reg_data() const;
};
enum {
@@ -304,6 +313,8 @@ private:
int format_last_byte_count;
std::string format_description_string;
+ bool delay_int;
+
void delay_cycles(emu_timer *tm, int cycles);
// Device timer subfunctions
@@ -351,7 +362,7 @@ private:
void live_run(attotime limit = attotime::never);
bool read_one_bit(const attotime &limit);
bool write_one_bit(const attotime &limit);
-
+ void reset_data_sync();
void live_write_raw(uint16_t raw);
void live_write_mfm(uint8_t mfm);
void live_write_fm(uint8_t fm);
@@ -526,13 +537,13 @@ protected:
class wd2791_device : public wd_fdc_analog_device_base {
public:
wd2791_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER(enmf_w) { enmf = state ? false : true; }
+ void enmf_w(int state) { enmf = state ? false : true; }
};
class wd2793_device : public wd_fdc_analog_device_base {
public:
wd2793_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER(enmf_w) { enmf = state ? false : true; }
+ void enmf_w(int state) { enmf = state ? false : true; }
};
class wd2795_device : public wd_fdc_analog_device_base {
diff --git a/src/devices/machine/wozfdc.cpp b/src/devices/machine/wozfdc.cpp
index 0c316a4c108..bee2f043e7e 100644
--- a/src/devices/machine/wozfdc.cpp
+++ b/src/devices/machine/wozfdc.cpp
@@ -13,6 +13,7 @@
#include "imagedev/floppy.h"
#include "formats/ap2_dsk.h"
+#include "formats/as_dsk.h"
/***************************************************************************
PARAMETERS
@@ -79,8 +80,8 @@ void wozfdc_device::device_start()
{
m_rom_p6 = machine().root_device().memregion(this->subtag(DISKII_P6_REGION).c_str())->base();
- timer = timer_alloc(0);
- delay_timer = timer_alloc(1);
+ timer = timer_alloc(FUNC(wozfdc_device::generic_tick), this);
+ delay_timer = timer_alloc(FUNC(wozfdc_device::delayed_tick), this);
save_item(NAME(last_6502_write));
save_item(NAME(mode_write));
@@ -178,12 +179,18 @@ void appleiii_fdc_device::device_reset()
enable1 = 1;
}
-void wozfdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(wozfdc_device::generic_tick)
+{
+ if(active)
+ lss_sync();
+}
+
+TIMER_CALLBACK_MEMBER(wozfdc_device::delayed_tick)
{
if(active)
lss_sync();
- if(id == 1 && active == MODE_DELAY) {
+ if(active == MODE_DELAY) {
if(floppy)
floppy->mon_w(true);
active = MODE_IDLE;
diff --git a/src/devices/machine/wozfdc.h b/src/devices/machine/wozfdc.h
index 6c7a438be17..acc03f487ec 100644
--- a/src/devices/machine/wozfdc.h
+++ b/src/devices/machine/wozfdc.h
@@ -14,7 +14,6 @@
#pragma once
#include "imagedev/floppy.h"
-#include "formats/flopimg.h"
#include "machine/74259.h"
//**************************************************************************
@@ -39,7 +38,9 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(generic_tick);
+ TIMER_CALLBACK_MEMBER(delayed_tick);
void control(int offset);
void set_phase(uint8_t data);
diff --git a/src/devices/machine/wtl3132.cpp b/src/devices/machine/wtl3132.cpp
index 2e86798b878..c5d3aeb02f9 100644
--- a/src/devices/machine/wtl3132.cpp
+++ b/src/devices/machine/wtl3132.cpp
@@ -16,7 +16,6 @@
#include "emu.h"
#include "wtl3132.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_REGS (1U << 1)
#define LOG_IO (1U << 2)
#define LOG_BYPASS (1U << 3)
@@ -42,11 +41,6 @@ wtl3132_device::wtl3132_device(machine_config const &mconfig, char const *tag, d
void wtl3132_device::device_start()
{
- m_fpcn_cb.resolve_safe();
- m_fpex_cb.resolve_safe();
- m_zero_cb.resolve_safe();
- m_port_x_cb.resolve_safe();
-
save_item(NAME(m_fpcn_state));
save_item(NAME(m_fpex_state));
save_item(NAME(m_zero_state));
@@ -342,8 +336,8 @@ void wtl3132_device::stage3(unsigned const index)
if ((m_mode & MODE_RTN) && OPF(code, ENCN) == 1)
m_cr = f32_lt(m_aa_in[1], i32_to_f32(-4194304)) || f32_lt(i32_to_f32(4194304), m_aa_in[1]);
- m_a_out.v = (f32_to_i32(m_aa_in[1], (m_mode & MODE_RTN) ?
- softfloat_round_near_even : softfloat_round_min, false) << 8) >> 8;
+ m_a_out.v = util::sext(f32_to_i32(m_aa_in[1], (m_mode & MODE_RTN) ?
+ softfloat_round_near_even : softfloat_round_min, false), 24);
LOG("slot %d stage 3 fix %f == 0x%08x\n", index, u2f(m_aa_in[1].v), m_a_out.v);
break;
case MF_FLUT:
diff --git a/src/devices/machine/x2201.cpp b/src/devices/machine/x2201.cpp
index d93fca101ff..cc35e7c8051 100644
--- a/src/devices/machine/x2201.cpp
+++ b/src/devices/machine/x2201.cpp
@@ -23,7 +23,8 @@
**********************************************************************/
#include "emu.h"
-#include "machine/x2201.h"
+#include "x2201.h"
+
#include <algorithm>
@@ -96,9 +97,10 @@ void x2201_device::nvram_default()
// specified file
//-------------------------------------------------
-void x2201_device::nvram_read(emu_file &file)
+bool x2201_device::nvram_read(util::read_stream &file)
{
- file.read(&m_eeprom[0], 1024 / 8);
+ auto const [err, actual] = util::read(file, &m_eeprom[0], 1024 / 8);
+ return !err && (actual == 1024 / 8);
}
@@ -107,9 +109,10 @@ void x2201_device::nvram_read(emu_file &file)
// specified file
//-------------------------------------------------
-void x2201_device::nvram_write(emu_file &file)
+bool x2201_device::nvram_write(util::write_stream &file)
{
- file.write(&m_eeprom[0], 1024 / 8);
+ auto const [err, actual] = util::write(file, &m_eeprom[0], 1024 / 8);
+ return !err;
}
@@ -149,7 +152,7 @@ void x2201_device::write(offs_t offset, u8 data)
// cs_w - write to the CS line (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(x2201_device::cs_w)
+void x2201_device::cs_w(int state)
{
m_cs = !state;
}
@@ -160,7 +163,7 @@ WRITE_LINE_MEMBER(x2201_device::cs_w)
// (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(x2201_device::store_w)
+void x2201_device::store_w(int state)
{
if (m_cs && !state && !m_store)
std::copy_n(&m_ram[0], 1024 / 8, &m_eeprom[0]);
@@ -174,7 +177,7 @@ WRITE_LINE_MEMBER(x2201_device::store_w)
// into RAM (active low)
//-------------------------------------------------
-WRITE_LINE_MEMBER(x2201_device::array_recall_w)
+void x2201_device::array_recall_w(int state)
{
if (m_cs && !state && !m_array_recall)
std::copy_n(&m_eeprom[0], 1024 / 8, &m_ram[0]);
diff --git a/src/devices/machine/x2201.h b/src/devices/machine/x2201.h
index 1d873850df1..3d5e8dd981d 100644
--- a/src/devices/machine/x2201.h
+++ b/src/devices/machine/x2201.h
@@ -41,9 +41,9 @@ public:
void write(offs_t offset, u8 data);
// control lines
- DECLARE_WRITE_LINE_MEMBER(cs_w);
- DECLARE_WRITE_LINE_MEMBER(array_recall_w);
- DECLARE_WRITE_LINE_MEMBER(store_w);
+ void cs_w(int state);
+ void array_recall_w(int state);
+ void store_w(int state);
protected:
// device-level overrides
@@ -51,8 +51,8 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
// optional default data
diff --git a/src/devices/machine/x2212.cpp b/src/devices/machine/x2212.cpp
index cc5028e0cc7..ddd31ab5af8 100644
--- a/src/devices/machine/x2212.cpp
+++ b/src/devices/machine/x2212.cpp
@@ -9,7 +9,8 @@
***************************************************************************/
#include "emu.h"
-#include "machine/x2212.h"
+#include "x2212.h"
+
#include <algorithm>
@@ -79,9 +80,10 @@ void x2212_device::nvram_default()
// .nv file
//-------------------------------------------------
-void x2212_device::nvram_read(emu_file &file)
+bool x2212_device::nvram_read(util::read_stream &file)
{
- file.read(&m_e2prom[0], m_size_data);
+ auto const [err, actual] = util::read(file, &m_e2prom[0], m_size_data);
+ return !err && (actual == m_size_data);
}
@@ -90,13 +92,14 @@ void x2212_device::nvram_read(emu_file &file)
// .nv file
//-------------------------------------------------
-void x2212_device::nvram_write(emu_file &file)
+bool x2212_device::nvram_write(util::write_stream &file)
{
// auto-save causes an implicit store prior to exiting (writing)
if (m_auto_save)
do_store();
- file.write(&m_e2prom[0], m_size_data);
+ auto const [err, actual] = util::write(file, &m_e2prom[0], m_size_data);
+ return !err;
}
diff --git a/src/devices/machine/x2212.h b/src/devices/machine/x2212.h
index 5fbcb23f532..feeb91a0d23 100644
--- a/src/devices/machine/x2212.h
+++ b/src/devices/machine/x2212.h
@@ -59,8 +59,8 @@ protected:
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read(emu_file &file) override;
- virtual void nvram_write(emu_file &file) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
// configuration state
diff --git a/src/devices/machine/x76f041.cpp b/src/devices/machine/x76f041.cpp
index 03fb5b65bf9..aa96ad90180 100644
--- a/src/devices/machine/x76f041.cpp
+++ b/src/devices/machine/x76f041.cpp
@@ -14,7 +14,11 @@
*/
#include "emu.h"
-#include "machine/x76f041.h"
+#include "x76f041.h"
+
+#include <cstdarg>
+#include <tuple>
+
#define VERBOSE_LEVEL ( 0 )
@@ -23,7 +27,7 @@ inline void ATTR_PRINTF( 3, 4 ) x76f041_device::verboselog( int n_level, const c
if( VERBOSE_LEVEL >= n_level )
{
va_list v;
- char buf[ 32768 ];
+ char buf[32768];
va_start( v, s_fmt );
vsprintf( buf, s_fmt, v );
va_end( v );
@@ -31,11 +35,12 @@ inline void ATTR_PRINTF( 3, 4 ) x76f041_device::verboselog( int n_level, const c
}
}
+
// device type definition
DEFINE_DEVICE_TYPE(X76F041, x76f041_device, "x76f041", "X76F041 Secure SerialFlash")
-x76f041_device::x76f041_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock )
- : device_t( mconfig, X76F041, tag, owner, clock ),
+x76f041_device::x76f041_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock ) :
+ device_t( mconfig, X76F041, tag, owner, clock ),
device_nvram_interface(mconfig, *this),
m_region(*this, DEVICE_SELF),
m_cs( 0 ),
@@ -48,13 +53,15 @@ x76f041_device::x76f041_device( const machine_config &mconfig, const char *tag,
m_bit( 0 ),
m_byte( 0 ),
m_command( 0 ),
- m_address( 0 )
+ m_address( 0 ),
+ m_is_password_accepted ( false )
{
}
void x76f041_device::device_start()
{
- memset( m_write_buffer, 0, sizeof( m_write_buffer ) );
+ std::fill( std::begin( m_write_buffer ), std::end( m_write_buffer ), 0 );
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
save_item( NAME( m_cs ) );
save_item( NAME( m_rst ) );
@@ -67,6 +74,7 @@ void x76f041_device::device_start()
save_item( NAME( m_byte ) );
save_item( NAME( m_command ) );
save_item( NAME( m_address ) );
+ save_item( NAME( m_is_password_accepted ) );
save_item( NAME( m_write_buffer ) );
save_item( NAME( m_response_to_reset ) );
save_item( NAME( m_write_password ) );
@@ -74,9 +82,29 @@ void x76f041_device::device_start()
save_item( NAME( m_configuration_password ) );
save_item( NAME( m_configuration_registers ) );
save_item( NAME( m_data ) );
+ save_item( NAME( m_password_temp ) );
+}
+
+void x76f041_device::device_reset()
+{
+ std::fill( std::begin( m_write_buffer ), std::end( m_write_buffer ), 0 );
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_cs = 0;
+ m_rst = 0;
+ m_scl = 0;
+ m_sdaw = 0;
+ m_sdar = 0;
+ m_state = STATE_STOP;
+ m_shift = 0;
+ m_bit = 0;
+ m_byte = 0;
+ m_command = 0;
+ m_address = 0;
+ m_is_password_accepted = false;
}
-WRITE_LINE_MEMBER( x76f041_device::write_cs )
+void x76f041_device::write_cs(int state)
{
if( m_cs != state )
{
@@ -100,7 +128,7 @@ WRITE_LINE_MEMBER( x76f041_device::write_cs )
m_cs = state;
}
-WRITE_LINE_MEMBER( x76f041_device::write_rst )
+void x76f041_device::write_rst(int state)
{
if( m_rst != state )
{
@@ -128,6 +156,15 @@ uint8_t *x76f041_device::password()
case COMMAND_READ:
return m_read_password;
+ case COMMAND_CONFIGURATION:
+ if( m_address == CONFIGURATION_PROGRAM_WRITE_PASSWORD )
+ return m_write_password;
+
+ if( m_address == CONFIGURATION_PROGRAM_READ_PASSWORD )
+ return m_read_password;
+
+ return m_configuration_password;
+
default:
return m_configuration_password;
}
@@ -135,6 +172,9 @@ uint8_t *x76f041_device::password()
void x76f041_device::password_ok()
{
+ if( m_configuration_registers[CONFIG_CR] & CR_RETRY_COUNTER_RESET_BIT )
+ m_configuration_registers[CONFIG_RC] = 0;
+
switch( m_command & 0xe0 )
{
case COMMAND_WRITE:
@@ -144,7 +184,7 @@ void x76f041_device::password_ok()
m_state = STATE_READ_DATA;
break;
case COMMAND_WRITE_USE_CONFIGURATION_PASSWORD:
- m_state = STATE_WRITE_DATA;
+ m_state = STATE_CONFIGURATION_WRITE_DATA;
break;
case COMMAND_READ_USE_CONFIGURATION_PASSWORD:
m_state = STATE_READ_DATA;
@@ -153,14 +193,22 @@ void x76f041_device::password_ok()
switch( m_address )
{
case CONFIGURATION_PROGRAM_WRITE_PASSWORD:
+ m_state = STATE_PROGRAM_WRITE_PASSWORD;
+ m_byte = 0;
break;
case CONFIGURATION_PROGRAM_READ_PASSWORD:
+ m_state = STATE_PROGRAM_READ_PASSWORD;
+ m_byte = 0;
break;
case CONFIGURATION_PROGRAM_CONFIGURATION_PASSWORD:
+ m_state = STATE_PROGRAM_CONFIGURATION_PASSWORD;
+ m_byte = 0;
break;
case CONFIGURATION_RESET_WRITE_PASSWORD:
+ m_state = STATE_RESET_WRITE_PASSWORD;
break;
case CONFIGURATION_RESET_READ_PASSWORD:
+ m_state = STATE_RESET_READ_PASSWORD;
break;
case CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS:
m_state = STATE_WRITE_CONFIGURATION_REGISTERS;
@@ -171,8 +219,10 @@ void x76f041_device::password_ok()
m_byte = 0;
break;
case CONFIGURATION_MASS_PROGRAM:
+ m_state = STATE_MASS_PROGRAM;
break;
case CONFIGURATION_MASS_ERASE:
+ m_state = STATE_MASS_ERASE;
break;
default:
break;
@@ -182,21 +232,56 @@ void x76f041_device::password_ok()
void x76f041_device::load_address()
{
- /* todo: handle other bcr bits */
- int bcr;
-
m_address = m_shift;
verboselog( 1, "-> address: %02x\n", m_address );
- if( ( m_command & 1 ) == 0 )
+ if( ( m_configuration_registers[CONFIG_CR] & CR_RETRY_COUNTER_ENABLE_BIT ) != 0 &&
+ m_configuration_registers[CONFIG_RR] == m_configuration_registers[CONFIG_RC] &&
+ ( m_configuration_registers[CONFIG_CR] & CR_UNAUTHORIZED_ACCESS_BITS ) == 0x80 )
{
- bcr = m_configuration_registers[ CONFIG_BCR1 ];
+ // No commands are allowed
+ verboselog( 1, "unauthorized access rejected\n" );
+ m_state = STATE_STOP;
+ m_sdar = 1;
+ m_byte = 0;
+ return;
}
- else
+
+ if( ( m_command & 0xe0 ) == COMMAND_CONFIGURATION )
{
- bcr = m_configuration_registers[ CONFIG_BCR2 ];
+ // Configuration commands can be used regardless of array control register bits
+ if( m_address == CONFIGURATION_RESET_WRITE_PASSWORD ||
+ m_address == CONFIGURATION_RESET_READ_PASSWORD ||
+ m_address == CONFIGURATION_MASS_PROGRAM ||
+ m_address == CONFIGURATION_MASS_ERASE )
+ {
+ verboselog( 1, "password not required\n" );
+ password_ok();
+ }
+ else
+ {
+ verboselog( 1, "send password\n" );
+ m_state = STATE_LOAD_PASSWORD;
+ m_byte = 0;
+ }
+
+ return;
+ }
+
+ if( ( m_configuration_registers[CONFIG_CR] & CR_RETRY_COUNTER_ENABLE_BIT ) != 0 &&
+ m_configuration_registers[CONFIG_RR] == m_configuration_registers[CONFIG_RC] &&
+ ( m_configuration_registers[CONFIG_CR] & CR_UNAUTHORIZED_ACCESS_BITS ) != 0x80 )
+ {
+ // Only configuration commands are allowed
+ verboselog( 1, "unauthorized access rejected\n" );
+ m_state = STATE_STOP;
+ m_sdar = 1;
+ m_byte = 0;
+ return;
}
+
+ int bcr = m_configuration_registers[( m_command & 1 ) ? CONFIG_BCR2 : CONFIG_BCR1];
if( ( m_address & 0x80 ) != 0 )
{
bcr >>= 4;
@@ -205,10 +290,11 @@ void x76f041_device::load_address()
if( ( ( m_command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Z ) != 0 && ( bcr & BCR_T ) != 0 ) ||
( ( m_command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_Z ) != 0 ) )
{
- /* todo: find out when this is really checked. */
+ /* TODO: find out when this is really checked. */
verboselog( 1, "command not allowed\n" );
m_state = STATE_STOP;
- m_sdar = 0;
+ m_sdar = 1;
+ m_byte = 0;
}
else if( ( ( m_command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_X ) == 0 ) ||
( ( m_command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Y ) == 0 ) )
@@ -233,7 +319,7 @@ int x76f041_device::data_offset()
return ( block_offset & 0x180 ) | ( ( block_offset + m_byte ) & 0x7f );
}
-WRITE_LINE_MEMBER( x76f041_device::write_scl )
+void x76f041_device::write_scl(int state)
{
if( m_scl != state )
{
@@ -250,7 +336,7 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
case STATE_RESPONSE_TO_RESET:
if( m_scl != 0 && state == 0 )
{
- m_sdar = ( m_response_to_reset[ m_byte ] >> m_bit ) & 1;
+ m_sdar = ( m_response_to_reset[m_byte] >> m_bit ) & 1;
verboselog( 2, "in response to reset %d (%d/%d)\n", m_sdar, m_byte, m_bit );
m_bit++;
@@ -272,7 +358,18 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
case STATE_LOAD_PASSWORD:
case STATE_VERIFY_PASSWORD:
case STATE_WRITE_DATA:
+ case STATE_CONFIGURATION_WRITE_DATA:
case STATE_WRITE_CONFIGURATION_REGISTERS:
+ case STATE_PROGRAM_WRITE_PASSWORD:
+ case STATE_PROGRAM_READ_PASSWORD:
+ case STATE_PROGRAM_CONFIGURATION_PASSWORD:
+ case STATE_RESET_WRITE_PASSWORD:
+ case STATE_RESET_READ_PASSWORD:
+ case STATE_MASS_PROGRAM:
+ case STATE_MASS_ERASE:
+ // FIXME: Processing on the rising edge of the clock causes sda to change state while clock is high
+ // which is not allowed. Also need to ensure that only valid device-id's and commands
+ // are acknowledged.
if( m_scl == 0 && state != 0 )
{
if( m_bit < 8 )
@@ -296,7 +393,7 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
case STATE_LOAD_COMMAND:
m_command = m_shift;
verboselog( 1, "-> command: %02x\n", m_command );
- /* todo: verify command is valid? */
+ /* TODO: verify command is valid? */
m_state = STATE_LOAD_ADDRESS;
break;
@@ -306,22 +403,32 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
case STATE_LOAD_PASSWORD:
verboselog( 1, "-> password: %02x\n", m_shift );
- m_write_buffer[ m_byte++ ] = m_shift;
+ m_write_buffer[m_byte++] = m_shift;
if( m_byte == sizeof( m_write_buffer ) )
{
m_state = STATE_VERIFY_PASSWORD;
+
+ // Perform the password acceptance check before verify password because
+ // password verify ack is spammed and will quickly overflow the
+ // retry counter.
+ m_is_password_accepted = memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0;
+ if( !m_is_password_accepted )
+ {
+ if( m_configuration_registers[CONFIG_CR] & CR_RETRY_COUNTER_ENABLE_BIT )
+ m_configuration_registers[CONFIG_RC]++;
+ }
}
break;
case STATE_VERIFY_PASSWORD:
verboselog( 1, "-> verify password: %02x\n", m_shift );
- /* todo: this should probably be handled as a command */
+ /* TODO: this should probably be handled as a command */
if( m_shift == 0xc0 )
{
- /* todo: this should take 10ms before it returns ok. */
- if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 )
+ /* TODO: this should take 10ms before it returns ok. */
+ if( m_is_password_accepted )
{
password_ok();
}
@@ -334,15 +441,45 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
case STATE_WRITE_DATA:
verboselog( 2, "-> data: %02x\n", m_shift );
- m_write_buffer[ m_byte++ ] = m_shift;
+ m_write_buffer[m_byte++] = m_shift;
if( m_byte == sizeof( m_write_buffer ) )
{
+ int bcr = m_configuration_registers[( m_command & 1 ) ? CONFIG_BCR2 : CONFIG_BCR1];
+ if( ( m_address & 0x80 ) != 0 )
+ {
+ bcr >>= 4;
+ }
+
+ if( ( bcr & ( BCR_Z | BCR_T ) ) == BCR_T )
+ {
+ // Bits in the data can only be set, not cleared, when in program only mode
+ bool is_unauthorized_write = false;
+
+ for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
+ {
+ int offset = data_offset();
+ if( m_write_buffer[m_byte] < m_data[offset] )
+ {
+ verboselog( 1, "tried to unset bits while in program only mode\n" );
+ is_unauthorized_write = true;
+ break;
+ }
+ }
+
+ if( is_unauthorized_write )
+ {
+ m_sdar = 1;
+ m_byte = 0;
+ break;
+ }
+ }
+
for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
{
int offset = data_offset();
- verboselog( 1, "-> data[ %03x ]: %02x\n", offset, m_write_buffer[ m_byte ] );
- m_data[ offset ] = m_write_buffer[ m_byte ];
+ verboselog( 1, "-> data[%03x]: %02x\n", offset, m_write_buffer[m_byte] );
+ m_data[offset] = m_write_buffer[m_byte];
}
m_byte = 0;
@@ -350,16 +487,109 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
}
break;
+
+ case STATE_CONFIGURATION_WRITE_DATA:
+ // Unlike normal writes, configuration writes aren't required to be exactly 8 bytes
+ // TODO: Store data in a temporary buffer until the proper end of the command before writing
+ verboselog( 2, "-> data: %02x\n", m_shift );
+ m_data[data_offset()] = m_shift;
+ m_byte++;
+ break;
+
case STATE_WRITE_CONFIGURATION_REGISTERS:
- verboselog( 1, "-> configuration register[ %d ]: %02x\n", m_byte, m_shift );
- /* todo: write after all bytes received? */
- m_configuration_registers[ m_byte++ ] = m_shift;
+ verboselog( 1, "-> configuration register[%d]: %02x\n", m_byte, m_shift );
+ /* TODO: write after all bytes received? */
+ m_configuration_registers[m_byte++] = m_shift;
if( m_byte == sizeof( m_configuration_registers ) )
{
m_byte = 0;
}
break;
+
+ case STATE_PROGRAM_WRITE_PASSWORD:
+ verboselog( 1, "-> program write password[%d]: %02x\n", m_byte, m_shift );
+ m_password_temp[m_byte++] = m_shift;
+
+ if( m_byte == sizeof( m_password_temp ) )
+ {
+ // Read in the password twice and if the two copies match then write it to the password field
+ if( memcmp( &m_password_temp[0], &m_password_temp[8], sizeof( m_write_password ) ) == 0 )
+ {
+ std::copy_n( std::begin( m_password_temp ), sizeof( m_write_password ), std::begin ( m_write_password ) );
+ }
+ else {
+ m_sdar = 1;
+ }
+
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_byte = 0;
+ }
+ break;
+
+ case STATE_PROGRAM_READ_PASSWORD:
+ verboselog( 1, "-> program read password[%d]: %02x\n", m_byte, m_shift );
+ m_password_temp[m_byte++] = m_shift;
+
+ if( m_byte == sizeof( m_password_temp ) )
+ {
+ if( memcmp( &m_password_temp[0], &m_password_temp[8], sizeof( m_read_password ) ) == 0 )
+ {
+ std::copy_n( std::begin( m_password_temp ), sizeof( m_read_password ), std::begin ( m_read_password ) );
+ }
+ else {
+ m_sdar = 1;
+ }
+
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_byte = 0;
+ }
+ break;
+
+ case STATE_PROGRAM_CONFIGURATION_PASSWORD:
+ verboselog( 1, "-> program configuration password[%d]: %02x\n", m_byte, m_shift );
+ m_password_temp[m_byte++] = m_shift;
+
+ if( m_byte == sizeof( m_password_temp ) )
+ {
+ if( memcmp( &m_password_temp[0], &m_password_temp[8], sizeof( m_configuration_password ) ) == 0 )
+ {
+ std::copy_n( std::begin( m_password_temp ), sizeof( m_configuration_password ), std::begin ( m_configuration_password ) );
+ }
+ else {
+ m_sdar = 1;
+ }
+
+ std::fill( std::begin( m_password_temp ), std::end( m_password_temp ), 0 );
+
+ m_byte = 0;
+ }
+ break;
+
+ case STATE_RESET_WRITE_PASSWORD:
+ verboselog( 1, "-> reset write password\n" );
+ std::fill( std::begin( m_write_password ), std::end( m_write_password ), 0 );
+ break;
+
+ case STATE_RESET_READ_PASSWORD:
+ verboselog( 1, "-> reset read password\n" );
+ std::fill( std::begin( m_read_password ), std::end( m_read_password ), 0 );
+ break;
+
+ case STATE_MASS_PROGRAM:
+ case STATE_MASS_ERASE:
+ {
+ const uint8_t fill = m_state == STATE_MASS_ERASE ? 0xff : 0;
+ verboselog( 1, "-> mass erase %02x\n", fill );
+ std::fill( std::begin( m_data ), std::end( m_data ), fill );
+ std::fill( std::begin( m_configuration_password ), std::end( m_configuration_password ), fill );
+ std::fill( std::begin( m_configuration_registers ), std::end( m_configuration_registers ), fill );
+ std::fill( std::begin( m_write_password ), std::end( m_write_password ), fill );
+ std::fill( std::begin( m_read_password ), std::end( m_read_password ), fill );
+ break;
+ }
}
m_bit = 0;
@@ -370,6 +600,8 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
case STATE_READ_DATA:
case STATE_READ_CONFIGURATION_REGISTERS:
+ // FIXME: Processing on the rising edge of the clock causes sda to change state while clock is high
+ // which is not allowed.
if( m_scl == 0 && state != 0 )
{
if( m_bit < 8 )
@@ -382,14 +614,14 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
{
case STATE_READ_DATA:
offset = data_offset();
- m_shift = m_data[ offset ];
- verboselog( 1, "<- data[ %03x ]: %02x\n", offset, m_shift );
+ m_shift = m_data[offset];
+ verboselog( 1, "<- data[%03x]: %02x\n", offset, m_shift );
break;
case STATE_READ_CONFIGURATION_REGISTERS:
offset = m_byte & 7;
- m_shift = m_configuration_registers[ offset ];
- verboselog( 1, "<- configuration register[ %d ]: %02x\n", offset, m_shift );
+ m_shift = m_configuration_registers[offset];
+ verboselog( 1, "<- configuration register[%d]: %02x\n", offset, m_shift );
break;
}
}
@@ -421,7 +653,7 @@ WRITE_LINE_MEMBER( x76f041_device::write_scl )
m_scl = state;
}
-WRITE_LINE_MEMBER( x76f041_device::write_sda )
+void x76f041_device::write_sda(int state)
{
if( m_sdaw != state )
{
@@ -447,7 +679,7 @@ WRITE_LINE_MEMBER( x76f041_device::write_sda )
break;
case STATE_LOAD_PASSWORD:
- /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */
+ /* TODO: this will be the 0xc0 command, but it's not handled as a command yet. */
verboselog( 1, "goto start\n" );
break;
@@ -471,7 +703,7 @@ WRITE_LINE_MEMBER( x76f041_device::write_sda )
m_sdaw = state;
}
-READ_LINE_MEMBER( x76f041_device::read_sda )
+int x76f041_device::read_sda()
{
if( m_cs != 0 )
{
@@ -520,22 +752,56 @@ void x76f041_device::nvram_default()
}
}
-void x76f041_device::nvram_read( emu_file &file )
+bool x76f041_device::nvram_read( util::read_stream &file )
{
- file.read( m_response_to_reset, sizeof( m_response_to_reset ) );
- file.read( m_write_password, sizeof( m_write_password ) );
- file.read( m_read_password, sizeof( m_read_password ) );
- file.read( m_configuration_password, sizeof( m_configuration_password ) );
- file.read( m_configuration_registers, sizeof( m_configuration_registers ) );
- file.read( m_data, sizeof( m_data ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = read( file, m_response_to_reset, sizeof( m_response_to_reset ) );
+ if( err || ( sizeof( m_response_to_reset ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_write_password, sizeof( m_write_password ) );
+ if( err || ( sizeof( m_write_password ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_read_password, sizeof( m_read_password ) );
+ if( err || ( sizeof( m_read_password ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_configuration_password, sizeof( m_configuration_password ) );
+ if( err || ( sizeof( m_configuration_password ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_configuration_registers, sizeof( m_configuration_registers ) );
+ if( err || ( sizeof( m_configuration_registers ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_data, sizeof( m_data ) );
+ if( err || ( sizeof( m_data ) != actual ) )
+ return false;
+
+ return true;
}
-void x76f041_device::nvram_write( emu_file &file )
+bool x76f041_device::nvram_write( util::write_stream &file )
{
- file.write( m_response_to_reset, sizeof( m_response_to_reset ) );
- file.write( m_write_password, sizeof( m_write_password ) );
- file.write( m_read_password, sizeof( m_read_password ) );
- file.write( m_configuration_password, sizeof( m_configuration_password ) );
- file.write( m_configuration_registers, sizeof( m_configuration_registers ) );
- file.write( m_data, sizeof( m_data ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = write( file, m_response_to_reset, sizeof( m_response_to_reset ) );
+ if (err)
+ return false;
+ std::tie( err, actual ) = write( file, m_write_password, sizeof( m_write_password ) );
+ if (err)
+ return false;
+ std::tie( err, actual ) = write( file, m_read_password, sizeof( m_read_password ) );
+ if (err)
+ return false;
+ std::tie( err, actual ) = write( file, m_configuration_password, sizeof( m_configuration_password ) );
+ if (err)
+ return false;
+ std::tie( err, actual ) = write( file, m_configuration_registers, sizeof( m_configuration_registers ) );
+ if (err)
+ return false;
+ std::tie( err, actual ) = write( file, m_data, sizeof( m_data ) );
+ if (err)
+ return false;
+
+ return true;
}
diff --git a/src/devices/machine/x76f041.h b/src/devices/machine/x76f041.h
index af487f75a1d..cb28bccc54b 100644
--- a/src/devices/machine/x76f041.h
+++ b/src/devices/machine/x76f041.h
@@ -18,25 +18,26 @@ class x76f041_device : public device_t,
{
public:
// construction/destruction
- x76f041_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ x76f041_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- DECLARE_WRITE_LINE_MEMBER( write_cs );
- DECLARE_WRITE_LINE_MEMBER( write_rst );
- DECLARE_WRITE_LINE_MEMBER( write_scl );
- DECLARE_WRITE_LINE_MEMBER( write_sda );
- DECLARE_READ_LINE_MEMBER( read_sda );
+ void write_cs(int state);
+ void write_rst(int state);
+ void write_scl(int state);
+ void write_sda(int state);
+ int read_sda();
protected:
// device-level overrides
virtual void device_start() override;
+ virtual void device_reset() override;
// device_nvram_interface overrides
virtual void nvram_default() override;
- virtual void nvram_read( emu_file &file ) override;
- virtual void nvram_write( emu_file &file ) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
- inline void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, const char *s_fmt, ... );
+ inline void ATTR_PRINTF(3, 4) verboselog(int n_level, const char *s_fmt, ...);
uint8_t *password();
void password_ok();
void load_address();
@@ -44,11 +45,24 @@ private:
enum configuration_register_t
{
- CONFIG_BCR1 = 0,
- CONFIG_BCR2 = 1,
- CONFIG_CR = 2,
- CONFIG_RR = 3,
- CONFIG_RC = 4
+ // If set to 1, retry counter is incremented when an invalid password is provided
+ CR_RETRY_COUNTER_ENABLE_BIT = 0x04,
+
+ // If set to 1, retry counter will be reset when a correct password is provided
+ CR_RETRY_COUNTER_RESET_BIT = 0x08,
+
+ // 10 = If retry counter is enabled, deny all commands when retry register equals retry counter
+ // 00, 01, 11 = If retry counter is enabled, allow only configuration commands when retry register equals retry counter
+ CR_UNAUTHORIZED_ACCESS_BITS = 0xc0,
+ };
+
+ enum configuration_registers_t
+ {
+ CONFIG_BCR1 = 0, // Array Control Register
+ CONFIG_BCR2 = 1, // Array Control Register 2
+ CONFIG_CR = 2, // Configuration Register
+ CONFIG_RR = 3, // Retry Register
+ CONFIG_RC = 4 // Reset Counter
};
enum bcr_t
@@ -91,8 +105,18 @@ private:
STATE_VERIFY_PASSWORD,
STATE_READ_DATA,
STATE_WRITE_DATA,
+ STATE_CONFIGURATION_WRITE_DATA,
STATE_READ_CONFIGURATION_REGISTERS,
- STATE_WRITE_CONFIGURATION_REGISTERS
+ STATE_WRITE_CONFIGURATION_REGISTERS,
+
+ STATE_PROGRAM_WRITE_PASSWORD,
+ STATE_PROGRAM_READ_PASSWORD,
+ STATE_PROGRAM_CONFIGURATION_PASSWORD,
+
+ STATE_RESET_WRITE_PASSWORD,
+ STATE_RESET_READ_PASSWORD,
+ STATE_MASS_PROGRAM,
+ STATE_MASS_ERASE
};
optional_memory_region m_region;
@@ -109,13 +133,15 @@ private:
int m_byte;
int m_command;
int m_address;
- uint8_t m_write_buffer[ 8 ];
- uint8_t m_response_to_reset[ 4 ];
- uint8_t m_write_password[ 8 ];
- uint8_t m_read_password[ 8 ];
- uint8_t m_configuration_password[ 8 ];
- uint8_t m_configuration_registers[ 8 ];
- uint8_t m_data[ 512 ];
+ bool m_is_password_accepted;
+ uint8_t m_write_buffer[8];
+ uint8_t m_response_to_reset[4];
+ uint8_t m_write_password[8];
+ uint8_t m_read_password[8];
+ uint8_t m_configuration_password[8];
+ uint8_t m_configuration_registers[8];
+ uint8_t m_data[512];
+ uint8_t m_password_temp[16];
};
diff --git a/src/devices/machine/x76f100.cpp b/src/devices/machine/x76f100.cpp
index 4c74bb5b7ad..b64bbdf32c2 100644
--- a/src/devices/machine/x76f100.cpp
+++ b/src/devices/machine/x76f100.cpp
@@ -12,7 +12,11 @@
*/
#include "emu.h"
-#include "machine/x76f100.h"
+#include "x76f100.h"
+
+#include <cstdarg>
+#include <tuple>
+
#define VERBOSE_LEVEL ( 0 )
@@ -21,7 +25,7 @@ inline void ATTR_PRINTF( 3, 4 ) x76f100_device::verboselog( int n_level, const c
if( VERBOSE_LEVEL >= n_level )
{
va_list v;
- char buf[ 32768 ];
+ char buf[32768];
va_start( v, s_fmt );
vsprintf( buf, s_fmt, v );
va_end( v );
@@ -29,11 +33,13 @@ inline void ATTR_PRINTF( 3, 4 ) x76f100_device::verboselog( int n_level, const c
}
}
+
// device type definition
DEFINE_DEVICE_TYPE(X76F100, x76f100_device, "x76f100", "X76F100 Secure SerialFlash")
-x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock )
- : device_t( mconfig, X76F100, tag, owner, clock ),
+
+x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock ) :
+ device_t( mconfig, X76F100, tag, owner, clock ),
device_nvram_interface(mconfig, *this),
m_region(*this, DEVICE_SELF),
m_cs( 0 ),
@@ -45,13 +51,15 @@ x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag,
m_shift( 0 ),
m_bit( 0 ),
m_byte( 0 ),
- m_command( 0 )
+ m_command( 0 ),
+ m_password_retry_counter( 0 ),
+ m_is_password_accepted( false )
{
}
void x76f100_device::device_start()
{
- memset( m_write_buffer, 0, sizeof( m_write_buffer ) );
+ std::fill( std::begin( m_write_buffer ), std::end( m_write_buffer ), 0 );
save_item( NAME( m_cs ) );
save_item( NAME( m_rst ) );
@@ -63,6 +71,8 @@ void x76f100_device::device_start()
save_item( NAME( m_bit ) );
save_item( NAME( m_byte ) );
save_item( NAME( m_command ) );
+ save_item( NAME( m_password_retry_counter ) );
+ save_item( NAME( m_is_password_accepted ) );
save_item( NAME( m_write_buffer ) );
save_item( NAME( m_response_to_reset ) );
save_item( NAME( m_write_password ) );
@@ -70,7 +80,25 @@ void x76f100_device::device_start()
save_item( NAME( m_data ) );
}
-WRITE_LINE_MEMBER( x76f100_device::write_cs )
+void x76f100_device::device_reset()
+{
+ std::fill( std::begin( m_write_buffer ), std::end( m_write_buffer ), 0 );
+
+ m_cs = 0;
+ m_rst = 0;
+ m_scl = 0;
+ m_sdaw = 0;
+ m_sdar = 0;
+ m_state = STATE_STOP;
+ m_shift = 0;
+ m_bit = 0;
+ m_byte = 0;
+ m_command = 0;
+ m_password_retry_counter = 0;
+ m_is_password_accepted = false;
+}
+
+void x76f100_device::write_cs(int state)
{
if( m_cs != state )
{
@@ -94,7 +122,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_cs )
m_cs = state;
}
-WRITE_LINE_MEMBER( x76f100_device::write_rst )
+void x76f100_device::write_rst(int state)
{
if( m_rst != state )
{
@@ -124,11 +152,13 @@ uint8_t *x76f100_device::password()
void x76f100_device::password_ok()
{
- if( ( m_command & 0xe1 ) == COMMAND_READ )
+ m_password_retry_counter = 0;
+
+ if( ( m_command & 0x81 ) == COMMAND_READ )
{
m_state = STATE_READ_DATA;
}
- else if( ( m_command & 0xe1 ) == COMMAND_WRITE )
+ else if( ( m_command & 0x81 ) == COMMAND_WRITE )
{
m_state = STATE_WRITE_DATA;
}
@@ -141,11 +171,18 @@ void x76f100_device::password_ok()
int x76f100_device::data_offset()
{
int block_offset = ( m_command >> 1 ) & 0x0f;
+ int offset = ( block_offset * sizeof( m_write_buffer ) ) + m_byte;
+
+ // Technically there are 4 bits assigned to sector values but since the data array is only 112 bytes,
+ // it will try reading out of bounds when the sector is 14 (= starts at 112) or 15 (= starts at 120).
+ // TODO: Verify what happens on real hardware when reading/writing sectors 14 and 15
+ if( offset >= sizeof ( m_data ) )
+ return -1;
- return ( block_offset * sizeof( m_write_buffer ) ) + m_byte;
+ return offset;
}
-WRITE_LINE_MEMBER( x76f100_device::write_scl )
+void x76f100_device::write_scl(int state)
{
if( m_scl != state )
{
@@ -164,7 +201,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
{
if( m_bit == 0 )
{
- m_shift = m_response_to_reset[ m_byte ];
+ m_shift = m_response_to_reset[m_byte];
verboselog( 1, "<- response_to_reset[%d]: %02x\n", m_byte, m_shift );
}
@@ -189,6 +226,9 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
case STATE_LOAD_PASSWORD:
case STATE_VERIFY_PASSWORD:
case STATE_WRITE_DATA:
+ // FIXME: Processing on the rising edge of the clock causes sda to change state while clock is high
+ // which is not allowed. Also need to ensure that only valid device-id's and commands
+ // are acknowledged.
if( m_scl == 0 && state != 0 )
{
if( m_bit < 8 )
@@ -212,28 +252,47 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
case STATE_LOAD_COMMAND:
m_command = m_shift;
verboselog( 1, "-> command: %02x\n", m_command );
- /* todo: verify command is valid? */
+ /* TODO: verify command is valid? */
m_state = STATE_LOAD_PASSWORD;
break;
case STATE_LOAD_PASSWORD:
verboselog( 1, "-> password: %02x\n", m_shift );
- m_write_buffer[ m_byte++ ] = m_shift;
+ m_write_buffer[m_byte++] = m_shift;
if( m_byte == sizeof( m_write_buffer ) )
{
m_state = STATE_VERIFY_PASSWORD;
+
+ // Perform the password acceptance check before verify password because
+ // password verify ack is spammed and will quickly overflow the
+ // retry counter. This becomes an issue with System 573 games that use the
+ // X76F100 as an install cartridge. The boot process first tries to use the
+ // game cartridge password and if not accepted will try the install cartridge
+ // password and then enter installation mode if accepted.
+ m_is_password_accepted = memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0;
+ if( !m_is_password_accepted )
+ {
+ m_password_retry_counter++;
+ if( m_password_retry_counter >= 8 )
+ {
+ std::fill( std::begin( m_read_password ), std::end( m_read_password ), 0 );
+ std::fill( std::begin( m_write_password ), std::end( m_write_password ), 0 );
+ std::fill( std::begin( m_data ), std::end( m_data ), 0 );
+ m_password_retry_counter = 0;
+ }
+ }
}
break;
case STATE_VERIFY_PASSWORD:
verboselog( 1, "-> verify password: %02x\n", m_shift );
- /* todo: this should probably be handled as a command */
+ /* TODO: this should probably be handled as a command */
if( m_shift == COMMAND_ACK_PASSWORD )
{
- /* todo: this should take 10ms before it returns ok. */
- if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 )
+ /* TODO: this should take 10ms before it returns ok. */
+ if( m_is_password_accepted )
{
password_ok();
}
@@ -246,15 +305,35 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
case STATE_WRITE_DATA:
verboselog( 2, "-> data: %02x\n", m_shift );
- m_write_buffer[ m_byte++ ] = m_shift;
+ m_write_buffer[m_byte++] = m_shift;
if( m_byte == sizeof( m_write_buffer ) )
{
- for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
+ if( m_command == COMMAND_CHANGE_WRITE_PASSWORD )
{
- int offset = data_offset();
- verboselog( 1, "-> data[ %03x ]: %02x\n", offset, m_write_buffer[ m_byte ] );
- m_data[ offset ] = m_write_buffer[ m_byte ];
+ std::copy( std::begin( m_write_buffer ), std::end( m_write_buffer ), std::begin( m_write_password ) );
+ }
+ else if( m_command == COMMAND_CHANGE_READ_PASSWORD )
+ {
+ std::copy( std::begin( m_write_buffer ), std::end( m_write_buffer ), std::begin( m_read_password ) );
+ }
+ else
+ {
+ for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ )
+ {
+ int offset = data_offset();
+
+ if( offset != -1 )
+ {
+ verboselog( 1, "-> data[%03x]: %02x\n", offset, m_write_buffer[m_byte] );
+ m_data[offset] = m_write_buffer[m_byte];
+ }
+ else
+ {
+ verboselog( 1, "-> attempted to write %02x out of bounds\n", m_write_buffer[m_byte] );
+ break;
+ }
+ }
}
m_byte = 0;
@@ -271,6 +350,8 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
break;
case STATE_READ_DATA:
+ // FIXME: Processing on the rising edge of the clock causes sda to change state while clock is high
+ // which is not allowed.
if( m_scl == 0 && state != 0 )
{
if( m_bit < 8 )
@@ -283,8 +364,18 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
{
case STATE_READ_DATA:
offset = data_offset();
- m_shift = m_data[ offset ];
- verboselog( 1, "<- data[ %02x ]: %02x\n", offset, m_shift );
+
+ if( offset != -1 )
+ {
+ m_shift = m_data[offset];
+ verboselog( 1, "<- data[%02x]: %02x\n", offset, m_shift );
+ }
+ else
+ {
+ m_shift = 0;
+ verboselog( 1, "<- attempted to read out of bounds\n" );
+ }
+
break;
}
}
@@ -316,7 +407,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_scl )
m_scl = state;
}
-WRITE_LINE_MEMBER( x76f100_device::write_sda )
+void x76f100_device::write_sda(int state)
{
if( m_sdaw != state )
{
@@ -342,7 +433,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_sda )
break;
case STATE_LOAD_PASSWORD:
- /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */
+ /* TODO: this will be the 0xc0 command, but it's not handled as a command yet. */
verboselog( 1, "goto start\n" );
break;
@@ -367,7 +458,7 @@ WRITE_LINE_MEMBER( x76f100_device::write_sda )
m_sdaw = state;
}
-READ_LINE_MEMBER( x76f100_device::read_sda )
+int x76f100_device::read_sda()
{
if( m_cs != 0 )
{
@@ -381,10 +472,10 @@ READ_LINE_MEMBER( x76f100_device::read_sda )
void x76f100_device::nvram_default()
{
- m_response_to_reset[ 0 ] = 0x19;
- m_response_to_reset[ 1 ] = 0x00;
- m_response_to_reset[ 2 ] = 0xaa;
- m_response_to_reset[ 3 ] = 0x55,
+ m_response_to_reset[0] = 0x19;
+ m_response_to_reset[1] = 0x00;
+ m_response_to_reset[2] = 0xaa;
+ m_response_to_reset[3] = 0x55,
memset( m_write_password, 0, sizeof( m_write_password ) );
memset( m_read_password, 0, sizeof( m_read_password ) );
@@ -411,18 +502,44 @@ void x76f100_device::nvram_default()
}
}
-void x76f100_device::nvram_read( emu_file &file )
+bool x76f100_device::nvram_read( util::read_stream &file )
{
- file.read( m_response_to_reset, sizeof( m_response_to_reset ) );
- file.read( m_write_password, sizeof( m_write_password ) );
- file.read( m_read_password, sizeof( m_read_password ) );
- file.read( m_data, sizeof( m_data ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = read( file, m_response_to_reset, sizeof( m_response_to_reset ) );
+ if( err || ( sizeof( m_response_to_reset ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_write_password, sizeof( m_write_password ) );
+ if( err || ( sizeof( m_write_password ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_read_password, sizeof( m_read_password ) );
+ if( err || ( sizeof( m_read_password ) != actual ) )
+ return false;
+ std::tie( err, actual ) = read( file, m_data, sizeof( m_data ) );
+ if( err || ( sizeof( m_data ) != actual ) )
+ return false;
+
+ return true;
}
-void x76f100_device::nvram_write( emu_file &file )
+bool x76f100_device::nvram_write( util::write_stream &file )
{
- file.write( m_response_to_reset, sizeof( m_response_to_reset ) );
- file.write( m_write_password, sizeof( m_write_password ) );
- file.write( m_read_password, sizeof( m_read_password ) );
- file.write( m_data, sizeof( m_data ) );
+ std::error_condition err;
+ size_t actual;
+
+ std::tie( err, actual ) = write( file, m_response_to_reset, sizeof( m_response_to_reset ) );
+ if ( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_write_password, sizeof( m_write_password ) );
+ if ( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_read_password, sizeof( m_read_password ) );
+ if ( err )
+ return false;
+ std::tie( err, actual ) = write( file, m_data, sizeof( m_data ) );
+ if ( err )
+ return false;
+
+ return true;
}
diff --git a/src/devices/machine/x76f100.h b/src/devices/machine/x76f100.h
index acec66e9c62..a323ff40fa6 100644
--- a/src/devices/machine/x76f100.h
+++ b/src/devices/machine/x76f100.h
@@ -17,22 +17,23 @@ class x76f100_device : public device_t, public device_nvram_interface
{
public:
// construction/destruction
- x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ x76f100_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- DECLARE_WRITE_LINE_MEMBER( write_cs );
- DECLARE_WRITE_LINE_MEMBER( write_rst );
- DECLARE_WRITE_LINE_MEMBER( write_scl );
- DECLARE_WRITE_LINE_MEMBER( write_sda );
- DECLARE_READ_LINE_MEMBER( read_sda );
+ void write_cs(int state);
+ void write_rst(int state);
+ void write_scl(int state);
+ void write_sda(int state);
+ int read_sda();
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
+ virtual void device_reset() override;
- // device_nvram_interface overrides
+ // device_nvram_interface implementation
virtual void nvram_default() override;
- virtual void nvram_read( emu_file &file ) override;
- virtual void nvram_write( emu_file &file ) override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
private:
inline void verboselog(int n_level, const char *s_fmt, ...) ATTR_PRINTF(3,4);
@@ -74,11 +75,13 @@ private:
int m_bit;
int m_byte;
int m_command;
- uint8_t m_write_buffer[ 8 ];
- uint8_t m_response_to_reset[ 4 ];
- uint8_t m_write_password[ 8 ];
- uint8_t m_read_password[ 8 ];
- uint8_t m_data[ 112 ];
+ int m_password_retry_counter;
+ bool m_is_password_accepted;
+ uint8_t m_write_buffer[8];
+ uint8_t m_response_to_reset[4];
+ uint8_t m_write_password[8];
+ uint8_t m_read_password[8];
+ uint8_t m_data[112];
};
// device type definition
diff --git a/src/devices/machine/xc1700e.cpp b/src/devices/machine/xc1700e.cpp
index fe056664b07..8c91a5293b1 100644
--- a/src/devices/machine/xc1700e.cpp
+++ b/src/devices/machine/xc1700e.cpp
@@ -51,7 +51,7 @@ base_xc1700e_device::base_xc1700e_device(const machine_config &mconfig, device_t
: device_t(mconfig, type, tag, owner, clock)
, m_capacity(capacity)
, m_region(*this, DEVICE_SELF)
- , m_cascade_cb(*this)
+ , m_cascade_cb(*this, 1)
, m_reset(true)
, m_address(0)
{
@@ -59,8 +59,6 @@ base_xc1700e_device::base_xc1700e_device(const machine_config &mconfig, device_t
void base_xc1700e_device::device_start()
{
- m_cascade_cb.resolve_safe(1);
-
save_item(NAME(m_reset));
save_item(NAME(m_address));
}
diff --git a/src/devices/machine/ym2148.cpp b/src/devices/machine/ym2148.cpp
index 04a3e53e97e..24e486e1012 100644
--- a/src/devices/machine/ym2148.cpp
+++ b/src/devices/machine/ym2148.cpp
@@ -22,7 +22,7 @@ ym2148_device::ym2148_device(const machine_config &mconfig, const char *tag, dev
, m_txd_handler(*this)
, m_irq_handler(*this)
, m_port_write_handler(*this)
- , m_port_read_handler(*this)
+ , m_port_read_handler(*this, 0xff)
, m_irq_state(CLEAR_LINE)
, m_irq_vector(0xff) // guess
, m_external_irq_vector(0xff) // guess
@@ -38,14 +38,9 @@ ym2148_device::ym2148_device(const machine_config &mconfig, const char *tag, dev
void ym2148_device::device_start()
{
- m_txd_handler.resolve_safe();
- m_irq_handler.resolve_safe();
- m_port_write_handler.resolve_safe();
- m_port_read_handler.resolve_safe(0xff);
-
// Start a timer to trigger at clock / 8 / 16
const attotime rate = clocks_to_attotime(8 * 16);
- m_timer = timer_alloc(0);
+ m_timer = timer_alloc(FUNC(ym2148_device::serial_clock_tick), this);
m_timer->adjust(rate, 0, rate);
}
@@ -136,7 +131,7 @@ void ym2148_device::update_irq()
}
-void ym2148_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(ym2148_device::serial_clock_tick)
{
receive_clock();
transmit_clock();
@@ -212,7 +207,7 @@ uint8_t ym2148_device::get_irq_vector()
}
-WRITE_LINE_MEMBER(ym2148_device::write_rxd)
+void ym2148_device::write_rxd(int state)
{
m_rxd = state;
}
diff --git a/src/devices/machine/ym2148.h b/src/devices/machine/ym2148.h
index 3cb13bf2058..e0e75188123 100644
--- a/src/devices/machine/ym2148.h
+++ b/src/devices/machine/ym2148.h
@@ -34,13 +34,14 @@ public:
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER(write_rxd);
+ void write_rxd(int state);
uint8_t get_irq_vector();
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(serial_clock_tick);
private:
devcb_write_line m_txd_handler;
diff --git a/src/devices/machine/ym3802.cpp b/src/devices/machine/ym3802.cpp
index 3f0e8080ba7..39008a2ea15 100644
--- a/src/devices/machine/ym3802.cpp
+++ b/src/devices/machine/ym3802.cpp
@@ -23,24 +23,20 @@ ym3802_device::ym3802_device(const machine_config &mconfig, const char *tag, dev
, device_serial_interface(mconfig, *this)
, m_irq_handler(*this)
, m_txd_handler(*this)
- , m_rxd_handler(*this)
+ , m_rxd_handler(*this, 0xff)
, m_reg(REG_MAX)
, m_wdr(0)
, m_irq_status(0)
, m_vector(0)
, m_clkm_rate(500000) // TODO: make these configurable
, m_clkf_rate(614400)
- {
- }
+{
+}
void ym3802_device::device_start()
{
- m_irq_handler.resolve_safe();
- m_txd_handler.resolve_safe();
- m_rxd_handler.resolve_safe(0xff);
- m_clock_timer = timer_alloc(TIMER_SYSTEM_CLOCK);
- m_midi_timer = timer_alloc(TIMER_TX_CLOCK);
- m_midi_counter_timer = timer_alloc(TIMER_MIDI_CLOCK);
+ m_midi_timer = timer_alloc(FUNC(ym3802_device::transmit_clk), this);
+ m_midi_counter_timer = timer_alloc(FUNC(ym3802_device::midi_clk), this);
save_item(NAME(m_reg));
}
@@ -54,20 +50,6 @@ void ym3802_device::device_reset()
set_comms_mode();
}
-void ym3802_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- // TODO: support clock and timers
- switch(id)
- {
- case TIMER_TX_CLOCK:
- transmit_clk();
- break;
- case TIMER_MIDI_CLOCK:
- midi_clk();
- break;
- }
-}
-
void ym3802_device::set_irq(uint8_t irq)
{
uint8_t x;
@@ -90,7 +72,7 @@ void ym3802_device::reset_irq(uint8_t irq)
m_irq_handler(CLEAR_LINE);
}
-void ym3802_device::transmit_clk()
+TIMER_CALLBACK_MEMBER(ym3802_device::transmit_clk)
{
if(m_reg[REG_TCR] & 0x01) // Tx Enable
{
@@ -116,7 +98,7 @@ void ym3802_device::transmit_clk()
}
}
-void ym3802_device::midi_clk()
+TIMER_CALLBACK_MEMBER(ym3802_device::midi_clk)
{
if(m_midi_counter_base > 1) // counter is not guaranteed to work if set to 0 or 1.
{
diff --git a/src/devices/machine/ym3802.h b/src/devices/machine/ym3802.h
index 68cdf4d535d..00e6683ed25 100644
--- a/src/devices/machine/ym3802.h
+++ b/src/devices/machine/ym3802.h
@@ -3,7 +3,10 @@
/*
* ym3802.h - Yamaha YM3802/YM3523 MCS MIDI Communication and Service Controller
*
- * * Registers:
+ * CLK input - anywhere from 1MHz up to 4MHz
+ * CLKM input - usually either 1MHz or 0.5MHz, or CLKF input - usually 614.4kHz
+ *
+ * Registers:
* reg0 : IVR (read-only)
* reg1 : RGR (bit 8 = reset, bits 0-3 = register bank select)
* reg2 : ISR (read-only)
@@ -26,7 +29,7 @@
class ym3802_device : public device_t, public device_serial_interface
{
public:
- // construction/destruction
+ // construction/destruction
ym3802_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// configuration helpers
@@ -41,7 +44,6 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
enum
@@ -118,15 +120,8 @@ private:
IRQ_GENERAL_TIMER = 0x80
};
- enum
- {
- TIMER_SYSTEM_CLOCK = 0x200, // CLK input - anywhere from 1MHz up to 4MHz
- TIMER_TX_CLOCK,
- TIMER_MIDI_CLOCK // CLKM input - usually either 1MHz or 0.5MHz, or CLKF input - usually 614.4kHz
- };
-
- void transmit_clk();
- void midi_clk();
+ TIMER_CALLBACK_MEMBER(transmit_clk);
+ TIMER_CALLBACK_MEMBER(midi_clk);
void reset_midi_timer();
void set_comms_mode();
void set_irq(uint8_t irq);
@@ -135,7 +130,6 @@ private:
devcb_write_line m_irq_handler;
devcb_write_line m_txd_handler;
devcb_read_line m_rxd_handler;
- emu_timer* m_clock_timer;
emu_timer* m_midi_timer;
emu_timer* m_midi_counter_timer;
diff --git a/src/devices/machine/z8038.cpp b/src/devices/machine/z8038.cpp
index b5c375b408e..05e3997187f 100644
--- a/src/devices/machine/z8038.cpp
+++ b/src/devices/machine/z8038.cpp
@@ -21,7 +21,6 @@
#include "emu.h"
#include "z8038.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_REG (1U << 1)
#define LOG_FIFO (1U << 2)
#define LOG_INT (1U << 3)
@@ -60,13 +59,6 @@ template void z8038_device::zbus_map<2>(address_map &map);
void z8038_device::device_start()
{
- m_out_int_cb.resolve_all_safe();
-
- m_out_E_cb.resolve_safe();
- m_out_F_cb.resolve_safe();
- m_out_H_cb.resolve_safe();
- m_out_J_cb.resolve_safe();
-
save_item(NAME(m_control_2));
save_item(NAME(m_control_3));
@@ -91,7 +83,7 @@ void z8038_device::device_start()
//save_item(NAME(m_fifo));
- m_int_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8038_device::int_check), this));
+ m_int_check = timer_alloc(FUNC(z8038_device::int_check), this);
// suppress startup interrupt line changes
m_port[0].int_asserted = false;
@@ -305,7 +297,7 @@ u8 z8038_device::byte_count_r(u8 const port)
{
/*
* Bit 6 is reset upon completion of the CPU read of the Byte Count
- * register. The ongoing count appears in t he Byte Count register after
+ * register. The ongoing count appears in the Byte Count register after
* the read.
*/
if (m_port[port].control_1 & CR1_FBCR)
@@ -483,7 +475,7 @@ void z8038_device::message_out_w(u8 const port, u8 data)
m_port[!port].interrupt_status[0] |= ISR0_MIP;
}
-WRITE_LINE_MEMBER(z8038_device::in_E)
+void z8038_device::in_E(int state)
{
// check port 2 in i/o mode and pin 35 configured as input
if ((m_port[0].control_0 & CR0_P2M_IO) && (m_control_3 & CR3_P2CLR))
@@ -499,7 +491,7 @@ WRITE_LINE_MEMBER(z8038_device::in_E)
}
}
-WRITE_LINE_MEMBER(z8038_device::in_F)
+void z8038_device::in_F(int state)
{
// check port 2 in i/o mode and pin 34 configured as input
if ((m_port[0].control_0 & CR0_P2M_IO) && (m_control_3 & CR3_P2DIR))
@@ -521,7 +513,7 @@ WRITE_LINE_MEMBER(z8038_device::in_F)
}
}
-WRITE_LINE_MEMBER(z8038_device::in_G)
+void z8038_device::in_G(int state)
{
// check port 2 in i/o mode
if (m_port[0].control_0 & CR0_P2M_IO)
diff --git a/src/devices/machine/z8038.h b/src/devices/machine/z8038.h
index 2e2201f10d6..d21408150e2 100644
--- a/src/devices/machine/z8038.h
+++ b/src/devices/machine/z8038.h
@@ -21,9 +21,9 @@ public:
auto out_J() { return m_out_J_cb.bind(); }
// port 2 input lines
- DECLARE_WRITE_LINE_MEMBER(in_E); // C̅L̅E̅A̅R̅
- DECLARE_WRITE_LINE_MEMBER(in_F); // Data Direction
- DECLARE_WRITE_LINE_MEMBER(in_G); // IN0
+ void in_E(int state); // C̅L̅E̅A̅R̅
+ void in_F(int state); // Data Direction
+ void in_G(int state); // IN0
// indirect register access
template <u8 Port> u8 reg_r() { return reg_r(Port - 1); }
diff --git a/src/devices/machine/z80ctc.cpp b/src/devices/machine/z80ctc.cpp
index c3004b1fade..7f0049b28e8 100644
--- a/src/devices/machine/z80ctc.cpp
+++ b/src/devices/machine/z80ctc.cpp
@@ -77,12 +77,17 @@ DEFINE_DEVICE_TYPE(Z80CTC_CHANNEL, z80ctc_channel_device, "z80ctc_channel", "Z80
//-------------------------------------------------
z80ctc_device::z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, Z80CTC, tag, owner, clock)
+ : z80ctc_device(mconfig, Z80CTC, tag, owner, clock)
+{
+}
+
+z80ctc_device::z80ctc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
, device_z80daisy_interface(mconfig, *this)
+ , m_channel(*this, "ch%u", 0U)
, m_intr_cb(*this)
, m_zc_cb(*this)
, m_vector(0)
- , m_channel(*this, "ch%u", 0U)
{
}
@@ -112,10 +117,10 @@ void z80ctc_device::write(offs_t offset, uint8_t data)
// trigger
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80ctc_device::trg0 ) { m_channel[0]->trigger(state != 0); }
-WRITE_LINE_MEMBER( z80ctc_device::trg1 ) { m_channel[1]->trigger(state != 0); }
-WRITE_LINE_MEMBER( z80ctc_device::trg2 ) { m_channel[2]->trigger(state != 0); }
-WRITE_LINE_MEMBER( z80ctc_device::trg3 ) { m_channel[3]->trigger(state != 0); }
+void z80ctc_device::trg0(int state) { m_channel[0]->trigger(state != 0); }
+void z80ctc_device::trg1(int state) { m_channel[1]->trigger(state != 0); }
+void z80ctc_device::trg2(int state) { m_channel[2]->trigger(state != 0); }
+void z80ctc_device::trg3(int state) { m_channel[3]->trigger(state != 0); }
//-------------------------------------------------
@@ -136,20 +141,6 @@ void z80ctc_device::device_add_mconfig(machine_config &config)
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void z80ctc_device::device_resolve_objects()
-{
- // resolve callbacks
- m_intr_cb.resolve_safe();
- m_zc_cb.resolve_all_safe();
-}
-
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -295,7 +286,8 @@ z80ctc_channel_device::z80ctc_channel_device(const machine_config &mconfig, cons
m_down(0),
m_extclk(0),
m_timer(nullptr),
- m_int_state(0)
+ m_int_state(0),
+ m_zc_to_timer(nullptr)
{
}
@@ -307,7 +299,8 @@ z80ctc_channel_device::z80ctc_channel_device(const machine_config &mconfig, cons
void z80ctc_channel_device::device_start()
{
// initialize state
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z80ctc_channel_device::timer_callback), this));
+ m_timer = timer_alloc(FUNC(z80ctc_channel_device::timer_callback), this);
+ m_zc_to_timer = timer_alloc(FUNC(z80ctc_channel_device::zc_to_callback), this);
// register for save states
save_item(NAME(m_mode));
@@ -495,7 +488,7 @@ void z80ctc_channel_device::trigger(bool state)
{
// if we hit zero, do the same thing as for a timer interrupt
if (--m_down == 0)
- timer_callback(nullptr,0);
+ timer_callback(0);
}
}
}
@@ -529,10 +522,15 @@ TIMER_CALLBACK_MEMBER(z80ctc_channel_device::timer_callback)
m_device->interrupt_check();
}
- // generate the clock pulse (FIXME: pulse width is based on bus clock)
+ // generate the clock pulse
m_device->m_zc_cb[m_index](1);
- m_device->m_zc_cb[m_index](0);
+ m_zc_to_timer->adjust(m_device->clocks_to_attotime(1));
// reset the down counter
m_down = m_tconst;
}
+
+TIMER_CALLBACK_MEMBER(z80ctc_channel_device::zc_to_callback)
+{
+ m_device->m_zc_cb[m_index](0);
+}
diff --git a/src/devices/machine/z80ctc.h b/src/devices/machine/z80ctc.h
index c70f1394acb..098915aceab 100644
--- a/src/devices/machine/z80ctc.h
+++ b/src/devices/machine/z80ctc.h
@@ -50,7 +50,7 @@ public:
z80ctc_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
protected:
- // device-level overrides
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
@@ -60,6 +60,7 @@ protected:
attotime period() const;
void trigger(bool state);
TIMER_CALLBACK_MEMBER(timer_callback);
+ TIMER_CALLBACK_MEMBER(zc_to_callback);
required_device<z80ctc_device> m_device; // pointer back to our device
int m_index; // our channel index
@@ -69,6 +70,7 @@ protected:
bool m_extclk; // current signal from the external clock
emu_timer * m_timer; // array of active timers
u8 m_int_state; // interrupt status (for daisy chain)
+ emu_timer * m_zc_to_timer; // zc to pulse timer
};
// ======================> z80ctc_device
@@ -90,39 +92,38 @@ public:
// read/write handlers
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( trg0 );
- DECLARE_WRITE_LINE_MEMBER( trg1 );
- DECLARE_WRITE_LINE_MEMBER( trg2 );
- DECLARE_WRITE_LINE_MEMBER( trg3 );
+ void trg0(int state);
+ void trg1(int state);
+ void trg2(int state);
+ void trg3(int state);
u16 get_channel_constant(int ch) const { return m_channel[ch]->m_tconst; }
protected:
- // device-level overrides
+ z80ctc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
+ // device_t implementation
virtual void device_add_mconfig(machine_config &config) override;
- virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset_after_children() override;
- // z80daisy_interface overrides
+ // z80daisy_interface implementation
virtual int z80daisy_irq_state() override;
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
-private:
// internal helpers
+ u8 channel_int_state(int ch) const noexcept { return m_channel[ch]->m_int_state; }
void interrupt_check();
- z80ctc_channel_device &channel_config(int ch) { return *subdevice<z80ctc_channel_device>(m_channel[ch].finder_tag()); }
+ z80ctc_channel_device &channel_config(int ch) { return *m_channel[ch].lookup(); }
// internal state
- devcb_write_line m_intr_cb; // interrupt callback
- devcb_write_line::array<4> m_zc_cb; // zero crossing/timer output callbacks
-
- u8 m_vector; // interrupt vector
+ required_device_array<z80ctc_channel_device, 4> m_channel; // subdevice for each channel
+ devcb_write_line m_intr_cb; // interrupt callback
+ devcb_write_line::array<4> m_zc_cb; // zero crossing/timer output callbacks
- // subdevice for each channel
- required_device_array<z80ctc_channel_device, 4> m_channel;
+ u8 m_vector; // interrupt vector
};
diff --git a/src/devices/machine/z80daisy_generic.cpp b/src/devices/machine/z80daisy_generic.cpp
index 3a5b6562f30..a7c74364426 100644
--- a/src/devices/machine/z80daisy_generic.cpp
+++ b/src/devices/machine/z80daisy_generic.cpp
@@ -39,9 +39,6 @@ z80daisy_generic_device::z80daisy_generic_device(const machine_config &mconfig,
void z80daisy_generic_device::device_start()
{
- // resolve callbacks
- m_int_handler.resolve_safe();
-
// register for save states
save_item(NAME(m_int));
save_item(NAME(m_mask));
@@ -94,13 +91,13 @@ void z80daisy_generic_device::update_interrupt()
// INTERFACE
//**************************************************************************
-WRITE_LINE_MEMBER( z80daisy_generic_device::int_w )
+void z80daisy_generic_device::int_w(int state)
{
m_int = state;
update_interrupt();
}
-WRITE_LINE_MEMBER( z80daisy_generic_device::mask_w )
+void z80daisy_generic_device::mask_w(int state)
{
m_mask = state;
update_interrupt();
diff --git a/src/devices/machine/z80daisy_generic.h b/src/devices/machine/z80daisy_generic.h
index d26b50e6ee7..c8bfa92fce4 100644
--- a/src/devices/machine/z80daisy_generic.h
+++ b/src/devices/machine/z80daisy_generic.h
@@ -30,8 +30,8 @@ public:
// configuration
void set_vector(uint8_t vector) { m_vector = vector; }
- DECLARE_WRITE_LINE_MEMBER(int_w);
- DECLARE_WRITE_LINE_MEMBER(mask_w);
+ void int_w(int state);
+ void mask_w(int state);
protected:
// device-level overrides
diff --git a/src/devices/machine/z80dma.cpp b/src/devices/machine/z80dma.cpp
index 1a347cc2f24..2e0240af8a3 100644
--- a/src/devices/machine/z80dma.cpp
+++ b/src/devices/machine/z80dma.cpp
@@ -26,7 +26,6 @@
#include "emu.h"
#include "z80dma.h"
-#define LOG_GENERAL (1U << 0)
#define LOG_DMA (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_DMA)
@@ -46,36 +45,13 @@ enum
INT_MATCH_END_OF_BLOCK
};
-constexpr int COMMAND_RESET = 0xc3;
-constexpr int COMMAND_RESET_PORT_A_TIMING = 0xc7;
-constexpr int COMMAND_RESET_PORT_B_TIMING = 0xcb;
-constexpr int COMMAND_LOAD = 0xcf;
-constexpr int COMMAND_CONTINUE = 0xd3;
-constexpr int COMMAND_DISABLE_INTERRUPTS = 0xaf;
-constexpr int COMMAND_ENABLE_INTERRUPTS = 0xab;
-constexpr int COMMAND_RESET_AND_DISABLE_INTERRUPTS = 0xa3;
-constexpr int COMMAND_ENABLE_AFTER_RETI = 0xb7;
-constexpr int COMMAND_READ_STATUS_BYTE = 0xbf;
-constexpr int COMMAND_REINITIALIZE_STATUS_BYTE = 0x8b;
-constexpr int COMMAND_INITIATE_READ_SEQUENCE = 0xa7;
-constexpr int COMMAND_FORCE_READY = 0xb3;
-constexpr int COMMAND_ENABLE_DMA = 0x87;
-constexpr int COMMAND_DISABLE_DMA = 0x83;
-constexpr int COMMAND_READ_MASK_FOLLOWS = 0xbb;
-
-constexpr int TM_TRANSFER = 0x01;
-constexpr int TM_SEARCH = 0x02;
-constexpr int TM_SEARCH_TRANSFER = 0x03;
-
//**************************************************************************
// MACROS
//**************************************************************************
-#define REGNUM(_m, _s) (((_m)<<3) + (_s))
#define GET_REGNUM(_r) (&(_r) - &(WR0))
-#define REG(_m, _s) m_regs[REGNUM(_m,_s)]
#define WR0 REG(0, 0)
#define WR1 REG(1, 0)
#define WR2 REG(2, 0)
@@ -135,7 +111,7 @@ constexpr int TM_SEARCH_TRANSFER = 0x03;
#define INT_ON_END_OF_BLOCK (INTERRUPT_CTRL & 0x02)
#define INT_ON_READY (INTERRUPT_CTRL & 0x40)
#define STATUS_AFFECTS_VECTOR (INTERRUPT_CTRL & 0x20)
-
+#define PULSE_GENERATED (INTERRUPT_CTRL & 0x04)
//**************************************************************************
@@ -150,15 +126,20 @@ DEFINE_DEVICE_TYPE(Z80DMA, z80dma_device, "z80dma", "Z80 DMA Controller")
//-------------------------------------------------
z80dma_device::z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, Z80DMA, tag, owner, clock)
+ : z80dma_device(mconfig, Z80DMA, tag, owner, clock)
+{
+}
+
+z80dma_device::z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
, device_z80daisy_interface(mconfig, *this)
, m_out_busreq_cb(*this)
, m_out_int_cb(*this)
, m_out_ieo_cb(*this)
, m_out_bao_cb(*this)
- , m_in_mreq_cb(*this)
+ , m_in_mreq_cb(*this, 0)
, m_out_mreq_cb(*this)
- , m_in_iorq_cb(*this)
+ , m_in_iorq_cb(*this, 0)
, m_out_iorq_cb(*this)
{
}
@@ -170,18 +151,8 @@ z80dma_device::z80dma_device(const machine_config &mconfig, const char *tag, dev
void z80dma_device::device_start()
{
- // resolve callbacks
- m_out_busreq_cb.resolve_safe();
- m_out_int_cb.resolve_safe();
- m_out_ieo_cb.resolve_safe();
- m_out_bao_cb.resolve_safe();
- m_in_mreq_cb.resolve_safe(0);
- m_out_mreq_cb.resolve_safe();
- m_in_iorq_cb.resolve_safe(0);
- m_out_iorq_cb.resolve_safe();
-
// allocate timer
- m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z80dma_device::timerproc), this));
+ m_timer = timer_alloc(FUNC(z80dma_device::timerproc), this);
// register for state saving
save_item(NAME(m_regs));
@@ -197,9 +168,11 @@ void z80dma_device::device_start()
save_item(NAME(m_addressA));
save_item(NAME(m_addressB));
save_item(NAME(m_count));
+ save_item(NAME(m_byte_counter));
save_item(NAME(m_rdy));
save_item(NAME(m_force_ready));
save_item(NAME(m_is_read));
+ save_item(NAME(m_is_pulse));
save_item(NAME(m_cur_cycle));
save_item(NAME(m_latch));
}
@@ -219,6 +192,7 @@ void z80dma_device::device_reset()
m_read_num_follow = m_read_cur_follow = 0;
m_reset_pointer = 0;
m_is_read = false;
+ m_is_pulse = false;
memset(m_regs, 0, sizeof(m_regs));
memset(m_regs_follow, 0, sizeof(m_regs_follow));
@@ -334,7 +308,12 @@ int z80dma_device::is_ready()
void z80dma_device::interrupt_check()
{
m_out_int_cb(m_ip ? ASSERT_LINE : CLEAR_LINE);
- m_out_ieo_cb(m_iei && !m_ip);
+
+ int ieo = m_iei;
+ if (m_ip) {
+ ieo = 0;
+ }
+ m_out_ieo_cb(ieo);
}
@@ -448,16 +427,11 @@ void z80dma_device::do_search()
}
}
-int z80dma_device::do_write()
+void z80dma_device::do_write()
{
- int done;
uint8_t mode;
mode = TRANSFER_MODE;
- if (m_count == 0x0000)
- {
- //FIXME: Any signal here
- }
switch(mode) {
case TM_TRANSFER:
do_transfer_write();
@@ -480,14 +454,7 @@ int z80dma_device::do_write()
m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
- m_count--;
- done = (m_count == 0xFFFF); //correct?
-
- if (done)
- {
- //FIXME: interrupt ?
- }
- return done;
+ m_byte_counter++;
}
@@ -497,31 +464,48 @@ int z80dma_device::do_write()
TIMER_CALLBACK_MEMBER(z80dma_device::timerproc)
{
- int done;
-
if (--m_cur_cycle)
{
return;
}
+ if (PULSE_GENERATED)
+ {
+ if (m_is_pulse)
+ {
+ m_out_int_cb(CLEAR_LINE);
+ m_is_pulse = false;
+ }
+ else
+ {
+ if ((m_byte_counter & 0xff)==PULSE_CTRL && is_ready())
+ {
+ m_is_pulse = true;
+ m_out_int_cb(ASSERT_LINE);
+ }
+ }
+ }
+
if (m_is_read && !is_ready()) return;
if (m_is_read)
{
/* TODO: there's a nasty recursion bug with Alpha for Sharp X1 Turbo on the transfers with this function! */
do_read();
- done = 0;
m_is_read = false;
m_cur_cycle = (PORTA_IS_SOURCE ? PORTA_CYCLE_LEN : PORTB_CYCLE_LEN);
}
else
{
- done = do_write();
+ do_write();
m_is_read = true;
m_cur_cycle = (PORTB_IS_SOURCE ? PORTA_CYCLE_LEN : PORTB_CYCLE_LEN);
+
+ // param==1 indicates final transfer
+ m_timer->set_param(m_byte_counter == m_count);
}
- if (done)
+ if (m_is_read && param)
{
m_dma_enabled = 0; //FIXME: Correct?
m_status = 0x09;
@@ -546,7 +530,9 @@ TIMER_CALLBACK_MEMBER(z80dma_device::timerproc)
m_addressA = PORTA_ADDRESS;
m_addressB = PORTB_ADDRESS;
m_count = BLOCKLEN;
+ m_byte_counter = 0;
m_status |= 0x30;
+ m_timer->set_param(0);
}
}
}
@@ -558,20 +544,17 @@ TIMER_CALLBACK_MEMBER(z80dma_device::timerproc)
void z80dma_device::update_status()
{
- uint16_t pending_transfer;
- attotime next;
-
// no transfer is active right now; is there a transfer pending right now?
- pending_transfer = is_ready() & m_dma_enabled;
+ bool const pending_transfer = is_ready() && m_dma_enabled;
if (pending_transfer)
{
m_is_read = true;
m_cur_cycle = (PORTA_IS_SOURCE ? PORTA_CYCLE_LEN : PORTB_CYCLE_LEN);
- next = attotime::from_hz(clock());
+ attotime const next = attotime::from_hz(clock());
m_timer->adjust(
attotime::zero,
- 0,
+ m_timer->param(),
// 1 byte transferred in 4 clock cycles
next);
}
@@ -698,6 +681,7 @@ void z80dma_device::write(uint8_t data)
m_read_regs_follow[0] = m_status;
break;
case COMMAND_RESET_AND_DISABLE_INTERRUPTS:
+ LOG("Z80DMA Reset and Disable Interrupts\n");
WR3 &= ~0x20;
m_ip = 0;
m_ius = 0;
@@ -708,8 +692,8 @@ void z80dma_device::write(uint8_t data)
LOG("Z80DMA Initiate Read Sequence\n");
m_read_cur_follow = m_read_num_follow = 0;
if(READ_MASK & 0x01) { m_read_regs_follow[m_read_num_follow++] = m_status; }
- if(READ_MASK & 0x02) { m_read_regs_follow[m_read_num_follow++] = m_count & 0xff; } //byte counter (low)
- if(READ_MASK & 0x04) { m_read_regs_follow[m_read_num_follow++] = m_count >> 8; } //byte counter (high)
+ if(READ_MASK & 0x02) { m_read_regs_follow[m_read_num_follow++] = m_byte_counter & 0xff; } //byte counter (low)
+ if(READ_MASK & 0x04) { m_read_regs_follow[m_read_num_follow++] = m_byte_counter >> 8; } //byte counter (high)
if(READ_MASK & 0x08) { m_read_regs_follow[m_read_num_follow++] = m_addressA & 0xff; } //port A address (low)
if(READ_MASK & 0x10) { m_read_regs_follow[m_read_num_follow++] = m_addressA >> 8; } //port A address (high)
if(READ_MASK & 0x20) { m_read_regs_follow[m_read_num_follow++] = m_addressB & 0xff; } //port B address (low)
@@ -739,7 +723,9 @@ void z80dma_device::write(uint8_t data)
m_addressA = PORTA_ADDRESS;
m_addressB = PORTB_ADDRESS;
m_count = BLOCKLEN;
+ m_byte_counter = 0;
m_status |= 0x30;
+ m_timer->set_param(0);
LOG("Z80DMA Load A: %x B: %x N: %x\n", m_addressA, m_addressB, m_count);
break;
@@ -750,7 +736,6 @@ void z80dma_device::write(uint8_t data)
case COMMAND_ENABLE_DMA:
LOG("Z80DMA Enable DMA\n");
m_dma_enabled = 1;
- update_status();
break;
case COMMAND_READ_MASK_FOLLOWS:
LOG("Z80DMA Set Read Mask\n");
@@ -759,9 +744,11 @@ void z80dma_device::write(uint8_t data)
case COMMAND_CONTINUE:
LOG("Z80DMA Continue\n");
m_count = BLOCKLEN;
+ m_byte_counter = 0;
m_dma_enabled = 1;
//"match not found" & "end of block" status flags zeroed here
m_status |= 0x30;
+ m_timer->set_param(0);
break;
case COMMAND_RESET_PORT_A_TIMING:
LOG("Z80DMA Reset Port A Timing\n");
@@ -774,7 +761,6 @@ void z80dma_device::write(uint8_t data)
case COMMAND_FORCE_READY:
LOG("Z80DMA Force Ready\n");
m_force_ready = 1;
- update_status();
break;
case COMMAND_ENABLE_INTERRUPTS:
LOG("Z80DMA Enable IRQ\n");
@@ -796,6 +782,7 @@ void z80dma_device::write(uint8_t data)
default:
logerror("Z80DMA Unknown WR6 command %02x\n", data);
}
+ update_status();
}
else if(data == 0x8e) //newtype on Sharp X1, unknown purpose
logerror("Z80DMA Unknown base register %02x\n", data);
@@ -826,8 +813,8 @@ void z80dma_device::write(uint8_t data)
m_read_cur_follow = m_read_num_follow = 0;
if(READ_MASK & 0x01) { m_read_regs_follow[m_read_num_follow++] = m_status; }
- if(READ_MASK & 0x02) { m_read_regs_follow[m_read_num_follow++] = m_count & 0xff; } //byte counter (low)
- if(READ_MASK & 0x04) { m_read_regs_follow[m_read_num_follow++] = m_count >> 8; } //byte counter (high)
+ if(READ_MASK & 0x02) { m_read_regs_follow[m_read_num_follow++] = m_byte_counter & 0xff; } //byte counter (low)
+ if(READ_MASK & 0x04) { m_read_regs_follow[m_read_num_follow++] = m_byte_counter >> 8; } //byte counter (high)
if(READ_MASK & 0x08) { m_read_regs_follow[m_read_num_follow++] = m_addressA & 0xff; } //port A address (low)
if(READ_MASK & 0x10) { m_read_regs_follow[m_read_num_follow++] = m_addressA >> 8; } //port A address (high)
if(READ_MASK & 0x20) { m_read_regs_follow[m_read_num_follow++] = m_addressB & 0xff; } //port B address (low)
@@ -863,7 +850,7 @@ TIMER_CALLBACK_MEMBER(z80dma_device::rdy_write_callback)
// rdy_w - ready input
//-------------------------------------------------
-WRITE_LINE_MEMBER(z80dma_device::rdy_w)
+void z80dma_device::rdy_w(int state)
{
LOG("Z80DMA RDY: %d Active High: %d\n", state, READY_ACTIVE_HIGH);
machine().scheduler().synchronize(timer_expired_delegate(FUNC(z80dma_device::rdy_write_callback),this), state);
@@ -874,7 +861,7 @@ WRITE_LINE_MEMBER(z80dma_device::rdy_w)
// wait_w - wait input
//-------------------------------------------------
-WRITE_LINE_MEMBER(z80dma_device::wait_w)
+void z80dma_device::wait_w(int state)
{
}
@@ -883,6 +870,6 @@ WRITE_LINE_MEMBER(z80dma_device::wait_w)
// bai_w - bus acknowledge input
//-------------------------------------------------
-WRITE_LINE_MEMBER(z80dma_device::bai_w)
+void z80dma_device::bai_w(int state)
{
}
diff --git a/src/devices/machine/z80dma.h b/src/devices/machine/z80dma.h
index 14725329bd0..7bbb91760ac 100644
--- a/src/devices/machine/z80dma.h
+++ b/src/devices/machine/z80dma.h
@@ -61,32 +61,67 @@ public:
auto out_iorq_callback() { return m_out_iorq_cb.bind(); }
uint8_t read();
- void write(uint8_t data);
-
- DECLARE_WRITE_LINE_MEMBER(iei_w) { m_iei = state; interrupt_check(); }
- DECLARE_WRITE_LINE_MEMBER(rdy_w);
- DECLARE_WRITE_LINE_MEMBER(wait_w);
- DECLARE_WRITE_LINE_MEMBER(bai_w);
-
-private:
- // device-level overrides
+ virtual void write(uint8_t data);
+
+ void iei_w(int state) { m_iei = state; interrupt_check(); }
+ void rdy_w(int state);
+ void wait_w(int state);
+ void bai_w(int state);
+
+protected:
+ static inline constexpr int COMMAND_RESET = 0xc3;
+ static inline constexpr int COMMAND_RESET_PORT_A_TIMING = 0xc7;
+ static inline constexpr int COMMAND_RESET_PORT_B_TIMING = 0xcb;
+ static inline constexpr int COMMAND_LOAD = 0xcf;
+ static inline constexpr int COMMAND_CONTINUE = 0xd3;
+ static inline constexpr int COMMAND_DISABLE_INTERRUPTS = 0xaf;
+ static inline constexpr int COMMAND_ENABLE_INTERRUPTS = 0xab;
+ static inline constexpr int COMMAND_RESET_AND_DISABLE_INTERRUPTS = 0xa3;
+ static inline constexpr int COMMAND_ENABLE_AFTER_RETI = 0xb7;
+ static inline constexpr int COMMAND_READ_STATUS_BYTE = 0xbf;
+ static inline constexpr int COMMAND_REINITIALIZE_STATUS_BYTE = 0x8b;
+ static inline constexpr int COMMAND_INITIATE_READ_SEQUENCE = 0xa7;
+ static inline constexpr int COMMAND_FORCE_READY = 0xb3;
+ static inline constexpr int COMMAND_ENABLE_DMA = 0x87;
+ static inline constexpr int COMMAND_DISABLE_DMA = 0x83;
+ static inline constexpr int COMMAND_READ_MASK_FOLLOWS = 0xbb;
+
+ static inline constexpr int TM_TRANSFER = 0x01;
+ static inline constexpr int TM_SEARCH = 0x02;
+ static inline constexpr int TM_SEARCH_TRANSFER = 0x03;
+
+ z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- // device_z80daisy_interface overrides
- virtual int z80daisy_irq_state() override;
- virtual int z80daisy_irq_ack() override;
- virtual void z80daisy_irq_reti() override;
-
// internal helpers
- int is_ready();
+ bool is_dma_enabled() const noexcept { return m_dma_enabled; }
+ u8 num_follow() const noexcept { return m_num_follow; }
+ virtual int is_ready();
void interrupt_check();
void trigger_interrupt(int level);
void do_read();
- int do_write();
+ virtual void do_write();
void do_transfer_write();
void do_search();
+ uint16_t &REG(unsigned m, unsigned s) noexcept { return m_regs[REGNUM(m, s)]; }
+
+ static constexpr unsigned REGNUM(unsigned m, unsigned s) { return (m << 3) + s; }
+
+ uint16_t m_addressA;
+ uint16_t m_addressB;
+ uint16_t m_count;
+ uint16_t m_byte_counter;
+
+private:
+ // device_z80daisy_interface implementation
+ virtual int z80daisy_irq_state() override;
+ virtual int z80daisy_irq_ack() override;
+ virtual void z80daisy_irq_reti() override;
+
TIMER_CALLBACK_MEMBER(timerproc);
void update_status();
@@ -105,7 +140,7 @@ private:
emu_timer *m_timer;
- uint16_t m_regs[(6<<3)+1+1];
+ uint16_t m_regs[(6 << 3) + 1 + 1];
uint8_t m_num_follow;
uint8_t m_cur_follow;
uint8_t m_regs_follow[5];
@@ -115,23 +150,20 @@ private:
uint8_t m_status;
uint8_t m_dma_enabled;
- uint16_t m_addressA;
- uint16_t m_addressB;
- uint16_t m_count;
-
int m_rdy;
int m_force_ready;
uint8_t m_reset_pointer;
bool m_is_read;
+ bool m_is_pulse;
uint8_t m_cur_cycle;
uint8_t m_latch;
// interrupts
- bool m_iei;
+ int m_iei; // interrupt enable input
int m_ip; // interrupt pending
int m_ius; // interrupt under service
- uint8_t m_vector; // interrupt vector
+ uint8_t m_vector; // interrupt vector
};
diff --git a/src/devices/machine/z80pio.cpp b/src/devices/machine/z80pio.cpp
index d269891e333..407c814f327 100644
--- a/src/devices/machine/z80pio.cpp
+++ b/src/devices/machine/z80pio.cpp
@@ -41,10 +41,10 @@ z80pio_device::z80pio_device(const machine_config &mconfig, const char *tag, dev
device_t(mconfig, Z80PIO, tag, owner, clock),
device_z80daisy_interface(mconfig, *this),
m_out_int_cb(*this),
- m_in_pa_cb(*this),
+ m_in_pa_cb(*this, 0),
m_out_pa_cb(*this),
m_out_ardy_cb(*this),
- m_in_pb_cb(*this),
+ m_in_pb_cb(*this, 0),
m_out_pb_cb(*this),
m_out_brdy_cb(*this)
{
@@ -59,15 +59,6 @@ void z80pio_device::device_start()
{
m_port[PORT_A].start(this, PORT_A);
m_port[PORT_B].start(this, PORT_B);
-
- // resolve callbacks
- m_out_int_cb.resolve_safe();
- m_in_pa_cb.resolve_safe(0);
- m_out_pa_cb.resolve_safe();
- m_out_ardy_cb.resolve_safe();
- m_in_pb_cb.resolve_safe(0);
- m_out_pb_cb.resolve_safe();
- m_out_brdy_cb.resolve_safe();
}
@@ -568,10 +559,24 @@ void z80pio_device::pio_port::write(uint8_t data)
data &= mask;
- if ((m_icw & 0x60) == 0 && data != mask) match = true;
- else if ((m_icw & 0x60) == 0x20 && data != 0) match = true;
- else if ((m_icw & 0x60) == 0x40 && data == 0) match = true;
- else if ((m_icw & 0x60) == 0x60 && data == mask) match = true;
+ switch (m_icw & 0x60)
+ {
+ case 0x00:
+ match = data != mask;
+ break;
+
+ case 0x20:
+ match = data != 0;
+ break;
+
+ case 0x40:
+ match = data == 0;
+ break;
+
+ case 0x60:
+ match = data == mask;
+ break;
+ }
if (!m_match && match && !m_ius)
{
@@ -601,11 +606,6 @@ void z80pio_device::pio_port::control_write(uint8_t data)
// load interrupt vector
m_vector = data;
if (LOG) m_device->logerror("Z80PIO Port %c Interrupt Vector: %02x\n", 'A' + m_index, data);
-
- // set interrupt enable
- m_icw |= ICW_ENABLE_INT;
- m_ie = true;
- check_interrupts();
}
else
{
diff --git a/src/devices/machine/z80pio.h b/src/devices/machine/z80pio.h
index a448fd9d502..5e9c562187e 100644
--- a/src/devices/machine/z80pio.h
+++ b/src/devices/machine/z80pio.h
@@ -58,6 +58,7 @@ public:
// construction/destruction
z80pio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ // configuration helpers
auto out_int_callback() { return m_out_int_cb.bind(); }
auto in_pa_callback() { return m_in_pa_cb.bind(); }
auto out_pa_callback() { return m_out_pa_cb.bind(); }
@@ -66,14 +67,13 @@ public:
auto out_pb_callback() { return m_out_pb_cb.bind(); }
auto out_brdy_callback() { return m_out_brdy_cb.bind(); }
-
// I/O line access
int rdy(int which) { return m_port[which].rdy(); }
void strobe(int which, bool state) { m_port[which].strobe(state); }
- DECLARE_READ_LINE_MEMBER( rdy_a ) { return rdy(PORT_A); }
- DECLARE_READ_LINE_MEMBER( rdy_b ) { return rdy(PORT_B); }
- DECLARE_WRITE_LINE_MEMBER( strobe_a ) { strobe(PORT_A, state); }
- DECLARE_WRITE_LINE_MEMBER( strobe_b ) { strobe(PORT_B, state); }
+ int rdy_a() { return rdy(PORT_A); }
+ int rdy_b() { return rdy(PORT_B); }
+ void strobe_a(int state) { strobe(PORT_A, state); }
+ void strobe_b(int state) { strobe(PORT_B, state); }
// control register I/O
uint8_t control_read();
@@ -97,22 +97,22 @@ public:
uint8_t port_b_read() { return port_read(PORT_B); }
void port_a_write(uint8_t data) { port_write(PORT_A, data); }
void port_b_write(uint8_t data) { port_write(PORT_B, data); }
- DECLARE_WRITE_LINE_MEMBER( pa0_w ) { port_write(PORT_A, 0, state); }
- DECLARE_WRITE_LINE_MEMBER( pa1_w ) { port_write(PORT_A, 1, state); }
- DECLARE_WRITE_LINE_MEMBER( pa2_w ) { port_write(PORT_A, 2, state); }
- DECLARE_WRITE_LINE_MEMBER( pa3_w ) { port_write(PORT_A, 3, state); }
- DECLARE_WRITE_LINE_MEMBER( pa4_w ) { port_write(PORT_A, 4, state); }
- DECLARE_WRITE_LINE_MEMBER( pa5_w ) { port_write(PORT_A, 5, state); }
- DECLARE_WRITE_LINE_MEMBER( pa6_w ) { port_write(PORT_A, 6, state); }
- DECLARE_WRITE_LINE_MEMBER( pa7_w ) { port_write(PORT_A, 7, state); }
- DECLARE_WRITE_LINE_MEMBER( pb0_w ) { port_write(PORT_B, 0, state); }
- DECLARE_WRITE_LINE_MEMBER( pb1_w ) { port_write(PORT_B, 1, state); }
- DECLARE_WRITE_LINE_MEMBER( pb2_w ) { port_write(PORT_B, 2, state); }
- DECLARE_WRITE_LINE_MEMBER( pb3_w ) { port_write(PORT_B, 3, state); }
- DECLARE_WRITE_LINE_MEMBER( pb4_w ) { port_write(PORT_B, 4, state); }
- DECLARE_WRITE_LINE_MEMBER( pb5_w ) { port_write(PORT_B, 5, state); }
- DECLARE_WRITE_LINE_MEMBER( pb6_w ) { port_write(PORT_B, 6, state); }
- DECLARE_WRITE_LINE_MEMBER( pb7_w ) { port_write(PORT_B, 7, state); }
+ void pa0_w(int state) { port_write(PORT_A, 0, state); }
+ void pa1_w(int state) { port_write(PORT_A, 1, state); }
+ void pa2_w(int state) { port_write(PORT_A, 2, state); }
+ void pa3_w(int state) { port_write(PORT_A, 3, state); }
+ void pa4_w(int state) { port_write(PORT_A, 4, state); }
+ void pa5_w(int state) { port_write(PORT_A, 5, state); }
+ void pa6_w(int state) { port_write(PORT_A, 6, state); }
+ void pa7_w(int state) { port_write(PORT_A, 7, state); }
+ void pb0_w(int state) { port_write(PORT_B, 0, state); }
+ void pb1_w(int state) { port_write(PORT_B, 1, state); }
+ void pb2_w(int state) { port_write(PORT_B, 2, state); }
+ void pb3_w(int state) { port_write(PORT_B, 3, state); }
+ void pb4_w(int state) { port_write(PORT_B, 4, state); }
+ void pb5_w(int state) { port_write(PORT_B, 5, state); }
+ void pb6_w(int state) { port_write(PORT_B, 6, state); }
+ void pb7_w(int state) { port_write(PORT_B, 7, state); }
// standard read/write, with C/D in bit 1, B/A in bit 0
u8 read(offs_t offset);
@@ -196,9 +196,9 @@ private:
int m_mode; // mode register
int m_next_control_word; // next control word
- uint8_t m_input; // input latch
- uint8_t m_output; // output latch
- uint8_t m_ior; // input/output register
+ uint8_t m_input; // input latch
+ uint8_t m_output; // output latch
+ uint8_t m_ior; // input/output register
bool m_rdy; // ready
bool m_stb; // strobe
@@ -206,14 +206,14 @@ private:
bool m_ie; // interrupt enabled
bool m_ip; // interrupt pending
bool m_ius; // interrupt under service
- uint8_t m_icw; // interrupt control word
- uint8_t m_vector; // interrupt vector
- uint8_t m_mask; // interrupt mask
+ uint8_t m_icw; // interrupt control word
+ uint8_t m_vector; // interrupt vector
+ uint8_t m_mask; // interrupt mask
bool m_match; // logic equation match
};
// internal state
- pio_port m_port[2];
+ pio_port m_port[2];
devcb_write_line m_out_int_cb;
devcb_read8 m_in_pa_cb;
diff --git a/src/devices/machine/z80scc.cpp b/src/devices/machine/z80scc.cpp
index e3a7c8a1d00..30b658e354b 100644
--- a/src/devices/machine/z80scc.cpp
+++ b/src/devices/machine/z80scc.cpp
@@ -99,16 +99,15 @@ baud rate:
// CONFIGURABLE LOGGING
//**************************************************************************
-#define LOG_GENERAL (1U << 0)
-#define LOG_SETUP (1U << 1)
-#define LOG_READ (1U << 2)
-#define LOG_INT (1U << 3)
-#define LOG_CMD (1U << 4)
-#define LOG_TX (1U << 5)
-#define LOG_RCV (1U << 6)
-#define LOG_CTS (1U << 7)
-#define LOG_DCD (1U << 8)
-#define LOG_SYNC (1U << 9)
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_INT (1U << 3)
+#define LOG_CMD (1U << 4)
+#define LOG_TX (1U << 5)
+#define LOG_RCV (1U << 6)
+#define LOG_CTS (1U << 7)
+#define LOG_DCD (1U << 8)
+#define LOG_SYNC (1U << 9)
//#define VERBOSE (LOG_GENERAL|LOG_SETUP|LOG_READ|LOG_INT|LOG_CMD|LOG_TX|LOG_RCV|LOG_CTS|LOG_DCD|LOG_SYNC)
//#define LOG_OUTPUT_STREAM std::cout
@@ -136,14 +135,8 @@ baud rate:
#define FUNCNAME __PRETTY_FUNCTION__
#endif
-/* LOCAL _BRG is set in z80scc.h, local timer based BRG is not complete and will be removed if not needed for synchrounous mode */
-#if Z80SCC_USE_LOCAL_BRG
-#define START_BIT_HUNT 1
-#define START_BIT_ADJUST 1
-#else
#define START_BIT_HUNT 0
#define START_BIT_ADJUST 0
-#endif
#define CHANA_TAG "cha"
#define CHANB_TAG "chb"
@@ -422,6 +415,7 @@ inline void z80scc_channel::out_dtr_cb(int state)
z80scc_device::z80scc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant)
: device_t(mconfig, type, tag, owner, clock),
device_z80daisy_interface(mconfig, *this),
+ m_wr9(0),
m_chanA(*this, CHANA_TAG),
m_chanB(*this, CHANB_TAG),
m_rxca(0),
@@ -486,29 +480,11 @@ scc8523l_device::scc8523l_device(const machine_config &mconfig, const char *tag,
}
//-------------------------------------------------
-// device_resolve_objects - device-specific setup
-//-------------------------------------------------
-void z80scc_device::device_resolve_objects()
-{
- LOG("%s\n", FUNCNAME);
-
- // resolve callbacks
- m_out_txd_cb.resolve_all_safe();
- m_out_dtr_cb.resolve_all_safe();
- m_out_rts_cb.resolve_all_safe();
- m_out_wreq_cb.resolve_all_safe();
- m_out_sync_cb.resolve_all_safe();
- m_out_rxdrq_cb.resolve_all_safe();
- m_out_txdrq_cb.resolve_all_safe();
- m_out_int_cb.resolve_safe();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void z80scc_device::device_start()
{
- LOG("%s", FUNCNAME);
+ LOG("%s\n", FUNCNAME);
// state saving
save_item(NAME(m_out_int_state));
@@ -525,7 +501,7 @@ void z80scc_device::device_start()
//-------------------------------------------------
void z80scc_device::device_reset_after_children()
{
- LOG("%s %s \n",tag(), FUNCNAME);
+ LOG("%s\n", FUNCNAME);
// Hardware reset values for registers where it differs from channel reset values
m_wr9 &= 0x3c;
@@ -585,7 +561,7 @@ int z80scc_device::z80daisy_irq_state()
{
int state = 0;
- LOGINT("%s %s A:%d%d%d B:%d%d%d ", tag(), FUNCNAME,
+ LOGINT("%s: A:%d%d%d B:%d%d%d\n", FUNCNAME,
m_int_state[0], m_int_state[1], m_int_state[2],
m_int_state[3], m_int_state[4], m_int_state[5]);
@@ -604,7 +580,7 @@ int z80scc_device::z80daisy_irq_state()
// Last chance to keep the control of the interrupt line
state |= (m_wr9 & WR9_BIT_DLC) ? Z80_DAISY_IEO : 0;
- LOGINT("- Interrupt State %u\n", state);
+ LOGINT("- Interrupt State %d\n", state);
return state;
}
@@ -617,7 +593,7 @@ int z80scc_device::z80daisy_irq_ack()
{
int ret = -1; // Indicate default vector
- LOGINT("%s %s \n",tag(), FUNCNAME);
+ LOGINT("%s\n", FUNCNAME);
// loop over all interrupt sources
for (auto & elem : m_int_state)
{
@@ -646,8 +622,7 @@ int z80scc_device::z80daisy_irq_ack()
{
// default irq vector is -1 for 68000 but 0 for z80 for example...
ret = owner()->subdevice<cpu_device>(m_cputag)->default_irq_vector(INPUT_LINE_IRQ0);
- LOGINT(" - failed to find an interrupt to ack, returning default IRQ vector: %02x\n", ret );
- logerror("z80sio_irq_ack: failed to find an interrupt to ack!\n");
+ logerror("%s: failed to find an interrupt to ack, returning default IRQ vector: %02x\n", FUNCNAME, ret);
}
return ret;
@@ -666,7 +641,7 @@ daisy chain, the SCC has a Disable Lower Chain (DLC) software command (WR9 bit 2
*/
void z80scc_device::z80daisy_irq_reti()
{
- LOGINT("%s %s - No RETI detection needed on SCC\n",tag(), FUNCNAME);
+ LOGINT("%s: No RETI detection needed on SCC\n", FUNCNAME);
}
@@ -690,7 +665,7 @@ void z80scc_device::check_interrupts()
//-------------------------------------------------
void z80scc_device::reset_interrupts()
{
- LOGINT("%s %s \n",tag(), FUNCNAME);
+ LOGINT("%s\n", FUNCNAME);
// reset internal interrupt sources
for (auto & elem : m_int_state)
{
@@ -747,6 +722,7 @@ int z80scc_device::get_extint_priority(int type)
case z80scc_channel::INT_TRANSMIT: prio = z80scc_channel::INT_TRANSMIT_PRIO; break;
case z80scc_channel::INT_SPECIAL: prio = z80scc_channel::INT_SPECIAL_PRIO; break;
default: logerror("Bad interrupt source being prioritized!");
+ break;
}
return prio;
}
@@ -762,7 +738,7 @@ void z80scc_device::trigger_interrupt(int index, int type)
int prio_level = 0;
- LOGINT("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, type);
+ LOGINT("%s: %02x\n", FUNCNAME, type);
/* The Master Interrupt Enable (MIE) bit, WR9 D3, must be set to enable the SCC to generate interrupts.*/
if (!(m_wr9 & WR9_BIT_MIE))
@@ -775,7 +751,7 @@ void z80scc_device::trigger_interrupt(int index, int type)
prio_level = get_extint_priority(type);
if (source < z80scc_channel::INT_TRANSMIT || source > z80scc_channel::INT_SPECIAL || prio_level < 0 || prio_level > 2)
{
- logerror("Attempt to trigger interrupt of unknown origin blocked: %02x/%02x on channel %c\n", source, prio_level, 'A' + index);
+ logerror("Attempt to trigger interrupt of unknown origin blocked: %02x/%02x\n", source, prio_level);
return;
}
// Vector modification requested?
@@ -784,7 +760,7 @@ void z80scc_device::trigger_interrupt(int index, int type)
vector = modify_vector(vector, index, source);
}
- LOGINT(" Interrupt Request fired of type %u and vector %02x\n", type, vector);
+ LOGINT(" Interrupt Request fired of type %d and vector %02x\n", type, vector);
// update vector register
m_chanB->m_rr2 = vector;
@@ -915,6 +891,7 @@ void z80scc_device::zbus_w(offs_t offset, uint8_t data)
m_chanA->scc_register_write(reg, data);
else
m_chanB->scc_register_write(reg, data);
+ break;
}
return;
@@ -1018,11 +995,9 @@ void z80scc_device::ab_dc_w(offs_t offset, uint8_t data)
z80scc_channel::z80scc_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, Z80SCC_CHANNEL, tag, owner, clock),
device_serial_interface(mconfig, *this),
-#if Z80SCC_USE_LOCAL_BRG
+ m_baudtimer(0),
m_brg_counter(0),
-#else
m_brg_rate(0),
-#endif
m_delayed_tx_brg_change(0),
m_rx_error(0),
m_rx_clock(0),
@@ -1071,15 +1046,13 @@ void z80scc_channel::device_start()
m_uart->m_wr0_ptrbits = 0;
m_rx_fifo_sz = (m_uart->m_variant & z80scc_device::SET_ESCC) ? 8 : 3;
- m_rx_fifo_wp = m_rx_fifo_rp = 0;
m_tx_fifo_sz = (m_uart->m_variant & z80scc_device::SET_ESCC) ? 4 : 1;
- m_tx_fifo_wp = m_tx_fifo_rp = 0;
-#if Z80SCC_USE_LOCAL_BRG
- // baudrate clocks and timers
- baudtimer = timer_alloc(TIMER_ID_BAUD);
-#endif
+ m_rxc = 0x00;
+ m_txc = 0x00;
+
+ m_baudtimer = timer_alloc(FUNC(z80scc_channel::brg_tick), this);
// state saving
save_item(NAME(m_rr0));
@@ -1136,6 +1109,12 @@ void z80scc_channel::device_start()
save_item(NAME(m_rts));
save_item(NAME(m_tx_int_disarm));
save_item(NAME(m_sync_pattern));
+ save_item(NAME(m_rxd));
+ save_item(NAME(m_rcv_mode));
+ save_item(NAME(m_index));
+ save_item(NAME(m_brg_rate));
+ save_item(NAME(m_delayed_tx_brg_change));
+ save_item(NAME(m_brg_counter));
}
@@ -1150,6 +1129,10 @@ void z80scc_channel::device_reset()
receive_register_reset();
transmit_register_reset();
+ // empty fifos
+ m_rx_fifo_wp = m_rx_fifo_rp = 0;
+ m_tx_fifo_wp = m_tx_fifo_rp = 0;
+
// Soft/Channel Reset values (mostly) according to SCC users manual
m_wr0 = 0x00;
m_wr1 &= 0x24;
@@ -1182,38 +1165,14 @@ void z80scc_channel::device_reset()
m_uart->reset_interrupts();
}
m_extint_states = m_rr0;
+ m_baudtimer->adjust(attotime::never);
+ m_brg_counter = 0;
}
-void z80scc_channel::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(z80scc_channel::brg_tick)
{
-// LOG("%s %d\n", FUNCNAME, id);
-
-#if Z80SCC_USE_LOCAL_BRG
- switch(id)
- {
- case TIMER_ID_BAUD:
- {
- //int brconst = m_wr13 << 8 | m_wr12 | 1; // If the counter is 1 the effect is passthrough ehh?! To avoid div0...
- if (m_wr14 & WR14_BRG_ENABLE)
- {
- // int rate = owner()->clock() / brconst;
- // attotime attorate = attotime::from_hz(rate);
- // timer.adjust(attorate, id, attorate);
- txc_w(m_brg_counter & 1);
- rxc_w(m_brg_counter & 1);
- m_brg_counter++; // Will just keep track of state in timer mode, not hardware counter value.
- }
- else
- {
- LOG(" - turning off Baudrate timer\n");
- timer.adjust(attotime::never, 0, attotime::never);
- }
- }
- break;
- default:
- logerror("Spurious timer %d event\n", id);
- }
-#endif
+ // wr15 & WR15_ZEROCOUNT is implied by this timer being running at all
+ m_uart->trigger_interrupt(m_index, INT_EXTERNAL);
}
@@ -1224,13 +1183,13 @@ void z80scc_channel::tra_callback()
{
if (!(m_wr5 & WR5_TX_ENABLE))
{
- LOGTX("%s \"%s \"Channel %c transmit mark 1 m_wr5:%02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_wr5);
+ LOGTX("%s: transmit mark 1 m_wr5:%02x\n", FUNCNAME, m_wr5);
// transmit mark
out_txd_cb(1);
}
else if (m_wr5 & WR5_SEND_BREAK)
{
- LOGTX("%s \"%s \"Channel %c send break 1 m_wr5:%02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_wr5);
+ LOGTX("%s: send break 1 m_wr5:%02x\n", FUNCNAME, m_wr5);
// transmit break
out_txd_cb(0);
}
@@ -1238,14 +1197,16 @@ void z80scc_channel::tra_callback()
{
int db = transmit_register_get_data_bit();
- LOGTX("%s \"%s \"Channel %c transmit data bit %d m_wr5:%02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, db, m_wr5);
+ LOGTX("%s: transmit data bit %d m_wr5:%02x\n", FUNCNAME, db, m_wr5);
// transmit data
out_txd_cb(db);
+
+ if (m_wr14 & WR14_LOCAL_LOOPBACK)
+ write_rx(db);
}
else
{
- LOGTX("%s \"%s \"Channel %c Failed to transmit m_wr5:%02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_wr5);
- logerror("%s \"%s \"Channel %c Failed to transmit\n", FUNCNAME, owner()->tag(), 'A' + m_index);
+ logerror("%s: Failed to transmit m_wr5:%02x\n", FUNCNAME, m_wr5);
}
}
@@ -1267,7 +1228,7 @@ void z80scc_channel::tra_complete()
if ( (m_rr0 & RR0_TX_BUFFER_EMPTY) == 0 || // Takes care of the NMOS/CMOS 1 slot TX FIFO
m_tx_fifo_rp != m_tx_fifo_wp) // or there are more characters to send in a longer FIFO.
{
- LOGTX("%s %s %c done sending, loading data from fifo:%02x '%c'\n", FUNCNAME, owner()->tag(), 'A' + m_index,
+ LOGTX("%s: done sending, loading data from fifo:%02x '%c'\n", FUNCNAME,
m_tx_data_fifo[m_tx_fifo_rp], isascii(m_tx_data_fifo[m_tx_fifo_rp]) ? m_tx_data_fifo[m_tx_fifo_rp] : ' ');
transmit_register_setup(m_tx_data_fifo[m_tx_fifo_rp]); // Reload the shift register
m_tx_fifo_rp_step();
@@ -1275,7 +1236,7 @@ void z80scc_channel::tra_complete()
}
else
{
- LOGTX("%s %s %c done sending, setting all sent bit\n", FUNCNAME, owner()->tag(), 'A' + m_index);
+ LOGTX("%s: done sending, setting all sent bit\n", FUNCNAME);
m_rr1 |= RR1_ALL_SENT;
// when the RTS bit is reset, the _RTS output goes high after the transmitter empties
@@ -1283,7 +1244,7 @@ void z80scc_channel::tra_complete()
set_rts(1);
}
- check_waitrequest();
+ check_dma_request();
if (m_wr1 & WR1_TX_INT_ENABLE && m_tx_int_disarm == 0)
{
@@ -1304,13 +1265,13 @@ void z80scc_channel::tra_complete()
}
else if (m_wr5 & WR5_SEND_BREAK)
{
- LOG("%s \"%s \"Channel %c Transmit Break 0 m_wr5:%02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_wr5);
+ LOG("%s: Transmit Break 0 m_wr5:%02x\n", FUNCNAME, m_wr5);
// transmit break
out_txd_cb(0);
}
else
{
- LOG("%s \"%s \"Channel %c Transmit Mark 1 m_wr5:%02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_wr5);
+ LOG("%s: Transmit Mark 1 m_wr5:%02x\n", FUNCNAME, m_wr5);
// transmit mark
out_txd_cb(1);
}
@@ -1324,16 +1285,13 @@ void z80scc_channel::rcv_callback()
{
if (m_wr3 & WR3_RX_ENABLE)
{
- LOG("%s \"%s \"Channel %c receive data bit %d m_wr3:%02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_rxd, m_wr3);
+ LOG("%s: receive data bit %d m_wr3:%02x\n", FUNCNAME, m_rxd, m_wr3);
receive_register_update_bit(m_rxd);
}
-#if 1
else
{
- LOG("%s \"%s \"Channel %c Received Data Bit but receiver is disabled\n", FUNCNAME, owner()->tag(), 'A' + m_index);
- logerror("%s \"%s \"Channel %c Received data dit but receiver is disabled\n", FUNCNAME, owner()->tag(), 'A' + m_index);
+ logerror("%s: Received data dit but receiver is disabled\n", FUNCNAME);
}
-#endif
}
@@ -1346,7 +1304,7 @@ void z80scc_channel::rcv_complete()
receive_register_extract();
data = get_received_char();
- LOG("%s \"%s \"Channel %c Received Data %c\n", FUNCNAME, owner()->tag(), 'A' + m_index, data);
+ LOG("%s: Received Data %c\n", FUNCNAME, data);
receive_data(data);
#if START_BIT_HUNT
m_rcv_mode = RCV_SEEKING;
@@ -1385,13 +1343,13 @@ TODO:
*/
void z80scc_channel::set_rts(int state)
{
- LOG("%s(%d) \"%s\": %c \n", FUNCNAME, state, owner()->tag(), 'A' + m_index);
+ LOG("%s(%d)\n", FUNCNAME, state);
out_rts_cb(state);
}
void z80scc_channel::update_rts()
{
-// LOG("%s(%d) \"%s\": %c \n", FUNCNAME, state, owner()->tag(), 'A' + m_index);
+// LOG("%s(%d)\n", FUNCNAME, state);
if (m_wr5 & WR5_RTS)
{
// when the RTS bit is set, the _RTS output goes low
@@ -1406,8 +1364,12 @@ void z80scc_channel::update_rts()
set_rts(!m_rts);
}
- // data terminal ready output follows the state programmed into the DTR bit*/
- set_dtr((m_wr5 & WR5_DTR) ? 0 : 1);
+ // data terminal ready output follows the state programmed into the DTR bit
+ // unless configured to use the DTR pin as the transmit REQ pin for DMA
+ if (!(m_wr14 & WR14_DTR_REQ_FUNC))
+ {
+ set_dtr((m_wr5 & WR5_DTR) ? 0 : 1);
+ }
}
//-------------------------------------------------
@@ -1471,16 +1433,16 @@ uint8_t z80scc_channel::do_sccreg_rr0()
{
uint8_t rr0 = m_rr0;
- LOG("%s %c %s <- %02x\n",tag(), 'A' + m_index, FUNCNAME, m_rr0);
+ LOG("%s <- %02x\n", FUNCNAME, m_rr0);
if (m_extint_latch == 1)
{
rr0 &= ((~m_wr15) | WR15_WR7PRIME | WR15_STATUS_FIFO); // clear enabled bits, saving 2 unrelated bits
rr0 |= (m_extint_states & ~((~m_wr15) | WR15_WR7PRIME | WR15_STATUS_FIFO)); // set enabled bits to latched states
- LOGINT("- %c returning latched value RR0:%02x WR15:%02x => %02x\n", 'A' + m_index, m_rr0, m_wr15, rr0);
+ LOGINT("- returning latched value RR0:%02x WR15:%02x => %02x\n", m_rr0, m_wr15, rr0);
}
else
{
- LOG("- %c returning unlatched value: %02x\n", 'A' + m_index, rr0);
+ LOG("- returning unlatched value: %02x\n", rr0);
}
return rr0;
@@ -1491,7 +1453,7 @@ uint8_t z80scc_channel::do_sccreg_rr0()
* codes for the I-Field in the SDLC Receive Mode. */
uint8_t z80scc_channel::do_sccreg_rr1()
{
- LOGR("%s %s <- %02x\n",tag(), FUNCNAME, m_rr1);
+ LOGR("%s <- %02x\n", FUNCNAME, m_rr1);
return m_rr1;
}
@@ -1590,7 +1552,6 @@ uint8_t z80scc_channel::do_sccreg_rr6()
LOGR("%s\n", FUNCNAME);
if (m_wr15 & WR15_STATUS_FIFO)
{
- LOGSYNC(" - Status FIFO for synchronous mode - not implemented\n");
logerror(" - Status FIFO for synchronous mode - not implemented\n");
return 0;
}
@@ -1610,20 +1571,12 @@ uint8_t z80scc_channel::do_sccreg_rr7()
LOGR("%s\n", FUNCNAME);
if (!(m_uart->m_variant & (z80scc_device::SET_NMOS)))
{
- logerror("%s not implemented feature\n", FUNCNAME);
+ logerror("%s: feature not implemented\n", FUNCNAME);
return 0;
}
return m_rr3;
}
-#if 0 // Short cutted in control_read()
-/* RR8 is the Receive Data register. */
-uint8_t z80scc_channel::do_sccreg_rr8()
-{
- return data_read():
-}
-#endif
-
/* (ESCC and 85C30 Only)
On the ESCC, Read Register 9 reflects the contents of Write Register 3 provided the Extended
Read option has been enabled. On the NMOS/CMOS version, a read to this location returns an image
@@ -1640,8 +1593,7 @@ uint8_t z80scc_channel::do_sccreg_rr9()
/* RR10 contains some SDLC related miscellaneous status bits. Unused bits are always 0. */
uint8_t z80scc_channel::do_sccreg_rr10()
{
- LOGR("%s\n", FUNCNAME);
- logerror("%s not implemented feature\n", FUNCNAME);
+ logerror("%s: feature not implemented\n", FUNCNAME);
return m_rr10;
}
@@ -1682,7 +1634,7 @@ uint8_t z80scc_channel::do_sccreg_rr14()
{
LOGR("%s\n", FUNCNAME);
if (m_uart->m_variant & (z80scc_device::SET_ESCC | z80scc_device::TYPE_SCC85C30))
- return BIT(m_wr7, 6) ? m_wr7 : m_rr10;
+ return BIT(m_wr7p, 6) ? m_wr7p : m_rr10;
else
return m_rr10;
}
@@ -1703,7 +1655,7 @@ uint8_t z80scc_channel::do_sccreg_rr15()
uint8_t z80scc_channel::scc_register_read( uint8_t reg)
{
if (reg > 1)
- LOG("%s %02x\n", FUNCNAME, reg);
+ LOG("%s: %02x\n", FUNCNAME, reg);
uint8_t data = 0;
uint8_t wreg = 0;
@@ -1751,7 +1703,8 @@ uint8_t z80scc_channel::scc_register_read( uint8_t reg)
case REG_RR14_WR7_OR_R10: data = do_sccreg_rr14(); break;
case REG_RR15_WR15_EXT_STAT: data = do_sccreg_rr15(); break;
default:
- logerror(" \"%s\"%s: %c : Unsupported RRx register:%02x\n", owner()->tag(), FUNCNAME, 'A' + m_index, reg);
+ logerror("%s: Unsupported RRx register:%02x\n", FUNCNAME, reg);
+ break;
}
return data;
}
@@ -1765,19 +1718,19 @@ uint8_t z80scc_channel::control_read()
int reg = m_uart->m_wr0_ptrbits;
int regmask = (WR0_REGISTER_MASK | (m_uart->m_wr0_ptrbits & WR0_POINT_HIGH));
- LOGR("%s(%02x) reg %02x, regmask %02x, WR0 %02x\n", FUNCNAME, data, reg, regmask, m_wr0);
+ LOGR("%s(%02x): reg %02x, regmask %02x, WR0 %02x\n", FUNCNAME, data, reg, regmask, m_wr0);
m_uart->m_wr0_ptrbits = 0;
reg &= regmask;
if (reg != 0)
{
- LOG("%s(%02x) reg %02x, regmask %02x, WR0 %02x\n", FUNCNAME, data, reg, regmask, m_wr0);
+ LOG("%s(%02x): reg %02x, regmask %02x, WR0 %02x\n", FUNCNAME, data, reg, regmask, m_wr0);
m_wr0 &= ~regmask; // mask out register index
}
data = scc_register_read(reg);
- //LOG("%s \"%s\": %c : Register R%d read '%02x'\n", FUNCNAME, owner()->tag(), 'A' + m_index, reg, data);
+ //LOG("%s: Register R%d read '%02x'\n", FUNCNAME, reg, data);
return data;
}
@@ -1800,11 +1753,11 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data)
addressing*/
if (m_uart->m_variant & z80scc_device::SET_Z85X3X)
{
- LOG("%s %s: %c : - Point High command\n", FUNCNAME, owner()->tag(), 'A' + m_index);
+ LOG("%s: Point High command\n", FUNCNAME);
m_uart->m_wr0_ptrbits |= 8;
}
else
- LOG("%s %s: %c : - NULL command 2\n", FUNCNAME, owner()->tag(), 'A' + m_index);
+ LOG("%s: NULL command 2\n", FUNCNAME);
break;
case WR0_RESET_EXT_STATUS:
/*After an External/Status interrupt (a change on a modem line or a break condition,
@@ -1819,7 +1772,7 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data)
(there are two transitions), another interrupt is not generated. Exceptions to this
rule are detailed in the RR0 description.*/
- LOGCMD("%s %c - Reset External/Status Interrupt, latch %s\n", owner()->tag(), 'A' + m_index,
+ LOGCMD("Reset External/Status Interrupt, latch %s\n",
m_extint_latch == 1? "is released" : "was already released");
// Release latch if no other external or status sources are active
if ((m_extint_latch = m_uart->update_extint(m_index)) == 0)
@@ -1830,25 +1783,17 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data)
priority conditions to request interrupts. This command allows the use of the internal
daisy chain (even in systems without an external daisy chain) and is the last operation in
an interrupt service routine. */
- if (m_uart->m_variant & z80scc_device::SET_NMOS)
- {
- logerror("WR0 SWI ack command not supported on NMOS\n");
- LOGCMD("%s: %c : WR0_RESET_HIGHEST_IUS command not available on NMOS!\n", owner()->tag(), 'A' + m_index);
- }
- else
+ LOGCMD("Reset Highest IUS\n");
+ // loop over all interrupt sources
+ for (auto & elem : m_uart->m_int_state)
{
- LOGCMD("%s: %c : Reset Highest IUS\n", owner()->tag(), 'A' + m_index);
- // loop over all interrupt sources
- for (auto & elem : m_uart->m_int_state)
+ // find the first interrupt under service
+ if (elem & Z80_DAISY_IEO)
{
- // find the first interrupt under service
- if (elem & Z80_DAISY_IEO)
- {
- LOGCMD("- %c found IUS bit to clear\n", 'A' + m_index);
- elem = 0; // Clear IUS bit (called IEO in z80 daisy lingo)
- m_uart->check_interrupts();
- break;
- }
+ LOGCMD("- found IUS bit to clear\n");
+ elem = 0; // Clear IUS bit (called IEO in z80 daisy lingo)
+ m_uart->check_interrupts();
+ break;
}
}
break;
@@ -1858,18 +1803,18 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data)
data with the special condition is held in the Receive FIFO until this command is issued. If either
of these modes is selected and this command is issued before the data has been read from the
Receive FIFO, the data is lost */
- LOGCMD("%s: %c : WR0_ERROR_RESET - not implemented\n", owner()->tag(), 'A' + m_index);
+ LOGCMD("WR0_ERROR_RESET - not implemented\n");
if (m_rx_fifo_wp != m_rx_fifo_rp)
m_rx_fifo_rp_step(); // Reset error state in fifo and unlock it. unlock == step to next slot in fifo.
break;
case WR0_SEND_ABORT: // Flush transmitter and Send 8-13 bits of '1's, used with SDLC
- LOGCMD("%s: %c : WR0_SEND_ABORT - not implemented\n", owner()->tag(), 'A' + m_index);
+ LOGCMD("WR0_SEND_ABORT - not implemented\n");
break;
case WR0_NULL: // Do nothing
- LOGCMD("%s: %c : WR0_NULL\n", owner()->tag(), 'A' + m_index);
+ LOGCMD("WR0_NULL\n");
break;
case WR0_ENABLE_INT_NEXT_RX: // enable interrupt on next receive character
- LOGCMD("%s: %c : WR0_ENABLE_INT_NEXT\n", owner()->tag(), 'A' + m_index);
+ LOGCMD("WR0_ENABLE_INT_NEXT\n");
m_rx_first = 1;
break;
case WR0_RESET_TX_INT: // reset transmitter interrupt pending
@@ -1879,7 +1824,7 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data)
been completely sent. This command is necessary to prevent the transmitter from requesting an
interrupt when the transmit buffer becomes empty (with Transmit Interrupt Enabled).*/
m_tx_int_disarm = 1;
- LOGCMD("%s: %c : WR0_RESET_TX_INT\n", owner()->tag(), 'A' + m_index);
+ LOGCMD("WR0_RESET_TX_INT\n");
m_uart->m_int_state[INT_TRANSMIT_PRIO + (m_index == z80scc_device::CHANNEL_A ? 0 : 3 )] = 0;
// Based on the fact that prio levels are aligned with the bitorder of rr3 we can do this...
m_uart->m_chanA->m_rr3 &= ~(1 << (INT_TRANSMIT_PRIO + ((m_index == z80scc_device::CHANNEL_A) ? 3 : 0)));
@@ -1905,8 +1850,6 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data)
case WR0_CRC_RESET_TX_UNDERRUN: /* Resets Tx underrun/EOM bit (D6 of the RRO register) */
LOGCMD(" CRC_RESET_TX_UNDERRUN - not implemented\n");
break;
- default: /* Will not happen unless someone messes with the mask */
- logerror(" Wrong CRC reset/init command:%02x\n", data & WR0_CRC_RESET_CODE_MASK);
}
if (m_uart->m_variant & z80scc_device::SET_Z85X3X)
@@ -1919,19 +1862,19 @@ void z80scc_channel::do_sccreg_wr0(uint8_t data)
/* Write Register 1 is the control register for the various SCC interrupt and Wait/Request modes.*/
void z80scc_channel::do_sccreg_wr1(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %c : %s - %02x\n", FUNCNAME, data, owner()->tag(), 'A' + m_index, FUNCNAME, data);
+ LOG("%s(%02x)\n", FUNCNAME, data);
/* TODO: Sort out SCC specific behaviours from legacy SIO behaviours inherited from z80dart.cpp:
- Channel B only bits vs
- Parity Is Special Condition, bit2 */
m_wr1 = data;
- LOG("- External Interrupt Enable %u\n", (data & WR1_EXT_INT_ENABLE) ? 1 : 0);
- LOG("- Transmit Interrupt Enable %u\n", (data & WR1_TX_INT_ENABLE) ? 1 : 0);
- LOG("- Parity is special condition %u\n", (data & WR1_PARITY_IS_SPEC_COND) ? 1 : 0);
- LOG("- Wait/DMA Request Enable %u\n", (data & WR1_WREQ_ENABLE) ? 1 : 0);
+ LOG("- External Interrupt Enable %d\n", (data & WR1_EXT_INT_ENABLE) ? 1 : 0);
+ LOG("- Transmit Interrupt Enable %d\n", (data & WR1_TX_INT_ENABLE) ? 1 : 0);
+ LOG("- Parity is special condition %d\n", (data & WR1_PARITY_IS_SPEC_COND) ? 1 : 0);
+ LOG("- Wait/DMA Request Enable %d\n", (data & WR1_WREQ_ENABLE) ? 1 : 0);
LOG("- Wait/DMA Request Function %s\n", (data & WR1_WREQ_FUNCTION) ? "Request" : "Wait");
LOG("- Wait/DMA Request on %s\n", (data & WR1_WREQ_ON_RX_TX) ? "Receive" : "Transmit");
- check_waitrequest();
+ check_dma_request();
switch (data & WR1_RX_INT_MODE_MASK)
{
@@ -1951,7 +1894,7 @@ void z80scc_channel::do_sccreg_wr1(uint8_t data)
LOG("- Receiver Interrupt on Special Conditions only\n");
break;
}
- if ((data & WR1_RX_INT_MODE_MASK) == WR1_PARITY_IS_SPEC_COND)
+ if (data & WR1_PARITY_IS_SPEC_COND)
LOG("- Parity error is a Special Condition\n");
m_uart->check_interrupts();
}
@@ -1961,8 +1904,8 @@ void z80scc_channel::do_sccreg_wr1(uint8_t data)
is controlled by the Vector Includes Status (VIS) and the Status High/Status Low bits in WR9.*/
void z80scc_channel::do_sccreg_wr2(uint8_t data)
{
- LOG("%s(%02x) Setting the interrupt vector\n", FUNCNAME, data);
- m_wr2 = data;
+ LOG("%s(%02x): Setting the interrupt vector\n", FUNCNAME, data);
+ m_uart->m_chanA->m_wr2 = data;
m_uart->m_chanA->m_rr2 = data;
m_uart->m_chanB->m_rr2 = data; /* TODO: Sort out the setting of ChanB depending on bits in WR9 */
@@ -1978,15 +1921,15 @@ void z80scc_channel::do_sccreg_wr2(uint8_t data)
the Sync/Hunt bit is set again is by the Enter Hunt Mode command or by disabling the receiver.*/
void z80scc_channel::do_sccreg_wr3(uint8_t data)
{
- LOG("%s(%02x) Setting up the receiver\n", FUNCNAME, data);
+ LOG("%s(%02x): Setting up the receiver\n", FUNCNAME, data);
m_wr3 = data;
- LOG("- Receiver Enable: %u\n", (data & WR3_RX_ENABLE) ? 1 : 0);
- LOG("- Sync Char Load Inhibit %u\n", (data & WR3_SYNC_CHAR_LOAD_INHIBIT) ? 1 : 0);
- LOG("- Address Search Mode %u\n", (data & WR3_ADDRESS_SEARCH_MODE) ? 1 : 0);
- LOG("- Rx CRC Enable %u\n", (data & WR3_RX_CRC_ENABLE) ? 1 : 0);
- LOG("- Enter Hunt Mode %u\n", (data & WR3_ENTER_HUNT_MODE) ? 1 : 0);
- LOG("- Auto Enables %u\n", (data & WR3_AUTO_ENABLES) ? 1 : 0);
- LOG("- Receiver Bits/Character %u\n", get_rx_word_length());
+ LOG("- Receiver Enable: %d\n", (data & WR3_RX_ENABLE) ? 1 : 0);
+ LOG("- Sync Char Load Inhibit %d\n", (data & WR3_SYNC_CHAR_LOAD_INHIBIT) ? 1 : 0);
+ LOG("- Address Search Mode %d\n", (data & WR3_ADDRESS_SEARCH_MODE) ? 1 : 0);
+ LOG("- Rx CRC Enable %d\n", (data & WR3_RX_CRC_ENABLE) ? 1 : 0);
+ LOG("- Enter Hunt Mode %d\n", (data & WR3_ENTER_HUNT_MODE) ? 1 : 0);
+ LOG("- Auto Enables %d\n", (data & WR3_AUTO_ENABLES) ? 1 : 0);
+ LOG("- Receiver Bits/Character %d\n", get_rx_word_length());
if ((m_wr3 & WR3_ENTER_HUNT_MODE) || ((m_wr3 & WR3_RX_ENABLE) == 0))
{
@@ -1998,7 +1941,7 @@ void z80scc_channel::do_sccreg_wr3(uint8_t data)
void z80scc_channel::do_sccreg_wr4(uint8_t data)
{
- LOG("%s(%02x) Setting up asynchronous frame format and clock\n", FUNCNAME, data);
+ LOG("%s(%02x): Setting up asynchronous frame format and clock\n", FUNCNAME, data);
if (data == m_wr4)
{
LOG("- suppressing reinit of Tx as write to wr4 is identical to previous value\n");
@@ -2013,7 +1956,7 @@ void z80scc_channel::do_sccreg_wr4(uint8_t data)
(data & WR4_BIT4 ? "External Sync Mode - /SYNC is used as input!" : "SDLC - not implemented")
: (data & WR4_BIT4 ? "16 bit" : "8 bit"))
: "Disabled");
- LOG("- Clock Mode: %uX\n", get_clock_mode());
+ LOG("- Clock Mode: %dX\n", get_clock_mode());
update_serial();
safe_transmit_register_reset();
receive_register_reset();
@@ -2022,43 +1965,42 @@ void z80scc_channel::do_sccreg_wr4(uint8_t data)
void z80scc_channel::do_sccreg_wr5(uint8_t data)
{
- LOG("%s(%02x) Setting up the transmitter\n", FUNCNAME, data);
- if (data == m_wr5)
- {
- LOG("- suppressing reinit of Tx as write to wr5 is identical to previous value\n");
- }
- else
+ if (data != m_wr5)
{
+ LOG("%s(%02x): Setting up the transmitter\n", FUNCNAME, data);
m_wr5 = data;
- LOG("- Transmitter Enable %u\n", (data & WR5_TX_ENABLE) ? 1 : 0);
- LOG("- Transmitter Bits/Character %u\n", get_tx_word_length());
- LOG("- Send Break %u\n", (data & WR5_SEND_BREAK) ? 1 : 0);
- LOG("- Request to Send %u\n", (data & WR5_RTS) ? 1 : 0);
- LOG("- Data Terminal Ready %u\n", (data & WR5_DTR) ? 1 : 0);
+ LOG("- Transmitter Enable %d\n", (data & WR5_TX_ENABLE) ? 1 : 0);
+ LOG("- Transmitter Bits/Character %d\n", get_tx_word_length());
+ LOG("- Send Break %d\n", (data & WR5_SEND_BREAK) ? 1 : 0);
+ LOG("- Request to Send %d\n", (data & WR5_RTS) ? 1 : 0);
+ LOG("- Data Terminal Ready %d\n", (data & WR5_DTR) ? 1 : 0);
update_serial();
safe_transmit_register_reset();
update_rts(); // Will also update DTR accordingly
- check_waitrequest();
+ check_dma_request();
}
}
void z80scc_channel::do_sccreg_wr6(uint8_t data)
{
- LOG("%s(%02x) Transmit sync\n", FUNCNAME, data);
+ LOG("%s(%02x): Transmit sync\n", FUNCNAME, data);
m_sync_pattern = (m_sync_pattern & 0xff00) | data;
}
void z80scc_channel::do_sccreg_wr7(uint8_t data)
{
- LOG("%s(%02x) Receive sync\n", FUNCNAME, data);
- m_sync_pattern = (data << 8) | (m_sync_pattern & 0xff);
+ LOG("%s(%02x): Receive sync\n", FUNCNAME, data);
+ if ((m_uart->m_variant & (z80scc_device::SET_ESCC | z80scc_device::TYPE_SCC85C30)) && BIT(m_wr15, 0))
+ m_wr7p = data;
+ else
+ m_sync_pattern = (data << 8) | (m_sync_pattern & 0xff);
}
/* WR8 is the transmit buffer register */
void z80scc_channel::do_sccreg_wr8(uint8_t data)
{
- LOGTX("%s(%02x) \"%s\": %c : Transmit Buffer write %02x\n", FUNCNAME, data, owner()->tag(), 'A' + m_index, data);
+ LOGTX("%s(%02x): Transmit Buffer write\n", FUNCNAME, data);
data_write(data);
}
@@ -2073,18 +2015,18 @@ void z80scc_channel::do_sccreg_wr9(uint8_t data)
switch (data & WR9_CMD_MASK)
{
case WR9_CMD_NORESET:
- LOG("\"%s\": %c : Master Interrupt Control - No reset %02x\n", owner()->tag(), 'A' + m_index, data);
+ LOG("Master Interrupt Control - No reset %02x\n", data);
break;
case WR9_CMD_CHNB_RESET:
- LOGINT("\"%s\": %c : Master Interrupt Control - Channel B reset %02x\n", owner()->tag(), 'A' + m_index, data);
+ LOGINT("Master Interrupt Control - Channel B reset %02x\n", data);
m_uart->m_chanB->reset();
break;
case WR9_CMD_CHNA_RESET:
- LOGINT("\"%s\": %c : Master Interrupt Control - Channel A reset %02x\n", owner()->tag(), 'A' + m_index, data);
+ LOGINT("Master Interrupt Control - Channel A reset %02x\n", data);
m_uart->m_chanA->reset();
break;
case WR9_CMD_HW_RESET:
- LOGINT("\"%s\": %c : Master Interrupt Control - Device reset %02x\n", owner()->tag(), 'A' + m_index, data);
+ LOGINT("Master Interrupt Control - Device reset %02x\n", data);
/*"The effects of this command are identical to those of a hardware reset, except that the Shift Right/Shift Left bit is
not changed and the MIE, Status High/Status Low and DLC bits take the programmed values that accompany this command."
*/
@@ -2106,6 +2048,7 @@ void z80scc_channel::do_sccreg_wr9(uint8_t data)
break;
default:
logerror("Code is broken in WR9, please report!\n");
+ break;
}
}
@@ -2114,7 +2057,7 @@ void z80scc_channel::do_sccreg_wr9(uint8_t data)
void z80scc_channel::do_sccreg_wr10(uint8_t data)
{
m_wr10 = data;
- LOG("\"%s\": %c : %s Misc Tx/Rx Control %02x - not implemented \n", owner()->tag(), 'A' + m_index, FUNCNAME, data);
+ LOG("%s: Misc Tx/Rx Control %02x - not implemented\n", FUNCNAME, data);
LOG("- 6/8 bit sync %d\n", data & WR10_8_6_BIT_SYNC ? 1 : 0);
LOG("- Loop Mode %d\n", data & WR10_LOOP_MODE ? 1 : 0);
LOG("- Abort/Flag on underrun %d\n", data & WR10_ABORT_FLAG_UNDERRUN ? 1 : 0);
@@ -2131,7 +2074,7 @@ receive and transmit clocks, the type of signal on the /SYNC and /RTxC pins, and
the /TRxC pin.*/
void z80scc_channel::do_sccreg_wr11(uint8_t data)
{
- LOG("\"%s\": %c : %s Clock Mode Control %02x\n", owner()->tag(), 'A' + m_index, FUNCNAME, data);
+ LOG("%s: Clock Mode Control %02x\n", FUNCNAME, data);
m_wr11 = data;
/*Bit 7: This bit controls the type of input signal the SCC expects to see on the /RTxC pin. If this bit is set
to 0, the SCC expects a TTL-compatible signal as an input to this pin. If this bit is set to 1, the SCC
@@ -2147,14 +2090,12 @@ void z80scc_channel::do_sccreg_wr11(uint8_t data)
interfere with any of the modes of operation in the SCC, but simply control a multiplexer just
before the internal receive clock input. A hardware reset forces the receive clock to come from the
/RTxC pin.*/
- LOG("- Receive clock source is: ");
switch (data & WR11_RCVCLK_SRC_MASK)
{
- case WR11_RCVCLK_SRC_RTXC: LOG("RTxC - not implemented\n"); break;
- case WR11_RCVCLK_SRC_TRXC: LOG("TRxC - not implemented\n"); break;
- case WR11_RCVCLK_SRC_BR: LOG("Baudrate Generator\n"); break;
- case WR11_RCVCLK_SRC_DPLL: LOG("DPLL - not implemented\n"); break;
- default: logerror("Wrong!\n");/* Will not happen unless someone messes with the mask */
+ case WR11_RCVCLK_SRC_RTXC: LOG("Receive clock source is RTxC\n"); break;
+ case WR11_RCVCLK_SRC_TRXC: LOG("Receive clock source is TRxC - not implemented\n"); break;
+ case WR11_RCVCLK_SRC_BR: LOG("Receive clock source is Baudrate Generator\n"); break;
+ case WR11_RCVCLK_SRC_DPLL: LOG("Receive clock source is DPLL - not implemented\n"); break;
}
/*Bits 4 and 3: Transmit Clock select bits 1 and 0.
These bits determine the source of the transmit clock as listed in Table . They do not interfere with
@@ -2163,14 +2104,12 @@ void z80scc_channel::do_sccreg_wr11(uint8_t data)
degrees the output of the DPLL used by the receiver. This makes the received and transmitted bit
cells occur simultaneously, neglecting delays. A hardware reset selects the /TRxC pin as the
source of the transmit clocks.*/
- LOG("- Transmit clock source is: ");
switch (data & WR11_TRACLK_SRC_MASK)
{
- case WR11_TRACLK_SRC_RTXC: LOG("RTxC - not implemented\n"); break;
- case WR11_TRACLK_SRC_TRXC: LOG("TRxC - not implemented\n"); break;
- case WR11_TRACLK_SRC_BR: LOG("Baudrate Generator\n"); break;
- case WR11_TRACLK_SRC_DPLL: LOG("DPLL - not implemented\n"); break;
- default: logerror("Wrong!\n");/* Will not happen unless someone messes with the mask */
+ case WR11_TRACLK_SRC_RTXC: LOG("Transmit clock source is RTxC\n"); break;
+ case WR11_TRACLK_SRC_TRXC: LOG("Transmit clock source is TRxC - not implemented\n"); break;
+ case WR11_TRACLK_SRC_BR: LOG("Transmit clock source is Baudrate Generator\n"); break;
+ case WR11_TRACLK_SRC_DPLL: LOG("Transmit clock source is DPLL - not implemented\n"); break;
}
/* Bit 2: TRxC Pin I/O control bit
This bit determines the direction of the /TRxC pin. If this bit is set to 1, the /TRxC pin is an output
@@ -2178,7 +2117,6 @@ void z80scc_channel::do_sccreg_wr11(uint8_t data)
transmit clock is programmed to come from the /TRxC pin, /TRxC is an input, regardless of the
state of this bit. The /TRxC pin is also an input if this bit is set to 0. A hardware reset forces this bit
to 0.*/
- LOG("- TRxC pin is %s\n", data & WR11_TRXC_DIRECTION ? "Output" : "Input");
/*Bits 1 and 0: /TRxC Output Source select bits 1 and 0
These bits determine the signal to be echoed out of the SCC via the /TRxC pin as listed in Table
on page 167. No signal is produced if /TRxC has been programmed as the source of either the
@@ -2188,16 +2126,18 @@ void z80scc_channel::do_sccreg_wr11(uint8_t data)
Hardware reset selects the XTAL oscillator as the output source*/
if (data & WR11_TRXC_DIRECTION)
{
- LOG("- TRxC pin output is: ");
switch (data & WR11_TRXSRC_SRC_MASK)
{
- case WR11_TRXSRC_SRC_XTAL: LOG("the Oscillator - not implemented\n"); break;
- case WR11_TRXSRC_SRC_TRA: LOG("Transmit clock - not implemented\n"); break;
- case WR11_TRXSRC_SRC_BR: LOG("Baudrate Generator\n"); break;
- case WR11_TRXSRC_SRC_DPLL: LOG("DPLL - not implemented\n"); break;
- default: logerror("Wrong!\n");/* Will not happen unless someone messes with the mask */
+ case WR11_TRXSRC_SRC_XTAL: LOG("TRxC output is the Oscillator - not implemented\n"); break;
+ case WR11_TRXSRC_SRC_TRA: LOG("TRxC output is Transmit clock - not implemented\n"); break;
+ case WR11_TRXSRC_SRC_BR: LOG("TRxC output is Baudrate Generator\n"); break;
+ case WR11_TRXSRC_SRC_DPLL: LOG("TRxC output is DPLL - not implemented\n"); break;
}
}
+ else
+ LOG("TRxC pin is Input\n");
+
+ update_serial();
}
/*WR12 contains the lower byte of the time constant for the baud rate generator. The time constant
@@ -2219,7 +2159,7 @@ void z80scc_channel::do_sccreg_wr12(uint8_t data)
{
m_wr12 = data;
update_serial();
- LOG("\"%s\": %c : %s %02x Low byte of Time Constant for Baudrate generator\n", owner()->tag(), 'A' + m_index, FUNCNAME, data);
+ LOG("%s(%02x): Low byte of Time Constant for Baudrate generator\n", FUNCNAME, data);
}
/* WR13 contains the upper byte of the time constant for the baud rate generator. */
@@ -2227,17 +2167,19 @@ void z80scc_channel::do_sccreg_wr13(uint8_t data)
{
m_wr13 = data;
update_serial();
- LOG("\"%s\": %c : %s %02x High byte of Time Constant for Baudrate generator\n", owner()->tag(), 'A' + m_index, FUNCNAME, data);
+ LOG("%s(%02x): High byte of Time Constant for Baudrate generator\n", FUNCNAME, data);
}
/*
WR14 contains some miscellaneous control bits */
void z80scc_channel::do_sccreg_wr14(uint8_t data)
{
+ bool brg_change = false;
+
switch (data & WR14_DPLL_CMD_MASK)
{
case WR14_CMD_NULL:
- LOG("\"%s\": %c : %s Misc Control Bits Null Command %02x\n", owner()->tag(), 'A' + m_index, FUNCNAME, data);
+ LOG("%s: Misc Control Bits Null Command %02x\n", FUNCNAME, data);
break;
case WR14_CMD_ESM:
/* Issuing this command causes the DPLL to enter the Search mode, where the DPLL searches for a locking edge in the
@@ -2259,67 +2201,57 @@ void z80scc_channel::do_sccreg_wr14(uint8_t data)
see an edge during the expected window, the one clock missing bit in RR10 is set. If the DPLL does not see an edge
after two successive attempts, the two clocks missing bits in RR10 are set and the DPLL automatically enters the
Search mode. This command resets both clocks missing latches.*/
- LOG("\"%s\": %c : %s Misc Control Bits Enter Search Mode Command - not implemented\n", owner()->tag(), 'A' + m_index, FUNCNAME);
+ LOG("%s: Misc Control Bits Enter Search Mode Command - not implemented\n", FUNCNAME);
break;
case WR14_CMD_RMC:
/* Issuing this command disables the DPLL, resets the clock missing latches in RR10, and forces a continuous Search mode state */
- LOG("\"%s\": %c : %s Misc Control Bits Reset Missing Clocks Command - not implemented\n", owner()->tag(), 'A' + m_index, FUNCNAME);
+ LOG("%s: Misc Control Bits Reset Missing Clocks Command - not implemented\n", FUNCNAME);
break;
case WR14_CMD_DISABLE_DPLL:
/* Issuing this command disables the DPLL, resets the clock missing latches in RR10, and forces a continuous Search mode state.*/
- LOG("\"%s\": %c : %s Misc Control Bits Disable DPLL Command - not implemented\n", owner()->tag(), 'A' + m_index, FUNCNAME);
+ LOG("%s: Misc Control Bits Disable DPLL Command - not implemented\n", FUNCNAME);
break;
case WR14_CMD_SS_BRG:
/* Issuing this command forces the clock for the DPLL to come from the output of the BRG. */
- LOG("\"%s\": %c : %s Misc Control Bits Baudrate Generator Input DPLL Command - not implemented\n", owner()->tag(), 'A' + m_index, FUNCNAME);
+ LOG("%s: Misc Control Bits Baudrate Generator Input DPLL Command - not implemented\n", FUNCNAME);
break;
case WR14_CMD_SS_RTXC:
/* Issuing the command forces the clock for the DPLL to come from the /RTxC pin or the crystal oscillator, depending on
the state of the XTAL/no XTAL bit in WR11. This mode is selected by a channel or hardware reset*/
- LOG("\"%s\": %c : %s Misc Control Bits RTxC Input DPLL Command - not implemented\n", owner()->tag(), 'A' + m_index, FUNCNAME);
+ LOG("%s: Misc Control Bits RTxC Input DPLL Command - not implemented\n", FUNCNAME);
break;
case WR14_CMD_SET_FM:
/* This command forces the DPLL to operate in the FM mode and is used to recover the clock from FM or Manchester-Encoded
data. (Manchester is decoded by placing the receiver in NRZ mode while the DPLL is in FM mode.)*/
- LOG("\"%s\": %c : %s Misc Control Bits Set FM Mode Command - not implemented\n", owner()->tag(), 'A' + m_index, FUNCNAME);
+ LOG("%s: Misc Control Bits Set FM Mode Command - not implemented\n", FUNCNAME);
break;
case WR14_CMD_SET_NRZI:
/* Issuing this command forces the DPLL to operate in the NRZI mode. This mode is also selected by a hardware or channel reset.*/
- LOG("\"%s\": %c : %s Mics Control Bits Set NRZI Mode Command - not implemented\n", owner()->tag(), 'A' + m_index, FUNCNAME);
+ LOG("%s: Misc Control Bits Set NRZI Mode Command - not implemented\n", FUNCNAME);
break;
default:
- logerror("\"%s\": %c : %s Mics Control Bits command %02x - not implemented \n", owner()->tag(), 'A' + m_index, FUNCNAME, data);
+ logerror("%s: Misc Control Bits command %02x - not implemented\n", FUNCNAME, data);
+ break;
}
/* Based on baudrate code from 8530scc.cpp */
if ( !(m_wr14 & WR14_BRG_ENABLE) && (data & WR14_BRG_ENABLE) ) // baud rate generator being enabled?
{
- LOG("\"%s\": %c : %s Mics Control Bits Baudrate generator enabled with ", owner()->tag(), 'A' + m_index, FUNCNAME);
- if (data & WR14_BRG_SOURCE) // Do we use the PCLK as baudrate source
- {
- LOG(" - PCLK as source\n");
-
-#if Z80SCC_USE_LOCAL_BRG
- baudtimer->adjust(attotime::from_hz(rate), TIMER_ID_BAUD, attotime::from_hz(rate)); // Start the baudrate generator
-#if START_BIT_HUNT
- m_rcv_mode = RCV_SEEKING;
-#endif
-#endif
- }
- else
- {
- LOG("external clock source\n");
- }
+ brg_change = true;
+ LOG("%s: Misc Control Bits Baudrate generator enabled with %s source\n", FUNCNAME, (data & WR14_BRG_SOURCE) ? "PCLK" : "external clock");
}
else if ( (m_wr14 & WR14_BRG_ENABLE) && !(data & WR14_BRG_ENABLE) ) // baud rate generator being disabled?
{
-#if Z80SCC_USE_LOCAL_BRG
- baudtimer->adjust(attotime::never, TIMER_ID_BAUD, attotime::never); // Stop the baudrate generator
+ m_baudtimer->adjust(attotime::never); // Stop the baudrate generator
m_brg_counter = 0;
-#endif
}
+
+ if (!(m_wr14 & WR14_LOCAL_LOOPBACK) && (data & WR14_LOCAL_LOOPBACK))
+ receive_register_reset();
+
// TODO: Add info on the other bits of this register
m_wr14 = data;
update_serial();
+ if (brg_change) update_baudtimer();
}
/* WR15 is the External/Status Source Control register. If the External/Status interrupts are enabled
@@ -2330,8 +2262,8 @@ void z80scc_channel::do_sccreg_wr14(uint8_t data)
#define WR15NO "not implemented"
void z80scc_channel::do_sccreg_wr15(uint8_t data)
{
- LOG("%s(%02x) \"%s\": %c : External/Status Control Bits\n",
- FUNCNAME, data, owner()->tag(), 'A' + m_index);
+ LOG("%s(%02x): External/Status Control Bits\n",
+ FUNCNAME, data);
LOG("WR7 prime ints : %s\n", data & WR15_WR7PRIME ? WR15NO : "disabled");
LOG("Zero count ints : %s\n", data & WR15_ZEROCOUNT ? WR15NO : "disabled");
LOG("14 bit Status FIFO : %s\n", data & WR15_STATUS_FIFO ? WR15NO : "disabled");
@@ -2340,7 +2272,13 @@ void z80scc_channel::do_sccreg_wr15(uint8_t data)
LOG("CTS ints : %s\n", data & WR15_CTS ? WR15EN : "disabled");
LOG("Tx underr./EOM ints: %s\n", data & WR15_TX_EOM ? WR15NO : "disabled");
LOG("Break/Abort ints : %s\n", data & WR15_BREAK_ABORT ? WR15NO : "disabled");
+
+ const uint8_t old_reg = m_wr15;
m_wr15 = data;
+ if ((old_reg & WR15_ZEROCOUNT) != (m_wr15 & WR15_ZEROCOUNT))
+ {
+ update_baudtimer();
+ }
}
void z80scc_channel::scc_register_write(uint8_t reg, uint8_t data)
@@ -2364,7 +2302,8 @@ void z80scc_channel::scc_register_write(uint8_t reg, uint8_t data)
case REG_WR14_MISC_CTRL: do_sccreg_wr14(data); break;
case REG_WR15_EXT_ST_INT_CTRL: do_sccreg_wr15(data); break;
default:
- logerror("\"%s\": %c : Unsupported WRx register:%02x\n", owner()->tag(), 'A' + m_index, reg);
+ logerror("Unsupported WRx register:%02x\n", reg);
+ break;
}
}
@@ -2403,7 +2342,7 @@ void z80scc_channel::control_write(uint8_t data)
m_wr0 &= ~regmask;
}
- LOGSETUP(" * %s %c Reg %02x <- %02x - %s\n", owner()->tag(), 'A' + m_index, reg, data, std::array<char const *, 16>
+ LOGSETUP(" * Reg %02x <- %02x - %s\n", reg, data, std::array<char const *, 16>
{{ "Command register", "Tx/Rx Interrupt and Data Transfer Modes", "Interrupt Vector", "Rx Parameters and Control",
"Tx/Rx Misc Parameters and Modes", "Tx Parameters and Controls", "Sync Characters or SDLC Address Field","Sync Character or SDLC Flag/Prime",
"Tx Buffer", "Master Interrupt Control", "Miscellaneous Tx/Rx Control Bits", "Clock Mode Control",
@@ -2420,7 +2359,7 @@ uint8_t z80scc_channel::data_read()
{
uint8_t data = 0;
- LOGRCV("%s \"%s\": %c : Data Register Read: ", FUNCNAME, owner()->tag(), 'A' + m_index);
+ LOGRCV("%s: Data Register Read", FUNCNAME);
if (m_rx_fifo_wp != m_rx_fifo_rp)
{
@@ -2464,10 +2403,11 @@ uint8_t z80scc_channel::data_read()
m_uart->check_interrupts();
}
}
+
+ check_dma_request();
}
else
{
- LOG("data_read: Attempt to read out character from empty FIFO\n");
logerror("data_read: Attempt to read out character from empty FIFO\n");
}
@@ -2513,13 +2453,12 @@ void z80scc_device::db_w(offs_t offset, uint8_t data) { m_chanB->data_write(data
void z80scc_channel::data_write(uint8_t data)
{
/* Tx FIFO is full or...? */
- LOG("%s \"%s\": %c : Data Register Write: %02d '%c'\n", FUNCNAME, owner()->tag(), 'A' + m_index, data, isprint(data) ? data : ' ');
+ LOG("%s: Data Register Write: %02d '%c'\n", FUNCNAME, data, isprint(data) ? data : ' ');
if ( !(m_rr0 & RR0_TX_BUFFER_EMPTY) && // NMOS/CMOS 1 slot "FIFO" is controlled by the TBE bit instead of fifo logic
( (m_tx_fifo_wp + 1 == m_tx_fifo_rp) || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) )))
{
logerror("- TX FIFO is full, discarding data\n");
- LOGTX("- TX FIFO is full, discarding data\n");
}
else // ..there is still room
{
@@ -2564,7 +2503,7 @@ void z80scc_channel::data_write(uint8_t data)
}
}
- check_waitrequest();
+ check_dma_request();
/* Transmitter enabled? */
if (m_wr5 & WR5_TX_ENABLE)
@@ -2616,7 +2555,7 @@ void z80scc_channel::data_write(uint8_t data)
//-------------------------------------------------
void z80scc_channel::receive_data(uint8_t data)
{
- LOGRCV("\"%s\": %c : Received Data Byte '%c'/%02x put into FIFO\n", owner()->tag(), 'A' + m_index, isprint(data) ? data : ' ', data);
+ LOGRCV("Received Data Byte '%c'/%02x put into FIFO\n", isprint(data) ? data : ' ', data);
if (m_rx_fifo_wp + 1 == m_rx_fifo_rp || ( (m_rx_fifo_wp + 1 == m_rx_fifo_sz) && (m_rx_fifo_rp == 0) ))
{
@@ -2626,7 +2565,7 @@ void z80scc_channel::receive_data(uint8_t data)
// store received character but do not step the fifo
m_rx_data_fifo[m_rx_fifo_wp] = data;
- logerror("Receive_data() Error %02x\n", m_rx_error_fifo[m_rx_fifo_wp] & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR));
+ LOGRCV("Receive_data() Error %02x\n", m_rx_error_fifo[m_rx_fifo_wp] & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR));
}
else
{
@@ -2643,6 +2582,7 @@ void z80scc_channel::receive_data(uint8_t data)
}
m_rr0 |= RR0_RX_CHAR_AVAILABLE;
+ check_dma_request();
// receive interrupt on FIRST and ALL character
switch (m_wr1 & WR1_RX_INT_MODE_MASK)
@@ -2668,7 +2608,7 @@ void z80scc_channel::receive_data(uint8_t data)
//-------------------------------------------------
void z80scc_channel::cts_w(int state)
{
- LOG("\"%s\"%s: %c : CTS %u\n", owner()->tag(), FUNCNAME, 'A' + m_index, state);
+ LOG("%s(%d)\n", FUNCNAME, state);
if ((m_rr0 & RR0_CTS) != (state ? 0 : RR0_CTS)) // SCC change detection logic
{
@@ -2705,7 +2645,7 @@ void z80scc_channel::cts_w(int state)
//-------------------------------------------------
void z80scc_channel::dcd_w(int state)
{
- LOGDCD("\"%s\": %c : DCD %u\n", owner()->tag(), 'A' + m_index, state);
+ LOGDCD("%s(%d)\n", FUNCNAME, state);
if ((m_rr0 & RR0_DCD) != (state ? 0 : RR0_DCD)) // SCC change detection logic
{
@@ -2744,7 +2684,7 @@ void z80scc_channel::dcd_w(int state)
//-------------------------------------------------
void z80scc_channel::sync_w(int state)
{
- LOGSYNC("\"%s\": %c : SYNC %u\n", owner()->tag(), 'A' + m_index, state);
+ LOGSYNC("%s(%d)\n", FUNCNAME, state);
/*
* The /SYNC pin is a general purpose input whose state is reported in the
@@ -2782,34 +2722,7 @@ void z80scc_channel::sync_w(int state)
//-------------------------------------------------
void z80scc_channel::rxc_w(int state)
{
-/* Support for external clock as source for BRG yet to be finished */
-#if 0
- //LOG("\"%s\": %c : Receiver Clock Pulse\n", owner()->tag(), m_index + 'A');
- if ( ((m_wr3 & WR3_RX_ENABLE) | (m_wr5 & WR5_TX_ENABLE)) && m_wr14 & WR14_BRG_ENABLE)
- {
- if (!(m_wr14 & WR14_BRG_SOURCE)) // Is the Baud rate Generator driven by RTxC?
- {
- printf("x");
- if (!m_brg_counter) // Zero crossing?!
- {
- printf(".");
- m_brg_counter = m_wr13 << 8 | m_wr12; // Reload BRG counter
- if ((m_wr11 & WR11_TRACLK_SRC_MASK) == WR11_TRACLK_SRC_BR) // Is transmitt clock driven by BRG?
- {
- printf("+");
- txc_w(state);
- }
- }
- else
- {
- m_brg_counter--;
- if ((m_wr11 & WR11_RCVCLK_SRC_MASK) == WR11_RCVCLK_SRC_BR) // Is receive clock driven by BRG and not zero cross
- return;
- }
- }
- }
-#endif
-
+ /* Support for external clock as source for BRG has not been added */
if (m_wr3 & WR3_RX_ENABLE)
{
int clocks = get_clock_mode();
@@ -2834,7 +2747,7 @@ void z80scc_channel::rxc_w(int state)
//-------------------------------------------------
void z80scc_channel::txc_w(int state)
{
- //LOG("\"%s\": %c : Transmitter Clock Pulse\n", owner()->tag(), m_index + 'A');
+ //LOG("Transmitter Clock Pulse\n");
if (m_wr5 & WR5_TX_ENABLE)
{
int clocks = get_clock_mode();
@@ -2884,19 +2797,64 @@ unsigned int z80scc_channel::get_brg_rate()
if (m_wr14 & WR14_BRG_SOURCE) // Do we use the PCLK as baudrate source
{
rate = owner()->clock() / (brg_const == 0 ? 1 : brg_const);
- LOG(" - Source bit rate (%d) = PCLK (%d) / (%d)\n", rate, owner()->clock(), brg_const);
+ LOG(" - BRG Source bit rate (%d) = PCLK (%d) / (%d)\n", rate, owner()->clock(), brg_const);
}
else // Else we use the RTxC as BRG source
{
unsigned int source = (m_index == z80scc_device::CHANNEL_A) ? m_uart->m_rxca : m_uart->m_rxcb;
rate = source / (brg_const == 0 ? 1 : brg_const);
- LOG(" - Source bit rate (%d) = RTxC (%d) / (%d)\n", rate, source, brg_const);
+ LOG(" - BRG Source bit rate (%d) = RTxC (%d) / (%d)\n", rate, source, brg_const);
}
return (rate / (2 * get_clock_mode()));
}
//-------------------------------------------------
+// get_rtxc_rate
+//-------------------------------------------------
+unsigned int z80scc_channel::get_rtxc_rate()
+{
+ unsigned int rate;
+ unsigned int source = (m_index == z80scc_device::CHANNEL_A) ? m_uart->m_rxca : m_uart->m_rxcb;
+ rate = source / get_clock_mode();
+ LOG(" - RTxC Source bit rate (%d) = RTxC (%d) / (%d)\n", rate, source, get_clock_mode());
+ return rate;
+}
+
+void z80scc_channel::update_baudtimer()
+{
+ unsigned int rate;
+ unsigned int brg_const;
+
+ if (m_wr14 & WR14_BRG_ENABLE)
+ {
+ brg_const = 2 + (m_wr13 << 8 | m_wr12);
+ if (m_wr14 & WR14_BRG_SOURCE) // Do we use the PCLK as baudrate source
+ {
+ rate = owner()->clock() / (brg_const == 0 ? 1 : brg_const);
+ }
+ else // Else we use the RTxC as BRG source
+ {
+ unsigned int source = (m_index == z80scc_device::CHANNEL_A) ? m_uart->m_rxca : m_uart->m_rxcb;
+ rate = source / (brg_const == 0 ? 1 : brg_const);
+ }
+
+ if (m_wr15 & WR15_ZEROCOUNT)
+ {
+ m_baudtimer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate));
+ }
+ else
+ {
+ m_baudtimer->adjust(attotime::never);
+ }
+ }
+ else
+ {
+ m_baudtimer->adjust(attotime::never);
+ }
+}
+
+//-------------------------------------------------
// update_serial -
//-------------------------------------------------
void z80scc_channel::update_serial()
@@ -2917,7 +2875,7 @@ void z80scc_channel::update_serial()
parity = PARITY_NONE;
}
- LOG("%s \"%s \"Channel %c setting data frame %d+%d%c%d\n", FUNCNAME, owner()->tag(), 'A' + m_index, 1,
+ LOG("%s: setting data frame %d+%d%c%d\n", FUNCNAME, 1,
data_bit_count, parity == PARITY_NONE ? 'N' : parity == PARITY_EVEN ? 'E' : 'O', (stop_bits + 1) / 2);
set_data_frame(1, data_bit_count, parity, stop_bits);
@@ -2949,9 +2907,20 @@ void z80scc_channel::update_serial()
}
else
{
- LOG("- BRG disabled\n");
- set_rcv_rate(0);
- set_tra_rate(0);
+ if ((m_wr11 & WR11_RCVCLK_SRC_MASK) == WR11_RCVCLK_SRC_RTXC &&
+ (m_wr11 & WR11_TRACLK_SRC_MASK) == WR11_TRACLK_SRC_RTXC)
+ {
+ m_brg_rate = get_rtxc_rate();
+ LOG("- BRG disabled, clock source RTxC (rate %d, clock %d)\n", m_brg_rate, get_clock_mode());
+ set_rcv_rate(m_brg_rate);
+ set_tra_rate(m_brg_rate);
+ }
+ else
+ {
+ LOG("- BRG disabled and RX/TX clock sources differ, unimplemented: stopping\n");
+ set_rcv_rate(0);
+ set_tra_rate(0);
+ }
}
// TODO: Check registers for use of RTxC and TRxC, if used as direct Tx and/or Rx clocks set them to value as programmed
// in m_uart->txca/txcb and rxca/rxcb respectivelly
@@ -2964,7 +2933,7 @@ void z80scc_channel::update_serial()
if (m_txc > 0 && !(m_wr14 & WR14_BRG_ENABLE))
{
set_tra_rate(m_txc / clocks);
- LOG(" - Transmit clock: %d mode: %d rate: %d/%xh\n", m_rxc, clocks, m_rxc / clocks, m_rxc / clocks);
+ LOG(" - Transmit clock: %d mode: %d rate: %d/%xh\n", m_txc, clocks, m_txc / clocks, m_txc / clocks);
}
}
@@ -3003,28 +2972,36 @@ void z80scc_channel::write_rx(int state)
}
/*
- * This is a partial implementation of the "wait/dma request" functionality of the SCC controlled by
+ * This is a partial implementation of the "wait/dma request" and "dtr request" DMA functionality of the SCC controlled by
* bits D7, D6 and D5 in WR1. This implementation is sufficient to support DMA request on transmit
- * used by the InterPro driver.
+ * used by the InterPro driver and DMA request on receive by the NWS-5000X driver.
*
* TODO:
* - wait function (D6=0)
* - wait/request function on receive (D5=1)
+ * - Synchronous mode timing differences
+ * - Configuration of WREQ and DTR/REQ timing (see datasheet)
+ * - Interaction with locked fifo on error condition
*/
-void z80scc_channel::check_waitrequest()
+void z80scc_channel::check_dma_request()
{
- // don't do anything if wait/request function is not enabled
- if ((m_wr1 & WR1_WREQ_ENABLE) == 0)
- return;
-
- // wait/request function for receive not implemented
- if (m_wr1 & WR1_WREQ_ON_RX_TX)
- return;
+ if (m_wr14 & WR14_DTR_REQ_FUNC)
+ {
+ // assert /DTR//REQ if transmit buffer is empty
+ set_dtr((m_rr0 & RR0_TX_BUFFER_EMPTY) ? 0 : 1);
+ }
- // if dma request function is enabled
- if (m_wr1 & WR1_WREQ_FUNCTION)
+ if ((m_wr1 & WR1_WREQ_ENABLE) && (m_wr1 & WR1_WREQ_FUNCTION))
{
- // assert /W//REQ if transmit buffer is empty and transmitter is enabled
- m_uart->m_out_wreq_cb[m_index](((m_rr0 & RR0_TX_BUFFER_EMPTY) && (m_wr5 & WR5_TX_ENABLE)) ? 0 : 1);
+ if (m_wr1 & WR1_WREQ_ON_RX_TX)
+ {
+ // assert /W//REQ if receive buffer has a character avaliable
+ m_uart->m_out_wreq_cb[m_index]((m_rr0 & RR0_RX_CHAR_AVAILABLE) ? 0 : 1);
+ }
+ else
+ {
+ // assert /W//REQ if transmit buffer is empty and transmitter is enabled
+ m_uart->m_out_wreq_cb[m_index](((m_rr0 & RR0_TX_BUFFER_EMPTY) && (m_wr5 & WR5_TX_ENABLE)) ? 0 : 1);
+ }
}
}
diff --git a/src/devices/machine/z80scc.h b/src/devices/machine/z80scc.h
index 18d6ffffc55..7b28c4f036d 100644
--- a/src/devices/machine/z80scc.h
+++ b/src/devices/machine/z80scc.h
@@ -39,12 +39,6 @@
#include "diserial.h"
//**************************************************************************
-// DEVICE CONFIGURATION MACROS
-//**************************************************************************
-
-#define Z80SCC_USE_LOCAL_BRG 0
-
-//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@@ -61,12 +55,7 @@ class z80scc_channel : public device_t,
public:
z80scc_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
- // device_serial_interface overrides
+ // device_serial_interface implementation
virtual void tra_callback() override;
virtual void tra_complete() override;
virtual void rcv_callback() override;
@@ -129,6 +118,8 @@ public:
void txc_w(int state);
void sync_w(int state);
+ TIMER_CALLBACK_MEMBER(brg_tick);
+
int m_rxc;
int m_txc;
@@ -237,22 +228,13 @@ protected:
REG_WR15_EXT_ST_INT_CTRL= 15
};
- enum
- {
- TIMER_ID_BAUD,
- TIMER_ID_XTAL,
- TIMER_ID_RTXC,
- TIMER_ID_TRXC
- };
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
-#if Z80SCC_USE_LOCAL_BRG
- emu_timer *baudtimer;
- uint16_t m_brg_counter;
-#else
- unsigned int m_brg_rate;
-#endif
- unsigned int m_delayed_tx_brg_change;
unsigned int get_brg_rate();
+ unsigned int get_rtxc_rate();
+ void update_baudtimer();
void scc_register_write(uint8_t reg, uint8_t data);
uint8_t scc_register_read(uint8_t reg);
@@ -266,7 +248,12 @@ protected:
int get_rx_word_length();
int get_tx_word_length();
void safe_transmit_register_reset();
- void check_waitrequest();
+ void check_dma_request();
+
+ emu_timer *m_baudtimer;
+ uint16_t m_brg_counter;
+ unsigned int m_brg_rate;
+ unsigned int m_delayed_tx_brg_change;
// receiver state
uint8_t m_rx_data_fifo[8]; // receive data FIFO
@@ -311,6 +298,7 @@ protected:
// SCC specifics
int m_ph; // Point high command to access regs 08-0f
uint8_t m_zc;
+
private:
// helpers
void out_txd_cb(int state);
@@ -397,13 +385,12 @@ public:
protected:
z80scc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
- // device-level overrides
- virtual void device_resolve_objects() override;
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset_after_children() override;
virtual void device_add_mconfig(machine_config &config) override;
- // device_z80daisy_interface overrides
+ // device_z80daisy_interface implementation
virtual int z80daisy_irq_state() override;
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
diff --git a/src/devices/machine/z80sio.cpp b/src/devices/machine/z80sio.cpp
index 8f5e9a145e0..11d2f4e61d0 100644
--- a/src/devices/machine/z80sio.cpp
+++ b/src/devices/machine/z80sio.cpp
@@ -72,19 +72,18 @@
// MACROS / CONSTANTS
//**************************************************************************
-//#define LOG_GENERAL (1U << 0)
-#define LOG_SETUP (1U << 1)
-#define LOG_READ (1U << 2)
-#define LOG_INT (1U << 3)
-#define LOG_CMD (1U << 4)
-#define LOG_TX (1U << 5)
-#define LOG_RCV (1U << 6)
-#define LOG_CTS (1U << 7)
-#define LOG_DCD (1U << 8)
-#define LOG_SYNC (1U << 9)
-#define LOG_BIT (1U << 10)
-#define LOG_RTS (1U << 11)
-#define LOG_BRG (1U << 12)
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_INT (1U << 3)
+#define LOG_CMD (1U << 4)
+#define LOG_TX (1U << 5)
+#define LOG_RCV (1U << 6)
+#define LOG_CTS (1U << 7)
+#define LOG_DCD (1U << 8)
+#define LOG_SYNC (1U << 9)
+#define LOG_BIT (1U << 10)
+#define LOG_RTS (1U << 11)
+#define LOG_BRG (1U << 12)
//#define VERBOSE (LOG_CMD | LOG_SETUP | LOG_SYNC | LOG_BIT | LOG_TX )
//#define LOG_OUTPUT_STREAM std::cout
@@ -456,24 +455,6 @@ void z80sio_device::device_validity_check(validity_checker &valid) const
}
//-------------------------------------------------
-// device_resolve_objects - device-specific setup
-//-------------------------------------------------
-void z80sio_device::device_resolve_objects()
-{
- LOG("%s\n", FUNCNAME);
-
- // resolve callbacks
- m_out_txd_cb.resolve_all_safe();
- m_out_dtr_cb.resolve_all_safe();
- m_out_rts_cb.resolve_all_safe();
- m_out_wrdy_cb.resolve_all_safe();
- m_out_sync_cb.resolve_all_safe();
- m_out_int_cb.resolve_safe();
- m_out_rxdrq_cb.resolve_all_safe();
- m_out_txdrq_cb.resolve_all_safe();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void z80sio_device::device_start()
@@ -506,7 +487,7 @@ int z80sio_device::z80daisy_irq_state()
// loop over all interrupt sources
int state = 0;
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// if we're servicing a request, don't indicate more interrupts
if (m_int_state[prio[i]] & Z80_DAISY_IEO)
@@ -531,7 +512,7 @@ int z80sio_device::z80daisy_irq_ack()
// loop over all interrupt sources
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// find the first channel with an interrupt requested
if (m_int_state[prio[i]] & Z80_DAISY_INT)
@@ -597,7 +578,7 @@ int i8274_device::z80daisy_irq_ack()
{
// loop over all interrupt sources
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// find the first channel with an interrupt requested
if (m_int_state[prio[i]] & Z80_DAISY_INT)
@@ -711,7 +692,7 @@ void z80sio_device::return_from_interrupt()
{
// loop over all interrupt sources
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// find the first channel with an interrupt requested
if (m_int_state[prio[i]] & (Z80_DAISY_IEO))
@@ -741,7 +722,7 @@ uint8_t z80sio_device::read_vector()
// modify vector for highest-priority pending interrupt
int const *const prio = interrupt_priorities();
vec &= 0xf1U;
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
if (m_int_state[prio[i]] & Z80_DAISY_INT)
{
@@ -797,7 +778,7 @@ uint8_t i8274_device::read_vector()
// modify vector for highest-priority pending interrupt
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
if (m_int_state[prio[i]] & Z80_DAISY_INT)
{
@@ -1087,7 +1068,7 @@ void mk68564_channel::device_start()
{
z80sio_channel::device_start();
- m_brg_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mk68564_channel::brg_timeout), this));
+ m_brg_timer = timer_alloc(FUNC(mk68564_channel::brg_timeout), this);
save_item(NAME(m_tx_auto_enable));
save_item(NAME(m_brg_tc));
@@ -2307,7 +2288,7 @@ void z80sio_channel::queue_received(uint16_t data, uint32_t error)
//-------------------------------------------------
// cts_w - clear to send handler
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::cts_w )
+void z80sio_channel::cts_w(int state)
{
if (bool(m_cts) != bool(state))
{
@@ -2325,7 +2306,7 @@ WRITE_LINE_MEMBER( z80sio_channel::cts_w )
//-------------------------------------------------
// dcd_w - data carrier detected handler
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::dcd_w )
+void z80sio_channel::dcd_w(int state)
{
if (bool(m_dcd) != bool(state))
{
@@ -2345,7 +2326,7 @@ WRITE_LINE_MEMBER( z80sio_channel::dcd_w )
//-------------------------------------------------
// sh_w - Sync Hunt handler
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::sync_w )
+void z80sio_channel::sync_w(int state)
{
if (bool(m_sync) != bool(state))
{
@@ -2363,7 +2344,7 @@ WRITE_LINE_MEMBER( z80sio_channel::sync_w )
//-------------------------------------------------
// rxc_w - receive clock
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::rxc_w )
+void z80sio_channel::rxc_w(int state)
{
//LOG("Z80SIO \"%s\" Channel %c : Receiver Clock Pulse\n", owner()->tag(), m_index + 'A');
//if ((receive_allowed() || m_rx_bit != 0) && state && !m_rx_clock)
@@ -2488,7 +2469,7 @@ WRITE_LINE_MEMBER( z80sio_channel::rxc_w )
//-------------------------------------------------
// txc_w - transmit clock
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::txc_w )
+void z80sio_channel::txc_w(int state)
{
//LOG("Z80SIO \"%s\" Channel %c : Transmitter Clock Pulse\n", owner()->tag(), m_index + 'A');
if (!state && m_tx_clock)
diff --git a/src/devices/machine/z80sio.h b/src/devices/machine/z80sio.h
index f8fbc1522c9..3cfc04bab45 100644
--- a/src/devices/machine/z80sio.h
+++ b/src/devices/machine/z80sio.h
@@ -202,12 +202,12 @@ public:
uint8_t data_read();
void data_write(uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( write_rx ) { m_rxd = state; }
- DECLARE_WRITE_LINE_MEMBER( cts_w );
- DECLARE_WRITE_LINE_MEMBER( dcd_w );
- DECLARE_WRITE_LINE_MEMBER( rxc_w );
- DECLARE_WRITE_LINE_MEMBER( txc_w );
- DECLARE_WRITE_LINE_MEMBER( sync_w );
+ void write_rx(int state) { m_rxd = state; }
+ void cts_w(int state);
+ void dcd_w(int state);
+ void rxc_w(int state);
+ void txc_w(int state);
+ void sync_w(int state);
// Register state
// read registers enum
@@ -286,7 +286,7 @@ protected:
uint32_t clock,
uint8_t rr1_auto_reset);
- // device-level overrides
+ // device_t implementation
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
@@ -511,31 +511,30 @@ public:
// interrupt acknowledge
virtual int m1_r();
- DECLARE_WRITE_LINE_MEMBER( rxa_w ) { m_chanA->write_rx(state); }
- DECLARE_WRITE_LINE_MEMBER( rxb_w ) { m_chanB->write_rx(state); }
- DECLARE_WRITE_LINE_MEMBER( ctsa_w ) { m_chanA->cts_w(state); }
- DECLARE_WRITE_LINE_MEMBER( ctsb_w ) { m_chanB->cts_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dcda_w ) { m_chanA->dcd_w(state); }
- DECLARE_WRITE_LINE_MEMBER( dcdb_w ) { m_chanB->dcd_w(state); }
- DECLARE_WRITE_LINE_MEMBER( rxca_w ) { m_chanA->rxc_w(state); }
- DECLARE_WRITE_LINE_MEMBER( rxcb_w ) { m_chanB->rxc_w(state); }
- DECLARE_WRITE_LINE_MEMBER( txca_w ) { m_chanA->txc_w(state); }
- DECLARE_WRITE_LINE_MEMBER( txcb_w ) { m_chanB->txc_w(state); }
- DECLARE_WRITE_LINE_MEMBER( rxtxcb_w ) { m_chanB->rxc_w(state); m_chanB->txc_w(state); }
- DECLARE_WRITE_LINE_MEMBER( synca_w ) { m_chanA->sync_w(state); }
- DECLARE_WRITE_LINE_MEMBER( syncb_w ) { m_chanB->sync_w(state); }
+ void rxa_w(int state) { m_chanA->write_rx(state); }
+ void rxb_w(int state) { m_chanB->write_rx(state); }
+ void ctsa_w(int state) { m_chanA->cts_w(state); }
+ void ctsb_w(int state) { m_chanB->cts_w(state); }
+ void dcda_w(int state) { m_chanA->dcd_w(state); }
+ void dcdb_w(int state) { m_chanB->dcd_w(state); }
+ void rxca_w(int state) { m_chanA->rxc_w(state); }
+ void rxcb_w(int state) { m_chanB->rxc_w(state); }
+ void txca_w(int state) { m_chanA->txc_w(state); }
+ void txcb_w(int state) { m_chanB->txc_w(state); }
+ void rxtxcb_w(int state) { m_chanB->rxc_w(state); m_chanB->txc_w(state); }
+ void synca_w(int state) { m_chanA->sync_w(state); }
+ void syncb_w(int state) { m_chanB->sync_w(state); }
protected:
z80sio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
+ // device_t implementation
virtual void device_validity_check(validity_checker &valid) const override;
- virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
- // device_z80daisy_interface overrides
+ // device_z80daisy_interface implementation
virtual int z80daisy_irq_state() override;
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
@@ -581,8 +580,8 @@ class z80dart_device : public z80sio_device
public:
z80dart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- DECLARE_WRITE_LINE_MEMBER( ria_w ) { m_chanA->sync_w(state); }
- DECLARE_WRITE_LINE_MEMBER( rib_w ) { m_chanB->sync_w(state); }
+ void ria_w(int state) { m_chanA->sync_w(state); }
+ void rib_w(int state) { m_chanB->sync_w(state); }
protected:
// device_t overrides
@@ -599,10 +598,10 @@ public:
protected:
i8274_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device_t overrides
+ // device_t implementation
virtual void device_add_mconfig(machine_config &config) override;
- // device_z80daisy_interface overrides
+ // device_z80daisy_interface implementation
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
@@ -628,7 +627,7 @@ public:
void write(offs_t offset, uint8_t data);
protected:
- // device_t overrides
+ // device_t implementation
virtual void device_add_mconfig(machine_config &config) override;
private:
diff --git a/src/devices/machine/z80sti.cpp b/src/devices/machine/z80sti.cpp
index 22d03323aa9..e16a9b9578d 100644
--- a/src/devices/machine/z80sti.cpp
+++ b/src/devices/machine/z80sti.cpp
@@ -81,7 +81,7 @@ z80sti_device::z80sti_device(const machine_config &mconfig, const char *tag, dev
, device_serial_interface(mconfig, *this)
, device_z80daisy_interface(mconfig, *this)
, m_out_int_cb(*this)
- , m_in_gpio_cb(*this)
+ , m_in_gpio_cb(*this, 0)
, m_out_gpio_cb(*this)
, m_out_so_cb(*this)
, m_out_tao_cb(*this)
@@ -110,21 +110,11 @@ z80sti_device::z80sti_device(const machine_config &mconfig, const char *tag, dev
void z80sti_device::device_start()
{
- // resolve callbacks
- m_out_int_cb.resolve_safe();
- m_in_gpio_cb.resolve_safe(0);
- m_out_gpio_cb.resolve_safe();
- m_out_so_cb.resolve_safe();
- m_out_tao_cb.resolve_safe();
- m_out_tbo_cb.resolve_safe();
- m_out_tco_cb.resolve_safe();
- m_out_tdo_cb.resolve_safe();
-
// create the counter timers
- m_timer[TIMER_A] = timer_alloc(TIMER_A);
- m_timer[TIMER_B] = timer_alloc(TIMER_B);
- m_timer[TIMER_C] = timer_alloc(TIMER_C);
- m_timer[TIMER_D] = timer_alloc(TIMER_D);
+ m_timer[TIMER_A] = timer_alloc(FUNC(z80sti_device::timer_count), this);
+ m_timer[TIMER_B] = timer_alloc(FUNC(z80sti_device::timer_count), this);
+ m_timer[TIMER_C] = timer_alloc(FUNC(z80sti_device::timer_count), this);
+ m_timer[TIMER_D] = timer_alloc(FUNC(z80sti_device::timer_count), this);
// create serial receive clock timer
if (m_rx_clock > 0)
@@ -176,16 +166,6 @@ void z80sti_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void z80sti_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- timer_count(id);
-}
-
-
-//-------------------------------------------------
// tra_callback -
//-------------------------------------------------
@@ -618,46 +598,46 @@ void z80sti_device::write(offs_t offset, uint8_t data)
// timer_count - timer count down
//-------------------------------------------------
-void z80sti_device::timer_count(int index)
+TIMER_CALLBACK_MEMBER(z80sti_device::timer_count)
{
- if (m_tmc[index] == 0x01)
+ if (m_tmc[param] == 0x01)
{
- //LOG("Z80STI Timer %c Expired\n", 'A' + index);
+ //LOG("Z80STI Timer %c Expired\n", 'A' + param);
// toggle timer output signal
- m_to[index] = !m_to[index];
+ m_to[param] = !m_to[param];
- switch (index)
+ switch (param)
{
case TIMER_A:
- m_out_tao_cb(m_to[index]);
+ m_out_tao_cb(m_to[param]);
break;
case TIMER_B:
- m_out_tbo_cb(m_to[index]);
+ m_out_tbo_cb(m_to[param]);
break;
case TIMER_C:
- m_out_tco_cb(m_to[index]);
+ m_out_tco_cb(m_to[param]);
break;
case TIMER_D:
- m_out_tdo_cb(m_to[index]);
+ m_out_tdo_cb(m_to[param]);
break;
}
- if (m_ier & (1 << INT_LEVEL_TIMER[index]))
+ if (m_ier & (1 << INT_LEVEL_TIMER[param]))
{
- LOG("Z80STI for Timer %c\n", 'A' + index);
+ LOG("Z80STI for Timer %c\n", 'A' + param);
// signal timer elapsed interrupt
- take_interrupt(INT_LEVEL_TIMER[index]);
+ take_interrupt(INT_LEVEL_TIMER[param]);
}
// load timer main counter
- m_tmc[index] = m_tdr[index];
+ m_tmc[param] = m_tdr[param];
}
else
{
// count down
- m_tmc[index]--;
+ m_tmc[param]--;
}
}
@@ -686,21 +666,21 @@ void z80sti_device::gpip_input(int bit, int state)
m_gpip = (m_gpip & ~(1 << bit)) | (state << bit);
}
-WRITE_LINE_MEMBER( z80sti_device::i0_w ) { gpip_input(0, state); }
-WRITE_LINE_MEMBER( z80sti_device::i1_w ) { gpip_input(1, state); }
-WRITE_LINE_MEMBER( z80sti_device::i2_w ) { gpip_input(2, state); }
-WRITE_LINE_MEMBER( z80sti_device::i3_w ) { gpip_input(3, state); }
-WRITE_LINE_MEMBER( z80sti_device::i4_w ) { gpip_input(4, state); }
-WRITE_LINE_MEMBER( z80sti_device::i5_w ) { gpip_input(5, state); }
-WRITE_LINE_MEMBER( z80sti_device::i6_w ) { gpip_input(6, state); }
-WRITE_LINE_MEMBER( z80sti_device::i7_w ) { gpip_input(7, state); }
+void z80sti_device::i0_w(int state) { gpip_input(0, state); }
+void z80sti_device::i1_w(int state) { gpip_input(1, state); }
+void z80sti_device::i2_w(int state) { gpip_input(2, state); }
+void z80sti_device::i3_w(int state) { gpip_input(3, state); }
+void z80sti_device::i4_w(int state) { gpip_input(4, state); }
+void z80sti_device::i5_w(int state) { gpip_input(5, state); }
+void z80sti_device::i6_w(int state) { gpip_input(6, state); }
+void z80sti_device::i7_w(int state) { gpip_input(7, state); }
//-------------------------------------------------
// rc_w - receiver clock
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sti_device::rc_w )
+void z80sti_device::rc_w(int state)
{
rx_clock_w(state);
}
@@ -710,7 +690,7 @@ WRITE_LINE_MEMBER( z80sti_device::rc_w )
// tc_w - transmitter clock
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sti_device::tc_w )
+void z80sti_device::tc_w(int state)
{
tx_clock_w(state);
}
diff --git a/src/devices/machine/z80sti.h b/src/devices/machine/z80sti.h
index 24c23964f3d..864b3adecbe 100644
--- a/src/devices/machine/z80sti.h
+++ b/src/devices/machine/z80sti.h
@@ -67,17 +67,17 @@ public:
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- DECLARE_WRITE_LINE_MEMBER( i0_w );
- DECLARE_WRITE_LINE_MEMBER( i1_w );
- DECLARE_WRITE_LINE_MEMBER( i2_w );
- DECLARE_WRITE_LINE_MEMBER( i3_w );
- DECLARE_WRITE_LINE_MEMBER( i4_w );
- DECLARE_WRITE_LINE_MEMBER( i5_w );
- DECLARE_WRITE_LINE_MEMBER( i6_w );
- DECLARE_WRITE_LINE_MEMBER( i7_w );
-
- DECLARE_WRITE_LINE_MEMBER( tc_w );
- DECLARE_WRITE_LINE_MEMBER( rc_w );
+ void i0_w(int state);
+ void i1_w(int state);
+ void i2_w(int state);
+ void i3_w(int state);
+ void i4_w(int state);
+ void i5_w(int state);
+ void i6_w(int state);
+ void i7_w(int state);
+
+ void tc_w(int state);
+ void rc_w(int state);
private:
enum
@@ -148,7 +148,6 @@ private:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_serial_interface overrides
virtual void tra_callback() override;
@@ -163,7 +162,7 @@ private:
// internal helpers
void check_interrupts();
void take_interrupt(int level);
- void timer_count(int index);
+ TIMER_CALLBACK_MEMBER(timer_count);
void gpip_input(int bit, int state);
// device callbacks
diff --git a/src/devices/machine/z8536.cpp b/src/devices/machine/z8536.cpp
index 56f4ed60a10..cb1fa74adb6 100644
--- a/src/devices/machine/z8536.cpp
+++ b/src/devices/machine/z8536.cpp
@@ -564,7 +564,7 @@ void cio_base_device::write_register(offs_t offset, u8 data, u8 mask)
// counter_enabled - is counter enabled?
//-------------------------------------------------
-bool cio_base_device::counter_enabled(device_timer_id id)
+bool cio_base_device::counter_enabled(int id)
{
bool enabled = false;
@@ -591,7 +591,7 @@ bool cio_base_device::counter_enabled(device_timer_id id)
// counter_external_output -
//-------------------------------------------------
-bool cio_base_device::counter_external_output(device_timer_id id)
+bool cio_base_device::counter_external_output(int id)
{
return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_EOE) ? true : false;
}
@@ -601,7 +601,7 @@ bool cio_base_device::counter_external_output(device_timer_id id)
// counter_external_count -
//-------------------------------------------------
-bool cio_base_device::counter_external_count(device_timer_id id)
+bool cio_base_device::counter_external_count(int id)
{
return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_ECE) ? true : false;
}
@@ -611,7 +611,7 @@ bool cio_base_device::counter_external_count(device_timer_id id)
// counter_external_trigger -
//-------------------------------------------------
-bool cio_base_device::counter_external_trigger(device_timer_id id)
+bool cio_base_device::counter_external_trigger(int id)
{
return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_ETE) ? true : false;
}
@@ -621,7 +621,7 @@ bool cio_base_device::counter_external_trigger(device_timer_id id)
// counter_external_gate -
//-------------------------------------------------
-bool cio_base_device::counter_external_gate(device_timer_id id)
+bool cio_base_device::counter_external_gate(int id)
{
return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_EDE) ? true : false;
}
@@ -631,7 +631,7 @@ bool cio_base_device::counter_external_gate(device_timer_id id)
// counter_gated -
//-------------------------------------------------
-bool cio_base_device::counter_gated(device_timer_id id)
+bool cio_base_device::counter_gated(int id)
{
return (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_GCB) ? true : false;
}
@@ -641,7 +641,7 @@ bool cio_base_device::counter_gated(device_timer_id id)
// count - count down
//-------------------------------------------------
-void cio_base_device::count(device_timer_id id)
+void cio_base_device::count(int id)
{
if (!counter_gated(id)) return;
if (!(m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_CIP)) return;
@@ -686,7 +686,7 @@ void cio_base_device::count(device_timer_id id)
// trigger -
//-------------------------------------------------
-void cio_base_device::trigger(device_timer_id id)
+void cio_base_device::trigger(int id)
{
// ignore triggers during countdown if retrigger is disabled
if (!(m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_REB) && (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_CIP)) return;
@@ -705,7 +705,7 @@ void cio_base_device::trigger(device_timer_id id)
// gate -
//-------------------------------------------------
-void cio_base_device::gate(device_timer_id id, int state)
+void cio_base_device::gate(int id, int state)
{
// TODO
}
@@ -748,7 +748,7 @@ void cio_base_device::external_port_w(int port, int bit, int state)
case PORT_A:
case PORT_B:
{
- assert((PORT_A_DATA_DIRECTION + (port << 3)) >= 0 && (PORT_A_DATA_DIRECTION + (port << 3)) < ARRAY_LENGTH(m_register));
+ assert((PORT_A_DATA_DIRECTION + (port << 3)) >= 0 && (PORT_A_DATA_DIRECTION + (port << 3)) < std::size(m_register));
u8 ddr = m_register[PORT_A_DATA_DIRECTION + (port << 3)];
if (!BIT(ddr, bit)) return;
@@ -779,11 +779,11 @@ void cio_base_device::external_port_w(int port, int bit, int state)
cio_base_device::cio_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, type, tag, owner, clock),
m_write_irq(*this),
- m_read_pa(*this),
+ m_read_pa(*this, 0),
m_write_pa(*this),
- m_read_pb(*this),
+ m_read_pb(*this, 0),
m_write_pb(*this),
- m_read_pc(*this),
+ m_read_pc(*this, 0),
m_write_pc(*this),
m_irq(CLEAR_LINE)
{
@@ -826,18 +826,9 @@ void cio_base_device::device_start()
}
// allocate timer
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(cio_base_device::advance_counters), this);
m_timer->adjust(attotime::from_hz(clock() / 2), 0, attotime::from_hz(clock() / 2));
- // resolve callbacks
- m_write_irq.resolve_safe();
- m_read_pa.resolve_safe(0);
- m_write_pa.resolve_safe();
- m_read_pb.resolve_safe(0);
- m_write_pb.resolve_safe();
- m_read_pc.resolve_safe(0);
- m_write_pc.resolve_safe();
-
save_item(NAME(m_irq));
save_item(NAME(m_register));
save_item(NAME(m_input));
@@ -885,10 +876,10 @@ void z8536_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// advance_counters -
//-------------------------------------------------
-void cio_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(cio_base_device::advance_counters)
{
if (counter_enabled(TIMER_1) && !counter_external_count(TIMER_1))
{
@@ -919,6 +910,32 @@ void cio_base_device::device_timer(emu_timer &timer, device_timer_id id, int par
int z8536_device::z80daisy_irq_state()
{
+ static const int prio[] =
+ {
+ COUNTER_TIMER_3_COMMAND_AND_STATUS,
+ PORT_A_COMMAND_AND_STATUS,
+ COUNTER_TIMER_2_COMMAND_AND_STATUS,
+ PORT_B_COMMAND_AND_STATUS,
+ COUNTER_TIMER_1_COMMAND_AND_STATUS
+ };
+
+ if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_MIE)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ if (m_register[prio[i]] & PCS_IUS)
+ {
+ // we are currently servicing an interrupt request
+ return Z80_DAISY_IEO;
+ }
+ else if ((m_register[prio[i]] & PCS_IE) && (m_register[prio[i]] & PCS_IP))
+ {
+ // indicate that we have an interrupt request waiting
+ return Z80_DAISY_INT;
+ }
+ }
+ }
+
return 0;
}
@@ -1015,19 +1032,19 @@ u8 z8536_device::read(offs_t offset)
{
switch (offset & 0x03)
{
- case 0:
+ case EXT_PORT_C:
data = read_register(PORT_C_DATA);
break;
- case 1:
+ case EXT_PORT_B:
data = read_register(PORT_B_DATA);
break;
- case 2:
+ case EXT_PORT_A:
data = read_register(PORT_A_DATA);
break;
- case 3:
+ case EXT_CONTROL:
// state 0 or state 1: read data
data = read_register(m_pointer);
@@ -1081,19 +1098,19 @@ void z8536_device::write(offs_t offset, u8 data)
{
switch (offset & 0x03)
{
- case PORT_C:
+ case EXT_PORT_C:
write_register(PORT_C_DATA, data);
break;
- case PORT_B:
+ case EXT_PORT_B:
write_register(PORT_B_DATA, data);
break;
- case PORT_A:
+ case EXT_PORT_A:
write_register(PORT_A_DATA, data);
break;
- case CONTROL:
+ case EXT_CONTROL:
if (m_state0)
{
// state 0: write pointer
diff --git a/src/devices/machine/z8536.h b/src/devices/machine/z8536.h
index 47c6545b670..7f046ad3f49 100644
--- a/src/devices/machine/z8536.h
+++ b/src/devices/machine/z8536.h
@@ -77,28 +77,28 @@ public:
auto pc_rd_cb() { return m_read_pc.bind(); }
auto pc_wr_cb() { return m_write_pc.bind(); }
- DECLARE_WRITE_LINE_MEMBER( pa0_w ) { external_port_w(PORT_A, 0, state); }
- DECLARE_WRITE_LINE_MEMBER( pa1_w ) { external_port_w(PORT_A, 1, state); }
- DECLARE_WRITE_LINE_MEMBER( pa2_w ) { external_port_w(PORT_A, 2, state); }
- DECLARE_WRITE_LINE_MEMBER( pa3_w ) { external_port_w(PORT_A, 3, state); }
- DECLARE_WRITE_LINE_MEMBER( pa4_w ) { external_port_w(PORT_A, 4, state); }
- DECLARE_WRITE_LINE_MEMBER( pa5_w ) { external_port_w(PORT_A, 5, state); }
- DECLARE_WRITE_LINE_MEMBER( pa6_w ) { external_port_w(PORT_A, 6, state); }
- DECLARE_WRITE_LINE_MEMBER( pa7_w ) { external_port_w(PORT_A, 7, state); }
-
- DECLARE_WRITE_LINE_MEMBER( pb0_w ) { external_port_w(PORT_B, 0, state); }
- DECLARE_WRITE_LINE_MEMBER( pb1_w ) { external_port_w(PORT_B, 1, state); }
- DECLARE_WRITE_LINE_MEMBER( pb2_w ) { external_port_w(PORT_B, 2, state); }
- DECLARE_WRITE_LINE_MEMBER( pb3_w ) { external_port_w(PORT_B, 3, state); }
- DECLARE_WRITE_LINE_MEMBER( pb4_w ) { external_port_w(PORT_B, 4, state); }
- DECLARE_WRITE_LINE_MEMBER( pb5_w ) { external_port_w(PORT_B, 5, state); }
- DECLARE_WRITE_LINE_MEMBER( pb6_w ) { external_port_w(PORT_B, 6, state); }
- DECLARE_WRITE_LINE_MEMBER( pb7_w ) { external_port_w(PORT_B, 7, state); }
-
- DECLARE_WRITE_LINE_MEMBER( pc0_w ) { external_port_w(PORT_C, 0, state); }
- DECLARE_WRITE_LINE_MEMBER( pc1_w ) { external_port_w(PORT_C, 1, state); }
- DECLARE_WRITE_LINE_MEMBER( pc2_w ) { external_port_w(PORT_C, 2, state); }
- DECLARE_WRITE_LINE_MEMBER( pc3_w ) { external_port_w(PORT_C, 3, state); }
+ void pa0_w(int state) { external_port_w(PORT_A, 0, state); }
+ void pa1_w(int state) { external_port_w(PORT_A, 1, state); }
+ void pa2_w(int state) { external_port_w(PORT_A, 2, state); }
+ void pa3_w(int state) { external_port_w(PORT_A, 3, state); }
+ void pa4_w(int state) { external_port_w(PORT_A, 4, state); }
+ void pa5_w(int state) { external_port_w(PORT_A, 5, state); }
+ void pa6_w(int state) { external_port_w(PORT_A, 6, state); }
+ void pa7_w(int state) { external_port_w(PORT_A, 7, state); }
+
+ void pb0_w(int state) { external_port_w(PORT_B, 0, state); }
+ void pb1_w(int state) { external_port_w(PORT_B, 1, state); }
+ void pb2_w(int state) { external_port_w(PORT_B, 2, state); }
+ void pb3_w(int state) { external_port_w(PORT_B, 3, state); }
+ void pb4_w(int state) { external_port_w(PORT_B, 4, state); }
+ void pb5_w(int state) { external_port_w(PORT_B, 5, state); }
+ void pb6_w(int state) { external_port_w(PORT_B, 6, state); }
+ void pb7_w(int state) { external_port_w(PORT_B, 7, state); }
+
+ void pc0_w(int state) { external_port_w(PORT_C, 0, state); }
+ void pc1_w(int state) { external_port_w(PORT_C, 1, state); }
+ void pc2_w(int state) { external_port_w(PORT_C, 2, state); }
+ void pc3_w(int state) { external_port_w(PORT_C, 3, state); }
int intack_r();
@@ -109,11 +109,12 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ TIMER_CALLBACK_MEMBER(advance_counters);
bool is_reset() const { return (m_register[MASTER_INTERRUPT_CONTROL] & MICR_RESET) != 0; }
- enum
+ enum : int
{
TIMER_1 = 0,
TIMER_2,
@@ -121,7 +122,7 @@ protected:
};
// ports
- enum
+ enum : int
{
PORT_A = 0,
PORT_B,
@@ -369,19 +370,18 @@ protected:
void write_register(offs_t offset, u8 data);
void write_register(offs_t offset, u8 data, u8 mask);
- bool counter_enabled(device_timer_id id);
- bool counter_external_output(device_timer_id id);
- bool counter_external_count(device_timer_id id);
- bool counter_external_trigger(device_timer_id id);
- bool counter_external_gate(device_timer_id id);
- bool counter_gated(device_timer_id id);
- void count(device_timer_id id);
- void trigger(device_timer_id id);
- void gate(device_timer_id id, int state);
+ bool counter_enabled(int id);
+ bool counter_external_output(int id);
+ bool counter_external_count(int id);
+ bool counter_external_trigger(int id);
+ bool counter_external_gate(int id);
+ bool counter_gated(int id);
+ void count(int id);
+ void trigger(int id);
+ void gate(int id, int state);
void match_pattern(int port);
void external_port_w(int port, int bit, int state);
-private:
devcb_write_line m_write_irq;
devcb_read8 m_read_pa;
@@ -444,6 +444,15 @@ protected:
virtual void z80daisy_irq_reti() override;
private:
+ // direct external access to ports
+ enum
+ {
+ EXT_PORT_C = 0,
+ EXT_PORT_B,
+ EXT_PORT_A,
+ EXT_CONTROL
+ };
+
// control state machine
bool m_state0;
u8 m_pointer;
diff --git a/src/devices/machine/zfmicro_usb.cpp b/src/devices/machine/zfmicro_usb.cpp
new file mode 100644
index 00000000000..13365987366
--- /dev/null
+++ b/src/devices/machine/zfmicro_usb.cpp
@@ -0,0 +1,100 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+ ZFMicro USB Host controller
+
+ TODO:
+ - Stub interface, to be merged with pci-usb;
+ - PCI values omitted from docs, assumes same as OpenHCI;
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "zfmicro_usb.h"
+
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_warning
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(ZFMICRO_USB, zfmicro_usb_device, "zfmicro_usb", "ZFMicro PCIUSB Host Controller")
+
+zfmicro_usb_device::zfmicro_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pci_device(mconfig, ZFMICRO_USB, tag, owner, clock)
+{
+ // Compaq vendor
+ set_ids(0x0e11a0f8, 0x00, 0x0c0310, 0x00);
+ // TODO: should really read from a std::list interface
+ m_downstream_ports = 2;
+}
+
+void zfmicro_usb_device::config_map(address_map &map)
+{
+ pci_device::config_map(map);
+// map(0x40, 0x43) ASIC Test Mode Enable
+// map(0x44, 0x44) ASIC Operational Mode Enable
+// ---- ---x Data Buffer Region 16
+// ---- ---1 16 bytes data buffer
+// ---- ---0 32 bytes
+}
+
+void zfmicro_usb_device::map(address_map &map)
+{
+ // HcRevision: operational mode
+ // 1 ---- ---- Legacy PS/2 present
+ // - 0001 0000 OpenHCI v1.0
+ map(0x000, 0x003).lr32(NAME([]() { return 0x00000110; }));
+ // ...
+ // HcFmInterval (Windows OSes fails if this isn't r/w)
+ map(0x034, 0x037).lrw32(
+ NAME([this]() { return m_HcFmInterval; } ),
+ NAME([this](offs_t offset, u32 data, u32 mem_mask) {
+ COMBINE_DATA(&m_HcFmInterval);
+ LOG("Write HcFmInterval %08x & %08x\n", data, mem_mask);
+ })
+ );
+ // ...
+ // HcRhDescriptorA
+ // 0000 0001 ---- ---- ---- ---- ---- ---- POTPGT (unknown for this, assume 2 ms)
+ // ---- ---- xxxx xxxx xxxx x-xx ---- ---- (writeable bits by host controller driver)
+ // ---- ---- ---- ---- ---- -0-- ---- ---- DT DeviceType (0) not a compound device
+ // ---- ---- ---- ---- ---- ---- xxxx xxxx NDP NumberDownstreamPorts (15 max)
+ map(0x048, 0x04b).lr32(NAME([this]() { return 0x01000000 | m_downstream_ports; }));
+ // ...
+
+ // legacy support mode (8-bit each)
+// map(0x100, 0x100) HceControl, bit 0 enables emulation mode
+// map(0x104, 0x104) HceInput
+// map(0x108, 0x108) HceOutput
+// map(0x10c, 0x10f) HceStatus
+}
+
+void zfmicro_usb_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
+{
+ // TODO: overrides I/O ports $0060-$0064 (emulation mode)
+}
+
+void zfmicro_usb_device::device_start()
+{
+ pci_device::device_start();
+
+ add_map(4096, M_MEM, FUNC(zfmicro_usb_device::map));
+
+ // INTA#
+ intr_pin = 1;
+}
+
+
+void zfmicro_usb_device::device_reset()
+{
+ pci_device::device_reset();
+
+ command = 0x0000;
+ // DEVSEL# medium timing
+ // Fast Back-to-Back Capable
+ status = 0x0280;
+ // unverified default, assume same as OpenHCI specs
+ m_HcFmInterval = 0x2edf;
+}
diff --git a/src/devices/machine/zfmicro_usb.h b/src/devices/machine/zfmicro_usb.h
new file mode 100644
index 00000000000..34d18892c32
--- /dev/null
+++ b/src/devices/machine/zfmicro_usb.h
@@ -0,0 +1,39 @@
+// license: BSD-3-Clause
+// copyright-holders: Angelo Salese
+
+#ifndef MAME_MACHINE_ZFMICRO_USB_H
+#define MAME_MACHINE_ZFMICRO_USB_H
+
+#pragma once
+
+#include "pci.h"
+
+class zfmicro_usb_device : public pci_device
+{
+public:
+ zfmicro_usb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ static constexpr feature_type unemulated_features() { return feature::MEDIA; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+// virtual void device_add_mconfig(machine_config &config) override;
+
+// virtual void reset_all_mappings() override;
+
+ virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
+ uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
+
+ virtual void config_map(address_map &map) override;
+
+ void map(address_map &map);
+
+private:
+ u8 m_downstream_ports;
+ u32 m_HcFmInterval = 0;
+};
+
+DECLARE_DEVICE_TYPE(ZFMICRO_USB, zfmicro_usb_device)
+
+#endif