From c51c443be11b4069b36c80dccd4960808d649227 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Thu, 30 Jun 2022 00:37:49 +1000 Subject: -Added support for directory names in SOURCES= -Retired the messshared project (combined with shared). -bus/nubus: Added table of video modes for Mac monitor sense values. --- scripts/build/makedep.py | 29 +- scripts/genie.lua | 5 +- scripts/target/mame/mame.lua | 8 - src/devices/bus/nubus/nubus_48gc.cpp | 35 +- src/mame/dooyong/dooyong.cpp | 2 +- src/mame/dooyong/dooyong_tilemap.cpp | 265 +++++ src/mame/dooyong/dooyong_tilemap.h | 156 +++ src/mame/dooyong/dooyong_v.cpp | 265 ----- src/mame/dooyong/dooyong_v.h | 156 --- src/mame/messshared/isbc_215g.cpp | 435 -------- src/mame/messshared/isbc_215g.h | 89 -- src/mame/messshared/mega32x.cpp | 1862 ---------------------------------- src/mame/messshared/mega32x.h | 242 ----- src/mame/messshared/megacdcd.cpp | 1409 ------------------------- src/mame/messshared/megacdcd.h | 197 ---- src/mame/messshared/mitcrt.cpp | 181 ---- src/mame/messshared/mitcrt.h | 76 -- src/mame/messshared/ms7004.cpp | 476 --------- src/mame/messshared/ms7004.h | 64 -- src/mame/messshared/teleprinter.cpp | 237 ----- src/mame/messshared/teleprinter.h | 42 - src/mame/messshared/vboysound.cpp | 501 --------- src/mame/messshared/vboysound.h | 92 -- src/mame/messshared/vt100_kbd.cpp | 541 ---------- src/mame/messshared/vt100_kbd.h | 97 -- src/mame/messshared/wswansound.cpp | 387 ------- src/mame/messshared/wswansound.h | 86 -- src/mame/messshared/z80bin.cpp | 78 -- src/mame/messshared/z80bin.h | 18 - src/mame/shared/isbc_215g.cpp | 435 ++++++++ src/mame/shared/isbc_215g.h | 89 ++ src/mame/shared/mega32x.cpp | 1862 ++++++++++++++++++++++++++++++++++ src/mame/shared/mega32x.h | 242 +++++ src/mame/shared/megacdcd.cpp | 1409 +++++++++++++++++++++++++ src/mame/shared/megacdcd.h | 197 ++++ src/mame/shared/mitcrt.cpp | 181 ++++ src/mame/shared/mitcrt.h | 76 ++ src/mame/shared/ms7004.cpp | 476 +++++++++ src/mame/shared/ms7004.h | 64 ++ src/mame/shared/teleprinter.cpp | 237 +++++ src/mame/shared/teleprinter.h | 42 + src/mame/shared/vboysound.cpp | 501 +++++++++ src/mame/shared/vboysound.h | 92 ++ src/mame/shared/vt100_kbd.cpp | 541 ++++++++++ src/mame/shared/vt100_kbd.h | 97 ++ src/mame/shared/wswansound.cpp | 387 +++++++ src/mame/shared/wswansound.h | 86 ++ src/mame/shared/z80bin.cpp | 78 ++ src/mame/shared/z80bin.h | 18 + 49 files changed, 7575 insertions(+), 7566 deletions(-) create mode 100644 src/mame/dooyong/dooyong_tilemap.cpp create mode 100644 src/mame/dooyong/dooyong_tilemap.h delete mode 100644 src/mame/dooyong/dooyong_v.cpp delete mode 100644 src/mame/dooyong/dooyong_v.h delete mode 100644 src/mame/messshared/isbc_215g.cpp delete mode 100644 src/mame/messshared/isbc_215g.h delete mode 100644 src/mame/messshared/mega32x.cpp delete mode 100644 src/mame/messshared/mega32x.h delete mode 100644 src/mame/messshared/megacdcd.cpp delete mode 100644 src/mame/messshared/megacdcd.h delete mode 100644 src/mame/messshared/mitcrt.cpp delete mode 100644 src/mame/messshared/mitcrt.h delete mode 100644 src/mame/messshared/ms7004.cpp delete mode 100644 src/mame/messshared/ms7004.h delete mode 100644 src/mame/messshared/teleprinter.cpp delete mode 100644 src/mame/messshared/teleprinter.h delete mode 100644 src/mame/messshared/vboysound.cpp delete mode 100644 src/mame/messshared/vboysound.h delete mode 100644 src/mame/messshared/vt100_kbd.cpp delete mode 100644 src/mame/messshared/vt100_kbd.h delete mode 100644 src/mame/messshared/wswansound.cpp delete mode 100644 src/mame/messshared/wswansound.h delete mode 100644 src/mame/messshared/z80bin.cpp delete mode 100644 src/mame/messshared/z80bin.h create mode 100644 src/mame/shared/isbc_215g.cpp create mode 100644 src/mame/shared/isbc_215g.h create mode 100644 src/mame/shared/mega32x.cpp create mode 100644 src/mame/shared/mega32x.h create mode 100644 src/mame/shared/megacdcd.cpp create mode 100644 src/mame/shared/megacdcd.h create mode 100644 src/mame/shared/mitcrt.cpp create mode 100644 src/mame/shared/mitcrt.h create mode 100644 src/mame/shared/ms7004.cpp create mode 100644 src/mame/shared/ms7004.h create mode 100644 src/mame/shared/teleprinter.cpp create mode 100644 src/mame/shared/teleprinter.h create mode 100644 src/mame/shared/vboysound.cpp create mode 100644 src/mame/shared/vboysound.h create mode 100644 src/mame/shared/vt100_kbd.cpp create mode 100644 src/mame/shared/vt100_kbd.h create mode 100644 src/mame/shared/wswansound.cpp create mode 100644 src/mame/shared/wswansound.h create mode 100644 src/mame/shared/z80bin.cpp create mode 100644 src/mame/shared/z80bin.h diff --git a/scripts/build/makedep.py b/scripts/build/makedep.py index 18da0a2981e..07406423ff2 100755 --- a/scripts/build/makedep.py +++ b/scripts/build/makedep.py @@ -722,7 +722,7 @@ def scan_source_dependencies(root, sources): parser = CppParser(handler) seen = set('/'.join(x for x in split_path(source) if x) for source in sources) remaining = list([(x, 0) for x in seen]) - default_roots = ((('src', 'devices'), 0), (('src', 'mame', 'shared'), 0), (('src', 'mame', 'messshared'), 0), (('src', 'lib'), 0)) + default_roots = ((('src', 'devices'), 0), (('src', 'mame', 'shared'), 0), (('src', 'lib'), 0)) while remaining: source, depth = remaining.pop() components = tuple(source.split('/')) @@ -768,7 +768,6 @@ def write_project(options, projectfile, mappings, sources, single): ' MAME_DIR .. "src/emu",\n' \ ' MAME_DIR .. "src/devices",\n' \ ' MAME_DIR .. "src/mame/shared",\n' \ - ' MAME_DIR .. "src/mame/messshared",\n' \ ' MAME_DIR .. "src/lib",\n' \ ' MAME_DIR .. "src/lib/util",\n' \ ' MAME_DIR .. "src/lib/netlist",\n' \ @@ -821,7 +820,6 @@ def write_project(options, projectfile, mappings, sources, single): ' MAME_DIR .. "src/emu",\n' \ ' MAME_DIR .. "src/devices",\n' \ ' MAME_DIR .. "src/mame/shared",\n' \ - ' MAME_DIR .. "src/mame/messshared",\n' \ ' MAME_DIR .. "src/lib",\n' \ ' MAME_DIR .. "src/lib/util",\n' \ ' MAME_DIR .. "src/lib/netlist",\n' \ @@ -839,12 +837,10 @@ def write_project(options, projectfile, mappings, sources, single): 'function linkProjects_mame_%s(_target, _subtarget)\n' \ ' links {\n' % (options.target, )) for lib in libnames: - if (lib != 'shared') and (lib != 'messshared'): + if lib != 'shared': projectfile.write(' "%s",\n' % (lib, )) if 'shared' in libraries: projectfile.write(' "shared",\n') - if 'messshared' in libraries: - projectfile.write(' "messshared",\n') projectfile.write( ' }\n' \ 'end\n' \ @@ -861,12 +857,29 @@ def write_project(options, projectfile, mappings, sources, single): projectfile.write('end\n') +def collect_sources(root, sources): + result = [ ] + for source in sources: + fullpath = os.path.join(root, source) + if os.path.isdir(fullpath): + for subdir, dirs, files in os.walk(fullpath): + for candidate in files: + if os.path.splitext(candidate)[1] == '.cpp': + if subdir != fullpath: + result.append(os.path.join(source, os.path.relpath(subdir, fullpath), candidate)) + else: + result.append(os.path.join(source, candidate)) + else: + result.append(source) + return result + + def write_filter(options, filterfile): sources = set() DriverFilter().parse_list(options.list, lambda n: sources.add(n), lambda n: None) drivers = set() - for source in options.sources: + for source in collect_sources(options.root, options.sources): components = tuple(x for x in split_path(source) if x) if (len(components) > 3) and (components[:2] == ('src', 'mame')): ext = os.path.splitext(components[-1])[1].lower() @@ -881,7 +894,7 @@ if __name__ == '__main__': options = parse_command_line() if options.command == 'sourcesproject': header_to_optional = collect_lua_directives(options) - source_dependencies = scan_source_dependencies(options.root, options.sources) + source_dependencies = scan_source_dependencies(options.root, collect_sources(options.root, options.sources)) write_project(options, sys.stdout, header_to_optional, source_dependencies, True) elif options.command == 'filterproject': header_to_optional = collect_lua_directives(options) diff --git a/scripts/genie.lua b/scripts/genie.lua index 6a3eca5014e..cef42ece7cb 100644 --- a/scripts/genie.lua +++ b/scripts/genie.lua @@ -1434,8 +1434,9 @@ if _OPTIONS["SOURCES"] ~= nil then local str = _OPTIONS["SOURCES"] local sourceargs = "" for word in string.gmatch(str, '([^,]+)') do - if not os.isfile(path.join(MAME_DIR, word)) then - error("File " .. word .. " does not exist") + local fullpath = path.join(MAME_DIR, word) + if (not os.isfile(fullpath)) and (not os.isdir(fullpath)) then + error("File/directory " .. word .. " does not exist") end sourceargs = sourceargs .. " " .. word end diff --git a/scripts/target/mame/mame.lua b/scripts/target/mame/mame.lua index c92e9c651ed..2a47c1ac1d4 100644 --- a/scripts/target/mame/mame.lua +++ b/scripts/target/mame/mame.lua @@ -1603,7 +1603,6 @@ function linkProjects_mame_mame(_target, _subtarget) "zpa", "zvt", "shared", -- must stay near the end - "messshared", -- must stay near the end } end @@ -1621,7 +1620,6 @@ function createMAMEProjects(_target, _subtarget, _name) MAME_DIR .. "src/emu", MAME_DIR .. "src/devices", MAME_DIR .. "src/mame/shared", - MAME_DIR .. "src/mame/messshared", MAME_DIR .. "src/lib", MAME_DIR .. "src/lib/util", MAME_DIR .. "3rdparty", @@ -1653,12 +1651,6 @@ files { MAME_DIR .. "src/mame/shared/*.cpp", } -createMAMEProjects(_target, _subtarget, "messshared") -files { - MAME_DIR .. "src/mame/messshared/*.h", - MAME_DIR .. "src/mame/messshared/*.cpp", -} - -------------------------------------------------- -- manufacturer-specific groupings for drivers -------------------------------------------------- diff --git a/src/devices/bus/nubus/nubus_48gc.cpp b/src/devices/bus/nubus/nubus_48gc.cpp index b12ff7fc196..9ab169ca73d 100644 --- a/src/devices/bus/nubus/nubus_48gc.cpp +++ b/src/devices/bus/nubus/nubus_48gc.cpp @@ -203,22 +203,25 @@ ROM_END // TODO: find a better place for this table to live struct mac_monitor_info { bool mono; unsigned sense[4]; }; mac_monitor_info const f_monitors[] = { - { false, { 0, 0, 0, 0 } }, // 0: RGB 21" - { true, { 1, 1, 1, 0 } }, // 1: Full-Page (B&W 15") - { false, { 2, 2, 0, 2 } }, // 2: RGB 12" - { true, { 3, 3, 1, 2 } }, // 3: Two-Page (B&W 21") - { false, { 4, 0, 4, 4 } }, // 4: NTSC Monitor - { false, { 5, 1, 5, 4 } }, // 5: RGB 15" - { false, { 6, 2, 4, 6 } }, // 6: Hi-Res (12-14") - { false, { 6, 0, 0, 6 } }, // 7: Multiple Scan 14" - { false, { 6, 0, 4, 6 } }, // 8: Multiple Scan 16" - { false, { 6, 2, 0, 6 } }, // 9: Multiple Scan 21" - { false, { 7, 0, 0, 0 } }, // 10: PAL Encoder - { false, { 7, 1, 1, 0 } }, // 11: NTSC Encoder - { false, { 7, 1, 1, 6 } }, // 12: VGA/Super VGA - { false, { 7, 2, 5, 2 } }, // 13: RGB 16" - { false, { 7, 3, 0, 0 } }, // 14: PAL Monitor - { false, { 7, 3, 4, 4 } } }; // 15: RGB 19" + // 512×385 640×480 640×870 832×624 1024×768 1152×870 + // 60.15 Hz 66.67 Hz 75.08 Hz 74.55 Hz 74.93 Hz 75.08 Hz 59.94 Hz 55.98 Hz 59.94 Hz 50.00 Hz + // portrait interlaced interlaced + { false, { 0, 0, 0, 0 } }, // 0: RGB 21" yes + { true, { 1, 1, 1, 0 } }, // 1: Full-Page (B&W 15") yes + { false, { 2, 2, 0, 2 } }, // 2: RGB 12" yes + { true, { 3, 3, 1, 2 } }, // 3: Two-Page (B&W 21") yes + { false, { 4, 0, 4, 4 } }, // 4: NTSC Monitor yes + { false, { 5, 1, 5, 4 } }, // 5: RGB 15" yes + { false, { 6, 2, 4, 6 } }, // 6: Hi-Res (12-14") yes + { false, { 6, 0, 0, 6 } }, // 7: Multiple Scan 14" yes yes + { false, { 6, 0, 4, 6 } }, // 8: Multiple Scan 16" yes yes yes yes + { false, { 6, 2, 0, 6 } }, // 9: Multiple Scan 21" yes yes yes yes + { false, { 7, 0, 0, 0 } }, // 10: PAL Encoder yes + { false, { 7, 1, 1, 0 } }, // 11: NTSC Encoder yes + { false, { 7, 1, 1, 6 } }, // 12: VGA/Super VGA yes yes + { false, { 7, 2, 5, 2 } }, // 13: RGB 16" yes + { false, { 7, 3, 0, 0 } }, // 14: PAL Monitor yes + { false, { 7, 3, 4, 4 } } }; // 15: RGB 19" yes //------------------------------------------------- diff --git a/src/mame/dooyong/dooyong.cpp b/src/mame/dooyong/dooyong.cpp index f6446b78ace..3f5570ebdf1 100644 --- a/src/mame/dooyong/dooyong.cpp +++ b/src/mame/dooyong/dooyong.cpp @@ -75,7 +75,7 @@ are almost identical, except for much darker BG layer colors). ***************************************************************************/ #include "emu.h" -#include "dooyong_v.h" +#include "dooyong_tilemap.h" #include "cpu/m68000/m68000.h" #include "cpu/z80/z80.h" diff --git a/src/mame/dooyong/dooyong_tilemap.cpp b/src/mame/dooyong/dooyong_tilemap.cpp new file mode 100644 index 00000000000..309c2b76983 --- /dev/null +++ b/src/mame/dooyong/dooyong_tilemap.cpp @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +#include "emu.h" +#include "dooyong_tilemap.h" + +#include "screen.h" + + +/* These games all have ROM-based tilemaps for the backgrounds, title + screens and sometimes "bosses" and special attacks. There are three + schemes for tilemap encoding. The scheme is chosen based on the + contents of the tilemap control variables. + Note that although the tilemaps are arbitrarily wide (hundreds of + thousands of pixels, depending on the size of the ROM), we only + decode a 1024 pixel wide block at a time, and invalidate the tilemap + when the X scroll moves out of range (trying to decode the whole lot + at once uses hundreds of megabytes of RAM). */ + +DEFINE_DEVICE_TYPE(DOOYONG_ROM_TILEMAP, dooyong_rom_tilemap_device, "dooyong_rom_tilemap", "Dooyong ROM Tilemap") +DEFINE_DEVICE_TYPE(RSHARK_ROM_TILEMAP, rshark_rom_tilemap_device, "rshark_rom_tilemap", "R-Shark ROM Tilemap") +DEFINE_DEVICE_TYPE(DOOYONG_RAM_TILEMAP, dooyong_ram_tilemap_device, "dooyong_ram_tilemap", "Dooyong RAM Tilemap") + + +dooyong_tilemap_device_base::dooyong_tilemap_device_base( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , m_gfxdecode(*this, finder_base::DUMMY_TAG) + , m_gfxnum(0) + , m_tilemap(nullptr) + , m_palette_bank(0) +{ +} + +void dooyong_tilemap_device_base::draw(screen_device &screen, bitmap_ind16 &dest, rectangle const &cliprect, u32 flags, u8 priority, u8 priority_mask) +{ + m_tilemap->draw(screen, dest, cliprect, flags, priority, priority_mask); +} + +void dooyong_tilemap_device_base::set_palette_bank(u16 bank) +{ + if (bank != m_palette_bank) + { + m_palette_bank = bank; + m_tilemap->mark_all_dirty(); + } +} + +dooyong_rom_tilemap_device::dooyong_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : dooyong_rom_tilemap_device(mconfig, DOOYONG_ROM_TILEMAP, tag, owner, clock) +{ +} + +dooyong_rom_tilemap_device::dooyong_rom_tilemap_device( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + u32 clock) + : dooyong_tilemap_device_base(mconfig, type, tag, owner, clock) + , m_rows(8) + , m_tilerom(*this, finder_base::DUMMY_TAG) + , m_tmap_cb(*this) + , m_tilerom_offset(0) + , m_tilerom_length(~0U) + , m_transparent_pen(~0U) + , m_registers{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +{ +} + +void dooyong_rom_tilemap_device::ctrl_w(offs_t offset, u8 data) +{ + offset &= 0x07U; + const u8 old = m_registers[offset]; + if (old != data) + { + m_registers[offset] = data; + switch (offset) + { + case 0: // Low byte of X scroll - scroll tilemap + m_tilemap->set_scrollx(0, data); + break; + case 1: // High byte of X scroll - mark tilemap dirty so new tile gfx will be loaded + m_tilemap->mark_all_dirty(); + break; + case 3: // Low byte of Y scroll + case 4: // High byte of Y scroll + m_tilemap->set_scrolly(0, m_registers[3] | (unsigned(m_registers[4]) << 8)); + break; + case 6: // Tilemap enable and mode control + m_tilemap->enable(!BIT(data, 4)); + if (BIT(data ^ old, 5)) // This sets the tilemap data format + m_tilemap->mark_all_dirty(); + break; + default: // Other addresses are used but function is unknown + // 0x05 and 0x07 are initialised on startup + // 0x02 is initialised on startup by some games and written to continuously by others + // printf("Unknown %s tilemap control: 0x%02x = 0x%02x\n", tag(), unsigned(offset), unsigned(data)); + break; + } + } +} + +void dooyong_rom_tilemap_device::device_start() +{ + if (!m_gfxdecode->started()) + throw device_missing_dependencies(); + + m_tmap_cb.resolve(); + + m_tilemap = &machine().tilemap().create( + *m_gfxdecode, + tilemap_get_info_delegate(*this, FUNC(dooyong_rom_tilemap_device::tile_info)), + TILEMAP_SCAN_COLS, + gfx().width(), + gfx().height(), + 1024 / gfx().width(), + m_rows); + if (~m_transparent_pen) + m_tilemap->set_transparent_pen(m_transparent_pen); + + if (0 > m_tilerom_offset) + m_tilerom_offset = m_tilerom.length() + m_tilerom_offset; + + if (m_tilerom_length < 0) + m_tilerom_length = m_tilerom.length(); + + std::fill(std::begin(m_registers), std::end(m_registers), 0U); + m_palette_bank = 0U; + + save_item(NAME(m_registers)); + save_item(NAME(m_palette_bank)); +} + +TILE_GET_INFO_MEMBER(dooyong_rom_tilemap_device::tile_info) +{ + const int tile_index_tile = adjust_tile_index(tile_index) & (m_tilerom_length - 1); + const u16 attr = m_tilerom[m_tilerom_offset + tile_index_tile]; + u32 code = 0, color = 0, flags; + if (BIT(m_registers[6], 5)) + { // lastday/gulfstrm/pollux/flytiger + // Tiles take one word in ROM: + // MSB LSB + // cCCC CYXc cccc cccc (bit 9 of gfx code, bits 3-0 of color, Y flip, X flip, bits 8-0 of gfx code) + // c = gfx code + // C = color code + // X = x flip + // Y = y flip + code = (BIT(attr, 15) << 9) | (attr & 0x01ff); + color = BIT(attr, 11, 4); + flags = TILE_FLIPYX(BIT(attr, 9, 2)); + } + else + { // bluehawk/primella/popbingo + // Tiles take one word in ROM: + // MSB LSB + // bluehawk YXCC CCcc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 9-0 of gfx code) + // primella YXCC CCcc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 9-0 of gfx code) + // popbingo YX?? ?ccc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 10-0 of gfx code) + // rshark YX?c cccc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 12-0 of gfx code) + // c = gfx code + // C = color code + // X = x flip + // Y = y flip + // ? = unused? + if (!m_tmap_cb.isnull()) + m_tmap_cb(attr & 0x3fff, code, color); + else // just mimic old driver behavior (default configuration) + { + code = attr & 0x3ff; + color = BIT(attr, 10, 4); + } + + flags = TILE_FLIPYX(BIT(attr, 14, 2)); + } + color |= m_palette_bank; + + tileinfo.set(m_gfxnum, code, color, flags); +} + + +rshark_rom_tilemap_device::rshark_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : dooyong_rom_tilemap_device(mconfig, RSHARK_ROM_TILEMAP, tag, owner, clock) + , m_colorrom(*this, finder_base::DUMMY_TAG) + , m_colorrom_offset(0) + , m_colorrom_length(0) +{ + m_rows = 32; +} + +void rshark_rom_tilemap_device::device_start() +{ + dooyong_rom_tilemap_device::device_start(); + + if (0 > m_colorrom_offset) + m_colorrom_offset = m_colorrom.length() + m_colorrom_offset; + + if (m_colorrom_length < 0) + m_colorrom_length = m_colorrom.length(); +} + +TILE_GET_INFO_MEMBER(rshark_rom_tilemap_device::tile_info) +{ + dooyong_rom_tilemap_device::tile_info(tilemap, tileinfo, tile_index); + + const int tile_index_color = adjust_tile_index(tile_index) & (m_colorrom_length - 1); + const u16 color = m_palette_bank | (m_colorrom[m_colorrom_offset + tile_index_color] & 0x0fU); + tileinfo.palette_base = gfx().colorbase() + (gfx().granularity() * (color % gfx().colors())); +} + + +dooyong_ram_tilemap_device::dooyong_ram_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : dooyong_tilemap_device_base(mconfig, DOOYONG_RAM_TILEMAP, tag, owner, clock) + , m_tileram() +{ +} + +void dooyong_ram_tilemap_device::tileram_w(offs_t offset, u16 data, u16 mem_mask) +{ + offset &= (64U * 32U) - 1U; + u16 value(m_tileram[offset]); + COMBINE_DATA(&value); + if (value != m_tileram[offset]) + { + m_tileram[offset] = value; + m_tilemap->mark_tile_dirty(offset); + } +} + +void dooyong_ram_tilemap_device::device_start() +{ + if (!m_gfxdecode->started()) + throw device_missing_dependencies(); + + m_tilemap = &machine().tilemap().create( + *m_gfxdecode, + tilemap_get_info_delegate(*this, FUNC(dooyong_ram_tilemap_device::tile_info)), + TILEMAP_SCAN_COLS, + 8, + 8, + 64, + 32); + m_tilemap->set_transparent_pen(15); + + m_tileram.reset(new u16[64 * 32]); + std::fill(m_tileram.get(), m_tileram.get() + (64 * 32), 0U); + m_palette_bank = 0U; + + save_pointer(NAME(m_tileram), 64 * 32); + save_item(NAME(m_palette_bank)); +} + +TILE_GET_INFO_MEMBER(dooyong_ram_tilemap_device::tile_info) +{ + // Each tile takes one word of memory: + // MSB LSB + // CCCC cccc cccc cccc (bits 3-0 of color code, bits 11-0 of gfx code) + // c = gfx code + // C = color code + const u16 attr(m_tileram[tile_index]); + tileinfo.set(m_gfxnum, attr & 0x0fffU, m_palette_bank | BIT(attr, 12, 4), 0); +} diff --git a/src/mame/dooyong/dooyong_tilemap.h b/src/mame/dooyong/dooyong_tilemap.h new file mode 100644 index 00000000000..2ee165fba1f --- /dev/null +++ b/src/mame/dooyong/dooyong_tilemap.h @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +#ifndef MAME_DOOYONG_DOOYONG_TILEMAP_H +#define MAME_DOOYONG_DOOYONG_TILEMAP_H + +#pragma once + +#include "video/bufsprite.h" +#include "tilemap.h" + +DECLARE_DEVICE_TYPE(DOOYONG_ROM_TILEMAP, dooyong_rom_tilemap_device) +DECLARE_DEVICE_TYPE(RSHARK_ROM_TILEMAP, rshark_rom_tilemap_device) +DECLARE_DEVICE_TYPE(DOOYONG_RAM_TILEMAP, dooyong_ram_tilemap_device) + + +class dooyong_tilemap_device_base : public device_t +{ +public: + template void set_gfxdecode_tag(T &&gfxdecode_tag) { m_gfxdecode.set_tag(std::forward(gfxdecode_tag)); } + void set_gfxnum(int gfxnum) { m_gfxnum = gfxnum; } + + void draw(screen_device &screen, bitmap_ind16 &dest, rectangle const &cliprect, u32 flags, u8 priority, u8 priority_mask = 0xff); + + void set_palette_bank(u16 bank); + +protected: + dooyong_tilemap_device_base( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + u32 clock); + + gfx_element const &gfx() const { return *m_gfxdecode->gfx(m_gfxnum); } + + required_device m_gfxdecode; + int m_gfxnum; + + tilemap_t *m_tilemap; + u16 m_palette_bank; +}; + +class dooyong_rom_tilemap_device : public dooyong_tilemap_device_base +{ +public: + template + dooyong_rom_tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxdecode_tag, int gfxnum, U &&tilerom_tag, int tilerom_offset, int tilerom_length) + : dooyong_rom_tilemap_device(mconfig, tag, owner, 0) + { + set_gfxdecode_tag(std::forward(gfxdecode_tag)); + set_gfxnum(gfxnum); + set_tilerom_tag(std::forward(tilerom_tag)); + set_tilerom_offset(tilerom_offset); + set_tilerom_length(tilerom_length); + } + + dooyong_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + template void set_tilerom_tag(U &&tilerom_tag) { m_tilerom.set_tag(std::forward(tilerom_tag)); } + void set_tilerom_offset(int offset) { m_tilerom_offset = offset; } + void set_tilerom_length(int length) { m_tilerom_length = length; } + void set_transparent_pen(unsigned pen) { m_transparent_pen = pen; } + + typedef device_delegate dooyong_tmap_cb_delegate; + template void set_tile_callback(T &&... args) { m_tmap_cb.set(std::forward(args)...); } + + void ctrl_w(offs_t offset, u8 data); + +protected: + dooyong_rom_tilemap_device( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + u32 clock); + + virtual void device_start() override; + + virtual TILE_GET_INFO_MEMBER(tile_info); + + tilemap_memory_index adjust_tile_index(tilemap_memory_index tile_index) const + { return tile_index + ((unsigned(m_registers[1]) * 256U / gfx().width()) * m_rows); } + + int m_rows; + +private: + required_region_ptr m_tilerom; + dooyong_tmap_cb_delegate m_tmap_cb; + int m_tilerom_offset; + int m_tilerom_length; + unsigned m_transparent_pen; + + u8 m_registers[0x10]; +}; + +class rshark_rom_tilemap_device : public dooyong_rom_tilemap_device +{ +public: + template + rshark_rom_tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxdecode_tag, int gfxnum, U &&tilerom_tag, int tilerom_offset, int tilerom_length, V &&colorrom_tag, int colorrom_offset, int colorrom_length) + : rshark_rom_tilemap_device(mconfig, tag, owner, 0) + { + set_gfxdecode_tag(std::forward(gfxdecode_tag)); + set_gfxnum(gfxnum); + set_tilerom_tag(std::forward(tilerom_tag)); + set_tilerom_offset(tilerom_offset); + set_tilerom_length(tilerom_length); + set_colorrom_tag(std::forward(colorrom_tag)); + set_colorrom_offset(colorrom_offset); + set_colorrom_length(colorrom_length); + } + + rshark_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + template void set_colorrom_tag(V &&colorrom_tag) { m_colorrom.set_tag(std::forward(colorrom_tag)); } + void set_colorrom_offset(int offset) { m_colorrom_offset = offset; } + void set_colorrom_length(int length) { m_colorrom_length = length; } + +protected: + virtual void device_start() override; + + virtual TILE_GET_INFO_MEMBER(tile_info) override; + +private: + required_region_ptr m_colorrom; + int m_colorrom_offset; + int m_colorrom_length; +}; + +class dooyong_ram_tilemap_device : public dooyong_tilemap_device_base +{ +public: + template + dooyong_ram_tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxdecode_tag, int gfxnum) + : dooyong_ram_tilemap_device(mconfig, tag, owner, 0) + { + set_gfxdecode_tag(std::forward(gfxdecode_tag)); + set_gfxnum(gfxnum); + } + + dooyong_ram_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + u16 tileram_r(offs_t offset) { return m_tileram[offset & ((64U * 32U) - 1)]; } + void tileram_w(offs_t offset, u16 data, u16 mem_mask = ~0); + void set_scrolly(int value) { m_tilemap->set_scrolly(value); } + +protected: + virtual void device_start() override; + +private: + TILE_GET_INFO_MEMBER(tile_info); + + std::unique_ptr m_tileram; +}; + +#endif // MAME_DOOYONG_DOOYONG_TILEMAP_H diff --git a/src/mame/dooyong/dooyong_v.cpp b/src/mame/dooyong/dooyong_v.cpp deleted file mode 100644 index 25fc0a0ef55..00000000000 --- a/src/mame/dooyong/dooyong_v.cpp +++ /dev/null @@ -1,265 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Vas Crabb -#include "emu.h" -#include "dooyong_v.h" - -#include "screen.h" - - -/* These games all have ROM-based tilemaps for the backgrounds, title - screens and sometimes "bosses" and special attacks. There are three - schemes for tilemap encoding. The scheme is chosen based on the - contents of the tilemap control variables. - Note that although the tilemaps are arbitrarily wide (hundreds of - thousands of pixels, depending on the size of the ROM), we only - decode a 1024 pixel wide block at a time, and invalidate the tilemap - when the X scroll moves out of range (trying to decode the whole lot - at once uses hundreds of megabytes of RAM). */ - -DEFINE_DEVICE_TYPE(DOOYONG_ROM_TILEMAP, dooyong_rom_tilemap_device, "dooyong_rom_tilemap", "Dooyong ROM Tilemap") -DEFINE_DEVICE_TYPE(RSHARK_ROM_TILEMAP, rshark_rom_tilemap_device, "rshark_rom_tilemap", "R-Shark ROM Tilemap") -DEFINE_DEVICE_TYPE(DOOYONG_RAM_TILEMAP, dooyong_ram_tilemap_device, "dooyong_ram_tilemap", "Dooyong RAM Tilemap") - - -dooyong_tilemap_device_base::dooyong_tilemap_device_base( - machine_config const &mconfig, - device_type type, - char const *tag, - device_t *owner, - u32 clock) - : device_t(mconfig, type, tag, owner, clock) - , m_gfxdecode(*this, finder_base::DUMMY_TAG) - , m_gfxnum(0) - , m_tilemap(nullptr) - , m_palette_bank(0) -{ -} - -void dooyong_tilemap_device_base::draw(screen_device &screen, bitmap_ind16 &dest, rectangle const &cliprect, u32 flags, u8 priority, u8 priority_mask) -{ - m_tilemap->draw(screen, dest, cliprect, flags, priority, priority_mask); -} - -void dooyong_tilemap_device_base::set_palette_bank(u16 bank) -{ - if (bank != m_palette_bank) - { - m_palette_bank = bank; - m_tilemap->mark_all_dirty(); - } -} - -dooyong_rom_tilemap_device::dooyong_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) - : dooyong_rom_tilemap_device(mconfig, DOOYONG_ROM_TILEMAP, tag, owner, clock) -{ -} - -dooyong_rom_tilemap_device::dooyong_rom_tilemap_device( - machine_config const &mconfig, - device_type type, - char const *tag, - device_t *owner, - u32 clock) - : dooyong_tilemap_device_base(mconfig, type, tag, owner, clock) - , m_rows(8) - , m_tilerom(*this, finder_base::DUMMY_TAG) - , m_tmap_cb(*this) - , m_tilerom_offset(0) - , m_tilerom_length(~0U) - , m_transparent_pen(~0U) - , m_registers{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } -{ -} - -void dooyong_rom_tilemap_device::ctrl_w(offs_t offset, u8 data) -{ - offset &= 0x07U; - const u8 old = m_registers[offset]; - if (old != data) - { - m_registers[offset] = data; - switch (offset) - { - case 0: // Low byte of X scroll - scroll tilemap - m_tilemap->set_scrollx(0, data); - break; - case 1: // High byte of X scroll - mark tilemap dirty so new tile gfx will be loaded - m_tilemap->mark_all_dirty(); - break; - case 3: // Low byte of Y scroll - case 4: // High byte of Y scroll - m_tilemap->set_scrolly(0, m_registers[3] | (unsigned(m_registers[4]) << 8)); - break; - case 6: // Tilemap enable and mode control - m_tilemap->enable(!BIT(data, 4)); - if (BIT(data ^ old, 5)) // This sets the tilemap data format - m_tilemap->mark_all_dirty(); - break; - default: // Other addresses are used but function is unknown - // 0x05 and 0x07 are initialised on startup - // 0x02 is initialised on startup by some games and written to continuously by others - // printf("Unknown %s tilemap control: 0x%02x = 0x%02x\n", tag(), unsigned(offset), unsigned(data)); - break; - } - } -} - -void dooyong_rom_tilemap_device::device_start() -{ - if (!m_gfxdecode->started()) - throw device_missing_dependencies(); - - m_tmap_cb.resolve(); - - m_tilemap = &machine().tilemap().create( - *m_gfxdecode, - tilemap_get_info_delegate(*this, FUNC(dooyong_rom_tilemap_device::tile_info)), - TILEMAP_SCAN_COLS, - gfx().width(), - gfx().height(), - 1024 / gfx().width(), - m_rows); - if (~m_transparent_pen) - m_tilemap->set_transparent_pen(m_transparent_pen); - - if (0 > m_tilerom_offset) - m_tilerom_offset = m_tilerom.length() + m_tilerom_offset; - - if (m_tilerom_length < 0) - m_tilerom_length = m_tilerom.length(); - - std::fill(std::begin(m_registers), std::end(m_registers), 0U); - m_palette_bank = 0U; - - save_item(NAME(m_registers)); - save_item(NAME(m_palette_bank)); -} - -TILE_GET_INFO_MEMBER(dooyong_rom_tilemap_device::tile_info) -{ - const int tile_index_tile = adjust_tile_index(tile_index) & (m_tilerom_length - 1); - const u16 attr = m_tilerom[m_tilerom_offset + tile_index_tile]; - u32 code = 0, color = 0, flags; - if (BIT(m_registers[6], 5)) - { // lastday/gulfstrm/pollux/flytiger - // Tiles take one word in ROM: - // MSB LSB - // cCCC CYXc cccc cccc (bit 9 of gfx code, bits 3-0 of color, Y flip, X flip, bits 8-0 of gfx code) - // c = gfx code - // C = color code - // X = x flip - // Y = y flip - code = (BIT(attr, 15) << 9) | (attr & 0x01ff); - color = BIT(attr, 11, 4); - flags = TILE_FLIPYX(BIT(attr, 9, 2)); - } - else - { // bluehawk/primella/popbingo - // Tiles take one word in ROM: - // MSB LSB - // bluehawk YXCC CCcc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 9-0 of gfx code) - // primella YXCC CCcc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 9-0 of gfx code) - // popbingo YX?? ?ccc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 10-0 of gfx code) - // rshark YX?c cccc cccc cccc (Y flip, X flip, bits 3-0 of color code, bits 12-0 of gfx code) - // c = gfx code - // C = color code - // X = x flip - // Y = y flip - // ? = unused? - if (!m_tmap_cb.isnull()) - m_tmap_cb(attr & 0x3fff, code, color); - else // just mimic old driver behavior (default configuration) - { - code = attr & 0x3ff; - color = BIT(attr, 10, 4); - } - - flags = TILE_FLIPYX(BIT(attr, 14, 2)); - } - color |= m_palette_bank; - - tileinfo.set(m_gfxnum, code, color, flags); -} - - -rshark_rom_tilemap_device::rshark_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) - : dooyong_rom_tilemap_device(mconfig, RSHARK_ROM_TILEMAP, tag, owner, clock) - , m_colorrom(*this, finder_base::DUMMY_TAG) - , m_colorrom_offset(0) - , m_colorrom_length(0) -{ - m_rows = 32; -} - -void rshark_rom_tilemap_device::device_start() -{ - dooyong_rom_tilemap_device::device_start(); - - if (0 > m_colorrom_offset) - m_colorrom_offset = m_colorrom.length() + m_colorrom_offset; - - if (m_colorrom_length < 0) - m_colorrom_length = m_colorrom.length(); -} - -TILE_GET_INFO_MEMBER(rshark_rom_tilemap_device::tile_info) -{ - dooyong_rom_tilemap_device::tile_info(tilemap, tileinfo, tile_index); - - const int tile_index_color = adjust_tile_index(tile_index) & (m_colorrom_length - 1); - const u16 color = m_palette_bank | (m_colorrom[m_colorrom_offset + tile_index_color] & 0x0fU); - tileinfo.palette_base = gfx().colorbase() + (gfx().granularity() * (color % gfx().colors())); -} - - -dooyong_ram_tilemap_device::dooyong_ram_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) - : dooyong_tilemap_device_base(mconfig, DOOYONG_RAM_TILEMAP, tag, owner, clock) - , m_tileram() -{ -} - -void dooyong_ram_tilemap_device::tileram_w(offs_t offset, u16 data, u16 mem_mask) -{ - offset &= (64U * 32U) - 1U; - u16 value(m_tileram[offset]); - COMBINE_DATA(&value); - if (value != m_tileram[offset]) - { - m_tileram[offset] = value; - m_tilemap->mark_tile_dirty(offset); - } -} - -void dooyong_ram_tilemap_device::device_start() -{ - if (!m_gfxdecode->started()) - throw device_missing_dependencies(); - - m_tilemap = &machine().tilemap().create( - *m_gfxdecode, - tilemap_get_info_delegate(*this, FUNC(dooyong_ram_tilemap_device::tile_info)), - TILEMAP_SCAN_COLS, - 8, - 8, - 64, - 32); - m_tilemap->set_transparent_pen(15); - - m_tileram.reset(new u16[64 * 32]); - std::fill(m_tileram.get(), m_tileram.get() + (64 * 32), 0U); - m_palette_bank = 0U; - - save_pointer(NAME(m_tileram), 64 * 32); - save_item(NAME(m_palette_bank)); -} - -TILE_GET_INFO_MEMBER(dooyong_ram_tilemap_device::tile_info) -{ - // Each tile takes one word of memory: - // MSB LSB - // CCCC cccc cccc cccc (bits 3-0 of color code, bits 11-0 of gfx code) - // c = gfx code - // C = color code - const u16 attr(m_tileram[tile_index]); - tileinfo.set(m_gfxnum, attr & 0x0fffU, m_palette_bank | BIT(attr, 12, 4), 0); -} diff --git a/src/mame/dooyong/dooyong_v.h b/src/mame/dooyong/dooyong_v.h deleted file mode 100644 index 31846057958..00000000000 --- a/src/mame/dooyong/dooyong_v.h +++ /dev/null @@ -1,156 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Vas Crabb -#ifndef MAME_VIDEO_DOOYONG_H -#define MAME_VIDEO_DOOYONG_H - -#pragma once - -#include "video/bufsprite.h" -#include "tilemap.h" - -DECLARE_DEVICE_TYPE(DOOYONG_ROM_TILEMAP, dooyong_rom_tilemap_device) -DECLARE_DEVICE_TYPE(RSHARK_ROM_TILEMAP, rshark_rom_tilemap_device) -DECLARE_DEVICE_TYPE(DOOYONG_RAM_TILEMAP, dooyong_ram_tilemap_device) - - -class dooyong_tilemap_device_base : public device_t -{ -public: - template void set_gfxdecode_tag(T &&gfxdecode_tag) { m_gfxdecode.set_tag(std::forward(gfxdecode_tag)); } - void set_gfxnum(int gfxnum) { m_gfxnum = gfxnum; } - - void draw(screen_device &screen, bitmap_ind16 &dest, rectangle const &cliprect, u32 flags, u8 priority, u8 priority_mask = 0xff); - - void set_palette_bank(u16 bank); - -protected: - dooyong_tilemap_device_base( - machine_config const &mconfig, - device_type type, - char const *tag, - device_t *owner, - u32 clock); - - gfx_element const &gfx() const { return *m_gfxdecode->gfx(m_gfxnum); } - - required_device m_gfxdecode; - int m_gfxnum; - - tilemap_t *m_tilemap; - u16 m_palette_bank; -}; - -class dooyong_rom_tilemap_device : public dooyong_tilemap_device_base -{ -public: - template - dooyong_rom_tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxdecode_tag, int gfxnum, U &&tilerom_tag, int tilerom_offset, int tilerom_length) - : dooyong_rom_tilemap_device(mconfig, tag, owner, 0) - { - set_gfxdecode_tag(std::forward(gfxdecode_tag)); - set_gfxnum(gfxnum); - set_tilerom_tag(std::forward(tilerom_tag)); - set_tilerom_offset(tilerom_offset); - set_tilerom_length(tilerom_length); - } - - dooyong_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - - template void set_tilerom_tag(U &&tilerom_tag) { m_tilerom.set_tag(std::forward(tilerom_tag)); } - void set_tilerom_offset(int offset) { m_tilerom_offset = offset; } - void set_tilerom_length(int length) { m_tilerom_length = length; } - void set_transparent_pen(unsigned pen) { m_transparent_pen = pen; } - - typedef device_delegate dooyong_tmap_cb_delegate; - template void set_tile_callback(T &&... args) { m_tmap_cb.set(std::forward(args)...); } - - void ctrl_w(offs_t offset, u8 data); - -protected: - dooyong_rom_tilemap_device( - machine_config const &mconfig, - device_type type, - char const *tag, - device_t *owner, - u32 clock); - - virtual void device_start() override; - - virtual TILE_GET_INFO_MEMBER(tile_info); - - tilemap_memory_index adjust_tile_index(tilemap_memory_index tile_index) const - { return tile_index + ((unsigned(m_registers[1]) * 256U / gfx().width()) * m_rows); } - - int m_rows; - -private: - required_region_ptr m_tilerom; - dooyong_tmap_cb_delegate m_tmap_cb; - int m_tilerom_offset; - int m_tilerom_length; - unsigned m_transparent_pen; - - u8 m_registers[0x10]; -}; - -class rshark_rom_tilemap_device : public dooyong_rom_tilemap_device -{ -public: - template - rshark_rom_tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxdecode_tag, int gfxnum, U &&tilerom_tag, int tilerom_offset, int tilerom_length, V &&colorrom_tag, int colorrom_offset, int colorrom_length) - : rshark_rom_tilemap_device(mconfig, tag, owner, 0) - { - set_gfxdecode_tag(std::forward(gfxdecode_tag)); - set_gfxnum(gfxnum); - set_tilerom_tag(std::forward(tilerom_tag)); - set_tilerom_offset(tilerom_offset); - set_tilerom_length(tilerom_length); - set_colorrom_tag(std::forward(colorrom_tag)); - set_colorrom_offset(colorrom_offset); - set_colorrom_length(colorrom_length); - } - - rshark_rom_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - - template void set_colorrom_tag(V &&colorrom_tag) { m_colorrom.set_tag(std::forward(colorrom_tag)); } - void set_colorrom_offset(int offset) { m_colorrom_offset = offset; } - void set_colorrom_length(int length) { m_colorrom_length = length; } - -protected: - virtual void device_start() override; - - virtual TILE_GET_INFO_MEMBER(tile_info) override; - -private: - required_region_ptr m_colorrom; - int m_colorrom_offset; - int m_colorrom_length; -}; - -class dooyong_ram_tilemap_device : public dooyong_tilemap_device_base -{ -public: - template - dooyong_ram_tilemap_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&gfxdecode_tag, int gfxnum) - : dooyong_ram_tilemap_device(mconfig, tag, owner, 0) - { - set_gfxdecode_tag(std::forward(gfxdecode_tag)); - set_gfxnum(gfxnum); - } - - dooyong_ram_tilemap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - - u16 tileram_r(offs_t offset) { return m_tileram[offset & ((64U * 32U) - 1)]; } - void tileram_w(offs_t offset, u16 data, u16 mem_mask = ~0); - void set_scrolly(int value) { m_tilemap->set_scrolly(value); } - -protected: - virtual void device_start() override; - -private: - TILE_GET_INFO_MEMBER(tile_info); - - std::unique_ptr m_tileram; -}; - -#endif // MAME_VIDEO_DOOYONG_H diff --git a/src/mame/messshared/isbc_215g.cpp b/src/mame/messshared/isbc_215g.cpp deleted file mode 100644 index 7bcc0211c5c..00000000000 --- a/src/mame/messshared/isbc_215g.cpp +++ /dev/null @@ -1,435 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Carl -// Currently only emulates Shugart SA1000 interface disks (aka ST506) -// despite the controller supporting many different disk types (hard sectored, onboard controllers, ANSI X3T9) -// Xenix supports the Quantum Q540 CHS 512,8,9 with 1024B sectors - -// TODO: multibus - -#include "emu.h" -#include "isbc_215g.h" - -DEFINE_DEVICE_TYPE(ISBC_215G, isbc_215g_device, "isbc_215g", "ISBC 215G Winchester Disk Controller") - -isbc_215g_device::isbc_215g_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, ISBC_215G, tag, owner, clock), - m_maincpu(*this, finder_base::DUMMY_TAG), - m_dmac(*this, "u84"), - m_hdd0(*this, "drive0"), - m_hdd1(*this, "drive1"), - m_sbx1(*this, "sbx1"), - m_sbx2(*this, "sbx2"), - m_out_irq_func(*this) -{ -} - -void isbc_215g_device::find_sector() -{ - //sector id - // 0/6-7: sector type - 0-data, 1-alternate, 2-bad, 3-invalid - // 0/4-5: size - 128<> 4) & 3); - - if(!m_geom[m_drive]) - return; - - if(m_cyl[m_drive] != cyl) - return; - - if((m_idcompare[3] != m_head) || (m_head > m_geom[m_drive]->heads)) - return; - - if(m_idcompare[2] > m_geom[m_drive]->sectors) - return; - - if(bps != m_geom[m_drive]->sectorbytes) - return; - - if(m_idcompare[0] >> 6) - return; - - m_idfound = true; - m_lba[m_drive] = (cyl * m_geom[m_drive]->heads + m_head) * m_geom[m_drive]->sectors + m_idcompare[2]; - m_secoffset = 0; - return; -} - -uint16_t isbc_215g_device::read_sector() -{ - uint16_t wps = 64 << ((m_idcompare[0] >> 4) & 3); - harddisk_image_device *drive = (m_drive ? m_hdd1 : m_hdd0); - if(!m_secoffset) - drive->get_hard_disk_file()->read(m_lba[m_drive], m_sector); - if(m_secoffset >= wps) - return 0; - return m_sector[m_secoffset++]; -} - -bool isbc_215g_device::write_sector(uint16_t data) -{ - uint16_t wps = 64 << ((m_idcompare[0] >> 4) & 3); - harddisk_image_device *drive = (m_drive ? m_hdd1 : m_hdd0); - if(m_secoffset >= wps) - return true; - m_sector[m_secoffset++] = data; - if(m_secoffset == wps) - { - drive->get_hard_disk_file()->write(m_lba[m_drive], m_sector); - return true; - } - return false; -} - -uint16_t isbc_215g_device::io_r(offs_t offset) -{ - uint16_t data = 0; - switch(offset) - { - case 0x00: - //read status - // 0: gnd - // 1: drive ready - // 2: seek done - // 3: sector sync found - // 4: fault - // 5: bus ack - // 6: sector id not found or bad ecc - // 7: timeout - // 8: sbx 1 present - // 9: sbx 1 int 0 - // a: sbx 1 int 1 - // b: sbx 1 opt 0 - // c: sbx 1 opt 1 - // d: illegal req/vendor 2 - // e: drive req - // f: index latch - data |= (!m_idfound) << 6; - data |= (m_sbx1->get_card_device() ? 0 : 1) << 8; - data |= m_isbx_irq[0] << 9; - data |= m_isbx_irq[1] << 10; - data |= ((m_index--) <= 0) ? 0x8000 : 0; // fake an index pulse - break; - case 0x04: - //read status 2 - // 0: sbx 2 present - // 1: sbx 2 int 0 - // 2: sbx 2 int 1 - // 3: sbx 2 opt 0 - // 4: sbx 2 opt 1 - // 5: vendor bit 0 - // 6: track 0/busy - // 7: wp - data |= m_sbx2->get_card_device() ? 0 : 1; - data |= m_isbx_irq[2] << 1; - data |= m_isbx_irq[3] << 2; - data |= (!m_cyl[m_drive]) ? 0 : 0x40; - break; - case 0x08: - //cmd data bus - break; - case 0x0c: - // reset channel 2 - if(machine().side_effects_disabled()) // reading this is bad - break; - m_dmac->sel_w(1); - m_dmac->ca_w(1); - m_dmac->ca_w(0); - m_dmac->sel_w(0); - break; - case 0x10: - //pit ch 0 - break; - case 0x11: - //pit ch 1 - break; - case 0x12: - //pit ch 2 - break; - case 0x14: - //read buffer - if(m_rdgate && !m_amsrch && m_geom[m_drive]) - data = read_sector(); - break; - case 0x18: - //vendor bit 1,3-4 - data |= 3<<4 | 2; - break; - default: - logerror("isbc_215g: invalid port read 0x80%02x\n", offset*2); - break; - } - return data; -} - -void isbc_215g_device::io_w(offs_t offset, uint16_t data) -{ - switch(offset) - { - case 0x00: - //control, 0x8002 doesn't set gates or search - // 0: wr gate - // 1: rd gate - // 2: address mark search - // 3: cmd bus enable - // 4: drive sel/head sel 2 - // 5: safe/head sel 1 - // 6: b ack - // 7: drive reg addr 0/step dir - // 8: drive reg addr 1 - // 9: cmd/rd - // a: para/head sel 0 - m_wrgate = data & 1; - m_rdgate = (data >> 1) & 1; - m_amsrch = (data >> 2) & 1; - if(m_wrgate && (m_rdgate || m_amsrch)) - logerror("isbc_215g: both write gate and read gate and/or address search enabled\n"); - else if(m_rdgate && m_amsrch) - find_sector(); - else if(m_amsrch) - logerror("isbc_215g: address search without read gate\n"); - [[fallthrough]]; - case 0x01: - m_stepdir = (data & 0x80) ? 1 : 0; - break; - case 0x04: - //clear index and id latch - m_index = 10; - m_idfound = false; - break; - case 0x08: - //cmd data bus/head sel - m_head = data & 7; - m_out_irq_func((data & 0x100) ? 1 : 0); - break; - case 0x0c: - //unit select - // 0: step/wr - // 1: sbx 1 opt 0/1 (sbx2?) - // 2: sbx 2 opt 0/1 - // 3: unit select 0 - // 4: unit select 1 - // 5: extr 2 - // 6: format - // 7: format wr gate - if(!m_step && (data & 1) && m_geom[m_drive]) - { - if(m_cyl[m_drive] && !m_stepdir) - m_cyl[m_drive]--; - else if((m_cyl[m_drive] < m_geom[m_drive]->cylinders) && m_stepdir) - m_cyl[m_drive]++; - } - m_step = data & 1; - m_drive = (data >> 3) & 1; // shugart interface, two drives only - if(((data >> 1) & 1) != m_fdctc) - { - m_fdctc = !m_fdctc; - m_sbx2->opt0_w(m_fdctc); - } - if((data & 0xc0) == 0xc0) // low-level format - { - if(!m_format) - m_format_bytes = 5; // sync + sector id - m_format = true; - } - else - m_format = false; - break; - case 0x10: - //pit ch 0 - break; - case 0x11: - //pit ch 1 - break; - case 0x12: - //pit ch 2 - break; - case 0x13: - //pit control - break; - case 0x14: - //write buffer - if(m_wrgate) - { - if(m_format) - { - m_format_bytes -= 2; - if(m_format_bytes <= 0) - { - m_dmac->ext1_w(1); - m_dmac->ext1_w(0); - m_format_bytes = 5; - } - } - else - { - if(m_geom[m_drive]) - { - if(write_sector(data)) - { - m_dmac->ext1_w(1); - m_dmac->ext1_w(0); - } - } - } - } - break; - case 0x18: - //sector id/format - m_idcompare[1] = data & 0xff; - m_idcompare[0] = data >> 8; - break; - case 0x1c: - //sector id low - m_idcompare[3] = data & 0xff; - m_idcompare[2] = data >> 8; - break; - default: - logerror("isbc_215g: invalid port write 0x80%02x\n", offset*2); - break; - } -} - -uint16_t isbc_215g_device::mem_r(offs_t offset, uint16_t mem_mask) -{ - // XXX: hack to permit debugger to disassemble rom - if(machine().side_effects_disabled() && (offset < 0x1fff)) - return m_dmac->space(AS_IO).read_word_unaligned(offset*2); - - switch(offset) - { - case 0x7fffb: - return 1; - case 0x7fffc: - return 0; - case 0x7fffd: - return m_wakeup; - default: - return m_maincpu_mem->read_word_unaligned(offset*2, mem_mask); - } -} - -void isbc_215g_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - m_maincpu_mem->write_word_unaligned(offset*2, data, mem_mask); -} - -void isbc_215g_device::isbc_215g_mem(address_map &map) -{ - map(0x00000, 0xfffff).rw(FUNC(isbc_215g_device::mem_r), FUNC(isbc_215g_device::mem_w)); -} - -void isbc_215g_device::isbc_215g_io(address_map &map) -{ - map(0x0000, 0x3fff).rom().region("i8089", 0); - map(0x4000, 0x47ff).mirror(0x3800).ram(); - map(0x8000, 0x8039).mirror(0x3fc0).rw(FUNC(isbc_215g_device::io_r), FUNC(isbc_215g_device::io_w)); - map(0xc070, 0xc08f).rw("sbx1", FUNC(isbx_slot_device::mcs0_r), FUNC(isbx_slot_device::mcs0_w)).umask16(0x00ff); - map(0xc0b0, 0xc0bf).rw("sbx1", FUNC(isbx_slot_device::mcs1_r), FUNC(isbx_slot_device::mcs1_w)).umask16(0x00ff); - map(0xc0d0, 0xc0df).rw("sbx2", FUNC(isbx_slot_device::mcs0_r), FUNC(isbx_slot_device::mcs0_w)).umask16(0x00ff); - map(0xc0e0, 0xc0ef).rw("sbx2", FUNC(isbx_slot_device::mcs1_r), FUNC(isbx_slot_device::mcs1_w)).umask16(0x00ff); -} - -WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_00_w) -{ - m_isbx_irq[0] = state ? true : false; -} - -WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_01_w) -{ - m_isbx_irq[1] = state ? true : false; -} - -WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_10_w) -{ - m_isbx_irq[2] = state ? true : false; -} - -WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_11_w) -{ - m_isbx_irq[3] = state ? true : false; -} - -void isbc_215g_device::device_add_mconfig(machine_config &config) -{ - I8089(config, m_dmac, XTAL(15'000'000) / 3); - m_dmac->set_addrmap(AS_PROGRAM, &isbc_215g_device::isbc_215g_mem); - m_dmac->set_addrmap(AS_IO, &isbc_215g_device::isbc_215g_io); - m_dmac->set_data_width(16); - - HARDDISK(config, "drive0", 0); - HARDDISK(config, "drive1", 0); - - ISBX_SLOT(config, m_sbx1, 0, isbx_cards, nullptr); - m_sbx1->mintr0().set(FUNC(isbc_215g_device::isbx_irq_00_w)); - m_sbx1->mintr1().set(FUNC(isbc_215g_device::isbx_irq_01_w)); - ISBX_SLOT(config, m_sbx2, 0, isbx_cards, "fdc_218a"); - m_sbx2->mintr0().set(FUNC(isbc_215g_device::isbx_irq_10_w)); - m_sbx2->mintr1().set(FUNC(isbc_215g_device::isbx_irq_11_w)); -} - - -ROM_START( isbc_215g ) - ROM_REGION16_LE( 0x4000, "i8089", ROMREGION_ERASEFF ) - ROM_LOAD16_BYTE( "174581.001.bin", 0x0000, 0x2000, CRC(ccdbc7ab) SHA1(5c2ebdde1b0252124177221ba9cacdb6d925a24d)) - ROM_LOAD16_BYTE( "174581.002.bin", 0x0001, 0x2000, CRC(6190fa67) SHA1(295dd4e75f699aaf93227cc4876cee8accae383a)) -ROM_END - -const tiny_rom_entry *isbc_215g_device::device_rom_region() const -{ - return ROM_NAME( isbc_215g ); -} - -void isbc_215g_device::device_reset() -{ - if(m_hdd0->get_hard_disk_file()) - m_geom[0] = &m_hdd0->get_hard_disk_file()->get_info(); - else - m_geom[0] = nullptr; - if(m_hdd1->get_hard_disk_file()) - m_geom[1] = &m_hdd1->get_hard_disk_file()->get_info(); - else - m_geom[1] = nullptr; - - m_reset = false; - m_fdctc = false; - m_isbx_irq[0] = m_isbx_irq[1] = m_isbx_irq[2] = m_isbx_irq[3] = false; -} - -void isbc_215g_device::device_start() -{ - m_maincpu_mem = &m_maincpu->space(AS_PROGRAM); - m_cyl[0] = m_cyl[1] = 0; - m_lba[0] = m_lba[1] = 0; - m_idcompare[0] = m_idcompare[1] = m_idcompare[2] = m_idcompare[3] = 0; - m_index = 10; - m_idfound = false; - m_drive = 0; - m_head = 0; - m_stepdir = false; - m_step = false; - m_format = false; - m_wrgate = false; - m_rdgate = false; - m_format_bytes = 0; - m_out_irq_func.resolve_safe(); - -} - -void isbc_215g_device::write(offs_t offset, uint8_t data) -{ - if(!offset) - { - data &= 3; - if(!data && (m_reset == 2)) - m_dmac->reset(); - m_out_irq_func(0); - m_dmac->ca_w(data == 1); - m_dmac->ca_w(0); - m_reset = data; - } -} diff --git a/src/mame/messshared/isbc_215g.h b/src/mame/messshared/isbc_215g.h deleted file mode 100644 index 8f00143dd17..00000000000 --- a/src/mame/messshared/isbc_215g.h +++ /dev/null @@ -1,89 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Carl -#ifndef MAME_MACHINE_ISBC_215G_H -#define MAME_MACHINE_ISBC_215G_H - -#pragma once - -#include "cpu/i8089/i8089.h" -#include "bus/isbx/isbx.h" -#include "imagedev/harddriv.h" - -class isbc_215g_device : public device_t -{ -public: - template - isbc_215g_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint16_t wakeup, T &&cpu_tag) - : isbc_215g_device(mconfig, tag, owner, clock) - { - m_wakeup = wakeup; - m_maincpu.set_tag(std::forward(cpu_tag)); - } - - isbc_215g_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - auto irq_callback() { return m_out_irq_func.bind(); } - - void write(offs_t offset, uint8_t data); - uint16_t io_r(offs_t offset); - void io_w(offs_t offset, uint16_t data); - uint16_t mem_r(offs_t offset, uint16_t mem_mask = ~0); - void mem_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - -protected: - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_add_mconfig(machine_config &config) override; - const tiny_rom_entry *device_rom_region() const override; - - void isbc_215g_io(address_map &map); - void isbc_215g_mem(address_map &map); - -private: - void find_sector(); - uint16_t read_sector(); - bool write_sector(uint16_t data); - - required_device m_maincpu; - required_device m_dmac; - required_device m_hdd0; - required_device m_hdd1; - required_device m_sbx1; - required_device m_sbx2; - - devcb_write_line m_out_irq_func; - - int m_reset; - uint16_t m_wakeup; - uint16_t m_secoffset; - uint16_t m_sector[512]; - address_space *m_maincpu_mem; - uint32_t m_lba[2]; - uint16_t m_cyl[2]; - uint8_t m_idcompare[4]; - uint8_t m_drive; - uint8_t m_head; - uint8_t m_index; - int8_t m_format_bytes; - bool m_idfound; - bool m_stepdir; - bool m_wrgate; - bool m_rdgate; - bool m_amsrch; - - bool m_isbx_irq[4]; - bool m_fdctc; - bool m_step; - bool m_format; - - const struct hard_disk_file::info* m_geom[2]; - - DECLARE_WRITE_LINE_MEMBER(isbx_irq_00_w); - DECLARE_WRITE_LINE_MEMBER(isbx_irq_01_w); - DECLARE_WRITE_LINE_MEMBER(isbx_irq_10_w); - DECLARE_WRITE_LINE_MEMBER(isbx_irq_11_w); -}; - -DECLARE_DEVICE_TYPE(ISBC_215G, isbc_215g_device) - -#endif // MAME_MACHINE_ISBC_215G_H diff --git a/src/mame/messshared/mega32x.cpp b/src/mame/messshared/mega32x.cpp deleted file mode 100644 index fdbf96179d6..00000000000 --- a/src/mame/messshared/mega32x.cpp +++ /dev/null @@ -1,1862 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:David Haywood -/* Megadrive / Genesis 32X emulation */ - -/* - - Fix 32X support (not used by any arcade systems?) - - this seems to require far greater sync and timing accuracy on rom / ram access than MAME can provide - - split NTSC / PAL drivers - - 36greatju: missing backup ram, has issues with golfer select due of that - - bcracers: write to undefined PWM register? - - fifa96 / nbajamte: dies on the gameplay, waiting for a comm change that never occurs; - - marsch1: doesn't boot, Master / Slave communicates through SCI - - tempo: intro is too fast, mostly noticeable with the PWM sound that cuts off too early when it gets to the title screen; - - tmek: gameplay is clearly too fast - - -32x Marsch tests documentation (keep start pressed at start-up for individual tests): - -MD side check: -#1 Communication Check -#2 FM Bit -#3 Irq Register -#4 Bank Control Register -#5 DREQ Control FULL bit -#6 DREQ SRC Address -#7 DREQ DST Address -#8 DREQ SIZE Address -#9 SEGA TV Register -#10 H IRQ Vector -#11 PWM Control Register -#12 PWM Frequency Register -#13 PWM Lch Pulse Width Register -#14 PWM Rch Pulse Width Register -#15 PWM MONO Pulse Width Register -32x side check: -#16 SH-2 Master Communication Check -#17 SH-2 Slave Communication Check -#18 SH-2 Master FM Bit -#19 SH-2 Slave FM Bit -#20 SH-2 Master IRQ Mask Register -#21 SH-2 Slave IRQ Mask Register -#22 SH-2 Master H Counter Register -#23 SH-2 Slave H Counter Register -#24 SH-2 Master PWM Timer Register -#25 SH-2 Slave PWM Timer Register -#26 SH-2 Master PWM Cont. Register -#27 SH-2 Slave PWM Cont. Register -#28 SH-2 Master PWM Freq. Register -#29 SH-2 Slave PWM Freq. Register -#30 SH-2 Master PWM Lch Register -#31 SH-2 Slave PWM Lch Register -#32 SH-2 Master PWM Rch Register -#33 SH-2 Slave PWM Rch Register -#34 SH-2 Master PWM Mono Register -#35 SH-2 Slave PWM Mono Register -#36 SH-2 Master ROM Read Check -#37 SH-2 Slave ROM Read Check -#38 SH-2 Serial Communication (ERROR - returns a Timeout Error) -MD & 32x check: -#39 MD&SH-2 Master Communication -#40 MD&SH-2 Slave Communication -#41 MD&SH-2 Master FM Bit R/W -#42 MD&SH-2 Slave FM Bit R/W -#43 MD&SH-2 Master DREQ CTL -#44 MD&SH-2 Slave DREQ CTL -#45 MD&SH-2 Master DREQ SRC address -#46 MD&SH-2 Slave DREQ SRC address -#47 MD&SH-2 Master DREQ DST address -#48 MD&SH-2 Slave DREQ DST address -#49 MD&SH-2 Master DREQ SIZE address -#50 MD&SH-2 Slave DREQ SIZE address -#51 SH-2 Master V IRQ -#52 SH-2 Slave V IRQ -#53 SH2 Master H IRQ (MD 0) -#54 SH2 Slave H IRQ (MD 0) -#55 SH2 Master H IRQ (MD 1) -#56 SH2 Slave H IRQ (MD 1) -#57 SH2 Master H IRQ (MD 2) -#58 SH2 Slave H IRQ (MD 2) -MD VDP check: -#59 Bitmap Mode Register -#60 Shift Register -#61 Auto Fill Length Register -#62 Auto Fill Start Address Register -#63 V Blank BIT -#64 H Blank BIT -#65 Palette Enable BIT -SH-2 VDP check: -#66 Frame Swap BIT -#67 SH-2 Master Bitmap MD -#68 SH-2 Slave Bitmap MD -#69 SH-2 Master Shift -#70 SH-2 Slave Shift -#71 SH-2 Master Fill SIZE -#72 SH-2 Slave Fill SIZE -#73 SH-2 Master Fill START -#74 SH-2 Slave Fill START -#75 SH-2 Master V Blank Bit -#76 SH-2 Slave V Blank Bit -#77 SH-2 Master H Blank Bit -#78 SH-2 Slave H Blank Bit -#79 SH-2 Master Palette Enable Bit -#80 SH-2 Slave Palette Enable Bit -#81 SH-2 Master Frame Swap Bit -#82 SH-2 Slave Frame Swap Bit -Framebuffer Check: -#83 MD Frame Buffer 0 -#84 MD Frame Buffer 1 -#85 SH-2 Master Frame Buffer 0 -#86 SH-2 Slave Frame Buffer 0 -#87 SH-2 Master Frame Buffer 1 -#88 SH-2 Slave Frame Buffer 1 -#89 MD Frame Buffer 0 Overwrite -#90 MD Frame Buffer 1 Overwrite -#91 MD Frame Buffer 0 Byte Write -#92 MD Frame Buffer 1 Byte Write -#93 SH-2 Master Frame Buffer 0 Overwrite -#94 SH-2 Slave Frame Buffer 0 Overwrite -#95 SH-2 Master Frame Buffer 1 Overwrite -#96 SH-2 Slave Frame Buffer 1 Overwrite -#97 SH-2 Master Frame Buffer 0 Byte Write -#98 SH-2 Slave Frame Buffer 0 Byte Write -#99 SH-2 Master Frame Buffer 1 Byte Write -#100 SH-2 Slave Frame Buffer 1 Byte Write -#101 MD Frame Buffer 0 Fill Data -#102 MD Frame Buffer 1 Fill Data -#103 MD Frame Buffer 0 Fill Length & Address -#104 MD Frame Buffer 1 Fill Length & Address -#105 SH-2 Master Frame Buffer 0 Fill Data -#106 SH-2 Slave Frame Buffer 0 Fill Data -#107 SH-2 Master Frame Buffer 1 Fill Data -#108 SH-2 Slave Frame Buffer 1 Fill Data -#109 SH-2 Master Frame Buffer 0 Fill Address -#110 SH-2 Slave Frame Buffer 0 Fill Address -#111 SH-2 Master Frame Buffer 1 Fill Address -#112 SH-2 Slave Frame Buffer 1 Fill Address -#113 MD Palette R/W (Blank Mode) -#114 MD Palette R/W (Display Mode) -#115 MD Palette R/W (Fill Mode) -#116 SH-2 Master Palette R/W (Blank Mode) -#117 SH-2 Slave Palette R/W (Blank Mode) -#118 SH-2 Master Palette R/W (Display Mode) -#119 SH-2 Slave Palette R/W (Display Mode) -#120 SH-2 Master Palette R/W (Fill Mode) -#121 SH-2 Slave Palette R/W (Fill Mode) -MD or SH-2 DMA check: -#122 SH-2 Master CPU Write DMA (68S) (ERROR) -#123 SH-2 Slave CPU Write DMA (68S) (ERROR) -#124 MD ROM to VRAM DMA (asserts after this) ------ -#127 SH-2 Master ROM to SDRAM DMA -#128 SH-2 Slave ROM to SDRAM DMA -#129 SH-2 Master ROM to Frame DMA -#130 SH-2 Slave ROM to Frame DMA -#131 SH-2 Master SDRAM to Frame DMA -#132 SH-2 Slave SDRAM to Frame DMA -#133 SH-2 Master Frame to SDRAM DMA -#134 SH-2 Slave Frame to SDRAM DMA -Sound Test (these don't explicitly fails): -#135 MD 68k Monaural Sound -#136 MD 68k L Sound -#137 MD 68k R Sound -#138 MD 68k L -> R Sound -#139 MD 68k R -> L Sound -#140 SH-2 Master Monaural Sound -#141 SH-2 Master L Sound -#142 SH-2 Master R Sound -#143 SH-2 Master L -> R Pan -#144 SH-2 Master R -> L Pan -#145 SH-2 Slave Monaural Sound -#146 SH-2 Slave L Sound -#147 SH-2 Slave R Sound -#148 SH-2 Slave L -> R Pan -#149 SH-2 Slave R -> L Pan -#150 SH-2 Master PWM Interrupt -#151 SH-2 Slave PWM Interrupt -#152 SH-2 Master PWM DMA Write (!) -#153 SH-2 Slave PWM DMA Write (!) -#154 Z80 PWM Monaural Sound (!) -#155 Z80 PWM L Sound (!) -#156 Z80 PWM R Sound (!) -GFX check (these don't explicitly fails): -#157 Direct Color Mode -#158 Packed Pixel Mode -#159 Runlength Mode -#160 Runlength Mode -#161 Runlength Mode - -*/ -#include "emu.h" -#include "mega32x.h" -#include "machine/timer.h" - - -// Fifa96 needs the CPUs swapped for the gameplay to enter due to some race conditions -// when using the DRC core. Needs further investigation, the non-DRC core works either -// way -#define _32X_SWAP_MASTER_SLAVE_HACK -#define _32X_COMMS_PORT_SYNC 0 -#define MAX_HPOSITION 480 -/* need to make some pwm stuff part of device */ - - - -#define SH2_VRES_IRQ_LEVEL 14 -#define SH2_VINT_IRQ_LEVEL 12 -#define SH2_HINT_IRQ_LEVEL 10 -#define SH2_CINT_IRQ_LEVEL 8 -#define SH2_PINT_IRQ_LEVEL 6 - - -DEFINE_DEVICE_TYPE(SEGA_32X_NTSC, sega_32x_ntsc_device, "sega_32x_ntsc", "Sega 32X (NTSC)") -DEFINE_DEVICE_TYPE(SEGA_32X_PAL, sega_32x_pal_device, "sega_32x_pal", "Sega 32X (PAL)") - -sega_32x_device::sega_32x_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_palette_interface(mconfig, *this) - , device_sound_interface(mconfig, *this) - , device_video_interface(mconfig, *this, false) - , m_sh2_shared(*this, "sh2_shared") - , m_main_cpu(*this, finder_base::DUMMY_TAG) - , m_master_cpu(*this, "32x_master_sh2") - , m_slave_cpu(*this, "32x_slave_sh2") - , m_ldac(*this, "ldac") - , m_rdac(*this, "rdac") - , m_scan_timer(*this, finder_base::DUMMY_TAG) - , m_rombank(*this, "rombank") - , m_stream(nullptr) -{ -} - -sega_32x_ntsc_device::sega_32x_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : sega_32x_device(mconfig, SEGA_32X_NTSC, tag, owner, clock) -{ -} - -sega_32x_pal_device::sega_32x_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : sega_32x_device(mconfig, SEGA_32X_PAL, tag, owner, clock) -{ -} - -uint16_t sega_32x_device::m68k_palette_r(offs_t offset) -{ - return m_32x_palette[offset]; -} - -void sega_32x_device::m68k_palette_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - COMBINE_DATA(&m_32x_palette[offset]); -} - -uint16_t sega_32x_device::m68k_dram_r(offs_t offset) -{ - return m_32x_access_dram[offset]; -} - -void sega_32x_device::m68k_dram_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if ((mem_mask&0xffff) == 0xffff) - { - // 16-bit accesses are normal - COMBINE_DATA(&m_32x_access_dram[offset]); - } - else - { - // 8-bit writes act as if they were going to the overwrite region! - // bc-racers and world series baseball rely on this! - // (tested on real hw) - - if ((mem_mask & 0xffff) == 0xff00) - { - if ((data & 0xff00) != 0x0000) - { - m_32x_access_dram[offset] = (data & 0xff00) | (m_32x_access_dram[offset] & 0x00ff); - } - } - else if ((mem_mask & 0xffff) == 0x00ff) - { - if ((data & 0x00ff) != 0x0000) - { - m_32x_access_dram[offset] = (data & 0x00ff) | (m_32x_access_dram[offset] & 0xff00); - } - } - } -} - -uint16_t sega_32x_device::m68k_dram_overwrite_r(offs_t offset) -{ - return m_32x_access_dram[offset]; -} - -void sega_32x_device::m68k_dram_overwrite_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - //COMBINE_DATA(&m_32x_access_dram[offset+0x10000]); - - if (ACCESSING_BITS_8_15) - { - if (data & 0xff00) - { - m_32x_access_dram[offset] = (m_32x_access_dram[offset]&0x00ff) | (data & 0xff00); - } - } - - if (ACCESSING_BITS_0_7) - { - if (data & 0x00ff) - { - m_32x_access_dram[offset] = (m_32x_access_dram[offset]&0xff00) | (data & 0x00ff); - } - } -} - -/**********************************************************************************************/ -// 68k side a15112 -// FIFO -/**********************************************************************************************/ - - - - -/* - -15106 DREQ - - ---- ---- F--- -K0R - - F = Fifo FULL - K = 68k CPU Write mode (0 = no, 1 = CPU write) - 0 = always 0? no, marsch test wants it to be latched or 1 - R = RV (0 = no operation, 1 = DMA Start allowed) <-- RV bit actually affects memory mapping, this is misleading.. it just sets the memory up in a suitable way to use the genesis VDP DMA - -*/ - - - - -uint16_t sega_32x_device::m68k_a15106_r() -{ - uint16_t retval; - - retval = m_a15106_reg; - - if (m_fifo_block_a_full && m_fifo_block_b_full) retval |= 0x8080; - - return retval; -} - -void sega_32x_device::m68k_a15106_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - { - m_a15106_reg = data & 0x7; - - if (m_a15106_reg & 0x1) /* NBA Jam TE relies on this */ - { - // install the game rom in the normal 0x000000-0x03fffff space used by the genesis - this allows VDP DMA operations to work as they have to be from this area or RAM - // it should also UNMAP the banked rom area... - space.install_rom(0x0000100, 0x03fffff, machine().root_device().memregion("gamecart")->base() + 0x100); - } - else - { - // we should be careful and map back any rom overlay (hint) and backup ram too I think... - - // this is actually blank / nop area - // we should also map the banked area back (we don't currently unmap it tho) - space.install_rom(0x0000100, 0x03fffff, machine().root_device().memregion("maincpu")->base()+0x100); - } - - if((m_a15106_reg & 4) == 0) // clears the FIFO state - { - m_current_fifo_block = m_fifo_block_a; - m_current_fifo_readblock = m_fifo_block_b; - m_current_fifo_write_pos = 0; - m_current_fifo_read_pos = 0; - m_fifo_block_a_full = 0; - m_fifo_block_b_full = 0; - } - - //printf("m68k_a15106_w %04x\n", data); - /* - if (m_a15106_reg & 0x4) - printf(" --- 68k Write Mode enabled\n"); - else - printf(" --- 68k Write Mode disabled\n"); - - if (m_a15106_reg & 0x1) - printf(" --- DMA Start Allowed \n"); - else - printf(" --- DMA Start No Operation\n"); - - */ - } -} - - - -uint16_t sega_32x_device::dreq_common_r(address_space &space, offs_t offset) -{ - address_space& _68kspace = m_main_cpu->space(AS_PROGRAM); - - switch (offset) - { - case 0x00/2: // a15108 / 4008 - case 0x02/2: // a1510a / 400a - return m_dreq_src_addr[offset&1]; - - case 0x04/2: // a1510c / 400c - case 0x06/2: // a1510e / 400e - return m_dreq_dst_addr[offset&1]; - - case 0x08/2: // a15110 / 4010 - return m_dreq_size; - - case 0x0a/2: // a15112 / 4012 - if (&space == &_68kspace) - { - printf("attempting to READ FIFO with 68k!\n"); - return 0xffff; - } - - uint16_t retdat = m_current_fifo_readblock[m_current_fifo_read_pos]; - - m_current_fifo_read_pos++; - - // printf("reading FIFO!\n"); - - if (m_current_fifo_readblock == m_fifo_block_a && !m_fifo_block_a_full) - logerror("Fifo block a isn't filled!\n"); - - if (m_current_fifo_readblock == m_fifo_block_b && !m_fifo_block_b_full) - logerror("%s Fifo block b isn't filled!\n", machine().describe_context()); - - - if (m_current_fifo_read_pos==4) - { - if (m_current_fifo_readblock == m_fifo_block_a) - { - m_fifo_block_a_full = 0; - - if (m_fifo_block_b_full) - { - m_current_fifo_readblock = m_fifo_block_b; - m_current_fifo_block = m_fifo_block_a; - } - - m_current_fifo_read_pos = 0; - } - else if (m_current_fifo_readblock == m_fifo_block_b) - { - m_fifo_block_b_full = 0; - - if (m_fifo_block_a_full) - { - m_current_fifo_readblock = m_fifo_block_a; - m_current_fifo_block = m_fifo_block_b; - } - - m_current_fifo_read_pos = 0; - } - } - - return retdat; - } - - return 0x0000; -} - -void sega_32x_device::dreq_common_w(address_space &space, offs_t offset, uint16_t data) -{ - address_space& _68kspace = m_main_cpu->space(AS_PROGRAM); - - switch (offset) - { - case 0x00/2: // a15108 / 4008 - case 0x02/2: // a1510a / 400a - if (&space != &_68kspace) - { - printf("attempting to WRITE DREQ SRC with SH2!\n"); - return; - } - - m_dreq_src_addr[offset&1] = ((offset&1) == 0) ? (data & 0xff) : (data & 0xfffe); - - //if((m_dreq_src_addr[0]<<16)|m_dreq_src_addr[1]) - // printf("DREQ set SRC = %08x\n",(m_dreq_src_addr[0]<<16)|m_dreq_src_addr[1]); - - break; - - case 0x04/2: // a1510c / 400c - case 0x06/2: // a1510e / 400e - if (&space != &_68kspace) - { - printf("attempting to WRITE DREQ DST with SH2!\n"); - return; - } - - m_dreq_dst_addr[offset&1] = ((offset&1) == 0) ? (data & 0xff) : (data & 0xffff); - - //if((m_dreq_dst_addr[0]<<16)|m_dreq_dst_addr[1]) - // printf("DREQ set DST = %08x\n",(m_dreq_dst_addr[0]<<16)|m_dreq_dst_addr[1]); - - break; - - case 0x08/2: // a15110 / 4010 - if (&space != &_68kspace) - { - printf("attempting to WRITE DREQ SIZE with SH2!\n"); - return; - } - - m_dreq_size = data & 0xfffc; - - // if(m_dreq_size) - // printf("DREQ set SIZE = %04x\n",m_dreq_size); - - break; - - case 0x0a/2: // a15112 / 4012 - FIFO Write (68k only!) - if (&space != &_68kspace) - { - printf("attempting to WRITE FIFO with SH2!\n"); - return; - } - - if (m_current_fifo_block==m_fifo_block_a && m_fifo_block_a_full) - { - printf("attempt to write to Full Fifo block a!\n"); - return; - } - - if (m_current_fifo_block==m_fifo_block_b && m_fifo_block_b_full) - { - printf("attempt to write to Full Fifo block b!\n"); - return; - } - - if((m_a15106_reg & 4) == 0) - { - printf("attempting to WRITE FIFO with 68S cleared!\n"); // corpse32 - return; - } - - m_current_fifo_block[m_current_fifo_write_pos] = data; - m_current_fifo_write_pos++; - - if (m_current_fifo_write_pos==4) - { - if (m_current_fifo_block==m_fifo_block_a) - { - m_fifo_block_a_full = 1; - if (!m_fifo_block_b_full) - { - m_current_fifo_block = m_fifo_block_b; - m_current_fifo_readblock = m_fifo_block_a; - // incase we have a stalled DMA in progress, let the SH2 know there is data available - m_master_cpu->sh2_notify_dma_data_available(); - m_slave_cpu->sh2_notify_dma_data_available(); - - } - m_current_fifo_write_pos = 0; - } - else - { - m_fifo_block_b_full = 1; - - if (!m_fifo_block_a_full) - { - m_current_fifo_block = m_fifo_block_a; - m_current_fifo_readblock = m_fifo_block_b; - // incase we have a stalled DMA in progress, let the SH2 know there is data available - m_master_cpu->sh2_notify_dma_data_available(); - m_slave_cpu->sh2_notify_dma_data_available(); - } - - m_current_fifo_write_pos = 0; - } - } - - break; - } -} - - - - -uint16_t sega_32x_device::m68k_a1511a_r() -{ - return m_sega_tv; -} - -void sega_32x_device::m68k_a1511a_w(uint16_t data) -{ - m_sega_tv = data & 1; - - printf("SEGA TV register set = %04x\n",data); -} - -/* -000070 H interrupt vector can be overwritten apparently -*/ - - - -uint16_t sega_32x_device::m68k_m_hint_vector_r(offs_t offset) -{ - return m_hint_vector[offset]; -} - -void sega_32x_device::m68k_m_hint_vector_w(offs_t offset, uint16_t data) -{ - m_hint_vector[offset] = data; -} - -// returns MARS, the system ID of the 32x -uint16_t sega_32x_device::m68k_MARS_r(offs_t offset) -{ - switch (offset) - { - case 0: - return 0x4d41; - - case 1: - return 0x5253; - } - - return 0x0000; -} - - -/**********************************************************************************************/ -// 68k side a15100 -// control register - used to enable 32x etc. -/**********************************************************************************************/ - - - -uint16_t sega_32x_device::m68k_a15100_r() -{ - return (m_32x_access_auth<<15) | 0x0080; -} - -void sega_32x_device::m68k_a15100_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - { - m_a15100_reg = (m_a15100_reg & 0xff00) | (data & 0x00ff); - - if (data & 0x02) - { - m_master_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); - m_slave_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); - } - - if (data & 0x01) - { - m_32x_adapter_enabled = 1; - space.install_rom(0x0880000, 0x08fffff, machine().root_device().memregion("gamecart")->base()); // 'fixed' 512kb rom bank - - space.install_read_bank(0x0900000, 0x09fffff, m_rombank); // 'bankable' 1024kb rom bank - m_rombank->set_base(machine().root_device().memregion("gamecart")->base()+((m_32x_68k_a15104_reg&0x3)*0x100000) ); - - space.install_rom(0x0000000, 0x03fffff, machine().root_device().memregion("32x_68k_bios")->base()); - - /* VDP area */ - space.install_read_handler(0x0a15180, 0x0a1518b, read16sm_delegate(*this, FUNC(sega_32x_device::common_vdp_regs_r))); // common / shared VDP regs - space.install_write_handler(0x0a15180, 0x0a1518b, write16_delegate(*this, FUNC(sega_32x_device::common_vdp_regs_w))); // common / shared VDP regs - space.install_read_handler(0x0a15200, 0x0a153ff, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_palette_r))); // access to 'palette' xRRRRRGGGGGBBBBB - space.install_write_handler(0x0a15200, 0x0a153ff, write16s_delegate(*this, FUNC(sega_32x_device::m68k_palette_w))); // access to 'palette' xRRRRRGGGGGBBBBB - space.install_read_handler(0x0840000, 0x085ffff, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_dram_r))); // access to 'display ram' (framebuffer) - space.install_write_handler(0x0840000, 0x085ffff, write16s_delegate(*this, FUNC(sega_32x_device::m68k_dram_w))); // access to 'display ram' (framebuffer) - space.install_read_handler(0x0860000, 0x087ffff, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_dram_overwrite_r))); // access to 'display ram' (framebuffer) - space.install_write_handler(0x0860000, 0x087ffff, write16s_delegate(*this, FUNC(sega_32x_device::m68k_dram_overwrite_w))); // access to 'display ram' (framebuffer) - - - - m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0x000070, 0x000073, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_w))); // h interrupt vector - } - else - { - m_32x_adapter_enabled = 0; - - space.install_rom(0x0000000, 0x03fffff, machine().root_device().memregion("gamecart")->base()); - m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0x000070, 0x000073, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_w))); // h interrupt vector - } - } - - if (ACCESSING_BITS_8_15) - { - m_a15100_reg = (m_a15100_reg & 0x00ff) | (data & 0xff00); - m_32x_access_auth = (data & 0x8000)>>15; - } -} - -/**********************************************************************************************/ -// 68k side a15102 -// command interrupt to SH2 -/**********************************************************************************************/ - - - -uint16_t sega_32x_device::m68k_a15102_r() -{ - //printf("_32x_68k_a15102_r\n"); - return m_32x_68k_a15102_reg; -} - -void sega_32x_device::m68k_a15102_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - { - m_32x_68k_a15102_reg = data & 3; - - if (data&0x1) - { - if (m_sh2_master_cmdint_enable) m_master_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,ASSERT_LINE); - else printf("master cmdint when masked!\n"); - } - - if (data&0x2) - { - if (m_sh2_slave_cmdint_enable) m_slave_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,ASSERT_LINE); - else printf("slave cmdint when masked!\n"); - } - } -} - -/**********************************************************************************************/ -// 68k side a15104 -// ROM banking for 68k rom -/**********************************************************************************************/ - - -uint16_t sega_32x_device::m68k_a15104_r() -{ - return m_32x_68k_a15104_reg; -} - -void sega_32x_device::m68k_a15104_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - { - m_32x_68k_a15104_reg = (m_32x_68k_a15104_reg & 0xff00) | (data & 0x00ff); - } - - if (ACCESSING_BITS_8_15) - { - m_32x_68k_a15104_reg = (m_32x_68k_a15104_reg & 0x00ff) | (data & 0xff00); - } - - m_rombank->set_base(machine().root_device().memregion("gamecart")->base()+((m_32x_68k_a15104_reg&0x3)*0x100000) ); -} - -/**********************************************************************************************/ -// 68k side a15120 - a1512f -// Communication Port 0 -// access from the SH2 via 4020 - 402f -/**********************************************************************************************/ - - -/**********************************************************************************************/ - -// reads -uint16_t sega_32x_device::m68k_m_commsram_r(offs_t offset) -{ - if (_32X_COMMS_PORT_SYNC) machine().scheduler().synchronize(); - return m_commsram[offset]; -} - -// writes -void sega_32x_device::m68k_m_commsram_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - COMBINE_DATA(&m_commsram[offset]); - if (_32X_COMMS_PORT_SYNC) machine().scheduler().synchronize(); -} - -/**********************************************************************************************/ -// 68k side a15130 - a1513f -// PWM registers -// access from the SH2 via 4030 - 403f -/**********************************************************************************************/ - -/* -TODO: -- noticeable static noise on Virtua Fighter Sega logo at start-up -- Understand if Speaker OFF makes the FIFO to advance or not -- move inside a device -*/ - - - - -void sega_32x_device::calculate_pwm_timer() -{ - if(m_pwm_tm_reg == 0) { m_pwm_tm_reg = 16; } // zero gives max range - if(m_pwm_cycle == 0) { m_pwm_cycle = 4095; } // zero gives max range - - /* if both RMD and LMD are set to OFF or pwm cycle register is one, then PWM timer ticks doesn't occur */ - if(m_pwm_cycle == 1 || ((m_pwm_ctrl & 0xf) == 0)) - m_32x_pwm_timer->adjust(attotime::never); - else - { - m_pwm_timer_tick = 0; - m_lch_fifo_state = m_rch_fifo_state = 0x4000; - m_lch_size = m_rch_size = 0; - m_32x_pwm_timer->adjust(attotime::from_hz(clock() / (m_pwm_cycle - 1))); - } -} - -void sega_32x_device::lch_pop() -{ - for (int i = 0; i < PWM_FIFO_SIZE - 1; i++) - m_cur_lch[i] = m_cur_lch[i + 1]; - m_lch_size--; -} - -void sega_32x_device::rch_pop() -{ - for (int i = 0; i < PWM_FIFO_SIZE - 1; i++) - m_cur_rch[i] = m_cur_rch[i + 1]; - m_rch_size--; -} - -TIMER_CALLBACK_MEMBER(sega_32x_device::handle_pwm_callback) -{ - if (m_lch_size > 0) - { - m_stream->update(); - switch(m_pwm_ctrl & 3) - { - case 0: /*Speaker OFF*/ break; - case 1: m_ldac->write(m_cur_lch[0]); break; - case 2: m_rdac->write(m_cur_lch[0]); break; - case 3: popmessage("Undefined PWM Lch value 3, contact MESSdev"); break; - } - - lch_pop(); - } - - m_lch_fifo_state = (m_lch_size == 0) ? 0x4000 : 0x0000; - - if (m_rch_size > 0) - { - m_stream->update(); - switch((m_pwm_ctrl & 0xc) >> 2) - { - case 0: /*Speaker OFF*/ break; - case 1: m_rdac->write(m_cur_rch[0]); break; - case 2: m_ldac->write(m_cur_rch[0]); break; - case 3: popmessage("Undefined PWM Rch value 3, contact MESSdev"); break; - } - - rch_pop(); - } - - m_rch_fifo_state = (m_rch_size == 0) ? 0x4000 : 0x0000; - - m_pwm_timer_tick++; - - if(m_pwm_timer_tick == m_pwm_tm_reg) - { - m_pwm_timer_tick = 0; - if(sh2_master_pwmint_enable) { m_master_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,ASSERT_LINE); } - if(sh2_slave_pwmint_enable) { m_slave_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,ASSERT_LINE); } - } - - m_32x_pwm_timer->adjust(attotime::from_hz(clock() / (m_pwm_cycle - 1))); -} - -uint16_t sega_32x_device::pwm_r(offs_t offset) -{ - switch(offset) - { - case 0x00/2: return m_pwm_ctrl; //control register - case 0x02/2: return m_pwm_cycle_reg; // cycle register - case 0x04/2: return m_lch_fifo_state; // l ch - case 0x06/2: return m_rch_fifo_state; // r ch - case 0x08/2: return m_lch_fifo_state & m_rch_fifo_state; // mono ch - } - - printf("Read at undefined PWM register %02x\n",offset); - return 0xffff; -} - -void sega_32x_device::pwm_w(offs_t offset, uint16_t data) -{ - switch(offset) - { - case 0x00/2: - m_pwm_ctrl = data & 0xffff; - m_pwm_tm_reg = (m_pwm_ctrl & 0xf00) >> 8; - calculate_pwm_timer(); - break; - case 0x02/2: - m_pwm_cycle = m_pwm_cycle_reg = data & 0xfff; - calculate_pwm_timer(); - break; - case 0x04/2: - if (m_lch_size == PWM_FIFO_SIZE) - lch_pop(); - m_cur_lch[m_lch_size++] = data; - - m_lch_fifo_state = (m_lch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; - break; - case 0x06/2: - if (m_rch_size == PWM_FIFO_SIZE) - rch_pop(); - m_cur_rch[m_rch_size++] = data; - - m_rch_fifo_state = (m_rch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; - break; - case 0x08/2: - if (m_lch_size == PWM_FIFO_SIZE) - lch_pop(); - m_cur_lch[m_lch_size++] = data; - - if (m_rch_size == PWM_FIFO_SIZE) - rch_pop(); - m_cur_rch[m_rch_size++] = data; - - m_lch_fifo_state = (m_lch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; - m_rch_fifo_state = (m_rch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; - break; - default: - printf("Write at undefined PWM register %02x %04x\n",offset,data); - break; - } -} - -void sega_32x_device::m68k_pwm_w(offs_t offset, uint16_t data) -{ - if(offset == 0/2) - pwm_w(offset,(data & 0x7f) | (m_pwm_ctrl & 0xff80)); - else - pwm_w(offset,data); -} - -void sega_32x_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) -{ - outputs[0] = inputs[0]; - outputs[1] = inputs[1]; -} - -/**********************************************************************************************/ -// 68k side a15180 -// framebuffer control -// also accessed from the SH2 @ 4100 -/**********************************************************************************************/ - -uint16_t sega_32x_device::get_hposition(void) -{ - if (get_framerate() > 0.0) - { - attotime time_elapsed_since_megadriv_scanline_timer; - uint16_t value4; - - time_elapsed_since_megadriv_scanline_timer = m_scan_timer->time_elapsed(); - - if (time_elapsed_since_megadriv_scanline_timer.attoseconds() < (ATTOSECONDS_PER_SECOND/get_framerate() /double(m_total_scanlines))) - { - value4 = (uint16_t)(MAX_HPOSITION*((double)(time_elapsed_since_megadriv_scanline_timer.attoseconds()) / (double)(ATTOSECONDS_PER_SECOND/get_framerate() /double(m_total_scanlines)))); - } - else /* in some cases (probably due to rounding errors) we get some stupid results (the odd huge value where the time elapsed is much higher than the scanline time??!).. hopefully by clamping the result to the maximum we limit errors */ - { - value4 = MAX_HPOSITION; - } - - return value4; - } - return MAX_HPOSITION; -} - -uint16_t sega_32x_device::common_vdp_regs_r(offs_t offset) -{ - // what happens if the z80 accesses it, what authorization do we use? - - int ntsc; - -// printf("_32x_68k_a15180_r (a15180) %04x\n",mem_mask); - - // read needs authorization too I think, undefined behavior otherwise - switch (offset) - { - case 0x00: - - // the flag is inverted compared to the megadrive - ntsc = m_32x_pal ? 0 : 1; - - return (ntsc << 15) | - (m_32x_videopriority << 7) | - (m_32x_240mode << 6) | - (m_32x_displaymode << 0); - - case 0x02/2: - return m_32x_screenshift; - - case 0x04/2: - return m_32x_autofill_length; - - case 0x06/2: - return m_32x_autofill_address; - - case 0x08/2: - return m_32x_autofill_data; - - case 0x0a/2: - uint16_t retdata = m_32x_a1518a_reg; - uint16_t hpos = get_hposition(); - int megadrive_hblank_flag = 0; - - if (m_32x_vblank_flag) retdata |= 0x8000; - - if (hpos>400) megadrive_hblank_flag = 1; - if (hpos>460) megadrive_hblank_flag = 0; - - if (megadrive_hblank_flag) retdata |= 0x4000; - - if (m_32x_vblank_flag) { retdata |= 2; } // framebuffer approval (TODO: condition is unknown at current time) - - if (megadrive_hblank_flag && m_32x_vblank_flag) { retdata |= 0x2000; } // palette approval (TODO: active high or low?) - - return retdata; - } - - return 0x0000; -} - - -void sega_32x_device::check_framebuffer_swap(bool enabled) -{ - // this logic should be correct, but makes things worse? - // enabled = (genesis_scanline_counter >= megadrive_irq6_scanline) from video/315_5313.cpp - //if (enabled) - { - m_32x_a1518a_reg = m_32x_fb_swap & 1; - - if (m_32x_fb_swap & 1) - { - m_32x_access_dram = m_32x_dram0.get(); - m_32x_display_dram = m_32x_dram1.get(); - } - else - { - m_32x_display_dram = m_32x_dram0.get(); - m_32x_access_dram = m_32x_dram1.get(); - } - } -} - - -void sega_32x_device::common_vdp_regs_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask) -{ - // what happens if the z80 accesses it, what authorization do we use? which address space do we get?? the z80 *can* write here and to the framebuffer via the window - - address_space& _68kspace = m_main_cpu->space(AS_PROGRAM); - - if (&space!= &_68kspace) - { - if (m_32x_access_auth!=1) - return; - } - - if (&space== &_68kspace) - { - if (m_32x_access_auth!=0) - return; - } - - - switch (offset) - { - case 0x00: - //printf("_32x_68k_a15180_w (a15180) %04x %04x source m_32x_access_auth %04x\n",data,mem_mask, m_32x_access_auth); - - if (ACCESSING_BITS_0_7) - { - m_32x_videopriority = (data & 0x80) >> 7; - m_32x_240mode = (data & 0x40) >> 6; - m_32x_displaymode = (data & 0x03) >> 0; - } - break; - - case 0x02/2: - if (ACCESSING_BITS_0_7) - { - m_32x_screenshift = data & 1; // allows 1 pixel shifting - } - if (ACCESSING_BITS_8_15) - { - } - break; - - case 0x04/2: - if (ACCESSING_BITS_0_7) - { - m_32x_autofill_length = data & 0xff; - } - - if (ACCESSING_BITS_8_15) - { - } - break; - - case 0x06/2: - if (ACCESSING_BITS_0_7) - { - m_32x_autofill_address = (m_32x_autofill_address & 0xff00) | (data & 0x00ff); - } - - if (ACCESSING_BITS_8_15) - { - m_32x_autofill_address = (m_32x_autofill_address & 0x00ff) | (data & 0xff00); - } - break; - - case 0x08/2: - if (ACCESSING_BITS_0_7) - { - m_32x_autofill_data = (m_32x_autofill_data & 0xff00) | (data & 0x00ff); - } - - if (ACCESSING_BITS_8_15) - { - m_32x_autofill_data = (m_32x_autofill_data & 0x00ff) | (data & 0xff00); - } - - // do the fill - shouldn't be instant.. - { - int i; - for (i=0; i> 15; - } - - if (ACCESSING_BITS_0_7) - { - m_sh2_hint_in_vbl = data & 0x80; - m_sh2_master_vint_enable = data & 0x8; - m_sh2_master_hint_enable = data & 0x4; - m_sh2_master_cmdint_enable = data & 0x2; - sh2_master_pwmint_enable = data & 0x1; - - //if (m_sh2_master_hint_enable) printf("m_sh2_master_hint_enable enable!\n"); - //if (sh2_master_pwmint_enable) printf("sh2_master_pwn_enable enable!\n"); - - check_irqs(); - } -} - -/* SLAVE */ - -uint16_t sega_32x_device::slave_4000_r() -{ - uint16_t retvalue = 0x0200; - retvalue |= m_32x_access_auth << 15; - retvalue |= m_sh2_hint_in_vbl; - retvalue |= m_sh2_slave_vint_enable; - retvalue |= m_sh2_slave_hint_enable; - retvalue |= m_sh2_slave_cmdint_enable; - retvalue |= sh2_slave_pwmint_enable; - - return retvalue; -} - - -void sega_32x_device::slave_4000_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (ACCESSING_BITS_8_15) - { - m_32x_access_auth = (data &0x8000) >> 15; - } - - if (ACCESSING_BITS_0_7) - { - m_sh2_hint_in_vbl = data & 0x80; - m_sh2_slave_vint_enable = data & 0x8; - m_sh2_slave_hint_enable = data & 0x4; - m_sh2_slave_cmdint_enable = data & 0x2; - sh2_slave_pwmint_enable = data & 0x1; - - //if (m_sh2_slave_hint_enable) printf("m_sh2_slave_hint_enable enable!\n"); - //if (sh2_slave_pwmint_enable) printf("sh2_slave_pwm_enable enable!\n"); - - check_irqs(); - } -} - -/**********************************************************************************************/ -// SH2 side 4002 -// Reserved ( Stand By Change Register ) -// Shouldn't be used -/**********************************************************************************************/ - -uint16_t sega_32x_device::common_4002_r() -{ - printf("reading 4002!\n"); - return 0x0000; -} - -void sega_32x_device::common_4002_w(uint16_t data) -{ - printf("write 4002!\n"); -} - - -/**********************************************************************************************/ -// SH2 side 4004 -// H Count Register (H Interrupt) -// 0 = every line -/**********************************************************************************************/ -uint16_t sega_32x_device::common_4004_r() -{ - return m_32x_hcount_reg; -} - -void sega_32x_device::common_4004_w(uint16_t data) -{ - m_32x_hcount_reg = data & 0xff; -} - - -/**********************************************************************************************/ -// SH2 side 4006 -// DReq Control Register -/**********************************************************************************************/ - -uint16_t sega_32x_device::common_4006_r() -{ - //printf("DREQ read!\n"); // tempo reads it, shut up for now - return m68k_a15106_r(); -} - -void sega_32x_device::common_4006_w(uint16_t data) -{ - printf("DREQ write!\n"); //register is read only on SH-2 side -} - - -/**********************************************************************************************/ -// SH2 side 4014 -// VRES (md reset button interrupt) clear -/**********************************************************************************************/ - -void sega_32x_device::master_4014_w(uint16_t data){ m_master_cpu->set_input_line(SH2_VRES_IRQ_LEVEL,CLEAR_LINE);} -void sega_32x_device::slave_4014_w(uint16_t data) { m_slave_cpu->set_input_line(SH2_VRES_IRQ_LEVEL,CLEAR_LINE);} - -/**********************************************************************************************/ -// SH2 side 4016 -// VINT (vertical interrupt) clear -/**********************************************************************************************/ - -void sega_32x_device::master_4016_w(uint16_t data){ m_sh2_master_vint_pending = 0; check_irqs(); } -void sega_32x_device::slave_4016_w(uint16_t data) { m_sh2_slave_vint_pending = 0; check_irqs(); } - -/**********************************************************************************************/ -// SH2 side 4018 -// HINT (horizontal interrupt) clear -/**********************************************************************************************/ - -void sega_32x_device::master_4018_w(uint16_t data){ m_master_cpu->set_input_line(SH2_HINT_IRQ_LEVEL,CLEAR_LINE);} -void sega_32x_device::slave_4018_w(uint16_t data) { m_slave_cpu->set_input_line(SH2_HINT_IRQ_LEVEL,CLEAR_LINE);} - -/**********************************************************************************************/ -// SH2 side 401A -// HINT (control register interrupt) clear -// Note: flag cleared here is a guess, according to After Burner behaviour -/**********************************************************************************************/ - -void sega_32x_device::master_401a_w(uint16_t data){ m_32x_68k_a15102_reg &= ~1; m_master_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,CLEAR_LINE);} -void sega_32x_device::slave_401a_w(uint16_t data) { m_32x_68k_a15102_reg &= ~2; m_slave_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,CLEAR_LINE);} - -/**********************************************************************************************/ -// SH2 side 401C -// PINT (PWM timer interrupt) clear -/**********************************************************************************************/ - -void sega_32x_device::master_401c_w(uint16_t data){ m_master_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,CLEAR_LINE);} -void sega_32x_device::slave_401c_w(uint16_t data) { m_slave_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,CLEAR_LINE);} - -/**********************************************************************************************/ -// SH2 side 401E -// ?? unknown / unused -/**********************************************************************************************/ - -void sega_32x_device::master_401e_w(uint16_t data) -{ - printf("master_401e_w\n"); -} - -void sega_32x_device::slave_401e_w(uint16_t data) -{ - printf("slave_401e_w\n"); -} - -/**********************************************************************************************/ -// SH2 side 4020 - 402f -// SH2 -> 68k Comms ports, -// access at a15120 - a1512f on 68k -// these just map through to the 68k functions -/**********************************************************************************************/ - -/* handled directly */ - -/**********************************************************************************************/ -// SH2 side 4030 -// PWM Control Register -/**********************************************************************************************/ - -/**********************************************************************************************/ -// SH2 side 4032 -// Cycle Register -/**********************************************************************************************/ - - -/**********************************************************************************************/ -// SH2 side 4034 -// LCH Pulse Width Register -/**********************************************************************************************/ - -/**********************************************************************************************/ -// SH2 side 4036 -// RCH Pulse Width Register -/**********************************************************************************************/ - -/**********************************************************************************************/ -// SH2 side 4038 -// Mono Pulse Width Register -/**********************************************************************************************/ - -/* 4100 - 43ff are VDP registers, you need permission to access them - ensure this is true for all! */ - -/**********************************************************************************************/ -// SH2 side 4200 - 43ff -// palette -// maps through to 68k at a15200 - a153ff -/**********************************************************************************************/ - -/* handled directly */ - -/**********************************************************************************************/ -// SH2 side 4000000 - 401ffff -// framebuffer -// maps through to 68k at 840000 - 85ffff -/**********************************************************************************************/ - -/* handled directly */ - -/**********************************************************************************************/ -// SH2 side 4020000 - 403ffff -// framebuffer overwrite -// maps through to 68k at 860000 - 87ffff -/**********************************************************************************************/ - -/* handled directly */ - - -/**********************************************************************************************/ -// SH2 memory maps -/**********************************************************************************************/ - -void sega_32x_device::sh2_common_map(address_map &map) -{ - map(0x00004002, 0x00004003).rw(FUNC(sega_32x_device::common_4002_r), FUNC(sega_32x_device::common_4002_w)); - map(0x00004004, 0x00004005).rw(FUNC(sega_32x_device::common_4004_r), FUNC(sega_32x_device::common_4004_w)); - map(0x00004006, 0x00004007).rw(FUNC(sega_32x_device::common_4006_r), FUNC(sega_32x_device::common_4006_w)); - - map(0x00004008, 0x00004013).rw(FUNC(sega_32x_device::dreq_common_r), FUNC(sega_32x_device::dreq_common_w)); - - map(0x00004014, 0x0000401f).nopr(); - - map(0x00004020, 0x0000402f).rw(FUNC(sega_32x_device::m68k_m_commsram_r), FUNC(sega_32x_device::m68k_m_commsram_w)); - map(0x00004030, 0x0000403f).rw(FUNC(sega_32x_device::pwm_r), FUNC(sega_32x_device::pwm_w)); - - map(0x00004100, 0x0000410b).rw(FUNC(sega_32x_device::common_vdp_regs_r), FUNC(sega_32x_device::common_vdp_regs_w)); - map(0x00004200, 0x000043ff).rw(FUNC(sega_32x_device::m68k_palette_r), FUNC(sega_32x_device::m68k_palette_w)); - - map(0x04000000, 0x0401ffff).rw(FUNC(sega_32x_device::m68k_dram_r), FUNC(sega_32x_device::m68k_dram_w)); - map(0x04020000, 0x0403ffff).rw(FUNC(sega_32x_device::m68k_dram_overwrite_r), FUNC(sega_32x_device::m68k_dram_overwrite_w)); - - map(0x06000000, 0x0603ffff).ram().share("sh2_shared"); - - map(0x02000000, 0x023fffff).rom().region(":gamecart_sh2", 0); - map(0x22000000, 0x223fffff).rom().region(":gamecart_sh2", 0); // cart mirror (fifa96) - - map(0xc0000000, 0xc0000fff).ram(); -} - -void sega_32x_device::sh2_main_map(address_map &map) -{ - sh2_common_map(map); - map(0x00000000, 0x00003fff).bankr("masterbios"); - - map(0x00004000, 0x00004001).rw(FUNC(sega_32x_device::master_4000_r), FUNC(sega_32x_device::master_4000_w)); - - map(0x00004014, 0x00004015).w(FUNC(sega_32x_device::master_4014_w)); - map(0x00004016, 0x00004017).w(FUNC(sega_32x_device::master_4016_w)); - map(0x00004018, 0x00004019).w(FUNC(sega_32x_device::master_4018_w)); - map(0x0000401a, 0x0000401b).w(FUNC(sega_32x_device::master_401a_w)); - map(0x0000401c, 0x0000401d).w(FUNC(sega_32x_device::master_401c_w)); - map(0x0000401e, 0x0000401f).w(FUNC(sega_32x_device::master_401e_w)); -} - -void sega_32x_device::sh2_slave_map(address_map &map) -{ - sh2_common_map(map); - map(0x00000000, 0x00003fff).bankr("slavebios"); - - map(0x00004000, 0x00004001).rw(FUNC(sega_32x_device::slave_4000_r), FUNC(sega_32x_device::slave_4000_w)); - - map(0x00004014, 0x00004015).w(FUNC(sega_32x_device::slave_4014_w)); - map(0x00004016, 0x00004017).w(FUNC(sega_32x_device::slave_4016_w)); - map(0x00004018, 0x00004019).w(FUNC(sega_32x_device::slave_4018_w)); - map(0x0000401a, 0x0000401b).w(FUNC(sega_32x_device::slave_401a_w)); - map(0x0000401c, 0x0000401d).w(FUNC(sega_32x_device::slave_401c_w)); - map(0x0000401e, 0x0000401f).w(FUNC(sega_32x_device::slave_401e_w)); -} - -/****************************************** END 32X related *************************************/ - - - - -void sega_32x_device::check_irqs() -{ - if (m_sh2_master_vint_enable && m_sh2_master_vint_pending) m_master_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,ASSERT_LINE); - else m_master_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,CLEAR_LINE); - - if (m_sh2_slave_vint_enable && m_sh2_slave_vint_pending) m_slave_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,ASSERT_LINE); - else m_slave_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,CLEAR_LINE); -} - -void sega_32x_device::interrupt_cb(int scanline, int irq6) -{ - if (scanline == irq6) - { - m_32x_vblank_flag = 1; - m_sh2_master_vint_pending = 1; - m_sh2_slave_vint_pending = 1; - check_irqs(); - } - - check_framebuffer_swap(scanline >= irq6); - - m_32x_hcount_compare_val++; - - if (m_32x_hcount_compare_val >= m_32x_hcount_reg) - { - m_32x_hcount_compare_val = -1; - - if (scanline < 224 || m_sh2_hint_in_vbl) - { - if (m_sh2_master_hint_enable) - m_master_cpu->set_input_line(SH2_HINT_IRQ_LEVEL, ASSERT_LINE); - if (m_sh2_slave_hint_enable) - m_slave_cpu->set_input_line(SH2_HINT_IRQ_LEVEL, ASSERT_LINE); - } - } -} - - -SH2_DMA_FIFO_DATA_AVAILABLE_CB(sega_32x_device::_32x_fifo_available_callback) -{ - if (src==0x4012) - { - if (m_current_fifo_readblock==m_fifo_block_a && m_fifo_block_a_full) - return 1; - - if (m_current_fifo_readblock==m_fifo_block_b && m_fifo_block_b_full) - return 1; - - return 0; - } - - return 1; -} - - - -void sega_32x_device::render_videobuffer_to_screenbuffer_helper(int scanline) -{ - int x; - - /* render 32x output to a buffer */ - if (m_32x_displaymode != 0) - { - if (m_32x_displaymode==1) - { - uint32_t lineoffs; - int start; - - lineoffs = m_32x_display_dram[scanline]; - - if (m_32x_screenshift == 0) start=0; - else start = -1; - - for (x=start;x<320;x++) - { - uint16_t coldata; - coldata = m_32x_display_dram[lineoffs]; - - { - if (x>=0) - { - m_32x_linerender[x] = m_32x_palette[(coldata & 0xff00)>>8]; - } - - x++; - - if (x>=0) - { - m_32x_linerender[x] = m_32x_palette[(coldata & 0x00ff)]; - } - } - - lineoffs++; - - } - } - else if (m_32x_displaymode==3) // mode 3 = RLE (used by BRUTAL intro) - { - uint32_t lineoffs; - int start; - - lineoffs = m_32x_display_dram[scanline]; - - if (m_32x_screenshift == 0) start=0; - else start = -1; - - x = start; - while (x<320) - { - uint16_t coldata, length, l; - coldata = m_32x_display_dram[lineoffs]; - length = ((coldata & 0xff00)>>8)+1; - coldata = (coldata & 0x00ff)>>0; - for (l=0;l=0) - { - m_32x_linerender[x] = m_32x_palette[(coldata)]; - } - x++; - } - - lineoffs++; - - } - } - else // MODE 2 - 15bpp mode, not used by any commercial games? - { - uint32_t lineoffs; - int start; - - lineoffs = m_32x_display_dram[scanline]; - - if (m_32x_screenshift == 0) start=0; - else start = -1; - - x = start; - while (x<320) - { - if (x>=0) - m_32x_linerender[x] = m_32x_display_dram[lineoffs&0xffff]; - - x++; - lineoffs++; - } - } - } -} - -void sega_32x_device::render_videobuffer_to_screenbuffer(int x, uint32_t priority, uint32_t &lineptr) -{ - if (m_32x_displaymode != 0) - { - if (!m_32x_videopriority) - { - if (priority && !(m_32x_linerender[x] & 0x8000)) - lineptr = pen(m_32x_linerender[x] & 0x7fff); - if (m_32x_linerender[x] & 0x8000) - lineptr = pen(m_32x_linerender[x] & 0x7fff); - } - else - { - if (priority && m_32x_linerender[x] & 0x8000) - lineptr = pen(m_32x_linerender[x] & 0x7fff); - if (!(m_32x_linerender[x] & 0x8000)) - lineptr = pen(m_32x_linerender[x] & 0x7fff); - } - } -} - -#if 0 -// for now we just use the regular loading because we have 2 different BIOS roms, and you can't use -bios within a device for obvious reasons -ROM_START( 32x ) - ROM_REGION( 0x400000, "32x_master_sh2", 0 ) - ROM_REGION( 0x400000, "32x_slave_sh2", 0 ) -ROM_END - -const rom_entry *sega_32x_device::device_rom_region() const -{ - return ROM_NAME( 32x ); -} -#endif - - -// brutal needs high levels of interleave or the background animations don't work -// and some stages simply freeze the game, the is not good for performance however. -// -// some games appear to dislike 'perfect' levels of interleave, probably due to -// non-emulated cache, ram waitstates and other issues? -#define _32X_INTERLEAVE_LEVEL \ - config.set_maximum_quantum(attotime::from_hz(1800000)); - -void sega_32x_device::device_add_mconfig(machine_config &config) -{ -#ifndef _32X_SWAP_MASTER_SLAVE_HACK - SH2(config, m_master_cpu, DERIVED_CLOCK(1, 1)); - m_master_cpu->set_is_slave(0); - m_master_cpu->set_dma_fifo_data_available_callback(FUNC(sega_32x_device::_32x_fifo_available_callback)); -#endif - - SH2(config, m_slave_cpu, DERIVED_CLOCK(1, 1)); - m_slave_cpu->set_is_slave(1); - m_slave_cpu->set_dma_fifo_data_available_callback(FUNC(sega_32x_device::_32x_fifo_available_callback)); - -#ifdef _32X_SWAP_MASTER_SLAVE_HACK - SH2(config, m_master_cpu, DERIVED_CLOCK(1, 1)); - m_master_cpu->set_is_slave(0); - m_master_cpu->set_dma_fifo_data_available_callback(FUNC(sega_32x_device::_32x_fifo_available_callback)); -#endif - - _32X_INTERLEAVE_LEVEL -} - -void sega_32x_ntsc_device::device_add_mconfig(machine_config &config) -{ - sega_32x_device::device_add_mconfig(config); - - m_master_cpu->set_addrmap(AS_PROGRAM, &sega_32x_ntsc_device::sh2_main_map); - m_slave_cpu->set_addrmap(AS_PROGRAM, &sega_32x_ntsc_device::sh2_slave_map); - - DAC_12BIT_R2R(config, m_ldac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 0); // unknown DAC - DAC_12BIT_R2R(config, m_rdac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 1); // unknown DAC -} - -void sega_32x_pal_device::device_add_mconfig(machine_config &config) -{ - sega_32x_device::device_add_mconfig(config); - - m_master_cpu->set_addrmap(AS_PROGRAM, &sega_32x_pal_device::sh2_main_map); - m_slave_cpu->set_addrmap(AS_PROGRAM, &sega_32x_pal_device::sh2_slave_map); - - DAC_16BIT_R2R(config, m_ldac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 0); // unknown DAC - DAC_16BIT_R2R(config, m_rdac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 1); // unknown DAC -} - - -void sega_32x_device::device_start() -{ - for (int i = 0; i < 32*32*32/**2*/; i++) - { - int r = (i >> 0) & 0x1f; - int g = (i >> 5) & 0x1f; - int b = (i >> 10) & 0x1f; - //int p = (i >> 15) & 0x01; // priority 'through' bit - set_pen_color(i, pal5bit(r), pal5bit(g), pal5bit(b)); - } - - m_stream = stream_alloc(2, 2, 48000 * 4); - m_32x_pwm_timer = timer_alloc(FUNC(sega_32x_device::handle_pwm_callback), this); - - m_32x_dram0 = std::make_unique(0x40000/2); - m_32x_dram1 = std::make_unique(0x40000/2); - - memset(m_32x_dram0.get(), 0x00, 0x40000); - memset(m_32x_dram1.get(), 0x00, 0x40000); - - m_32x_palette = std::make_unique(0x200/2); - - memset(m_32x_palette.get(), 0x00, 0x200); - - m_32x_display_dram = m_32x_dram0.get(); - m_32x_access_dram = m_32x_dram1.get(); -} - -void sega_32x_device::device_reset() -{ - /* Interrupts are masked / disabled at first */ - m_sh2_master_vint_enable = m_sh2_slave_vint_enable = 0; - m_sh2_master_hint_enable = m_sh2_slave_hint_enable = 0; - m_sh2_master_cmdint_enable = m_sh2_slave_cmdint_enable = 0; - sh2_master_pwmint_enable = sh2_slave_pwmint_enable = 0; - m_sh2_master_vint_pending = m_sh2_slave_vint_pending = 0; - m_sh2_hint_in_vbl = 0; - - // start in a reset state - m_sh2_are_running = 0; - - m_32x_a1518a_reg = 0x00; // initial value - m_32x_68k_a15104_reg = 0x00; - - m_32x_autofill_length = 0; - m_32x_autofill_address = 0; - m_32x_autofill_data = 0; - m_32x_screenshift = 0; - m_32x_videopriority = 0; // MD priority - m_32x_displaymode = 0; - m_32x_240mode = 0; - - m_current_fifo_block = m_fifo_block_a; - m_current_fifo_readblock = m_fifo_block_b; - m_current_fifo_write_pos = 0; - m_current_fifo_read_pos = 0; - m_fifo_block_a_full = 0; - m_fifo_block_b_full = 0; - - m_32x_hcount_compare_val = -1; - m_32x_hcount_reg = 0; - - m_32x_fb_swap = 0; - - m_pwm_tm_reg = 0; - m_pwm_cycle = m_pwm_cycle_reg = 0; - m_pwm_ctrl = 0; - calculate_pwm_timer(); - - m_lch_size = 0; - m_rch_size = 0; - - m_total_scanlines = 262; - -// moved from init - - m_32x_adapter_enabled = 0; - m_32x_access_auth = 0; - - if (m_32x_adapter_enabled == 0) - { - m_main_cpu->space(AS_PROGRAM).install_rom(0x0000000, 0x03fffff, machine().root_device().memregion(":gamecart")->base()); - m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0x000070, 0x000073, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_w))); // h interrupt vector - }; - - - m_a15100_reg = 0x0000; - m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15100, 0xa15101, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15100_r))); // framebuffer control regs - m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15100, 0xa15101, write16_delegate(*this, FUNC(sega_32x_device::m68k_a15100_w))); // framebuffer control regs - m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15102, 0xa15103, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15102_r))); // send irq to sh2 - m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15102, 0xa15103, write16s_delegate(*this, FUNC(sega_32x_device::m68k_a15102_w))); // send irq to sh2 - m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15104, 0xa15105, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15104_r))); // 68k BANK rom set - m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15104, 0xa15105, write16s_delegate(*this, FUNC(sega_32x_device::m68k_a15104_w))); // 68k BANK rom set - m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15106, 0xa15107, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15106_r))); // dreq stuff - m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15106, 0xa15107, write16_delegate(*this, FUNC(sega_32x_device::m68k_a15106_w))); // dreq stuff - m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0xa15108, 0xa15113, read16m_delegate(*this, FUNC(sega_32x_device::dreq_common_r)), write16m_delegate(*this, FUNC(sega_32x_device::dreq_common_w))); // dreq src / dst / length /fifo - - m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0xa1511a, 0xa1511b, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a1511a_r)), write16smo_delegate(*this, FUNC(sega_32x_device::m68k_a1511a_w))); // SEGA TV - - m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15120, 0xa1512f, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_commsram_r))); // comms reg 0-7 - m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15120, 0xa1512f, write16s_delegate(*this, FUNC(sega_32x_device::m68k_m_commsram_w))); // comms reg 0-7 - m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0xa15130, 0xa1513f, read16sm_delegate(*this, FUNC(sega_32x_device::pwm_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_pwm_w))); - - m_main_cpu->space(AS_PROGRAM).install_read_handler(0x0a130ec, 0x0a130ef, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_MARS_r))); // system ID - - - -// checking if these help brutal, they don't. - m_master_cpu->sh2drc_set_options(SH2DRC_COMPATIBLE_OPTIONS); - m_slave_cpu->sh2drc_set_options(SH2DRC_COMPATIBLE_OPTIONS); - - uint32_t *cart = (uint32_t *)memregion(":gamecart_sh2")->base(); - - m_master_cpu->sh2drc_add_fastram(0x06000000, 0x0603ffff, 0, &m_sh2_shared[0]); - m_master_cpu->sh2drc_add_fastram(0x02000000, 0x023fffff, 0, cart); - m_master_cpu->sh2drc_add_fastram(0x22000000, 0x223fffff, 0, cart); - m_slave_cpu->sh2drc_add_fastram(0x06000000, 0x0603ffff, 0, &m_sh2_shared[0]); - m_slave_cpu->sh2drc_add_fastram(0x02000000, 0x023fffff, 0, cart); - m_slave_cpu->sh2drc_add_fastram(0x22000000, 0x223fffff, 0, cart); - - -// install these now, otherwise we'll get the following (incorrect) warnings on startup.. -// SH-2 device ':sega32x:32x_slave_sh2': program space memory map entry 0-3FFF references non-existent region ':slave' -// SH-2 device ':sega32x:32x_master_sh2': program space memory map entry 0-3FFF references non-existent region ':master' - uint8_t* masterbios = (uint8_t*)machine().root_device().memregion(":master")->base(); - uint8_t* slavebios = (uint8_t*)machine().root_device().memregion(":slave")->base(); - membank("masterbios")->configure_entries(0, 1, masterbios, 0x4000); - membank("slavebios")->configure_entries(0, 1, slavebios, 0x4000); - membank("masterbios")->set_entry(0); - membank("slavebios")->set_entry(0); -} - -// if the system has a 32x, the extra CPUs are paused at start -void sega_32x_device::pause_cpu() -{ - m_master_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); - m_slave_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); -} diff --git a/src/mame/messshared/mega32x.h b/src/mame/messshared/mega32x.h deleted file mode 100644 index 5d07d35df4d..00000000000 --- a/src/mame/messshared/mega32x.h +++ /dev/null @@ -1,242 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:David Haywood -/* 32X */ -#ifndef MAME_MACHINE_MEGA32X_H -#define MAME_MACHINE_MEGA32X_H - -#pragma once - -#include "cpu/m68000/m68000.h" -#include "cpu/sh/sh2.h" -#include "cpu/sh/sh2comn.h" -#include "machine/timer.h" -#include "sound/dac.h" -#include "emupal.h" -#include "screen.h" - -class sega_32x_device : public device_t, public device_palette_interface, public device_sound_interface, public device_video_interface -{ -public: - void pause_cpu(); - - // set some variables at start, depending on region (shall be moved to a device interface?) - void set_framerate(int rate) { m_framerate = rate; } - void set_32x_pal(bool pal) { m_32x_pal = pal ? 1 : 0; } - void set_total_scanlines(int total) { m_base_total_scanlines = total; } // this get set at start only - double get_framerate() { return has_screen() ? screen().frame_period().as_hz() : double(m_framerate); } - - void screen_eof(bool mode3) - { - m_32x_vblank_flag = 0; - m_32x_hcount_compare_val = -1; - update_total_scanlines(mode3); - } - - uint16_t m68k_palette_r(offs_t offset); - void m68k_palette_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t m68k_dram_r(offs_t offset); - void m68k_dram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t m68k_dram_overwrite_r(offs_t offset); - void m68k_dram_overwrite_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t m68k_a15106_r(); - void m68k_a15106_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t dreq_common_r(address_space &space, offs_t offset); - void dreq_common_w(address_space &space, offs_t offset, uint16_t data); - uint16_t m68k_a1511a_r(); - void m68k_a1511a_w(uint16_t data); - uint16_t m68k_m_hint_vector_r(offs_t offset); - void m68k_m_hint_vector_w(offs_t offset, uint16_t data); - uint16_t m68k_MARS_r(offs_t offset); - uint16_t m68k_a15100_r(); - void m68k_a15100_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t m68k_a15102_r(); - void m68k_a15102_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t m68k_a15104_r(); - void m68k_a15104_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t m68k_m_commsram_r(offs_t offset); - void m68k_m_commsram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t pwm_r(offs_t offset); - void pwm_w(offs_t offset, uint16_t data); - void m68k_pwm_w(offs_t offset, uint16_t data); - uint16_t common_vdp_regs_r(offs_t offset); - void common_vdp_regs_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t master_4000_r(); - void master_4000_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t slave_4000_r(); - void slave_4000_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t common_4002_r(); - void common_4002_w(uint16_t data); - uint16_t common_4004_r(); - void common_4004_w(uint16_t data); - uint16_t common_4006_r(); - void common_4006_w(uint16_t data); - void master_4014_w(uint16_t data); - void slave_4014_w(uint16_t data); - void master_4016_w(uint16_t data); - void slave_4016_w(uint16_t data); - void master_4018_w(uint16_t data); - void slave_4018_w(uint16_t data); - void master_401a_w(uint16_t data); - void slave_401a_w(uint16_t data); - void master_401c_w(uint16_t data); - void slave_401c_w(uint16_t data); - void master_401e_w(uint16_t data); - void slave_401e_w(uint16_t data); - - SH2_DMA_FIFO_DATA_AVAILABLE_CB(_32x_fifo_available_callback); - - void render_videobuffer_to_screenbuffer_helper(int scanline); - void render_videobuffer_to_screenbuffer(int x, uint32_t priority, uint32_t &lineptr); - int sh2_master_pwmint_enable = 0, sh2_slave_pwmint_enable = 0; - - void check_framebuffer_swap(bool enabled); - void check_irqs(); - void interrupt_cb(int scanline, int irq6); - - void sh2_main_map(address_map &map); - void sh2_slave_map(address_map &map); - void sh2_common_map(address_map &map); - -protected: - sega_32x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - - required_shared_ptr m_sh2_shared; - - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_add_mconfig(machine_config &config) override; - - // device_palette_interface overrides - virtual uint32_t palette_entries() const override { return 32*32*32/**2*/; } - - // device_sound_interface overrides - virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; - - void update_total_scanlines(bool mode3) { m_total_scanlines = mode3 ? (m_base_total_scanlines * 2) : m_base_total_scanlines; } // this gets set at each EOF - - /* our main vblank handler resets this */ - required_device m_main_cpu; - required_device m_master_cpu; - required_device m_slave_cpu; - required_device m_ldac; - required_device m_rdac; - required_device m_scan_timer; - memory_bank_creator m_rombank; - - int m_32x_hcount_compare_val = 0; - int m_32x_vblank_flag = 0; - int m_sh2_are_running = 0; - int m_32x_240mode = 0; - uint16_t m_32x_a1518a_reg = 0; - - sound_stream *m_stream = nullptr; - TIMER_CALLBACK_MEMBER(handle_pwm_callback); - void calculate_pwm_timer(); - uint16_t m_pwm_ctrl = 0, m_pwm_cycle = 0, m_pwm_tm_reg = 0; - static constexpr int PWM_FIFO_SIZE = 3; - uint16_t m_cur_lch[PWM_FIFO_SIZE]{},m_cur_rch[PWM_FIFO_SIZE]{}; - uint16_t m_pwm_cycle_reg = 0; //used for latching - uint8_t m_pwm_timer_tick = 0; - uint8_t m_lch_size = 0, m_rch_size = 0; - uint16_t m_lch_fifo_state = 0, m_rch_fifo_state = 0; - - void lch_pop(); - void rch_pop(); - - uint16_t get_hposition(void); - - emu_timer *m_32x_pwm_timer = nullptr; - -private: - - int m_32x_displaymode = 0; - int m_32x_videopriority = 0; - uint32_t m_32x_linerender[320+258]{}; // tmp buffer (bigger than it needs to be to simplify RLE decode) - - int m_32x_adapter_enabled = 0; - int m_32x_access_auth = 0; - int m_32x_screenshift = 0; - - uint16_t m_32x_68k_a15104_reg = 0; - int m_sh2_master_vint_enable = 0, m_sh2_slave_vint_enable = 0; - int m_sh2_master_hint_enable = 0, m_sh2_slave_hint_enable = 0; - int m_sh2_master_cmdint_enable = 0, m_sh2_slave_cmdint_enable = 0; - int m_sh2_hint_in_vbl = 0; - int m_sh2_master_vint_pending = 0; - int m_sh2_slave_vint_pending = 0; - int m_32x_fb_swap = 0; - int m_32x_hcount_reg = 0; - - uint16_t m_32x_autofill_length = 0; - uint16_t m_32x_autofill_address = 0; - uint16_t m_32x_autofill_data = 0; - uint16_t m_a15106_reg = 0; - uint16_t m_dreq_src_addr[2]{}, m_dreq_dst_addr[2]{}, m_dreq_size = 0; - uint8_t m_sega_tv = 0; - uint16_t m_hint_vector[2]{}; - uint16_t m_a15100_reg = 0; - int m_32x_68k_a15102_reg = 0; - - int m_32x_pal = 0; - int m_framerate = 0; - int m_base_total_scanlines = 0; - int m_total_scanlines = 0; - - uint16_t m_commsram[8]{}; - - std::unique_ptr m_32x_dram0; - std::unique_ptr m_32x_dram1; - uint16_t *m_32x_display_dram = nullptr, *m_32x_access_dram = nullptr; - std::unique_ptr m_32x_palette; - - uint16_t m_fifo_block_a[4]{}; - uint16_t m_fifo_block_b[4]{}; - uint16_t* m_current_fifo_block = nullptr; - uint16_t* m_current_fifo_readblock = nullptr; - int m_current_fifo_write_pos = 0; - int m_current_fifo_read_pos = 0; - int m_fifo_block_a_full = 0; - int m_fifo_block_b_full = 0; -}; - - -class sega_32x_ntsc_device : public sega_32x_device -{ -public: - template - sega_32x_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&main_cpu_tag, U &&timer_tag) - : sega_32x_ntsc_device(mconfig, tag, owner, clock) - { - m_main_cpu.set_tag(std::forward(main_cpu_tag)); - m_scan_timer.set_tag(std::forward(timer_tag)); - } - - sega_32x_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - virtual void device_add_mconfig(machine_config &config) override; - -}; - -class sega_32x_pal_device : public sega_32x_device -{ -public: - template - sega_32x_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&main_cpu_tag, U &&timer_tag) - : sega_32x_pal_device(mconfig, tag, owner, clock) - { - m_main_cpu.set_tag(std::forward(main_cpu_tag)); - m_scan_timer.set_tag(std::forward(timer_tag)); - } - - sega_32x_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - virtual void device_add_mconfig(machine_config &config) override; -}; - - -DECLARE_DEVICE_TYPE(SEGA_32X_NTSC, sega_32x_ntsc_device) -DECLARE_DEVICE_TYPE(SEGA_32X_PAL, sega_32x_pal_device) - -#endif // MAME_MACHINE_MEGA32X_H diff --git a/src/mame/messshared/megacdcd.cpp b/src/mame/messshared/megacdcd.cpp deleted file mode 100644 index 22759b96a3a..00000000000 --- a/src/mame/messshared/megacdcd.cpp +++ /dev/null @@ -1,1409 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:David Haywood -/* CD controller code from megacd.c, used by Sega CD / Mega CD */ - -/* todo: cleanup(!!), make more generic, unifiy implementation with NeoCD, turn into a device and move to the proper lc89510.c file - currently this is a bit of a mix of system specific bits, incomplete implementations etc. as well as a rather kludgy combination - of the CDC and drive emulation. */ - - -#include "emu.h" -#include "megacdcd.h" - -#define READ_MAIN (0x0200) -#define READ_SUB (0x0300) - -#define REG_W_SBOUT (0x0) -#define REG_W_IFCTRL (0x1) -#define REG_W_DBCL (0x2) -#define REG_W_DBCH (0x3) -#define REG_W_DACL (0x4) -#define REG_W_DACH (0x5) -#define REG_W_DTTRG (0x6) -#define REG_W_DTACK (0x7) -#define REG_W_WAL (0x8) -#define REG_W_WAH (0x9) -#define REG_W_CTRL0 (0xA) -#define REG_W_CTRL1 (0xB) -#define REG_W_PTL (0xC) -#define REG_W_PTH (0xD) -#define REG_W_CTRL2 (0xE) -#define REG_W_RESET (0xF) - -#define REG_R_COMIN (0x0) -#define REG_R_IFSTAT (0x1) -#define REG_R_DBCL (0x2) -#define REG_R_DBCH (0x3) -#define REG_R_HEAD0 (0x4) -#define REG_R_HEAD1 (0x5) -#define REG_R_HEAD2 (0x6) -#define REG_R_HEAD3 (0x7) -#define REG_R_PTL (0x8) -#define REG_R_PTH (0x9) -#define REG_R_WAL (0xa) -#define REG_R_WAH (0xb) -#define REG_R_STAT0 (0xc) -#define REG_R_STAT1 (0xd) -#define REG_R_STAT2 (0xe) -#define REG_R_STAT3 (0xf) - -#define CMD_STATUS (0x0) -#define CMD_STOPALL (0x1) -#define CMD_GETTOC (0x2) -#define CMD_READ (0x3) -#define CMD_SEEK (0x4) -// (0x5) -#define CMD_STOP (0x6) -#define CMD_RESUME (0x7) -#define CMD_FF (0x8) -#define CMD_RW (0x9) -#define CMD_INIT (0xa) -// (0xb) -#define CMD_CLOSE (0xc) -#define CMD_OPEN (0xd) -// (0xe) -// (0xf) - - -#define TOCCMD_CURPOS (0x0) -#define TOCCMD_TRKPOS (0x1) -#define TOCCMD_CURTRK (0x2) -#define TOCCMD_LENGTH (0x3) -#define TOCCMD_FIRSTLAST (0x4) -#define TOCCMD_TRACKADDR (0x5) - - - - -#define SET_CDD_DATA_MODE \ - CDD_CONTROL |= 0x0100; -#define SET_CDD_AUDIO_MODE \ - CDD_CONTROL &= ~0x0100; -#define STOP_CDC_READ \ - SCD_STATUS_CDC &= ~0x01; -#define SET_CDC_READ \ - SCD_STATUS_CDC |= 0x01; -#define SET_CDC_DMA \ - SCD_STATUS_CDC |= 0x08; -#define STOP_CDC_DMA \ - SCD_STATUS_CDC &= ~0x08; -#define SCD_READ_ENABLED \ - (SCD_STATUS_CDC & 1) - -#define SCD_DMA_ENABLED \ - (SCD_STATUS_CDC & 0x08) - -#define CLEAR_CDD_RESULT \ - CDD_MIN = CDD_SEC = CDD_FRAME = CDD_EXT = 0; -#define CHECK_SCD_LV5_INTERRUPT \ - if (segacd_irq_mask & 0x20) \ - { \ - m_68k->set_input_line(5, HOLD_LINE); \ - } -#define CHECK_SCD_LV4_INTERRUPT \ - if (segacd_irq_mask & 0x10) \ - { \ - m_68k->set_input_line(4, HOLD_LINE); \ - } -#define CHECK_SCD_LV4_INTERRUPT_A \ - if (segacd_irq_mask & 0x10) \ - { \ - m_68k->set_input_line(4, HOLD_LINE); \ - } - - -#define CURRENT_TRACK_IS_DATA \ - (segacd.toc->tracks[SCD_CURTRK - 1].trktype != cdrom_file::CD_TRACK_AUDIO) - -#define CDD_PLAYINGCDDA 0x0100 -#define CDD_READY 0x0400 -#define CDD_STOPPED 0x0900 - - -/* neocd */ - -#define CD_FRAMES_MINUTE (60 * 75) -#define CD_FRAMES_SECOND ( 75) -#define CD_FRAMES_PREGAP ( 2 * 75) - -#define SEK_IRQSTATUS_NONE (0x0000) -#define SEK_IRQSTATUS_AUTO (0x2000) -#define SEK_IRQSTATUS_ACK (0x1000) - - -DEFINE_DEVICE_TYPE(LC89510_TEMP, lc89510_temp_device, "lc89510_temp", "lc89510_temp_device") - -lc89510_temp_device::lc89510_temp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, LC89510_TEMP, tag, owner, clock) - , m_segacd_dma_callback(*this, FUNC(lc89510_temp_device::Fake_CDC_Do_DMA)) - , m_type1_interrupt_callback(*this, FUNC(lc89510_temp_device::dummy_interrupt_callback)) - , m_type2_interrupt_callback(*this, FUNC(lc89510_temp_device::dummy_interrupt_callback)) - , m_type3_interrupt_callback(*this, FUNC(lc89510_temp_device::dummy_interrupt_callback)) - , m_cdrom(*this, finder_base::DUMMY_TAG) - , m_cdda(*this, "cdda") - , m_68k(*this, finder_base::DUMMY_TAG) -{ - is_neoCD = false; - - nff0002 = 0; - for (auto & elem : CDD_TX) - elem = 0; - for (auto & elem : CDD_RX) - elem = 0; - NeoCDCommsWordCount = 0; - NeoCD_StatusHack = 0; - SCD_CURLBA = 0; - - CDC_REG0 = 0; - - segacd_irq_mask = 0; -} - -void lc89510_temp_device::dummy_interrupt_callback() -{ -} - -// HACK for DMA handling, this gets replaced -void lc89510_temp_device::Fake_CDC_Do_DMA(int &dmacount, uint8_t *CDC_BUFFER, uint16_t &dma_addrc, uint16_t &destination ) -{ - fatalerror("Fake_CDC_Do_DMA\n"); -} - -void lc89510_temp_device::device_start() -{ - m_segacd_dma_callback.resolve(); - m_type1_interrupt_callback.resolve(); - m_type2_interrupt_callback.resolve(); - m_type3_interrupt_callback.resolve(); -} - -void lc89510_temp_device::device_reset() -{ - m_cdda->stop_audio(); -} - - -inline int lc89510_temp_device::to_bcd(int val, bool byte) -{ - if (val > 99) val = 99; - - if (byte) return (((val) / 10) << 4) + ((val) % 10); - else return (((val) / 10) << 8) + ((val) % 10); -} - - - -void lc89510_temp_device::set_data_audio_mode(void) -{ - if (CURRENT_TRACK_IS_DATA) - { - SET_CDD_DATA_MODE - } - else - { - SET_CDD_AUDIO_MODE - //fatalerror("CDDA unsupported\n"); - } -} - -void lc89510_temp_device::CDD_DoChecksum(void) -{ - int checksum = - CDD_RX[0] + - CDD_RX[1] + - CDD_RX[2] + - CDD_RX[3] + - CDD_RX[4] + - CDD_RX[5] + - CDD_RX[6] + - CDD_RX[7] + - CDD_RX[8]; - - if (is_neoCD) checksum += 0x5; // why?? - checksum &= 0xf; - checksum ^= 0xf; - - CDD_RX[9] = checksum; -} - -bool lc89510_temp_device::CDD_Check_TX_Checksum(void) -{ - int checksum = - CDD_TX[0] + - CDD_TX[1] + - CDD_TX[2] + - CDD_TX[3] + - CDD_TX[4] + - CDD_TX[5] + - CDD_TX[6] + - CDD_TX[7] + - CDD_TX[8]; - - if (is_neoCD) checksum += 0x5; // why?? - checksum &= 0xf; - checksum ^= 0xf; - - if (CDD_TX[9] == checksum) - return true; - - return false; -} - -// converts our 16-bit working regs to 8-bit regs and checksums them -void lc89510_temp_device::CDD_Export(bool neocd_hack) -{ - if (!neocd_hack) - CDD_RX[0] = (CDD_STATUS & 0xff00)>>8; - else - { - // printf("was %02x returning %02x\n", (CDD_STATUS & 0xff00)>>8, NeoCD_StatusHack); - CDD_RX[0] = NeoCD_StatusHack; - } - - CDD_RX[1] = (CDD_STATUS & 0x00ff)>>0; - CDD_RX[2] = (CDD_MIN & 0xff00)>>8; - CDD_RX[3] = (CDD_MIN & 0x00ff)>>0; - CDD_RX[4] = (CDD_SEC & 0xff00)>>8; - CDD_RX[5] = (CDD_SEC & 0x00ff)>>0; - CDD_RX[6] = (CDD_FRAME & 0xff00)>>8; - CDD_RX[7] = (CDD_FRAME & 0x00ff)>>0; - CDD_RX[8] = (CDD_EXT & 0x00ff)>>0; - /* 9 = checksum */ - - CDD_DoChecksum(); - - CDD_CONTROL &= ~4; // Clear HOCK bit - -} - - - - - - -void lc89510_temp_device::CDD_GetStatus(void) -{ - uint16_t s = (CDD_STATUS & 0x0f00); - - if ((s == 0x0200) || (s == 0x0700) || (s == 0x0e00)) - CDD_STATUS = (SCD_STATUS & 0xff00) | (CDD_STATUS & 0x00ff); -} - - -void lc89510_temp_device::CDD_Stop() -{ - CLEAR_CDD_RESULT - STOP_CDC_READ - SCD_STATUS = CDD_STOPPED; - CDD_STATUS = 0x0000; - SET_CDD_DATA_MODE - m_cdda->stop_audio(); //stop any pending CD-DA - - //neocd - NeoCD_StatusHack = 0x0E; - - -} - - -void lc89510_temp_device::CDD_GetPos(void) -{ - CLEAR_CDD_RESULT - uint32_t msf; - CDD_STATUS &= 0xFF; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - CDD_STATUS |= SCD_STATUS; - msf = cdrom_file::lba_to_msf_alt(SCD_CURLBA+150); - CDD_MIN = to_bcd(((msf & 0x00ff0000)>>16),false); - CDD_SEC = to_bcd(((msf & 0x0000ff00)>>8),false); - CDD_FRAME = to_bcd(((msf & 0x000000ff)>>0),false); -} - -void lc89510_temp_device::CDD_GetTrackPos(void) -{ - CLEAR_CDD_RESULT - int elapsedlba; - uint32_t msf; - CDD_STATUS &= 0xFF; - // uint32_t end_msf = ; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - CDD_STATUS |= SCD_STATUS; - elapsedlba = SCD_CURLBA - segacd.toc->tracks[ segacd.cd->get_track(SCD_CURLBA) ].logframeofs; - msf = cdrom_file::lba_to_msf_alt (elapsedlba); - //popmessage("%08x %08x",SCD_CURLBA,segacd.toc->tracks[ cdrom_get_track(segacd.cd, SCD_CURLBA) + 1 ].logframeofs); - CDD_MIN = to_bcd(((msf & 0x00ff0000)>>16),false); - CDD_SEC = to_bcd(((msf & 0x0000ff00)>>8),false); - CDD_FRAME = to_bcd(((msf & 0x000000ff)>>0),false); -} - -void lc89510_temp_device::CDD_GetTrack(void) -{ - CLEAR_CDD_RESULT - CDD_STATUS &= 0xFF; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - CDD_STATUS |= SCD_STATUS; - SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; - CDD_MIN = to_bcd(SCD_CURTRK, false); -} - -void lc89510_temp_device::CDD_Length(void) -{ - CLEAR_CDD_RESULT - CDD_STATUS &= 0xFF; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - CDD_STATUS |= SCD_STATUS; - - uint32_t startlba = (segacd.toc->tracks[segacd.cd->get_last_track()].logframeofs); - uint32_t startmsf = cdrom_file::lba_to_msf_alt( startlba ); - - CDD_MIN = to_bcd((startmsf&0x00ff0000)>>16,false); - CDD_SEC = to_bcd((startmsf&0x0000ff00)>>8,false); - CDD_FRAME = to_bcd((startmsf&0x000000ff)>>0,false); -} - - -void lc89510_temp_device::CDD_FirstLast(void) -{ - CLEAR_CDD_RESULT - CDD_STATUS &= 0xFF; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - CDD_STATUS |= SCD_STATUS; - CDD_MIN = 1; // first - CDD_SEC = to_bcd(segacd.cd->get_last_track(),false); // last -} - -void lc89510_temp_device::CDD_GetTrackAdr(void) -{ - CLEAR_CDD_RESULT - - CDD_STATUS &= 0xFF; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - - int track = (CDD_TX[5] & 0xF) + (CDD_TX[4] & 0xF) * 10; - int last_track = segacd.cd->get_last_track(); - - CDD_STATUS |= SCD_STATUS; - - if (track > last_track) - track = last_track; - - if (track < 1) - track = 1; - - uint32_t startlba = (segacd.toc->tracks[track-1].logframeofs); - uint32_t startmsf = cdrom_file::lba_to_msf_alt( startlba+150 ); - - CDD_MIN = to_bcd((startmsf&0x00ff0000)>>16,false); - CDD_SEC = to_bcd((startmsf&0x0000ff00)>>8,false); - CDD_FRAME = to_bcd((startmsf&0x000000ff)>>0,false); - CDD_EXT = track % 10; - - if (segacd.toc->tracks[track - 1].trktype != cdrom_file::CD_TRACK_AUDIO) - CDD_FRAME |= 0x0800; -} - -// verify what this is.. the NeoCd emu code only checked the track type but -// checked it where we put CDD_EXT, not CDD_FRAME (RX[7] vs RX[8] in Export) -void lc89510_temp_device::CDD_GetTrackType(void) -{ - CLEAR_CDD_RESULT - - CDD_STATUS &= 0xFF; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - - int track = (CDD_TX[5] & 0xF) + (CDD_TX[4] & 0xF) * 10; - int last_track = segacd.cd->get_last_track(); - - CDD_STATUS |= SCD_STATUS; - - if (track > last_track) - track = last_track; - - if (track < 1) - track = 1; - - if (segacd.toc->tracks[track - 1].trktype != cdrom_file::CD_TRACK_AUDIO) - { - CDD_EXT = 0x08; - CDD_FRAME |= 0x0800; - } - - - -} - -uint32_t lc89510_temp_device::getmsf_from_regs(void) -{ - uint32_t msf = 0; - - msf = ((CDD_TX[3] & 0xF) + (CDD_TX[2] & 0xF) * 10) << 16; - msf |= ((CDD_TX[5] & 0xF) + (CDD_TX[4] & 0xF) * 10) << 8; - msf |= ((CDD_TX[7] & 0xF) + (CDD_TX[6] & 0xF) * 10) << 0; - - return msf; -} - -void lc89510_temp_device::CDD_Play() -{ - CLEAR_CDD_RESULT - uint32_t msf = getmsf_from_regs(); - SCD_CURLBA = cdrom_file::msf_to_lba(msf)-150; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - uint32_t track_length = segacd.toc->tracks[ segacd.cd->get_track(SCD_CURLBA) ].logframes; - SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; - LC8951UpdateHeader(); - SCD_STATUS = CDD_PLAYINGCDDA; - CDD_STATUS = 0x0102; - set_data_audio_mode(); - printf("%d Track played\n",SCD_CURTRK); - CDD_MIN = to_bcd(SCD_CURTRK, false); - if(!(CURRENT_TRACK_IS_DATA)) - m_cdda->start_audio(SCD_CURLBA, SCD_CURLBA + track_length); - SET_CDC_READ - - - NeoCD_StatusHack = 1; - -} - - -void lc89510_temp_device::CDD_Seek(void) -{ - CLEAR_CDD_RESULT - uint32_t msf = getmsf_from_regs(); - SCD_CURLBA = cdrom_file::msf_to_lba(msf)-150; - if(segacd.cd == nullptr) // no CD is there, bail out - return; - SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; - LC8951UpdateHeader(); - STOP_CDC_READ - SCD_STATUS = CDD_READY; - CDD_STATUS = 0x0200; - set_data_audio_mode(); -} - - -void lc89510_temp_device::CDD_Pause() -{ - CLEAR_CDD_RESULT - STOP_CDC_READ - SCD_STATUS = CDD_READY; - CDD_STATUS = SCD_STATUS; - SET_CDD_DATA_MODE - - //segacd.current_frame = cdda_get_audio_lba( machine.device( "cdda" ) ); - //if(!(CURRENT_TRACK_IS_DATA)) - m_cdda->pause_audio(1); - - - NeoCD_StatusHack = 4; - - -} - -void lc89510_temp_device::CDD_Resume() -{ - CLEAR_CDD_RESULT - STOP_CDC_READ - if(segacd.cd == nullptr) // no CD is there, bail out - return; - SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; - SCD_STATUS = CDD_PLAYINGCDDA; - CDD_STATUS = 0x0102; - set_data_audio_mode(); - CDD_MIN = to_bcd (SCD_CURTRK, false); - SET_CDC_READ - //if(!(CURRENT_TRACK_IS_DATA)) - m_cdda->pause_audio(0); - - NeoCD_StatusHack = 1; -} - - -void lc89510_temp_device::CDD_FF() -{ - fatalerror("Fast Forward unsupported\n"); -} - - -void lc89510_temp_device::CDD_RW() -{ - fatalerror("Fast Rewind unsupported\n"); -} - - -void lc89510_temp_device::CDD_Open(void) -{ - fatalerror("Close Tray unsupported\n"); - /* TODO: re-read CD-ROM buffer here (Mega CD has multi disc games iirc?) */ -} - - -void lc89510_temp_device::CDD_Close(void) -{ - fatalerror("Open Tray unsupported\n"); - /* TODO: clear CD-ROM buffer here */ -} - - -void lc89510_temp_device::CDD_Init(void) -{ - CLEAR_CDD_RESULT - STOP_CDC_READ - SCD_STATUS = CDD_READY; - CDD_STATUS = SCD_STATUS; - CDD_SEC = 1; - CDD_FRAME = 1; -} - - -void lc89510_temp_device::CDD_Default(void) -{ - CLEAR_CDD_RESULT - CDD_STATUS = SCD_STATUS; - - - NeoCD_StatusHack = 9; -} - - -void lc89510_temp_device::CDD_Reset(void) -{ - CLEAR_CDD_RESULT - CDD_CONTROL = CDD_STATUS = 0; - - for (int i = 0; i < 10; i++) - CDD_RX[i] = CDD_TX[i] = 0; - - CDD_DoChecksum(); - - SCD_CURTRK = SCD_CURLBA = 0; - SCD_STATUS = CDD_READY; -} - -void lc89510_temp_device::CDC_Reset(void) -{ - memset(CDC_BUFFER, 0x00, ((16 * 1024 * 2) + SECTOR_SIZE)); - - LC8951RegistersW[REG_W_DACL] = LC8951RegistersW[REG_W_DACH] = LC8951RegistersW[REG_W_DBCL] = LC8951RegistersW[REG_W_DBCH] = LC8951RegistersW[REG_W_PTH] = LC8951RegistersW[REG_W_PTL] = LC8951RegistersW[REG_W_SBOUT] = LC8951RegistersW[REG_W_IFCTRL] = LC8951RegistersW[REG_W_CTRL0] = LC8951RegistersW[REG_W_CTRL1] = - LC8951RegistersW[REG_W_CTRL2] = LC8951RegistersR[REG_R_HEAD1] = LC8951RegistersR[REG_R_HEAD2] = LC8951RegistersR[REG_R_HEAD3] = LC8951RegistersR[REG_R_STAT0] = LC8951RegistersR[REG_R_STAT1] = LC8951RegistersR[REG_R_STAT2] = CDC_DECODE = 0; - - LC8951RegistersR[REG_R_IFSTAT] = 0xFF; - int wa = SECTOR_SIZE * 2; - LC8951RegistersW[REG_W_WAL] = wa & 0xff; LC8951RegistersW[REG_W_WAH] = (wa >> 8) &0xff; - LC8951RegistersR[REG_R_HEAD0] = 0x01; - LC8951RegistersR[REG_R_STAT3] = 0x80; - - LC8951UpdateHeader(); -} - - -void lc89510_temp_device::lc89510_Reset(void) -{ - CDD_Reset(); - CDC_Reset(); - - CDC_REG0 = CDC_REG1 = SCD_STATUS_CDC = CDD_DONE = 0; -} - - -void lc89510_temp_device::CDC_Do_DMA(int rate) -{ - uint32_t length; - - uint16_t destination = CDC_REG0 & 0x0700; - - if (!(SCD_DMA_ENABLED)) - return; - - if ((destination == READ_MAIN) || (destination==READ_SUB)) - { - CDC_REG0 |= 0x4000; - return; - } - - int dma_count_register = LC8951RegistersW[REG_W_DBCL] | (LC8951RegistersW[REG_W_DBCH]<<8); - - if (dma_count_register <= (rate * 2)) - { - length = (dma_count_register + 1) >> 1; - CDC_End_Transfer(); - } - else - length = rate; - - - int dmacount = length; - - uint16_t dma_addrc = LC8951RegistersW[REG_W_DACL] | (LC8951RegistersW[REG_W_DACH]<<8); - - // HACK - m_segacd_dma_callback(dmacount, CDC_BUFFER, dma_addrc, destination ); - - - dma_addrc += length*2; - LC8951RegistersW[REG_W_DACL] = dma_addrc & 0xff; LC8951RegistersW[REG_W_DACH] = (dma_addrc >> 8) & 0xff; - - if (SCD_DMA_ENABLED) - dma_count_register -= length*2; - else - dma_count_register = 0; - - LC8951RegistersW[REG_W_DBCL] = dma_count_register & 0xff; LC8951RegistersW[REG_W_DBCH] = (dma_count_register>>8) & 0xff; - -} - - - - -uint16_t lc89510_temp_device::CDC_Host_r(uint16_t type) -{ - uint16_t destination = CDC_REG0 & 0x0700; - - if (SCD_DMA_ENABLED) - { - if (destination == type) - { - int dma_count_register = LC8951RegistersW[REG_W_DBCL] | (LC8951RegistersW[REG_W_DBCH]<<8); - - dma_count_register -= 2; - - if (dma_count_register <= 0) - { - if (type==READ_SUB) dma_count_register = 0; - - CDC_End_Transfer(); - } - - LC8951RegistersW[REG_W_DBCL] = dma_count_register & 0xff; LC8951RegistersW[REG_W_DBCH] = (dma_count_register>>8) & 0xff; - - uint16_t dma_addrc = LC8951RegistersW[REG_W_DACL] | (LC8951RegistersW[REG_W_DACH]<<8); - - uint16_t data = (CDC_BUFFER[dma_addrc]<<8) | CDC_BUFFER[dma_addrc+1]; - dma_addrc += 2; - - LC8951RegistersW[REG_W_DACL] = dma_addrc & 0xff; LC8951RegistersW[REG_W_DACH] = (dma_addrc >> 8) & 0xff; - - - return data; - } - } - - return 0; -} - - - - -uint8_t lc89510_temp_device::CDC_Reg_r(void) -{ - int reg = CDC_REG0 & 0xF; - uint8_t ret = 0; - - - uint16_t decoderegs = 0x73F2; - - if ((decoderegs>>reg)&1) - CDC_DECODE |= (1 << reg); - - - CDC_REG0 = (CDC_REG0 & 0xFFF0) | ((reg+1)&0xf); - - switch (reg) - { - case REG_R_COMIN: ret = 0/*COMIN*/; break; - case REG_R_IFSTAT: ret = LC8951RegistersR[REG_R_IFSTAT]; break; - case REG_R_DBCL: ret = LC8951RegistersW[REG_W_DBCL]; break; - case REG_R_DBCH: -// LC8951RegistersR[REG_R_DBCH] &= 0x0F; // NeoCD? -// LC8951RegistersR[REG_R_DBCH] |= (LC8951RegistersR[REG_R_IFSTAT] & 0x40) ? 0x00 : 0xF0; // NeoCD? - ret = LC8951RegistersW[REG_W_DBCH]; break; - case REG_R_HEAD0: ret = LC8951RegistersR[REG_R_HEAD0]; break; - case REG_R_HEAD1: ret = LC8951RegistersR[REG_R_HEAD1]; break; - case REG_R_HEAD2: ret = LC8951RegistersR[REG_R_HEAD2]; break; - case REG_R_HEAD3: ret = LC8951RegistersR[REG_R_HEAD3]; break; - case REG_R_PTL: ret = LC8951RegistersW[REG_W_PTL]; break; - case REG_R_PTH: ret = LC8951RegistersW[REG_W_PTH]; break; - case REG_R_WAL: ret = LC8951RegistersW[REG_W_WAL]; break; - case REG_R_WAH: ret = LC8951RegistersW[REG_W_WAH]; break; - case REG_R_STAT0: ret = LC8951RegistersR[REG_R_STAT0]; break; - case REG_R_STAT1: ret = LC8951RegistersR[REG_R_STAT1]; - // LC8951RegistersR[REG_R_IFSTAT] |= 0x20; // NeoCD? // reset DECI - break; - case REG_R_STAT2: ret = LC8951RegistersR[REG_R_STAT2]; break; - case REG_R_STAT3: ret = LC8951RegistersR[REG_R_STAT3]; - - LC8951RegistersR[REG_R_IFSTAT] |= 0x20; // SegaCD? // reset DECI - if (!is_neoCD) - { - if ((LC8951RegistersW[REG_W_CTRL0] & 0x80) && (LC8951RegistersW[REG_W_IFCTRL] & 0x20)) - { - if ((CDC_DECODE & decoderegs) == decoderegs) - LC8951RegistersR[REG_R_STAT3] = 0x80; - } - } - break; - - } - - - return ret; -} - -void lc89510_temp_device::CDC_Reg_w(uint8_t data) -{ - int reg = CDC_REG0 & 0xF; - - int changers0[0x10] = { 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0}; - - if (changers0[reg]) - CDC_REG0 = (CDC_REG0 & 0xFFF0) | (reg+1); - - switch (reg) - { - case REG_W_SBOUT: - LC8951RegistersW[REG_W_SBOUT] = data; - break; - - case REG_W_IFCTRL: - LC8951RegistersW[REG_W_IFCTRL] = data; - - if (!(LC8951RegistersW[REG_W_IFCTRL] & 0x02)) - { - LC8951RegistersW[REG_W_DBCL] = 0; LC8951RegistersW[REG_W_DBCH] = 0; - STOP_CDC_DMA; - LC8951RegistersR[REG_R_IFSTAT] |= 0x08; - } - break; - - case REG_W_DBCL: LC8951RegistersW[REG_W_DBCL] = data; break; - case REG_W_DBCH: LC8951RegistersW[REG_W_DBCH] = data; break; - case REG_W_DACL: LC8951RegistersW[REG_W_DACL] = data; break; - case REG_W_DACH: LC8951RegistersW[REG_W_DACH] = data; break; - - case REG_W_DTTRG: - if (!is_neoCD) - { - if (LC8951RegistersW[REG_W_IFCTRL] & 0x02) - { - LC8951RegistersR[REG_R_IFSTAT] &= ~0x08; - SET_CDC_DMA; - CDC_REG0 &= ~0x8000; - } - } - else - { - LC8951RegistersW[REG_W_DTTRG] = ~0x00; - LC8951RegistersR[REG_R_IFSTAT] &= ~0x08; - } - break; - - case REG_W_DTACK: - //if (!is_neoCD) - { - LC8951RegistersR[REG_R_IFSTAT] |= 0x40; - } - //else - //{ - // LC8951RegistersW[REG_W_DTACK] = ~0x00; - // LC8951RegistersR[REG_R_IFSTAT] &= ~0x40; - //} - break; - case REG_W_WAL: LC8951RegistersW[REG_W_WAL] = data; break; - case REG_W_WAH: LC8951RegistersW[REG_W_WAH] = data; break; - case REG_W_CTRL0: LC8951RegistersW[REG_W_CTRL0] = data; break; - case REG_W_CTRL1: LC8951RegistersW[REG_W_CTRL1] = data; - //LC8951UpdateHeader(); // NeoCD - break; - case REG_W_PTL: LC8951RegistersW[REG_W_PTL] = data; break; - case REG_W_PTH: LC8951RegistersW[REG_W_PTH] = data; break; - case REG_W_CTRL2: LC8951RegistersW[REG_W_CTRL2] = data; break; - case REG_W_RESET: CDC_Reset(); break; - } -} - - - -void lc89510_temp_device::CDD_Process(int reason) -{ - CDD_Export(); - CHECK_SCD_LV4_INTERRUPT -} - -void lc89510_temp_device::CDD_Handle_TOC_Commands(void) -{ - int subcmd = CDD_TX[3]; - CDD_STATUS = (CDD_STATUS & 0xFF00) | subcmd; - - switch (subcmd) - { - case TOCCMD_CURPOS: CDD_GetPos(); break; - case TOCCMD_TRKPOS: CDD_GetTrackPos(); break; - case TOCCMD_CURTRK: CDD_GetTrack(); break; - case TOCCMD_LENGTH: CDD_Length(); break; - case TOCCMD_FIRSTLAST: CDD_FirstLast(); break; - case TOCCMD_TRACKADDR: CDD_GetTrackAdr(); break; - case 6: CDD_GetTrackType(); break; // NGCD, might be wrong, make sure Sega CD doesn't hate it - default: CDD_GetStatus(); break; - } -} - -static const char *const CDD_import_cmdnames[] = -{ - "Get Status", // 0 - "Stop ALL", // 1 - "Handle TOC", // 2 - "Play", // 3 - "Seek", // 4 - " (5)", // 5 - "Pause", // 6 - "Resume", // 7 - "FF", // 8 - "RWD", // 9 - "INIT", // A - " (b)", // B - "Close Tray", // C - "Open Tray", // D - " (e)", // E - " (f)" // F -}; - -bool lc89510_temp_device::CDD_Import() -{ - // don't execute the command if the checksum isn't valid - if (!CDD_Check_TX_Checksum()) - { - printf("invalid checksum\n"); - return false; - } - - if(CDD_TX[0] != 2 && CDD_TX[0] != 0) - printf("%s\n",CDD_import_cmdnames[CDD_TX[0]]); - - switch (CDD_TX[0]) - { - case CMD_STATUS: CDD_GetStatus(); break; - case CMD_STOPALL: CDD_Stop(); break; - case CMD_GETTOC: CDD_Handle_TOC_Commands(); break; - case CMD_READ: CDD_Play(); break; - case CMD_SEEK: CDD_Seek(); break; - case CMD_STOP: CDD_Pause(); break; - case CMD_RESUME: CDD_Resume(); break; - case CMD_FF: CDD_FF(); break; - case CMD_RW: CDD_RW(); break; - case CMD_INIT: CDD_Init(); break; - case CMD_CLOSE: CDD_Open(); break; - case CMD_OPEN: CDD_Close(); break; - default: CDD_Default(); break; - } - - CDD_DONE = 1; - return true; -} - - -/************************************************************** - CDC Stuff ******** -**************************************************************/ - - - -void lc89510_temp_device::segacd_cdc_mode_address_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - COMBINE_DATA(&CDC_REG0); -} - -uint16_t lc89510_temp_device::segacd_cdc_mode_address_r() -{ - return CDC_REG0; -} - -void lc89510_temp_device::segacd_cdc_data_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - COMBINE_DATA(&CDC_REG1); - - if (ACCESSING_BITS_0_7) - CDC_Reg_w(data); -} - -uint16_t lc89510_temp_device::segacd_cdc_data_r(offs_t offset, uint16_t mem_mask) -{ - uint16_t retdat = 0x0000; - - if (ACCESSING_BITS_0_7) - retdat |= CDC_Reg_r(); - - return retdat; -} - - -uint16_t lc89510_temp_device::cdc_data_sub_r() -{ - return CDC_Host_r(READ_SUB); -} - -uint16_t lc89510_temp_device::cdc_data_main_r() -{ - return CDC_Host_r(READ_MAIN); -} - - - - -uint16_t lc89510_temp_device::segacd_irq_mask_r() -{ - return segacd_irq_mask; -} - -void lc89510_temp_device::segacd_irq_mask_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - { - uint16_t control = CDD_CONTROL; - - // printf("segacd_irq_mask_w %04x %04x (CDD control is %04x)\n",data, mem_mask, control); - - if (data & 0x10) - { - if (control & 0x04) - { - if (!(segacd_irq_mask & 0x10)) - { - segacd_irq_mask = data & 0x7e; - CDD_Process(0); - return; - } - } - } - - segacd_irq_mask = data & 0x7e; - } - else - { - printf("segacd_irq_mask_w only MSB written\n"); - - } -} - -uint16_t lc89510_temp_device::segacd_cdd_ctrl_r() -{ - return CDD_CONTROL; -} - - -void lc89510_temp_device::segacd_cdd_ctrl_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - { - uint16_t control = CDD_CONTROL; - - - //printf("segacd_cdd_ctrl_w %04x %04x (control %04x irq %04x\n", data, mem_mask, control, segacd_irq_mask); - - data &=0x4; // only HOCK bit is writable - - if (data & 0x4) - { - if (!(control & 0x4)) - { - if (segacd_irq_mask&0x10) - { - CDD_Process(1); - } - } - } - - CDD_CONTROL |= data; - } - else - { - printf("segacd_cdd_ctrl_w only MSB written\n"); - } -} - - -// mapped as serial -uint8_t lc89510_temp_device::neocd_cdd_rx_r() -{ - uint8_t ret = 0; - - if (NeoCDCommsWordCount >= 0 && NeoCDCommsWordCount < 10) { - ret = CDD_RX[NeoCDCommsWordCount] & 0x0F; - } - - if (bNeoCDCommsClock) { - ret |= 0x10; - } - - return ret; -} - -// mapped like 'ram' -uint8_t lc89510_temp_device::segacd_cdd_rx_r(offs_t offset) -{ - return CDD_RX[offset]; -} - -// mapped as serial -void lc89510_temp_device::neocd_cdd_tx_w(uint8_t data) -{ - //printf("neocd_cdd_tx_w %d, %02x\n", NeoCDCommsWordCount, data); - - if (NeoCDCommsWordCount >= 0 && NeoCDCommsWordCount < 10) { - CDD_TX[NeoCDCommsWordCount] = data & 0x0F; - } -} - -void lc89510_temp_device::segacd_cdd_tx_w(offs_t offset, uint8_t data) -{ - CDD_TX[offset] = data; - - if(offset == 9) - { - CDD_Import(); - } -} - - - - - - -uint16_t lc89510_temp_device::segacd_cdfader_r() -{ - return 0; -} - -void lc89510_temp_device::segacd_cdfader_w(uint16_t data) -{ - static double cdfader_vol; - if(data & 0x800f) - printf("CD Fader register write %04x\n",data); - - cdfader_vol = (double)((data & 0x3ff0) >> 4); - - if(data & 0x4000) - cdfader_vol = 1.0; - else - cdfader_vol = cdfader_vol / 1024.0; - - //printf("%f\n",cdfader_vol); - - m_cdda->set_output_gain(ALL_OUTPUTS, cdfader_vol); -} - -void lc89510_temp_device::reset_cd(void) -{ - /* init cd-rom device */ - - lc89510_Reset(); - - { - segacd.cd = m_cdrom->get_cdrom_file(); - if ( segacd.cd ) - { - segacd.toc = &segacd.cd->get_toc(); - m_cdda->set_cdrom(segacd.cd); - m_cdda->stop_audio(); //stop any pending CD-DA - } - } - - - -// if (segacd.cd) -// printf("cd found\n"); -} - - - -TIMER_DEVICE_CALLBACK_MEMBER( lc89510_temp_device::segacd_access_timer_callback ) -{ - if (!is_neoCD) - { - if (CDD_DONE) - { - CDD_DONE = 0; - CDD_Export(); - CHECK_SCD_LV4_INTERRUPT_A - } - } - else - { - if (nff0002 & 0x0050) - { - m_type2_interrupt_callback(); - } - } - - if (SCD_READ_ENABLED) // if (nff0002 & 0x0050) if (nff0002 & 0x0500); - { - set_data_audio_mode(); - Read_LBA_To_Buffer(); - } - -} - - -void lc89510_temp_device::device_add_mconfig(machine_config &config) -{ - TIMER(config, "hock_timer").configure_periodic(FUNC(lc89510_temp_device::segacd_access_timer_callback), attotime::from_hz(75)); - - cdda_device &cdda(CDDA(config, "cdda")); - cdda.add_route(0, ":lspeaker", 0.50); // TODO: accurate volume balance - cdda.add_route(1, ":rspeaker", 0.50); -} - - - -/* Neo CD */ - - -void lc89510_temp_device::NeoCDCommsReset() -{ - bNeoCDCommsClock = true; - - memset(CDD_TX, 0, sizeof(CDD_TX)); - memset(CDD_RX, 0, sizeof(CDD_RX)); - - NeoCDCommsWordCount = 0; - - NeoCD_StatusHack = 9; - - - nff0016 = 0; -} - - - - -void lc89510_temp_device::NeoCDCommsControl(uint8_t clock, uint8_t send) -{ - if (clock && !bNeoCDCommsClock) { - NeoCDCommsWordCount++; - if (NeoCDCommsWordCount >= 10) { - NeoCDCommsWordCount = 0; - - if (send) - { - if (CDD_TX[0]) - { - if (!CDD_Import()) - return; - - CDD_Export(true); // true == neocd hack, - } - - } - - } - } - bNeoCDCommsClock = clock; -} - - -void lc89510_temp_device::LC8951UpdateHeader() // neocd -{ - if (LC8951RegistersW[REG_W_CTRL1] & 1) { - // HEAD registers have sub-header - - LC8951RegistersR[REG_R_HEAD0] = 0; // HEAD0 - LC8951RegistersR[REG_R_HEAD1] = 0; // HEAD1 - LC8951RegistersR[REG_R_HEAD2] = 0; // HEAD2 - LC8951RegistersR[REG_R_HEAD3] = 0; // HEAD3 - - } else { - // HEAD registers have header - uint32_t msf = cdrom_file::lba_to_msf_alt(SCD_CURLBA+150); - - LC8951RegistersR[REG_R_HEAD0] = to_bcd (((msf & 0x00ff0000)>>16), true); // HEAD0 - LC8951RegistersR[REG_R_HEAD1] = to_bcd (((msf & 0x0000ff00)>>8), true); // HEAD1 - LC8951RegistersR[REG_R_HEAD2] = to_bcd (((msf & 0x000000ff)>>0), true); // HEAD2 - LC8951RegistersR[REG_R_HEAD3] = 0x1; // HEAD3 - } -} - -char* lc89510_temp_device::LC8915InitTransfer(int NeoCDDMACount) -{ - if (!LC8951RegistersW[REG_W_DTTRG]) { - //bprintf(PRINT_ERROR, _T(" LC8951 DTTRG status invalid\n")); - return nullptr; - } - if (!(LC8951RegistersW[REG_W_IFCTRL] & 0x02)) { - //bprintf(PRINT_ERROR, _T(" LC8951 DOUTEN status invalid\n")); - return nullptr; - } - if (((LC8951RegistersW[REG_W_DACH] << 8) | LC8951RegistersW[REG_W_DACL]) + (NeoCDDMACount << 1) > EXTERNAL_BUFFER_SIZE) { - //bprintf(PRINT_ERROR, _T(" DMA transfer exceeds current sector in LC8951 external buffer\n")); - - return nullptr; - } - - char* addr = (char*)CDC_BUFFER + ((LC8951RegistersW[REG_W_DACH] << 8) | LC8951RegistersW[REG_W_DACL]); - return addr; -} - -void lc89510_temp_device::LC8915EndTransfer() -{ - LC8951RegistersW[REG_W_DTTRG] = 0x00; // reset DTTRG - - LC8951RegistersR[REG_R_IFSTAT] |= 0x48; // set DTEI & DTBSY - if (LC8951RegistersW[REG_W_IFCTRL] & 0x40) { - // trigger DTE interrupt - - // the Neo Geo CD doesn't use the DTE interrupt - // nIRQAcknowledge &= ~0x20; - // NeoCDIRQUpdate(0); - - } -} - - -void lc89510_temp_device::CDC_End_Transfer() -{ - STOP_CDC_DMA - CDC_REG0 |= 0x8000; - CDC_REG0 &= ~0x4000; - LC8951RegistersR[REG_R_IFSTAT] |= 0x08; - - if (LC8951RegistersW[REG_W_IFCTRL] & 0x40) - { - LC8951RegistersR[REG_R_IFSTAT] &= ~0x40; - CHECK_SCD_LV5_INTERRUPT - } -} - - - - - - -void lc89510_temp_device::scd_ctrl_checks() -{ - LC8951RegistersR[REG_R_STAT0] = 0x80; - - (LC8951RegistersW[REG_W_CTRL0] & 0x10) ? (LC8951RegistersR[REG_R_STAT2] = LC8951RegistersW[REG_W_CTRL1] & 0x08) : (LC8951RegistersR[REG_R_STAT2] = LC8951RegistersW[REG_W_CTRL1] & 0x0C); - (LC8951RegistersW[REG_W_CTRL0] & 0x02) ? (LC8951RegistersR[REG_R_STAT3] = 0x20) : (LC8951RegistersR[REG_R_STAT3] = 0x00); - - if (LC8951RegistersW[REG_W_IFCTRL] & 0x20) - { - if (is_neoCD) - { - m_type1_interrupt_callback(); - } - else - { - // todo: make callback - CHECK_SCD_LV5_INTERRUPT - } - - - - LC8951RegistersR[REG_R_IFSTAT] &= ~0x20; - CDC_DECODE = 0; - } -} - -void lc89510_temp_device::scd_advance_current_readpos(void) -{ - SCD_CURLBA++; - - int pt = LC8951RegistersW[REG_W_PTL] | (LC8951RegistersW[REG_W_PTH] << 8); - int wa = LC8951RegistersW[REG_W_WAL] | (LC8951RegistersW[REG_W_WAH] << 8); - - wa += SECTOR_SIZE; - pt += SECTOR_SIZE; - - wa &= 0x7fff; - pt &= 0x7fff; - - LC8951RegistersW[REG_W_PTL] = pt & 0xff; LC8951RegistersW[REG_W_PTH] = (pt >> 8) &0xff; - LC8951RegistersW[REG_W_WAL] = wa & 0xff; LC8951RegistersW[REG_W_WAH] = (wa >> 8) &0xff; - -} - -int lc89510_temp_device::Read_LBA_To_Buffer() -{ - bool data_track = false; - if (CDD_CONTROL & 0x0100) data_track = true; - - if (data_track) - segacd.cd->read_data(SCD_CURLBA, SCD_BUFFER, cdrom_file::CD_TRACK_MODE1); - - LC8951UpdateHeader(); - - if (!data_track) - { - scd_advance_current_readpos(); - } - - if (LC8951RegistersW[REG_W_CTRL0] & 0x80) - { - if (LC8951RegistersW[REG_W_CTRL0] & 0x04) - { - if (data_track) - { - scd_advance_current_readpos(); - - int pt = LC8951RegistersW[REG_W_PTL] | (LC8951RegistersW[REG_W_PTH] << 8); - - memcpy(&CDC_BUFFER[pt + 4], SCD_BUFFER, 2048); - CDC_BUFFER[pt+0] = LC8951RegistersR[REG_R_HEAD0]; - CDC_BUFFER[pt+1] = LC8951RegistersR[REG_R_HEAD1]; - CDC_BUFFER[pt+2] = LC8951RegistersR[REG_R_HEAD2]; - CDC_BUFFER[pt+3] = LC8951RegistersR[REG_R_HEAD3]; - - - if (is_neoCD) - { - // This simulates the protection used by the NeoCDZ, a number of games (samsrpg for example) - // will not be recognized unless this happens. Is this part of the CDC error correction - // mechanism? - char *buffer_hack = (char*)&CDC_BUFFER[pt]; - if (buffer_hack[4 + 64] == 'g' && !strncmp(buffer_hack + 4, "Copyright by SNK", 16)) - { - buffer_hack[4 + 64] = 'f'; - } - } - - } - else - { - int pt = LC8951RegistersW[REG_W_PTL] | (LC8951RegistersW[REG_W_PTH] << 8); - - memcpy(&CDC_BUFFER[pt], SCD_BUFFER, SECTOR_SIZE); - } - } - - scd_ctrl_checks(); - - - } - - - return 0; -} - - - - - - -void lc89510_temp_device::nff0002_set(uint16_t wordValue) -{ - nff0002 = wordValue; -} - -void lc89510_temp_device::nff0016_set(uint16_t wordValue) -{ - nff0016 = wordValue; -} - -uint16_t lc89510_temp_device::nff0016_r(void) { return nff0016; } diff --git a/src/mame/messshared/megacdcd.h b/src/mame/messshared/megacdcd.h deleted file mode 100644 index 21fc407896b..00000000000 --- a/src/mame/messshared/megacdcd.h +++ /dev/null @@ -1,197 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:David Haywood -#ifndef MAME_MACHINE_SEGACDCD_H -#define MAME_MACHINE_SEGACDCD_H - -#include "imagedev/chd_cd.h" -#include "machine/timer.h" -#include "sound/cdda.h" - - -class lc89510_temp_device : public device_t -{ -public: - typedef device_delegate dma_delegate; - typedef device_delegate interrupt_delegate; - - void set_is_neoCD(bool new_is_neoCD) { is_neoCD = new_is_neoCD; } - - template void set_type1_interrupt_callback(T &&... args) { m_type1_interrupt_callback.set(std::forward(args)...); } - template void set_type2_interrupt_callback(T &&... args) { m_type2_interrupt_callback.set(std::forward(args)...); } - template void set_type3_interrupt_callback(T &&... args) { m_type3_interrupt_callback.set(std::forward(args)...); } - - template void set_cdc_do_dma_callback(T &&... args) { m_segacd_dma_callback.set(std::forward(args)...); } - - template void set_cdrom_tag(T &&tag) { m_cdrom.set_tag(std::forward(tag)); } - template void set_68k_tag(T &&tag) { m_68k.set_tag(std::forward(tag)); } - - - lc89510_temp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - uint16_t get_segacd_irq_mask() const { return segacd_irq_mask; } - - uint16_t segacd_irq_mask_r(); - void segacd_irq_mask_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t segacd_cdd_ctrl_r(); - void segacd_cdd_ctrl_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint8_t segacd_cdd_rx_r(offs_t offset); - void segacd_cdd_tx_w(offs_t offset, uint8_t data); - uint16_t segacd_cdfader_r(); - void segacd_cdfader_w(uint16_t data); - - void segacd_cdc_mode_address_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t segacd_cdc_mode_address_r(); - void segacd_cdc_data_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint16_t segacd_cdc_data_r(offs_t offset, uint16_t mem_mask = ~0); - uint16_t cdc_data_sub_r(); - uint16_t cdc_data_main_r(); - - void CDC_Do_DMA(int rate); - - uint8_t CDC_Reg_r(void); - void CDC_Reg_w(uint8_t data); - - void reset_cd(); - - // NeoGeo CD stuff - void neocd_cdd_tx_w(uint8_t data); - uint8_t neocd_cdd_rx_r(); - void NeoCDCommsControl(uint8_t clock, uint8_t send); - void NeoCDCommsReset(); - - uint16_t nff0016_r(); - void nff0016_set(uint16_t wordValue); - void nff0002_set(uint16_t wordValue); - - char* LC8915InitTransfer(int NeoCDDMACount); - void LC8915EndTransfer(); - -protected: - static constexpr unsigned SECTOR_SIZE = 2352; - static constexpr unsigned EXTERNAL_BUFFER_SIZE = (32 * 1024 * 2) + SECTOR_SIZE; - - // HACK for DMA handling - dma_delegate m_segacd_dma_callback; - interrupt_delegate m_type1_interrupt_callback; - interrupt_delegate m_type2_interrupt_callback; - interrupt_delegate m_type3_interrupt_callback; - - void Fake_CDC_Do_DMA(int &dmacount, uint8_t *CDC_BUFFER, uint16_t &dma_addrc, uint16_t &destination ); - - void dummy_interrupt_callback(); - - - required_device m_cdrom; - required_device m_cdda; - - // HACK for neoCD handling - optional_device m_68k; - bool is_neoCD; - - - struct segacd_t - { - cdrom_file *cd; - const cdrom_file::toc *toc; - uint32_t current_frame; - }; - - - segacd_t segacd; - - uint8_t SCD_BUFFER[2560]; - - uint32_t SCD_STATUS; - uint32_t SCD_STATUS_CDC; - int32_t SCD_CURLBA; - uint8_t SCD_CURTRK; - - - uint16_t CDC_DECODE; - uint16_t CDC_REG0; - uint16_t CDC_REG1; - - uint8_t CDC_BUFFER[EXTERNAL_BUFFER_SIZE]; - - - uint8_t CDD_RX[10]; - uint8_t CDD_TX[10]; - - uint32_t CDD_STATUS; - uint32_t CDD_MIN; - uint32_t CDD_SEC; - uint32_t CDD_FRAME; - uint32_t CDD_EXT; - - uint16_t CDD_CONTROL; - - int16_t CDD_DONE; - - inline int to_bcd(int val, bool byte); - void set_data_audio_mode(void); - void CDD_DoChecksum(void); - bool CDD_Check_TX_Checksum(void); - void CDD_Export(bool neocd_hack = false); - void scd_ctrl_checks(); - void scd_advance_current_readpos(void); - int Read_LBA_To_Buffer(); - void CDD_GetStatus(void); - void CDD_Stop(); - void CDD_GetPos(void); - void CDD_GetTrackPos(void); - void CDD_GetTrack(void); - void CDD_Length(void); - void CDD_FirstLast(void); - void CDD_GetTrackAdr(void); - void CDD_GetTrackType(void); - uint32_t getmsf_from_regs(void); - void CDD_Play(); - void CDD_Seek(void); - void CDD_Pause(); - void CDD_Resume(); - void CDD_FF(); - void CDD_RW(); - void CDD_Open(void); - void CDD_Close(void); - void CDD_Init(void); - void CDD_Default(void); - void CDD_Reset(void); - void CDC_Reset(void); - void lc89510_Reset(void); - void CDC_End_Transfer(); - uint16_t CDC_Host_r(uint16_t type); - void CDD_Process(int reason); - void CDD_Handle_TOC_Commands(void); - bool CDD_Import(); - - uint16_t segacd_irq_mask; - - /* NeoCD */ - uint16_t nff0002; - uint16_t nff0016; - - - int32_t LC8951RegistersR[16]; - int32_t LC8951RegistersW[16]; - - - - bool bNeoCDCommsClock; - - int32_t NeoCDCommsWordCount; - - int32_t NeoCD_StatusHack; - - void LC8951UpdateHeader(); - - - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_add_mconfig(machine_config &config) override; - - TIMER_DEVICE_CALLBACK_MEMBER( segacd_access_timer_callback ); -}; - -DECLARE_DEVICE_TYPE(LC89510_TEMP, lc89510_temp_device) - -#endif // MAME_MACHINE_SEGACDCD_H diff --git a/src/mame/messshared/mitcrt.cpp b/src/mame/messshared/mitcrt.cpp deleted file mode 100644 index 30037934a4c..00000000000 --- a/src/mame/messshared/mitcrt.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Raphael Nabet -/* - video/crt.c - - CRT video emulation for TX-0 and PDP-1. - - -Theory of operation: - - What makes such CRT devices so odd is that there is no video processor, no - scan logic, no refresh logic. The beam position and intensity is - controlled by the program completely: in order to draw an object, the - program must direct the beam to each point of the object, and in order to - refresh it, the program must redraw the object periodically. - - Since the refresh rates are highly variable (completely controlled by the - program), I need to simulate CRT remanence: the intensity of each pixel on - display decreases regularly. In order to keep this efficient, I keep a - list of non-black pixels, and only process these pixels on each refresh. - In order to improve efficiency further, I keep a distinct list for each - line of the display: I have found that it improves drawing speed slightly - (probably because it improves the cache hit rate). - - - Raphael Nabet 2002-2004 - Based on earlier work by Chris Salomon -*/ - -#include "emu.h" -#include "mitcrt.h" - - -// special value that tells that the node is not in list -enum -{ - intensity_pixel_not_in_list = -1 -}; - - -// device type definition -DEFINE_DEVICE_TYPE(CRT, crt_device, "crt", "CRT Video") - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// crt_device - constructor -//------------------------------------------------- - -crt_device::crt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, CRT, tag, owner, clock), - m_list(nullptr), - m_list_head(nullptr), - m_decay_counter(0), - m_num_intensity_levels(0), - m_window_offset_x(0), - m_window_offset_y(0), - m_window_width(0), - m_window_height(0) -{ -} - - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void crt_device::device_start() -{ - /* alloc the arrays */ - m_list = std::make_unique(m_window_width * m_window_height); - m_list_head = std::make_unique(m_window_height); - - /* fill with black and set up list as empty */ - for (int i = 0; i < (m_window_width * m_window_height); i++) - m_list[i].intensity = intensity_pixel_not_in_list; - - for (int i = 0; i < m_window_height; i++) - m_list_head[i] = -1; - - m_decay_counter = 0; -} - - -// -// crt_plot -// -// schedule a pixel to be plotted -// -void crt_device::plot(int x, int y) -{ - crt_point *node; - int list_index; - - /* compute pixel coordinates */ - if (x<0) x=0; - if (y<0) y=0; - if ((x>(m_window_width-1)) || ((y>m_window_height-1))) - return; - y = (m_window_height-1) - y; - - /* find entry in list */ - list_index = x + y*m_window_width; - - node = &m_list[list_index]; - - if (node->intensity == intensity_pixel_not_in_list) - { /* insert node in list if it is not in it */ - node->next = m_list_head[y]; - m_list_head[y] = list_index; - } - /* set intensity */ - node->intensity = m_num_intensity_levels; -} - - -// -// crt_eof -// -// keep track of time -// -void crt_device::eof() -{ - m_decay_counter++; -} - - -// -// crt_update -// -// update the bitmap -// -void crt_device::update(bitmap_ind16 &bitmap) -{ - //if (m_decay_counter) - { - /* some time has elapsed: let's update the screen */ - for (int y=0; yintensity == m_num_intensity_levels) - /* new pixel: set to max intensity */ - node->intensity = m_num_intensity_levels-1; - else - { - /* otherwise, apply intensity decay */ - node->intensity -= m_decay_counter; - if (node->intensity < 0) - node->intensity = 0; - } - - /* draw pixel on screen */ - //plot_pixel(bitmap, x, y+m_window_offset_y, node->intensity); - line[x] = node->intensity; - - if (node->intensity != 0) - p_i = i; /* current node will be next iteration's previous node */ - else - { /* delete current node */ - node->intensity = intensity_pixel_not_in_list; - if (p_i != -1) - m_list[p_i].next = node->next; - else - m_list_head[y] = node->next; - } - } - } - - m_decay_counter = 0; - } -} diff --git a/src/mame/messshared/mitcrt.h b/src/mame/messshared/mitcrt.h deleted file mode 100644 index bf4c94fd0d5..00000000000 --- a/src/mame/messshared/mitcrt.h +++ /dev/null @@ -1,76 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Raphael Nabet -/************************************************************************* - - video/crt.h - - CRT video emulation for TX-0 and PDP-1 - -*************************************************************************/ - -#ifndef MAME_VIDEO_CRT_H -#define MAME_VIDEO_CRT_H - -#pragma once - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> crt_device - -class crt_device : public device_t -{ -public: - crt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - void set_num_levels(int levels) { m_num_intensity_levels = levels; } - void set_offsets(int x_offset, int y_offset) - { - m_window_offset_x = x_offset; - m_window_offset_y = y_offset; - } - void set_size(int width, int height) - { - m_window_width = width; - m_window_height = height; - } - - void plot(int x, int y); - void eof(); - void update(bitmap_ind16 &bitmap); - -protected: - // device-level overrides - virtual void device_start() override; - -private: - struct crt_point - { - crt_point() { } - - int intensity = 0; /* current intensity of the pixel */ - /* a node is not in the list when (intensity == -1) */ - int next = 0; /* index of next pixel in list */ - }; - - std::unique_ptr m_list; /* array of (crt_window_width*crt_window_height) point */ - std::unique_ptr m_list_head; /* head of the list of lit pixels (index in the array) */ - /* keep a separate list for each display line (makes the video code slightly faster) */ - - int m_decay_counter; /* incremented each frame (tells for how many frames the CRT has decayed between two screen refresh) */ - - /* CRT window */ - int m_num_intensity_levels; - int m_window_offset_x; - int m_window_offset_y; - int m_window_width; - int m_window_height; -}; - -DECLARE_DEVICE_TYPE(CRT, crt_device) - - - -#endif // MAME_VIDEO_CRT_H diff --git a/src/mame/messshared/ms7004.cpp b/src/mame/messshared/ms7004.cpp deleted file mode 100644 index ee04d98c888..00000000000 --- a/src/mame/messshared/ms7004.cpp +++ /dev/null @@ -1,476 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Sergey Svishchev -/* - Elektronika MS 7004 keyboard (DEC LK-201 workalike with extra keys - for Cyrillic characters). - - To do: - - connect LEDs and speaker -*/ - -#include "emu.h" -#include "ms7004.h" -#include "speaker.h" - - -//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already -#define LOG_DEBUG (1U << 1) - -//#define VERBOSE (LOG_GENERAL | LOG_DEBUG) -//#define LOG_OUTPUT_FUNC printf -#include "logmacro.h" - -#define LOGDBG(...) LOGMASKED(LOG_DEBUG, __VA_ARGS__) - - -//************************************************************************** -// MACROS / CONSTANTS -//************************************************************************** - -#define MS7004_CPU_TAG "i8035" -#define MS7004_SPK_TAG "beeper" - - -//************************************************************************** -// DEVICE DEFINITIONS -//************************************************************************** - -DEFINE_DEVICE_TYPE(MS7004, ms7004_device, "ms7004", "MS7004 keyboard") - -ROM_START( ms7004 ) - ROM_REGION (0x800, MS7004_CPU_TAG, 0) - ROM_LOAD ("mc7004_keyboard_original.rom", 0x0000, 0x800, CRC(69fcab53) SHA1(2d7cc7cd182f2ee09ecf2c539e33db3c2195f778)) -ROM_END - -//------------------------------------------------- -// ADDRESS_MAP -//------------------------------------------------- - -void ms7004_device::ms7004_map(address_map &map) -{ - map(0x0000, 0x07ff).rom(); -} - - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- - -void ms7004_device::device_add_mconfig(machine_config &config) -{ - I8035(config, m_maincpu, XTAL(4'608'000)); - m_maincpu->set_addrmap(AS_PROGRAM, &ms7004_device::ms7004_map); - m_maincpu->p1_out_cb().set(FUNC(ms7004_device::p1_w)); - m_maincpu->p2_out_cb().set(FUNC(ms7004_device::p2_w)); - m_maincpu->t1_in_cb().set(FUNC(ms7004_device::t1_r)); - m_maincpu->prog_out_cb().set(m_i8243, FUNC(i8243_device::prog_w)); - - I8243(config, m_i8243); - m_i8243->p4_out_cb().set(FUNC(ms7004_device::i8243_port_w<0>)); - m_i8243->p5_out_cb().set(FUNC(ms7004_device::i8243_port_w<1>)); - m_i8243->p6_out_cb().set(FUNC(ms7004_device::i8243_port_w<2>)); - m_i8243->p7_out_cb().set(FUNC(ms7004_device::i8243_port_w<3>)); - - SPEAKER(config, "mono").front_center(); - BEEP(config, m_speaker, 3250).add_route(ALL_OUTPUTS, "mono", 0.50); -} - -const tiny_rom_entry *ms7004_device::device_rom_region() const -{ - return ROM_NAME(ms7004); -} - -//------------------------------------------------- -// INPUT_PORTS( ms7004 ) -//------------------------------------------------- -/* -bit sig XSn ????n ---- --- --- --- -0 8 16 15 -1 9 15 14 -2 10 14 13 -3 11 13 12 -4 12 19 16 -5 13 12 11 -6 14 11 10 -7 15 10 9 -8 16 9 8 -9 17 8 7 -10 18 7 6 -11 19 6 5 -12 20 3 1 -13 21 1 2 -14 22 4 3 -15 23 5 4 - -0xc9 KEY_LANGLE_RANGLE 'резервная клавиша' -0xbc KEY_DELETE ЗБ -0xbd KEY_RETURN ВК -0xbf KEY_TILDE '; +' -0xc4 - 'Ъ' -0xca - '/ ?' -0xed KEY_PERIOD 'Ю @' -0xf1 - '_' -<...> - -0x56 KEY_F1 СТОП КАДР -0x57 KEY_F2 ПЕЧАТЬ КАДРА -0x58 KEY_F3 ПАУЗА -0x59 KEY_F4 УСТ РЕЖИМА -0x5a KEY_F5 Ф5 - -0x64 KEY_F6 ПРЕРЫВ -0x65 KEY_F7 ПРОДОЛЖ -0x66 KEY_F8 ОТМЕН -0x67 KEY_F9 ОСНОВН КАДР -0x69 KEY_F10 ВЫХОД - -0x71 KEY_F11 Ф11 (АР2) -0x72 KEY_F12 Ф12 (ВШ) -0x73 KEY_F13 Ф13 (ПС) -0x74 KEY_F14 ДОП ВАРИАНТ - -0x7c KEY_HELP ПМ -0x7d KEY_MENU ИСП - -0x80 KEY_F17 Ф17 -0x81 KEY_F18 Ф18 -0x82 KEY_F19 Ф19 -0x83 KEY_F20 Ф20 - -0xb0 KEY_LOCK ФКС -0xae KEY_SHIFT ВР -0xaf KEY_CTRL СУ - -0xb1 KEY_META КМП -0xb2 - РУС/ЛАТ - -0x8a KEY_FIND НТ -0x8b KEY_INSERT_HERE ВСТ -0x8c KEY_REMOVE УДАЛ -0x8d KEY_SELECT ВЫБР -0x8e KEY_PREV_SCREEN ПРЕД КАДР -0x8f KEY_NEXT_SCREEN СЛЕД КАДР - -nothing sends '@' or '`' - -`/~ sends ^/~ -2/@ sends 2/" -6/^ sends 6/& -7/& sends 7/' -8 * sends 8/( -9/( sends 9/) -0/) sends 0/0 --/_ sends _/_ -+/= sends -/= -;/: sends ;/+ -'/" sends : * - -F10 sends ^C -F11 sends ESC -F12 sends ^H -*/ -INPUT_PORTS_START( ms7004 ) - PORT_START("KBD12") // vertical row 1 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Hold Screen (F1)") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // '{' / '|' - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) - - PORT_START("KBD13") // vertical row 2 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Setup (F3)") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Data / Talk (F4)") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHAR('j') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHAR('c') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CHAR('f') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Rus/Lat") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Compose") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) - - PORT_START("KBD14") // vertical row 3 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Break (F5)") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CHAR('u') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CHAR('y') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CHAR('q') - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD15") // vertical row 4 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CHAR('k') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CHAR('w') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CHAR('s') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD11") // vertical row 5 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Interrupt (F6)") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CHAR('e') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('p') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHAR('a') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CHAR('m') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) - - PORT_START("KBD10") // vertical row 6 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Resume (F7)") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CHAR('n') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CHAR('g') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CHAR('r') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CHAR('t') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CHAR('i') - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CHAR(' ') - - PORT_START("KBD9") // vertical row 7 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cancel (F8)") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Main Screen (F9)") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHAR('o') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x') - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CHAR('b') - - PORT_START("KBD8") // vertical row 8 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Exit (F10)") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHAR('d') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHAR('l') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('@') PORT_CHAR('`') - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') - - PORT_START("KBD7") // vertical row 9 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC (F11)") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=') - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CHAR('h') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CHAR('v') - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') - - PORT_START("KBD6") // vertical row 10 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BS (F12)") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF (F13)") PORT_CODE(KEYCODE_PRTSCR) PORT_CHAR(UCHAR_MAMEKEY(PRTSCR)) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // '}' - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*') - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // sends '_' - PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') - PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('_') PORT_CHAR('_') - - PORT_START("KBD5") // vertical row 11 - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Additional Options (F14)") PORT_CODE(KEYCODE_PAUSE) PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE); -} - -//------------------------------------------------- -// p1_w - -//------------------------------------------------- - -void ms7004_device::p1_w(uint8_t data) -{ - /* - bit description - - 0 Matrix row bit 0 - 1 Matrix row bit 1 - 2 Matrix row bit 2 - 3 Speaker - 4 -STROBE (to matrix mux) - 5 LED "Latin" - 6 - 7 Serial TX - */ - LOGDBG("p1_w %02x = send %d\n", data, BIT(data, 7)); - - m_p1 = data; - m_tx_handler(BIT(data, 7)); -} - - -//------------------------------------------------- -// p2_w - -//------------------------------------------------- - -void ms7004_device::p2_w(uint8_t data) -{ - /* - bit description - - 0 Matrix columns, to 8243 (port 4) - 1 Matrix columns, to 8243 (port 5) - 2 Matrix columns, to 8243 (port 6) - 3 Matrix columns, to 8243 (port 7) - 4 LED "Wait" - 5 LED "Compose" - 6 LED "Caps" - 7 LED "Hold" - */ - LOGDBG("p2_w %02x = col %d\n", data, data&15); - - m_p2 = data; - m_i8243->p2_w(data); -} - - -//------------------------------------------------- -// prog_w - -//------------------------------------------------- - -template -void ms7004_device::i8243_port_w(uint8_t data) -{ - int sense = 0; - - LOGDBG("8243 port %d data %02xH\n", P + 4, data); - - if (data) { - switch(data) { - case 0x01: sense = m_kbd[(P << 2) + 0]->read(); break; - case 0x02: sense = m_kbd[(P << 2) + 1]->read(); break; - case 0x04: sense = m_kbd[(P << 2) + 2]->read(); break; - case 0x08: sense = m_kbd[(P << 2) + 3]->read(); break; - } - m_keylatch = BIT(sense, (m_p1 & 7)); - if (m_keylatch) - LOG("row %d col %02x t1 %d\n", - (m_p1 & 7), (P << 4 | data), m_keylatch); - } -} - - -//------------------------------------------------- -// t1_r - -//------------------------------------------------- - -READ_LINE_MEMBER(ms7004_device::t1_r) -{ - if (!BIT(m_p1, 4)) - return m_keylatch; - else - return 0; -} diff --git a/src/mame/messshared/ms7004.h b/src/mame/messshared/ms7004.h deleted file mode 100644 index ace9c954667..00000000000 --- a/src/mame/messshared/ms7004.h +++ /dev/null @@ -1,64 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Sergey Svishchev -#ifndef MAME_MACHINE_MS7004_H -#define MAME_MACHINE_MS7004_H - -#pragma once - -#include "cpu/mcs48/mcs48.h" -#include "machine/i8243.h" -#include "sound/beep.h" - -#include "diserial.h" - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> ms7004_device - -class ms7004_device : public device_t //, public device_serial_interface -{ -public: - // construction/destruction - ms7004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - auto tx_handler() { return m_tx_handler.bind(); } - auto rts_handler() { return m_rts_handler.bind(); } - - DECLARE_WRITE_LINE_MEMBER( write_rxd ); - - void ms7004_map(address_map &map); -protected: - // device-level overrides - virtual void device_add_mconfig(machine_config &config) override; - virtual const tiny_rom_entry *device_rom_region() const override; - virtual ioport_constructor device_input_ports() const override; - virtual void device_start() override; - virtual void device_reset() override; - -private: - required_device m_maincpu; - required_device m_speaker; - required_device m_i8243; - - required_ioport_array<16> m_kbd; - - int m_keylatch; // keyboard row latch - uint8_t m_p1; - uint8_t m_p2; - - devcb_write_line m_tx_handler; - devcb_write_line m_rts_handler; - - void p1_w(uint8_t data); - void p2_w(uint8_t data); - DECLARE_READ_LINE_MEMBER( t1_r ); - template void i8243_port_w(uint8_t data); -}; - -// device type definition -DECLARE_DEVICE_TYPE(MS7004, ms7004_device) - -#endif // MAME_MACHINE_MS7004_H diff --git a/src/mame/messshared/teleprinter.cpp b/src/mame/messshared/teleprinter.cpp deleted file mode 100644 index 75b1654a7ef..00000000000 --- a/src/mame/messshared/teleprinter.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic -#include "emu.h" -#include "teleprinter.h" - -#include "screen.h" -#include "speaker.h" - - -static const uint8_t teleprinter_font[128*8] = -{ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, - 0x38,0x38,0x38,0x38,0x00,0x00,0x00,0x00, - 0x3f,0x3f,0x3f,0x3f,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, - 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, - 0x38,0x38,0x38,0x38,0x07,0x07,0x07,0x07, - 0x3f,0x3f,0x3f,0x3f,0x07,0x07,0x07,0x07, - 0x00,0x00,0x00,0x00,0x38,0x38,0x38,0x38, - 0x07,0x07,0x07,0x07,0x38,0x38,0x38,0x38, - 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, - 0x3f,0x3f,0x3f,0x3f,0x38,0x38,0x38,0x38, - 0x00,0x00,0x00,0x00,0x3f,0x3f,0x3f,0x3f, - 0x07,0x07,0x07,0x07,0x3f,0x3f,0x3f,0x3f, - 0x38,0x38,0x38,0x38,0x3f,0x3f,0x3f,0x3f, - 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, - 0x00,0x00,0x00,0x00,0x2a,0x15,0x2a,0x15, - 0x2a,0x15,0x2a,0x15,0x00,0x00,0x00,0x00, - 0x3f,0x3f,0x3f,0x3f,0x2a,0x15,0x2a,0x15, - 0x2a,0x15,0x2a,0x15,0x3f,0x3f,0x3f,0x3f, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x00, - 0x14,0x14,0x14,0x00,0x00,0x00,0x00,0x00, - 0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,0x00, - 0x08,0x3c,0x0a,0x1c,0x28,0x1e,0x08,0x00, - 0x06,0x26,0x10,0x08,0x04,0x32,0x30,0x00, - 0x08,0x14,0x14,0x0c,0x2a,0x12,0x2c,0x00, - 0x08,0x08,0x04,0x00,0x00,0x00,0x00,0x00, - 0x10,0x08,0x04,0x04,0x04,0x08,0x10,0x00, - 0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00, - 0x00,0x08,0x2a,0x1c,0x2a,0x08,0x00,0x00, - 0x00,0x08,0x08,0x3e,0x08,0x08,0x00,0x00, - 0x00,0x00,0x00,0x00,0x08,0x08,0x04,0x00, - 0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00, - 0x00,0x20,0x10,0x08,0x04,0x02,0x00,0x00, - 0x1c,0x22,0x32,0x2a,0x26,0x22,0x1c,0x00, - 0x08,0x0c,0x08,0x08,0x08,0x08,0x1c,0x00, - 0x1c,0x22,0x20,0x18,0x04,0x02,0x3e,0x00, - 0x3e,0x20,0x10,0x18,0x20,0x22,0x1c,0x00, - 0x10,0x18,0x14,0x12,0x3e,0x10,0x10,0x00, - 0x3e,0x02,0x1e,0x20,0x20,0x22,0x1c,0x00, - 0x10,0x08,0x04,0x1c,0x22,0x22,0x1c,0x00, - 0x3e,0x20,0x10,0x08,0x04,0x04,0x04,0x00, - 0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,0x00, - 0x1c,0x22,0x22,0x1c,0x10,0x08,0x04,0x00, - 0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00, - 0x00,0x00,0x08,0x00,0x08,0x08,0x04,0x00, - 0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x00, - 0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,0x00, - 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00, - 0x1c,0x22,0x20,0x10,0x08,0x00,0x08,0x00, - 0x1c,0x22,0x32,0x2a,0x3a,0x02,0x3c,0x00, - 0x08,0x14,0x22,0x22,0x3e,0x22,0x22,0x00, - 0x1e,0x22,0x22,0x1e,0x22,0x22,0x1e,0x00, - 0x1c,0x22,0x02,0x02,0x02,0x22,0x1c,0x00, - 0x1e,0x24,0x24,0x24,0x24,0x24,0x1e,0x00, - 0x3e,0x02,0x02,0x1e,0x02,0x02,0x3e,0x00, - 0x3e,0x02,0x02,0x1e,0x02,0x02,0x02,0x00, - 0x1c,0x22,0x02,0x02,0x32,0x22,0x3c,0x00, - 0x22,0x22,0x22,0x3e,0x22,0x22,0x22,0x00, - 0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,0x00, - 0x38,0x10,0x10,0x10,0x10,0x12,0x0c,0x00, - 0x22,0x12,0x0a,0x06,0x0a,0x12,0x22,0x00, - 0x02,0x02,0x02,0x02,0x02,0x02,0x3e,0x00, - 0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,0x00, - 0x22,0x22,0x26,0x2a,0x32,0x22,0x22,0x00, - 0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,0x00, - 0x1e,0x22,0x22,0x1e,0x02,0x02,0x02,0x00, - 0x1c,0x22,0x22,0x22,0x2a,0x12,0x2c,0x00, - 0x1e,0x22,0x22,0x1e,0x0a,0x12,0x22,0x00, - 0x1c,0x22,0x02,0x1c,0x20,0x22,0x1c,0x00, - 0x3e,0x08,0x08,0x08,0x08,0x08,0x08,0x00, - 0x22,0x22,0x22,0x22,0x22,0x22,0x1c,0x00, - 0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00, - 0x22,0x22,0x22,0x2a,0x2a,0x2a,0x14,0x00, - 0x22,0x22,0x14,0x08,0x14,0x22,0x22,0x00, - 0x22,0x22,0x22,0x14,0x08,0x08,0x08,0x00, - 0x3e,0x20,0x10,0x08,0x04,0x02,0x3e,0x00, - 0x0e,0x02,0x02,0x02,0x02,0x02,0x0e,0x00, - 0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00, - 0x38,0x20,0x20,0x20,0x20,0x20,0x38,0x00, - 0x08,0x1c,0x2a,0x08,0x08,0x08,0x08,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00, - 0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x1c,0x20,0x3c,0x22,0x3c,0x00, - 0x02,0x02,0x1e,0x22,0x22,0x22,0x1e,0x00, - 0x00,0x00,0x3c,0x02,0x02,0x02,0x3c,0x00, - 0x20,0x20,0x3c,0x22,0x22,0x22,0x3c,0x00, - 0x00,0x00,0x1c,0x22,0x3e,0x02,0x1c,0x00, - 0x18,0x04,0x0e,0x04,0x04,0x04,0x04,0x00, - 0x00,0x00,0x3c,0x22,0x22,0x3c,0x20,0x18, - 0x02,0x02,0x1e,0x22,0x22,0x22,0x22,0x00, - 0x08,0x00,0x0c,0x08,0x08,0x08,0x1c,0x00, - 0x10,0x00,0x18,0x10,0x10,0x10,0x12,0x0c, - 0x02,0x02,0x22,0x12,0x0e,0x16,0x22,0x00, - 0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x00, - 0x00,0x00,0x16,0x2a,0x2a,0x2a,0x2a,0x00, - 0x00,0x00,0x1a,0x26,0x22,0x22,0x22,0x00, - 0x00,0x00,0x1c,0x22,0x22,0x22,0x1c,0x00, - 0x00,0x00,0x1e,0x22,0x22,0x1e,0x02,0x02, - 0x00,0x00,0x3c,0x22,0x22,0x3c,0x20,0x20, - 0x00,0x00,0x34,0x0c,0x04,0x04,0x04,0x00, - 0x00,0x00,0x3c,0x02,0x1c,0x20,0x1e,0x00, - 0x08,0x08,0x1c,0x08,0x08,0x08,0x10,0x00, - 0x00,0x00,0x22,0x22,0x22,0x32,0x2c,0x00, - 0x00,0x00,0x22,0x22,0x22,0x14,0x08,0x00, - 0x00,0x00,0x22,0x22,0x2a,0x2a,0x14,0x00, - 0x00,0x00,0x22,0x14,0x08,0x14,0x22,0x00, - 0x00,0x00,0x22,0x22,0x14,0x08,0x04,0x02, - 0x00,0x00,0x3e,0x10,0x08,0x04,0x3e,0x00, - 0x10,0x08,0x08,0x04,0x08,0x08,0x10,0x00, - 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00, - 0x04,0x08,0x08,0x10,0x08,0x08,0x04,0x00, - 0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x2a,0x15,0x2a,0x15,0x2a,0x15,0x2a,0x15 -}; - -teleprinter_device::teleprinter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : generic_terminal_device(mconfig, TELEPRINTER, tag, owner, clock, WIDTH, HEIGHT) -{ -} - -void teleprinter_device::scroll_line() -{ - memmove(m_buffer.get(), m_buffer.get() + m_width, (m_height-1) * m_width); - memset(m_buffer.get() + m_width * (m_height-1), 0x20, m_width); -} - -void teleprinter_device::write_char(uint8_t data) { - m_buffer[(m_height-1)*m_width+m_x_pos] = data; - m_x_pos++; - if (m_x_pos >= m_width) - { - m_x_pos = 0; - scroll_line(); - } -} - -void teleprinter_device::clear() { - memset(m_buffer.get(), 0, m_width*m_height); - m_x_pos = 0; -} - -void teleprinter_device::term_write(uint8_t data) -{ - switch(data) { - case 10: m_x_pos = 0; - scroll_line(); - break; - case 13: m_x_pos = 0; break; - case 9: m_x_pos = (m_x_pos & 0xf8) + 8; - if (m_x_pos >= m_width) - m_x_pos = m_width-1; - - break; - case 16: break; - default: write_char(data); break; - } -} - -/*************************************************************************** - VIDEO HARDWARE -***************************************************************************/ -uint32_t teleprinter_device::tp_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - for (int y = 0; y < m_height; y++) - { - for (int c = 0; c < 8; c++) - { - int horpos = 0; - for (int x = 0; x < m_width; x++) - { - uint8_t code = teleprinter_font[(m_buffer[y*m_width + x] & 0x7f) *8 + c]; - for (int b = 0; b < 8; b++) - { - bitmap.pix(y*8 + c, horpos++) = (code >> b) & 0x01 ? 0 : 0x00ffffff; - } - } - } - } - return 0; -} - -/*************************************************************************** - VIDEO HARDWARE -***************************************************************************/ -void teleprinter_device::device_add_mconfig(machine_config &config) -{ - screen_device &screen(SCREEN(config, TELEPRINTER_SCREEN_TAG, SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(50); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ - screen.set_size(teleprinter_device::WIDTH*8, teleprinter_device::HEIGHT*8); - screen.set_visarea(0, teleprinter_device::WIDTH*8-1, 0, teleprinter_device::HEIGHT*8-1); - screen.set_screen_update(FUNC(teleprinter_device::tp_update)); - generic_keyboard_device &keyboard(GENERIC_KEYBOARD(config, "keyboard", 0)); - keyboard.set_keyboard_callback(FUNC(generic_terminal_device::kbd_put)); - - SPEAKER(config, "bell").front_center(); - BEEP(config, "beeper", 2'000).add_route(ALL_OUTPUTS, "bell", 0.50); -} - - -/*------------------------------------------------- - device_reset - device-specific reset --------------------------------------------------*/ - -void teleprinter_device::device_reset() -{ - clear(); - generic_terminal_device::device_reset(); -} - -DEFINE_DEVICE_TYPE(TELEPRINTER, teleprinter_device, "teleprinter", "Teleprinter") diff --git a/src/mame/messshared/teleprinter.h b/src/mame/messshared/teleprinter.h deleted file mode 100644 index 05eb6c63c8f..00000000000 --- a/src/mame/messshared/teleprinter.h +++ /dev/null @@ -1,42 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic -#ifndef MAME_MACHINE_TELEPRINTER_H -#define MAME_MACHINE_TELEPRINTER_H - -#pragma once - -#include "machine/terminal.h" - - -/*************************************************************************** - DEVICE CONFIGURATION MACROS -***************************************************************************/ - -#define TELEPRINTER_SCREEN_TAG "tty_screen" - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -class teleprinter_device : public generic_terminal_device -{ -public: - teleprinter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - virtual void term_write(uint8_t data) override; - virtual void device_reset() override; - virtual void device_add_mconfig(machine_config &config) override; - -private: - static constexpr unsigned WIDTH = 80; - static constexpr unsigned HEIGHT = 50; - uint32_t tp_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect); - void scroll_line(); - void write_char(uint8_t data); - void clear(); -}; - -DECLARE_DEVICE_TYPE(TELEPRINTER, teleprinter_device) - -#endif // MAME_MACHINE_TELEPRINTER_H diff --git a/src/mame/messshared/vboysound.cpp b/src/mame/messshared/vboysound.cpp deleted file mode 100644 index 5cb56eddabf..00000000000 --- a/src/mame/messshared/vboysound.cpp +++ /dev/null @@ -1,501 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont -/* - vboy.c - Virtual Boy audio emulation - - By Richard Bannister and Gil Pedersen. - MAME device adaptation by R. Belmont -*/ - -#include "emu.h" -#include "vboysound.h" - -// device type definition -DEFINE_DEVICE_TYPE(VBOYSND, vboysnd_device, "vboysnd", "Virtual Boy Audio") - -//#define LAME_COMPILER_BUG - -#define SxINT 0x00 -#define SxLRV 0x04 -#define SxFQL 0x08 -#define SxFQH 0x0c -#define SxEV0 0x10 -#define SxEV1 0x14 -#define SxRAM 0x18 - -#define SxINTb 0x400+SxINT -#define SxLRVb 0x400+SxLRV -#define SxFQLb 0x400+SxFQL -#define SxFQHb 0x400+SxFQH -#define SxEV0b 0x400+SxEV0 -#define SxEV1b 0x400+SxEV1 -#define SxRAMb 0x400+SxRAM - -#define S5SWP 0x51c -#define SST0P 0x580 - -static const uint16_t outTbl[64][32] = { - { 0x0000, 0xffe0, 0xffc0, 0xffa0, 0xff80, 0xff60, 0xff40, 0xff20, 0xff00, 0xfee0, 0xfec0, 0xfea0, 0xfe80, 0xfe60, 0xfe40, 0xfe20, - 0xfe00, 0xfde0, 0xfdc0, 0xfda0, 0xfd80, 0xfd60, 0xfd40, 0xfd20, 0xfd00, 0xfce0, 0xfcc0, 0xfca0, 0xfc80, 0xfc60, 0xfc40, 0xfc20}, - { 0x0000, 0xffe1, 0xffc2, 0xffa3, 0xff84, 0xff65, 0xff46, 0xff27, 0xff08, 0xfee9, 0xfeca, 0xfeab, 0xfe8c, 0xfe6d, 0xfe4e, 0xfe2f, - 0xfe10, 0xfdf1, 0xfdd2, 0xfdb3, 0xfd94, 0xfd75, 0xfd56, 0xfd37, 0xfd18, 0xfcf9, 0xfcda, 0xfcbb, 0xfc9c, 0xfc7d, 0xfc5e, 0xfc3f}, - { 0x0000, 0xffe2, 0xffc4, 0xffa6, 0xff88, 0xff6a, 0xff4c, 0xff2e, 0xff10, 0xfef2, 0xfed4, 0xfeb6, 0xfe98, 0xfe7a, 0xfe5c, 0xfe3e, - 0xfe20, 0xfe02, 0xfde4, 0xfdc6, 0xfda8, 0xfd8a, 0xfd6c, 0xfd4e, 0xfd30, 0xfd12, 0xfcf4, 0xfcd6, 0xfcb8, 0xfc9a, 0xfc7c, 0xfc5e}, - { 0x0000, 0xffe3, 0xffc6, 0xffa9, 0xff8c, 0xff6f, 0xff52, 0xff35, 0xff18, 0xfefb, 0xfede, 0xfec1, 0xfea4, 0xfe87, 0xfe6a, 0xfe4d, - 0xfe30, 0xfe13, 0xfdf6, 0xfdd9, 0xfdbc, 0xfd9f, 0xfd82, 0xfd65, 0xfd48, 0xfd2b, 0xfd0e, 0xfcf1, 0xfcd4, 0xfcb7, 0xfc9a, 0xfc7d}, - { 0x0000, 0xffe4, 0xffc8, 0xffac, 0xff90, 0xff74, 0xff58, 0xff3c, 0xff20, 0xff04, 0xfee8, 0xfecc, 0xfeb0, 0xfe94, 0xfe78, 0xfe5c, - 0xfe40, 0xfe24, 0xfe08, 0xfdec, 0xfdd0, 0xfdb4, 0xfd98, 0xfd7c, 0xfd60, 0xfd44, 0xfd28, 0xfd0c, 0xfcf0, 0xfcd4, 0xfcb8, 0xfc9c}, - { 0x0000, 0xffe5, 0xffca, 0xffaf, 0xff94, 0xff79, 0xff5e, 0xff43, 0xff28, 0xff0d, 0xfef2, 0xfed7, 0xfebc, 0xfea1, 0xfe86, 0xfe6b, - 0xfe50, 0xfe35, 0xfe1a, 0xfdff, 0xfde4, 0xfdc9, 0xfdae, 0xfd93, 0xfd78, 0xfd5d, 0xfd42, 0xfd27, 0xfd0c, 0xfcf1, 0xfcd6, 0xfcbb}, - { 0x0000, 0xffe6, 0xffcc, 0xffb2, 0xff98, 0xff7e, 0xff64, 0xff4a, 0xff30, 0xff16, 0xfefc, 0xfee2, 0xfec8, 0xfeae, 0xfe94, 0xfe7a, - 0xfe60, 0xfe46, 0xfe2c, 0xfe12, 0xfdf8, 0xfdde, 0xfdc4, 0xfdaa, 0xfd90, 0xfd76, 0xfd5c, 0xfd42, 0xfd28, 0xfd0e, 0xfcf4, 0xfcda}, - { 0x0000, 0xffe7, 0xffce, 0xffb5, 0xff9c, 0xff83, 0xff6a, 0xff51, 0xff38, 0xff1f, 0xff06, 0xfeed, 0xfed4, 0xfebb, 0xfea2, 0xfe89, - 0xfe70, 0xfe57, 0xfe3e, 0xfe25, 0xfe0c, 0xfdf3, 0xfdda, 0xfdc1, 0xfda8, 0xfd8f, 0xfd76, 0xfd5d, 0xfd44, 0xfd2b, 0xfd12, 0xfcf9}, - { 0x0000, 0xffe8, 0xffd0, 0xffb8, 0xffa0, 0xff88, 0xff70, 0xff58, 0xff40, 0xff28, 0xff10, 0xfef8, 0xfee0, 0xfec8, 0xfeb0, 0xfe98, - 0xfe80, 0xfe68, 0xfe50, 0xfe38, 0xfe20, 0xfe08, 0xfdf0, 0xfdd8, 0xfdc0, 0xfda8, 0xfd90, 0xfd78, 0xfd60, 0xfd48, 0xfd30, 0xfd18}, - { 0x0000, 0xffe9, 0xffd2, 0xffbb, 0xffa4, 0xff8d, 0xff76, 0xff5f, 0xff48, 0xff31, 0xff1a, 0xff03, 0xfeec, 0xfed5, 0xfebe, 0xfea7, - 0xfe90, 0xfe79, 0xfe62, 0xfe4b, 0xfe34, 0xfe1d, 0xfe06, 0xfdef, 0xfdd8, 0xfdc1, 0xfdaa, 0xfd93, 0xfd7c, 0xfd65, 0xfd4e, 0xfd37}, - { 0x0000, 0xffea, 0xffd4, 0xffbe, 0xffa8, 0xff92, 0xff7c, 0xff66, 0xff50, 0xff3a, 0xff24, 0xff0e, 0xfef8, 0xfee2, 0xfecc, 0xfeb6, - 0xfea0, 0xfe8a, 0xfe74, 0xfe5e, 0xfe48, 0xfe32, 0xfe1c, 0xfe06, 0xfdf0, 0xfdda, 0xfdc4, 0xfdae, 0xfd98, 0xfd82, 0xfd6c, 0xfd56}, - { 0x0000, 0xffeb, 0xffd6, 0xffc1, 0xffac, 0xff97, 0xff82, 0xff6d, 0xff58, 0xff43, 0xff2e, 0xff19, 0xff04, 0xfeef, 0xfeda, 0xfec5, - 0xfeb0, 0xfe9b, 0xfe86, 0xfe71, 0xfe5c, 0xfe47, 0xfe32, 0xfe1d, 0xfe08, 0xfdf3, 0xfdde, 0xfdc9, 0xfdb4, 0xfd9f, 0xfd8a, 0xfd75}, - { 0x0000, 0xffec, 0xffd8, 0xffc4, 0xffb0, 0xff9c, 0xff88, 0xff74, 0xff60, 0xff4c, 0xff38, 0xff24, 0xff10, 0xfefc, 0xfee8, 0xfed4, - 0xfec0, 0xfeac, 0xfe98, 0xfe84, 0xfe70, 0xfe5c, 0xfe48, 0xfe34, 0xfe20, 0xfe0c, 0xfdf8, 0xfde4, 0xfdd0, 0xfdbc, 0xfda8, 0xfd94}, - { 0x0000, 0xffed, 0xffda, 0xffc7, 0xffb4, 0xffa1, 0xff8e, 0xff7b, 0xff68, 0xff55, 0xff42, 0xff2f, 0xff1c, 0xff09, 0xfef6, 0xfee3, - 0xfed0, 0xfebd, 0xfeaa, 0xfe97, 0xfe84, 0xfe71, 0xfe5e, 0xfe4b, 0xfe38, 0xfe25, 0xfe12, 0xfdff, 0xfdec, 0xfdd9, 0xfdc6, 0xfdb3}, - { 0x0000, 0xffee, 0xffdc, 0xffca, 0xffb8, 0xffa6, 0xff94, 0xff82, 0xff70, 0xff5e, 0xff4c, 0xff3a, 0xff28, 0xff16, 0xff04, 0xfef2, - 0xfee0, 0xfece, 0xfebc, 0xfeaa, 0xfe98, 0xfe86, 0xfe74, 0xfe62, 0xfe50, 0xfe3e, 0xfe2c, 0xfe1a, 0xfe08, 0xfdf6, 0xfde4, 0xfdd2}, - { 0x0000, 0xffef, 0xffde, 0xffcd, 0xffbc, 0xffab, 0xff9a, 0xff89, 0xff78, 0xff67, 0xff56, 0xff45, 0xff34, 0xff23, 0xff12, 0xff01, - 0xfef0, 0xfedf, 0xfece, 0xfebd, 0xfeac, 0xfe9b, 0xfe8a, 0xfe79, 0xfe68, 0xfe57, 0xfe46, 0xfe35, 0xfe24, 0xfe13, 0xfe02, 0xfdf1}, - { 0x0000, 0xfff0, 0xffe0, 0xffd0, 0xffc0, 0xffb0, 0xffa0, 0xff90, 0xff80, 0xff70, 0xff60, 0xff50, 0xff40, 0xff30, 0xff20, 0xff10, - 0xff00, 0xfef0, 0xfee0, 0xfed0, 0xfec0, 0xfeb0, 0xfea0, 0xfe90, 0xfe80, 0xfe70, 0xfe60, 0xfe50, 0xfe40, 0xfe30, 0xfe20, 0xfe10}, - { 0x0000, 0xfff1, 0xffe2, 0xffd3, 0xffc4, 0xffb5, 0xffa6, 0xff97, 0xff88, 0xff79, 0xff6a, 0xff5b, 0xff4c, 0xff3d, 0xff2e, 0xff1f, - 0xff10, 0xff01, 0xfef2, 0xfee3, 0xfed4, 0xfec5, 0xfeb6, 0xfea7, 0xfe98, 0xfe89, 0xfe7a, 0xfe6b, 0xfe5c, 0xfe4d, 0xfe3e, 0xfe2f}, - { 0x0000, 0xfff2, 0xffe4, 0xffd6, 0xffc8, 0xffba, 0xffac, 0xff9e, 0xff90, 0xff82, 0xff74, 0xff66, 0xff58, 0xff4a, 0xff3c, 0xff2e, - 0xff20, 0xff12, 0xff04, 0xfef6, 0xfee8, 0xfeda, 0xfecc, 0xfebe, 0xfeb0, 0xfea2, 0xfe94, 0xfe86, 0xfe78, 0xfe6a, 0xfe5c, 0xfe4e}, - { 0x0000, 0xfff3, 0xffe6, 0xffd9, 0xffcc, 0xffbf, 0xffb2, 0xffa5, 0xff98, 0xff8b, 0xff7e, 0xff71, 0xff64, 0xff57, 0xff4a, 0xff3d, - 0xff30, 0xff23, 0xff16, 0xff09, 0xfefc, 0xfeef, 0xfee2, 0xfed5, 0xfec8, 0xfebb, 0xfeae, 0xfea1, 0xfe94, 0xfe87, 0xfe7a, 0xfe6d}, - { 0x0000, 0xfff4, 0xffe8, 0xffdc, 0xffd0, 0xffc4, 0xffb8, 0xffac, 0xffa0, 0xff94, 0xff88, 0xff7c, 0xff70, 0xff64, 0xff58, 0xff4c, - 0xff40, 0xff34, 0xff28, 0xff1c, 0xff10, 0xff04, 0xfef8, 0xfeec, 0xfee0, 0xfed4, 0xfec8, 0xfebc, 0xfeb0, 0xfea4, 0xfe98, 0xfe8c}, - { 0x0000, 0xfff5, 0xffea, 0xffdf, 0xffd4, 0xffc9, 0xffbe, 0xffb3, 0xffa8, 0xff9d, 0xff92, 0xff87, 0xff7c, 0xff71, 0xff66, 0xff5b, - 0xff50, 0xff45, 0xff3a, 0xff2f, 0xff24, 0xff19, 0xff0e, 0xff03, 0xfef8, 0xfeed, 0xfee2, 0xfed7, 0xfecc, 0xfec1, 0xfeb6, 0xfeab}, - { 0x0000, 0xfff6, 0xffec, 0xffe2, 0xffd8, 0xffce, 0xffc4, 0xffba, 0xffb0, 0xffa6, 0xff9c, 0xff92, 0xff88, 0xff7e, 0xff74, 0xff6a, - 0xff60, 0xff56, 0xff4c, 0xff42, 0xff38, 0xff2e, 0xff24, 0xff1a, 0xff10, 0xff06, 0xfefc, 0xfef2, 0xfee8, 0xfede, 0xfed4, 0xfeca}, - { 0x0000, 0xfff7, 0xffee, 0xffe5, 0xffdc, 0xffd3, 0xffca, 0xffc1, 0xffb8, 0xffaf, 0xffa6, 0xff9d, 0xff94, 0xff8b, 0xff82, 0xff79, - 0xff70, 0xff67, 0xff5e, 0xff55, 0xff4c, 0xff43, 0xff3a, 0xff31, 0xff28, 0xff1f, 0xff16, 0xff0d, 0xff04, 0xfefb, 0xfef2, 0xfee9}, - { 0x0000, 0xfff8, 0xfff0, 0xffe8, 0xffe0, 0xffd8, 0xffd0, 0xffc8, 0xffc0, 0xffb8, 0xffb0, 0xffa8, 0xffa0, 0xff98, 0xff90, 0xff88, - 0xff80, 0xff78, 0xff70, 0xff68, 0xff60, 0xff58, 0xff50, 0xff48, 0xff40, 0xff38, 0xff30, 0xff28, 0xff20, 0xff18, 0xff10, 0xff08}, - { 0x0000, 0xfff9, 0xfff2, 0xffeb, 0xffe4, 0xffdd, 0xffd6, 0xffcf, 0xffc8, 0xffc1, 0xffba, 0xffb3, 0xffac, 0xffa5, 0xff9e, 0xff97, - 0xff90, 0xff89, 0xff82, 0xff7b, 0xff74, 0xff6d, 0xff66, 0xff5f, 0xff58, 0xff51, 0xff4a, 0xff43, 0xff3c, 0xff35, 0xff2e, 0xff27}, - { 0x0000, 0xfffa, 0xfff4, 0xffee, 0xffe8, 0xffe2, 0xffdc, 0xffd6, 0xffd0, 0xffca, 0xffc4, 0xffbe, 0xffb8, 0xffb2, 0xffac, 0xffa6, - 0xffa0, 0xff9a, 0xff94, 0xff8e, 0xff88, 0xff82, 0xff7c, 0xff76, 0xff70, 0xff6a, 0xff64, 0xff5e, 0xff58, 0xff52, 0xff4c, 0xff46}, - { 0x0000, 0xfffb, 0xfff6, 0xfff1, 0xffec, 0xffe7, 0xffe2, 0xffdd, 0xffd8, 0xffd3, 0xffce, 0xffc9, 0xffc4, 0xffbf, 0xffba, 0xffb5, - 0xffb0, 0xffab, 0xffa6, 0xffa1, 0xff9c, 0xff97, 0xff92, 0xff8d, 0xff88, 0xff83, 0xff7e, 0xff79, 0xff74, 0xff6f, 0xff6a, 0xff65}, - { 0x0000, 0xfffc, 0xfff8, 0xfff4, 0xfff0, 0xffec, 0xffe8, 0xffe4, 0xffe0, 0xffdc, 0xffd8, 0xffd4, 0xffd0, 0xffcc, 0xffc8, 0xffc4, - 0xffc0, 0xffbc, 0xffb8, 0xffb4, 0xffb0, 0xffac, 0xffa8, 0xffa4, 0xffa0, 0xff9c, 0xff98, 0xff94, 0xff90, 0xff8c, 0xff88, 0xff84}, - { 0x0000, 0xfffd, 0xfffa, 0xfff7, 0xfff4, 0xfff1, 0xffee, 0xffeb, 0xffe8, 0xffe5, 0xffe2, 0xffdf, 0xffdc, 0xffd9, 0xffd6, 0xffd3, - 0xffd0, 0xffcd, 0xffca, 0xffc7, 0xffc4, 0xffc1, 0xffbe, 0xffbb, 0xffb8, 0xffb5, 0xffb2, 0xffaf, 0xffac, 0xffa9, 0xffa6, 0xffa3}, - { 0x0000, 0xfffe, 0xfffc, 0xfffa, 0xfff8, 0xfff6, 0xfff4, 0xfff2, 0xfff0, 0xffee, 0xffec, 0xffea, 0xffe8, 0xffe6, 0xffe4, 0xffe2, - 0xffe0, 0xffde, 0xffdc, 0xffda, 0xffd8, 0xffd6, 0xffd4, 0xffd2, 0xffd0, 0xffce, 0xffcc, 0xffca, 0xffc8, 0xffc6, 0xffc4, 0xffc2}, - { 0x0000, 0xffff, 0xfffe, 0xfffd, 0xfffc, 0xfffb, 0xfffa, 0xfff9, 0xfff8, 0xfff7, 0xfff6, 0xfff5, 0xfff4, 0xfff3, 0xfff2, 0xfff1, - 0xfff0, 0xffef, 0xffee, 0xffed, 0xffec, 0xffeb, 0xffea, 0xffe9, 0xffe8, 0xffe7, 0xffe6, 0xffe5, 0xffe4, 0xffe3, 0xffe2, 0xffe1}, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f}, - { 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001a, 0x001c, 0x001e, - 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003a, 0x003c, 0x003e}, - { 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, 0x0018, 0x001b, 0x001e, 0x0021, 0x0024, 0x0027, 0x002a, 0x002d, - 0x0030, 0x0033, 0x0036, 0x0039, 0x003c, 0x003f, 0x0042, 0x0045, 0x0048, 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005a, 0x005d}, - { 0x0000, 0x0004, 0x0008, 0x000c, 0x0010, 0x0014, 0x0018, 0x001c, 0x0020, 0x0024, 0x0028, 0x002c, 0x0030, 0x0034, 0x0038, 0x003c, - 0x0040, 0x0044, 0x0048, 0x004c, 0x0050, 0x0054, 0x0058, 0x005c, 0x0060, 0x0064, 0x0068, 0x006c, 0x0070, 0x0074, 0x0078, 0x007c}, - { 0x0000, 0x0005, 0x000a, 0x000f, 0x0014, 0x0019, 0x001e, 0x0023, 0x0028, 0x002d, 0x0032, 0x0037, 0x003c, 0x0041, 0x0046, 0x004b, - 0x0050, 0x0055, 0x005a, 0x005f, 0x0064, 0x0069, 0x006e, 0x0073, 0x0078, 0x007d, 0x0082, 0x0087, 0x008c, 0x0091, 0x0096, 0x009b}, - { 0x0000, 0x0006, 0x000c, 0x0012, 0x0018, 0x001e, 0x0024, 0x002a, 0x0030, 0x0036, 0x003c, 0x0042, 0x0048, 0x004e, 0x0054, 0x005a, - 0x0060, 0x0066, 0x006c, 0x0072, 0x0078, 0x007e, 0x0084, 0x008a, 0x0090, 0x0096, 0x009c, 0x00a2, 0x00a8, 0x00ae, 0x00b4, 0x00ba}, - { 0x0000, 0x0007, 0x000e, 0x0015, 0x001c, 0x0023, 0x002a, 0x0031, 0x0038, 0x003f, 0x0046, 0x004d, 0x0054, 0x005b, 0x0062, 0x0069, - 0x0070, 0x0077, 0x007e, 0x0085, 0x008c, 0x0093, 0x009a, 0x00a1, 0x00a8, 0x00af, 0x00b6, 0x00bd, 0x00c4, 0x00cb, 0x00d2, 0x00d9}, - { 0x0000, 0x0008, 0x0010, 0x0018, 0x0020, 0x0028, 0x0030, 0x0038, 0x0040, 0x0048, 0x0050, 0x0058, 0x0060, 0x0068, 0x0070, 0x0078, - 0x0080, 0x0088, 0x0090, 0x0098, 0x00a0, 0x00a8, 0x00b0, 0x00b8, 0x00c0, 0x00c8, 0x00d0, 0x00d8, 0x00e0, 0x00e8, 0x00f0, 0x00f8}, - { 0x0000, 0x0009, 0x0012, 0x001b, 0x0024, 0x002d, 0x0036, 0x003f, 0x0048, 0x0051, 0x005a, 0x0063, 0x006c, 0x0075, 0x007e, 0x0087, - 0x0090, 0x0099, 0x00a2, 0x00ab, 0x00b4, 0x00bd, 0x00c6, 0x00cf, 0x00d8, 0x00e1, 0x00ea, 0x00f3, 0x00fc, 0x0105, 0x010e, 0x0117}, - { 0x0000, 0x000a, 0x0014, 0x001e, 0x0028, 0x0032, 0x003c, 0x0046, 0x0050, 0x005a, 0x0064, 0x006e, 0x0078, 0x0082, 0x008c, 0x0096, - 0x00a0, 0x00aa, 0x00b4, 0x00be, 0x00c8, 0x00d2, 0x00dc, 0x00e6, 0x00f0, 0x00fa, 0x0104, 0x010e, 0x0118, 0x0122, 0x012c, 0x0136}, - { 0x0000, 0x000b, 0x0016, 0x0021, 0x002c, 0x0037, 0x0042, 0x004d, 0x0058, 0x0063, 0x006e, 0x0079, 0x0084, 0x008f, 0x009a, 0x00a5, - 0x00b0, 0x00bb, 0x00c6, 0x00d1, 0x00dc, 0x00e7, 0x00f2, 0x00fd, 0x0108, 0x0113, 0x011e, 0x0129, 0x0134, 0x013f, 0x014a, 0x0155}, - { 0x0000, 0x000c, 0x0018, 0x0024, 0x0030, 0x003c, 0x0048, 0x0054, 0x0060, 0x006c, 0x0078, 0x0084, 0x0090, 0x009c, 0x00a8, 0x00b4, - 0x00c0, 0x00cc, 0x00d8, 0x00e4, 0x00f0, 0x00fc, 0x0108, 0x0114, 0x0120, 0x012c, 0x0138, 0x0144, 0x0150, 0x015c, 0x0168, 0x0174}, - { 0x0000, 0x000d, 0x001a, 0x0027, 0x0034, 0x0041, 0x004e, 0x005b, 0x0068, 0x0075, 0x0082, 0x008f, 0x009c, 0x00a9, 0x00b6, 0x00c3, - 0x00d0, 0x00dd, 0x00ea, 0x00f7, 0x0104, 0x0111, 0x011e, 0x012b, 0x0138, 0x0145, 0x0152, 0x015f, 0x016c, 0x0179, 0x0186, 0x0193}, - { 0x0000, 0x000e, 0x001c, 0x002a, 0x0038, 0x0046, 0x0054, 0x0062, 0x0070, 0x007e, 0x008c, 0x009a, 0x00a8, 0x00b6, 0x00c4, 0x00d2, - 0x00e0, 0x00ee, 0x00fc, 0x010a, 0x0118, 0x0126, 0x0134, 0x0142, 0x0150, 0x015e, 0x016c, 0x017a, 0x0188, 0x0196, 0x01a4, 0x01b2}, - { 0x0000, 0x000f, 0x001e, 0x002d, 0x003c, 0x004b, 0x005a, 0x0069, 0x0078, 0x0087, 0x0096, 0x00a5, 0x00b4, 0x00c3, 0x00d2, 0x00e1, - 0x00f0, 0x00ff, 0x010e, 0x011d, 0x012c, 0x013b, 0x014a, 0x0159, 0x0168, 0x0177, 0x0186, 0x0195, 0x01a4, 0x01b3, 0x01c2, 0x01d1}, - { 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, 0x0090, 0x00a0, 0x00b0, 0x00c0, 0x00d0, 0x00e0, 0x00f0, - 0x0100, 0x0110, 0x0120, 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01a0, 0x01b0, 0x01c0, 0x01d0, 0x01e0, 0x01f0}, - { 0x0000, 0x0011, 0x0022, 0x0033, 0x0044, 0x0055, 0x0066, 0x0077, 0x0088, 0x0099, 0x00aa, 0x00bb, 0x00cc, 0x00dd, 0x00ee, 0x00ff, - 0x0110, 0x0121, 0x0132, 0x0143, 0x0154, 0x0165, 0x0176, 0x0187, 0x0198, 0x01a9, 0x01ba, 0x01cb, 0x01dc, 0x01ed, 0x01fe, 0x020f}, - { 0x0000, 0x0012, 0x0024, 0x0036, 0x0048, 0x005a, 0x006c, 0x007e, 0x0090, 0x00a2, 0x00b4, 0x00c6, 0x00d8, 0x00ea, 0x00fc, 0x010e, - 0x0120, 0x0132, 0x0144, 0x0156, 0x0168, 0x017a, 0x018c, 0x019e, 0x01b0, 0x01c2, 0x01d4, 0x01e6, 0x01f8, 0x020a, 0x021c, 0x022e}, - { 0x0000, 0x0013, 0x0026, 0x0039, 0x004c, 0x005f, 0x0072, 0x0085, 0x0098, 0x00ab, 0x00be, 0x00d1, 0x00e4, 0x00f7, 0x010a, 0x011d, - 0x0130, 0x0143, 0x0156, 0x0169, 0x017c, 0x018f, 0x01a2, 0x01b5, 0x01c8, 0x01db, 0x01ee, 0x0201, 0x0214, 0x0227, 0x023a, 0x024d}, - { 0x0000, 0x0014, 0x0028, 0x003c, 0x0050, 0x0064, 0x0078, 0x008c, 0x00a0, 0x00b4, 0x00c8, 0x00dc, 0x00f0, 0x0104, 0x0118, 0x012c, - 0x0140, 0x0154, 0x0168, 0x017c, 0x0190, 0x01a4, 0x01b8, 0x01cc, 0x01e0, 0x01f4, 0x0208, 0x021c, 0x0230, 0x0244, 0x0258, 0x026c}, - { 0x0000, 0x0015, 0x002a, 0x003f, 0x0054, 0x0069, 0x007e, 0x0093, 0x00a8, 0x00bd, 0x00d2, 0x00e7, 0x00fc, 0x0111, 0x0126, 0x013b, - 0x0150, 0x0165, 0x017a, 0x018f, 0x01a4, 0x01b9, 0x01ce, 0x01e3, 0x01f8, 0x020d, 0x0222, 0x0237, 0x024c, 0x0261, 0x0276, 0x028b}, - { 0x0000, 0x0016, 0x002c, 0x0042, 0x0058, 0x006e, 0x0084, 0x009a, 0x00b0, 0x00c6, 0x00dc, 0x00f2, 0x0108, 0x011e, 0x0134, 0x014a, - 0x0160, 0x0176, 0x018c, 0x01a2, 0x01b8, 0x01ce, 0x01e4, 0x01fa, 0x0210, 0x0226, 0x023c, 0x0252, 0x0268, 0x027e, 0x0294, 0x02aa}, - { 0x0000, 0x0017, 0x002e, 0x0045, 0x005c, 0x0073, 0x008a, 0x00a1, 0x00b8, 0x00cf, 0x00e6, 0x00fd, 0x0114, 0x012b, 0x0142, 0x0159, - 0x0170, 0x0187, 0x019e, 0x01b5, 0x01cc, 0x01e3, 0x01fa, 0x0211, 0x0228, 0x023f, 0x0256, 0x026d, 0x0284, 0x029b, 0x02b2, 0x02c9}, - { 0x0000, 0x0018, 0x0030, 0x0048, 0x0060, 0x0078, 0x0090, 0x00a8, 0x00c0, 0x00d8, 0x00f0, 0x0108, 0x0120, 0x0138, 0x0150, 0x0168, - 0x0180, 0x0198, 0x01b0, 0x01c8, 0x01e0, 0x01f8, 0x0210, 0x0228, 0x0240, 0x0258, 0x0270, 0x0288, 0x02a0, 0x02b8, 0x02d0, 0x02e8}, - { 0x0000, 0x0019, 0x0032, 0x004b, 0x0064, 0x007d, 0x0096, 0x00af, 0x00c8, 0x00e1, 0x00fa, 0x0113, 0x012c, 0x0145, 0x015e, 0x0177, - 0x0190, 0x01a9, 0x01c2, 0x01db, 0x01f4, 0x020d, 0x0226, 0x023f, 0x0258, 0x0271, 0x028a, 0x02a3, 0x02bc, 0x02d5, 0x02ee, 0x0307}, - { 0x0000, 0x001a, 0x0034, 0x004e, 0x0068, 0x0082, 0x009c, 0x00b6, 0x00d0, 0x00ea, 0x0104, 0x011e, 0x0138, 0x0152, 0x016c, 0x0186, - 0x01a0, 0x01ba, 0x01d4, 0x01ee, 0x0208, 0x0222, 0x023c, 0x0256, 0x0270, 0x028a, 0x02a4, 0x02be, 0x02d8, 0x02f2, 0x030c, 0x0326}, - { 0x0000, 0x001b, 0x0036, 0x0051, 0x006c, 0x0087, 0x00a2, 0x00bd, 0x00d8, 0x00f3, 0x010e, 0x0129, 0x0144, 0x015f, 0x017a, 0x0195, - 0x01b0, 0x01cb, 0x01e6, 0x0201, 0x021c, 0x0237, 0x0252, 0x026d, 0x0288, 0x02a3, 0x02be, 0x02d9, 0x02f4, 0x030f, 0x032a, 0x0345}, - { 0x0000, 0x001c, 0x0038, 0x0054, 0x0070, 0x008c, 0x00a8, 0x00c4, 0x00e0, 0x00fc, 0x0118, 0x0134, 0x0150, 0x016c, 0x0188, 0x01a4, - 0x01c0, 0x01dc, 0x01f8, 0x0214, 0x0230, 0x024c, 0x0268, 0x0284, 0x02a0, 0x02bc, 0x02d8, 0x02f4, 0x0310, 0x032c, 0x0348, 0x0364}, - { 0x0000, 0x001d, 0x003a, 0x0057, 0x0074, 0x0091, 0x00ae, 0x00cb, 0x00e8, 0x0105, 0x0122, 0x013f, 0x015c, 0x0179, 0x0196, 0x01b3, - 0x01d0, 0x01ed, 0x020a, 0x0227, 0x0244, 0x0261, 0x027e, 0x029b, 0x02b8, 0x02d5, 0x02f2, 0x030f, 0x032c, 0x0349, 0x0366, 0x0383}, - { 0x0000, 0x001e, 0x003c, 0x005a, 0x0078, 0x0096, 0x00b4, 0x00d2, 0x00f0, 0x010e, 0x012c, 0x014a, 0x0168, 0x0186, 0x01a4, 0x01c2, - 0x01e0, 0x01fe, 0x021c, 0x023a, 0x0258, 0x0276, 0x0294, 0x02b2, 0x02d0, 0x02ee, 0x030c, 0x032a, 0x0348, 0x0366, 0x0384, 0x03a2}, - { 0x0000, 0x001f, 0x003e, 0x005d, 0x007c, 0x009b, 0x00ba, 0x00d9, 0x00f8, 0x0117, 0x0136, 0x0155, 0x0174, 0x0193, 0x01b2, 0x01d1, - 0x01f0, 0x020f, 0x022e, 0x024d, 0x026c, 0x028b, 0x02aa, 0x02c9, 0x02e8, 0x0307, 0x0326, 0x0345, 0x0364, 0x0383, 0x03a2, 0x03c1} -}; - -static const int8_t outLvlTbl[16][16] = { - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2}, - { 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}, - { 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6}, - { 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8}, - { 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10}, - { 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12}, - { 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 8, 10, 11, 12, 13, 14}, - { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - { 0, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17}, - { 0, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19}, - { 0, 2, 3, 5, 6, 7, 9, 10, 12, 13, 14, 16, 17, 18, 20, 21}, - { 0, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23}, - { 0, 2, 4, 5, 7, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25}, - { 0, 2, 4, 6, 8, 9, 11, 13, 15, 16, 18, 20, 22, 23, 25, 27}, - { 0, 2, 4, 6, 8, 10, 12, 14, 16, 17, 19, 21, 23, 25, 27, 29} -}; - -static inline uint8_t mgetb(uint8_t *ptr) { return *ptr; } -static inline void mputb(uint8_t *ptr, int8_t data) { *ptr = data; } - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// vboysnd_device - constructor -//------------------------------------------------- - -vboysnd_device::vboysnd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, VBOYSND, tag, owner, clock) - , device_sound_interface(mconfig, *this) -{ -} - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void vboysnd_device::device_start() -{ - uint32_t rate = clock() / 120; - // create the stream - m_stream = stream_alloc(0, 2, rate); - - m_timer = timer_alloc(FUNC(vboysnd_device::delayed_stream_update), this); - m_timer->adjust(attotime::zero, 0, rate ? attotime::from_hz(rate / 4) : attotime::never); - - for (int i=0; i<2048; i++) - waveFreq2LenTbl[i] = ((2048 - i) * 32) / 120; - for (int i=0; i<32; i++) - waveTimer2LenTbl[i] = (i+1) * 120; - for (int i=0; i<8; i++) - waveEnv2LenTbl[i] = (i + 1) * 4 * 120; - - for (int i = 0; i < 5; i++) - memset(&snd_channel[i], 0, sizeof(s_snd_channel)); - - memset(m_aram, 0, 0x600); -} - - -//------------------------------------------------- -// device_clock_changed -//------------------------------------------------- - -void vboysnd_device::device_clock_changed() -{ - uint32_t rate = clock() / 120; - m_stream->set_sample_rate(rate); - - m_timer->adjust(attotime::zero, 0, rate ? attotime::from_hz(rate / 4) : attotime::never); -} - - -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - -void vboysnd_device::device_reset() -{ - m_stream->update(); - - int i; - - for (i=0; i<4; i++) - snd_channel[i].playing = false; -} - -//------------------------------------------------- -// delayed_stream_update -//------------------------------------------------- - -TIMER_CALLBACK_MEMBER(vboysnd_device::delayed_stream_update) -{ - m_stream->update(); -} - -//------------------------------------------------- -// sound_stream_update - handle update requests for -// our sound stream -//------------------------------------------------- - -void vboysnd_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) -{ - int len, i, j, channel; - - auto &outL = outputs[0]; - auto &outR = outputs[1]; - - len = outL.samples(); - -// if (mgetb(m_aram+SST0P) & 0x1) // Sound Stop Reg -// goto end; - - for (channel=0; channel<5; channel++) - { - float size; - int k = 0, waveAddr; - - i = channel * 0x40; - snd_channel[channel].sample_len = waveFreq2LenTbl[((mgetb(m_aram+SxFQHb+i) & 0x7) << 8) | mgetb(m_aram+SxFQLb+i)]; - waveAddr = (mgetb(m_aram + SxRAMb + i) & 0x3) << 7; - - size = (float)snd_channel[channel].sample_len / 32.0f; - for (j=0; j<32;) - { - int8_t byte = mgetb(m_aram + waveAddr + (j++ << 2)) & 0x3f; -// int8_t nbyte = mgetb(m_aram + waveAddr + (j << 2)) & 0x3f; - int end = (int)(((float)j)*size); - float val, add; - - val = (float)byte; - add = /*(nbyte-byte)/(end-k)*/ 0.0; // no interpolation - - for (; kplaying) - continue; - - outLeft = outLvlTbl[channel->volLeft][channel->envelope]; - outRight = outLvlTbl[channel->volRight][channel->envelope]; -// env1 = ((uint8_t)mgetb(m_aram+SxEV1b+i*0x40)); - if (channel->env1 & 0x01) - { - channel->env_time++; - -// env0 = ((uint8_t)mgetb(m_aram+SxEV0b+i*0x40)); - if (channel->env_time >= channel->env_steptime /*waveEnv2LenTbl[env0 & 0x7]*/) - { - // it's time for a step - channel->env_time = 0; - if (channel->env0 & 0x08) - { - // step up - channel->envelope++; - if (channel->envelope >= 0xf) - { - if (channel->env1 & 0x02) channel->envelope = channel->env0 >> 4; - else { channel->env1 &= ~0x01; channel->envelope = 0xf; } - } - } - else - { - // step down - channel->envelope--; - if (channel->envelope <= 0) - { - if (channel->env1 & 0x02) channel->envelope = channel->env0 >> 4; - else { channel->env1 &= ~0x01; channel->envelope = 0x0; } - } - } - } - } - - outTblPtr = (int16_t *) outTbl[channel->sample[channel->offset]]; - if (outLeft) note_left += outTblPtr[outLeft ]; - if (outRight) note_right += outTblPtr[outRight]; - channel->offset++; - - if (channel->offset >= channel->sample_len) - channel->offset = 0; - - if (channel->time > 0) - { - channel->time--; - if (channel->time <= 0) - channel->playing = false; - } - } - - - // scale to 16 bits - note_left = (note_left << 5) | ((note_left >> 6) & 0x1f); - note_right = (note_right << 5) | ((note_right >> 6) & 0x1f); - - outL.put_int_clamp(j, (int16_t)note_left, 32768); - outR.put_int_clamp(j, (int16_t)note_right, 32768); - } -} - -//------------------------------------------------- -// read - read from the chip's registers and internal RAM -//------------------------------------------------- - -uint8_t vboysnd_device::read(offs_t offset) -{ - m_stream->update(); - return m_aram[offset]; -} - -//------------------------------------------------- -// write - write to the chip's registers and internal RAM -//------------------------------------------------- - -void vboysnd_device::write(offs_t offset, uint8_t data) -{ - int freq, i; -// int waveAddr; - int volReg, intervalReg; - int channel, ouroffs; - - mputb((uint8_t *)m_aram+offset, data); - if (offset < 0x400) - return; - - channel = (offset-0x400) >> 6; - ouroffs = offset & 0x3f; - - ///process_sound(cpu.vcount); - - if (channel == 6 && ouroffs == 0) - { - if (mgetb(m_aram+SST0P) & 0x1) - for (i=0; i<4; i++) - snd_channel[i].playing = 0; - return; - } - - // Extract frequencies and build the wave for the first 4 sound sources - i = channel * 0x40; - switch (ouroffs) - { - case SxLRV: - if (channel < 5) - { - volReg = mgetb(m_aram + SxLRVb + i); // 6-4-4 - L/R output level setting - if (snd_channel[channel].playing) - { - snd_channel[channel].volLeft = ((uint8_t)volReg) >> 4; - snd_channel[channel].volRight = ((uint8_t)volReg) & 0xf; - break; - } - } - [[fallthrough]]; // FIXME: really? - case SxINT: - if (channel < 5) - { - uint8_t env0, env1; - // find out if the sound is playing - intervalReg = mgetb(m_aram + SxINTb + i); // 6-4-6 - Sound Interval - volReg = mgetb(m_aram + SxLRVb + i); // 6-4-4 - L/R output level setting - - if (((intervalReg & 0x80) == 0) || (volReg == 0)) - { - snd_channel[channel].playing = false; - return; - } - snd_channel[channel].playing = true; - - // 6-4-1 - Waveform address comes from SxRAM. -// waveAddr = (mgetb(m_aram + SxRAMb + i) & 0x3) << 7; - - // 6-4-15 - Frequency comes from here - freq = ((mgetb(m_aram+SxFQHb+i) & 0x7) << 8) | mgetb(m_aram+SxFQLb+i); - - env0 = mgetb(m_aram+SxEV0b+i); env1 = mgetb(m_aram+SxEV1b+i); - snd_channel[channel].env0 = env0; - snd_channel[channel].env1 = env1; - snd_channel[channel].volLeft = ((uint8_t)volReg) >> 4; - snd_channel[channel].volRight = ((uint8_t)volReg) & 0xf; - snd_channel[channel].env_steptime = (env1 & 0x1) ? waveEnv2LenTbl[env0 & 0x7] : 0; - snd_channel[channel].sample_len = waveFreq2LenTbl[freq]; - - snd_channel[channel].offset = 0; - snd_channel[channel].time = (intervalReg & 0x20) ? waveTimer2LenTbl[intervalReg & 0x1f] : 0; - snd_channel[channel].envelope = ((uint8_t)mgetb(m_aram+SxEV0b+i)) >> 4; - snd_channel[channel].env_time = 0; - } - else - { - intervalReg = mgetb(m_aram + SxINTb + i); // 6-4-6 - Sound Interval - volReg = mgetb(m_aram + SxLRVb + i); // 6-4-4 - L/R output level setting - - if (((intervalReg & 0x80) == 0) || (volReg == 0)) - { -// snd_channel[channel].playing = false; - return; - } -// Debugger(); // uses white noise -// snd_channel[channel].playing = true; - } - break; - - case SxEV0: - if (channel < 5) - if (snd_channel[channel].playing) - snd_channel[channel].envelope = ((uint8_t)mgetb(m_aram+SxEV0b+i)) >> 4; - break; - } -} diff --git a/src/mame/messshared/vboysound.h b/src/mame/messshared/vboysound.h deleted file mode 100644 index 11f8dbc44b8..00000000000 --- a/src/mame/messshared/vboysound.h +++ /dev/null @@ -1,92 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:R. Belmont -/* - vboy.h - Virtual Boy audio emulation - - By Richard Bannister and Gil Pedersen. - MAME device adaptation by R. Belmont -*/ -#ifndef MAME_AUDIO_VBOY_H -#define MAME_AUDIO_VBOY_H - -#pragma once - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> vboysnd_device - -class vboysnd_device : public device_t, public device_sound_interface -{ -public: - // construction/destruction - vboysnd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 5'000'000); - - uint8_t read(offs_t offset); - void write(offs_t offset, uint8_t data); - - sound_stream *m_stream = nullptr; - -protected: - static constexpr unsigned CHANNELS = 4; - - struct s_snd_channel { - int8_t playing = 0; // the sound is playing - - // state when sound was enabled - uint32_t env_steptime = 0; // Envelope step time - uint8_t env0 = 0; // Envelope data - uint8_t env1 = 0; // Envelope data - uint8_t volLeft = 0; // Left output volume - uint8_t volRight = 0; // Right output volume - uint8_t sample[580]{}; // sample to play - int sample_len = 0; // length of sample - - // values that change, as the sample is played - int offset = 0; // current offset in sample - int time = 0; // the duration that this sample is to be played - uint8_t envelope = 0; // Current envelope level (604) - int env_time = 0; // The duration between envelope decay/grow (608) - }; - - struct s_regchan { - int32_t sINT; - int32_t sLRV; - int32_t sFQL; - int32_t sFQH; - int32_t sEV0; - int32_t sEV1; - int32_t sRAM; - }; - - struct s_sreg { - // Sound registers structure - s_regchan c[4]; - }; - - // device-level overrides - virtual void device_start() override; - virtual void device_clock_changed() override; - virtual void device_reset() override; - - virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; - - TIMER_CALLBACK_MEMBER(delayed_stream_update); - - s_snd_channel snd_channel[5]; - - uint16_t waveFreq2LenTbl[2048]; - uint16_t waveTimer2LenTbl[32]; - uint16_t waveEnv2LenTbl[8]; - - emu_timer *m_timer = nullptr; - - uint8_t m_aram[0x600]; -}; - -// device type definition -DECLARE_DEVICE_TYPE(VBOYSND, vboysnd_device) - -#endif //MAME_AUDIO_VBOY_H diff --git a/src/mame/messshared/vt100_kbd.cpp b/src/mame/messshared/vt100_kbd.cpp deleted file mode 100644 index 70d5fb7cb4d..00000000000 --- a/src/mame/messshared/vt100_kbd.cpp +++ /dev/null @@ -1,541 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic, Jonathan Gevaryahu, AJR -/*************************************************************************** - - DEC VT100 keyboard emulation - - All data to and from the keyboard is transmitted over a single - bidirectional wire. The clock that runs the keyboard's UART and - scan counters is multiplexed with the serial data signal. - - MS7002 is a Soviet clone of the VT100 keyboard. It features a - bit-paired JCUKEN layout and Russian/Latin mode select keys, but - the codes it produces are mostly the same, as is the electrical - interface. - -***************************************************************************/ - -#include "emu.h" -#include "vt100_kbd.h" - -#include "logmacro.h" - - -//************************************************************************** -// VT100 KEYBOARD DEVICE -//************************************************************************** - -DEFINE_DEVICE_TYPE(VT100_KEYBOARD, vt100_keyboard_device, "vt100_kbd", "VT100 Keyboard") - -static INPUT_PORTS_START(vt100_kbd) - PORT_START("LINE0") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) - - PORT_START("LINE1") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num Enter") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num ,") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) - - PORT_START("LINE2") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) - - PORT_START("LINE3") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Delete") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) - - PORT_START("LINE4") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num Return") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("]") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("~") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("=") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line feed") PORT_CODE(KEYCODE_RALT) PORT_CHAR(0x0a) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - - PORT_START("LINE5") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("[") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\\") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("'") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') - - PORT_START("LINE6") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') - - PORT_START("LINE7") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') - - PORT_START("LINE8") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') - - PORT_START("LINE9") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') - - PORT_START("LINEA") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("No scroll") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') - - PORT_START("LINEB") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Setup") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) - - PORT_START("LINEC") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2) - - PORT_START("LINED") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) - - PORT_START("LINEE") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_TOGGLE - - PORT_START("LINEF") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) // Always return 0x7f on last scan line -INPUT_PORTS_END - - -//------------------------------------------------- -// vt100_keyboard_device - constructor -//------------------------------------------------- - -vt100_keyboard_device::vt100_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : vt100_keyboard_device(mconfig, VT100_KEYBOARD, tag, owner, clock) -{ -} - -vt100_keyboard_device::vt100_keyboard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) - : device_t(mconfig, type, tag, owner, clock) - , m_signal_out_cb(*this) - , m_uart(*this, "uart") - , m_speaker(*this, "beeper") - , m_scan_counter(*this, "counter") - , m_key_row(*this, "LINE%X", 0) - , m_online_led(*this, "online_led") - , m_local_led(*this, "local_led") - , m_locked_led(*this, "locked_led") - , m_ln_led(*this, "l%u_led", 1U) - , m_signal_line(true) - , m_last_signal_change(attotime::zero) - , m_last_scan(0) -{ -} - - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- - -void vt100_keyboard_device::device_add_mconfig(machine_config &config) -{ - SPEAKER(config, "mono").front_center(); - BEEP(config, m_speaker, 786); // 7.945us per serial clock = ~125865.324hz, / 160 clocks per char = ~ 786 hz - m_speaker->add_route(ALL_OUTPUTS, "mono", 0.50); - - AY31015(config, m_uart); - m_uart->write_so_callback().set(FUNC(vt100_keyboard_device::signal_out_w)); - - RIPPLE_COUNTER(config, m_scan_counter); // 2x 74LS93 - m_scan_counter->set_stages(8); - m_scan_counter->count_out_cb().set(FUNC(vt100_keyboard_device::key_scan_w)); -} - - -//------------------------------------------------- -// input_ports - device-specific input ports -//------------------------------------------------- - -ioport_constructor vt100_keyboard_device::device_input_ports() const -{ - return INPUT_PORTS_NAME(vt100_kbd); -} - - -//------------------------------------------------- -// device_resolve_objects - resolve objects that -// may be needed for other devices to set -// initial conditions at start time -//------------------------------------------------- - -void vt100_keyboard_device::device_resolve_objects() -{ - m_signal_out_cb.resolve_safe(); -} - - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void vt100_keyboard_device::device_start() -{ - if (!m_uart->started()) - throw device_missing_dependencies(); - - m_uart->write_tsb(0); - m_uart->write_eps(1); - m_uart->write_np(1); - m_uart->write_nb1(1); - m_uart->write_nb2(1); - m_uart->write_cs(1); - m_uart->write_swe(0); - - m_online_led.resolve(); - m_local_led.resolve(); - m_locked_led.resolve(); - m_ln_led.resolve(); - - m_online_led = 0; - m_local_led = 1; - m_locked_led = 1; - for (int n = 0; n < 4; n++) - m_ln_led[n] = 1; - - save_item(NAME(m_signal_line)); - save_item(NAME(m_last_signal_change)); - save_item(NAME(m_last_scan)); -} - - -//------------------------------------------------- -// signal_line_w - handle external serial input -//------------------------------------------------- - -WRITE_LINE_MEMBER(vt100_keyboard_device::signal_line_w) -{ - if (m_signal_line == bool(state)) - return; - - if (machine().time() > m_last_signal_change + attotime::from_usec(5)) - m_uart->write_si(m_signal_line); - - if (scan_enabled()) - m_scan_counter->clock_w(state); - - if (state) - { - bool dav = m_uart->dav_r(); - m_uart->write_rdav(!dav); - - if (dav) - { - u8 data = m_uart->receive(); - m_online_led = BIT(data, 5) ? 1 : 0; - m_local_led = BIT(data, 5) ? 0 : 1; - m_locked_led = BIT(data, 4) ? 0 : 1; - for (int n = 0; n < 4; n++) - m_ln_led[n] = BIT(data, 3 - n) ? 0 : 1; - m_speaker->set_state(BIT(data, 7)); - - if (BIT(data, 6)) - { - m_scan_counter->reset_w(0); - scan_start(); - } - } - } - - m_uart->write_rcp(state); - m_uart->write_tcp(state); - - m_signal_line = bool(state); - m_last_signal_change = machine().time(); -} - - -//------------------------------------------------- -// signal_out_w - transmit serial keyboard output -//------------------------------------------------- - -WRITE_LINE_MEMBER(vt100_keyboard_device::signal_out_w) -{ - m_signal_out_cb(state); -} - - -//------------------------------------------------- -// key_scan_w - handle scan counter outputs -//------------------------------------------------- - -void vt100_keyboard_device::key_scan_w(u8 data) -{ - if (BIT(data, 0)) - { - u8 input_row = m_key_row[(data >> 1) & 15]->read(); - if (!BIT(input_row, (data >> 5) & 7)) - { - if (data != 0xff) - LOG("Keycode pressed: %02X\n", (data >> 1) & 0x7f); - m_uart->transmit((data >> 1) & 0x7f); - } - } - - if (!BIT(data, 7) && BIT(m_last_scan, 7)) - { - m_last_scan = 0; - m_scan_counter->reset_w(1); - } - else - m_last_scan = data; -} - - -//************************************************************************** -// MS7002 KEYBOARD DEVICE -//************************************************************************** - -DEFINE_DEVICE_TYPE(MS7002, ms7002_device, "ms7002", "MS7002 Keyboard") - -static INPUT_PORTS_START(ms7002) - PORT_START("LINE0") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) - - PORT_START("LINE1") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\x92\xd0\x9e\xd0\x94") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) - - PORT_START("LINE2") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9b\xd0\x90\xd0\xa2") // ЛАТ = латинские - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) - - PORT_START("LINE3") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('_') // note that this does NOT double as Ъ - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x97\xd0\x91") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // ЗБ = забой - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa0\xd0\x92") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // ПРВ = перерыв - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\xa8") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x08) // ВШ = возврат на шаг - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) - - PORT_START("LINE4") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\x9a") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(0x0d) // ВК = возврат каретки - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa9 ]") PORT_CODE(KEYCODE_O) PORT_CHAR('}') PORT_CHAR(']') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa7 \xc2\xac") PORT_CODE(KEYCODE_X) PORT_CHAR(0x203e, '~') PORT_CHAR(0xac, '^') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR(';') PORT_CHAR('+') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') PORT_CHAR('=') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('0') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa1") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(0x0a) // ПС = перевод строки - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) - - PORT_START("LINE5") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f P") PORT_CODE(KEYCODE_G) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa8 [") PORT_CODE(KEYCODE_I) PORT_CHAR('{') PORT_CHAR('[') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(':') PORT_CHAR('*') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa0\xd0\xa3\xd0\xa1") // РУС = русские - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xad \\") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('|') PORT_CHAR('\\') - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) // possibly Keypad 9 - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('.') PORT_CHAR('>') - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('/') PORT_CHAR('?') - - PORT_START("LINE6") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9e O") PORT_CODE(KEYCODE_J) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x98 I") PORT_CODE(KEYCODE_B) PORT_CHAR('i') PORT_CHAR('I') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('9') PORT_CHAR(')') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('8') PORT_CHAR('(') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9b L") PORT_CODE(KEYCODE_K) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xae @") PORT_CODE(KEYCODE_STOP) PORT_CHAR('`') PORT_CHAR('@') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RALT) PORT_CHAR(',') PORT_CHAR('<') - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9c M") PORT_CODE(KEYCODE_V) PORT_CHAR('m') PORT_CHAR('M') - - PORT_START("LINE7") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xab Y") PORT_CODE(KEYCODE_S) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR(0x19) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa3 U") PORT_CODE(KEYCODE_E) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR(0x15) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('7') PORT_CHAR('\'') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('6') PORT_CHAR('&') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9a K") PORT_CODE(KEYCODE_R) PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR(0x0b) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x99 J") PORT_CODE(KEYCODE_Q) PORT_CHAR('j') PORT_CHAR('J') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9d N") PORT_CODE(KEYCODE_Y) PORT_CHAR('n') PORT_CHAR('N') PORT_CHAR(0x0e) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') - - PORT_START("LINE8") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa2 T") PORT_CODE(KEYCODE_N) PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa0 R") PORT_CODE(KEYCODE_H) PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 \xc2\xa4") PORT_CODE(KEYCODE_5) PORT_CHAR('4') PORT_CHAR(0xa4, '$') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('5') PORT_CHAR('%') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x93 G") PORT_CODE(KEYCODE_U) PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa5 H") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('h') PORT_CHAR('H') - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x91 B") PORT_CODE(KEYCODE_COMMA) PORT_CHAR('b') PORT_CHAR('B') PORT_CHAR(0x02) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x96 V") PORT_CODE(KEYCODE_COLON) PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16) - - PORT_START("LINE9") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92 W") PORT_CODE(KEYCODE_D) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x95 E") PORT_CODE(KEYCODE_T) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('3') PORT_CHAR('#') - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('2') PORT_CHAR('"') - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa4 F") PORT_CODE(KEYCODE_A) PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x94 D") PORT_CODE(KEYCODE_L) PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xac X") PORT_CODE(KEYCODE_M) PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa6 C") PORT_CODE(KEYCODE_W) PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03) - - PORT_START("LINEA") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xaf Q") PORT_CODE(KEYCODE_Z) PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('1') PORT_CHAR('!') - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x90\xd0\xa0" "2") PORT_CODE(KEYCODE_ESC) PORT_CHAR(0x1b) // АР2 = авторегистр 2 - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa2\xd0\x90\xd0\x91") PORT_CODE(KEYCODE_TAB) PORT_CHAR(0x09) // ТАБ = табуляция - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x90 A") PORT_CODE(KEYCODE_F) PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01) - PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa1 S") PORT_CODE(KEYCODE_C) PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13) - PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa1\xd0\xa2\xd0\x9e\xd0\x9f") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // СТОП - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x97 Z") PORT_CODE(KEYCODE_P) PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a) - - PORT_START("LINEB") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa3\xd0\xa1\xd0\xa2") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5) ) // УСТ = установка - - PORT_START("LINEC") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa3\xd0\x9f\xd0\xa0") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) // УПР = управляющий - - PORT_START("LINED") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa1\xd0\x94\xd0\x92") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // СДВ = сдвинуть - - PORT_START("LINEE") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\xa0") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_TOGGLE // ВР = верхний регистр - - PORT_START("LINEF") - PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) // Always return 0x7f on last scan line -INPUT_PORTS_END - - -//------------------------------------------------- -// ms7002_device - constructor -//------------------------------------------------- - -ms7002_device::ms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : vt100_keyboard_device(mconfig, MS7002, tag, owner, clock) - , m_scan_enable(false) -{ -} - - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- - -void ms7002_device::device_add_mconfig(machine_config &config) -{ - vt100_keyboard_device::device_add_mconfig(config); - - subdevice("uart")->write_tbmt_callback().set(FUNC(ms7002_device::scan_disable_w)); -} - - -//------------------------------------------------- -// input_ports - device-specific input ports -//------------------------------------------------- - -ioport_constructor ms7002_device::device_input_ports() const -{ - return INPUT_PORTS_NAME(ms7002); -} - - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void ms7002_device::device_start() -{ - vt100_keyboard_device::device_start(); - - save_item(NAME(m_scan_enable)); -} - - -//------------------------------------------------- -// scan_disable_w - suspend scan count once -// keycode is being transmitted -//------------------------------------------------- - -WRITE_LINE_MEMBER(ms7002_device::scan_disable_w) -{ - if (!state) - m_scan_enable = false; -} diff --git a/src/mame/messshared/vt100_kbd.h b/src/mame/messshared/vt100_kbd.h deleted file mode 100644 index 9b6f15a490d..00000000000 --- a/src/mame/messshared/vt100_kbd.h +++ /dev/null @@ -1,97 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic, Jonathan Gevaryahu, AJR -/*************************************************************************** - - DEC VT100 keyboard emulation - -***************************************************************************/ - -#ifndef MAME_MACHINE_VT100_KBD_H -#define MAME_MACHINE_VT100_KBD_H - -#pragma once - -#include "machine/ay31015.h" -#include "machine/ripple_counter.h" -#include "sound/beep.h" -#include "speaker.h" - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> vt100_keyboard_device - -class vt100_keyboard_device : public device_t -{ -public: - // construction/destruction - vt100_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - - // configuration - auto signal_out_callback() { return m_signal_out_cb.bind(); } - - DECLARE_WRITE_LINE_MEMBER(signal_line_w); - -protected: - vt100_keyboard_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_add_mconfig(machine_config &config) override; - virtual ioport_constructor device_input_ports() const override; - - virtual bool scan_enabled() const { return m_uart->tbmt_r(); } - virtual void scan_start() { } - -private: - // internal helpers - DECLARE_WRITE_LINE_MEMBER(signal_out_w); - DECLARE_WRITE_LINE_MEMBER(scan_disable_w); - void key_scan_w(u8 data); - - devcb_write_line m_signal_out_cb; - - required_device m_uart; - required_device m_speaker; - required_device m_scan_counter; - required_ioport_array<16> m_key_row; - - output_finder<> m_online_led; - output_finder<> m_local_led; - output_finder<> m_locked_led; - output_finder<4> m_ln_led; - - bool m_signal_line; - attotime m_last_signal_change; - u8 m_last_scan; -}; - -// ======================> ms7002_device - -class ms7002_device : public vt100_keyboard_device -{ -public: - // construction/destruction - ms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - -protected: - virtual void device_start() override; - virtual void device_add_mconfig(machine_config &config) override; - virtual ioport_constructor device_input_ports() const override; - - virtual bool scan_enabled() const override { return m_scan_enable; } - virtual void scan_start() override { m_scan_enable = true; } - -private: - DECLARE_WRITE_LINE_MEMBER(scan_disable_w); - - bool m_scan_enable; -}; - -// device type definitions -DECLARE_DEVICE_TYPE(VT100_KEYBOARD, vt100_keyboard_device) -DECLARE_DEVICE_TYPE(MS7002, ms7002_device) - -#endif // MAME_MACHINE_VT100_KBD_H diff --git a/src/mame/messshared/wswansound.cpp b/src/mame/messshared/wswansound.cpp deleted file mode 100644 index 773bfda4948..00000000000 --- a/src/mame/messshared/wswansound.cpp +++ /dev/null @@ -1,387 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Wilbert Pol -/************************************************************************************** - - Wonderswan sound emulation - - Wilbert Pol - - Sound emulation is preliminary and not complete - - -The noise taps and behavior are the same as the Virtual Boy. - -**************************************************************************************/ - -#include "emu.h" -#include "wswansound.h" - - -// device type definition -DEFINE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device, "wswan_sound", "WonderSwan Custom Sound") - - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// wswan_sound_device - constructor -//------------------------------------------------- - -wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, WSWAN_SND, tag, owner, clock), - device_sound_interface(mconfig, *this), - device_rom_interface(mconfig, *this), - m_channel(nullptr), - m_sweep_step(0), - m_sweep_time(0), - m_sweep_count(0), - m_noise_type(0), - m_noise_reset(0), - m_noise_enable(0), - m_noise_output(0), - m_sample_address(0), - m_audio2_voice(0), - m_audio3_sweep(0), - m_audio4_noise(0), - m_mono(0), - m_output_volume(0), - m_external_stereo(0), - m_external_speaker(0), - m_noise_shift(0), - m_master_volume(0) -{ -} - -static constexpr int clk_div = 64; - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void wswan_sound_device::device_start() -{ - m_channel = stream_alloc(0, 2, clock() / clk_div); - - save_item(NAME(m_sweep_step)); - save_item(NAME(m_sweep_time)); - save_item(NAME(m_sweep_count)); - save_item(NAME(m_noise_type)); - save_item(NAME(m_noise_reset)); - save_item(NAME(m_noise_enable)); - save_item(NAME(m_sample_address)); - save_item(NAME(m_audio2_voice)); - save_item(NAME(m_audio3_sweep)); - save_item(NAME(m_audio4_noise)); - save_item(NAME(m_mono)); - save_item(NAME(m_output_volume)); - save_item(NAME(m_external_stereo)); - save_item(NAME(m_external_speaker)); - save_item(NAME(m_noise_shift)); - save_item(NAME(m_master_volume)); - save_item(NAME(m_system_volume)); - save_item(STRUCT_MEMBER(m_audio, freq)); - save_item(STRUCT_MEMBER(m_audio, period)); - save_item(STRUCT_MEMBER(m_audio, pos)); - save_item(STRUCT_MEMBER(m_audio, vol_left)); - save_item(STRUCT_MEMBER(m_audio, vol_right)); - save_item(STRUCT_MEMBER(m_audio, on)); - save_item(STRUCT_MEMBER(m_audio, offset)); - save_item(STRUCT_MEMBER(m_audio, signal)); -} - -void wswan_sound_device::device_clock_changed() -{ - m_channel->set_sample_rate(clock() / clk_div); -} - -void wswan_sound_device::rom_bank_updated() -{ - m_channel->update(); -} - -//------------------------------------------------- -// device_reset -//------------------------------------------------- - -void wswan_sound_device::device_reset() -{ - for (int i = 0; i < 4; i++) - { - m_audio[i].on = 0; - m_audio[i].signal = 0; - m_audio[i].offset = 0; - m_audio[i].pos = 0; - } - m_noise_output = 0; -} - -int wswan_sound_device::fetch_sample(int channel, int offset) -{ - u16 w = read_word(m_sample_address + ((channel & 3) << 4) + ((offset >> 1) & 0x0e)); - - return (w >> ((offset & 0x03) * 4)) & 0x0f; -} - -//------------------------------------------------- -// sound_stream_update - handle a stream update -//------------------------------------------------- - -void wswan_sound_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) -{ - auto &outputl = outputs[0]; - auto &outputr = outputs[1]; - for (int sampindex = 0; sampindex < outputl.samples(); sampindex++) - { - s32 left = 0, right = 0; - - if (m_audio[0].on) - { - s32 sample = m_audio[0].signal; - m_audio[0].pos += clk_div; - if (m_audio[0].pos >= m_audio[0].period) - { - m_audio[0].pos -= m_audio[0].period; - m_audio[0].signal = fetch_sample(0, m_audio[0].offset++); - } - left += m_audio[0].vol_left * sample; - right += m_audio[0].vol_right * sample; - } - - if (m_audio[1].on) - { - if (m_audio2_voice) - { - u8 voice_data = (m_audio[1].vol_left << 4) | m_audio[1].vol_right; - left += voice_data * (m_master_volume & 0x0f); - right += voice_data * (m_master_volume & 0x0f); - } - else - { - s32 sample = m_audio[1].signal; - m_audio[1].pos += clk_div; - if (m_audio[1].pos >= m_audio[1].period) - { - m_audio[1].pos -= m_audio[1].period; - m_audio[1].signal = fetch_sample(1, m_audio[1].offset++); - } - left += m_audio[1].vol_left * sample; - right += m_audio[1].vol_right * sample; - } - } - - if (m_audio[2].on) - { - s32 sample = m_audio[2].signal; - m_audio[2].pos += clk_div; - if (m_audio[2].pos >= m_audio[2].period) - { - m_audio[2].pos -= m_audio[2].period; - m_audio[2].signal = fetch_sample(2, m_audio[2].offset++); - } - if (m_audio3_sweep && m_sweep_time) - { - m_sweep_count += clk_div; - if (m_sweep_count >= m_sweep_time) - { - m_sweep_count -= m_sweep_time; - m_audio[2].freq += m_sweep_step; - m_audio[2].freq &= 0x7ff; - m_audio[2].period = 2048 - m_audio[2].freq; - } - } - left += m_audio[2].vol_left * sample; - right += m_audio[2].vol_right * sample; - } - - if (m_audio[3].on) - { - s32 sample = m_audio[3].signal; - m_audio[3].pos += clk_div; - if (m_audio[3].pos >= m_audio[3].period) - { - if (m_audio4_noise) - m_audio[3].signal = m_noise_output ? 0xf : 0; - else - m_audio[3].signal = fetch_sample(3, m_audio[3].offset++); - - m_audio[3].pos -= m_audio[3].period; - - if (m_noise_reset) - { - m_noise_reset = 0; - m_noise_shift = 0; - m_noise_output = 0; - } - - if (m_noise_enable) - { - static int shift_bit[] = { 14, 10, 13, 4, 8, 6, 9, 11 }; - - m_noise_output = (1 ^ (m_noise_shift >> 7) ^ (m_noise_shift >> shift_bit[m_noise_type])) & 1; - m_noise_shift = m_noise_shift << 1 | m_noise_output; - } - } - left += m_audio[3].vol_left * sample; - right += m_audio[3].vol_right * sample; - } - - outputl.put_int(sampindex, left, 32768 >> 5); - outputr.put_int(sampindex, right, 32768 >> 5); - } -} - - -u16 wswan_sound_device::port_r(offs_t offset, u16 mem_mask) -{ - m_channel->update(); - switch (offset) { - case 0x80 / 2: - case 0x82 / 2: - case 0x84 / 2: - case 0x86 / 2: - return m_audio[offset & 0x03].freq; - case 0x88 / 2: - return (m_audio[0].vol_left << 4) | m_audio[0].vol_right | - (m_audio[1].vol_left << 12) | (m_audio[1].vol_right << 8); - case 0x8a / 2: - return (m_audio[2].vol_left << 4) | m_audio[2].vol_right | - (m_audio[3].vol_left << 12) | (m_audio[3].vol_right << 8); - case 0x8c / 2: - return m_sweep_step | (((m_sweep_time / 8192) - 1) << 8); - case 0x8e / 2: - return m_noise_type | (m_noise_reset ? 0x08 : 0x00) | (m_noise_enable ? 0x10 : 0x00) | - ((m_sample_address << 2) & 0xff00); - case 0x90 / 2: - return (m_audio[0].on ? 0x01 : 0x00) | - (m_audio[1].on ? 0x02 : 0x00) | - (m_audio[2].on ? 0x04 : 0x00) | - (m_audio[3].on ? 0x08 : 0x00) | - (m_audio2_voice ? 0x20 : 0x00) | - (m_audio3_sweep ? 0x40 : 0x00) | - (m_audio4_noise ? 0x80 : 0x00) | - (m_mono ? 0x0100 : 0x00) | (m_output_volume << 9) | - (m_external_stereo ? 0x0800 : 0x00) | - (m_external_speaker ? 0x00 : 0x00); // TODO 0x80 is set when external speaker is connected - case 0x92 / 2: - return m_noise_shift; - case 0x94 / 2: - return m_master_volume; - case 0x9e / 2: - return m_system_volume; - } - return 0; -} - -void wswan_sound_device::port_w(offs_t offset, u16 data, u16 mem_mask) -{ - m_channel->update(); - - switch (offset) - { - case 0x80 / 2: // Audio 1 freq - case 0x82 / 2: // Audio 2 freq - case 0x84 / 2: // Audio 3 freq - case 0x86 / 2: // Audio 4 freq - COMBINE_DATA(&m_audio[offset & 0x03].freq); - m_audio[offset & 0x03].freq &= 0x7ff; - m_audio[offset & 0x03].period = 2048 - m_audio[offset & 0x03].freq; - break; - - case 0x88 / 2: - // Audio 1 volume - if (ACCESSING_BITS_0_7) - { - m_audio[0].vol_left = (data >> 4) & 0x0f; - m_audio[0].vol_right = data & 0x0f; - } - // Audio 2 volume - if (ACCESSING_BITS_8_15) - { - m_audio[1].vol_left = (data >> 12) & 0x0f; - m_audio[1].vol_right = (data >> 8) & 0x0f; - } - break; - - case 0x8a / 2: - // Audio 3 volume - if (ACCESSING_BITS_0_7) - { - m_audio[2].vol_left = (data >> 4) & 0x0f; - m_audio[2].vol_right = data & 0x0f; - } - // Audio 4 volume - if (ACCESSING_BITS_8_15) - { - m_audio[3].vol_left = (data >> 12) & 0x0f; - m_audio[3].vol_right = (data >> 8) & 0x0f; - } - break; - - case 0x8c / 2: - // Sweep step - if (ACCESSING_BITS_0_7) - { - m_sweep_step = (int8_t)(data & 0xff); - } - // Sweep time - if (ACCESSING_BITS_8_15) - { - m_sweep_time = 8192 * ((data >> 8) + 1); - } - break; - - case 0x8e / 2: - // Noise control - if (ACCESSING_BITS_0_7) - { - m_noise_type = data & 0x07; - m_noise_reset = BIT(data, 3); - m_noise_enable = BIT(data, 4); - } - // Sample location - if (ACCESSING_BITS_8_15) - { - m_sample_address = (data & 0xff00) >> 2; - } - break; - - case 0x90 / 2: - // Audio control - if (ACCESSING_BITS_0_7) - { - m_audio[0].on = BIT(data, 0); - m_audio[1].on = BIT(data, 1); - m_audio[2].on = BIT(data, 2); - m_audio[3].on = BIT(data, 3); - m_audio2_voice = BIT(data, 5); - m_audio3_sweep = BIT(data, 6); - m_audio4_noise = BIT(data, 7); - } - // Audio output - if (ACCESSING_BITS_8_15) - { - m_mono = BIT(data, 8); - m_output_volume = ((data >> 9) & 0x03); - m_external_stereo = BIT(data, 11); - m_external_speaker = 1; - } - break; - - case 0x92 / 2: // Noise counter shift register - COMBINE_DATA(&m_noise_shift); - m_noise_shift &= 0x7fff; - break; - - case 0x94 / 2: // Master volume - if (ACCESSING_BITS_0_7) - m_master_volume = data & 0xff; - break; - - case 0x9e / 2: // WSC volume setting (0, 1, 2, 3) (TODO) - if (ACCESSING_BITS_0_7) - m_system_volume = data & 0x03; - break; - } -} diff --git a/src/mame/messshared/wswansound.h b/src/mame/messshared/wswansound.h deleted file mode 100644 index 43906b5d090..00000000000 --- a/src/mame/messshared/wswansound.h +++ /dev/null @@ -1,86 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Wilbert Pol -#ifndef MAME_AUDIO_WSWAN_H -#define MAME_AUDIO_WSWAN_H - -#pragma once - -#include "dirom.h" - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> wswan_sound_device - -class wswan_sound_device : public device_t, - public device_sound_interface, - public device_rom_interface<14,1> -{ -public: - wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - - void port_w(offs_t offset, u16 data, u16 mem_mask); - u16 port_r(offs_t offset, u16 mem_mask); - -protected: - struct CHAN - { - CHAN() : - freq(0), - period(0), - pos(0), - vol_left(0), - vol_right(0), - on(0), - offset(0), - signal(0) { } - - u16 freq; - u16 period; - u32 pos; - u8 vol_left; - u8 vol_right; - u8 on; - u8 offset; - u8 signal; - }; - - // device-level overrides - virtual void device_start() override; - virtual void device_clock_changed() override; - virtual void device_reset() override; - - virtual void rom_bank_updated() override; - - // sound stream update overrides - virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; - -private: - int fetch_sample(int channel, int offset); - - sound_stream *m_channel; - CHAN m_audio[4]; - s8 m_sweep_step; - u32 m_sweep_time; - u32 m_sweep_count; - u8 m_noise_type; - u8 m_noise_reset; - u8 m_noise_enable; - u8 m_noise_output; - u16 m_sample_address; - u8 m_audio2_voice; - u8 m_audio3_sweep; - u8 m_audio4_noise; - u8 m_mono; - u8 m_output_volume; - u8 m_external_stereo; - u8 m_external_speaker; - u16 m_noise_shift; - u8 m_master_volume; - u8 m_system_volume = 0; -}; - -DECLARE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device) - -#endif // MAME_AUDIO_WSWAN_H diff --git a/src/mame/messshared/z80bin.cpp b/src/mame/messshared/z80bin.cpp deleted file mode 100644 index c76f256e7f2..00000000000 --- a/src/mame/messshared/z80bin.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Robbbert -#include "emu.h" -#include "z80bin.h" - -/*------------------------------------------------- - z80bin_load_file - load a z80bin file into - memory --------------------------------------------------*/ - -image_init_result z80bin_load_file(device_image_interface &image, address_space &space, uint16_t &exec_addr, uint16_t &start_addr, uint16_t &end_addr) -{ - uint16_t args[3]{}; - uint16_t i = 0U, j = 0U, size = 0U; - uint8_t data = 0U; - char pgmname[256]{}; - char message[512]{}; - - image.fseek(7, SEEK_SET); - - char ch = '\0'; - uint32_t bytes = 0; - while ((bytes = image.fread(&ch, 1)) != 0 && ch != 0x1A) - { - if (ch != '\0') - { - if (i >= (std::size(pgmname) - 1)) - { - image.seterror(image_error::INVALIDIMAGE, "File name too long"); - image.message(" File name too long"); - return image_init_result::FAIL; - } - - pgmname[i] = ch; /* build program name */ - i++; - } - } - - if (bytes == 0) - { - image.seterror(image_error::INVALIDIMAGE, "Unexpected EOF while getting file name"); - image.message(" Unexpected EOF while getting file name"); - return image_init_result::FAIL; - } - - pgmname[i] = '\0'; /* terminate string with a null */ - - if (image.fread(args, sizeof(args)) != sizeof(args)) - { - image.seterror(image_error::INVALIDIMAGE, "Unexpected EOF while getting file size"); - image.message(" Unexpected EOF while getting file size"); - return image_init_result::FAIL; - } - - exec_addr = little_endianize_int16(args[0]); - start_addr = little_endianize_int16(args[1]); - end_addr = little_endianize_int16(args[2]); - - size = (end_addr - start_addr + 1) & 0xffff; - - /* display a message about the loaded quickload */ - image.message(" %s\nsize=%04X : start=%04X : end=%04X : exec=%04X",pgmname,size,start_addr,end_addr,exec_addr); - - for (i = 0; i < size; i++) - { - j = (start_addr + i) & 0xffff; - if (image.fread(&data, 1) != 1) - { - snprintf(message, std::size(message), "%s: Unexpected EOF while writing byte to %04X", pgmname, (unsigned) j); - image.seterror(image_error::INVALIDIMAGE, message); - image.message("%s: Unexpected EOF while writing byte to %04X", pgmname, (unsigned) j); - return image_init_result::FAIL; - } - space.write_byte(j, data); - } - - return image_init_result::PASS; -} diff --git a/src/mame/messshared/z80bin.h b/src/mame/messshared/z80bin.h deleted file mode 100644 index ecadaae549d..00000000000 --- a/src/mame/messshared/z80bin.h +++ /dev/null @@ -1,18 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Robbbert -/********************************************************************* - - machine/z80bin.h - - Quickload code for Z80 bin format - -*********************************************************************/ - -#ifndef MAME_MACHINE_Z80BIN_H -#define MAME_MACHINE_Z80BIN_H - -#pragma once - -image_init_result z80bin_load_file(device_image_interface &image, address_space &space, uint16_t &exec_addr, uint16_t &start_addr, uint16_t &end_addr); - -#endif // MAME_MACHINE_Z80BIN_H diff --git a/src/mame/shared/isbc_215g.cpp b/src/mame/shared/isbc_215g.cpp new file mode 100644 index 00000000000..7bcc0211c5c --- /dev/null +++ b/src/mame/shared/isbc_215g.cpp @@ -0,0 +1,435 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +// Currently only emulates Shugart SA1000 interface disks (aka ST506) +// despite the controller supporting many different disk types (hard sectored, onboard controllers, ANSI X3T9) +// Xenix supports the Quantum Q540 CHS 512,8,9 with 1024B sectors + +// TODO: multibus + +#include "emu.h" +#include "isbc_215g.h" + +DEFINE_DEVICE_TYPE(ISBC_215G, isbc_215g_device, "isbc_215g", "ISBC 215G Winchester Disk Controller") + +isbc_215g_device::isbc_215g_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, ISBC_215G, tag, owner, clock), + m_maincpu(*this, finder_base::DUMMY_TAG), + m_dmac(*this, "u84"), + m_hdd0(*this, "drive0"), + m_hdd1(*this, "drive1"), + m_sbx1(*this, "sbx1"), + m_sbx2(*this, "sbx2"), + m_out_irq_func(*this) +{ +} + +void isbc_215g_device::find_sector() +{ + //sector id + // 0/6-7: sector type - 0-data, 1-alternate, 2-bad, 3-invalid + // 0/4-5: size - 128<> 4) & 3); + + if(!m_geom[m_drive]) + return; + + if(m_cyl[m_drive] != cyl) + return; + + if((m_idcompare[3] != m_head) || (m_head > m_geom[m_drive]->heads)) + return; + + if(m_idcompare[2] > m_geom[m_drive]->sectors) + return; + + if(bps != m_geom[m_drive]->sectorbytes) + return; + + if(m_idcompare[0] >> 6) + return; + + m_idfound = true; + m_lba[m_drive] = (cyl * m_geom[m_drive]->heads + m_head) * m_geom[m_drive]->sectors + m_idcompare[2]; + m_secoffset = 0; + return; +} + +uint16_t isbc_215g_device::read_sector() +{ + uint16_t wps = 64 << ((m_idcompare[0] >> 4) & 3); + harddisk_image_device *drive = (m_drive ? m_hdd1 : m_hdd0); + if(!m_secoffset) + drive->get_hard_disk_file()->read(m_lba[m_drive], m_sector); + if(m_secoffset >= wps) + return 0; + return m_sector[m_secoffset++]; +} + +bool isbc_215g_device::write_sector(uint16_t data) +{ + uint16_t wps = 64 << ((m_idcompare[0] >> 4) & 3); + harddisk_image_device *drive = (m_drive ? m_hdd1 : m_hdd0); + if(m_secoffset >= wps) + return true; + m_sector[m_secoffset++] = data; + if(m_secoffset == wps) + { + drive->get_hard_disk_file()->write(m_lba[m_drive], m_sector); + return true; + } + return false; +} + +uint16_t isbc_215g_device::io_r(offs_t offset) +{ + uint16_t data = 0; + switch(offset) + { + case 0x00: + //read status + // 0: gnd + // 1: drive ready + // 2: seek done + // 3: sector sync found + // 4: fault + // 5: bus ack + // 6: sector id not found or bad ecc + // 7: timeout + // 8: sbx 1 present + // 9: sbx 1 int 0 + // a: sbx 1 int 1 + // b: sbx 1 opt 0 + // c: sbx 1 opt 1 + // d: illegal req/vendor 2 + // e: drive req + // f: index latch + data |= (!m_idfound) << 6; + data |= (m_sbx1->get_card_device() ? 0 : 1) << 8; + data |= m_isbx_irq[0] << 9; + data |= m_isbx_irq[1] << 10; + data |= ((m_index--) <= 0) ? 0x8000 : 0; // fake an index pulse + break; + case 0x04: + //read status 2 + // 0: sbx 2 present + // 1: sbx 2 int 0 + // 2: sbx 2 int 1 + // 3: sbx 2 opt 0 + // 4: sbx 2 opt 1 + // 5: vendor bit 0 + // 6: track 0/busy + // 7: wp + data |= m_sbx2->get_card_device() ? 0 : 1; + data |= m_isbx_irq[2] << 1; + data |= m_isbx_irq[3] << 2; + data |= (!m_cyl[m_drive]) ? 0 : 0x40; + break; + case 0x08: + //cmd data bus + break; + case 0x0c: + // reset channel 2 + if(machine().side_effects_disabled()) // reading this is bad + break; + m_dmac->sel_w(1); + m_dmac->ca_w(1); + m_dmac->ca_w(0); + m_dmac->sel_w(0); + break; + case 0x10: + //pit ch 0 + break; + case 0x11: + //pit ch 1 + break; + case 0x12: + //pit ch 2 + break; + case 0x14: + //read buffer + if(m_rdgate && !m_amsrch && m_geom[m_drive]) + data = read_sector(); + break; + case 0x18: + //vendor bit 1,3-4 + data |= 3<<4 | 2; + break; + default: + logerror("isbc_215g: invalid port read 0x80%02x\n", offset*2); + break; + } + return data; +} + +void isbc_215g_device::io_w(offs_t offset, uint16_t data) +{ + switch(offset) + { + case 0x00: + //control, 0x8002 doesn't set gates or search + // 0: wr gate + // 1: rd gate + // 2: address mark search + // 3: cmd bus enable + // 4: drive sel/head sel 2 + // 5: safe/head sel 1 + // 6: b ack + // 7: drive reg addr 0/step dir + // 8: drive reg addr 1 + // 9: cmd/rd + // a: para/head sel 0 + m_wrgate = data & 1; + m_rdgate = (data >> 1) & 1; + m_amsrch = (data >> 2) & 1; + if(m_wrgate && (m_rdgate || m_amsrch)) + logerror("isbc_215g: both write gate and read gate and/or address search enabled\n"); + else if(m_rdgate && m_amsrch) + find_sector(); + else if(m_amsrch) + logerror("isbc_215g: address search without read gate\n"); + [[fallthrough]]; + case 0x01: + m_stepdir = (data & 0x80) ? 1 : 0; + break; + case 0x04: + //clear index and id latch + m_index = 10; + m_idfound = false; + break; + case 0x08: + //cmd data bus/head sel + m_head = data & 7; + m_out_irq_func((data & 0x100) ? 1 : 0); + break; + case 0x0c: + //unit select + // 0: step/wr + // 1: sbx 1 opt 0/1 (sbx2?) + // 2: sbx 2 opt 0/1 + // 3: unit select 0 + // 4: unit select 1 + // 5: extr 2 + // 6: format + // 7: format wr gate + if(!m_step && (data & 1) && m_geom[m_drive]) + { + if(m_cyl[m_drive] && !m_stepdir) + m_cyl[m_drive]--; + else if((m_cyl[m_drive] < m_geom[m_drive]->cylinders) && m_stepdir) + m_cyl[m_drive]++; + } + m_step = data & 1; + m_drive = (data >> 3) & 1; // shugart interface, two drives only + if(((data >> 1) & 1) != m_fdctc) + { + m_fdctc = !m_fdctc; + m_sbx2->opt0_w(m_fdctc); + } + if((data & 0xc0) == 0xc0) // low-level format + { + if(!m_format) + m_format_bytes = 5; // sync + sector id + m_format = true; + } + else + m_format = false; + break; + case 0x10: + //pit ch 0 + break; + case 0x11: + //pit ch 1 + break; + case 0x12: + //pit ch 2 + break; + case 0x13: + //pit control + break; + case 0x14: + //write buffer + if(m_wrgate) + { + if(m_format) + { + m_format_bytes -= 2; + if(m_format_bytes <= 0) + { + m_dmac->ext1_w(1); + m_dmac->ext1_w(0); + m_format_bytes = 5; + } + } + else + { + if(m_geom[m_drive]) + { + if(write_sector(data)) + { + m_dmac->ext1_w(1); + m_dmac->ext1_w(0); + } + } + } + } + break; + case 0x18: + //sector id/format + m_idcompare[1] = data & 0xff; + m_idcompare[0] = data >> 8; + break; + case 0x1c: + //sector id low + m_idcompare[3] = data & 0xff; + m_idcompare[2] = data >> 8; + break; + default: + logerror("isbc_215g: invalid port write 0x80%02x\n", offset*2); + break; + } +} + +uint16_t isbc_215g_device::mem_r(offs_t offset, uint16_t mem_mask) +{ + // XXX: hack to permit debugger to disassemble rom + if(machine().side_effects_disabled() && (offset < 0x1fff)) + return m_dmac->space(AS_IO).read_word_unaligned(offset*2); + + switch(offset) + { + case 0x7fffb: + return 1; + case 0x7fffc: + return 0; + case 0x7fffd: + return m_wakeup; + default: + return m_maincpu_mem->read_word_unaligned(offset*2, mem_mask); + } +} + +void isbc_215g_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + m_maincpu_mem->write_word_unaligned(offset*2, data, mem_mask); +} + +void isbc_215g_device::isbc_215g_mem(address_map &map) +{ + map(0x00000, 0xfffff).rw(FUNC(isbc_215g_device::mem_r), FUNC(isbc_215g_device::mem_w)); +} + +void isbc_215g_device::isbc_215g_io(address_map &map) +{ + map(0x0000, 0x3fff).rom().region("i8089", 0); + map(0x4000, 0x47ff).mirror(0x3800).ram(); + map(0x8000, 0x8039).mirror(0x3fc0).rw(FUNC(isbc_215g_device::io_r), FUNC(isbc_215g_device::io_w)); + map(0xc070, 0xc08f).rw("sbx1", FUNC(isbx_slot_device::mcs0_r), FUNC(isbx_slot_device::mcs0_w)).umask16(0x00ff); + map(0xc0b0, 0xc0bf).rw("sbx1", FUNC(isbx_slot_device::mcs1_r), FUNC(isbx_slot_device::mcs1_w)).umask16(0x00ff); + map(0xc0d0, 0xc0df).rw("sbx2", FUNC(isbx_slot_device::mcs0_r), FUNC(isbx_slot_device::mcs0_w)).umask16(0x00ff); + map(0xc0e0, 0xc0ef).rw("sbx2", FUNC(isbx_slot_device::mcs1_r), FUNC(isbx_slot_device::mcs1_w)).umask16(0x00ff); +} + +WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_00_w) +{ + m_isbx_irq[0] = state ? true : false; +} + +WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_01_w) +{ + m_isbx_irq[1] = state ? true : false; +} + +WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_10_w) +{ + m_isbx_irq[2] = state ? true : false; +} + +WRITE_LINE_MEMBER(isbc_215g_device::isbx_irq_11_w) +{ + m_isbx_irq[3] = state ? true : false; +} + +void isbc_215g_device::device_add_mconfig(machine_config &config) +{ + I8089(config, m_dmac, XTAL(15'000'000) / 3); + m_dmac->set_addrmap(AS_PROGRAM, &isbc_215g_device::isbc_215g_mem); + m_dmac->set_addrmap(AS_IO, &isbc_215g_device::isbc_215g_io); + m_dmac->set_data_width(16); + + HARDDISK(config, "drive0", 0); + HARDDISK(config, "drive1", 0); + + ISBX_SLOT(config, m_sbx1, 0, isbx_cards, nullptr); + m_sbx1->mintr0().set(FUNC(isbc_215g_device::isbx_irq_00_w)); + m_sbx1->mintr1().set(FUNC(isbc_215g_device::isbx_irq_01_w)); + ISBX_SLOT(config, m_sbx2, 0, isbx_cards, "fdc_218a"); + m_sbx2->mintr0().set(FUNC(isbc_215g_device::isbx_irq_10_w)); + m_sbx2->mintr1().set(FUNC(isbc_215g_device::isbx_irq_11_w)); +} + + +ROM_START( isbc_215g ) + ROM_REGION16_LE( 0x4000, "i8089", ROMREGION_ERASEFF ) + ROM_LOAD16_BYTE( "174581.001.bin", 0x0000, 0x2000, CRC(ccdbc7ab) SHA1(5c2ebdde1b0252124177221ba9cacdb6d925a24d)) + ROM_LOAD16_BYTE( "174581.002.bin", 0x0001, 0x2000, CRC(6190fa67) SHA1(295dd4e75f699aaf93227cc4876cee8accae383a)) +ROM_END + +const tiny_rom_entry *isbc_215g_device::device_rom_region() const +{ + return ROM_NAME( isbc_215g ); +} + +void isbc_215g_device::device_reset() +{ + if(m_hdd0->get_hard_disk_file()) + m_geom[0] = &m_hdd0->get_hard_disk_file()->get_info(); + else + m_geom[0] = nullptr; + if(m_hdd1->get_hard_disk_file()) + m_geom[1] = &m_hdd1->get_hard_disk_file()->get_info(); + else + m_geom[1] = nullptr; + + m_reset = false; + m_fdctc = false; + m_isbx_irq[0] = m_isbx_irq[1] = m_isbx_irq[2] = m_isbx_irq[3] = false; +} + +void isbc_215g_device::device_start() +{ + m_maincpu_mem = &m_maincpu->space(AS_PROGRAM); + m_cyl[0] = m_cyl[1] = 0; + m_lba[0] = m_lba[1] = 0; + m_idcompare[0] = m_idcompare[1] = m_idcompare[2] = m_idcompare[3] = 0; + m_index = 10; + m_idfound = false; + m_drive = 0; + m_head = 0; + m_stepdir = false; + m_step = false; + m_format = false; + m_wrgate = false; + m_rdgate = false; + m_format_bytes = 0; + m_out_irq_func.resolve_safe(); + +} + +void isbc_215g_device::write(offs_t offset, uint8_t data) +{ + if(!offset) + { + data &= 3; + if(!data && (m_reset == 2)) + m_dmac->reset(); + m_out_irq_func(0); + m_dmac->ca_w(data == 1); + m_dmac->ca_w(0); + m_reset = data; + } +} diff --git a/src/mame/shared/isbc_215g.h b/src/mame/shared/isbc_215g.h new file mode 100644 index 00000000000..8f00143dd17 --- /dev/null +++ b/src/mame/shared/isbc_215g.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef MAME_MACHINE_ISBC_215G_H +#define MAME_MACHINE_ISBC_215G_H + +#pragma once + +#include "cpu/i8089/i8089.h" +#include "bus/isbx/isbx.h" +#include "imagedev/harddriv.h" + +class isbc_215g_device : public device_t +{ +public: + template + isbc_215g_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint16_t wakeup, T &&cpu_tag) + : isbc_215g_device(mconfig, tag, owner, clock) + { + m_wakeup = wakeup; + m_maincpu.set_tag(std::forward(cpu_tag)); + } + + isbc_215g_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto irq_callback() { return m_out_irq_func.bind(); } + + void write(offs_t offset, uint8_t data); + uint16_t io_r(offs_t offset); + void io_w(offs_t offset, uint16_t data); + uint16_t mem_r(offs_t offset, uint16_t mem_mask = ~0); + void mem_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + const tiny_rom_entry *device_rom_region() const override; + + void isbc_215g_io(address_map &map); + void isbc_215g_mem(address_map &map); + +private: + void find_sector(); + uint16_t read_sector(); + bool write_sector(uint16_t data); + + required_device m_maincpu; + required_device m_dmac; + required_device m_hdd0; + required_device m_hdd1; + required_device m_sbx1; + required_device m_sbx2; + + devcb_write_line m_out_irq_func; + + int m_reset; + uint16_t m_wakeup; + uint16_t m_secoffset; + uint16_t m_sector[512]; + address_space *m_maincpu_mem; + uint32_t m_lba[2]; + uint16_t m_cyl[2]; + uint8_t m_idcompare[4]; + uint8_t m_drive; + uint8_t m_head; + uint8_t m_index; + int8_t m_format_bytes; + bool m_idfound; + bool m_stepdir; + bool m_wrgate; + bool m_rdgate; + bool m_amsrch; + + bool m_isbx_irq[4]; + bool m_fdctc; + bool m_step; + bool m_format; + + const struct hard_disk_file::info* m_geom[2]; + + DECLARE_WRITE_LINE_MEMBER(isbx_irq_00_w); + DECLARE_WRITE_LINE_MEMBER(isbx_irq_01_w); + DECLARE_WRITE_LINE_MEMBER(isbx_irq_10_w); + DECLARE_WRITE_LINE_MEMBER(isbx_irq_11_w); +}; + +DECLARE_DEVICE_TYPE(ISBC_215G, isbc_215g_device) + +#endif // MAME_MACHINE_ISBC_215G_H diff --git a/src/mame/shared/mega32x.cpp b/src/mame/shared/mega32x.cpp new file mode 100644 index 00000000000..fdbf96179d6 --- /dev/null +++ b/src/mame/shared/mega32x.cpp @@ -0,0 +1,1862 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* Megadrive / Genesis 32X emulation */ + +/* + + Fix 32X support (not used by any arcade systems?) + - this seems to require far greater sync and timing accuracy on rom / ram access than MAME can provide + - split NTSC / PAL drivers + - 36greatju: missing backup ram, has issues with golfer select due of that + - bcracers: write to undefined PWM register? + - fifa96 / nbajamte: dies on the gameplay, waiting for a comm change that never occurs; + - marsch1: doesn't boot, Master / Slave communicates through SCI + - tempo: intro is too fast, mostly noticeable with the PWM sound that cuts off too early when it gets to the title screen; + - tmek: gameplay is clearly too fast + + +32x Marsch tests documentation (keep start pressed at start-up for individual tests): + +MD side check: +#1 Communication Check +#2 FM Bit +#3 Irq Register +#4 Bank Control Register +#5 DREQ Control FULL bit +#6 DREQ SRC Address +#7 DREQ DST Address +#8 DREQ SIZE Address +#9 SEGA TV Register +#10 H IRQ Vector +#11 PWM Control Register +#12 PWM Frequency Register +#13 PWM Lch Pulse Width Register +#14 PWM Rch Pulse Width Register +#15 PWM MONO Pulse Width Register +32x side check: +#16 SH-2 Master Communication Check +#17 SH-2 Slave Communication Check +#18 SH-2 Master FM Bit +#19 SH-2 Slave FM Bit +#20 SH-2 Master IRQ Mask Register +#21 SH-2 Slave IRQ Mask Register +#22 SH-2 Master H Counter Register +#23 SH-2 Slave H Counter Register +#24 SH-2 Master PWM Timer Register +#25 SH-2 Slave PWM Timer Register +#26 SH-2 Master PWM Cont. Register +#27 SH-2 Slave PWM Cont. Register +#28 SH-2 Master PWM Freq. Register +#29 SH-2 Slave PWM Freq. Register +#30 SH-2 Master PWM Lch Register +#31 SH-2 Slave PWM Lch Register +#32 SH-2 Master PWM Rch Register +#33 SH-2 Slave PWM Rch Register +#34 SH-2 Master PWM Mono Register +#35 SH-2 Slave PWM Mono Register +#36 SH-2 Master ROM Read Check +#37 SH-2 Slave ROM Read Check +#38 SH-2 Serial Communication (ERROR - returns a Timeout Error) +MD & 32x check: +#39 MD&SH-2 Master Communication +#40 MD&SH-2 Slave Communication +#41 MD&SH-2 Master FM Bit R/W +#42 MD&SH-2 Slave FM Bit R/W +#43 MD&SH-2 Master DREQ CTL +#44 MD&SH-2 Slave DREQ CTL +#45 MD&SH-2 Master DREQ SRC address +#46 MD&SH-2 Slave DREQ SRC address +#47 MD&SH-2 Master DREQ DST address +#48 MD&SH-2 Slave DREQ DST address +#49 MD&SH-2 Master DREQ SIZE address +#50 MD&SH-2 Slave DREQ SIZE address +#51 SH-2 Master V IRQ +#52 SH-2 Slave V IRQ +#53 SH2 Master H IRQ (MD 0) +#54 SH2 Slave H IRQ (MD 0) +#55 SH2 Master H IRQ (MD 1) +#56 SH2 Slave H IRQ (MD 1) +#57 SH2 Master H IRQ (MD 2) +#58 SH2 Slave H IRQ (MD 2) +MD VDP check: +#59 Bitmap Mode Register +#60 Shift Register +#61 Auto Fill Length Register +#62 Auto Fill Start Address Register +#63 V Blank BIT +#64 H Blank BIT +#65 Palette Enable BIT +SH-2 VDP check: +#66 Frame Swap BIT +#67 SH-2 Master Bitmap MD +#68 SH-2 Slave Bitmap MD +#69 SH-2 Master Shift +#70 SH-2 Slave Shift +#71 SH-2 Master Fill SIZE +#72 SH-2 Slave Fill SIZE +#73 SH-2 Master Fill START +#74 SH-2 Slave Fill START +#75 SH-2 Master V Blank Bit +#76 SH-2 Slave V Blank Bit +#77 SH-2 Master H Blank Bit +#78 SH-2 Slave H Blank Bit +#79 SH-2 Master Palette Enable Bit +#80 SH-2 Slave Palette Enable Bit +#81 SH-2 Master Frame Swap Bit +#82 SH-2 Slave Frame Swap Bit +Framebuffer Check: +#83 MD Frame Buffer 0 +#84 MD Frame Buffer 1 +#85 SH-2 Master Frame Buffer 0 +#86 SH-2 Slave Frame Buffer 0 +#87 SH-2 Master Frame Buffer 1 +#88 SH-2 Slave Frame Buffer 1 +#89 MD Frame Buffer 0 Overwrite +#90 MD Frame Buffer 1 Overwrite +#91 MD Frame Buffer 0 Byte Write +#92 MD Frame Buffer 1 Byte Write +#93 SH-2 Master Frame Buffer 0 Overwrite +#94 SH-2 Slave Frame Buffer 0 Overwrite +#95 SH-2 Master Frame Buffer 1 Overwrite +#96 SH-2 Slave Frame Buffer 1 Overwrite +#97 SH-2 Master Frame Buffer 0 Byte Write +#98 SH-2 Slave Frame Buffer 0 Byte Write +#99 SH-2 Master Frame Buffer 1 Byte Write +#100 SH-2 Slave Frame Buffer 1 Byte Write +#101 MD Frame Buffer 0 Fill Data +#102 MD Frame Buffer 1 Fill Data +#103 MD Frame Buffer 0 Fill Length & Address +#104 MD Frame Buffer 1 Fill Length & Address +#105 SH-2 Master Frame Buffer 0 Fill Data +#106 SH-2 Slave Frame Buffer 0 Fill Data +#107 SH-2 Master Frame Buffer 1 Fill Data +#108 SH-2 Slave Frame Buffer 1 Fill Data +#109 SH-2 Master Frame Buffer 0 Fill Address +#110 SH-2 Slave Frame Buffer 0 Fill Address +#111 SH-2 Master Frame Buffer 1 Fill Address +#112 SH-2 Slave Frame Buffer 1 Fill Address +#113 MD Palette R/W (Blank Mode) +#114 MD Palette R/W (Display Mode) +#115 MD Palette R/W (Fill Mode) +#116 SH-2 Master Palette R/W (Blank Mode) +#117 SH-2 Slave Palette R/W (Blank Mode) +#118 SH-2 Master Palette R/W (Display Mode) +#119 SH-2 Slave Palette R/W (Display Mode) +#120 SH-2 Master Palette R/W (Fill Mode) +#121 SH-2 Slave Palette R/W (Fill Mode) +MD or SH-2 DMA check: +#122 SH-2 Master CPU Write DMA (68S) (ERROR) +#123 SH-2 Slave CPU Write DMA (68S) (ERROR) +#124 MD ROM to VRAM DMA (asserts after this) +----- +#127 SH-2 Master ROM to SDRAM DMA +#128 SH-2 Slave ROM to SDRAM DMA +#129 SH-2 Master ROM to Frame DMA +#130 SH-2 Slave ROM to Frame DMA +#131 SH-2 Master SDRAM to Frame DMA +#132 SH-2 Slave SDRAM to Frame DMA +#133 SH-2 Master Frame to SDRAM DMA +#134 SH-2 Slave Frame to SDRAM DMA +Sound Test (these don't explicitly fails): +#135 MD 68k Monaural Sound +#136 MD 68k L Sound +#137 MD 68k R Sound +#138 MD 68k L -> R Sound +#139 MD 68k R -> L Sound +#140 SH-2 Master Monaural Sound +#141 SH-2 Master L Sound +#142 SH-2 Master R Sound +#143 SH-2 Master L -> R Pan +#144 SH-2 Master R -> L Pan +#145 SH-2 Slave Monaural Sound +#146 SH-2 Slave L Sound +#147 SH-2 Slave R Sound +#148 SH-2 Slave L -> R Pan +#149 SH-2 Slave R -> L Pan +#150 SH-2 Master PWM Interrupt +#151 SH-2 Slave PWM Interrupt +#152 SH-2 Master PWM DMA Write (!) +#153 SH-2 Slave PWM DMA Write (!) +#154 Z80 PWM Monaural Sound (!) +#155 Z80 PWM L Sound (!) +#156 Z80 PWM R Sound (!) +GFX check (these don't explicitly fails): +#157 Direct Color Mode +#158 Packed Pixel Mode +#159 Runlength Mode +#160 Runlength Mode +#161 Runlength Mode + +*/ +#include "emu.h" +#include "mega32x.h" +#include "machine/timer.h" + + +// Fifa96 needs the CPUs swapped for the gameplay to enter due to some race conditions +// when using the DRC core. Needs further investigation, the non-DRC core works either +// way +#define _32X_SWAP_MASTER_SLAVE_HACK +#define _32X_COMMS_PORT_SYNC 0 +#define MAX_HPOSITION 480 +/* need to make some pwm stuff part of device */ + + + +#define SH2_VRES_IRQ_LEVEL 14 +#define SH2_VINT_IRQ_LEVEL 12 +#define SH2_HINT_IRQ_LEVEL 10 +#define SH2_CINT_IRQ_LEVEL 8 +#define SH2_PINT_IRQ_LEVEL 6 + + +DEFINE_DEVICE_TYPE(SEGA_32X_NTSC, sega_32x_ntsc_device, "sega_32x_ntsc", "Sega 32X (NTSC)") +DEFINE_DEVICE_TYPE(SEGA_32X_PAL, sega_32x_pal_device, "sega_32x_pal", "Sega 32X (PAL)") + +sega_32x_device::sega_32x_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_palette_interface(mconfig, *this) + , device_sound_interface(mconfig, *this) + , device_video_interface(mconfig, *this, false) + , m_sh2_shared(*this, "sh2_shared") + , m_main_cpu(*this, finder_base::DUMMY_TAG) + , m_master_cpu(*this, "32x_master_sh2") + , m_slave_cpu(*this, "32x_slave_sh2") + , m_ldac(*this, "ldac") + , m_rdac(*this, "rdac") + , m_scan_timer(*this, finder_base::DUMMY_TAG) + , m_rombank(*this, "rombank") + , m_stream(nullptr) +{ +} + +sega_32x_ntsc_device::sega_32x_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sega_32x_device(mconfig, SEGA_32X_NTSC, tag, owner, clock) +{ +} + +sega_32x_pal_device::sega_32x_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sega_32x_device(mconfig, SEGA_32X_PAL, tag, owner, clock) +{ +} + +uint16_t sega_32x_device::m68k_palette_r(offs_t offset) +{ + return m_32x_palette[offset]; +} + +void sega_32x_device::m68k_palette_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_32x_palette[offset]); +} + +uint16_t sega_32x_device::m68k_dram_r(offs_t offset) +{ + return m_32x_access_dram[offset]; +} + +void sega_32x_device::m68k_dram_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if ((mem_mask&0xffff) == 0xffff) + { + // 16-bit accesses are normal + COMBINE_DATA(&m_32x_access_dram[offset]); + } + else + { + // 8-bit writes act as if they were going to the overwrite region! + // bc-racers and world series baseball rely on this! + // (tested on real hw) + + if ((mem_mask & 0xffff) == 0xff00) + { + if ((data & 0xff00) != 0x0000) + { + m_32x_access_dram[offset] = (data & 0xff00) | (m_32x_access_dram[offset] & 0x00ff); + } + } + else if ((mem_mask & 0xffff) == 0x00ff) + { + if ((data & 0x00ff) != 0x0000) + { + m_32x_access_dram[offset] = (data & 0x00ff) | (m_32x_access_dram[offset] & 0xff00); + } + } + } +} + +uint16_t sega_32x_device::m68k_dram_overwrite_r(offs_t offset) +{ + return m_32x_access_dram[offset]; +} + +void sega_32x_device::m68k_dram_overwrite_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + //COMBINE_DATA(&m_32x_access_dram[offset+0x10000]); + + if (ACCESSING_BITS_8_15) + { + if (data & 0xff00) + { + m_32x_access_dram[offset] = (m_32x_access_dram[offset]&0x00ff) | (data & 0xff00); + } + } + + if (ACCESSING_BITS_0_7) + { + if (data & 0x00ff) + { + m_32x_access_dram[offset] = (m_32x_access_dram[offset]&0xff00) | (data & 0x00ff); + } + } +} + +/**********************************************************************************************/ +// 68k side a15112 +// FIFO +/**********************************************************************************************/ + + + + +/* + +15106 DREQ + + ---- ---- F--- -K0R + + F = Fifo FULL + K = 68k CPU Write mode (0 = no, 1 = CPU write) + 0 = always 0? no, marsch test wants it to be latched or 1 + R = RV (0 = no operation, 1 = DMA Start allowed) <-- RV bit actually affects memory mapping, this is misleading.. it just sets the memory up in a suitable way to use the genesis VDP DMA + +*/ + + + + +uint16_t sega_32x_device::m68k_a15106_r() +{ + uint16_t retval; + + retval = m_a15106_reg; + + if (m_fifo_block_a_full && m_fifo_block_b_full) retval |= 0x8080; + + return retval; +} + +void sega_32x_device::m68k_a15106_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + m_a15106_reg = data & 0x7; + + if (m_a15106_reg & 0x1) /* NBA Jam TE relies on this */ + { + // install the game rom in the normal 0x000000-0x03fffff space used by the genesis - this allows VDP DMA operations to work as they have to be from this area or RAM + // it should also UNMAP the banked rom area... + space.install_rom(0x0000100, 0x03fffff, machine().root_device().memregion("gamecart")->base() + 0x100); + } + else + { + // we should be careful and map back any rom overlay (hint) and backup ram too I think... + + // this is actually blank / nop area + // we should also map the banked area back (we don't currently unmap it tho) + space.install_rom(0x0000100, 0x03fffff, machine().root_device().memregion("maincpu")->base()+0x100); + } + + if((m_a15106_reg & 4) == 0) // clears the FIFO state + { + m_current_fifo_block = m_fifo_block_a; + m_current_fifo_readblock = m_fifo_block_b; + m_current_fifo_write_pos = 0; + m_current_fifo_read_pos = 0; + m_fifo_block_a_full = 0; + m_fifo_block_b_full = 0; + } + + //printf("m68k_a15106_w %04x\n", data); + /* + if (m_a15106_reg & 0x4) + printf(" --- 68k Write Mode enabled\n"); + else + printf(" --- 68k Write Mode disabled\n"); + + if (m_a15106_reg & 0x1) + printf(" --- DMA Start Allowed \n"); + else + printf(" --- DMA Start No Operation\n"); + + */ + } +} + + + +uint16_t sega_32x_device::dreq_common_r(address_space &space, offs_t offset) +{ + address_space& _68kspace = m_main_cpu->space(AS_PROGRAM); + + switch (offset) + { + case 0x00/2: // a15108 / 4008 + case 0x02/2: // a1510a / 400a + return m_dreq_src_addr[offset&1]; + + case 0x04/2: // a1510c / 400c + case 0x06/2: // a1510e / 400e + return m_dreq_dst_addr[offset&1]; + + case 0x08/2: // a15110 / 4010 + return m_dreq_size; + + case 0x0a/2: // a15112 / 4012 + if (&space == &_68kspace) + { + printf("attempting to READ FIFO with 68k!\n"); + return 0xffff; + } + + uint16_t retdat = m_current_fifo_readblock[m_current_fifo_read_pos]; + + m_current_fifo_read_pos++; + + // printf("reading FIFO!\n"); + + if (m_current_fifo_readblock == m_fifo_block_a && !m_fifo_block_a_full) + logerror("Fifo block a isn't filled!\n"); + + if (m_current_fifo_readblock == m_fifo_block_b && !m_fifo_block_b_full) + logerror("%s Fifo block b isn't filled!\n", machine().describe_context()); + + + if (m_current_fifo_read_pos==4) + { + if (m_current_fifo_readblock == m_fifo_block_a) + { + m_fifo_block_a_full = 0; + + if (m_fifo_block_b_full) + { + m_current_fifo_readblock = m_fifo_block_b; + m_current_fifo_block = m_fifo_block_a; + } + + m_current_fifo_read_pos = 0; + } + else if (m_current_fifo_readblock == m_fifo_block_b) + { + m_fifo_block_b_full = 0; + + if (m_fifo_block_a_full) + { + m_current_fifo_readblock = m_fifo_block_a; + m_current_fifo_block = m_fifo_block_b; + } + + m_current_fifo_read_pos = 0; + } + } + + return retdat; + } + + return 0x0000; +} + +void sega_32x_device::dreq_common_w(address_space &space, offs_t offset, uint16_t data) +{ + address_space& _68kspace = m_main_cpu->space(AS_PROGRAM); + + switch (offset) + { + case 0x00/2: // a15108 / 4008 + case 0x02/2: // a1510a / 400a + if (&space != &_68kspace) + { + printf("attempting to WRITE DREQ SRC with SH2!\n"); + return; + } + + m_dreq_src_addr[offset&1] = ((offset&1) == 0) ? (data & 0xff) : (data & 0xfffe); + + //if((m_dreq_src_addr[0]<<16)|m_dreq_src_addr[1]) + // printf("DREQ set SRC = %08x\n",(m_dreq_src_addr[0]<<16)|m_dreq_src_addr[1]); + + break; + + case 0x04/2: // a1510c / 400c + case 0x06/2: // a1510e / 400e + if (&space != &_68kspace) + { + printf("attempting to WRITE DREQ DST with SH2!\n"); + return; + } + + m_dreq_dst_addr[offset&1] = ((offset&1) == 0) ? (data & 0xff) : (data & 0xffff); + + //if((m_dreq_dst_addr[0]<<16)|m_dreq_dst_addr[1]) + // printf("DREQ set DST = %08x\n",(m_dreq_dst_addr[0]<<16)|m_dreq_dst_addr[1]); + + break; + + case 0x08/2: // a15110 / 4010 + if (&space != &_68kspace) + { + printf("attempting to WRITE DREQ SIZE with SH2!\n"); + return; + } + + m_dreq_size = data & 0xfffc; + + // if(m_dreq_size) + // printf("DREQ set SIZE = %04x\n",m_dreq_size); + + break; + + case 0x0a/2: // a15112 / 4012 - FIFO Write (68k only!) + if (&space != &_68kspace) + { + printf("attempting to WRITE FIFO with SH2!\n"); + return; + } + + if (m_current_fifo_block==m_fifo_block_a && m_fifo_block_a_full) + { + printf("attempt to write to Full Fifo block a!\n"); + return; + } + + if (m_current_fifo_block==m_fifo_block_b && m_fifo_block_b_full) + { + printf("attempt to write to Full Fifo block b!\n"); + return; + } + + if((m_a15106_reg & 4) == 0) + { + printf("attempting to WRITE FIFO with 68S cleared!\n"); // corpse32 + return; + } + + m_current_fifo_block[m_current_fifo_write_pos] = data; + m_current_fifo_write_pos++; + + if (m_current_fifo_write_pos==4) + { + if (m_current_fifo_block==m_fifo_block_a) + { + m_fifo_block_a_full = 1; + if (!m_fifo_block_b_full) + { + m_current_fifo_block = m_fifo_block_b; + m_current_fifo_readblock = m_fifo_block_a; + // incase we have a stalled DMA in progress, let the SH2 know there is data available + m_master_cpu->sh2_notify_dma_data_available(); + m_slave_cpu->sh2_notify_dma_data_available(); + + } + m_current_fifo_write_pos = 0; + } + else + { + m_fifo_block_b_full = 1; + + if (!m_fifo_block_a_full) + { + m_current_fifo_block = m_fifo_block_a; + m_current_fifo_readblock = m_fifo_block_b; + // incase we have a stalled DMA in progress, let the SH2 know there is data available + m_master_cpu->sh2_notify_dma_data_available(); + m_slave_cpu->sh2_notify_dma_data_available(); + } + + m_current_fifo_write_pos = 0; + } + } + + break; + } +} + + + + +uint16_t sega_32x_device::m68k_a1511a_r() +{ + return m_sega_tv; +} + +void sega_32x_device::m68k_a1511a_w(uint16_t data) +{ + m_sega_tv = data & 1; + + printf("SEGA TV register set = %04x\n",data); +} + +/* +000070 H interrupt vector can be overwritten apparently +*/ + + + +uint16_t sega_32x_device::m68k_m_hint_vector_r(offs_t offset) +{ + return m_hint_vector[offset]; +} + +void sega_32x_device::m68k_m_hint_vector_w(offs_t offset, uint16_t data) +{ + m_hint_vector[offset] = data; +} + +// returns MARS, the system ID of the 32x +uint16_t sega_32x_device::m68k_MARS_r(offs_t offset) +{ + switch (offset) + { + case 0: + return 0x4d41; + + case 1: + return 0x5253; + } + + return 0x0000; +} + + +/**********************************************************************************************/ +// 68k side a15100 +// control register - used to enable 32x etc. +/**********************************************************************************************/ + + + +uint16_t sega_32x_device::m68k_a15100_r() +{ + return (m_32x_access_auth<<15) | 0x0080; +} + +void sega_32x_device::m68k_a15100_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + m_a15100_reg = (m_a15100_reg & 0xff00) | (data & 0x00ff); + + if (data & 0x02) + { + m_master_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + m_slave_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + } + + if (data & 0x01) + { + m_32x_adapter_enabled = 1; + space.install_rom(0x0880000, 0x08fffff, machine().root_device().memregion("gamecart")->base()); // 'fixed' 512kb rom bank + + space.install_read_bank(0x0900000, 0x09fffff, m_rombank); // 'bankable' 1024kb rom bank + m_rombank->set_base(machine().root_device().memregion("gamecart")->base()+((m_32x_68k_a15104_reg&0x3)*0x100000) ); + + space.install_rom(0x0000000, 0x03fffff, machine().root_device().memregion("32x_68k_bios")->base()); + + /* VDP area */ + space.install_read_handler(0x0a15180, 0x0a1518b, read16sm_delegate(*this, FUNC(sega_32x_device::common_vdp_regs_r))); // common / shared VDP regs + space.install_write_handler(0x0a15180, 0x0a1518b, write16_delegate(*this, FUNC(sega_32x_device::common_vdp_regs_w))); // common / shared VDP regs + space.install_read_handler(0x0a15200, 0x0a153ff, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_palette_r))); // access to 'palette' xRRRRRGGGGGBBBBB + space.install_write_handler(0x0a15200, 0x0a153ff, write16s_delegate(*this, FUNC(sega_32x_device::m68k_palette_w))); // access to 'palette' xRRRRRGGGGGBBBBB + space.install_read_handler(0x0840000, 0x085ffff, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_dram_r))); // access to 'display ram' (framebuffer) + space.install_write_handler(0x0840000, 0x085ffff, write16s_delegate(*this, FUNC(sega_32x_device::m68k_dram_w))); // access to 'display ram' (framebuffer) + space.install_read_handler(0x0860000, 0x087ffff, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_dram_overwrite_r))); // access to 'display ram' (framebuffer) + space.install_write_handler(0x0860000, 0x087ffff, write16s_delegate(*this, FUNC(sega_32x_device::m68k_dram_overwrite_w))); // access to 'display ram' (framebuffer) + + + + m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0x000070, 0x000073, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_w))); // h interrupt vector + } + else + { + m_32x_adapter_enabled = 0; + + space.install_rom(0x0000000, 0x03fffff, machine().root_device().memregion("gamecart")->base()); + m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0x000070, 0x000073, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_w))); // h interrupt vector + } + } + + if (ACCESSING_BITS_8_15) + { + m_a15100_reg = (m_a15100_reg & 0x00ff) | (data & 0xff00); + m_32x_access_auth = (data & 0x8000)>>15; + } +} + +/**********************************************************************************************/ +// 68k side a15102 +// command interrupt to SH2 +/**********************************************************************************************/ + + + +uint16_t sega_32x_device::m68k_a15102_r() +{ + //printf("_32x_68k_a15102_r\n"); + return m_32x_68k_a15102_reg; +} + +void sega_32x_device::m68k_a15102_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + m_32x_68k_a15102_reg = data & 3; + + if (data&0x1) + { + if (m_sh2_master_cmdint_enable) m_master_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,ASSERT_LINE); + else printf("master cmdint when masked!\n"); + } + + if (data&0x2) + { + if (m_sh2_slave_cmdint_enable) m_slave_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,ASSERT_LINE); + else printf("slave cmdint when masked!\n"); + } + } +} + +/**********************************************************************************************/ +// 68k side a15104 +// ROM banking for 68k rom +/**********************************************************************************************/ + + +uint16_t sega_32x_device::m68k_a15104_r() +{ + return m_32x_68k_a15104_reg; +} + +void sega_32x_device::m68k_a15104_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + m_32x_68k_a15104_reg = (m_32x_68k_a15104_reg & 0xff00) | (data & 0x00ff); + } + + if (ACCESSING_BITS_8_15) + { + m_32x_68k_a15104_reg = (m_32x_68k_a15104_reg & 0x00ff) | (data & 0xff00); + } + + m_rombank->set_base(machine().root_device().memregion("gamecart")->base()+((m_32x_68k_a15104_reg&0x3)*0x100000) ); +} + +/**********************************************************************************************/ +// 68k side a15120 - a1512f +// Communication Port 0 +// access from the SH2 via 4020 - 402f +/**********************************************************************************************/ + + +/**********************************************************************************************/ + +// reads +uint16_t sega_32x_device::m68k_m_commsram_r(offs_t offset) +{ + if (_32X_COMMS_PORT_SYNC) machine().scheduler().synchronize(); + return m_commsram[offset]; +} + +// writes +void sega_32x_device::m68k_m_commsram_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_commsram[offset]); + if (_32X_COMMS_PORT_SYNC) machine().scheduler().synchronize(); +} + +/**********************************************************************************************/ +// 68k side a15130 - a1513f +// PWM registers +// access from the SH2 via 4030 - 403f +/**********************************************************************************************/ + +/* +TODO: +- noticeable static noise on Virtua Fighter Sega logo at start-up +- Understand if Speaker OFF makes the FIFO to advance or not +- move inside a device +*/ + + + + +void sega_32x_device::calculate_pwm_timer() +{ + if(m_pwm_tm_reg == 0) { m_pwm_tm_reg = 16; } // zero gives max range + if(m_pwm_cycle == 0) { m_pwm_cycle = 4095; } // zero gives max range + + /* if both RMD and LMD are set to OFF or pwm cycle register is one, then PWM timer ticks doesn't occur */ + if(m_pwm_cycle == 1 || ((m_pwm_ctrl & 0xf) == 0)) + m_32x_pwm_timer->adjust(attotime::never); + else + { + m_pwm_timer_tick = 0; + m_lch_fifo_state = m_rch_fifo_state = 0x4000; + m_lch_size = m_rch_size = 0; + m_32x_pwm_timer->adjust(attotime::from_hz(clock() / (m_pwm_cycle - 1))); + } +} + +void sega_32x_device::lch_pop() +{ + for (int i = 0; i < PWM_FIFO_SIZE - 1; i++) + m_cur_lch[i] = m_cur_lch[i + 1]; + m_lch_size--; +} + +void sega_32x_device::rch_pop() +{ + for (int i = 0; i < PWM_FIFO_SIZE - 1; i++) + m_cur_rch[i] = m_cur_rch[i + 1]; + m_rch_size--; +} + +TIMER_CALLBACK_MEMBER(sega_32x_device::handle_pwm_callback) +{ + if (m_lch_size > 0) + { + m_stream->update(); + switch(m_pwm_ctrl & 3) + { + case 0: /*Speaker OFF*/ break; + case 1: m_ldac->write(m_cur_lch[0]); break; + case 2: m_rdac->write(m_cur_lch[0]); break; + case 3: popmessage("Undefined PWM Lch value 3, contact MESSdev"); break; + } + + lch_pop(); + } + + m_lch_fifo_state = (m_lch_size == 0) ? 0x4000 : 0x0000; + + if (m_rch_size > 0) + { + m_stream->update(); + switch((m_pwm_ctrl & 0xc) >> 2) + { + case 0: /*Speaker OFF*/ break; + case 1: m_rdac->write(m_cur_rch[0]); break; + case 2: m_ldac->write(m_cur_rch[0]); break; + case 3: popmessage("Undefined PWM Rch value 3, contact MESSdev"); break; + } + + rch_pop(); + } + + m_rch_fifo_state = (m_rch_size == 0) ? 0x4000 : 0x0000; + + m_pwm_timer_tick++; + + if(m_pwm_timer_tick == m_pwm_tm_reg) + { + m_pwm_timer_tick = 0; + if(sh2_master_pwmint_enable) { m_master_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,ASSERT_LINE); } + if(sh2_slave_pwmint_enable) { m_slave_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,ASSERT_LINE); } + } + + m_32x_pwm_timer->adjust(attotime::from_hz(clock() / (m_pwm_cycle - 1))); +} + +uint16_t sega_32x_device::pwm_r(offs_t offset) +{ + switch(offset) + { + case 0x00/2: return m_pwm_ctrl; //control register + case 0x02/2: return m_pwm_cycle_reg; // cycle register + case 0x04/2: return m_lch_fifo_state; // l ch + case 0x06/2: return m_rch_fifo_state; // r ch + case 0x08/2: return m_lch_fifo_state & m_rch_fifo_state; // mono ch + } + + printf("Read at undefined PWM register %02x\n",offset); + return 0xffff; +} + +void sega_32x_device::pwm_w(offs_t offset, uint16_t data) +{ + switch(offset) + { + case 0x00/2: + m_pwm_ctrl = data & 0xffff; + m_pwm_tm_reg = (m_pwm_ctrl & 0xf00) >> 8; + calculate_pwm_timer(); + break; + case 0x02/2: + m_pwm_cycle = m_pwm_cycle_reg = data & 0xfff; + calculate_pwm_timer(); + break; + case 0x04/2: + if (m_lch_size == PWM_FIFO_SIZE) + lch_pop(); + m_cur_lch[m_lch_size++] = data; + + m_lch_fifo_state = (m_lch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; + break; + case 0x06/2: + if (m_rch_size == PWM_FIFO_SIZE) + rch_pop(); + m_cur_rch[m_rch_size++] = data; + + m_rch_fifo_state = (m_rch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; + break; + case 0x08/2: + if (m_lch_size == PWM_FIFO_SIZE) + lch_pop(); + m_cur_lch[m_lch_size++] = data; + + if (m_rch_size == PWM_FIFO_SIZE) + rch_pop(); + m_cur_rch[m_rch_size++] = data; + + m_lch_fifo_state = (m_lch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; + m_rch_fifo_state = (m_rch_size == PWM_FIFO_SIZE) ? 0x8000 : 0x0000; + break; + default: + printf("Write at undefined PWM register %02x %04x\n",offset,data); + break; + } +} + +void sega_32x_device::m68k_pwm_w(offs_t offset, uint16_t data) +{ + if(offset == 0/2) + pwm_w(offset,(data & 0x7f) | (m_pwm_ctrl & 0xff80)); + else + pwm_w(offset,data); +} + +void sega_32x_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + outputs[0] = inputs[0]; + outputs[1] = inputs[1]; +} + +/**********************************************************************************************/ +// 68k side a15180 +// framebuffer control +// also accessed from the SH2 @ 4100 +/**********************************************************************************************/ + +uint16_t sega_32x_device::get_hposition(void) +{ + if (get_framerate() > 0.0) + { + attotime time_elapsed_since_megadriv_scanline_timer; + uint16_t value4; + + time_elapsed_since_megadriv_scanline_timer = m_scan_timer->time_elapsed(); + + if (time_elapsed_since_megadriv_scanline_timer.attoseconds() < (ATTOSECONDS_PER_SECOND/get_framerate() /double(m_total_scanlines))) + { + value4 = (uint16_t)(MAX_HPOSITION*((double)(time_elapsed_since_megadriv_scanline_timer.attoseconds()) / (double)(ATTOSECONDS_PER_SECOND/get_framerate() /double(m_total_scanlines)))); + } + else /* in some cases (probably due to rounding errors) we get some stupid results (the odd huge value where the time elapsed is much higher than the scanline time??!).. hopefully by clamping the result to the maximum we limit errors */ + { + value4 = MAX_HPOSITION; + } + + return value4; + } + return MAX_HPOSITION; +} + +uint16_t sega_32x_device::common_vdp_regs_r(offs_t offset) +{ + // what happens if the z80 accesses it, what authorization do we use? + + int ntsc; + +// printf("_32x_68k_a15180_r (a15180) %04x\n",mem_mask); + + // read needs authorization too I think, undefined behavior otherwise + switch (offset) + { + case 0x00: + + // the flag is inverted compared to the megadrive + ntsc = m_32x_pal ? 0 : 1; + + return (ntsc << 15) | + (m_32x_videopriority << 7) | + (m_32x_240mode << 6) | + (m_32x_displaymode << 0); + + case 0x02/2: + return m_32x_screenshift; + + case 0x04/2: + return m_32x_autofill_length; + + case 0x06/2: + return m_32x_autofill_address; + + case 0x08/2: + return m_32x_autofill_data; + + case 0x0a/2: + uint16_t retdata = m_32x_a1518a_reg; + uint16_t hpos = get_hposition(); + int megadrive_hblank_flag = 0; + + if (m_32x_vblank_flag) retdata |= 0x8000; + + if (hpos>400) megadrive_hblank_flag = 1; + if (hpos>460) megadrive_hblank_flag = 0; + + if (megadrive_hblank_flag) retdata |= 0x4000; + + if (m_32x_vblank_flag) { retdata |= 2; } // framebuffer approval (TODO: condition is unknown at current time) + + if (megadrive_hblank_flag && m_32x_vblank_flag) { retdata |= 0x2000; } // palette approval (TODO: active high or low?) + + return retdata; + } + + return 0x0000; +} + + +void sega_32x_device::check_framebuffer_swap(bool enabled) +{ + // this logic should be correct, but makes things worse? + // enabled = (genesis_scanline_counter >= megadrive_irq6_scanline) from video/315_5313.cpp + //if (enabled) + { + m_32x_a1518a_reg = m_32x_fb_swap & 1; + + if (m_32x_fb_swap & 1) + { + m_32x_access_dram = m_32x_dram0.get(); + m_32x_display_dram = m_32x_dram1.get(); + } + else + { + m_32x_display_dram = m_32x_dram0.get(); + m_32x_access_dram = m_32x_dram1.get(); + } + } +} + + +void sega_32x_device::common_vdp_regs_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask) +{ + // what happens if the z80 accesses it, what authorization do we use? which address space do we get?? the z80 *can* write here and to the framebuffer via the window + + address_space& _68kspace = m_main_cpu->space(AS_PROGRAM); + + if (&space!= &_68kspace) + { + if (m_32x_access_auth!=1) + return; + } + + if (&space== &_68kspace) + { + if (m_32x_access_auth!=0) + return; + } + + + switch (offset) + { + case 0x00: + //printf("_32x_68k_a15180_w (a15180) %04x %04x source m_32x_access_auth %04x\n",data,mem_mask, m_32x_access_auth); + + if (ACCESSING_BITS_0_7) + { + m_32x_videopriority = (data & 0x80) >> 7; + m_32x_240mode = (data & 0x40) >> 6; + m_32x_displaymode = (data & 0x03) >> 0; + } + break; + + case 0x02/2: + if (ACCESSING_BITS_0_7) + { + m_32x_screenshift = data & 1; // allows 1 pixel shifting + } + if (ACCESSING_BITS_8_15) + { + } + break; + + case 0x04/2: + if (ACCESSING_BITS_0_7) + { + m_32x_autofill_length = data & 0xff; + } + + if (ACCESSING_BITS_8_15) + { + } + break; + + case 0x06/2: + if (ACCESSING_BITS_0_7) + { + m_32x_autofill_address = (m_32x_autofill_address & 0xff00) | (data & 0x00ff); + } + + if (ACCESSING_BITS_8_15) + { + m_32x_autofill_address = (m_32x_autofill_address & 0x00ff) | (data & 0xff00); + } + break; + + case 0x08/2: + if (ACCESSING_BITS_0_7) + { + m_32x_autofill_data = (m_32x_autofill_data & 0xff00) | (data & 0x00ff); + } + + if (ACCESSING_BITS_8_15) + { + m_32x_autofill_data = (m_32x_autofill_data & 0x00ff) | (data & 0xff00); + } + + // do the fill - shouldn't be instant.. + { + int i; + for (i=0; i> 15; + } + + if (ACCESSING_BITS_0_7) + { + m_sh2_hint_in_vbl = data & 0x80; + m_sh2_master_vint_enable = data & 0x8; + m_sh2_master_hint_enable = data & 0x4; + m_sh2_master_cmdint_enable = data & 0x2; + sh2_master_pwmint_enable = data & 0x1; + + //if (m_sh2_master_hint_enable) printf("m_sh2_master_hint_enable enable!\n"); + //if (sh2_master_pwmint_enable) printf("sh2_master_pwn_enable enable!\n"); + + check_irqs(); + } +} + +/* SLAVE */ + +uint16_t sega_32x_device::slave_4000_r() +{ + uint16_t retvalue = 0x0200; + retvalue |= m_32x_access_auth << 15; + retvalue |= m_sh2_hint_in_vbl; + retvalue |= m_sh2_slave_vint_enable; + retvalue |= m_sh2_slave_hint_enable; + retvalue |= m_sh2_slave_cmdint_enable; + retvalue |= sh2_slave_pwmint_enable; + + return retvalue; +} + + +void sega_32x_device::slave_4000_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_8_15) + { + m_32x_access_auth = (data &0x8000) >> 15; + } + + if (ACCESSING_BITS_0_7) + { + m_sh2_hint_in_vbl = data & 0x80; + m_sh2_slave_vint_enable = data & 0x8; + m_sh2_slave_hint_enable = data & 0x4; + m_sh2_slave_cmdint_enable = data & 0x2; + sh2_slave_pwmint_enable = data & 0x1; + + //if (m_sh2_slave_hint_enable) printf("m_sh2_slave_hint_enable enable!\n"); + //if (sh2_slave_pwmint_enable) printf("sh2_slave_pwm_enable enable!\n"); + + check_irqs(); + } +} + +/**********************************************************************************************/ +// SH2 side 4002 +// Reserved ( Stand By Change Register ) +// Shouldn't be used +/**********************************************************************************************/ + +uint16_t sega_32x_device::common_4002_r() +{ + printf("reading 4002!\n"); + return 0x0000; +} + +void sega_32x_device::common_4002_w(uint16_t data) +{ + printf("write 4002!\n"); +} + + +/**********************************************************************************************/ +// SH2 side 4004 +// H Count Register (H Interrupt) +// 0 = every line +/**********************************************************************************************/ +uint16_t sega_32x_device::common_4004_r() +{ + return m_32x_hcount_reg; +} + +void sega_32x_device::common_4004_w(uint16_t data) +{ + m_32x_hcount_reg = data & 0xff; +} + + +/**********************************************************************************************/ +// SH2 side 4006 +// DReq Control Register +/**********************************************************************************************/ + +uint16_t sega_32x_device::common_4006_r() +{ + //printf("DREQ read!\n"); // tempo reads it, shut up for now + return m68k_a15106_r(); +} + +void sega_32x_device::common_4006_w(uint16_t data) +{ + printf("DREQ write!\n"); //register is read only on SH-2 side +} + + +/**********************************************************************************************/ +// SH2 side 4014 +// VRES (md reset button interrupt) clear +/**********************************************************************************************/ + +void sega_32x_device::master_4014_w(uint16_t data){ m_master_cpu->set_input_line(SH2_VRES_IRQ_LEVEL,CLEAR_LINE);} +void sega_32x_device::slave_4014_w(uint16_t data) { m_slave_cpu->set_input_line(SH2_VRES_IRQ_LEVEL,CLEAR_LINE);} + +/**********************************************************************************************/ +// SH2 side 4016 +// VINT (vertical interrupt) clear +/**********************************************************************************************/ + +void sega_32x_device::master_4016_w(uint16_t data){ m_sh2_master_vint_pending = 0; check_irqs(); } +void sega_32x_device::slave_4016_w(uint16_t data) { m_sh2_slave_vint_pending = 0; check_irqs(); } + +/**********************************************************************************************/ +// SH2 side 4018 +// HINT (horizontal interrupt) clear +/**********************************************************************************************/ + +void sega_32x_device::master_4018_w(uint16_t data){ m_master_cpu->set_input_line(SH2_HINT_IRQ_LEVEL,CLEAR_LINE);} +void sega_32x_device::slave_4018_w(uint16_t data) { m_slave_cpu->set_input_line(SH2_HINT_IRQ_LEVEL,CLEAR_LINE);} + +/**********************************************************************************************/ +// SH2 side 401A +// HINT (control register interrupt) clear +// Note: flag cleared here is a guess, according to After Burner behaviour +/**********************************************************************************************/ + +void sega_32x_device::master_401a_w(uint16_t data){ m_32x_68k_a15102_reg &= ~1; m_master_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,CLEAR_LINE);} +void sega_32x_device::slave_401a_w(uint16_t data) { m_32x_68k_a15102_reg &= ~2; m_slave_cpu->set_input_line(SH2_CINT_IRQ_LEVEL,CLEAR_LINE);} + +/**********************************************************************************************/ +// SH2 side 401C +// PINT (PWM timer interrupt) clear +/**********************************************************************************************/ + +void sega_32x_device::master_401c_w(uint16_t data){ m_master_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,CLEAR_LINE);} +void sega_32x_device::slave_401c_w(uint16_t data) { m_slave_cpu->set_input_line(SH2_PINT_IRQ_LEVEL,CLEAR_LINE);} + +/**********************************************************************************************/ +// SH2 side 401E +// ?? unknown / unused +/**********************************************************************************************/ + +void sega_32x_device::master_401e_w(uint16_t data) +{ + printf("master_401e_w\n"); +} + +void sega_32x_device::slave_401e_w(uint16_t data) +{ + printf("slave_401e_w\n"); +} + +/**********************************************************************************************/ +// SH2 side 4020 - 402f +// SH2 -> 68k Comms ports, +// access at a15120 - a1512f on 68k +// these just map through to the 68k functions +/**********************************************************************************************/ + +/* handled directly */ + +/**********************************************************************************************/ +// SH2 side 4030 +// PWM Control Register +/**********************************************************************************************/ + +/**********************************************************************************************/ +// SH2 side 4032 +// Cycle Register +/**********************************************************************************************/ + + +/**********************************************************************************************/ +// SH2 side 4034 +// LCH Pulse Width Register +/**********************************************************************************************/ + +/**********************************************************************************************/ +// SH2 side 4036 +// RCH Pulse Width Register +/**********************************************************************************************/ + +/**********************************************************************************************/ +// SH2 side 4038 +// Mono Pulse Width Register +/**********************************************************************************************/ + +/* 4100 - 43ff are VDP registers, you need permission to access them - ensure this is true for all! */ + +/**********************************************************************************************/ +// SH2 side 4200 - 43ff +// palette +// maps through to 68k at a15200 - a153ff +/**********************************************************************************************/ + +/* handled directly */ + +/**********************************************************************************************/ +// SH2 side 4000000 - 401ffff +// framebuffer +// maps through to 68k at 840000 - 85ffff +/**********************************************************************************************/ + +/* handled directly */ + +/**********************************************************************************************/ +// SH2 side 4020000 - 403ffff +// framebuffer overwrite +// maps through to 68k at 860000 - 87ffff +/**********************************************************************************************/ + +/* handled directly */ + + +/**********************************************************************************************/ +// SH2 memory maps +/**********************************************************************************************/ + +void sega_32x_device::sh2_common_map(address_map &map) +{ + map(0x00004002, 0x00004003).rw(FUNC(sega_32x_device::common_4002_r), FUNC(sega_32x_device::common_4002_w)); + map(0x00004004, 0x00004005).rw(FUNC(sega_32x_device::common_4004_r), FUNC(sega_32x_device::common_4004_w)); + map(0x00004006, 0x00004007).rw(FUNC(sega_32x_device::common_4006_r), FUNC(sega_32x_device::common_4006_w)); + + map(0x00004008, 0x00004013).rw(FUNC(sega_32x_device::dreq_common_r), FUNC(sega_32x_device::dreq_common_w)); + + map(0x00004014, 0x0000401f).nopr(); + + map(0x00004020, 0x0000402f).rw(FUNC(sega_32x_device::m68k_m_commsram_r), FUNC(sega_32x_device::m68k_m_commsram_w)); + map(0x00004030, 0x0000403f).rw(FUNC(sega_32x_device::pwm_r), FUNC(sega_32x_device::pwm_w)); + + map(0x00004100, 0x0000410b).rw(FUNC(sega_32x_device::common_vdp_regs_r), FUNC(sega_32x_device::common_vdp_regs_w)); + map(0x00004200, 0x000043ff).rw(FUNC(sega_32x_device::m68k_palette_r), FUNC(sega_32x_device::m68k_palette_w)); + + map(0x04000000, 0x0401ffff).rw(FUNC(sega_32x_device::m68k_dram_r), FUNC(sega_32x_device::m68k_dram_w)); + map(0x04020000, 0x0403ffff).rw(FUNC(sega_32x_device::m68k_dram_overwrite_r), FUNC(sega_32x_device::m68k_dram_overwrite_w)); + + map(0x06000000, 0x0603ffff).ram().share("sh2_shared"); + + map(0x02000000, 0x023fffff).rom().region(":gamecart_sh2", 0); + map(0x22000000, 0x223fffff).rom().region(":gamecart_sh2", 0); // cart mirror (fifa96) + + map(0xc0000000, 0xc0000fff).ram(); +} + +void sega_32x_device::sh2_main_map(address_map &map) +{ + sh2_common_map(map); + map(0x00000000, 0x00003fff).bankr("masterbios"); + + map(0x00004000, 0x00004001).rw(FUNC(sega_32x_device::master_4000_r), FUNC(sega_32x_device::master_4000_w)); + + map(0x00004014, 0x00004015).w(FUNC(sega_32x_device::master_4014_w)); + map(0x00004016, 0x00004017).w(FUNC(sega_32x_device::master_4016_w)); + map(0x00004018, 0x00004019).w(FUNC(sega_32x_device::master_4018_w)); + map(0x0000401a, 0x0000401b).w(FUNC(sega_32x_device::master_401a_w)); + map(0x0000401c, 0x0000401d).w(FUNC(sega_32x_device::master_401c_w)); + map(0x0000401e, 0x0000401f).w(FUNC(sega_32x_device::master_401e_w)); +} + +void sega_32x_device::sh2_slave_map(address_map &map) +{ + sh2_common_map(map); + map(0x00000000, 0x00003fff).bankr("slavebios"); + + map(0x00004000, 0x00004001).rw(FUNC(sega_32x_device::slave_4000_r), FUNC(sega_32x_device::slave_4000_w)); + + map(0x00004014, 0x00004015).w(FUNC(sega_32x_device::slave_4014_w)); + map(0x00004016, 0x00004017).w(FUNC(sega_32x_device::slave_4016_w)); + map(0x00004018, 0x00004019).w(FUNC(sega_32x_device::slave_4018_w)); + map(0x0000401a, 0x0000401b).w(FUNC(sega_32x_device::slave_401a_w)); + map(0x0000401c, 0x0000401d).w(FUNC(sega_32x_device::slave_401c_w)); + map(0x0000401e, 0x0000401f).w(FUNC(sega_32x_device::slave_401e_w)); +} + +/****************************************** END 32X related *************************************/ + + + + +void sega_32x_device::check_irqs() +{ + if (m_sh2_master_vint_enable && m_sh2_master_vint_pending) m_master_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,ASSERT_LINE); + else m_master_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,CLEAR_LINE); + + if (m_sh2_slave_vint_enable && m_sh2_slave_vint_pending) m_slave_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,ASSERT_LINE); + else m_slave_cpu->set_input_line(SH2_VINT_IRQ_LEVEL,CLEAR_LINE); +} + +void sega_32x_device::interrupt_cb(int scanline, int irq6) +{ + if (scanline == irq6) + { + m_32x_vblank_flag = 1; + m_sh2_master_vint_pending = 1; + m_sh2_slave_vint_pending = 1; + check_irqs(); + } + + check_framebuffer_swap(scanline >= irq6); + + m_32x_hcount_compare_val++; + + if (m_32x_hcount_compare_val >= m_32x_hcount_reg) + { + m_32x_hcount_compare_val = -1; + + if (scanline < 224 || m_sh2_hint_in_vbl) + { + if (m_sh2_master_hint_enable) + m_master_cpu->set_input_line(SH2_HINT_IRQ_LEVEL, ASSERT_LINE); + if (m_sh2_slave_hint_enable) + m_slave_cpu->set_input_line(SH2_HINT_IRQ_LEVEL, ASSERT_LINE); + } + } +} + + +SH2_DMA_FIFO_DATA_AVAILABLE_CB(sega_32x_device::_32x_fifo_available_callback) +{ + if (src==0x4012) + { + if (m_current_fifo_readblock==m_fifo_block_a && m_fifo_block_a_full) + return 1; + + if (m_current_fifo_readblock==m_fifo_block_b && m_fifo_block_b_full) + return 1; + + return 0; + } + + return 1; +} + + + +void sega_32x_device::render_videobuffer_to_screenbuffer_helper(int scanline) +{ + int x; + + /* render 32x output to a buffer */ + if (m_32x_displaymode != 0) + { + if (m_32x_displaymode==1) + { + uint32_t lineoffs; + int start; + + lineoffs = m_32x_display_dram[scanline]; + + if (m_32x_screenshift == 0) start=0; + else start = -1; + + for (x=start;x<320;x++) + { + uint16_t coldata; + coldata = m_32x_display_dram[lineoffs]; + + { + if (x>=0) + { + m_32x_linerender[x] = m_32x_palette[(coldata & 0xff00)>>8]; + } + + x++; + + if (x>=0) + { + m_32x_linerender[x] = m_32x_palette[(coldata & 0x00ff)]; + } + } + + lineoffs++; + + } + } + else if (m_32x_displaymode==3) // mode 3 = RLE (used by BRUTAL intro) + { + uint32_t lineoffs; + int start; + + lineoffs = m_32x_display_dram[scanline]; + + if (m_32x_screenshift == 0) start=0; + else start = -1; + + x = start; + while (x<320) + { + uint16_t coldata, length, l; + coldata = m_32x_display_dram[lineoffs]; + length = ((coldata & 0xff00)>>8)+1; + coldata = (coldata & 0x00ff)>>0; + for (l=0;l=0) + { + m_32x_linerender[x] = m_32x_palette[(coldata)]; + } + x++; + } + + lineoffs++; + + } + } + else // MODE 2 - 15bpp mode, not used by any commercial games? + { + uint32_t lineoffs; + int start; + + lineoffs = m_32x_display_dram[scanline]; + + if (m_32x_screenshift == 0) start=0; + else start = -1; + + x = start; + while (x<320) + { + if (x>=0) + m_32x_linerender[x] = m_32x_display_dram[lineoffs&0xffff]; + + x++; + lineoffs++; + } + } + } +} + +void sega_32x_device::render_videobuffer_to_screenbuffer(int x, uint32_t priority, uint32_t &lineptr) +{ + if (m_32x_displaymode != 0) + { + if (!m_32x_videopriority) + { + if (priority && !(m_32x_linerender[x] & 0x8000)) + lineptr = pen(m_32x_linerender[x] & 0x7fff); + if (m_32x_linerender[x] & 0x8000) + lineptr = pen(m_32x_linerender[x] & 0x7fff); + } + else + { + if (priority && m_32x_linerender[x] & 0x8000) + lineptr = pen(m_32x_linerender[x] & 0x7fff); + if (!(m_32x_linerender[x] & 0x8000)) + lineptr = pen(m_32x_linerender[x] & 0x7fff); + } + } +} + +#if 0 +// for now we just use the regular loading because we have 2 different BIOS roms, and you can't use -bios within a device for obvious reasons +ROM_START( 32x ) + ROM_REGION( 0x400000, "32x_master_sh2", 0 ) + ROM_REGION( 0x400000, "32x_slave_sh2", 0 ) +ROM_END + +const rom_entry *sega_32x_device::device_rom_region() const +{ + return ROM_NAME( 32x ); +} +#endif + + +// brutal needs high levels of interleave or the background animations don't work +// and some stages simply freeze the game, the is not good for performance however. +// +// some games appear to dislike 'perfect' levels of interleave, probably due to +// non-emulated cache, ram waitstates and other issues? +#define _32X_INTERLEAVE_LEVEL \ + config.set_maximum_quantum(attotime::from_hz(1800000)); + +void sega_32x_device::device_add_mconfig(machine_config &config) +{ +#ifndef _32X_SWAP_MASTER_SLAVE_HACK + SH2(config, m_master_cpu, DERIVED_CLOCK(1, 1)); + m_master_cpu->set_is_slave(0); + m_master_cpu->set_dma_fifo_data_available_callback(FUNC(sega_32x_device::_32x_fifo_available_callback)); +#endif + + SH2(config, m_slave_cpu, DERIVED_CLOCK(1, 1)); + m_slave_cpu->set_is_slave(1); + m_slave_cpu->set_dma_fifo_data_available_callback(FUNC(sega_32x_device::_32x_fifo_available_callback)); + +#ifdef _32X_SWAP_MASTER_SLAVE_HACK + SH2(config, m_master_cpu, DERIVED_CLOCK(1, 1)); + m_master_cpu->set_is_slave(0); + m_master_cpu->set_dma_fifo_data_available_callback(FUNC(sega_32x_device::_32x_fifo_available_callback)); +#endif + + _32X_INTERLEAVE_LEVEL +} + +void sega_32x_ntsc_device::device_add_mconfig(machine_config &config) +{ + sega_32x_device::device_add_mconfig(config); + + m_master_cpu->set_addrmap(AS_PROGRAM, &sega_32x_ntsc_device::sh2_main_map); + m_slave_cpu->set_addrmap(AS_PROGRAM, &sega_32x_ntsc_device::sh2_slave_map); + + DAC_12BIT_R2R(config, m_ldac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 0); // unknown DAC + DAC_12BIT_R2R(config, m_rdac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 1); // unknown DAC +} + +void sega_32x_pal_device::device_add_mconfig(machine_config &config) +{ + sega_32x_device::device_add_mconfig(config); + + m_master_cpu->set_addrmap(AS_PROGRAM, &sega_32x_pal_device::sh2_main_map); + m_slave_cpu->set_addrmap(AS_PROGRAM, &sega_32x_pal_device::sh2_slave_map); + + DAC_16BIT_R2R(config, m_ldac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 0); // unknown DAC + DAC_16BIT_R2R(config, m_rdac, 0).add_route(ALL_OUTPUTS, *this, 0.4, 1); // unknown DAC +} + + +void sega_32x_device::device_start() +{ + for (int i = 0; i < 32*32*32/**2*/; i++) + { + int r = (i >> 0) & 0x1f; + int g = (i >> 5) & 0x1f; + int b = (i >> 10) & 0x1f; + //int p = (i >> 15) & 0x01; // priority 'through' bit + set_pen_color(i, pal5bit(r), pal5bit(g), pal5bit(b)); + } + + m_stream = stream_alloc(2, 2, 48000 * 4); + m_32x_pwm_timer = timer_alloc(FUNC(sega_32x_device::handle_pwm_callback), this); + + m_32x_dram0 = std::make_unique(0x40000/2); + m_32x_dram1 = std::make_unique(0x40000/2); + + memset(m_32x_dram0.get(), 0x00, 0x40000); + memset(m_32x_dram1.get(), 0x00, 0x40000); + + m_32x_palette = std::make_unique(0x200/2); + + memset(m_32x_palette.get(), 0x00, 0x200); + + m_32x_display_dram = m_32x_dram0.get(); + m_32x_access_dram = m_32x_dram1.get(); +} + +void sega_32x_device::device_reset() +{ + /* Interrupts are masked / disabled at first */ + m_sh2_master_vint_enable = m_sh2_slave_vint_enable = 0; + m_sh2_master_hint_enable = m_sh2_slave_hint_enable = 0; + m_sh2_master_cmdint_enable = m_sh2_slave_cmdint_enable = 0; + sh2_master_pwmint_enable = sh2_slave_pwmint_enable = 0; + m_sh2_master_vint_pending = m_sh2_slave_vint_pending = 0; + m_sh2_hint_in_vbl = 0; + + // start in a reset state + m_sh2_are_running = 0; + + m_32x_a1518a_reg = 0x00; // initial value + m_32x_68k_a15104_reg = 0x00; + + m_32x_autofill_length = 0; + m_32x_autofill_address = 0; + m_32x_autofill_data = 0; + m_32x_screenshift = 0; + m_32x_videopriority = 0; // MD priority + m_32x_displaymode = 0; + m_32x_240mode = 0; + + m_current_fifo_block = m_fifo_block_a; + m_current_fifo_readblock = m_fifo_block_b; + m_current_fifo_write_pos = 0; + m_current_fifo_read_pos = 0; + m_fifo_block_a_full = 0; + m_fifo_block_b_full = 0; + + m_32x_hcount_compare_val = -1; + m_32x_hcount_reg = 0; + + m_32x_fb_swap = 0; + + m_pwm_tm_reg = 0; + m_pwm_cycle = m_pwm_cycle_reg = 0; + m_pwm_ctrl = 0; + calculate_pwm_timer(); + + m_lch_size = 0; + m_rch_size = 0; + + m_total_scanlines = 262; + +// moved from init + + m_32x_adapter_enabled = 0; + m_32x_access_auth = 0; + + if (m_32x_adapter_enabled == 0) + { + m_main_cpu->space(AS_PROGRAM).install_rom(0x0000000, 0x03fffff, machine().root_device().memregion(":gamecart")->base()); + m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0x000070, 0x000073, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_hint_vector_w))); // h interrupt vector + }; + + + m_a15100_reg = 0x0000; + m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15100, 0xa15101, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15100_r))); // framebuffer control regs + m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15100, 0xa15101, write16_delegate(*this, FUNC(sega_32x_device::m68k_a15100_w))); // framebuffer control regs + m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15102, 0xa15103, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15102_r))); // send irq to sh2 + m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15102, 0xa15103, write16s_delegate(*this, FUNC(sega_32x_device::m68k_a15102_w))); // send irq to sh2 + m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15104, 0xa15105, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15104_r))); // 68k BANK rom set + m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15104, 0xa15105, write16s_delegate(*this, FUNC(sega_32x_device::m68k_a15104_w))); // 68k BANK rom set + m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15106, 0xa15107, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a15106_r))); // dreq stuff + m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15106, 0xa15107, write16_delegate(*this, FUNC(sega_32x_device::m68k_a15106_w))); // dreq stuff + m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0xa15108, 0xa15113, read16m_delegate(*this, FUNC(sega_32x_device::dreq_common_r)), write16m_delegate(*this, FUNC(sega_32x_device::dreq_common_w))); // dreq src / dst / length /fifo + + m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0xa1511a, 0xa1511b, read16smo_delegate(*this, FUNC(sega_32x_device::m68k_a1511a_r)), write16smo_delegate(*this, FUNC(sega_32x_device::m68k_a1511a_w))); // SEGA TV + + m_main_cpu->space(AS_PROGRAM).install_read_handler(0xa15120, 0xa1512f, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_m_commsram_r))); // comms reg 0-7 + m_main_cpu->space(AS_PROGRAM).install_write_handler(0xa15120, 0xa1512f, write16s_delegate(*this, FUNC(sega_32x_device::m68k_m_commsram_w))); // comms reg 0-7 + m_main_cpu->space(AS_PROGRAM).install_readwrite_handler(0xa15130, 0xa1513f, read16sm_delegate(*this, FUNC(sega_32x_device::pwm_r)), write16sm_delegate(*this, FUNC(sega_32x_device::m68k_pwm_w))); + + m_main_cpu->space(AS_PROGRAM).install_read_handler(0x0a130ec, 0x0a130ef, read16sm_delegate(*this, FUNC(sega_32x_device::m68k_MARS_r))); // system ID + + + +// checking if these help brutal, they don't. + m_master_cpu->sh2drc_set_options(SH2DRC_COMPATIBLE_OPTIONS); + m_slave_cpu->sh2drc_set_options(SH2DRC_COMPATIBLE_OPTIONS); + + uint32_t *cart = (uint32_t *)memregion(":gamecart_sh2")->base(); + + m_master_cpu->sh2drc_add_fastram(0x06000000, 0x0603ffff, 0, &m_sh2_shared[0]); + m_master_cpu->sh2drc_add_fastram(0x02000000, 0x023fffff, 0, cart); + m_master_cpu->sh2drc_add_fastram(0x22000000, 0x223fffff, 0, cart); + m_slave_cpu->sh2drc_add_fastram(0x06000000, 0x0603ffff, 0, &m_sh2_shared[0]); + m_slave_cpu->sh2drc_add_fastram(0x02000000, 0x023fffff, 0, cart); + m_slave_cpu->sh2drc_add_fastram(0x22000000, 0x223fffff, 0, cart); + + +// install these now, otherwise we'll get the following (incorrect) warnings on startup.. +// SH-2 device ':sega32x:32x_slave_sh2': program space memory map entry 0-3FFF references non-existent region ':slave' +// SH-2 device ':sega32x:32x_master_sh2': program space memory map entry 0-3FFF references non-existent region ':master' + uint8_t* masterbios = (uint8_t*)machine().root_device().memregion(":master")->base(); + uint8_t* slavebios = (uint8_t*)machine().root_device().memregion(":slave")->base(); + membank("masterbios")->configure_entries(0, 1, masterbios, 0x4000); + membank("slavebios")->configure_entries(0, 1, slavebios, 0x4000); + membank("masterbios")->set_entry(0); + membank("slavebios")->set_entry(0); +} + +// if the system has a 32x, the extra CPUs are paused at start +void sega_32x_device::pause_cpu() +{ + m_master_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_slave_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); +} diff --git a/src/mame/shared/mega32x.h b/src/mame/shared/mega32x.h new file mode 100644 index 00000000000..5d07d35df4d --- /dev/null +++ b/src/mame/shared/mega32x.h @@ -0,0 +1,242 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 32X */ +#ifndef MAME_MACHINE_MEGA32X_H +#define MAME_MACHINE_MEGA32X_H + +#pragma once + +#include "cpu/m68000/m68000.h" +#include "cpu/sh/sh2.h" +#include "cpu/sh/sh2comn.h" +#include "machine/timer.h" +#include "sound/dac.h" +#include "emupal.h" +#include "screen.h" + +class sega_32x_device : public device_t, public device_palette_interface, public device_sound_interface, public device_video_interface +{ +public: + void pause_cpu(); + + // set some variables at start, depending on region (shall be moved to a device interface?) + void set_framerate(int rate) { m_framerate = rate; } + void set_32x_pal(bool pal) { m_32x_pal = pal ? 1 : 0; } + void set_total_scanlines(int total) { m_base_total_scanlines = total; } // this get set at start only + double get_framerate() { return has_screen() ? screen().frame_period().as_hz() : double(m_framerate); } + + void screen_eof(bool mode3) + { + m_32x_vblank_flag = 0; + m_32x_hcount_compare_val = -1; + update_total_scanlines(mode3); + } + + uint16_t m68k_palette_r(offs_t offset); + void m68k_palette_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t m68k_dram_r(offs_t offset); + void m68k_dram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t m68k_dram_overwrite_r(offs_t offset); + void m68k_dram_overwrite_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t m68k_a15106_r(); + void m68k_a15106_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t dreq_common_r(address_space &space, offs_t offset); + void dreq_common_w(address_space &space, offs_t offset, uint16_t data); + uint16_t m68k_a1511a_r(); + void m68k_a1511a_w(uint16_t data); + uint16_t m68k_m_hint_vector_r(offs_t offset); + void m68k_m_hint_vector_w(offs_t offset, uint16_t data); + uint16_t m68k_MARS_r(offs_t offset); + uint16_t m68k_a15100_r(); + void m68k_a15100_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t m68k_a15102_r(); + void m68k_a15102_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t m68k_a15104_r(); + void m68k_a15104_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t m68k_m_commsram_r(offs_t offset); + void m68k_m_commsram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t pwm_r(offs_t offset); + void pwm_w(offs_t offset, uint16_t data); + void m68k_pwm_w(offs_t offset, uint16_t data); + uint16_t common_vdp_regs_r(offs_t offset); + void common_vdp_regs_w(address_space &space, offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t master_4000_r(); + void master_4000_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t slave_4000_r(); + void slave_4000_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t common_4002_r(); + void common_4002_w(uint16_t data); + uint16_t common_4004_r(); + void common_4004_w(uint16_t data); + uint16_t common_4006_r(); + void common_4006_w(uint16_t data); + void master_4014_w(uint16_t data); + void slave_4014_w(uint16_t data); + void master_4016_w(uint16_t data); + void slave_4016_w(uint16_t data); + void master_4018_w(uint16_t data); + void slave_4018_w(uint16_t data); + void master_401a_w(uint16_t data); + void slave_401a_w(uint16_t data); + void master_401c_w(uint16_t data); + void slave_401c_w(uint16_t data); + void master_401e_w(uint16_t data); + void slave_401e_w(uint16_t data); + + SH2_DMA_FIFO_DATA_AVAILABLE_CB(_32x_fifo_available_callback); + + void render_videobuffer_to_screenbuffer_helper(int scanline); + void render_videobuffer_to_screenbuffer(int x, uint32_t priority, uint32_t &lineptr); + int sh2_master_pwmint_enable = 0, sh2_slave_pwmint_enable = 0; + + void check_framebuffer_swap(bool enabled); + void check_irqs(); + void interrupt_cb(int scanline, int irq6); + + void sh2_main_map(address_map &map); + void sh2_slave_map(address_map &map); + void sh2_common_map(address_map &map); + +protected: + sega_32x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + required_shared_ptr m_sh2_shared; + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + // device_palette_interface overrides + virtual uint32_t palette_entries() const override { return 32*32*32/**2*/; } + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + + void update_total_scanlines(bool mode3) { m_total_scanlines = mode3 ? (m_base_total_scanlines * 2) : m_base_total_scanlines; } // this gets set at each EOF + + /* our main vblank handler resets this */ + required_device m_main_cpu; + required_device m_master_cpu; + required_device m_slave_cpu; + required_device m_ldac; + required_device m_rdac; + required_device m_scan_timer; + memory_bank_creator m_rombank; + + int m_32x_hcount_compare_val = 0; + int m_32x_vblank_flag = 0; + int m_sh2_are_running = 0; + int m_32x_240mode = 0; + uint16_t m_32x_a1518a_reg = 0; + + sound_stream *m_stream = nullptr; + TIMER_CALLBACK_MEMBER(handle_pwm_callback); + void calculate_pwm_timer(); + uint16_t m_pwm_ctrl = 0, m_pwm_cycle = 0, m_pwm_tm_reg = 0; + static constexpr int PWM_FIFO_SIZE = 3; + uint16_t m_cur_lch[PWM_FIFO_SIZE]{},m_cur_rch[PWM_FIFO_SIZE]{}; + uint16_t m_pwm_cycle_reg = 0; //used for latching + uint8_t m_pwm_timer_tick = 0; + uint8_t m_lch_size = 0, m_rch_size = 0; + uint16_t m_lch_fifo_state = 0, m_rch_fifo_state = 0; + + void lch_pop(); + void rch_pop(); + + uint16_t get_hposition(void); + + emu_timer *m_32x_pwm_timer = nullptr; + +private: + + int m_32x_displaymode = 0; + int m_32x_videopriority = 0; + uint32_t m_32x_linerender[320+258]{}; // tmp buffer (bigger than it needs to be to simplify RLE decode) + + int m_32x_adapter_enabled = 0; + int m_32x_access_auth = 0; + int m_32x_screenshift = 0; + + uint16_t m_32x_68k_a15104_reg = 0; + int m_sh2_master_vint_enable = 0, m_sh2_slave_vint_enable = 0; + int m_sh2_master_hint_enable = 0, m_sh2_slave_hint_enable = 0; + int m_sh2_master_cmdint_enable = 0, m_sh2_slave_cmdint_enable = 0; + int m_sh2_hint_in_vbl = 0; + int m_sh2_master_vint_pending = 0; + int m_sh2_slave_vint_pending = 0; + int m_32x_fb_swap = 0; + int m_32x_hcount_reg = 0; + + uint16_t m_32x_autofill_length = 0; + uint16_t m_32x_autofill_address = 0; + uint16_t m_32x_autofill_data = 0; + uint16_t m_a15106_reg = 0; + uint16_t m_dreq_src_addr[2]{}, m_dreq_dst_addr[2]{}, m_dreq_size = 0; + uint8_t m_sega_tv = 0; + uint16_t m_hint_vector[2]{}; + uint16_t m_a15100_reg = 0; + int m_32x_68k_a15102_reg = 0; + + int m_32x_pal = 0; + int m_framerate = 0; + int m_base_total_scanlines = 0; + int m_total_scanlines = 0; + + uint16_t m_commsram[8]{}; + + std::unique_ptr m_32x_dram0; + std::unique_ptr m_32x_dram1; + uint16_t *m_32x_display_dram = nullptr, *m_32x_access_dram = nullptr; + std::unique_ptr m_32x_palette; + + uint16_t m_fifo_block_a[4]{}; + uint16_t m_fifo_block_b[4]{}; + uint16_t* m_current_fifo_block = nullptr; + uint16_t* m_current_fifo_readblock = nullptr; + int m_current_fifo_write_pos = 0; + int m_current_fifo_read_pos = 0; + int m_fifo_block_a_full = 0; + int m_fifo_block_b_full = 0; +}; + + +class sega_32x_ntsc_device : public sega_32x_device +{ +public: + template + sega_32x_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&main_cpu_tag, U &&timer_tag) + : sega_32x_ntsc_device(mconfig, tag, owner, clock) + { + m_main_cpu.set_tag(std::forward(main_cpu_tag)); + m_scan_timer.set_tag(std::forward(timer_tag)); + } + + sega_32x_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override; + +}; + +class sega_32x_pal_device : public sega_32x_device +{ +public: + template + sega_32x_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&main_cpu_tag, U &&timer_tag) + : sega_32x_pal_device(mconfig, tag, owner, clock) + { + m_main_cpu.set_tag(std::forward(main_cpu_tag)); + m_scan_timer.set_tag(std::forward(timer_tag)); + } + + sega_32x_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override; +}; + + +DECLARE_DEVICE_TYPE(SEGA_32X_NTSC, sega_32x_ntsc_device) +DECLARE_DEVICE_TYPE(SEGA_32X_PAL, sega_32x_pal_device) + +#endif // MAME_MACHINE_MEGA32X_H diff --git a/src/mame/shared/megacdcd.cpp b/src/mame/shared/megacdcd.cpp new file mode 100644 index 00000000000..22759b96a3a --- /dev/null +++ b/src/mame/shared/megacdcd.cpp @@ -0,0 +1,1409 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* CD controller code from megacd.c, used by Sega CD / Mega CD */ + +/* todo: cleanup(!!), make more generic, unifiy implementation with NeoCD, turn into a device and move to the proper lc89510.c file + currently this is a bit of a mix of system specific bits, incomplete implementations etc. as well as a rather kludgy combination + of the CDC and drive emulation. */ + + +#include "emu.h" +#include "megacdcd.h" + +#define READ_MAIN (0x0200) +#define READ_SUB (0x0300) + +#define REG_W_SBOUT (0x0) +#define REG_W_IFCTRL (0x1) +#define REG_W_DBCL (0x2) +#define REG_W_DBCH (0x3) +#define REG_W_DACL (0x4) +#define REG_W_DACH (0x5) +#define REG_W_DTTRG (0x6) +#define REG_W_DTACK (0x7) +#define REG_W_WAL (0x8) +#define REG_W_WAH (0x9) +#define REG_W_CTRL0 (0xA) +#define REG_W_CTRL1 (0xB) +#define REG_W_PTL (0xC) +#define REG_W_PTH (0xD) +#define REG_W_CTRL2 (0xE) +#define REG_W_RESET (0xF) + +#define REG_R_COMIN (0x0) +#define REG_R_IFSTAT (0x1) +#define REG_R_DBCL (0x2) +#define REG_R_DBCH (0x3) +#define REG_R_HEAD0 (0x4) +#define REG_R_HEAD1 (0x5) +#define REG_R_HEAD2 (0x6) +#define REG_R_HEAD3 (0x7) +#define REG_R_PTL (0x8) +#define REG_R_PTH (0x9) +#define REG_R_WAL (0xa) +#define REG_R_WAH (0xb) +#define REG_R_STAT0 (0xc) +#define REG_R_STAT1 (0xd) +#define REG_R_STAT2 (0xe) +#define REG_R_STAT3 (0xf) + +#define CMD_STATUS (0x0) +#define CMD_STOPALL (0x1) +#define CMD_GETTOC (0x2) +#define CMD_READ (0x3) +#define CMD_SEEK (0x4) +// (0x5) +#define CMD_STOP (0x6) +#define CMD_RESUME (0x7) +#define CMD_FF (0x8) +#define CMD_RW (0x9) +#define CMD_INIT (0xa) +// (0xb) +#define CMD_CLOSE (0xc) +#define CMD_OPEN (0xd) +// (0xe) +// (0xf) + + +#define TOCCMD_CURPOS (0x0) +#define TOCCMD_TRKPOS (0x1) +#define TOCCMD_CURTRK (0x2) +#define TOCCMD_LENGTH (0x3) +#define TOCCMD_FIRSTLAST (0x4) +#define TOCCMD_TRACKADDR (0x5) + + + + +#define SET_CDD_DATA_MODE \ + CDD_CONTROL |= 0x0100; +#define SET_CDD_AUDIO_MODE \ + CDD_CONTROL &= ~0x0100; +#define STOP_CDC_READ \ + SCD_STATUS_CDC &= ~0x01; +#define SET_CDC_READ \ + SCD_STATUS_CDC |= 0x01; +#define SET_CDC_DMA \ + SCD_STATUS_CDC |= 0x08; +#define STOP_CDC_DMA \ + SCD_STATUS_CDC &= ~0x08; +#define SCD_READ_ENABLED \ + (SCD_STATUS_CDC & 1) + +#define SCD_DMA_ENABLED \ + (SCD_STATUS_CDC & 0x08) + +#define CLEAR_CDD_RESULT \ + CDD_MIN = CDD_SEC = CDD_FRAME = CDD_EXT = 0; +#define CHECK_SCD_LV5_INTERRUPT \ + if (segacd_irq_mask & 0x20) \ + { \ + m_68k->set_input_line(5, HOLD_LINE); \ + } +#define CHECK_SCD_LV4_INTERRUPT \ + if (segacd_irq_mask & 0x10) \ + { \ + m_68k->set_input_line(4, HOLD_LINE); \ + } +#define CHECK_SCD_LV4_INTERRUPT_A \ + if (segacd_irq_mask & 0x10) \ + { \ + m_68k->set_input_line(4, HOLD_LINE); \ + } + + +#define CURRENT_TRACK_IS_DATA \ + (segacd.toc->tracks[SCD_CURTRK - 1].trktype != cdrom_file::CD_TRACK_AUDIO) + +#define CDD_PLAYINGCDDA 0x0100 +#define CDD_READY 0x0400 +#define CDD_STOPPED 0x0900 + + +/* neocd */ + +#define CD_FRAMES_MINUTE (60 * 75) +#define CD_FRAMES_SECOND ( 75) +#define CD_FRAMES_PREGAP ( 2 * 75) + +#define SEK_IRQSTATUS_NONE (0x0000) +#define SEK_IRQSTATUS_AUTO (0x2000) +#define SEK_IRQSTATUS_ACK (0x1000) + + +DEFINE_DEVICE_TYPE(LC89510_TEMP, lc89510_temp_device, "lc89510_temp", "lc89510_temp_device") + +lc89510_temp_device::lc89510_temp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, LC89510_TEMP, tag, owner, clock) + , m_segacd_dma_callback(*this, FUNC(lc89510_temp_device::Fake_CDC_Do_DMA)) + , m_type1_interrupt_callback(*this, FUNC(lc89510_temp_device::dummy_interrupt_callback)) + , m_type2_interrupt_callback(*this, FUNC(lc89510_temp_device::dummy_interrupt_callback)) + , m_type3_interrupt_callback(*this, FUNC(lc89510_temp_device::dummy_interrupt_callback)) + , m_cdrom(*this, finder_base::DUMMY_TAG) + , m_cdda(*this, "cdda") + , m_68k(*this, finder_base::DUMMY_TAG) +{ + is_neoCD = false; + + nff0002 = 0; + for (auto & elem : CDD_TX) + elem = 0; + for (auto & elem : CDD_RX) + elem = 0; + NeoCDCommsWordCount = 0; + NeoCD_StatusHack = 0; + SCD_CURLBA = 0; + + CDC_REG0 = 0; + + segacd_irq_mask = 0; +} + +void lc89510_temp_device::dummy_interrupt_callback() +{ +} + +// HACK for DMA handling, this gets replaced +void lc89510_temp_device::Fake_CDC_Do_DMA(int &dmacount, uint8_t *CDC_BUFFER, uint16_t &dma_addrc, uint16_t &destination ) +{ + fatalerror("Fake_CDC_Do_DMA\n"); +} + +void lc89510_temp_device::device_start() +{ + m_segacd_dma_callback.resolve(); + m_type1_interrupt_callback.resolve(); + m_type2_interrupt_callback.resolve(); + m_type3_interrupt_callback.resolve(); +} + +void lc89510_temp_device::device_reset() +{ + m_cdda->stop_audio(); +} + + +inline int lc89510_temp_device::to_bcd(int val, bool byte) +{ + if (val > 99) val = 99; + + if (byte) return (((val) / 10) << 4) + ((val) % 10); + else return (((val) / 10) << 8) + ((val) % 10); +} + + + +void lc89510_temp_device::set_data_audio_mode(void) +{ + if (CURRENT_TRACK_IS_DATA) + { + SET_CDD_DATA_MODE + } + else + { + SET_CDD_AUDIO_MODE + //fatalerror("CDDA unsupported\n"); + } +} + +void lc89510_temp_device::CDD_DoChecksum(void) +{ + int checksum = + CDD_RX[0] + + CDD_RX[1] + + CDD_RX[2] + + CDD_RX[3] + + CDD_RX[4] + + CDD_RX[5] + + CDD_RX[6] + + CDD_RX[7] + + CDD_RX[8]; + + if (is_neoCD) checksum += 0x5; // why?? + checksum &= 0xf; + checksum ^= 0xf; + + CDD_RX[9] = checksum; +} + +bool lc89510_temp_device::CDD_Check_TX_Checksum(void) +{ + int checksum = + CDD_TX[0] + + CDD_TX[1] + + CDD_TX[2] + + CDD_TX[3] + + CDD_TX[4] + + CDD_TX[5] + + CDD_TX[6] + + CDD_TX[7] + + CDD_TX[8]; + + if (is_neoCD) checksum += 0x5; // why?? + checksum &= 0xf; + checksum ^= 0xf; + + if (CDD_TX[9] == checksum) + return true; + + return false; +} + +// converts our 16-bit working regs to 8-bit regs and checksums them +void lc89510_temp_device::CDD_Export(bool neocd_hack) +{ + if (!neocd_hack) + CDD_RX[0] = (CDD_STATUS & 0xff00)>>8; + else + { + // printf("was %02x returning %02x\n", (CDD_STATUS & 0xff00)>>8, NeoCD_StatusHack); + CDD_RX[0] = NeoCD_StatusHack; + } + + CDD_RX[1] = (CDD_STATUS & 0x00ff)>>0; + CDD_RX[2] = (CDD_MIN & 0xff00)>>8; + CDD_RX[3] = (CDD_MIN & 0x00ff)>>0; + CDD_RX[4] = (CDD_SEC & 0xff00)>>8; + CDD_RX[5] = (CDD_SEC & 0x00ff)>>0; + CDD_RX[6] = (CDD_FRAME & 0xff00)>>8; + CDD_RX[7] = (CDD_FRAME & 0x00ff)>>0; + CDD_RX[8] = (CDD_EXT & 0x00ff)>>0; + /* 9 = checksum */ + + CDD_DoChecksum(); + + CDD_CONTROL &= ~4; // Clear HOCK bit + +} + + + + + + +void lc89510_temp_device::CDD_GetStatus(void) +{ + uint16_t s = (CDD_STATUS & 0x0f00); + + if ((s == 0x0200) || (s == 0x0700) || (s == 0x0e00)) + CDD_STATUS = (SCD_STATUS & 0xff00) | (CDD_STATUS & 0x00ff); +} + + +void lc89510_temp_device::CDD_Stop() +{ + CLEAR_CDD_RESULT + STOP_CDC_READ + SCD_STATUS = CDD_STOPPED; + CDD_STATUS = 0x0000; + SET_CDD_DATA_MODE + m_cdda->stop_audio(); //stop any pending CD-DA + + //neocd + NeoCD_StatusHack = 0x0E; + + +} + + +void lc89510_temp_device::CDD_GetPos(void) +{ + CLEAR_CDD_RESULT + uint32_t msf; + CDD_STATUS &= 0xFF; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + CDD_STATUS |= SCD_STATUS; + msf = cdrom_file::lba_to_msf_alt(SCD_CURLBA+150); + CDD_MIN = to_bcd(((msf & 0x00ff0000)>>16),false); + CDD_SEC = to_bcd(((msf & 0x0000ff00)>>8),false); + CDD_FRAME = to_bcd(((msf & 0x000000ff)>>0),false); +} + +void lc89510_temp_device::CDD_GetTrackPos(void) +{ + CLEAR_CDD_RESULT + int elapsedlba; + uint32_t msf; + CDD_STATUS &= 0xFF; + // uint32_t end_msf = ; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + CDD_STATUS |= SCD_STATUS; + elapsedlba = SCD_CURLBA - segacd.toc->tracks[ segacd.cd->get_track(SCD_CURLBA) ].logframeofs; + msf = cdrom_file::lba_to_msf_alt (elapsedlba); + //popmessage("%08x %08x",SCD_CURLBA,segacd.toc->tracks[ cdrom_get_track(segacd.cd, SCD_CURLBA) + 1 ].logframeofs); + CDD_MIN = to_bcd(((msf & 0x00ff0000)>>16),false); + CDD_SEC = to_bcd(((msf & 0x0000ff00)>>8),false); + CDD_FRAME = to_bcd(((msf & 0x000000ff)>>0),false); +} + +void lc89510_temp_device::CDD_GetTrack(void) +{ + CLEAR_CDD_RESULT + CDD_STATUS &= 0xFF; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + CDD_STATUS |= SCD_STATUS; + SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; + CDD_MIN = to_bcd(SCD_CURTRK, false); +} + +void lc89510_temp_device::CDD_Length(void) +{ + CLEAR_CDD_RESULT + CDD_STATUS &= 0xFF; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + CDD_STATUS |= SCD_STATUS; + + uint32_t startlba = (segacd.toc->tracks[segacd.cd->get_last_track()].logframeofs); + uint32_t startmsf = cdrom_file::lba_to_msf_alt( startlba ); + + CDD_MIN = to_bcd((startmsf&0x00ff0000)>>16,false); + CDD_SEC = to_bcd((startmsf&0x0000ff00)>>8,false); + CDD_FRAME = to_bcd((startmsf&0x000000ff)>>0,false); +} + + +void lc89510_temp_device::CDD_FirstLast(void) +{ + CLEAR_CDD_RESULT + CDD_STATUS &= 0xFF; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + CDD_STATUS |= SCD_STATUS; + CDD_MIN = 1; // first + CDD_SEC = to_bcd(segacd.cd->get_last_track(),false); // last +} + +void lc89510_temp_device::CDD_GetTrackAdr(void) +{ + CLEAR_CDD_RESULT + + CDD_STATUS &= 0xFF; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + + int track = (CDD_TX[5] & 0xF) + (CDD_TX[4] & 0xF) * 10; + int last_track = segacd.cd->get_last_track(); + + CDD_STATUS |= SCD_STATUS; + + if (track > last_track) + track = last_track; + + if (track < 1) + track = 1; + + uint32_t startlba = (segacd.toc->tracks[track-1].logframeofs); + uint32_t startmsf = cdrom_file::lba_to_msf_alt( startlba+150 ); + + CDD_MIN = to_bcd((startmsf&0x00ff0000)>>16,false); + CDD_SEC = to_bcd((startmsf&0x0000ff00)>>8,false); + CDD_FRAME = to_bcd((startmsf&0x000000ff)>>0,false); + CDD_EXT = track % 10; + + if (segacd.toc->tracks[track - 1].trktype != cdrom_file::CD_TRACK_AUDIO) + CDD_FRAME |= 0x0800; +} + +// verify what this is.. the NeoCd emu code only checked the track type but +// checked it where we put CDD_EXT, not CDD_FRAME (RX[7] vs RX[8] in Export) +void lc89510_temp_device::CDD_GetTrackType(void) +{ + CLEAR_CDD_RESULT + + CDD_STATUS &= 0xFF; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + + int track = (CDD_TX[5] & 0xF) + (CDD_TX[4] & 0xF) * 10; + int last_track = segacd.cd->get_last_track(); + + CDD_STATUS |= SCD_STATUS; + + if (track > last_track) + track = last_track; + + if (track < 1) + track = 1; + + if (segacd.toc->tracks[track - 1].trktype != cdrom_file::CD_TRACK_AUDIO) + { + CDD_EXT = 0x08; + CDD_FRAME |= 0x0800; + } + + + +} + +uint32_t lc89510_temp_device::getmsf_from_regs(void) +{ + uint32_t msf = 0; + + msf = ((CDD_TX[3] & 0xF) + (CDD_TX[2] & 0xF) * 10) << 16; + msf |= ((CDD_TX[5] & 0xF) + (CDD_TX[4] & 0xF) * 10) << 8; + msf |= ((CDD_TX[7] & 0xF) + (CDD_TX[6] & 0xF) * 10) << 0; + + return msf; +} + +void lc89510_temp_device::CDD_Play() +{ + CLEAR_CDD_RESULT + uint32_t msf = getmsf_from_regs(); + SCD_CURLBA = cdrom_file::msf_to_lba(msf)-150; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + uint32_t track_length = segacd.toc->tracks[ segacd.cd->get_track(SCD_CURLBA) ].logframes; + SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; + LC8951UpdateHeader(); + SCD_STATUS = CDD_PLAYINGCDDA; + CDD_STATUS = 0x0102; + set_data_audio_mode(); + printf("%d Track played\n",SCD_CURTRK); + CDD_MIN = to_bcd(SCD_CURTRK, false); + if(!(CURRENT_TRACK_IS_DATA)) + m_cdda->start_audio(SCD_CURLBA, SCD_CURLBA + track_length); + SET_CDC_READ + + + NeoCD_StatusHack = 1; + +} + + +void lc89510_temp_device::CDD_Seek(void) +{ + CLEAR_CDD_RESULT + uint32_t msf = getmsf_from_regs(); + SCD_CURLBA = cdrom_file::msf_to_lba(msf)-150; + if(segacd.cd == nullptr) // no CD is there, bail out + return; + SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; + LC8951UpdateHeader(); + STOP_CDC_READ + SCD_STATUS = CDD_READY; + CDD_STATUS = 0x0200; + set_data_audio_mode(); +} + + +void lc89510_temp_device::CDD_Pause() +{ + CLEAR_CDD_RESULT + STOP_CDC_READ + SCD_STATUS = CDD_READY; + CDD_STATUS = SCD_STATUS; + SET_CDD_DATA_MODE + + //segacd.current_frame = cdda_get_audio_lba( machine.device( "cdda" ) ); + //if(!(CURRENT_TRACK_IS_DATA)) + m_cdda->pause_audio(1); + + + NeoCD_StatusHack = 4; + + +} + +void lc89510_temp_device::CDD_Resume() +{ + CLEAR_CDD_RESULT + STOP_CDC_READ + if(segacd.cd == nullptr) // no CD is there, bail out + return; + SCD_CURTRK = segacd.cd->get_track(SCD_CURLBA)+1; + SCD_STATUS = CDD_PLAYINGCDDA; + CDD_STATUS = 0x0102; + set_data_audio_mode(); + CDD_MIN = to_bcd (SCD_CURTRK, false); + SET_CDC_READ + //if(!(CURRENT_TRACK_IS_DATA)) + m_cdda->pause_audio(0); + + NeoCD_StatusHack = 1; +} + + +void lc89510_temp_device::CDD_FF() +{ + fatalerror("Fast Forward unsupported\n"); +} + + +void lc89510_temp_device::CDD_RW() +{ + fatalerror("Fast Rewind unsupported\n"); +} + + +void lc89510_temp_device::CDD_Open(void) +{ + fatalerror("Close Tray unsupported\n"); + /* TODO: re-read CD-ROM buffer here (Mega CD has multi disc games iirc?) */ +} + + +void lc89510_temp_device::CDD_Close(void) +{ + fatalerror("Open Tray unsupported\n"); + /* TODO: clear CD-ROM buffer here */ +} + + +void lc89510_temp_device::CDD_Init(void) +{ + CLEAR_CDD_RESULT + STOP_CDC_READ + SCD_STATUS = CDD_READY; + CDD_STATUS = SCD_STATUS; + CDD_SEC = 1; + CDD_FRAME = 1; +} + + +void lc89510_temp_device::CDD_Default(void) +{ + CLEAR_CDD_RESULT + CDD_STATUS = SCD_STATUS; + + + NeoCD_StatusHack = 9; +} + + +void lc89510_temp_device::CDD_Reset(void) +{ + CLEAR_CDD_RESULT + CDD_CONTROL = CDD_STATUS = 0; + + for (int i = 0; i < 10; i++) + CDD_RX[i] = CDD_TX[i] = 0; + + CDD_DoChecksum(); + + SCD_CURTRK = SCD_CURLBA = 0; + SCD_STATUS = CDD_READY; +} + +void lc89510_temp_device::CDC_Reset(void) +{ + memset(CDC_BUFFER, 0x00, ((16 * 1024 * 2) + SECTOR_SIZE)); + + LC8951RegistersW[REG_W_DACL] = LC8951RegistersW[REG_W_DACH] = LC8951RegistersW[REG_W_DBCL] = LC8951RegistersW[REG_W_DBCH] = LC8951RegistersW[REG_W_PTH] = LC8951RegistersW[REG_W_PTL] = LC8951RegistersW[REG_W_SBOUT] = LC8951RegistersW[REG_W_IFCTRL] = LC8951RegistersW[REG_W_CTRL0] = LC8951RegistersW[REG_W_CTRL1] = + LC8951RegistersW[REG_W_CTRL2] = LC8951RegistersR[REG_R_HEAD1] = LC8951RegistersR[REG_R_HEAD2] = LC8951RegistersR[REG_R_HEAD3] = LC8951RegistersR[REG_R_STAT0] = LC8951RegistersR[REG_R_STAT1] = LC8951RegistersR[REG_R_STAT2] = CDC_DECODE = 0; + + LC8951RegistersR[REG_R_IFSTAT] = 0xFF; + int wa = SECTOR_SIZE * 2; + LC8951RegistersW[REG_W_WAL] = wa & 0xff; LC8951RegistersW[REG_W_WAH] = (wa >> 8) &0xff; + LC8951RegistersR[REG_R_HEAD0] = 0x01; + LC8951RegistersR[REG_R_STAT3] = 0x80; + + LC8951UpdateHeader(); +} + + +void lc89510_temp_device::lc89510_Reset(void) +{ + CDD_Reset(); + CDC_Reset(); + + CDC_REG0 = CDC_REG1 = SCD_STATUS_CDC = CDD_DONE = 0; +} + + +void lc89510_temp_device::CDC_Do_DMA(int rate) +{ + uint32_t length; + + uint16_t destination = CDC_REG0 & 0x0700; + + if (!(SCD_DMA_ENABLED)) + return; + + if ((destination == READ_MAIN) || (destination==READ_SUB)) + { + CDC_REG0 |= 0x4000; + return; + } + + int dma_count_register = LC8951RegistersW[REG_W_DBCL] | (LC8951RegistersW[REG_W_DBCH]<<8); + + if (dma_count_register <= (rate * 2)) + { + length = (dma_count_register + 1) >> 1; + CDC_End_Transfer(); + } + else + length = rate; + + + int dmacount = length; + + uint16_t dma_addrc = LC8951RegistersW[REG_W_DACL] | (LC8951RegistersW[REG_W_DACH]<<8); + + // HACK + m_segacd_dma_callback(dmacount, CDC_BUFFER, dma_addrc, destination ); + + + dma_addrc += length*2; + LC8951RegistersW[REG_W_DACL] = dma_addrc & 0xff; LC8951RegistersW[REG_W_DACH] = (dma_addrc >> 8) & 0xff; + + if (SCD_DMA_ENABLED) + dma_count_register -= length*2; + else + dma_count_register = 0; + + LC8951RegistersW[REG_W_DBCL] = dma_count_register & 0xff; LC8951RegistersW[REG_W_DBCH] = (dma_count_register>>8) & 0xff; + +} + + + + +uint16_t lc89510_temp_device::CDC_Host_r(uint16_t type) +{ + uint16_t destination = CDC_REG0 & 0x0700; + + if (SCD_DMA_ENABLED) + { + if (destination == type) + { + int dma_count_register = LC8951RegistersW[REG_W_DBCL] | (LC8951RegistersW[REG_W_DBCH]<<8); + + dma_count_register -= 2; + + if (dma_count_register <= 0) + { + if (type==READ_SUB) dma_count_register = 0; + + CDC_End_Transfer(); + } + + LC8951RegistersW[REG_W_DBCL] = dma_count_register & 0xff; LC8951RegistersW[REG_W_DBCH] = (dma_count_register>>8) & 0xff; + + uint16_t dma_addrc = LC8951RegistersW[REG_W_DACL] | (LC8951RegistersW[REG_W_DACH]<<8); + + uint16_t data = (CDC_BUFFER[dma_addrc]<<8) | CDC_BUFFER[dma_addrc+1]; + dma_addrc += 2; + + LC8951RegistersW[REG_W_DACL] = dma_addrc & 0xff; LC8951RegistersW[REG_W_DACH] = (dma_addrc >> 8) & 0xff; + + + return data; + } + } + + return 0; +} + + + + +uint8_t lc89510_temp_device::CDC_Reg_r(void) +{ + int reg = CDC_REG0 & 0xF; + uint8_t ret = 0; + + + uint16_t decoderegs = 0x73F2; + + if ((decoderegs>>reg)&1) + CDC_DECODE |= (1 << reg); + + + CDC_REG0 = (CDC_REG0 & 0xFFF0) | ((reg+1)&0xf); + + switch (reg) + { + case REG_R_COMIN: ret = 0/*COMIN*/; break; + case REG_R_IFSTAT: ret = LC8951RegistersR[REG_R_IFSTAT]; break; + case REG_R_DBCL: ret = LC8951RegistersW[REG_W_DBCL]; break; + case REG_R_DBCH: +// LC8951RegistersR[REG_R_DBCH] &= 0x0F; // NeoCD? +// LC8951RegistersR[REG_R_DBCH] |= (LC8951RegistersR[REG_R_IFSTAT] & 0x40) ? 0x00 : 0xF0; // NeoCD? + ret = LC8951RegistersW[REG_W_DBCH]; break; + case REG_R_HEAD0: ret = LC8951RegistersR[REG_R_HEAD0]; break; + case REG_R_HEAD1: ret = LC8951RegistersR[REG_R_HEAD1]; break; + case REG_R_HEAD2: ret = LC8951RegistersR[REG_R_HEAD2]; break; + case REG_R_HEAD3: ret = LC8951RegistersR[REG_R_HEAD3]; break; + case REG_R_PTL: ret = LC8951RegistersW[REG_W_PTL]; break; + case REG_R_PTH: ret = LC8951RegistersW[REG_W_PTH]; break; + case REG_R_WAL: ret = LC8951RegistersW[REG_W_WAL]; break; + case REG_R_WAH: ret = LC8951RegistersW[REG_W_WAH]; break; + case REG_R_STAT0: ret = LC8951RegistersR[REG_R_STAT0]; break; + case REG_R_STAT1: ret = LC8951RegistersR[REG_R_STAT1]; + // LC8951RegistersR[REG_R_IFSTAT] |= 0x20; // NeoCD? // reset DECI + break; + case REG_R_STAT2: ret = LC8951RegistersR[REG_R_STAT2]; break; + case REG_R_STAT3: ret = LC8951RegistersR[REG_R_STAT3]; + + LC8951RegistersR[REG_R_IFSTAT] |= 0x20; // SegaCD? // reset DECI + if (!is_neoCD) + { + if ((LC8951RegistersW[REG_W_CTRL0] & 0x80) && (LC8951RegistersW[REG_W_IFCTRL] & 0x20)) + { + if ((CDC_DECODE & decoderegs) == decoderegs) + LC8951RegistersR[REG_R_STAT3] = 0x80; + } + } + break; + + } + + + return ret; +} + +void lc89510_temp_device::CDC_Reg_w(uint8_t data) +{ + int reg = CDC_REG0 & 0xF; + + int changers0[0x10] = { 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0}; + + if (changers0[reg]) + CDC_REG0 = (CDC_REG0 & 0xFFF0) | (reg+1); + + switch (reg) + { + case REG_W_SBOUT: + LC8951RegistersW[REG_W_SBOUT] = data; + break; + + case REG_W_IFCTRL: + LC8951RegistersW[REG_W_IFCTRL] = data; + + if (!(LC8951RegistersW[REG_W_IFCTRL] & 0x02)) + { + LC8951RegistersW[REG_W_DBCL] = 0; LC8951RegistersW[REG_W_DBCH] = 0; + STOP_CDC_DMA; + LC8951RegistersR[REG_R_IFSTAT] |= 0x08; + } + break; + + case REG_W_DBCL: LC8951RegistersW[REG_W_DBCL] = data; break; + case REG_W_DBCH: LC8951RegistersW[REG_W_DBCH] = data; break; + case REG_W_DACL: LC8951RegistersW[REG_W_DACL] = data; break; + case REG_W_DACH: LC8951RegistersW[REG_W_DACH] = data; break; + + case REG_W_DTTRG: + if (!is_neoCD) + { + if (LC8951RegistersW[REG_W_IFCTRL] & 0x02) + { + LC8951RegistersR[REG_R_IFSTAT] &= ~0x08; + SET_CDC_DMA; + CDC_REG0 &= ~0x8000; + } + } + else + { + LC8951RegistersW[REG_W_DTTRG] = ~0x00; + LC8951RegistersR[REG_R_IFSTAT] &= ~0x08; + } + break; + + case REG_W_DTACK: + //if (!is_neoCD) + { + LC8951RegistersR[REG_R_IFSTAT] |= 0x40; + } + //else + //{ + // LC8951RegistersW[REG_W_DTACK] = ~0x00; + // LC8951RegistersR[REG_R_IFSTAT] &= ~0x40; + //} + break; + case REG_W_WAL: LC8951RegistersW[REG_W_WAL] = data; break; + case REG_W_WAH: LC8951RegistersW[REG_W_WAH] = data; break; + case REG_W_CTRL0: LC8951RegistersW[REG_W_CTRL0] = data; break; + case REG_W_CTRL1: LC8951RegistersW[REG_W_CTRL1] = data; + //LC8951UpdateHeader(); // NeoCD + break; + case REG_W_PTL: LC8951RegistersW[REG_W_PTL] = data; break; + case REG_W_PTH: LC8951RegistersW[REG_W_PTH] = data; break; + case REG_W_CTRL2: LC8951RegistersW[REG_W_CTRL2] = data; break; + case REG_W_RESET: CDC_Reset(); break; + } +} + + + +void lc89510_temp_device::CDD_Process(int reason) +{ + CDD_Export(); + CHECK_SCD_LV4_INTERRUPT +} + +void lc89510_temp_device::CDD_Handle_TOC_Commands(void) +{ + int subcmd = CDD_TX[3]; + CDD_STATUS = (CDD_STATUS & 0xFF00) | subcmd; + + switch (subcmd) + { + case TOCCMD_CURPOS: CDD_GetPos(); break; + case TOCCMD_TRKPOS: CDD_GetTrackPos(); break; + case TOCCMD_CURTRK: CDD_GetTrack(); break; + case TOCCMD_LENGTH: CDD_Length(); break; + case TOCCMD_FIRSTLAST: CDD_FirstLast(); break; + case TOCCMD_TRACKADDR: CDD_GetTrackAdr(); break; + case 6: CDD_GetTrackType(); break; // NGCD, might be wrong, make sure Sega CD doesn't hate it + default: CDD_GetStatus(); break; + } +} + +static const char *const CDD_import_cmdnames[] = +{ + "Get Status", // 0 + "Stop ALL", // 1 + "Handle TOC", // 2 + "Play", // 3 + "Seek", // 4 + " (5)", // 5 + "Pause", // 6 + "Resume", // 7 + "FF", // 8 + "RWD", // 9 + "INIT", // A + " (b)", // B + "Close Tray", // C + "Open Tray", // D + " (e)", // E + " (f)" // F +}; + +bool lc89510_temp_device::CDD_Import() +{ + // don't execute the command if the checksum isn't valid + if (!CDD_Check_TX_Checksum()) + { + printf("invalid checksum\n"); + return false; + } + + if(CDD_TX[0] != 2 && CDD_TX[0] != 0) + printf("%s\n",CDD_import_cmdnames[CDD_TX[0]]); + + switch (CDD_TX[0]) + { + case CMD_STATUS: CDD_GetStatus(); break; + case CMD_STOPALL: CDD_Stop(); break; + case CMD_GETTOC: CDD_Handle_TOC_Commands(); break; + case CMD_READ: CDD_Play(); break; + case CMD_SEEK: CDD_Seek(); break; + case CMD_STOP: CDD_Pause(); break; + case CMD_RESUME: CDD_Resume(); break; + case CMD_FF: CDD_FF(); break; + case CMD_RW: CDD_RW(); break; + case CMD_INIT: CDD_Init(); break; + case CMD_CLOSE: CDD_Open(); break; + case CMD_OPEN: CDD_Close(); break; + default: CDD_Default(); break; + } + + CDD_DONE = 1; + return true; +} + + +/************************************************************** + CDC Stuff ******** +**************************************************************/ + + + +void lc89510_temp_device::segacd_cdc_mode_address_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&CDC_REG0); +} + +uint16_t lc89510_temp_device::segacd_cdc_mode_address_r() +{ + return CDC_REG0; +} + +void lc89510_temp_device::segacd_cdc_data_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&CDC_REG1); + + if (ACCESSING_BITS_0_7) + CDC_Reg_w(data); +} + +uint16_t lc89510_temp_device::segacd_cdc_data_r(offs_t offset, uint16_t mem_mask) +{ + uint16_t retdat = 0x0000; + + if (ACCESSING_BITS_0_7) + retdat |= CDC_Reg_r(); + + return retdat; +} + + +uint16_t lc89510_temp_device::cdc_data_sub_r() +{ + return CDC_Host_r(READ_SUB); +} + +uint16_t lc89510_temp_device::cdc_data_main_r() +{ + return CDC_Host_r(READ_MAIN); +} + + + + +uint16_t lc89510_temp_device::segacd_irq_mask_r() +{ + return segacd_irq_mask; +} + +void lc89510_temp_device::segacd_irq_mask_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + uint16_t control = CDD_CONTROL; + + // printf("segacd_irq_mask_w %04x %04x (CDD control is %04x)\n",data, mem_mask, control); + + if (data & 0x10) + { + if (control & 0x04) + { + if (!(segacd_irq_mask & 0x10)) + { + segacd_irq_mask = data & 0x7e; + CDD_Process(0); + return; + } + } + } + + segacd_irq_mask = data & 0x7e; + } + else + { + printf("segacd_irq_mask_w only MSB written\n"); + + } +} + +uint16_t lc89510_temp_device::segacd_cdd_ctrl_r() +{ + return CDD_CONTROL; +} + + +void lc89510_temp_device::segacd_cdd_ctrl_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_0_7) + { + uint16_t control = CDD_CONTROL; + + + //printf("segacd_cdd_ctrl_w %04x %04x (control %04x irq %04x\n", data, mem_mask, control, segacd_irq_mask); + + data &=0x4; // only HOCK bit is writable + + if (data & 0x4) + { + if (!(control & 0x4)) + { + if (segacd_irq_mask&0x10) + { + CDD_Process(1); + } + } + } + + CDD_CONTROL |= data; + } + else + { + printf("segacd_cdd_ctrl_w only MSB written\n"); + } +} + + +// mapped as serial +uint8_t lc89510_temp_device::neocd_cdd_rx_r() +{ + uint8_t ret = 0; + + if (NeoCDCommsWordCount >= 0 && NeoCDCommsWordCount < 10) { + ret = CDD_RX[NeoCDCommsWordCount] & 0x0F; + } + + if (bNeoCDCommsClock) { + ret |= 0x10; + } + + return ret; +} + +// mapped like 'ram' +uint8_t lc89510_temp_device::segacd_cdd_rx_r(offs_t offset) +{ + return CDD_RX[offset]; +} + +// mapped as serial +void lc89510_temp_device::neocd_cdd_tx_w(uint8_t data) +{ + //printf("neocd_cdd_tx_w %d, %02x\n", NeoCDCommsWordCount, data); + + if (NeoCDCommsWordCount >= 0 && NeoCDCommsWordCount < 10) { + CDD_TX[NeoCDCommsWordCount] = data & 0x0F; + } +} + +void lc89510_temp_device::segacd_cdd_tx_w(offs_t offset, uint8_t data) +{ + CDD_TX[offset] = data; + + if(offset == 9) + { + CDD_Import(); + } +} + + + + + + +uint16_t lc89510_temp_device::segacd_cdfader_r() +{ + return 0; +} + +void lc89510_temp_device::segacd_cdfader_w(uint16_t data) +{ + static double cdfader_vol; + if(data & 0x800f) + printf("CD Fader register write %04x\n",data); + + cdfader_vol = (double)((data & 0x3ff0) >> 4); + + if(data & 0x4000) + cdfader_vol = 1.0; + else + cdfader_vol = cdfader_vol / 1024.0; + + //printf("%f\n",cdfader_vol); + + m_cdda->set_output_gain(ALL_OUTPUTS, cdfader_vol); +} + +void lc89510_temp_device::reset_cd(void) +{ + /* init cd-rom device */ + + lc89510_Reset(); + + { + segacd.cd = m_cdrom->get_cdrom_file(); + if ( segacd.cd ) + { + segacd.toc = &segacd.cd->get_toc(); + m_cdda->set_cdrom(segacd.cd); + m_cdda->stop_audio(); //stop any pending CD-DA + } + } + + + +// if (segacd.cd) +// printf("cd found\n"); +} + + + +TIMER_DEVICE_CALLBACK_MEMBER( lc89510_temp_device::segacd_access_timer_callback ) +{ + if (!is_neoCD) + { + if (CDD_DONE) + { + CDD_DONE = 0; + CDD_Export(); + CHECK_SCD_LV4_INTERRUPT_A + } + } + else + { + if (nff0002 & 0x0050) + { + m_type2_interrupt_callback(); + } + } + + if (SCD_READ_ENABLED) // if (nff0002 & 0x0050) if (nff0002 & 0x0500); + { + set_data_audio_mode(); + Read_LBA_To_Buffer(); + } + +} + + +void lc89510_temp_device::device_add_mconfig(machine_config &config) +{ + TIMER(config, "hock_timer").configure_periodic(FUNC(lc89510_temp_device::segacd_access_timer_callback), attotime::from_hz(75)); + + cdda_device &cdda(CDDA(config, "cdda")); + cdda.add_route(0, ":lspeaker", 0.50); // TODO: accurate volume balance + cdda.add_route(1, ":rspeaker", 0.50); +} + + + +/* Neo CD */ + + +void lc89510_temp_device::NeoCDCommsReset() +{ + bNeoCDCommsClock = true; + + memset(CDD_TX, 0, sizeof(CDD_TX)); + memset(CDD_RX, 0, sizeof(CDD_RX)); + + NeoCDCommsWordCount = 0; + + NeoCD_StatusHack = 9; + + + nff0016 = 0; +} + + + + +void lc89510_temp_device::NeoCDCommsControl(uint8_t clock, uint8_t send) +{ + if (clock && !bNeoCDCommsClock) { + NeoCDCommsWordCount++; + if (NeoCDCommsWordCount >= 10) { + NeoCDCommsWordCount = 0; + + if (send) + { + if (CDD_TX[0]) + { + if (!CDD_Import()) + return; + + CDD_Export(true); // true == neocd hack, + } + + } + + } + } + bNeoCDCommsClock = clock; +} + + +void lc89510_temp_device::LC8951UpdateHeader() // neocd +{ + if (LC8951RegistersW[REG_W_CTRL1] & 1) { + // HEAD registers have sub-header + + LC8951RegistersR[REG_R_HEAD0] = 0; // HEAD0 + LC8951RegistersR[REG_R_HEAD1] = 0; // HEAD1 + LC8951RegistersR[REG_R_HEAD2] = 0; // HEAD2 + LC8951RegistersR[REG_R_HEAD3] = 0; // HEAD3 + + } else { + // HEAD registers have header + uint32_t msf = cdrom_file::lba_to_msf_alt(SCD_CURLBA+150); + + LC8951RegistersR[REG_R_HEAD0] = to_bcd (((msf & 0x00ff0000)>>16), true); // HEAD0 + LC8951RegistersR[REG_R_HEAD1] = to_bcd (((msf & 0x0000ff00)>>8), true); // HEAD1 + LC8951RegistersR[REG_R_HEAD2] = to_bcd (((msf & 0x000000ff)>>0), true); // HEAD2 + LC8951RegistersR[REG_R_HEAD3] = 0x1; // HEAD3 + } +} + +char* lc89510_temp_device::LC8915InitTransfer(int NeoCDDMACount) +{ + if (!LC8951RegistersW[REG_W_DTTRG]) { + //bprintf(PRINT_ERROR, _T(" LC8951 DTTRG status invalid\n")); + return nullptr; + } + if (!(LC8951RegistersW[REG_W_IFCTRL] & 0x02)) { + //bprintf(PRINT_ERROR, _T(" LC8951 DOUTEN status invalid\n")); + return nullptr; + } + if (((LC8951RegistersW[REG_W_DACH] << 8) | LC8951RegistersW[REG_W_DACL]) + (NeoCDDMACount << 1) > EXTERNAL_BUFFER_SIZE) { + //bprintf(PRINT_ERROR, _T(" DMA transfer exceeds current sector in LC8951 external buffer\n")); + + return nullptr; + } + + char* addr = (char*)CDC_BUFFER + ((LC8951RegistersW[REG_W_DACH] << 8) | LC8951RegistersW[REG_W_DACL]); + return addr; +} + +void lc89510_temp_device::LC8915EndTransfer() +{ + LC8951RegistersW[REG_W_DTTRG] = 0x00; // reset DTTRG + + LC8951RegistersR[REG_R_IFSTAT] |= 0x48; // set DTEI & DTBSY + if (LC8951RegistersW[REG_W_IFCTRL] & 0x40) { + // trigger DTE interrupt + + // the Neo Geo CD doesn't use the DTE interrupt + // nIRQAcknowledge &= ~0x20; + // NeoCDIRQUpdate(0); + + } +} + + +void lc89510_temp_device::CDC_End_Transfer() +{ + STOP_CDC_DMA + CDC_REG0 |= 0x8000; + CDC_REG0 &= ~0x4000; + LC8951RegistersR[REG_R_IFSTAT] |= 0x08; + + if (LC8951RegistersW[REG_W_IFCTRL] & 0x40) + { + LC8951RegistersR[REG_R_IFSTAT] &= ~0x40; + CHECK_SCD_LV5_INTERRUPT + } +} + + + + + + +void lc89510_temp_device::scd_ctrl_checks() +{ + LC8951RegistersR[REG_R_STAT0] = 0x80; + + (LC8951RegistersW[REG_W_CTRL0] & 0x10) ? (LC8951RegistersR[REG_R_STAT2] = LC8951RegistersW[REG_W_CTRL1] & 0x08) : (LC8951RegistersR[REG_R_STAT2] = LC8951RegistersW[REG_W_CTRL1] & 0x0C); + (LC8951RegistersW[REG_W_CTRL0] & 0x02) ? (LC8951RegistersR[REG_R_STAT3] = 0x20) : (LC8951RegistersR[REG_R_STAT3] = 0x00); + + if (LC8951RegistersW[REG_W_IFCTRL] & 0x20) + { + if (is_neoCD) + { + m_type1_interrupt_callback(); + } + else + { + // todo: make callback + CHECK_SCD_LV5_INTERRUPT + } + + + + LC8951RegistersR[REG_R_IFSTAT] &= ~0x20; + CDC_DECODE = 0; + } +} + +void lc89510_temp_device::scd_advance_current_readpos(void) +{ + SCD_CURLBA++; + + int pt = LC8951RegistersW[REG_W_PTL] | (LC8951RegistersW[REG_W_PTH] << 8); + int wa = LC8951RegistersW[REG_W_WAL] | (LC8951RegistersW[REG_W_WAH] << 8); + + wa += SECTOR_SIZE; + pt += SECTOR_SIZE; + + wa &= 0x7fff; + pt &= 0x7fff; + + LC8951RegistersW[REG_W_PTL] = pt & 0xff; LC8951RegistersW[REG_W_PTH] = (pt >> 8) &0xff; + LC8951RegistersW[REG_W_WAL] = wa & 0xff; LC8951RegistersW[REG_W_WAH] = (wa >> 8) &0xff; + +} + +int lc89510_temp_device::Read_LBA_To_Buffer() +{ + bool data_track = false; + if (CDD_CONTROL & 0x0100) data_track = true; + + if (data_track) + segacd.cd->read_data(SCD_CURLBA, SCD_BUFFER, cdrom_file::CD_TRACK_MODE1); + + LC8951UpdateHeader(); + + if (!data_track) + { + scd_advance_current_readpos(); + } + + if (LC8951RegistersW[REG_W_CTRL0] & 0x80) + { + if (LC8951RegistersW[REG_W_CTRL0] & 0x04) + { + if (data_track) + { + scd_advance_current_readpos(); + + int pt = LC8951RegistersW[REG_W_PTL] | (LC8951RegistersW[REG_W_PTH] << 8); + + memcpy(&CDC_BUFFER[pt + 4], SCD_BUFFER, 2048); + CDC_BUFFER[pt+0] = LC8951RegistersR[REG_R_HEAD0]; + CDC_BUFFER[pt+1] = LC8951RegistersR[REG_R_HEAD1]; + CDC_BUFFER[pt+2] = LC8951RegistersR[REG_R_HEAD2]; + CDC_BUFFER[pt+3] = LC8951RegistersR[REG_R_HEAD3]; + + + if (is_neoCD) + { + // This simulates the protection used by the NeoCDZ, a number of games (samsrpg for example) + // will not be recognized unless this happens. Is this part of the CDC error correction + // mechanism? + char *buffer_hack = (char*)&CDC_BUFFER[pt]; + if (buffer_hack[4 + 64] == 'g' && !strncmp(buffer_hack + 4, "Copyright by SNK", 16)) + { + buffer_hack[4 + 64] = 'f'; + } + } + + } + else + { + int pt = LC8951RegistersW[REG_W_PTL] | (LC8951RegistersW[REG_W_PTH] << 8); + + memcpy(&CDC_BUFFER[pt], SCD_BUFFER, SECTOR_SIZE); + } + } + + scd_ctrl_checks(); + + + } + + + return 0; +} + + + + + + +void lc89510_temp_device::nff0002_set(uint16_t wordValue) +{ + nff0002 = wordValue; +} + +void lc89510_temp_device::nff0016_set(uint16_t wordValue) +{ + nff0016 = wordValue; +} + +uint16_t lc89510_temp_device::nff0016_r(void) { return nff0016; } diff --git a/src/mame/shared/megacdcd.h b/src/mame/shared/megacdcd.h new file mode 100644 index 00000000000..21fc407896b --- /dev/null +++ b/src/mame/shared/megacdcd.h @@ -0,0 +1,197 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#ifndef MAME_MACHINE_SEGACDCD_H +#define MAME_MACHINE_SEGACDCD_H + +#include "imagedev/chd_cd.h" +#include "machine/timer.h" +#include "sound/cdda.h" + + +class lc89510_temp_device : public device_t +{ +public: + typedef device_delegate dma_delegate; + typedef device_delegate interrupt_delegate; + + void set_is_neoCD(bool new_is_neoCD) { is_neoCD = new_is_neoCD; } + + template void set_type1_interrupt_callback(T &&... args) { m_type1_interrupt_callback.set(std::forward(args)...); } + template void set_type2_interrupt_callback(T &&... args) { m_type2_interrupt_callback.set(std::forward(args)...); } + template void set_type3_interrupt_callback(T &&... args) { m_type3_interrupt_callback.set(std::forward(args)...); } + + template void set_cdc_do_dma_callback(T &&... args) { m_segacd_dma_callback.set(std::forward(args)...); } + + template void set_cdrom_tag(T &&tag) { m_cdrom.set_tag(std::forward(tag)); } + template void set_68k_tag(T &&tag) { m_68k.set_tag(std::forward(tag)); } + + + lc89510_temp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + uint16_t get_segacd_irq_mask() const { return segacd_irq_mask; } + + uint16_t segacd_irq_mask_r(); + void segacd_irq_mask_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t segacd_cdd_ctrl_r(); + void segacd_cdd_ctrl_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint8_t segacd_cdd_rx_r(offs_t offset); + void segacd_cdd_tx_w(offs_t offset, uint8_t data); + uint16_t segacd_cdfader_r(); + void segacd_cdfader_w(uint16_t data); + + void segacd_cdc_mode_address_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t segacd_cdc_mode_address_r(); + void segacd_cdc_data_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + uint16_t segacd_cdc_data_r(offs_t offset, uint16_t mem_mask = ~0); + uint16_t cdc_data_sub_r(); + uint16_t cdc_data_main_r(); + + void CDC_Do_DMA(int rate); + + uint8_t CDC_Reg_r(void); + void CDC_Reg_w(uint8_t data); + + void reset_cd(); + + // NeoGeo CD stuff + void neocd_cdd_tx_w(uint8_t data); + uint8_t neocd_cdd_rx_r(); + void NeoCDCommsControl(uint8_t clock, uint8_t send); + void NeoCDCommsReset(); + + uint16_t nff0016_r(); + void nff0016_set(uint16_t wordValue); + void nff0002_set(uint16_t wordValue); + + char* LC8915InitTransfer(int NeoCDDMACount); + void LC8915EndTransfer(); + +protected: + static constexpr unsigned SECTOR_SIZE = 2352; + static constexpr unsigned EXTERNAL_BUFFER_SIZE = (32 * 1024 * 2) + SECTOR_SIZE; + + // HACK for DMA handling + dma_delegate m_segacd_dma_callback; + interrupt_delegate m_type1_interrupt_callback; + interrupt_delegate m_type2_interrupt_callback; + interrupt_delegate m_type3_interrupt_callback; + + void Fake_CDC_Do_DMA(int &dmacount, uint8_t *CDC_BUFFER, uint16_t &dma_addrc, uint16_t &destination ); + + void dummy_interrupt_callback(); + + + required_device m_cdrom; + required_device m_cdda; + + // HACK for neoCD handling + optional_device m_68k; + bool is_neoCD; + + + struct segacd_t + { + cdrom_file *cd; + const cdrom_file::toc *toc; + uint32_t current_frame; + }; + + + segacd_t segacd; + + uint8_t SCD_BUFFER[2560]; + + uint32_t SCD_STATUS; + uint32_t SCD_STATUS_CDC; + int32_t SCD_CURLBA; + uint8_t SCD_CURTRK; + + + uint16_t CDC_DECODE; + uint16_t CDC_REG0; + uint16_t CDC_REG1; + + uint8_t CDC_BUFFER[EXTERNAL_BUFFER_SIZE]; + + + uint8_t CDD_RX[10]; + uint8_t CDD_TX[10]; + + uint32_t CDD_STATUS; + uint32_t CDD_MIN; + uint32_t CDD_SEC; + uint32_t CDD_FRAME; + uint32_t CDD_EXT; + + uint16_t CDD_CONTROL; + + int16_t CDD_DONE; + + inline int to_bcd(int val, bool byte); + void set_data_audio_mode(void); + void CDD_DoChecksum(void); + bool CDD_Check_TX_Checksum(void); + void CDD_Export(bool neocd_hack = false); + void scd_ctrl_checks(); + void scd_advance_current_readpos(void); + int Read_LBA_To_Buffer(); + void CDD_GetStatus(void); + void CDD_Stop(); + void CDD_GetPos(void); + void CDD_GetTrackPos(void); + void CDD_GetTrack(void); + void CDD_Length(void); + void CDD_FirstLast(void); + void CDD_GetTrackAdr(void); + void CDD_GetTrackType(void); + uint32_t getmsf_from_regs(void); + void CDD_Play(); + void CDD_Seek(void); + void CDD_Pause(); + void CDD_Resume(); + void CDD_FF(); + void CDD_RW(); + void CDD_Open(void); + void CDD_Close(void); + void CDD_Init(void); + void CDD_Default(void); + void CDD_Reset(void); + void CDC_Reset(void); + void lc89510_Reset(void); + void CDC_End_Transfer(); + uint16_t CDC_Host_r(uint16_t type); + void CDD_Process(int reason); + void CDD_Handle_TOC_Commands(void); + bool CDD_Import(); + + uint16_t segacd_irq_mask; + + /* NeoCD */ + uint16_t nff0002; + uint16_t nff0016; + + + int32_t LC8951RegistersR[16]; + int32_t LC8951RegistersW[16]; + + + + bool bNeoCDCommsClock; + + int32_t NeoCDCommsWordCount; + + int32_t NeoCD_StatusHack; + + void LC8951UpdateHeader(); + + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + TIMER_DEVICE_CALLBACK_MEMBER( segacd_access_timer_callback ); +}; + +DECLARE_DEVICE_TYPE(LC89510_TEMP, lc89510_temp_device) + +#endif // MAME_MACHINE_SEGACDCD_H diff --git a/src/mame/shared/mitcrt.cpp b/src/mame/shared/mitcrt.cpp new file mode 100644 index 00000000000..30037934a4c --- /dev/null +++ b/src/mame/shared/mitcrt.cpp @@ -0,0 +1,181 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + video/crt.c + + CRT video emulation for TX-0 and PDP-1. + + +Theory of operation: + + What makes such CRT devices so odd is that there is no video processor, no + scan logic, no refresh logic. The beam position and intensity is + controlled by the program completely: in order to draw an object, the + program must direct the beam to each point of the object, and in order to + refresh it, the program must redraw the object periodically. + + Since the refresh rates are highly variable (completely controlled by the + program), I need to simulate CRT remanence: the intensity of each pixel on + display decreases regularly. In order to keep this efficient, I keep a + list of non-black pixels, and only process these pixels on each refresh. + In order to improve efficiency further, I keep a distinct list for each + line of the display: I have found that it improves drawing speed slightly + (probably because it improves the cache hit rate). + + + Raphael Nabet 2002-2004 + Based on earlier work by Chris Salomon +*/ + +#include "emu.h" +#include "mitcrt.h" + + +// special value that tells that the node is not in list +enum +{ + intensity_pixel_not_in_list = -1 +}; + + +// device type definition +DEFINE_DEVICE_TYPE(CRT, crt_device, "crt", "CRT Video") + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crt_device - constructor +//------------------------------------------------- + +crt_device::crt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, CRT, tag, owner, clock), + m_list(nullptr), + m_list_head(nullptr), + m_decay_counter(0), + m_num_intensity_levels(0), + m_window_offset_x(0), + m_window_offset_y(0), + m_window_width(0), + m_window_height(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crt_device::device_start() +{ + /* alloc the arrays */ + m_list = std::make_unique(m_window_width * m_window_height); + m_list_head = std::make_unique(m_window_height); + + /* fill with black and set up list as empty */ + for (int i = 0; i < (m_window_width * m_window_height); i++) + m_list[i].intensity = intensity_pixel_not_in_list; + + for (int i = 0; i < m_window_height; i++) + m_list_head[i] = -1; + + m_decay_counter = 0; +} + + +// +// crt_plot +// +// schedule a pixel to be plotted +// +void crt_device::plot(int x, int y) +{ + crt_point *node; + int list_index; + + /* compute pixel coordinates */ + if (x<0) x=0; + if (y<0) y=0; + if ((x>(m_window_width-1)) || ((y>m_window_height-1))) + return; + y = (m_window_height-1) - y; + + /* find entry in list */ + list_index = x + y*m_window_width; + + node = &m_list[list_index]; + + if (node->intensity == intensity_pixel_not_in_list) + { /* insert node in list if it is not in it */ + node->next = m_list_head[y]; + m_list_head[y] = list_index; + } + /* set intensity */ + node->intensity = m_num_intensity_levels; +} + + +// +// crt_eof +// +// keep track of time +// +void crt_device::eof() +{ + m_decay_counter++; +} + + +// +// crt_update +// +// update the bitmap +// +void crt_device::update(bitmap_ind16 &bitmap) +{ + //if (m_decay_counter) + { + /* some time has elapsed: let's update the screen */ + for (int y=0; yintensity == m_num_intensity_levels) + /* new pixel: set to max intensity */ + node->intensity = m_num_intensity_levels-1; + else + { + /* otherwise, apply intensity decay */ + node->intensity -= m_decay_counter; + if (node->intensity < 0) + node->intensity = 0; + } + + /* draw pixel on screen */ + //plot_pixel(bitmap, x, y+m_window_offset_y, node->intensity); + line[x] = node->intensity; + + if (node->intensity != 0) + p_i = i; /* current node will be next iteration's previous node */ + else + { /* delete current node */ + node->intensity = intensity_pixel_not_in_list; + if (p_i != -1) + m_list[p_i].next = node->next; + else + m_list_head[y] = node->next; + } + } + } + + m_decay_counter = 0; + } +} diff --git a/src/mame/shared/mitcrt.h b/src/mame/shared/mitcrt.h new file mode 100644 index 00000000000..bf4c94fd0d5 --- /dev/null +++ b/src/mame/shared/mitcrt.h @@ -0,0 +1,76 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/************************************************************************* + + video/crt.h + + CRT video emulation for TX-0 and PDP-1 + +*************************************************************************/ + +#ifndef MAME_VIDEO_CRT_H +#define MAME_VIDEO_CRT_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> crt_device + +class crt_device : public device_t +{ +public: + crt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void set_num_levels(int levels) { m_num_intensity_levels = levels; } + void set_offsets(int x_offset, int y_offset) + { + m_window_offset_x = x_offset; + m_window_offset_y = y_offset; + } + void set_size(int width, int height) + { + m_window_width = width; + m_window_height = height; + } + + void plot(int x, int y); + void eof(); + void update(bitmap_ind16 &bitmap); + +protected: + // device-level overrides + virtual void device_start() override; + +private: + struct crt_point + { + crt_point() { } + + int intensity = 0; /* current intensity of the pixel */ + /* a node is not in the list when (intensity == -1) */ + int next = 0; /* index of next pixel in list */ + }; + + std::unique_ptr m_list; /* array of (crt_window_width*crt_window_height) point */ + std::unique_ptr m_list_head; /* head of the list of lit pixels (index in the array) */ + /* keep a separate list for each display line (makes the video code slightly faster) */ + + int m_decay_counter; /* incremented each frame (tells for how many frames the CRT has decayed between two screen refresh) */ + + /* CRT window */ + int m_num_intensity_levels; + int m_window_offset_x; + int m_window_offset_y; + int m_window_width; + int m_window_height; +}; + +DECLARE_DEVICE_TYPE(CRT, crt_device) + + + +#endif // MAME_VIDEO_CRT_H diff --git a/src/mame/shared/ms7004.cpp b/src/mame/shared/ms7004.cpp new file mode 100644 index 00000000000..ee04d98c888 --- /dev/null +++ b/src/mame/shared/ms7004.cpp @@ -0,0 +1,476 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/* + Elektronika MS 7004 keyboard (DEC LK-201 workalike with extra keys + for Cyrillic characters). + + To do: + - connect LEDs and speaker +*/ + +#include "emu.h" +#include "ms7004.h" +#include "speaker.h" + + +//#define LOG_GENERAL (1U << 0) //defined in logmacro.h already +#define LOG_DEBUG (1U << 1) + +//#define VERBOSE (LOG_GENERAL | LOG_DEBUG) +//#define LOG_OUTPUT_FUNC printf +#include "logmacro.h" + +#define LOGDBG(...) LOGMASKED(LOG_DEBUG, __VA_ARGS__) + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define MS7004_CPU_TAG "i8035" +#define MS7004_SPK_TAG "beeper" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(MS7004, ms7004_device, "ms7004", "MS7004 keyboard") + +ROM_START( ms7004 ) + ROM_REGION (0x800, MS7004_CPU_TAG, 0) + ROM_LOAD ("mc7004_keyboard_original.rom", 0x0000, 0x800, CRC(69fcab53) SHA1(2d7cc7cd182f2ee09ecf2c539e33db3c2195f778)) +ROM_END + +//------------------------------------------------- +// ADDRESS_MAP +//------------------------------------------------- + +void ms7004_device::ms7004_map(address_map &map) +{ + map(0x0000, 0x07ff).rom(); +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void ms7004_device::device_add_mconfig(machine_config &config) +{ + I8035(config, m_maincpu, XTAL(4'608'000)); + m_maincpu->set_addrmap(AS_PROGRAM, &ms7004_device::ms7004_map); + m_maincpu->p1_out_cb().set(FUNC(ms7004_device::p1_w)); + m_maincpu->p2_out_cb().set(FUNC(ms7004_device::p2_w)); + m_maincpu->t1_in_cb().set(FUNC(ms7004_device::t1_r)); + m_maincpu->prog_out_cb().set(m_i8243, FUNC(i8243_device::prog_w)); + + I8243(config, m_i8243); + m_i8243->p4_out_cb().set(FUNC(ms7004_device::i8243_port_w<0>)); + m_i8243->p5_out_cb().set(FUNC(ms7004_device::i8243_port_w<1>)); + m_i8243->p6_out_cb().set(FUNC(ms7004_device::i8243_port_w<2>)); + m_i8243->p7_out_cb().set(FUNC(ms7004_device::i8243_port_w<3>)); + + SPEAKER(config, "mono").front_center(); + BEEP(config, m_speaker, 3250).add_route(ALL_OUTPUTS, "mono", 0.50); +} + +const tiny_rom_entry *ms7004_device::device_rom_region() const +{ + return ROM_NAME(ms7004); +} + +//------------------------------------------------- +// INPUT_PORTS( ms7004 ) +//------------------------------------------------- +/* +bit sig XSn ????n +--- --- --- --- +0 8 16 15 +1 9 15 14 +2 10 14 13 +3 11 13 12 +4 12 19 16 +5 13 12 11 +6 14 11 10 +7 15 10 9 +8 16 9 8 +9 17 8 7 +10 18 7 6 +11 19 6 5 +12 20 3 1 +13 21 1 2 +14 22 4 3 +15 23 5 4 + +0xc9 KEY_LANGLE_RANGLE 'резервная клавиша' +0xbc KEY_DELETE ЗБ +0xbd KEY_RETURN ВК +0xbf KEY_TILDE '; +' +0xc4 - 'Ъ' +0xca - '/ ?' +0xed KEY_PERIOD 'Ю @' +0xf1 - '_' +<...> + +0x56 KEY_F1 СТОП КАДР +0x57 KEY_F2 ПЕЧАТЬ КАДРА +0x58 KEY_F3 ПАУЗА +0x59 KEY_F4 УСТ РЕЖИМА +0x5a KEY_F5 Ф5 + +0x64 KEY_F6 ПРЕРЫВ +0x65 KEY_F7 ПРОДОЛЖ +0x66 KEY_F8 ОТМЕН +0x67 KEY_F9 ОСНОВН КАДР +0x69 KEY_F10 ВЫХОД + +0x71 KEY_F11 Ф11 (АР2) +0x72 KEY_F12 Ф12 (ВШ) +0x73 KEY_F13 Ф13 (ПС) +0x74 KEY_F14 ДОП ВАРИАНТ + +0x7c KEY_HELP ПМ +0x7d KEY_MENU ИСП + +0x80 KEY_F17 Ф17 +0x81 KEY_F18 Ф18 +0x82 KEY_F19 Ф19 +0x83 KEY_F20 Ф20 + +0xb0 KEY_LOCK ФКС +0xae KEY_SHIFT ВР +0xaf KEY_CTRL СУ + +0xb1 KEY_META КМП +0xb2 - РУС/ЛАТ + +0x8a KEY_FIND НТ +0x8b KEY_INSERT_HERE ВСТ +0x8c KEY_REMOVE УДАЛ +0x8d KEY_SELECT ВЫБР +0x8e KEY_PREV_SCREEN ПРЕД КАДР +0x8f KEY_NEXT_SCREEN СЛЕД КАДР + +nothing sends '@' or '`' + +`/~ sends ^/~ +2/@ sends 2/" +6/^ sends 6/& +7/& sends 7/' +8 * sends 8/( +9/( sends 9/) +0/) sends 0/0 +-/_ sends _/_ ++/= sends -/= +;/: sends ;/+ +'/" sends : * + +F10 sends ^C +F11 sends ESC +F12 sends ^H +*/ +INPUT_PORTS_START( ms7004 ) + PORT_START("KBD12") // vertical row 1 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Hold Screen (F1)") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // '{' / '|' + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + + PORT_START("KBD13") // vertical row 2 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Setup (F3)") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Data / Talk (F4)") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHAR('j') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHAR('c') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CHAR('f') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Rus/Lat") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Compose") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + + PORT_START("KBD14") // vertical row 3 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Break (F5)") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CHAR('u') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CHAR('y') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CHAR('q') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD15") // vertical row 4 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CHAR('k') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CHAR('w') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CHAR('s') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD11") // vertical row 5 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Interrupt (F6)") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CHAR('e') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('p') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHAR('a') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CHAR('m') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KBD10") // vertical row 6 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Resume (F7)") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CHAR('n') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CHAR('g') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CHAR('r') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CHAR('t') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CHAR('i') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CHAR(' ') + + PORT_START("KBD9") // vertical row 7 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cancel (F8)") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Main Screen (F9)") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHAR('o') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CHAR('b') + + PORT_START("KBD8") // vertical row 8 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Exit (F10)") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHAR('d') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHAR('l') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('@') PORT_CHAR('`') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + + PORT_START("KBD7") // vertical row 9 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC (F11)") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CHAR('h') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CHAR('v') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + + PORT_START("KBD6") // vertical row 10 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BS (F12)") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF (F13)") PORT_CODE(KEYCODE_PRTSCR) PORT_CHAR(UCHAR_MAMEKEY(PRTSCR)) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // '}' + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // sends '_' + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('_') PORT_CHAR('_') + + PORT_START("KBD5") // vertical row 11 + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Additional Options (F14)") PORT_CODE(KEYCODE_PAUSE) PORT_CHAR(UCHAR_MAMEKEY(PAUSE)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE); +} + +//------------------------------------------------- +// p1_w - +//------------------------------------------------- + +void ms7004_device::p1_w(uint8_t data) +{ + /* + bit description + + 0 Matrix row bit 0 + 1 Matrix row bit 1 + 2 Matrix row bit 2 + 3 Speaker + 4 -STROBE (to matrix mux) + 5 LED "Latin" + 6 + 7 Serial TX + */ + LOGDBG("p1_w %02x = send %d\n", data, BIT(data, 7)); + + m_p1 = data; + m_tx_handler(BIT(data, 7)); +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +void ms7004_device::p2_w(uint8_t data) +{ + /* + bit description + + 0 Matrix columns, to 8243 (port 4) + 1 Matrix columns, to 8243 (port 5) + 2 Matrix columns, to 8243 (port 6) + 3 Matrix columns, to 8243 (port 7) + 4 LED "Wait" + 5 LED "Compose" + 6 LED "Caps" + 7 LED "Hold" + */ + LOGDBG("p2_w %02x = col %d\n", data, data&15); + + m_p2 = data; + m_i8243->p2_w(data); +} + + +//------------------------------------------------- +// prog_w - +//------------------------------------------------- + +template +void ms7004_device::i8243_port_w(uint8_t data) +{ + int sense = 0; + + LOGDBG("8243 port %d data %02xH\n", P + 4, data); + + if (data) { + switch(data) { + case 0x01: sense = m_kbd[(P << 2) + 0]->read(); break; + case 0x02: sense = m_kbd[(P << 2) + 1]->read(); break; + case 0x04: sense = m_kbd[(P << 2) + 2]->read(); break; + case 0x08: sense = m_kbd[(P << 2) + 3]->read(); break; + } + m_keylatch = BIT(sense, (m_p1 & 7)); + if (m_keylatch) + LOG("row %d col %02x t1 %d\n", + (m_p1 & 7), (P << 4 | data), m_keylatch); + } +} + + +//------------------------------------------------- +// t1_r - +//------------------------------------------------- + +READ_LINE_MEMBER(ms7004_device::t1_r) +{ + if (!BIT(m_p1, 4)) + return m_keylatch; + else + return 0; +} diff --git a/src/mame/shared/ms7004.h b/src/mame/shared/ms7004.h new file mode 100644 index 00000000000..ace9c954667 --- /dev/null +++ b/src/mame/shared/ms7004.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +#ifndef MAME_MACHINE_MS7004_H +#define MAME_MACHINE_MS7004_H + +#pragma once + +#include "cpu/mcs48/mcs48.h" +#include "machine/i8243.h" +#include "sound/beep.h" + +#include "diserial.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ms7004_device + +class ms7004_device : public device_t //, public device_serial_interface +{ +public: + // construction/destruction + ms7004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto tx_handler() { return m_tx_handler.bind(); } + auto rts_handler() { return m_rts_handler.bind(); } + + DECLARE_WRITE_LINE_MEMBER( write_rxd ); + + void ms7004_map(address_map &map); +protected: + // device-level overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_start() override; + virtual void device_reset() override; + +private: + required_device m_maincpu; + required_device m_speaker; + required_device m_i8243; + + required_ioport_array<16> m_kbd; + + int m_keylatch; // keyboard row latch + uint8_t m_p1; + uint8_t m_p2; + + devcb_write_line m_tx_handler; + devcb_write_line m_rts_handler; + + void p1_w(uint8_t data); + void p2_w(uint8_t data); + DECLARE_READ_LINE_MEMBER( t1_r ); + template void i8243_port_w(uint8_t data); +}; + +// device type definition +DECLARE_DEVICE_TYPE(MS7004, ms7004_device) + +#endif // MAME_MACHINE_MS7004_H diff --git a/src/mame/shared/teleprinter.cpp b/src/mame/shared/teleprinter.cpp new file mode 100644 index 00000000000..75b1654a7ef --- /dev/null +++ b/src/mame/shared/teleprinter.cpp @@ -0,0 +1,237 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#include "emu.h" +#include "teleprinter.h" + +#include "screen.h" +#include "speaker.h" + + +static const uint8_t teleprinter_font[128*8] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, + 0x38,0x38,0x38,0x38,0x00,0x00,0x00,0x00, + 0x3f,0x3f,0x3f,0x3f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x38,0x38,0x38,0x38,0x07,0x07,0x07,0x07, + 0x3f,0x3f,0x3f,0x3f,0x07,0x07,0x07,0x07, + 0x00,0x00,0x00,0x00,0x38,0x38,0x38,0x38, + 0x07,0x07,0x07,0x07,0x38,0x38,0x38,0x38, + 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, + 0x3f,0x3f,0x3f,0x3f,0x38,0x38,0x38,0x38, + 0x00,0x00,0x00,0x00,0x3f,0x3f,0x3f,0x3f, + 0x07,0x07,0x07,0x07,0x3f,0x3f,0x3f,0x3f, + 0x38,0x38,0x38,0x38,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x00,0x00,0x00,0x00,0x2a,0x15,0x2a,0x15, + 0x2a,0x15,0x2a,0x15,0x00,0x00,0x00,0x00, + 0x3f,0x3f,0x3f,0x3f,0x2a,0x15,0x2a,0x15, + 0x2a,0x15,0x2a,0x15,0x3f,0x3f,0x3f,0x3f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x00, + 0x14,0x14,0x14,0x00,0x00,0x00,0x00,0x00, + 0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,0x00, + 0x08,0x3c,0x0a,0x1c,0x28,0x1e,0x08,0x00, + 0x06,0x26,0x10,0x08,0x04,0x32,0x30,0x00, + 0x08,0x14,0x14,0x0c,0x2a,0x12,0x2c,0x00, + 0x08,0x08,0x04,0x00,0x00,0x00,0x00,0x00, + 0x10,0x08,0x04,0x04,0x04,0x08,0x10,0x00, + 0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00, + 0x00,0x08,0x2a,0x1c,0x2a,0x08,0x00,0x00, + 0x00,0x08,0x08,0x3e,0x08,0x08,0x00,0x00, + 0x00,0x00,0x00,0x00,0x08,0x08,0x04,0x00, + 0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00, + 0x00,0x20,0x10,0x08,0x04,0x02,0x00,0x00, + 0x1c,0x22,0x32,0x2a,0x26,0x22,0x1c,0x00, + 0x08,0x0c,0x08,0x08,0x08,0x08,0x1c,0x00, + 0x1c,0x22,0x20,0x18,0x04,0x02,0x3e,0x00, + 0x3e,0x20,0x10,0x18,0x20,0x22,0x1c,0x00, + 0x10,0x18,0x14,0x12,0x3e,0x10,0x10,0x00, + 0x3e,0x02,0x1e,0x20,0x20,0x22,0x1c,0x00, + 0x10,0x08,0x04,0x1c,0x22,0x22,0x1c,0x00, + 0x3e,0x20,0x10,0x08,0x04,0x04,0x04,0x00, + 0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,0x00, + 0x1c,0x22,0x22,0x1c,0x10,0x08,0x04,0x00, + 0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00, + 0x00,0x00,0x08,0x00,0x08,0x08,0x04,0x00, + 0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x00, + 0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,0x00, + 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00, + 0x1c,0x22,0x20,0x10,0x08,0x00,0x08,0x00, + 0x1c,0x22,0x32,0x2a,0x3a,0x02,0x3c,0x00, + 0x08,0x14,0x22,0x22,0x3e,0x22,0x22,0x00, + 0x1e,0x22,0x22,0x1e,0x22,0x22,0x1e,0x00, + 0x1c,0x22,0x02,0x02,0x02,0x22,0x1c,0x00, + 0x1e,0x24,0x24,0x24,0x24,0x24,0x1e,0x00, + 0x3e,0x02,0x02,0x1e,0x02,0x02,0x3e,0x00, + 0x3e,0x02,0x02,0x1e,0x02,0x02,0x02,0x00, + 0x1c,0x22,0x02,0x02,0x32,0x22,0x3c,0x00, + 0x22,0x22,0x22,0x3e,0x22,0x22,0x22,0x00, + 0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,0x00, + 0x38,0x10,0x10,0x10,0x10,0x12,0x0c,0x00, + 0x22,0x12,0x0a,0x06,0x0a,0x12,0x22,0x00, + 0x02,0x02,0x02,0x02,0x02,0x02,0x3e,0x00, + 0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,0x00, + 0x22,0x22,0x26,0x2a,0x32,0x22,0x22,0x00, + 0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,0x00, + 0x1e,0x22,0x22,0x1e,0x02,0x02,0x02,0x00, + 0x1c,0x22,0x22,0x22,0x2a,0x12,0x2c,0x00, + 0x1e,0x22,0x22,0x1e,0x0a,0x12,0x22,0x00, + 0x1c,0x22,0x02,0x1c,0x20,0x22,0x1c,0x00, + 0x3e,0x08,0x08,0x08,0x08,0x08,0x08,0x00, + 0x22,0x22,0x22,0x22,0x22,0x22,0x1c,0x00, + 0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00, + 0x22,0x22,0x22,0x2a,0x2a,0x2a,0x14,0x00, + 0x22,0x22,0x14,0x08,0x14,0x22,0x22,0x00, + 0x22,0x22,0x22,0x14,0x08,0x08,0x08,0x00, + 0x3e,0x20,0x10,0x08,0x04,0x02,0x3e,0x00, + 0x0e,0x02,0x02,0x02,0x02,0x02,0x0e,0x00, + 0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00, + 0x38,0x20,0x20,0x20,0x20,0x20,0x38,0x00, + 0x08,0x1c,0x2a,0x08,0x08,0x08,0x08,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00, + 0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x1c,0x20,0x3c,0x22,0x3c,0x00, + 0x02,0x02,0x1e,0x22,0x22,0x22,0x1e,0x00, + 0x00,0x00,0x3c,0x02,0x02,0x02,0x3c,0x00, + 0x20,0x20,0x3c,0x22,0x22,0x22,0x3c,0x00, + 0x00,0x00,0x1c,0x22,0x3e,0x02,0x1c,0x00, + 0x18,0x04,0x0e,0x04,0x04,0x04,0x04,0x00, + 0x00,0x00,0x3c,0x22,0x22,0x3c,0x20,0x18, + 0x02,0x02,0x1e,0x22,0x22,0x22,0x22,0x00, + 0x08,0x00,0x0c,0x08,0x08,0x08,0x1c,0x00, + 0x10,0x00,0x18,0x10,0x10,0x10,0x12,0x0c, + 0x02,0x02,0x22,0x12,0x0e,0x16,0x22,0x00, + 0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x00, + 0x00,0x00,0x16,0x2a,0x2a,0x2a,0x2a,0x00, + 0x00,0x00,0x1a,0x26,0x22,0x22,0x22,0x00, + 0x00,0x00,0x1c,0x22,0x22,0x22,0x1c,0x00, + 0x00,0x00,0x1e,0x22,0x22,0x1e,0x02,0x02, + 0x00,0x00,0x3c,0x22,0x22,0x3c,0x20,0x20, + 0x00,0x00,0x34,0x0c,0x04,0x04,0x04,0x00, + 0x00,0x00,0x3c,0x02,0x1c,0x20,0x1e,0x00, + 0x08,0x08,0x1c,0x08,0x08,0x08,0x10,0x00, + 0x00,0x00,0x22,0x22,0x22,0x32,0x2c,0x00, + 0x00,0x00,0x22,0x22,0x22,0x14,0x08,0x00, + 0x00,0x00,0x22,0x22,0x2a,0x2a,0x14,0x00, + 0x00,0x00,0x22,0x14,0x08,0x14,0x22,0x00, + 0x00,0x00,0x22,0x22,0x14,0x08,0x04,0x02, + 0x00,0x00,0x3e,0x10,0x08,0x04,0x3e,0x00, + 0x10,0x08,0x08,0x04,0x08,0x08,0x10,0x00, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00, + 0x04,0x08,0x08,0x10,0x08,0x08,0x04,0x00, + 0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x2a,0x15,0x2a,0x15,0x2a,0x15,0x2a,0x15 +}; + +teleprinter_device::teleprinter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : generic_terminal_device(mconfig, TELEPRINTER, tag, owner, clock, WIDTH, HEIGHT) +{ +} + +void teleprinter_device::scroll_line() +{ + memmove(m_buffer.get(), m_buffer.get() + m_width, (m_height-1) * m_width); + memset(m_buffer.get() + m_width * (m_height-1), 0x20, m_width); +} + +void teleprinter_device::write_char(uint8_t data) { + m_buffer[(m_height-1)*m_width+m_x_pos] = data; + m_x_pos++; + if (m_x_pos >= m_width) + { + m_x_pos = 0; + scroll_line(); + } +} + +void teleprinter_device::clear() { + memset(m_buffer.get(), 0, m_width*m_height); + m_x_pos = 0; +} + +void teleprinter_device::term_write(uint8_t data) +{ + switch(data) { + case 10: m_x_pos = 0; + scroll_line(); + break; + case 13: m_x_pos = 0; break; + case 9: m_x_pos = (m_x_pos & 0xf8) + 8; + if (m_x_pos >= m_width) + m_x_pos = m_width-1; + + break; + case 16: break; + default: write_char(data); break; + } +} + +/*************************************************************************** + VIDEO HARDWARE +***************************************************************************/ +uint32_t teleprinter_device::tp_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + for (int y = 0; y < m_height; y++) + { + for (int c = 0; c < 8; c++) + { + int horpos = 0; + for (int x = 0; x < m_width; x++) + { + uint8_t code = teleprinter_font[(m_buffer[y*m_width + x] & 0x7f) *8 + c]; + for (int b = 0; b < 8; b++) + { + bitmap.pix(y*8 + c, horpos++) = (code >> b) & 0x01 ? 0 : 0x00ffffff; + } + } + } + } + return 0; +} + +/*************************************************************************** + VIDEO HARDWARE +***************************************************************************/ +void teleprinter_device::device_add_mconfig(machine_config &config) +{ + screen_device &screen(SCREEN(config, TELEPRINTER_SCREEN_TAG, SCREEN_TYPE_RASTER)); + screen.set_refresh_hz(50); + screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ + screen.set_size(teleprinter_device::WIDTH*8, teleprinter_device::HEIGHT*8); + screen.set_visarea(0, teleprinter_device::WIDTH*8-1, 0, teleprinter_device::HEIGHT*8-1); + screen.set_screen_update(FUNC(teleprinter_device::tp_update)); + generic_keyboard_device &keyboard(GENERIC_KEYBOARD(config, "keyboard", 0)); + keyboard.set_keyboard_callback(FUNC(generic_terminal_device::kbd_put)); + + SPEAKER(config, "bell").front_center(); + BEEP(config, "beeper", 2'000).add_route(ALL_OUTPUTS, "bell", 0.50); +} + + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ + +void teleprinter_device::device_reset() +{ + clear(); + generic_terminal_device::device_reset(); +} + +DEFINE_DEVICE_TYPE(TELEPRINTER, teleprinter_device, "teleprinter", "Teleprinter") diff --git a/src/mame/shared/teleprinter.h b/src/mame/shared/teleprinter.h new file mode 100644 index 00000000000..05eb6c63c8f --- /dev/null +++ b/src/mame/shared/teleprinter.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#ifndef MAME_MACHINE_TELEPRINTER_H +#define MAME_MACHINE_TELEPRINTER_H + +#pragma once + +#include "machine/terminal.h" + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define TELEPRINTER_SCREEN_TAG "tty_screen" + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +class teleprinter_device : public generic_terminal_device +{ +public: + teleprinter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void term_write(uint8_t data) override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + +private: + static constexpr unsigned WIDTH = 80; + static constexpr unsigned HEIGHT = 50; + uint32_t tp_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void scroll_line(); + void write_char(uint8_t data); + void clear(); +}; + +DECLARE_DEVICE_TYPE(TELEPRINTER, teleprinter_device) + +#endif // MAME_MACHINE_TELEPRINTER_H diff --git a/src/mame/shared/vboysound.cpp b/src/mame/shared/vboysound.cpp new file mode 100644 index 00000000000..5cb56eddabf --- /dev/null +++ b/src/mame/shared/vboysound.cpp @@ -0,0 +1,501 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + vboy.c - Virtual Boy audio emulation + + By Richard Bannister and Gil Pedersen. + MAME device adaptation by R. Belmont +*/ + +#include "emu.h" +#include "vboysound.h" + +// device type definition +DEFINE_DEVICE_TYPE(VBOYSND, vboysnd_device, "vboysnd", "Virtual Boy Audio") + +//#define LAME_COMPILER_BUG + +#define SxINT 0x00 +#define SxLRV 0x04 +#define SxFQL 0x08 +#define SxFQH 0x0c +#define SxEV0 0x10 +#define SxEV1 0x14 +#define SxRAM 0x18 + +#define SxINTb 0x400+SxINT +#define SxLRVb 0x400+SxLRV +#define SxFQLb 0x400+SxFQL +#define SxFQHb 0x400+SxFQH +#define SxEV0b 0x400+SxEV0 +#define SxEV1b 0x400+SxEV1 +#define SxRAMb 0x400+SxRAM + +#define S5SWP 0x51c +#define SST0P 0x580 + +static const uint16_t outTbl[64][32] = { + { 0x0000, 0xffe0, 0xffc0, 0xffa0, 0xff80, 0xff60, 0xff40, 0xff20, 0xff00, 0xfee0, 0xfec0, 0xfea0, 0xfe80, 0xfe60, 0xfe40, 0xfe20, + 0xfe00, 0xfde0, 0xfdc0, 0xfda0, 0xfd80, 0xfd60, 0xfd40, 0xfd20, 0xfd00, 0xfce0, 0xfcc0, 0xfca0, 0xfc80, 0xfc60, 0xfc40, 0xfc20}, + { 0x0000, 0xffe1, 0xffc2, 0xffa3, 0xff84, 0xff65, 0xff46, 0xff27, 0xff08, 0xfee9, 0xfeca, 0xfeab, 0xfe8c, 0xfe6d, 0xfe4e, 0xfe2f, + 0xfe10, 0xfdf1, 0xfdd2, 0xfdb3, 0xfd94, 0xfd75, 0xfd56, 0xfd37, 0xfd18, 0xfcf9, 0xfcda, 0xfcbb, 0xfc9c, 0xfc7d, 0xfc5e, 0xfc3f}, + { 0x0000, 0xffe2, 0xffc4, 0xffa6, 0xff88, 0xff6a, 0xff4c, 0xff2e, 0xff10, 0xfef2, 0xfed4, 0xfeb6, 0xfe98, 0xfe7a, 0xfe5c, 0xfe3e, + 0xfe20, 0xfe02, 0xfde4, 0xfdc6, 0xfda8, 0xfd8a, 0xfd6c, 0xfd4e, 0xfd30, 0xfd12, 0xfcf4, 0xfcd6, 0xfcb8, 0xfc9a, 0xfc7c, 0xfc5e}, + { 0x0000, 0xffe3, 0xffc6, 0xffa9, 0xff8c, 0xff6f, 0xff52, 0xff35, 0xff18, 0xfefb, 0xfede, 0xfec1, 0xfea4, 0xfe87, 0xfe6a, 0xfe4d, + 0xfe30, 0xfe13, 0xfdf6, 0xfdd9, 0xfdbc, 0xfd9f, 0xfd82, 0xfd65, 0xfd48, 0xfd2b, 0xfd0e, 0xfcf1, 0xfcd4, 0xfcb7, 0xfc9a, 0xfc7d}, + { 0x0000, 0xffe4, 0xffc8, 0xffac, 0xff90, 0xff74, 0xff58, 0xff3c, 0xff20, 0xff04, 0xfee8, 0xfecc, 0xfeb0, 0xfe94, 0xfe78, 0xfe5c, + 0xfe40, 0xfe24, 0xfe08, 0xfdec, 0xfdd0, 0xfdb4, 0xfd98, 0xfd7c, 0xfd60, 0xfd44, 0xfd28, 0xfd0c, 0xfcf0, 0xfcd4, 0xfcb8, 0xfc9c}, + { 0x0000, 0xffe5, 0xffca, 0xffaf, 0xff94, 0xff79, 0xff5e, 0xff43, 0xff28, 0xff0d, 0xfef2, 0xfed7, 0xfebc, 0xfea1, 0xfe86, 0xfe6b, + 0xfe50, 0xfe35, 0xfe1a, 0xfdff, 0xfde4, 0xfdc9, 0xfdae, 0xfd93, 0xfd78, 0xfd5d, 0xfd42, 0xfd27, 0xfd0c, 0xfcf1, 0xfcd6, 0xfcbb}, + { 0x0000, 0xffe6, 0xffcc, 0xffb2, 0xff98, 0xff7e, 0xff64, 0xff4a, 0xff30, 0xff16, 0xfefc, 0xfee2, 0xfec8, 0xfeae, 0xfe94, 0xfe7a, + 0xfe60, 0xfe46, 0xfe2c, 0xfe12, 0xfdf8, 0xfdde, 0xfdc4, 0xfdaa, 0xfd90, 0xfd76, 0xfd5c, 0xfd42, 0xfd28, 0xfd0e, 0xfcf4, 0xfcda}, + { 0x0000, 0xffe7, 0xffce, 0xffb5, 0xff9c, 0xff83, 0xff6a, 0xff51, 0xff38, 0xff1f, 0xff06, 0xfeed, 0xfed4, 0xfebb, 0xfea2, 0xfe89, + 0xfe70, 0xfe57, 0xfe3e, 0xfe25, 0xfe0c, 0xfdf3, 0xfdda, 0xfdc1, 0xfda8, 0xfd8f, 0xfd76, 0xfd5d, 0xfd44, 0xfd2b, 0xfd12, 0xfcf9}, + { 0x0000, 0xffe8, 0xffd0, 0xffb8, 0xffa0, 0xff88, 0xff70, 0xff58, 0xff40, 0xff28, 0xff10, 0xfef8, 0xfee0, 0xfec8, 0xfeb0, 0xfe98, + 0xfe80, 0xfe68, 0xfe50, 0xfe38, 0xfe20, 0xfe08, 0xfdf0, 0xfdd8, 0xfdc0, 0xfda8, 0xfd90, 0xfd78, 0xfd60, 0xfd48, 0xfd30, 0xfd18}, + { 0x0000, 0xffe9, 0xffd2, 0xffbb, 0xffa4, 0xff8d, 0xff76, 0xff5f, 0xff48, 0xff31, 0xff1a, 0xff03, 0xfeec, 0xfed5, 0xfebe, 0xfea7, + 0xfe90, 0xfe79, 0xfe62, 0xfe4b, 0xfe34, 0xfe1d, 0xfe06, 0xfdef, 0xfdd8, 0xfdc1, 0xfdaa, 0xfd93, 0xfd7c, 0xfd65, 0xfd4e, 0xfd37}, + { 0x0000, 0xffea, 0xffd4, 0xffbe, 0xffa8, 0xff92, 0xff7c, 0xff66, 0xff50, 0xff3a, 0xff24, 0xff0e, 0xfef8, 0xfee2, 0xfecc, 0xfeb6, + 0xfea0, 0xfe8a, 0xfe74, 0xfe5e, 0xfe48, 0xfe32, 0xfe1c, 0xfe06, 0xfdf0, 0xfdda, 0xfdc4, 0xfdae, 0xfd98, 0xfd82, 0xfd6c, 0xfd56}, + { 0x0000, 0xffeb, 0xffd6, 0xffc1, 0xffac, 0xff97, 0xff82, 0xff6d, 0xff58, 0xff43, 0xff2e, 0xff19, 0xff04, 0xfeef, 0xfeda, 0xfec5, + 0xfeb0, 0xfe9b, 0xfe86, 0xfe71, 0xfe5c, 0xfe47, 0xfe32, 0xfe1d, 0xfe08, 0xfdf3, 0xfdde, 0xfdc9, 0xfdb4, 0xfd9f, 0xfd8a, 0xfd75}, + { 0x0000, 0xffec, 0xffd8, 0xffc4, 0xffb0, 0xff9c, 0xff88, 0xff74, 0xff60, 0xff4c, 0xff38, 0xff24, 0xff10, 0xfefc, 0xfee8, 0xfed4, + 0xfec0, 0xfeac, 0xfe98, 0xfe84, 0xfe70, 0xfe5c, 0xfe48, 0xfe34, 0xfe20, 0xfe0c, 0xfdf8, 0xfde4, 0xfdd0, 0xfdbc, 0xfda8, 0xfd94}, + { 0x0000, 0xffed, 0xffda, 0xffc7, 0xffb4, 0xffa1, 0xff8e, 0xff7b, 0xff68, 0xff55, 0xff42, 0xff2f, 0xff1c, 0xff09, 0xfef6, 0xfee3, + 0xfed0, 0xfebd, 0xfeaa, 0xfe97, 0xfe84, 0xfe71, 0xfe5e, 0xfe4b, 0xfe38, 0xfe25, 0xfe12, 0xfdff, 0xfdec, 0xfdd9, 0xfdc6, 0xfdb3}, + { 0x0000, 0xffee, 0xffdc, 0xffca, 0xffb8, 0xffa6, 0xff94, 0xff82, 0xff70, 0xff5e, 0xff4c, 0xff3a, 0xff28, 0xff16, 0xff04, 0xfef2, + 0xfee0, 0xfece, 0xfebc, 0xfeaa, 0xfe98, 0xfe86, 0xfe74, 0xfe62, 0xfe50, 0xfe3e, 0xfe2c, 0xfe1a, 0xfe08, 0xfdf6, 0xfde4, 0xfdd2}, + { 0x0000, 0xffef, 0xffde, 0xffcd, 0xffbc, 0xffab, 0xff9a, 0xff89, 0xff78, 0xff67, 0xff56, 0xff45, 0xff34, 0xff23, 0xff12, 0xff01, + 0xfef0, 0xfedf, 0xfece, 0xfebd, 0xfeac, 0xfe9b, 0xfe8a, 0xfe79, 0xfe68, 0xfe57, 0xfe46, 0xfe35, 0xfe24, 0xfe13, 0xfe02, 0xfdf1}, + { 0x0000, 0xfff0, 0xffe0, 0xffd0, 0xffc0, 0xffb0, 0xffa0, 0xff90, 0xff80, 0xff70, 0xff60, 0xff50, 0xff40, 0xff30, 0xff20, 0xff10, + 0xff00, 0xfef0, 0xfee0, 0xfed0, 0xfec0, 0xfeb0, 0xfea0, 0xfe90, 0xfe80, 0xfe70, 0xfe60, 0xfe50, 0xfe40, 0xfe30, 0xfe20, 0xfe10}, + { 0x0000, 0xfff1, 0xffe2, 0xffd3, 0xffc4, 0xffb5, 0xffa6, 0xff97, 0xff88, 0xff79, 0xff6a, 0xff5b, 0xff4c, 0xff3d, 0xff2e, 0xff1f, + 0xff10, 0xff01, 0xfef2, 0xfee3, 0xfed4, 0xfec5, 0xfeb6, 0xfea7, 0xfe98, 0xfe89, 0xfe7a, 0xfe6b, 0xfe5c, 0xfe4d, 0xfe3e, 0xfe2f}, + { 0x0000, 0xfff2, 0xffe4, 0xffd6, 0xffc8, 0xffba, 0xffac, 0xff9e, 0xff90, 0xff82, 0xff74, 0xff66, 0xff58, 0xff4a, 0xff3c, 0xff2e, + 0xff20, 0xff12, 0xff04, 0xfef6, 0xfee8, 0xfeda, 0xfecc, 0xfebe, 0xfeb0, 0xfea2, 0xfe94, 0xfe86, 0xfe78, 0xfe6a, 0xfe5c, 0xfe4e}, + { 0x0000, 0xfff3, 0xffe6, 0xffd9, 0xffcc, 0xffbf, 0xffb2, 0xffa5, 0xff98, 0xff8b, 0xff7e, 0xff71, 0xff64, 0xff57, 0xff4a, 0xff3d, + 0xff30, 0xff23, 0xff16, 0xff09, 0xfefc, 0xfeef, 0xfee2, 0xfed5, 0xfec8, 0xfebb, 0xfeae, 0xfea1, 0xfe94, 0xfe87, 0xfe7a, 0xfe6d}, + { 0x0000, 0xfff4, 0xffe8, 0xffdc, 0xffd0, 0xffc4, 0xffb8, 0xffac, 0xffa0, 0xff94, 0xff88, 0xff7c, 0xff70, 0xff64, 0xff58, 0xff4c, + 0xff40, 0xff34, 0xff28, 0xff1c, 0xff10, 0xff04, 0xfef8, 0xfeec, 0xfee0, 0xfed4, 0xfec8, 0xfebc, 0xfeb0, 0xfea4, 0xfe98, 0xfe8c}, + { 0x0000, 0xfff5, 0xffea, 0xffdf, 0xffd4, 0xffc9, 0xffbe, 0xffb3, 0xffa8, 0xff9d, 0xff92, 0xff87, 0xff7c, 0xff71, 0xff66, 0xff5b, + 0xff50, 0xff45, 0xff3a, 0xff2f, 0xff24, 0xff19, 0xff0e, 0xff03, 0xfef8, 0xfeed, 0xfee2, 0xfed7, 0xfecc, 0xfec1, 0xfeb6, 0xfeab}, + { 0x0000, 0xfff6, 0xffec, 0xffe2, 0xffd8, 0xffce, 0xffc4, 0xffba, 0xffb0, 0xffa6, 0xff9c, 0xff92, 0xff88, 0xff7e, 0xff74, 0xff6a, + 0xff60, 0xff56, 0xff4c, 0xff42, 0xff38, 0xff2e, 0xff24, 0xff1a, 0xff10, 0xff06, 0xfefc, 0xfef2, 0xfee8, 0xfede, 0xfed4, 0xfeca}, + { 0x0000, 0xfff7, 0xffee, 0xffe5, 0xffdc, 0xffd3, 0xffca, 0xffc1, 0xffb8, 0xffaf, 0xffa6, 0xff9d, 0xff94, 0xff8b, 0xff82, 0xff79, + 0xff70, 0xff67, 0xff5e, 0xff55, 0xff4c, 0xff43, 0xff3a, 0xff31, 0xff28, 0xff1f, 0xff16, 0xff0d, 0xff04, 0xfefb, 0xfef2, 0xfee9}, + { 0x0000, 0xfff8, 0xfff0, 0xffe8, 0xffe0, 0xffd8, 0xffd0, 0xffc8, 0xffc0, 0xffb8, 0xffb0, 0xffa8, 0xffa0, 0xff98, 0xff90, 0xff88, + 0xff80, 0xff78, 0xff70, 0xff68, 0xff60, 0xff58, 0xff50, 0xff48, 0xff40, 0xff38, 0xff30, 0xff28, 0xff20, 0xff18, 0xff10, 0xff08}, + { 0x0000, 0xfff9, 0xfff2, 0xffeb, 0xffe4, 0xffdd, 0xffd6, 0xffcf, 0xffc8, 0xffc1, 0xffba, 0xffb3, 0xffac, 0xffa5, 0xff9e, 0xff97, + 0xff90, 0xff89, 0xff82, 0xff7b, 0xff74, 0xff6d, 0xff66, 0xff5f, 0xff58, 0xff51, 0xff4a, 0xff43, 0xff3c, 0xff35, 0xff2e, 0xff27}, + { 0x0000, 0xfffa, 0xfff4, 0xffee, 0xffe8, 0xffe2, 0xffdc, 0xffd6, 0xffd0, 0xffca, 0xffc4, 0xffbe, 0xffb8, 0xffb2, 0xffac, 0xffa6, + 0xffa0, 0xff9a, 0xff94, 0xff8e, 0xff88, 0xff82, 0xff7c, 0xff76, 0xff70, 0xff6a, 0xff64, 0xff5e, 0xff58, 0xff52, 0xff4c, 0xff46}, + { 0x0000, 0xfffb, 0xfff6, 0xfff1, 0xffec, 0xffe7, 0xffe2, 0xffdd, 0xffd8, 0xffd3, 0xffce, 0xffc9, 0xffc4, 0xffbf, 0xffba, 0xffb5, + 0xffb0, 0xffab, 0xffa6, 0xffa1, 0xff9c, 0xff97, 0xff92, 0xff8d, 0xff88, 0xff83, 0xff7e, 0xff79, 0xff74, 0xff6f, 0xff6a, 0xff65}, + { 0x0000, 0xfffc, 0xfff8, 0xfff4, 0xfff0, 0xffec, 0xffe8, 0xffe4, 0xffe0, 0xffdc, 0xffd8, 0xffd4, 0xffd0, 0xffcc, 0xffc8, 0xffc4, + 0xffc0, 0xffbc, 0xffb8, 0xffb4, 0xffb0, 0xffac, 0xffa8, 0xffa4, 0xffa0, 0xff9c, 0xff98, 0xff94, 0xff90, 0xff8c, 0xff88, 0xff84}, + { 0x0000, 0xfffd, 0xfffa, 0xfff7, 0xfff4, 0xfff1, 0xffee, 0xffeb, 0xffe8, 0xffe5, 0xffe2, 0xffdf, 0xffdc, 0xffd9, 0xffd6, 0xffd3, + 0xffd0, 0xffcd, 0xffca, 0xffc7, 0xffc4, 0xffc1, 0xffbe, 0xffbb, 0xffb8, 0xffb5, 0xffb2, 0xffaf, 0xffac, 0xffa9, 0xffa6, 0xffa3}, + { 0x0000, 0xfffe, 0xfffc, 0xfffa, 0xfff8, 0xfff6, 0xfff4, 0xfff2, 0xfff0, 0xffee, 0xffec, 0xffea, 0xffe8, 0xffe6, 0xffe4, 0xffe2, + 0xffe0, 0xffde, 0xffdc, 0xffda, 0xffd8, 0xffd6, 0xffd4, 0xffd2, 0xffd0, 0xffce, 0xffcc, 0xffca, 0xffc8, 0xffc6, 0xffc4, 0xffc2}, + { 0x0000, 0xffff, 0xfffe, 0xfffd, 0xfffc, 0xfffb, 0xfffa, 0xfff9, 0xfff8, 0xfff7, 0xfff6, 0xfff5, 0xfff4, 0xfff3, 0xfff2, 0xfff1, + 0xfff0, 0xffef, 0xffee, 0xffed, 0xffec, 0xffeb, 0xffea, 0xffe9, 0xffe8, 0xffe7, 0xffe6, 0xffe5, 0xffe4, 0xffe3, 0xffe2, 0xffe1}, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f}, + { 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, 0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x001a, 0x001c, 0x001e, + 0x0020, 0x0022, 0x0024, 0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038, 0x003a, 0x003c, 0x003e}, + { 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, 0x0018, 0x001b, 0x001e, 0x0021, 0x0024, 0x0027, 0x002a, 0x002d, + 0x0030, 0x0033, 0x0036, 0x0039, 0x003c, 0x003f, 0x0042, 0x0045, 0x0048, 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005a, 0x005d}, + { 0x0000, 0x0004, 0x0008, 0x000c, 0x0010, 0x0014, 0x0018, 0x001c, 0x0020, 0x0024, 0x0028, 0x002c, 0x0030, 0x0034, 0x0038, 0x003c, + 0x0040, 0x0044, 0x0048, 0x004c, 0x0050, 0x0054, 0x0058, 0x005c, 0x0060, 0x0064, 0x0068, 0x006c, 0x0070, 0x0074, 0x0078, 0x007c}, + { 0x0000, 0x0005, 0x000a, 0x000f, 0x0014, 0x0019, 0x001e, 0x0023, 0x0028, 0x002d, 0x0032, 0x0037, 0x003c, 0x0041, 0x0046, 0x004b, + 0x0050, 0x0055, 0x005a, 0x005f, 0x0064, 0x0069, 0x006e, 0x0073, 0x0078, 0x007d, 0x0082, 0x0087, 0x008c, 0x0091, 0x0096, 0x009b}, + { 0x0000, 0x0006, 0x000c, 0x0012, 0x0018, 0x001e, 0x0024, 0x002a, 0x0030, 0x0036, 0x003c, 0x0042, 0x0048, 0x004e, 0x0054, 0x005a, + 0x0060, 0x0066, 0x006c, 0x0072, 0x0078, 0x007e, 0x0084, 0x008a, 0x0090, 0x0096, 0x009c, 0x00a2, 0x00a8, 0x00ae, 0x00b4, 0x00ba}, + { 0x0000, 0x0007, 0x000e, 0x0015, 0x001c, 0x0023, 0x002a, 0x0031, 0x0038, 0x003f, 0x0046, 0x004d, 0x0054, 0x005b, 0x0062, 0x0069, + 0x0070, 0x0077, 0x007e, 0x0085, 0x008c, 0x0093, 0x009a, 0x00a1, 0x00a8, 0x00af, 0x00b6, 0x00bd, 0x00c4, 0x00cb, 0x00d2, 0x00d9}, + { 0x0000, 0x0008, 0x0010, 0x0018, 0x0020, 0x0028, 0x0030, 0x0038, 0x0040, 0x0048, 0x0050, 0x0058, 0x0060, 0x0068, 0x0070, 0x0078, + 0x0080, 0x0088, 0x0090, 0x0098, 0x00a0, 0x00a8, 0x00b0, 0x00b8, 0x00c0, 0x00c8, 0x00d0, 0x00d8, 0x00e0, 0x00e8, 0x00f0, 0x00f8}, + { 0x0000, 0x0009, 0x0012, 0x001b, 0x0024, 0x002d, 0x0036, 0x003f, 0x0048, 0x0051, 0x005a, 0x0063, 0x006c, 0x0075, 0x007e, 0x0087, + 0x0090, 0x0099, 0x00a2, 0x00ab, 0x00b4, 0x00bd, 0x00c6, 0x00cf, 0x00d8, 0x00e1, 0x00ea, 0x00f3, 0x00fc, 0x0105, 0x010e, 0x0117}, + { 0x0000, 0x000a, 0x0014, 0x001e, 0x0028, 0x0032, 0x003c, 0x0046, 0x0050, 0x005a, 0x0064, 0x006e, 0x0078, 0x0082, 0x008c, 0x0096, + 0x00a0, 0x00aa, 0x00b4, 0x00be, 0x00c8, 0x00d2, 0x00dc, 0x00e6, 0x00f0, 0x00fa, 0x0104, 0x010e, 0x0118, 0x0122, 0x012c, 0x0136}, + { 0x0000, 0x000b, 0x0016, 0x0021, 0x002c, 0x0037, 0x0042, 0x004d, 0x0058, 0x0063, 0x006e, 0x0079, 0x0084, 0x008f, 0x009a, 0x00a5, + 0x00b0, 0x00bb, 0x00c6, 0x00d1, 0x00dc, 0x00e7, 0x00f2, 0x00fd, 0x0108, 0x0113, 0x011e, 0x0129, 0x0134, 0x013f, 0x014a, 0x0155}, + { 0x0000, 0x000c, 0x0018, 0x0024, 0x0030, 0x003c, 0x0048, 0x0054, 0x0060, 0x006c, 0x0078, 0x0084, 0x0090, 0x009c, 0x00a8, 0x00b4, + 0x00c0, 0x00cc, 0x00d8, 0x00e4, 0x00f0, 0x00fc, 0x0108, 0x0114, 0x0120, 0x012c, 0x0138, 0x0144, 0x0150, 0x015c, 0x0168, 0x0174}, + { 0x0000, 0x000d, 0x001a, 0x0027, 0x0034, 0x0041, 0x004e, 0x005b, 0x0068, 0x0075, 0x0082, 0x008f, 0x009c, 0x00a9, 0x00b6, 0x00c3, + 0x00d0, 0x00dd, 0x00ea, 0x00f7, 0x0104, 0x0111, 0x011e, 0x012b, 0x0138, 0x0145, 0x0152, 0x015f, 0x016c, 0x0179, 0x0186, 0x0193}, + { 0x0000, 0x000e, 0x001c, 0x002a, 0x0038, 0x0046, 0x0054, 0x0062, 0x0070, 0x007e, 0x008c, 0x009a, 0x00a8, 0x00b6, 0x00c4, 0x00d2, + 0x00e0, 0x00ee, 0x00fc, 0x010a, 0x0118, 0x0126, 0x0134, 0x0142, 0x0150, 0x015e, 0x016c, 0x017a, 0x0188, 0x0196, 0x01a4, 0x01b2}, + { 0x0000, 0x000f, 0x001e, 0x002d, 0x003c, 0x004b, 0x005a, 0x0069, 0x0078, 0x0087, 0x0096, 0x00a5, 0x00b4, 0x00c3, 0x00d2, 0x00e1, + 0x00f0, 0x00ff, 0x010e, 0x011d, 0x012c, 0x013b, 0x014a, 0x0159, 0x0168, 0x0177, 0x0186, 0x0195, 0x01a4, 0x01b3, 0x01c2, 0x01d1}, + { 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, 0x0090, 0x00a0, 0x00b0, 0x00c0, 0x00d0, 0x00e0, 0x00f0, + 0x0100, 0x0110, 0x0120, 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01a0, 0x01b0, 0x01c0, 0x01d0, 0x01e0, 0x01f0}, + { 0x0000, 0x0011, 0x0022, 0x0033, 0x0044, 0x0055, 0x0066, 0x0077, 0x0088, 0x0099, 0x00aa, 0x00bb, 0x00cc, 0x00dd, 0x00ee, 0x00ff, + 0x0110, 0x0121, 0x0132, 0x0143, 0x0154, 0x0165, 0x0176, 0x0187, 0x0198, 0x01a9, 0x01ba, 0x01cb, 0x01dc, 0x01ed, 0x01fe, 0x020f}, + { 0x0000, 0x0012, 0x0024, 0x0036, 0x0048, 0x005a, 0x006c, 0x007e, 0x0090, 0x00a2, 0x00b4, 0x00c6, 0x00d8, 0x00ea, 0x00fc, 0x010e, + 0x0120, 0x0132, 0x0144, 0x0156, 0x0168, 0x017a, 0x018c, 0x019e, 0x01b0, 0x01c2, 0x01d4, 0x01e6, 0x01f8, 0x020a, 0x021c, 0x022e}, + { 0x0000, 0x0013, 0x0026, 0x0039, 0x004c, 0x005f, 0x0072, 0x0085, 0x0098, 0x00ab, 0x00be, 0x00d1, 0x00e4, 0x00f7, 0x010a, 0x011d, + 0x0130, 0x0143, 0x0156, 0x0169, 0x017c, 0x018f, 0x01a2, 0x01b5, 0x01c8, 0x01db, 0x01ee, 0x0201, 0x0214, 0x0227, 0x023a, 0x024d}, + { 0x0000, 0x0014, 0x0028, 0x003c, 0x0050, 0x0064, 0x0078, 0x008c, 0x00a0, 0x00b4, 0x00c8, 0x00dc, 0x00f0, 0x0104, 0x0118, 0x012c, + 0x0140, 0x0154, 0x0168, 0x017c, 0x0190, 0x01a4, 0x01b8, 0x01cc, 0x01e0, 0x01f4, 0x0208, 0x021c, 0x0230, 0x0244, 0x0258, 0x026c}, + { 0x0000, 0x0015, 0x002a, 0x003f, 0x0054, 0x0069, 0x007e, 0x0093, 0x00a8, 0x00bd, 0x00d2, 0x00e7, 0x00fc, 0x0111, 0x0126, 0x013b, + 0x0150, 0x0165, 0x017a, 0x018f, 0x01a4, 0x01b9, 0x01ce, 0x01e3, 0x01f8, 0x020d, 0x0222, 0x0237, 0x024c, 0x0261, 0x0276, 0x028b}, + { 0x0000, 0x0016, 0x002c, 0x0042, 0x0058, 0x006e, 0x0084, 0x009a, 0x00b0, 0x00c6, 0x00dc, 0x00f2, 0x0108, 0x011e, 0x0134, 0x014a, + 0x0160, 0x0176, 0x018c, 0x01a2, 0x01b8, 0x01ce, 0x01e4, 0x01fa, 0x0210, 0x0226, 0x023c, 0x0252, 0x0268, 0x027e, 0x0294, 0x02aa}, + { 0x0000, 0x0017, 0x002e, 0x0045, 0x005c, 0x0073, 0x008a, 0x00a1, 0x00b8, 0x00cf, 0x00e6, 0x00fd, 0x0114, 0x012b, 0x0142, 0x0159, + 0x0170, 0x0187, 0x019e, 0x01b5, 0x01cc, 0x01e3, 0x01fa, 0x0211, 0x0228, 0x023f, 0x0256, 0x026d, 0x0284, 0x029b, 0x02b2, 0x02c9}, + { 0x0000, 0x0018, 0x0030, 0x0048, 0x0060, 0x0078, 0x0090, 0x00a8, 0x00c0, 0x00d8, 0x00f0, 0x0108, 0x0120, 0x0138, 0x0150, 0x0168, + 0x0180, 0x0198, 0x01b0, 0x01c8, 0x01e0, 0x01f8, 0x0210, 0x0228, 0x0240, 0x0258, 0x0270, 0x0288, 0x02a0, 0x02b8, 0x02d0, 0x02e8}, + { 0x0000, 0x0019, 0x0032, 0x004b, 0x0064, 0x007d, 0x0096, 0x00af, 0x00c8, 0x00e1, 0x00fa, 0x0113, 0x012c, 0x0145, 0x015e, 0x0177, + 0x0190, 0x01a9, 0x01c2, 0x01db, 0x01f4, 0x020d, 0x0226, 0x023f, 0x0258, 0x0271, 0x028a, 0x02a3, 0x02bc, 0x02d5, 0x02ee, 0x0307}, + { 0x0000, 0x001a, 0x0034, 0x004e, 0x0068, 0x0082, 0x009c, 0x00b6, 0x00d0, 0x00ea, 0x0104, 0x011e, 0x0138, 0x0152, 0x016c, 0x0186, + 0x01a0, 0x01ba, 0x01d4, 0x01ee, 0x0208, 0x0222, 0x023c, 0x0256, 0x0270, 0x028a, 0x02a4, 0x02be, 0x02d8, 0x02f2, 0x030c, 0x0326}, + { 0x0000, 0x001b, 0x0036, 0x0051, 0x006c, 0x0087, 0x00a2, 0x00bd, 0x00d8, 0x00f3, 0x010e, 0x0129, 0x0144, 0x015f, 0x017a, 0x0195, + 0x01b0, 0x01cb, 0x01e6, 0x0201, 0x021c, 0x0237, 0x0252, 0x026d, 0x0288, 0x02a3, 0x02be, 0x02d9, 0x02f4, 0x030f, 0x032a, 0x0345}, + { 0x0000, 0x001c, 0x0038, 0x0054, 0x0070, 0x008c, 0x00a8, 0x00c4, 0x00e0, 0x00fc, 0x0118, 0x0134, 0x0150, 0x016c, 0x0188, 0x01a4, + 0x01c0, 0x01dc, 0x01f8, 0x0214, 0x0230, 0x024c, 0x0268, 0x0284, 0x02a0, 0x02bc, 0x02d8, 0x02f4, 0x0310, 0x032c, 0x0348, 0x0364}, + { 0x0000, 0x001d, 0x003a, 0x0057, 0x0074, 0x0091, 0x00ae, 0x00cb, 0x00e8, 0x0105, 0x0122, 0x013f, 0x015c, 0x0179, 0x0196, 0x01b3, + 0x01d0, 0x01ed, 0x020a, 0x0227, 0x0244, 0x0261, 0x027e, 0x029b, 0x02b8, 0x02d5, 0x02f2, 0x030f, 0x032c, 0x0349, 0x0366, 0x0383}, + { 0x0000, 0x001e, 0x003c, 0x005a, 0x0078, 0x0096, 0x00b4, 0x00d2, 0x00f0, 0x010e, 0x012c, 0x014a, 0x0168, 0x0186, 0x01a4, 0x01c2, + 0x01e0, 0x01fe, 0x021c, 0x023a, 0x0258, 0x0276, 0x0294, 0x02b2, 0x02d0, 0x02ee, 0x030c, 0x032a, 0x0348, 0x0366, 0x0384, 0x03a2}, + { 0x0000, 0x001f, 0x003e, 0x005d, 0x007c, 0x009b, 0x00ba, 0x00d9, 0x00f8, 0x0117, 0x0136, 0x0155, 0x0174, 0x0193, 0x01b2, 0x01d1, + 0x01f0, 0x020f, 0x022e, 0x024d, 0x026c, 0x028b, 0x02aa, 0x02c9, 0x02e8, 0x0307, 0x0326, 0x0345, 0x0364, 0x0383, 0x03a2, 0x03c1} +}; + +static const int8_t outLvlTbl[16][16] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2}, + { 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}, + { 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6}, + { 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8}, + { 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10}, + { 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12}, + { 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 8, 10, 11, 12, 13, 14}, + { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + { 0, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17}, + { 0, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19}, + { 0, 2, 3, 5, 6, 7, 9, 10, 12, 13, 14, 16, 17, 18, 20, 21}, + { 0, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23}, + { 0, 2, 4, 5, 7, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25}, + { 0, 2, 4, 6, 8, 9, 11, 13, 15, 16, 18, 20, 22, 23, 25, 27}, + { 0, 2, 4, 6, 8, 10, 12, 14, 16, 17, 19, 21, 23, 25, 27, 29} +}; + +static inline uint8_t mgetb(uint8_t *ptr) { return *ptr; } +static inline void mputb(uint8_t *ptr, int8_t data) { *ptr = data; } + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vboysnd_device - constructor +//------------------------------------------------- + +vboysnd_device::vboysnd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, VBOYSND, tag, owner, clock) + , device_sound_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vboysnd_device::device_start() +{ + uint32_t rate = clock() / 120; + // create the stream + m_stream = stream_alloc(0, 2, rate); + + m_timer = timer_alloc(FUNC(vboysnd_device::delayed_stream_update), this); + m_timer->adjust(attotime::zero, 0, rate ? attotime::from_hz(rate / 4) : attotime::never); + + for (int i=0; i<2048; i++) + waveFreq2LenTbl[i] = ((2048 - i) * 32) / 120; + for (int i=0; i<32; i++) + waveTimer2LenTbl[i] = (i+1) * 120; + for (int i=0; i<8; i++) + waveEnv2LenTbl[i] = (i + 1) * 4 * 120; + + for (int i = 0; i < 5; i++) + memset(&snd_channel[i], 0, sizeof(s_snd_channel)); + + memset(m_aram, 0, 0x600); +} + + +//------------------------------------------------- +// device_clock_changed +//------------------------------------------------- + +void vboysnd_device::device_clock_changed() +{ + uint32_t rate = clock() / 120; + m_stream->set_sample_rate(rate); + + m_timer->adjust(attotime::zero, 0, rate ? attotime::from_hz(rate / 4) : attotime::never); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vboysnd_device::device_reset() +{ + m_stream->update(); + + int i; + + for (i=0; i<4; i++) + snd_channel[i].playing = false; +} + +//------------------------------------------------- +// delayed_stream_update +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(vboysnd_device::delayed_stream_update) +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void vboysnd_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + int len, i, j, channel; + + auto &outL = outputs[0]; + auto &outR = outputs[1]; + + len = outL.samples(); + +// if (mgetb(m_aram+SST0P) & 0x1) // Sound Stop Reg +// goto end; + + for (channel=0; channel<5; channel++) + { + float size; + int k = 0, waveAddr; + + i = channel * 0x40; + snd_channel[channel].sample_len = waveFreq2LenTbl[((mgetb(m_aram+SxFQHb+i) & 0x7) << 8) | mgetb(m_aram+SxFQLb+i)]; + waveAddr = (mgetb(m_aram + SxRAMb + i) & 0x3) << 7; + + size = (float)snd_channel[channel].sample_len / 32.0f; + for (j=0; j<32;) + { + int8_t byte = mgetb(m_aram + waveAddr + (j++ << 2)) & 0x3f; +// int8_t nbyte = mgetb(m_aram + waveAddr + (j << 2)) & 0x3f; + int end = (int)(((float)j)*size); + float val, add; + + val = (float)byte; + add = /*(nbyte-byte)/(end-k)*/ 0.0; // no interpolation + + for (; kplaying) + continue; + + outLeft = outLvlTbl[channel->volLeft][channel->envelope]; + outRight = outLvlTbl[channel->volRight][channel->envelope]; +// env1 = ((uint8_t)mgetb(m_aram+SxEV1b+i*0x40)); + if (channel->env1 & 0x01) + { + channel->env_time++; + +// env0 = ((uint8_t)mgetb(m_aram+SxEV0b+i*0x40)); + if (channel->env_time >= channel->env_steptime /*waveEnv2LenTbl[env0 & 0x7]*/) + { + // it's time for a step + channel->env_time = 0; + if (channel->env0 & 0x08) + { + // step up + channel->envelope++; + if (channel->envelope >= 0xf) + { + if (channel->env1 & 0x02) channel->envelope = channel->env0 >> 4; + else { channel->env1 &= ~0x01; channel->envelope = 0xf; } + } + } + else + { + // step down + channel->envelope--; + if (channel->envelope <= 0) + { + if (channel->env1 & 0x02) channel->envelope = channel->env0 >> 4; + else { channel->env1 &= ~0x01; channel->envelope = 0x0; } + } + } + } + } + + outTblPtr = (int16_t *) outTbl[channel->sample[channel->offset]]; + if (outLeft) note_left += outTblPtr[outLeft ]; + if (outRight) note_right += outTblPtr[outRight]; + channel->offset++; + + if (channel->offset >= channel->sample_len) + channel->offset = 0; + + if (channel->time > 0) + { + channel->time--; + if (channel->time <= 0) + channel->playing = false; + } + } + + + // scale to 16 bits + note_left = (note_left << 5) | ((note_left >> 6) & 0x1f); + note_right = (note_right << 5) | ((note_right >> 6) & 0x1f); + + outL.put_int_clamp(j, (int16_t)note_left, 32768); + outR.put_int_clamp(j, (int16_t)note_right, 32768); + } +} + +//------------------------------------------------- +// read - read from the chip's registers and internal RAM +//------------------------------------------------- + +uint8_t vboysnd_device::read(offs_t offset) +{ + m_stream->update(); + return m_aram[offset]; +} + +//------------------------------------------------- +// write - write to the chip's registers and internal RAM +//------------------------------------------------- + +void vboysnd_device::write(offs_t offset, uint8_t data) +{ + int freq, i; +// int waveAddr; + int volReg, intervalReg; + int channel, ouroffs; + + mputb((uint8_t *)m_aram+offset, data); + if (offset < 0x400) + return; + + channel = (offset-0x400) >> 6; + ouroffs = offset & 0x3f; + + ///process_sound(cpu.vcount); + + if (channel == 6 && ouroffs == 0) + { + if (mgetb(m_aram+SST0P) & 0x1) + for (i=0; i<4; i++) + snd_channel[i].playing = 0; + return; + } + + // Extract frequencies and build the wave for the first 4 sound sources + i = channel * 0x40; + switch (ouroffs) + { + case SxLRV: + if (channel < 5) + { + volReg = mgetb(m_aram + SxLRVb + i); // 6-4-4 - L/R output level setting + if (snd_channel[channel].playing) + { + snd_channel[channel].volLeft = ((uint8_t)volReg) >> 4; + snd_channel[channel].volRight = ((uint8_t)volReg) & 0xf; + break; + } + } + [[fallthrough]]; // FIXME: really? + case SxINT: + if (channel < 5) + { + uint8_t env0, env1; + // find out if the sound is playing + intervalReg = mgetb(m_aram + SxINTb + i); // 6-4-6 - Sound Interval + volReg = mgetb(m_aram + SxLRVb + i); // 6-4-4 - L/R output level setting + + if (((intervalReg & 0x80) == 0) || (volReg == 0)) + { + snd_channel[channel].playing = false; + return; + } + snd_channel[channel].playing = true; + + // 6-4-1 - Waveform address comes from SxRAM. +// waveAddr = (mgetb(m_aram + SxRAMb + i) & 0x3) << 7; + + // 6-4-15 - Frequency comes from here + freq = ((mgetb(m_aram+SxFQHb+i) & 0x7) << 8) | mgetb(m_aram+SxFQLb+i); + + env0 = mgetb(m_aram+SxEV0b+i); env1 = mgetb(m_aram+SxEV1b+i); + snd_channel[channel].env0 = env0; + snd_channel[channel].env1 = env1; + snd_channel[channel].volLeft = ((uint8_t)volReg) >> 4; + snd_channel[channel].volRight = ((uint8_t)volReg) & 0xf; + snd_channel[channel].env_steptime = (env1 & 0x1) ? waveEnv2LenTbl[env0 & 0x7] : 0; + snd_channel[channel].sample_len = waveFreq2LenTbl[freq]; + + snd_channel[channel].offset = 0; + snd_channel[channel].time = (intervalReg & 0x20) ? waveTimer2LenTbl[intervalReg & 0x1f] : 0; + snd_channel[channel].envelope = ((uint8_t)mgetb(m_aram+SxEV0b+i)) >> 4; + snd_channel[channel].env_time = 0; + } + else + { + intervalReg = mgetb(m_aram + SxINTb + i); // 6-4-6 - Sound Interval + volReg = mgetb(m_aram + SxLRVb + i); // 6-4-4 - L/R output level setting + + if (((intervalReg & 0x80) == 0) || (volReg == 0)) + { +// snd_channel[channel].playing = false; + return; + } +// Debugger(); // uses white noise +// snd_channel[channel].playing = true; + } + break; + + case SxEV0: + if (channel < 5) + if (snd_channel[channel].playing) + snd_channel[channel].envelope = ((uint8_t)mgetb(m_aram+SxEV0b+i)) >> 4; + break; + } +} diff --git a/src/mame/shared/vboysound.h b/src/mame/shared/vboysound.h new file mode 100644 index 00000000000..11f8dbc44b8 --- /dev/null +++ b/src/mame/shared/vboysound.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + vboy.h - Virtual Boy audio emulation + + By Richard Bannister and Gil Pedersen. + MAME device adaptation by R. Belmont +*/ +#ifndef MAME_AUDIO_VBOY_H +#define MAME_AUDIO_VBOY_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vboysnd_device + +class vboysnd_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + vboysnd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 5'000'000); + + uint8_t read(offs_t offset); + void write(offs_t offset, uint8_t data); + + sound_stream *m_stream = nullptr; + +protected: + static constexpr unsigned CHANNELS = 4; + + struct s_snd_channel { + int8_t playing = 0; // the sound is playing + + // state when sound was enabled + uint32_t env_steptime = 0; // Envelope step time + uint8_t env0 = 0; // Envelope data + uint8_t env1 = 0; // Envelope data + uint8_t volLeft = 0; // Left output volume + uint8_t volRight = 0; // Right output volume + uint8_t sample[580]{}; // sample to play + int sample_len = 0; // length of sample + + // values that change, as the sample is played + int offset = 0; // current offset in sample + int time = 0; // the duration that this sample is to be played + uint8_t envelope = 0; // Current envelope level (604) + int env_time = 0; // The duration between envelope decay/grow (608) + }; + + struct s_regchan { + int32_t sINT; + int32_t sLRV; + int32_t sFQL; + int32_t sFQH; + int32_t sEV0; + int32_t sEV1; + int32_t sRAM; + }; + + struct s_sreg { + // Sound registers structure + s_regchan c[4]; + }; + + // device-level overrides + virtual void device_start() override; + virtual void device_clock_changed() override; + virtual void device_reset() override; + + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + + TIMER_CALLBACK_MEMBER(delayed_stream_update); + + s_snd_channel snd_channel[5]; + + uint16_t waveFreq2LenTbl[2048]; + uint16_t waveTimer2LenTbl[32]; + uint16_t waveEnv2LenTbl[8]; + + emu_timer *m_timer = nullptr; + + uint8_t m_aram[0x600]; +}; + +// device type definition +DECLARE_DEVICE_TYPE(VBOYSND, vboysnd_device) + +#endif //MAME_AUDIO_VBOY_H diff --git a/src/mame/shared/vt100_kbd.cpp b/src/mame/shared/vt100_kbd.cpp new file mode 100644 index 00000000000..70d5fb7cb4d --- /dev/null +++ b/src/mame/shared/vt100_kbd.cpp @@ -0,0 +1,541 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic, Jonathan Gevaryahu, AJR +/*************************************************************************** + + DEC VT100 keyboard emulation + + All data to and from the keyboard is transmitted over a single + bidirectional wire. The clock that runs the keyboard's UART and + scan counters is multiplexed with the serial data signal. + + MS7002 is a Soviet clone of the VT100 keyboard. It features a + bit-paired JCUKEN layout and Russian/Latin mode select keys, but + the codes it produces are mostly the same, as is the electrical + interface. + +***************************************************************************/ + +#include "emu.h" +#include "vt100_kbd.h" + +#include "logmacro.h" + + +//************************************************************************** +// VT100 KEYBOARD DEVICE +//************************************************************************** + +DEFINE_DEVICE_TYPE(VT100_KEYBOARD, vt100_keyboard_device, "vt100_kbd", "VT100 Keyboard") + +static INPUT_PORTS_START(vt100_kbd) + PORT_START("LINE0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + + PORT_START("LINE1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num Enter") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num ,") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + + PORT_START("LINE2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + + PORT_START("LINE3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Delete") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + + PORT_START("LINE4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Num Return") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("]") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("~") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("=") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line feed") PORT_CODE(KEYCODE_RALT) PORT_CHAR(0x0a) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("LINE5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("[") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\\") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("'") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + + PORT_START("LINE6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + + PORT_START("LINE7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + + PORT_START("LINE8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + + PORT_START("LINE9") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + + PORT_START("LINEA") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("No scroll") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + + PORT_START("LINEB") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Setup") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + + PORT_START("LINEC") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + + PORT_START("LINED") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + + PORT_START("LINEE") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_TOGGLE + + PORT_START("LINEF") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) // Always return 0x7f on last scan line +INPUT_PORTS_END + + +//------------------------------------------------- +// vt100_keyboard_device - constructor +//------------------------------------------------- + +vt100_keyboard_device::vt100_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : vt100_keyboard_device(mconfig, VT100_KEYBOARD, tag, owner, clock) +{ +} + +vt100_keyboard_device::vt100_keyboard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , m_signal_out_cb(*this) + , m_uart(*this, "uart") + , m_speaker(*this, "beeper") + , m_scan_counter(*this, "counter") + , m_key_row(*this, "LINE%X", 0) + , m_online_led(*this, "online_led") + , m_local_led(*this, "local_led") + , m_locked_led(*this, "locked_led") + , m_ln_led(*this, "l%u_led", 1U) + , m_signal_line(true) + , m_last_signal_change(attotime::zero) + , m_last_scan(0) +{ +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void vt100_keyboard_device::device_add_mconfig(machine_config &config) +{ + SPEAKER(config, "mono").front_center(); + BEEP(config, m_speaker, 786); // 7.945us per serial clock = ~125865.324hz, / 160 clocks per char = ~ 786 hz + m_speaker->add_route(ALL_OUTPUTS, "mono", 0.50); + + AY31015(config, m_uart); + m_uart->write_so_callback().set(FUNC(vt100_keyboard_device::signal_out_w)); + + RIPPLE_COUNTER(config, m_scan_counter); // 2x 74LS93 + m_scan_counter->set_stages(8); + m_scan_counter->count_out_cb().set(FUNC(vt100_keyboard_device::key_scan_w)); +} + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vt100_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(vt100_kbd); +} + + +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void vt100_keyboard_device::device_resolve_objects() +{ + m_signal_out_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vt100_keyboard_device::device_start() +{ + if (!m_uart->started()) + throw device_missing_dependencies(); + + m_uart->write_tsb(0); + m_uart->write_eps(1); + m_uart->write_np(1); + m_uart->write_nb1(1); + m_uart->write_nb2(1); + m_uart->write_cs(1); + m_uart->write_swe(0); + + m_online_led.resolve(); + m_local_led.resolve(); + m_locked_led.resolve(); + m_ln_led.resolve(); + + m_online_led = 0; + m_local_led = 1; + m_locked_led = 1; + for (int n = 0; n < 4; n++) + m_ln_led[n] = 1; + + save_item(NAME(m_signal_line)); + save_item(NAME(m_last_signal_change)); + save_item(NAME(m_last_scan)); +} + + +//------------------------------------------------- +// signal_line_w - handle external serial input +//------------------------------------------------- + +WRITE_LINE_MEMBER(vt100_keyboard_device::signal_line_w) +{ + if (m_signal_line == bool(state)) + return; + + if (machine().time() > m_last_signal_change + attotime::from_usec(5)) + m_uart->write_si(m_signal_line); + + if (scan_enabled()) + m_scan_counter->clock_w(state); + + if (state) + { + bool dav = m_uart->dav_r(); + m_uart->write_rdav(!dav); + + if (dav) + { + u8 data = m_uart->receive(); + m_online_led = BIT(data, 5) ? 1 : 0; + m_local_led = BIT(data, 5) ? 0 : 1; + m_locked_led = BIT(data, 4) ? 0 : 1; + for (int n = 0; n < 4; n++) + m_ln_led[n] = BIT(data, 3 - n) ? 0 : 1; + m_speaker->set_state(BIT(data, 7)); + + if (BIT(data, 6)) + { + m_scan_counter->reset_w(0); + scan_start(); + } + } + } + + m_uart->write_rcp(state); + m_uart->write_tcp(state); + + m_signal_line = bool(state); + m_last_signal_change = machine().time(); +} + + +//------------------------------------------------- +// signal_out_w - transmit serial keyboard output +//------------------------------------------------- + +WRITE_LINE_MEMBER(vt100_keyboard_device::signal_out_w) +{ + m_signal_out_cb(state); +} + + +//------------------------------------------------- +// key_scan_w - handle scan counter outputs +//------------------------------------------------- + +void vt100_keyboard_device::key_scan_w(u8 data) +{ + if (BIT(data, 0)) + { + u8 input_row = m_key_row[(data >> 1) & 15]->read(); + if (!BIT(input_row, (data >> 5) & 7)) + { + if (data != 0xff) + LOG("Keycode pressed: %02X\n", (data >> 1) & 0x7f); + m_uart->transmit((data >> 1) & 0x7f); + } + } + + if (!BIT(data, 7) && BIT(m_last_scan, 7)) + { + m_last_scan = 0; + m_scan_counter->reset_w(1); + } + else + m_last_scan = data; +} + + +//************************************************************************** +// MS7002 KEYBOARD DEVICE +//************************************************************************** + +DEFINE_DEVICE_TYPE(MS7002, ms7002_device, "ms7002", "MS7002 Keyboard") + +static INPUT_PORTS_START(ms7002) + PORT_START("LINE0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + + PORT_START("LINE1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\x92\xd0\x9e\xd0\x94") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + + PORT_START("LINE2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9b\xd0\x90\xd0\xa2") // ЛАТ = латинские + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa4" "2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + + PORT_START("LINE3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('_') // note that this does NOT double as Ъ + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x97\xd0\x91") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // ЗБ = забой + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa0\xd0\x92") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // ПРВ = перерыв + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\xa8") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x08) // ВШ = возврат на шаг + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + + PORT_START("LINE4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\x9a") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(0x0d) // ВК = возврат каретки + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa9 ]") PORT_CODE(KEYCODE_O) PORT_CHAR('}') PORT_CHAR(']') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa7 \xc2\xac") PORT_CODE(KEYCODE_X) PORT_CHAR(0x203e, '~') PORT_CHAR(0xac, '^') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR(';') PORT_CHAR('+') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') PORT_CHAR('=') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('0') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f\xd0\xa1") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(0x0a) // ПС = перевод строки + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("LINE5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9f P") PORT_CODE(KEYCODE_G) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa8 [") PORT_CODE(KEYCODE_I) PORT_CHAR('{') PORT_CHAR('[') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(':') PORT_CHAR('*') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa0\xd0\xa3\xd0\xa1") // РУС = русские + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xad \\") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('|') PORT_CHAR('\\') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) // possibly Keypad 9 + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('/') PORT_CHAR('?') + + PORT_START("LINE6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9e O") PORT_CODE(KEYCODE_J) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x98 I") PORT_CODE(KEYCODE_B) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9b L") PORT_CODE(KEYCODE_K) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xae @") PORT_CODE(KEYCODE_STOP) PORT_CHAR('`') PORT_CHAR('@') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RALT) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9c M") PORT_CODE(KEYCODE_V) PORT_CHAR('m') PORT_CHAR('M') + + PORT_START("LINE7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xab Y") PORT_CODE(KEYCODE_S) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR(0x19) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa3 U") PORT_CODE(KEYCODE_E) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR(0x15) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('7') PORT_CHAR('\'') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9a K") PORT_CODE(KEYCODE_R) PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR(0x0b) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x99 J") PORT_CODE(KEYCODE_Q) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x9d N") PORT_CODE(KEYCODE_Y) PORT_CHAR('n') PORT_CHAR('N') PORT_CHAR(0x0e) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + + PORT_START("LINE8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa2 T") PORT_CODE(KEYCODE_N) PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa0 R") PORT_CODE(KEYCODE_H) PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 \xc2\xa4") PORT_CODE(KEYCODE_5) PORT_CHAR('4') PORT_CHAR(0xa4, '$') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x93 G") PORT_CODE(KEYCODE_U) PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa5 H") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x91 B") PORT_CODE(KEYCODE_COMMA) PORT_CHAR('b') PORT_CHAR('B') PORT_CHAR(0x02) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x96 V") PORT_CODE(KEYCODE_COLON) PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16) + + PORT_START("LINE9") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92 W") PORT_CODE(KEYCODE_D) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x95 E") PORT_CODE(KEYCODE_T) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa4 F") PORT_CODE(KEYCODE_A) PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x94 D") PORT_CODE(KEYCODE_L) PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xac X") PORT_CODE(KEYCODE_M) PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa6 C") PORT_CODE(KEYCODE_W) PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03) + + PORT_START("LINEA") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xaf Q") PORT_CODE(KEYCODE_Z) PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x90\xd0\xa0" "2") PORT_CODE(KEYCODE_ESC) PORT_CHAR(0x1b) // АР2 = авторегистр 2 + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa2\xd0\x90\xd0\x91") PORT_CODE(KEYCODE_TAB) PORT_CHAR(0x09) // ТАБ = табуляция + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x90 A") PORT_CODE(KEYCODE_F) PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa1 S") PORT_CODE(KEYCODE_C) PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa1\xd0\xa2\xd0\x9e\xd0\x9f") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // СТОП + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x97 Z") PORT_CODE(KEYCODE_P) PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a) + + PORT_START("LINEB") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa3\xd0\xa1\xd0\xa2") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5) ) // УСТ = установка + + PORT_START("LINEC") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa3\xd0\x9f\xd0\xa0") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) // УПР = управляющий + + PORT_START("LINED") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\xa1\xd0\x94\xd0\x92") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // СДВ = сдвинуть + + PORT_START("LINEE") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xd0\x92\xd0\xa0") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_TOGGLE // ВР = верхний регистр + + PORT_START("LINEF") + PORT_BIT(0x7F, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) // Always return 0x7f on last scan line +INPUT_PORTS_END + + +//------------------------------------------------- +// ms7002_device - constructor +//------------------------------------------------- + +ms7002_device::ms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : vt100_keyboard_device(mconfig, MS7002, tag, owner, clock) + , m_scan_enable(false) +{ +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void ms7002_device::device_add_mconfig(machine_config &config) +{ + vt100_keyboard_device::device_add_mconfig(config); + + subdevice("uart")->write_tbmt_callback().set(FUNC(ms7002_device::scan_disable_w)); +} + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor ms7002_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ms7002); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ms7002_device::device_start() +{ + vt100_keyboard_device::device_start(); + + save_item(NAME(m_scan_enable)); +} + + +//------------------------------------------------- +// scan_disable_w - suspend scan count once +// keycode is being transmitted +//------------------------------------------------- + +WRITE_LINE_MEMBER(ms7002_device::scan_disable_w) +{ + if (!state) + m_scan_enable = false; +} diff --git a/src/mame/shared/vt100_kbd.h b/src/mame/shared/vt100_kbd.h new file mode 100644 index 00000000000..9b6f15a490d --- /dev/null +++ b/src/mame/shared/vt100_kbd.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic, Jonathan Gevaryahu, AJR +/*************************************************************************** + + DEC VT100 keyboard emulation + +***************************************************************************/ + +#ifndef MAME_MACHINE_VT100_KBD_H +#define MAME_MACHINE_VT100_KBD_H + +#pragma once + +#include "machine/ay31015.h" +#include "machine/ripple_counter.h" +#include "sound/beep.h" +#include "speaker.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vt100_keyboard_device + +class vt100_keyboard_device : public device_t +{ +public: + // construction/destruction + vt100_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + // configuration + auto signal_out_callback() { return m_signal_out_cb.bind(); } + + DECLARE_WRITE_LINE_MEMBER(signal_line_w); + +protected: + vt100_keyboard_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_add_mconfig(machine_config &config) override; + virtual ioport_constructor device_input_ports() const override; + + virtual bool scan_enabled() const { return m_uart->tbmt_r(); } + virtual void scan_start() { } + +private: + // internal helpers + DECLARE_WRITE_LINE_MEMBER(signal_out_w); + DECLARE_WRITE_LINE_MEMBER(scan_disable_w); + void key_scan_w(u8 data); + + devcb_write_line m_signal_out_cb; + + required_device m_uart; + required_device m_speaker; + required_device m_scan_counter; + required_ioport_array<16> m_key_row; + + output_finder<> m_online_led; + output_finder<> m_local_led; + output_finder<> m_locked_led; + output_finder<4> m_ln_led; + + bool m_signal_line; + attotime m_last_signal_change; + u8 m_last_scan; +}; + +// ======================> ms7002_device + +class ms7002_device : public vt100_keyboard_device +{ +public: + // construction/destruction + ms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual void device_start() override; + virtual void device_add_mconfig(machine_config &config) override; + virtual ioport_constructor device_input_ports() const override; + + virtual bool scan_enabled() const override { return m_scan_enable; } + virtual void scan_start() override { m_scan_enable = true; } + +private: + DECLARE_WRITE_LINE_MEMBER(scan_disable_w); + + bool m_scan_enable; +}; + +// device type definitions +DECLARE_DEVICE_TYPE(VT100_KEYBOARD, vt100_keyboard_device) +DECLARE_DEVICE_TYPE(MS7002, ms7002_device) + +#endif // MAME_MACHINE_VT100_KBD_H diff --git a/src/mame/shared/wswansound.cpp b/src/mame/shared/wswansound.cpp new file mode 100644 index 00000000000..773bfda4948 --- /dev/null +++ b/src/mame/shared/wswansound.cpp @@ -0,0 +1,387 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/************************************************************************************** + + Wonderswan sound emulation + + Wilbert Pol + + Sound emulation is preliminary and not complete + + +The noise taps and behavior are the same as the Virtual Boy. + +**************************************************************************************/ + +#include "emu.h" +#include "wswansound.h" + + +// device type definition +DEFINE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device, "wswan_sound", "WonderSwan Custom Sound") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wswan_sound_device - constructor +//------------------------------------------------- + +wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, WSWAN_SND, tag, owner, clock), + device_sound_interface(mconfig, *this), + device_rom_interface(mconfig, *this), + m_channel(nullptr), + m_sweep_step(0), + m_sweep_time(0), + m_sweep_count(0), + m_noise_type(0), + m_noise_reset(0), + m_noise_enable(0), + m_noise_output(0), + m_sample_address(0), + m_audio2_voice(0), + m_audio3_sweep(0), + m_audio4_noise(0), + m_mono(0), + m_output_volume(0), + m_external_stereo(0), + m_external_speaker(0), + m_noise_shift(0), + m_master_volume(0) +{ +} + +static constexpr int clk_div = 64; + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wswan_sound_device::device_start() +{ + m_channel = stream_alloc(0, 2, clock() / clk_div); + + save_item(NAME(m_sweep_step)); + save_item(NAME(m_sweep_time)); + save_item(NAME(m_sweep_count)); + save_item(NAME(m_noise_type)); + save_item(NAME(m_noise_reset)); + save_item(NAME(m_noise_enable)); + save_item(NAME(m_sample_address)); + save_item(NAME(m_audio2_voice)); + save_item(NAME(m_audio3_sweep)); + save_item(NAME(m_audio4_noise)); + save_item(NAME(m_mono)); + save_item(NAME(m_output_volume)); + save_item(NAME(m_external_stereo)); + save_item(NAME(m_external_speaker)); + save_item(NAME(m_noise_shift)); + save_item(NAME(m_master_volume)); + save_item(NAME(m_system_volume)); + save_item(STRUCT_MEMBER(m_audio, freq)); + save_item(STRUCT_MEMBER(m_audio, period)); + save_item(STRUCT_MEMBER(m_audio, pos)); + save_item(STRUCT_MEMBER(m_audio, vol_left)); + save_item(STRUCT_MEMBER(m_audio, vol_right)); + save_item(STRUCT_MEMBER(m_audio, on)); + save_item(STRUCT_MEMBER(m_audio, offset)); + save_item(STRUCT_MEMBER(m_audio, signal)); +} + +void wswan_sound_device::device_clock_changed() +{ + m_channel->set_sample_rate(clock() / clk_div); +} + +void wswan_sound_device::rom_bank_updated() +{ + m_channel->update(); +} + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void wswan_sound_device::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_audio[i].on = 0; + m_audio[i].signal = 0; + m_audio[i].offset = 0; + m_audio[i].pos = 0; + } + m_noise_output = 0; +} + +int wswan_sound_device::fetch_sample(int channel, int offset) +{ + u16 w = read_word(m_sample_address + ((channel & 3) << 4) + ((offset >> 1) & 0x0e)); + + return (w >> ((offset & 0x03) * 4)) & 0x0f; +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void wswan_sound_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + auto &outputl = outputs[0]; + auto &outputr = outputs[1]; + for (int sampindex = 0; sampindex < outputl.samples(); sampindex++) + { + s32 left = 0, right = 0; + + if (m_audio[0].on) + { + s32 sample = m_audio[0].signal; + m_audio[0].pos += clk_div; + if (m_audio[0].pos >= m_audio[0].period) + { + m_audio[0].pos -= m_audio[0].period; + m_audio[0].signal = fetch_sample(0, m_audio[0].offset++); + } + left += m_audio[0].vol_left * sample; + right += m_audio[0].vol_right * sample; + } + + if (m_audio[1].on) + { + if (m_audio2_voice) + { + u8 voice_data = (m_audio[1].vol_left << 4) | m_audio[1].vol_right; + left += voice_data * (m_master_volume & 0x0f); + right += voice_data * (m_master_volume & 0x0f); + } + else + { + s32 sample = m_audio[1].signal; + m_audio[1].pos += clk_div; + if (m_audio[1].pos >= m_audio[1].period) + { + m_audio[1].pos -= m_audio[1].period; + m_audio[1].signal = fetch_sample(1, m_audio[1].offset++); + } + left += m_audio[1].vol_left * sample; + right += m_audio[1].vol_right * sample; + } + } + + if (m_audio[2].on) + { + s32 sample = m_audio[2].signal; + m_audio[2].pos += clk_div; + if (m_audio[2].pos >= m_audio[2].period) + { + m_audio[2].pos -= m_audio[2].period; + m_audio[2].signal = fetch_sample(2, m_audio[2].offset++); + } + if (m_audio3_sweep && m_sweep_time) + { + m_sweep_count += clk_div; + if (m_sweep_count >= m_sweep_time) + { + m_sweep_count -= m_sweep_time; + m_audio[2].freq += m_sweep_step; + m_audio[2].freq &= 0x7ff; + m_audio[2].period = 2048 - m_audio[2].freq; + } + } + left += m_audio[2].vol_left * sample; + right += m_audio[2].vol_right * sample; + } + + if (m_audio[3].on) + { + s32 sample = m_audio[3].signal; + m_audio[3].pos += clk_div; + if (m_audio[3].pos >= m_audio[3].period) + { + if (m_audio4_noise) + m_audio[3].signal = m_noise_output ? 0xf : 0; + else + m_audio[3].signal = fetch_sample(3, m_audio[3].offset++); + + m_audio[3].pos -= m_audio[3].period; + + if (m_noise_reset) + { + m_noise_reset = 0; + m_noise_shift = 0; + m_noise_output = 0; + } + + if (m_noise_enable) + { + static int shift_bit[] = { 14, 10, 13, 4, 8, 6, 9, 11 }; + + m_noise_output = (1 ^ (m_noise_shift >> 7) ^ (m_noise_shift >> shift_bit[m_noise_type])) & 1; + m_noise_shift = m_noise_shift << 1 | m_noise_output; + } + } + left += m_audio[3].vol_left * sample; + right += m_audio[3].vol_right * sample; + } + + outputl.put_int(sampindex, left, 32768 >> 5); + outputr.put_int(sampindex, right, 32768 >> 5); + } +} + + +u16 wswan_sound_device::port_r(offs_t offset, u16 mem_mask) +{ + m_channel->update(); + switch (offset) { + case 0x80 / 2: + case 0x82 / 2: + case 0x84 / 2: + case 0x86 / 2: + return m_audio[offset & 0x03].freq; + case 0x88 / 2: + return (m_audio[0].vol_left << 4) | m_audio[0].vol_right | + (m_audio[1].vol_left << 12) | (m_audio[1].vol_right << 8); + case 0x8a / 2: + return (m_audio[2].vol_left << 4) | m_audio[2].vol_right | + (m_audio[3].vol_left << 12) | (m_audio[3].vol_right << 8); + case 0x8c / 2: + return m_sweep_step | (((m_sweep_time / 8192) - 1) << 8); + case 0x8e / 2: + return m_noise_type | (m_noise_reset ? 0x08 : 0x00) | (m_noise_enable ? 0x10 : 0x00) | + ((m_sample_address << 2) & 0xff00); + case 0x90 / 2: + return (m_audio[0].on ? 0x01 : 0x00) | + (m_audio[1].on ? 0x02 : 0x00) | + (m_audio[2].on ? 0x04 : 0x00) | + (m_audio[3].on ? 0x08 : 0x00) | + (m_audio2_voice ? 0x20 : 0x00) | + (m_audio3_sweep ? 0x40 : 0x00) | + (m_audio4_noise ? 0x80 : 0x00) | + (m_mono ? 0x0100 : 0x00) | (m_output_volume << 9) | + (m_external_stereo ? 0x0800 : 0x00) | + (m_external_speaker ? 0x00 : 0x00); // TODO 0x80 is set when external speaker is connected + case 0x92 / 2: + return m_noise_shift; + case 0x94 / 2: + return m_master_volume; + case 0x9e / 2: + return m_system_volume; + } + return 0; +} + +void wswan_sound_device::port_w(offs_t offset, u16 data, u16 mem_mask) +{ + m_channel->update(); + + switch (offset) + { + case 0x80 / 2: // Audio 1 freq + case 0x82 / 2: // Audio 2 freq + case 0x84 / 2: // Audio 3 freq + case 0x86 / 2: // Audio 4 freq + COMBINE_DATA(&m_audio[offset & 0x03].freq); + m_audio[offset & 0x03].freq &= 0x7ff; + m_audio[offset & 0x03].period = 2048 - m_audio[offset & 0x03].freq; + break; + + case 0x88 / 2: + // Audio 1 volume + if (ACCESSING_BITS_0_7) + { + m_audio[0].vol_left = (data >> 4) & 0x0f; + m_audio[0].vol_right = data & 0x0f; + } + // Audio 2 volume + if (ACCESSING_BITS_8_15) + { + m_audio[1].vol_left = (data >> 12) & 0x0f; + m_audio[1].vol_right = (data >> 8) & 0x0f; + } + break; + + case 0x8a / 2: + // Audio 3 volume + if (ACCESSING_BITS_0_7) + { + m_audio[2].vol_left = (data >> 4) & 0x0f; + m_audio[2].vol_right = data & 0x0f; + } + // Audio 4 volume + if (ACCESSING_BITS_8_15) + { + m_audio[3].vol_left = (data >> 12) & 0x0f; + m_audio[3].vol_right = (data >> 8) & 0x0f; + } + break; + + case 0x8c / 2: + // Sweep step + if (ACCESSING_BITS_0_7) + { + m_sweep_step = (int8_t)(data & 0xff); + } + // Sweep time + if (ACCESSING_BITS_8_15) + { + m_sweep_time = 8192 * ((data >> 8) + 1); + } + break; + + case 0x8e / 2: + // Noise control + if (ACCESSING_BITS_0_7) + { + m_noise_type = data & 0x07; + m_noise_reset = BIT(data, 3); + m_noise_enable = BIT(data, 4); + } + // Sample location + if (ACCESSING_BITS_8_15) + { + m_sample_address = (data & 0xff00) >> 2; + } + break; + + case 0x90 / 2: + // Audio control + if (ACCESSING_BITS_0_7) + { + m_audio[0].on = BIT(data, 0); + m_audio[1].on = BIT(data, 1); + m_audio[2].on = BIT(data, 2); + m_audio[3].on = BIT(data, 3); + m_audio2_voice = BIT(data, 5); + m_audio3_sweep = BIT(data, 6); + m_audio4_noise = BIT(data, 7); + } + // Audio output + if (ACCESSING_BITS_8_15) + { + m_mono = BIT(data, 8); + m_output_volume = ((data >> 9) & 0x03); + m_external_stereo = BIT(data, 11); + m_external_speaker = 1; + } + break; + + case 0x92 / 2: // Noise counter shift register + COMBINE_DATA(&m_noise_shift); + m_noise_shift &= 0x7fff; + break; + + case 0x94 / 2: // Master volume + if (ACCESSING_BITS_0_7) + m_master_volume = data & 0xff; + break; + + case 0x9e / 2: // WSC volume setting (0, 1, 2, 3) (TODO) + if (ACCESSING_BITS_0_7) + m_system_volume = data & 0x03; + break; + } +} diff --git a/src/mame/shared/wswansound.h b/src/mame/shared/wswansound.h new file mode 100644 index 00000000000..43906b5d090 --- /dev/null +++ b/src/mame/shared/wswansound.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef MAME_AUDIO_WSWAN_H +#define MAME_AUDIO_WSWAN_H + +#pragma once + +#include "dirom.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wswan_sound_device + +class wswan_sound_device : public device_t, + public device_sound_interface, + public device_rom_interface<14,1> +{ +public: + wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + void port_w(offs_t offset, u16 data, u16 mem_mask); + u16 port_r(offs_t offset, u16 mem_mask); + +protected: + struct CHAN + { + CHAN() : + freq(0), + period(0), + pos(0), + vol_left(0), + vol_right(0), + on(0), + offset(0), + signal(0) { } + + u16 freq; + u16 period; + u32 pos; + u8 vol_left; + u8 vol_right; + u8 on; + u8 offset; + u8 signal; + }; + + // device-level overrides + virtual void device_start() override; + virtual void device_clock_changed() override; + virtual void device_reset() override; + + virtual void rom_bank_updated() override; + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + +private: + int fetch_sample(int channel, int offset); + + sound_stream *m_channel; + CHAN m_audio[4]; + s8 m_sweep_step; + u32 m_sweep_time; + u32 m_sweep_count; + u8 m_noise_type; + u8 m_noise_reset; + u8 m_noise_enable; + u8 m_noise_output; + u16 m_sample_address; + u8 m_audio2_voice; + u8 m_audio3_sweep; + u8 m_audio4_noise; + u8 m_mono; + u8 m_output_volume; + u8 m_external_stereo; + u8 m_external_speaker; + u16 m_noise_shift; + u8 m_master_volume; + u8 m_system_volume = 0; +}; + +DECLARE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device) + +#endif // MAME_AUDIO_WSWAN_H diff --git a/src/mame/shared/z80bin.cpp b/src/mame/shared/z80bin.cpp new file mode 100644 index 00000000000..c76f256e7f2 --- /dev/null +++ b/src/mame/shared/z80bin.cpp @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Robbbert +#include "emu.h" +#include "z80bin.h" + +/*------------------------------------------------- + z80bin_load_file - load a z80bin file into + memory +-------------------------------------------------*/ + +image_init_result z80bin_load_file(device_image_interface &image, address_space &space, uint16_t &exec_addr, uint16_t &start_addr, uint16_t &end_addr) +{ + uint16_t args[3]{}; + uint16_t i = 0U, j = 0U, size = 0U; + uint8_t data = 0U; + char pgmname[256]{}; + char message[512]{}; + + image.fseek(7, SEEK_SET); + + char ch = '\0'; + uint32_t bytes = 0; + while ((bytes = image.fread(&ch, 1)) != 0 && ch != 0x1A) + { + if (ch != '\0') + { + if (i >= (std::size(pgmname) - 1)) + { + image.seterror(image_error::INVALIDIMAGE, "File name too long"); + image.message(" File name too long"); + return image_init_result::FAIL; + } + + pgmname[i] = ch; /* build program name */ + i++; + } + } + + if (bytes == 0) + { + image.seterror(image_error::INVALIDIMAGE, "Unexpected EOF while getting file name"); + image.message(" Unexpected EOF while getting file name"); + return image_init_result::FAIL; + } + + pgmname[i] = '\0'; /* terminate string with a null */ + + if (image.fread(args, sizeof(args)) != sizeof(args)) + { + image.seterror(image_error::INVALIDIMAGE, "Unexpected EOF while getting file size"); + image.message(" Unexpected EOF while getting file size"); + return image_init_result::FAIL; + } + + exec_addr = little_endianize_int16(args[0]); + start_addr = little_endianize_int16(args[1]); + end_addr = little_endianize_int16(args[2]); + + size = (end_addr - start_addr + 1) & 0xffff; + + /* display a message about the loaded quickload */ + image.message(" %s\nsize=%04X : start=%04X : end=%04X : exec=%04X",pgmname,size,start_addr,end_addr,exec_addr); + + for (i = 0; i < size; i++) + { + j = (start_addr + i) & 0xffff; + if (image.fread(&data, 1) != 1) + { + snprintf(message, std::size(message), "%s: Unexpected EOF while writing byte to %04X", pgmname, (unsigned) j); + image.seterror(image_error::INVALIDIMAGE, message); + image.message("%s: Unexpected EOF while writing byte to %04X", pgmname, (unsigned) j); + return image_init_result::FAIL; + } + space.write_byte(j, data); + } + + return image_init_result::PASS; +} diff --git a/src/mame/shared/z80bin.h b/src/mame/shared/z80bin.h new file mode 100644 index 00000000000..ecadaae549d --- /dev/null +++ b/src/mame/shared/z80bin.h @@ -0,0 +1,18 @@ +// license:BSD-3-Clause +// copyright-holders:Robbbert +/********************************************************************* + + machine/z80bin.h + + Quickload code for Z80 bin format + +*********************************************************************/ + +#ifndef MAME_MACHINE_Z80BIN_H +#define MAME_MACHINE_Z80BIN_H + +#pragma once + +image_init_result z80bin_load_file(device_image_interface &image, address_space &space, uint16_t &exec_addr, uint16_t &start_addr, uint16_t &end_addr); + +#endif // MAME_MACHINE_Z80BIN_H -- cgit v1.2.3