diff options
Diffstat (limited to 'src')
42 files changed, 2994 insertions, 726 deletions
diff --git a/src/devices/bus/econet/e01.cpp b/src/devices/bus/econet/e01.cpp index ed60ccc2d28..6176268d6d7 100644 --- a/src/devices/bus/econet/e01.cpp +++ b/src/devices/bus/econet/e01.cpp @@ -53,7 +53,7 @@ #include "e01.h" #include "bus/scsi/scsihd.h" - +#include "softlist.h" //************************************************************************** @@ -166,6 +166,10 @@ WRITE_LINE_MEMBER( e01_device::clk_en_w ) m_clk_en = state; } +FLOPPY_FORMATS_MEMBER( floppy_formats_afs ) + FLOPPY_AFS_FORMAT +FLOPPY_FORMATS_END0 + static SLOT_INTERFACE_START( e01_floppies ) SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) // NEC FD1036 A SLOT_INTERFACE_END @@ -253,8 +257,9 @@ static MACHINE_CONFIG_FRAGMENT( e01 ) MCFG_WD2793_ADD(WD2793_TAG, XTAL_8MHz/4) MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(e01_device, fdc_irq_w)) MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(e01_device, fdc_drq_w)) - MCFG_FLOPPY_DRIVE_ADD(WD2793_TAG":0", e01_floppies, "35dd", floppy_image_device::default_floppy_formats) - MCFG_FLOPPY_DRIVE_ADD(WD2793_TAG":1", e01_floppies, "35dd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD2793_TAG":0", e01_floppies, "35dd", floppy_formats_afs) + MCFG_FLOPPY_DRIVE_ADD(WD2793_TAG":1", e01_floppies, "35dd", floppy_formats_afs) + MCFG_SOFTWARE_LIST_ADD("flop_ls_e01", "e01_flop") MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") MCFG_CENTRONICS_ACK_HANDLER(DEVWRITELINE(R6522_TAG, via6522_device, write_ca1)) diff --git a/src/devices/bus/econet/e01.h b/src/devices/bus/econet/e01.h index e83b9a0b6bd..02a432c936d 100644 --- a/src/devices/bus/econet/e01.h +++ b/src/devices/bus/econet/e01.h @@ -22,6 +22,7 @@ #include "machine/mc6854.h" #include "machine/ram.h" #include "machine/wd_fdc.h" +#include "formats/afs_dsk.h" class e01_device : public device_t, public device_econet_interface @@ -37,6 +38,8 @@ public: TYPE_E01S }; + DECLARE_FLOPPY_FORMATS(floppy_formats_afs); + DECLARE_READ8_MEMBER( read ); DECLARE_WRITE8_MEMBER( write ); DECLARE_READ8_MEMBER( ram_select_r ); diff --git a/src/devices/bus/electron/exp.cpp b/src/devices/bus/electron/exp.cpp new file mode 100644 index 00000000000..b13f6534002 --- /dev/null +++ b/src/devices/bus/electron/exp.cpp @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Electron Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ELECTRON_EXPANSION_SLOT = &device_creator<electron_expansion_slot_device>; + + +//************************************************************************** +// DEVICE ELECTRON_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_electron_expansion_interface - constructor +//------------------------------------------------- + +device_electron_expansion_interface::device_electron_expansion_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast<electron_expansion_slot_device *>(device.owner()); +} + + +//------------------------------------------------- +// ~device_electron_expansion_card_interface - destructor +//------------------------------------------------- + +device_electron_expansion_interface::~device_electron_expansion_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// electron_expansion_slot_device - constructor +//------------------------------------------------- + +electron_expansion_slot_device::electron_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ELECTRON_EXPANSION_SLOT, "Expansion port", tag, owner, clock, "electron_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void electron_expansion_slot_device::device_start() +{ + m_card = dynamic_cast<device_electron_expansion_interface *>(get_card_device()); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void electron_expansion_slot_device::device_reset() +{ + if (get_card_device()) + { + get_card_device()->reset(); + } +} + + +//------------------------------------------------- +// SLOT_INTERFACE( electron_expansion_devices ) +//------------------------------------------------- + + +// slot devices +//#include "plus1.h" +//#include "plus3.h" +//#include "aplus3.h" +//#include "aplus5.h" +//#include "slogger.h" +//#include "fbjoy.h" +//#include "m2105.h" + + +SLOT_INTERFACE_START( electron_expansion_devices ) + //SLOT_INTERFACE("plus1", ELECTRON_PLUS1) + //SLOT_INTERFACE("plus3", ELECTRON_PLUS3) + //SLOT_INTERFACE("aplus3", ELECTRON_APLUS3) + //SLOT_INTERFACE("aplus5", ELECTRON_APLUS5) + //SLOT_INTERFACE("slogger", ELECTRON_SLOGGER) + //SLOT_INTERFACE("fbjoy", ELECTRON_FBJOY) + //SLOT_INTERFACE("m2105", ELECTRON_M2105) +SLOT_INTERFACE_END diff --git a/src/devices/bus/electron/exp.h b/src/devices/bus/electron/exp.h new file mode 100644 index 00000000000..cfcb7478a10 --- /dev/null +++ b/src/devices/bus/electron/exp.h @@ -0,0 +1,158 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************** + + Electron Expansion Port emulation + +********************************************************************** + + Pinout: + + 18V AC 2 1 18V AC + AC RETURN 4 3 AC RETURN + -5V 6 5 -5V + 0V 8 7 0V + +5V 10 9 +5V + 16MHz 12 11 SOUND O/P + PHI OUT 14 13 ÷13 IN + NMI 16 15 RST + R/W 18 17 IRQ + D6 20 19 D7 + D4 22 21 D5 + D2 24 23 D3 + D0 26 25 D1 + NC 28 27 RDY + SLOT 30 29 SLOT + A14 32 31 A15 + A12 34 33 A13 + A10 36 35 A11 + A0 38 37 A9 + A2 40 39 A1 + A4 42 41 A3 + A6 44 43 A5 + A8 46 45 A7 + 0V 48 47 0V + +5V 50 49 +5V + + Signal Definitions: + + 18V AC (pins 1,2) - These lines are connected directly to the output from the Electron mains power +AC RETURNS (pins 3,4) - adaptor. A total of 6W may be drawn from these lines as long as no power is + taken from +5V (pins 9,10,49,50). For safety reasons these lines must never + be used as an AC input to the Electron. + -5V (pins 5,6) - A -5V supply from the Electron. Up to 20mA (total) may safely be drawn + from this line by expansion modules. + 0V (pins 7,8,47,48) - Ground. Expansion modules with their own power supply must have the 0V + lines commoned with the Electron. ++5V (pins 9,10,49,50) - A +5V supply from the Electron. Up to 500mA (total) may safely be drawn + from this line by expansion modules as long as no power is taken from 18V + AC (pins 1,2,3,4). + SOUND O/P (pin 11) - Sound output. A 3V peak to peak source via a 1K series resistor from the + Electron ULA. + 16 MHz (pin 12) - 16 Megahertz from the Electron main oscillator. This output may be used + for clock generation within an expansion module. + /13 IN (pin 13) - 16 Megahertz divided by 13. This output may be used for baud rate + generation. If divided by 1024 it will give approximately 1200Hz. + PHI OUT (pin 14) - The 6502 input clock. The low time is nominally 250ns. The high time may + be 250ns (2MHz operation when reading ROMs) or 750ns or 1250ns + (stretched clock for a 1MHz access, the length depending on the phase of the + 2MHz clock) or up to 40us (if in modes 0-3) + RST (pin 15) - Reset (active low). This is an OUTPUT ONLY for the system reset line. It + may be used to initialise expansion modules on power up and when the + BREAK key is pressed. + NMI (pin 16) - Non-Maskable Interrupt (negative edge triggered). This is the system NMI + line which is open collector (wire-OR) and may be asserted by an expansion + module. The pull-up resistor on this line inside the ULA is 3k3. Care must + be taken to avoid masking other interrupts by holding the line low. Using + NMI on the Electron requires knowledge of operating system protocols. + IRQ (pin 17) - Interrupt Request (active low). This is the system IRQ line which is open + collector (wire-OR) and may be asserted by an expansion module. The pull- + up resistor on this line inside the ULA is 3k3. It is essential for the correct + operation of the machine that interrupts to not occur until the software is + capable of dealing with them. Interrupts on the Electron expansion bus should + therefore be disabled on power-up and reset. Significant use of interrupt + service time may affect other machine functions, eg the real time clock. + R/W (pin 18) - The system read/write line from the 6502. + D7-D0 (pins 19-26) - Bi-directional data bus. The direction of data is determined by R/W. + RDY (pin 27) - 6502 ready line (active low). May be asserted by an expansion module to + stop the processor when reading slow memory. This line works on read only + (R/W=1). + (pin 28) - No connection + (pins 29,30) - Polarising key connector. + A0-A15 (pins 31-46) - 6502 address bus. + +**********************************************************************/ + +#pragma once + +#ifndef __ELECTRON_EXPANSION_SLOT__ +#define __ELECTRON_EXPANSION_SLOT__ + +#include "emu.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define ELECTRON_EXPANSION_SLOT_TAG "exp" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ELECTRON_EXPANSION_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ELECTRON_EXPANSION_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_ELECTRON_PASSTHRU_EXPANSION_SLOT_ADD() \ + MCFG_ELECTRON_EXPANSION_SLOT_ADD(ELECTRON_EXPANSION_SLOT_TAG, 0, electron_expansion_devices, nullptr) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> electron_expansion_slot_device + +class device_electron_expansion_interface; + +class electron_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + electron_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~electron_expansion_slot_device() {} + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + device_electron_expansion_interface *m_card; +}; + + +// ======================> device_electron_expansion_card_interface + +class device_electron_expansion_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_electron_expansion_interface(const machine_config &mconfig, device_t &device); + virtual ~device_electron_expansion_interface(); + +protected: + electron_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type ELECTRON_EXPANSION_SLOT; + +SLOT_INTERFACE_EXTERN( electron_expansion_devices ); + + +#endif diff --git a/src/devices/machine/terminal.cpp b/src/devices/machine/terminal.cpp index 86388182f15..a2be090b261 100644 --- a/src/devices/machine/terminal.cpp +++ b/src/devices/machine/terminal.cpp @@ -319,7 +319,7 @@ WRITE8_MEMBER( generic_terminal_device::kbd_put ) ***************************************************************************/ static MACHINE_CONFIG_FRAGMENT( generic_terminal ) - MCFG_SCREEN_ADD_MONOCHROME(TERMINAL_SCREEN_TAG, RASTER, rgb_t::green) + MCFG_SCREEN_ADD_MONOCHROME(TERMINAL_SCREEN_TAG, RASTER, rgb_t::white) MCFG_SCREEN_REFRESH_RATE(50) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ MCFG_SCREEN_SIZE(TERMINAL_WIDTH*8, TERMINAL_HEIGHT*10) diff --git a/src/devices/video/vector.cpp b/src/devices/video/vector.cpp index 8606fe666aa..53286f3c623 100644 --- a/src/devices/video/vector.cpp +++ b/src/devices/video/vector.cpp @@ -145,7 +145,7 @@ void vector_device::clear_list(void) UINT32 vector_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - UINT32 flags = PRIMFLAG_ANTIALIAS(machine().options().antialias() ? 1 : 0) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD) | PRIMFLAG_VECTOR(1); + UINT32 flags = PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD) | PRIMFLAG_VECTOR(1); const rectangle &visarea = screen.visible_area(); float xscale = 1.0f / (65536 * visarea.width()); float yscale = 1.0f / (65536 * visarea.height()); diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp index 1b99a55e1ba..dc799ca235b 100644 --- a/src/emu/emuopts.cpp +++ b/src/emu/emuopts.cpp @@ -120,7 +120,6 @@ const options_entry emu_options::s_option_entries[] = // vector options { nullptr, nullptr, OPTION_HEADER, "CORE VECTOR OPTIONS" }, - { OPTION_ANTIALIAS ";aa", "1", OPTION_BOOLEAN, "use antialiasing when drawing vectors" }, { OPTION_BEAM_WIDTH_MIN, "1.0", OPTION_FLOAT, "set vector beam width minimum" }, { OPTION_BEAM_WIDTH_MAX, "1.0", OPTION_FLOAT, "set vector beam width maximum" }, { OPTION_BEAM_INTENSITY_WEIGHT, "0", OPTION_FLOAT, "set vector beam intensity weight " }, diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h index 2b6630d38dd..e3ae4bda6d8 100644 --- a/src/emu/emuopts.h +++ b/src/emu/emuopts.h @@ -108,7 +108,6 @@ #define OPTION_EFFECT "effect" // core vector options -#define OPTION_ANTIALIAS "antialias" #define OPTION_BEAM_WIDTH_MIN "beam_width_min" #define OPTION_BEAM_WIDTH_MAX "beam_width_max" #define OPTION_BEAM_INTENSITY_WEIGHT "beam_intensity_weight" @@ -295,7 +294,6 @@ public: const char *effect() const { return value(OPTION_EFFECT); } // core vector options - bool antialias() const { return bool_value(OPTION_ANTIALIAS); } float beam_width_min() const { return float_value(OPTION_BEAM_WIDTH_MIN); } float beam_width_max() const { return float_value(OPTION_BEAM_WIDTH_MAX); } float beam_intensity_weight() const { return float_value(OPTION_BEAM_INTENSITY_WEIGHT); } diff --git a/src/emu/output.cpp b/src/emu/output.cpp index b905c45d70b..026e5f84ad0 100644 --- a/src/emu/output.cpp +++ b/src/emu/output.cpp @@ -9,6 +9,7 @@ #include "emu.h" #include "coreutil.h" +#include "modules/output/output_module.h" //************************************************************************** // OUTPUT MANAGER @@ -210,10 +211,10 @@ void output_manager::set_notifier(const char *outname, output_notifier_func call notifier for all outputs -------------------------------------------------*/ -void output_manager::notify_all(output_notifier_func callback, void *param) +void output_manager::notify_all(output_module *module) { for (auto &item : m_itemtable) - (*callback)(item.second.name.c_str(), item.second.value, param); + module->notify(item.second.name.c_str(), item.second.value); } diff --git a/src/emu/output.h b/src/emu/output.h index e83399aa4b1..69c5bc5b402 100644 --- a/src/emu/output.h +++ b/src/emu/output.h @@ -21,6 +21,7 @@ TYPE DEFINITIONS ***************************************************************************/ +class output_module; typedef void (*output_notifier_func)(const char *outname, INT32 value, void *param); // ======================> output_manager @@ -72,7 +73,7 @@ public: void set_notifier(const char *outname, output_notifier_func callback, void *param); // set a notifier on a particular output, or globally if nullptr - void notify_all(output_notifier_func callback, void *param); + void notify_all(output_module *module); // map a name to a unique ID UINT32 name_to_id(const char *outname); diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp index ee78ad5125d..8fa5b1b7046 100644 --- a/src/emu/rendutil.cpp +++ b/src/emu/rendutil.cpp @@ -535,7 +535,7 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_ bounds1->x0 = modbounds.x1 - unity; bounds1->y0 = modbounds.y1 + unitx; - /* rotate the unit vector by -09 degrees and add to point 1 */ + /* rotate the unit vector by -90 degrees and add to point 1 */ bounds1->x1 = modbounds.x1 + unity; bounds1->y1 = modbounds.y1 - unitx; } diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp index 4f0f6be9a83..d1999a1ce16 100644 --- a/src/frontend/mame/ui/ui.cpp +++ b/src/frontend/mame/ui/ui.cpp @@ -2015,8 +2015,8 @@ std::vector<ui::menu_item> mame_ui_manager::slider_init(running_machine &machine { // add vector control sliders.push_back(slider_alloc(machine, SLIDER_ID_FLICKER + slider_index, _("Vector Flicker"), 0, 0, 1000, 10, nullptr)); - sliders.push_back(slider_alloc(machine, SLIDER_ID_BEAM_WIDTH_MIN + slider_index, _("Beam Width Minimum"), 1, 100, 1000, 1, nullptr)); - sliders.push_back(slider_alloc(machine, SLIDER_ID_BEAM_WIDTH_MAX + slider_index, _("Beam Width Maximum"), 1, 100, 1000, 1, nullptr)); + sliders.push_back(slider_alloc(machine, SLIDER_ID_BEAM_WIDTH_MIN + slider_index, _("Beam Width Minimum"), 100, 100, 1000, 1, nullptr)); + sliders.push_back(slider_alloc(machine, SLIDER_ID_BEAM_WIDTH_MAX + slider_index, _("Beam Width Maximum"), 100, 100, 1000, 1, nullptr)); sliders.push_back(slider_alloc(machine, SLIDER_ID_BEAM_INTENSITY + slider_index, _("Beam Intensity Weight"), -1000, 0, 1000, 10, nullptr)); slider_index++; break; diff --git a/src/lib/formats/afs_dsk.cpp b/src/lib/formats/afs_dsk.cpp new file mode 100644 index 00000000000..5e1ff5aa66c --- /dev/null +++ b/src/lib/formats/afs_dsk.cpp @@ -0,0 +1,60 @@ +// license:GPL-2.0+ +// copyright-holders:Nigel Barnes +/*************************************************************************** + + Acorn FileStore + + Disk image formats + +***************************************************************************/ + +#include "afs_dsk.h" + + +afs_format::afs_format() : wd177x_format(formats) +{ +} + +const char *afs_format::name() const +{ + return "afs"; +} + +const char *afs_format::description() const +{ + return "Acorn FileStore disk image"; +} + +const char *afs_format::extensions() const +{ + return "adl,img"; +} + +int afs_format::identify(io_generic *io, UINT32 form_factor) +{ + int type = find_size(io, form_factor); + + if (type != -1) + return 50; + return 0; +} + +int afs_format::get_image_offset(const format &f, int head, int track) +{ + if (f.sector_base_id == -1) + return (track * f.head_count + head) * compute_track_size(f); + else + return (f.track_count * head + track) * compute_track_size(f); +} + +const afs_format::format afs_format::formats[] = +{ + { // 640K 3 1/2 inch 80 track double sided double density (interleaved) - gaps unverified + floppy_image::FF_35, floppy_image::DSQD, floppy_image::MFM, + 2000, 16, 80, 2, 256, {}, -1, { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }, 60, 22, 43 + }, + {} +}; + + +const floppy_format_type FLOPPY_AFS_FORMAT = &floppy_image_format_creator<afs_format>; diff --git a/src/lib/formats/afs_dsk.h b/src/lib/formats/afs_dsk.h new file mode 100644 index 00000000000..e8e7190f7cd --- /dev/null +++ b/src/lib/formats/afs_dsk.h @@ -0,0 +1,37 @@ +// license:GPL-2.0+ +// copyright-holders:Nigel Barnes +/*************************************************************************** + + Acorn FileStore + + Disk image formats + +***************************************************************************/ + +#pragma once + +#ifndef __AFS_DSK_H__ +#define __AFS_DSK_H__ + +#include "wd177x_dsk.h" + + +class afs_format : public wd177x_format +{ +public: + afs_format(); + + virtual int identify(io_generic *io, UINT32 form_factor) override; + virtual int get_image_offset(const format &f, int head, int track) override; + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + +private: + static const format formats[]; +}; + + +extern const floppy_format_type FLOPPY_AFS_FORMAT; + +#endif // __AFS_DSK_H__ diff --git a/src/lib/formats/fsd_dsk.cpp b/src/lib/formats/fsd_dsk.cpp index 6fec1c9754e..0896c47d8ac 100644 --- a/src/lib/formats/fsd_dsk.cpp +++ b/src/lib/formats/fsd_dsk.cpp @@ -92,6 +92,7 @@ int fsd_format::identify(io_generic *io, UINT32 form_factor) if (memcmp(h, "FSD", 3) == 0) { return 100; } + LOG_FORMATS("fsd: no match\n"); return 0; } @@ -112,18 +113,18 @@ bool fsd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) //popmessage("Loading image of '%s'\n", title); - desc_pc_sector sects[10]; + desc_pc_sector sects[256]; UINT8 total_tracks = img[pos++]; UINT8 tnum, hnum, snum, ssize, error; hnum = 0; - //osd_printf_verbose("%d Tracks\n", total_tracks+1); - //osd_printf_verbose("Tr.# No.S Sec.# Tr.ID Head# SecID IDsiz REsiz Error\n"); + LOG_FORMATS("%02d Tracks\n", total_tracks+1); + LOG_FORMATS("Tr.# No.S Sec.# Tr.ID Head# SecID IDsiz REsiz Error\n"); for(int curr_track=0; curr_track <= total_tracks; curr_track++) { UINT8 track = img[pos++]; UINT8 spt = img[pos++]; - //osd_printf_verbose("%x %x\n", track, spt); + LOG_FORMATS("%02X %02X\n", track, spt); if (spt > 0) // formatted { UINT8 readable = img[pos++]; @@ -145,22 +146,16 @@ bool fsd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) sects[i].bad_crc = (error & 0x0e) == 0x0e; sects[i].data = &img[pos]; pos += sects[i].actual_size; - //osd_printf_verbose("Read %x %x %x %x %x %x %x\n", i, sects[i].track, sects[i].head, sects[i].sector, sects[i].size, sects[i].actual_size, error); + LOG_FORMATS("Read %02X %02X %02X %02X %02X %02X %02X\n", i, sects[i].track, sects[i].head, sects[i].sector, sects[i].size, sects[i].actual_size, error); } else { - throw emu_fatalerror("fsd_format: Unsupported unreadable sector on track %d sector %d head %d", track, i, hnum); - - // Unreadable sectors not supported!! - //sects[i].track = track; - //sects[i].head = 0; - //sects[i].sector = i; - //sects[i].size = 0; - //sects[i].actual_size = 0; - //sects[i].deleted = false; - //sects[i].bad_crc = false; - //sects[i].data = nullptr; - //osd_printf_verbose("Unread %x %x %x %x %x %x %x\n", i, sects[i].track, sects[i].head, sects[i].sector, sects[i].size, sects[i].actual_size, 0); + LOG_FORMATS("Unreadable sector on track %02d sector %02X head %02d", track, i, hnum); + sects[i].actual_size = 0; + sects[i].deleted = false; + sects[i].bad_crc = false; + sects[i].data = nullptr; + LOG_FORMATS("Unread %02X %02X %02X %02X %02X %02X %02X\n", i, sects[i].track, sects[i].head, sects[i].sector, sects[i].size, sects[i].actual_size, 0); } } } @@ -170,7 +165,7 @@ bool fsd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) sects[0].head = hnum; sects[0].sector = 0; sects[0].size = 0; - //osd_printf_verbose("Unform %x %x %x %x %x %x %x\n", 0, sects[0].track, sects[0].head, sects[0].sector, sects[0].size, sects[0].actual_size, 0); + LOG_FORMATS("Unform %02X %02X %02X %02X %02X %02X %02X\n", 0, sects[0].track, sects[0].head, sects[0].sector, sects[0].size, sects[0].actual_size, 0); } build_wd_track_fm(curr_track, hnum, image, 50000, spt, sects, 10, 40, 10); } diff --git a/src/mame/drivers/electron.cpp b/src/mame/drivers/electron.cpp index 106fc034a03..ac902576be6 100644 --- a/src/mame/drivers/electron.cpp +++ b/src/mame/drivers/electron.cpp @@ -223,6 +223,9 @@ static MACHINE_CONFIG_START( electron, electron_state ) MCFG_GENERIC_CARTSLOT_ADD("cartslot", generic_plain_slot, "electron_cart") MCFG_GENERIC_LOAD(electron_state, electron_cart) + /* expansion ports */ + MCFG_ELECTRON_EXPANSION_SLOT_ADD("exp", electron_expansion_devices, nullptr) + /* software lists */ MCFG_SOFTWARE_LIST_ADD("cass_list","electron_cass") MCFG_SOFTWARE_LIST_ADD("cart_list","electron_cart") diff --git a/src/mame/drivers/imds2.cpp b/src/mame/drivers/imds2.cpp index 65e32e3009f..bcc2358c81c 100644 --- a/src/mame/drivers/imds2.cpp +++ b/src/mame/drivers/imds2.cpp @@ -62,7 +62,7 @@ // // NOTE: // Firmware running on PIO is NOT original because a dump is not available at the moment. -// Emulator runs a version of PIO firmware that was specifically developped by me to implement +// Emulator runs a version of PIO firmware that was specifically developed by me to implement // line printer output. // // TODO: @@ -881,7 +881,18 @@ MACHINE_CONFIG_END ROM_START(imds2) // ROM definition of IPC cpu (8085A) ROM_REGION(0x1000 , "ipcrom" , 0) - ROM_LOAD("ipc_a82.bin" , 0x0000 , 0x1000 , CRC(0889394f) SHA1(b7525baf1884a7d67402dea4b5566016a9861ef2)) + ROM_DEFAULT_BIOS("mon13") + // 1x2732 Copyright 1979 + ROM_SYSTEM_BIOS(0, "mon13", "Series II Monitor v1.3") + ROMX_LOAD("ipc13_a82.bin" , 0x0000 , 0x1000 , CRC(0889394f) SHA1(b7525baf1884a7d67402dea4b5566016a9861ef2), ROM_BIOS(1)) + // 2x2716 Copyright 1978 + ROM_SYSTEM_BIOS(1, "mon12", "Series II Monitor v1.2") + ROMX_LOAD("ipc12_a57.bin" , 0x0000 , 0x0800 , CRC(6496efaf) SHA1(1a9c0f1b19c1807803db3f1543f51349d7fd693a), ROM_BIOS(2)) + ROMX_LOAD("ipc12_a48.bin" , 0x0800 , 0x0800 , CRC(258dc9a6) SHA1(3fde993aee06d9af5093d7a2d9a8cbd71fed0951), ROM_BIOS(2)) + // 2x2716 Copyright 1977 + ROM_SYSTEM_BIOS(2, "mon11", "Series II Monitor v1.1") + ROMX_LOAD("ipc11_a57.bin" , 0x0000 , 0x0800 , CRC(ffb7c036) SHA1(6f60cdfe20621c4b633c972adcb644a1c02eaa39), ROM_BIOS(3)) + ROMX_LOAD("ipc11_a48.bin" , 0x0800 , 0x0800 , CRC(3696ff28) SHA1(38b435e10a81629430275aec051fb0a55ec1f6fd), ROM_BIOS(3)) // ROM definition of IOC cpu (8080A) ROM_REGION(0x2000 , "ioccpu" , 0) @@ -891,7 +902,7 @@ ROM_START(imds2) ROM_LOAD("ioc_a53.bin" , 0x1800 , 0x0800 , CRC(c8df4bb9) SHA1(2dfb921e94ae7033a7182457b2f00657674d1b77)) // ROM definition of PIO controller (8041A) - // For the time being a specially developped PIO firmware is used until a dump of the original PIO is + // For the time being a specially developed PIO firmware is used until a dump of the original PIO is // available. ROM_REGION(0x400 , "iocpio" , 0) ROM_LOAD("pio_a72.bin" , 0 , 0x400 , BAD_DUMP CRC(8c8e740b)) diff --git a/src/mame/drivers/naomi.cpp b/src/mame/drivers/naomi.cpp index a6fd8205c72..e3fcb568072 100644 --- a/src/mame/drivers/naomi.cpp +++ b/src/mame/drivers/naomi.cpp @@ -411,7 +411,7 @@ Power Stone 841-0001C 21597 8 (64Mb) Power Stone 2 841-0008C 23127 9 (64Mb) present 315-6213 317-5054-COM joystick + 3 buttons Puyo Puyo Da! 841-0006C 22206 20 (64Mb) ? 315-6213 317-5052-COM Ring Out 4x4 840-0004C 21779 10 (64Mb) present 315-6213 317-0250-COM requires 2 JVS boards -Samba de Amigo (Rev B) 840-0020C 22966B 16 (64Mb) present 315-6213 317-0270-COM will boot but requires special controller to play it +Samba de Amigo (Rev B) (Rev A) 840-0020C 22966B 16 (64Mb) present 315-6213 317-0270-COM will boot but requires special controller to play it Sega Marine Fishing 840-0027C 22221 10 (64Mb) ? 315-6213 not present ROM 3&4 not present. Requires 837-13844 JVS IO with all DIPSW Off and fishing controller Sega Strike Fighter (Rev A, set 1) 840-0035C 23323A 20 (64Mb) present 315-6213 317-0281-COM have "Rev. A" label on case Sega Strike Fighter (Rev A, set 2) 840-0035C 23786A 20 (64Mb) present 315-6213 317-0281-COM have "Rev. A" label on PCB @@ -5295,7 +5295,7 @@ ROM_START( samba ) NAOMI_DEFAULT_EEPROM ROM_REGION( 0x8800000, "rom_board", ROMREGION_ERASEFF) - ROM_LOAD("epr-22966b.ic22",0x0000000, 0x0400000, CRC(893116b8) SHA1(35cb4f40690ff21af5ab7cc5adbc53228d6fb0b3) ) + ROM_LOAD("epr-22966b.ic22",0x0000000, 0x0400000, CRC(893116b8) SHA1(35cb4f40690ff21af5ab7cc5adbc53228d6fb0b3) ) // was also found in cartridge with Rev.A case label ROM_LOAD("mpr-22950.ic1", 0x0800000, 0x0800000, CRC(16dee15c) SHA1(b46849e492756ff406bf8956303472255fcf55a5) ) ROM_LOAD("mpr-22951.ic2", 0x1000000, 0x0800000, CRC(f509496f) SHA1(41281576f7d58c8ede9c0a89bfd46a98d5b97033) ) ROM_LOAD("mpr-22952.ic3", 0x1800000, 0x0800000, CRC(fb9b3ef0) SHA1(e9d44b673c273e97445a12186496a0594e291542) ) @@ -8761,10 +8761,34 @@ ROM_END /********************************************** * -* Naomi 2 network DVD-ROM defines +* Naomi 2 network CD and DVD-ROM defines * *********************************************/ +ROM_START( wccf116 ) + NAOMIGD_BIOS + NAOMI_DEFAULT_EEPROM + + DISK_REGION( "gdrom" ) + DISK_IMAGE_READONLY( "cdp-10001c", 0, SHA1(efa6ef20f278c99efbf7c3630b1c8e2cad0a05c0) ) // CD-R + + ROM_REGION( 0x4000, "pic", ROMREGION_ERASEFF) + //PIC is missing + ROM_LOAD("wccf1.pic", 0x00, 0x4000, NO_DUMP ) +ROM_END + +ROM_START( wccf1dup ) + NAOMIGD_BIOS + NAOMI_DEFAULT_EEPROM + + DISK_REGION( "gdrom" ) + DISK_IMAGE_READONLY( "cdp-10003", 0, SHA1(13064b6e03527f1222b6bd01c0ba9a063d7be949) ) + + ROM_REGION( 0x4000, "pic", ROMREGION_ERASEFF) + //PIC is missing, same as CDP-10001C + ROM_LOAD("wccf1.pic", 0x00, 0x4000, NO_DUMP ) +ROM_END + ROM_START( wccf212e ) NAOMIGD_BIOS NAOMI_DEFAULT_EEPROM @@ -8783,6 +8807,18 @@ ROM_START( wccf212e ) ROM_LOAD("fpr23911.ic18", 0x000000, 0x200000, CRC(1a1da741) SHA1(532ea7fc4dab11e012a521abcf5fdadd9b40d631) ) ROM_END +// "Drive Checker", contain only optical media ejector win32 program +ROM_START( wccf2chk ) + NAOMIGD_BIOS + NAOMI_DEFAULT_EEPROM + + DISK_REGION( "gdrom" ) + DISK_IMAGE_READONLY( "cdv-10007", 0, SHA1(6c5994c9b5ba5719569c541fabdd71a7ff1275aa) ) + + ROM_REGION( 0x4000, "pic", ROMREGION_ERASEFF) + // not used +ROM_END + ROM_START( wccf234j ) NAOMIGD_BIOS NAOMI_DEFAULT_EEPROM @@ -9763,9 +9799,10 @@ GAME( 2003, puyofevp, naomi, naomim1, naomi, naomi_state, naomi, ROT0, "Sega", " // 00?? ExZeus (GDL-00xx) /* CDP-xxxxx and CDV-xxxxx (CD-ROM and DVD-ROM for Naomi 2 Satellite Terminal) */ -// CDP-10001 - World Club Champion Football Serie A 2001-2002 Ver.2 (Hitmaker / Sega, 2003) +/* CDP-10001C*/ GAME( 2003, wccf116, naomigd, naomigd, naomi, naomi_state, naomigd, ROT0, "Hitmaker / Sega", "World Club Champion Football Serie A 2001-2002 Ver. 2 (CDP-10001C)", GAME_FLAGS ) +/* CDP-10003 */ GAME( 2002, wccf1dup, naomigd, naomigd, naomi, naomi_state, naomigd, ROT0, "Hitmaker / Sega", "World Club Champion Football Serie A 2001-2002 DIMM FIRM Ver.3.03 (CDP-10003)", GAME_FLAGS ) /* CDV-10002 */ GAME( 2004, wccf212e, naomigd, naomigd, naomi, naomi_state, naomigd, ROT0, "Hitmaker / Sega", "World Club Champion Football Serie A 2002-2003 Ver.2.12 (CDV-10002)", GAME_FLAGS ) -// CDV-10007 - World Club Champion Football Serie A 2002-2003 (Hitmaker / Sega, 2003) +/* CDV-10007 */ GAME( 2004, wccf2chk, naomigd, naomigd, naomi, naomi_state, naomigd, ROT0, "Hitmaker / Sega", "World Club Champion Football Serie A 2002-2003 Drive Checker (CDV-10007)", GAME_FLAGS ) // actually just disc ejector /* CDV-10008 */ GAME( 2004, wccf234j, naomigd, naomigd, naomi, naomi_state, naomigd, ROT0, "Hitmaker / Sega", "World Club Champion Football Serie A 2002-2003 Ver.2.34 (CDV-10008)", GAME_FLAGS ) /* CDV-10013 */ GAME( 2005, wccf310j, naomigd, naomigd, naomi, naomi_state, naomigd, ROT0, "Sega", "World Club Champion Football European Clubs 2004-2005 (CDV-10013)", GAME_FLAGS ) /* CDV-10015 */ GAME( 2005, wccf331e, wccf322e,naomigd, naomi, naomi_state, naomigd, ROT0, "Sega", "World Club Champion Football European Clubs 2004-2005 Ver.1.1 (CDV-10015)", GAME_FLAGS ) diff --git a/src/mame/drivers/sorcerer.cpp b/src/mame/drivers/sorcerer.cpp index d596e241355..8b090c49a43 100644 --- a/src/mame/drivers/sorcerer.cpp +++ b/src/mame/drivers/sorcerer.cpp @@ -115,8 +115,7 @@ It was often hooked to a printer, a joystick, a music card, or a speaker. We emulate the printer and the speaker. Another 25-pin port provided two-way serial communications. Only two speeds are -available - 300 baud and 1200 baud. There is no handshaking. This protocol is -currently not emulated. +available - 300 baud and 1200 baud. There is no handshaking. Other pins on this connector provided for two cassette players. The connections for cassette unit 1 are duplicated on a set of phono plugs. @@ -155,6 +154,11 @@ NOTES (2011-08-08) stable, so be prepared to cold boot whenever something goes wrong. +NOTES (2016-06-06) +1. SORCERER_USING_RS232 removed, since the core now supports RS-232 as a device. + Not actually tested due to the bios bugs making it + pretty much impossible to use. + ********************************************************************************/ #include "includes/sorcerer.h" @@ -396,6 +400,14 @@ static const floppy_interface sorcerer_floppy_interface = "floppy_8" }; +static DEVICE_INPUT_DEFAULTS_START( terminal ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_1200 ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_1200 ) + DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_2 ) +DEVICE_INPUT_DEFAULTS_END static MACHINE_CONFIG_START( sorcerer, sorcerer_state ) /* basic machine hardware */ @@ -425,6 +437,8 @@ static MACHINE_CONFIG_START( sorcerer, sorcerer_state ) MCFG_DEVICE_ADD( "uart", AY31015, 0 ) MCFG_AY31015_TX_CLOCK(ES_UART_CLOCK) MCFG_AY31015_RX_CLOCK(ES_UART_CLOCK) + MCFG_RS232_PORT_ADD("rs232", default_rs232_devices, "null_modem") + MCFG_DEVICE_CARD_DEVICE_INPUT_DEFAULTS("terminal", terminal) /* printer */ MCFG_CENTRONICS_ADD("centronics", centronics_devices, "covox") diff --git a/src/mame/drivers/sun3.cpp b/src/mame/drivers/sun3.cpp index 00126ba93a9..acd477636fa 100644 --- a/src/mame/drivers/sun3.cpp +++ b/src/mame/drivers/sun3.cpp @@ -2,20 +2,7 @@ // copyright-holders:Miodrag Milanovic, R. Belmont /*************************************************************************** - sun3.c: preliminary driver for Sun 3 and Sun 3x models. - - status: 3/80 POSTs, 3/460 needs its unique RTC chip (also used by non-3x Sun 3s). - - TODO: - - Z8530 SCC needs to actually speak serial so we can hook up the mouse and keyboard. - - Improve interrupt controller emulation. - - Figure out how the IOMMU works. - - Intersil 7170 device for 3/460 and 3/480 (they use the same PROMs). - - Sun custom MMU for original Sun 3 models. - - AM7990 LANCE chip support for everyone. - - Figure out how the parallel printer port maps to Centronics and make it so. - - Much more... - + sun3.c: preliminary driver for Sun 3 models Sun-3 Models ------------ @@ -162,55 +149,6 @@ 4/280 by replacing the CPU board. Code-named "Sirius". - 3/80 - Processor(s): 68030 @ 20MHz, 68882 @ 20MHz, 68030 on-chip - MMU, 3 MIPS, 0.16 MFLOPS - CPU: 501-1401/1650 - Chassis type: square pizza box - Bus: P4 connector (not same as P4 on 3/60) - Memory: 16M or 40M physical, 4G virtual, 100ns cycle - Notes: Similar packaging to SparcStation 1. Parallel - port, SCSI port, AUI Ethernet, 1.44M 3.5" floppy - (720K on early units?). No onboard framebuffer. - Code-named "Hydra". Type-4 keyboard and Sun-4 - mouse, plugged together and into the machine - with a small DIN plug. 1M x 9 30-pin 100ns - SIMMs. Boot ROM versions 3.0.2 and later allow - using 4M SIMMs in some slots for up to 40M (see - Misc Q&A #15). - - 3/460 - Processor(s): 68030 @ 33 MHz, 68882, 68030 on-chip MMU, - 7 MIPS, 0.6 MFLOPS - CPU: 501-1299/1550 - Bus: VME - Memory: 128M physical with ECC, 4G/process virtual, - 64K cache, 80ns cycle - Notes: A 3/260 upgraded with a 3/4xx CPU board. Uses - original 3/2xx memory boards. - - 3/470 - Processor(s): 68030 @ 33 MHz, 68882, 68030 on-chip MMU, - 7 MIPS, 0.6 MFLOPS - CPU: 501-1299/1550 - Chassis type: deskside - Bus: VME - Memory: 128M physical with ECC, 4G/process virtual, - 64K cache, 80ns cycle - Notes: Rare. Code-named "Pegasus". 8M standard, uses - same memory boards as 3/2xx. - - 3/480 - Processor(s): 68030 @ 33 MHz, 68882, 68030 on-chip MMU, - 7 MIPS, 0.6 MFLOPS - CPU: 501-1299/1550 - Chassis type: rackmount - Bus: VME - Memory: 128M physical with ECC, 4G/process virtual, - 64K cache, 80ns cycle - Notes: Rare. Code-named "Pegasus". 8M standard, uses - same memory boards as 3/2xx. - 3/E Processor(s): 68020 CPU: 501-8028 @@ -220,87 +158,51 @@ factor. Serial and keyboard ports. External RAM, framebuffer, and SCSI/ethernet boards available. - - Sun3X notes from NetBSD and Linux: - - RAM_END 0x40000000 - P4DAC 0x50200000 - VIDEO_P4ID 0x50300000 - BW2_ADDR 0x50400000 - ENA_PLANE 0x50600000 - FPA_ADDR 0x5c000000 - IOMMU 0x60000000 - ENABLEREG 0x61000000 - BUSERRREG 0x61000400 - DIAGREG 0x61000800 - IDPROM1 0x61000c00 (3/470) - MEMREG 0x61001000 - INTERREG 0x61001400 - SCC1 0x62000000 (keyboard/mouse) - SCC2 0x62002000 (serial console) - EEPROM 0x64000000 - IDPROM2 0x640007d8 (3/80) - CLOCK2 0x640007f8 (3/80 Mostek 48T02) - CLOCK1 0x64002000 (3/470 Intersil 7170) - INTELETH 0x65000000 - LANCEETH 0x65002000 - EMULEXSCSI 0x66000000 (3/80 5394) - EMULLEXDMA 0x66001000 (3/80) - PCACHETAG 0x68000000 - ECCPARREG 0x6a1e0000 - IOCTAGS 0x6c000000 - IOCFLUSH 0x6d000000 - FDC 0x6e000000 (3/80 Intel 82077) - FDC_CNTRL 0x6e000400 - FDC_VEC 0x6e000800 - PRINTER 0x6f00003c (3/80) - - The Sun3x System Enable Register controls the function of a few - on-board devices and general system operation. It is cleared when - the system is reset. - - 15 0 - +---+---+---+---+---+---+---+---+---+---+---+---+---+---.---.---+ - |BT |FPP|DMA| 0 |VID|RES|FPA|DIA| 0 |CCH|IOC|LBK|DCH| UNUSED | - +---+---+---+---+---+---+---+---+---+---+---+---+---+---.---.---+ - - Where: DCH = debug mode for system cache - LBK = VME loopback - IOC = I/O cache enable - CCH = system cache enable - DIA = diagnostic switch - FPA = enable floating-point accelerator - RES = 0 for hi-res, 1 for low res - VID = enable video display - DMA = enable system DVMA - FPP = enable 68881/2 FPU - BT = 0 for boot state, 1 for normal state - - bad '030 MMU mapping: L fef82000 -> P 00000000 - + +3/60 ROM breakpoints for start-of-tests +fefb104 - bus error test +fefb18e - interrupt test +fefb1da - clock IRQ test +fefb344 - MMU page valid test +fefb3c4 - MMU read-only permissions test +fefb45e - parity test: no spurious NMI generated from normal parity operation +fefb50c - parity test: NMI is generated when we write with inverted parity and enable parity NMIs +fefb5c8 - size memory by bus error +fef58c0 - EPROM checksum read? + +fefcb34 - bpset for each test on 3/260 ROM ****************************************************************************/ #include "emu.h" #include "cpu/m68000/m68000.h" #include "machine/timekpr.h" +#include "machine/ram.h" #include "machine/z80scc.h" -#include "bus/scsi/scsi.h" -#include "bus/scsi/scsihd.h" -#include "bus/scsi/scsicd.h" -#include "machine/ncr539x.h" -#include "machine/upd765.h" -#include "formats/pc_dsk.h" -#include "formats/mfi_dsk.h" +#include "machine/bankdev.h" #include "bus/rs232/rs232.h" #define TIMEKEEPER_TAG "timekpr" #define SCC1_TAG "scc1" #define SCC2_TAG "scc2" -#define ESP_TAG "esp" -#define FDC_TAG "fdc" #define RS232A_TAG "rs232a" #define RS232B_TAG "rs232b" +// page table entry constants +#define PM_VALID (0x80000000) // page is valid +#define PM_WRITEMASK (0x40000000) // writable? +#define PM_SYSMASK (0x20000000) // system use only? +#define PM_CACHE (0x10000000) // cachable? +#define PM_TYPEMASK (0x0c000000) // type mask +#define PM_ACCESSED (0x02000000) // accessed flag +#define PM_MODIFIED (0x01000000) // modified flag + +#define BE_FPENABLE (0x04) // FPU not enabled +#define BE_FPBERR (0x08) // FPU encountered a bus error +#define BE_VMEBERR (0x10) // VME encountered a bus error +#define BE_TIMEOUT (0x20) // timeout - memory doesn't exist +#define BE_PROTERR (0x40) // protection failed on MMU page lookup +#define BE_INVALID (0x80) // invalid entry on MMU page lookup + class sun3_state : public driver_device { public: @@ -309,244 +211,473 @@ public: m_maincpu(*this, "maincpu"), m_scc1(*this, SCC1_TAG), m_scc2(*this, SCC2_TAG), - m_fdc(*this, FDC_TAG), m_p_ram(*this, "p_ram"), - m_bw2_vram(*this, "bw2_vram") + m_bw2_vram(*this, "bw2_vram"), + m_type0space(*this, "type0"), + m_type1space(*this, "type1"), + m_type2space(*this, "type2"), + m_type3space(*this, "type3"), + m_rom(*this, "user1"), + m_ram(*this, RAM_TAG) { } - required_device<cpu_device> m_maincpu; + required_device<m68020_device> m_maincpu; required_device<z80scc_device> m_scc1; required_device<z80scc_device> m_scc2; - optional_device<n82077aa_device> m_fdc; + virtual void machine_start() override; virtual void machine_reset() override; - required_shared_ptr<UINT32> m_p_ram; + optional_shared_ptr<UINT32> m_p_ram; optional_shared_ptr<UINT32> m_bw2_vram; - - DECLARE_READ32_MEMBER(enable_r); - DECLARE_WRITE32_MEMBER(enable_w); - DECLARE_READ32_MEMBER(buserr_r); - DECLARE_WRITE32_MEMBER(buserr_w); - DECLARE_READ32_MEMBER(diag_r); - DECLARE_WRITE32_MEMBER(diag_w); - DECLARE_READ32_MEMBER(printer_r); - DECLARE_WRITE32_MEMBER(printer_w); - DECLARE_READ32_MEMBER(iommu_r); - DECLARE_WRITE32_MEMBER(iommu_w); - DECLARE_READ32_MEMBER(irqctrl_r); - DECLARE_WRITE32_MEMBER(irqctrl_w); - DECLARE_READ32_MEMBER(memreg_r); - DECLARE_WRITE32_MEMBER(memreg_w); - DECLARE_READ32_MEMBER(memrerraddr_r); - DECLARE_WRITE32_MEMBER(memrerraddr_w); - DECLARE_READ32_MEMBER(fdc_control_r); - DECLARE_WRITE32_MEMBER(fdc_control_w); - DECLARE_READ32_MEMBER(cause_buserr_r); - DECLARE_WRITE32_MEMBER(cause_buserr_w); - DECLARE_WRITE32_MEMBER(ramwrite_w); - DECLARE_READ32_MEMBER(fpa_r); - DECLARE_READ32_MEMBER(p4id_r); - - DECLARE_FLOPPY_FORMATS( floppy_formats ); - - TIMER_DEVICE_CALLBACK_MEMBER(sun380_timer); + optional_device<address_map_bank_device> m_type0space, m_type1space, m_type2space, m_type3space; + required_memory_region m_rom; + required_device<ram_device> m_ram; + + DECLARE_READ32_MEMBER( tl_mmu_r ); + DECLARE_WRITE32_MEMBER( tl_mmu_w ); + DECLARE_READ32_MEMBER( ram_r ); + DECLARE_WRITE32_MEMBER( ram_w ); + DECLARE_READ32_MEMBER( parity_r ); + DECLARE_WRITE32_MEMBER( parity_w ); + DECLARE_READ32_MEMBER( irqctrl_r ); + DECLARE_WRITE32_MEMBER( irqctrl_w ); + DECLARE_WRITE8_MEMBER( rtc7170_w ); UINT32 bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); private: - UINT32 m_enable, m_buserr, m_diag, m_printer, m_irqctrl, m_memreg, m_memerraddr; - UINT32 m_iommu[0x800]; + UINT32 *m_rom_ptr, *m_ram_ptr; + UINT32 m_enable, m_buserr, m_diag, m_dvma_enable, m_parregs[8], m_irqctrl; + + UINT32 m_context; + UINT8 m_segmap[8][2048]; + UINT32 m_pagemap[4096]; + UINT32 m_ram_size, m_ram_size_words; bool m_bInBusErr; }; -static ADDRESS_MAP_START(sun3_mem, AS_PROGRAM, 32, sun3_state) - ADDRESS_MAP_UNMAP_HIGH - AM_RANGE(0x00000000, 0x00ffffff) AM_RAM AM_SHARE("p_ram") // 16MB - AM_RANGE(0x0fef0000, 0x0fefffff) AM_ROM AM_REGION("user1",0) -ADDRESS_MAP_END - -static ADDRESS_MAP_START(sun3_80_mem, AS_PROGRAM, 32, sun3_state) - AM_RANGE(0x00000000, 0x03ffffff) AM_RAM AM_SHARE("p_ram") AM_WRITE(ramwrite_w) - AM_RANGE(0x40000000, 0x40000003) AM_READWRITE(cause_buserr_r, cause_buserr_w) - AM_RANGE(0x50300000, 0x50300003) AM_READ(p4id_r) - AM_RANGE(0x50400000, 0x504fffff) AM_RAM AM_SHARE("bw2_vram") - AM_RANGE(0x60000000, 0x60001fff) AM_READWRITE(iommu_r, iommu_w) - AM_RANGE(0x61000000, 0x61000003) AM_READWRITE(enable_r, enable_w) - AM_RANGE(0x61000400, 0x61000403) AM_READWRITE(buserr_r, buserr_w) - AM_RANGE(0x61000800, 0x61000803) AM_READWRITE(diag_r, diag_w) - AM_RANGE(0x61001000, 0x61001003) AM_READWRITE(memreg_r, memreg_w) - AM_RANGE(0x61001004, 0x61001007) AM_READWRITE(memrerraddr_r, memrerraddr_w) - AM_RANGE(0x61001400, 0x61001403) AM_READWRITE(irqctrl_r, irqctrl_w) - AM_RANGE(0x62000000, 0x6200000f) AM_DEVREADWRITE8(SCC1_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) - AM_RANGE(0x62002000, 0x6200200f) AM_DEVREADWRITE8(SCC2_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) - AM_RANGE(0x63000000, 0x6301ffff) AM_ROM AM_REGION("user1",0) - AM_RANGE(0x64000000, 0x640007ff) AM_DEVREADWRITE8(TIMEKEEPER_TAG, timekeeper_device, read, write, 0xffffffff) - AM_RANGE(0x66000000, 0x6600003f) AM_DEVREADWRITE8(ESP_TAG, ncr539x_device, read, write, 0xff000000) - AM_RANGE(0x6e000000, 0x6e000007) AM_DEVICE8(FDC_TAG, n82077aa_device, map, 0xffffffff) - AM_RANGE(0x6e000400, 0x6e000403) AM_READWRITE(fdc_control_r, fdc_control_w) - AM_RANGE(0x6f00003c, 0x6f00003f) AM_READWRITE(printer_r, printer_w) - AM_RANGE(0xfefe0000, 0xfefeffff) AM_ROM AM_REGION("user1",0) -ADDRESS_MAP_END - -static ADDRESS_MAP_START(sun3_460_mem, AS_PROGRAM, 32, sun3_state) - AM_RANGE(0x00000000, 0x03ffffff) AM_RAM AM_SHARE("p_ram") AM_WRITE(ramwrite_w) - AM_RANGE(0x09000000, 0x09000003) AM_READWRITE(cause_buserr_r, cause_buserr_w) - AM_RANGE(0x50300000, 0x50300003) AM_READ(p4id_r) - AM_RANGE(0x50400000, 0x504fffff) AM_RAM AM_SHARE("bw2_vram") - AM_RANGE(0x5c000f14, 0x5c000f17) AM_READ(fpa_r) - AM_RANGE(0x60000000, 0x60001fff) AM_READWRITE(iommu_r, iommu_w) - AM_RANGE(0x61000000, 0x61000003) AM_READWRITE(enable_r, enable_w) - AM_RANGE(0x61000400, 0x61000403) AM_READWRITE(buserr_r, buserr_w) - AM_RANGE(0x61000800, 0x61000803) AM_READWRITE(diag_r, diag_w) - AM_RANGE(0x61001000, 0x61001003) AM_READWRITE(memreg_r, memreg_w) - AM_RANGE(0x61001004, 0x61001007) AM_READWRITE(memrerraddr_r, memrerraddr_w) - AM_RANGE(0x61001400, 0x61001403) AM_READWRITE(irqctrl_r, irqctrl_w) - AM_RANGE(0x62000000, 0x6200000f) AM_DEVREADWRITE8(SCC1_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) - AM_RANGE(0x62002000, 0x6200200f) AM_DEVREADWRITE8(SCC2_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) - AM_RANGE(0x63000000, 0x6301ffff) AM_ROM AM_REGION("user1",0) - - AM_RANGE(0x6f00003c, 0x6f00003f) AM_READWRITE(printer_r, printer_w) - AM_RANGE(0xfefe0000, 0xfefeffff) AM_ROM AM_REGION("user1",0) -ADDRESS_MAP_END - -READ32_MEMBER( sun3_state::p4id_r ) -{ - return (1<<24); // 0 = hires bw2 1600x1280, 1 = bw2 1152x900, 0x45 is "Ibis" color, blt 0x68 is "Lego" color -} - -WRITE32_MEMBER( sun3_state::fdc_control_w ) +READ32_MEMBER( sun3_state::ram_r ) { - logerror("FDC write %02x (%08x)\n", data >> 24, space.device().safe_pc()); -} - -READ32_MEMBER( sun3_state::fdc_control_r ) -{ - // Type of floppy present - // 0 = no floppy in drive - // 1 = ed - // 2 = hd - // 3 = dd - - if(m_fdc) { - floppy_image_device *fdev = machine().device<floppy_connector>(":fdc:0")->get_device(); - if(fdev->exists()) { - UINT32 variant = fdev->get_variant(); - switch(variant) { - case floppy_image::SSSD: - case floppy_image::SSDD: - case floppy_image::DSDD: - return 3 << 24; - - case floppy_image::DSHD: - return 2 << 24; - - case floppy_image::DSED: - return 1 << 24; - } - } - } + if (offset < m_ram_size_words) return m_ram_ptr[offset]; - return 0 << 24; + if (!m_bInBusErr) + { + //printf("ram_r: bus error on timeout, access to invalid addr %08x, PC=%x\n", offset<<2, m_maincpu->pc); + m_buserr = BE_TIMEOUT; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + } + + return 0xffffffff; } -WRITE32_MEMBER(sun3_state::ramwrite_w) +WRITE32_MEMBER( sun3_state::ram_w ) { - UINT32 *pRAM = (UINT32 *)m_p_ram.target(); - - if (((m_memreg & 0xf0000000) == 0x70000000) && + // if writing bad parity is enabled + if (((m_parregs[0] & 0x20000000) == 0x20000000) && (m_irqctrl & 0x01000000) && !(m_bInBusErr)) { - m_memerraddr = offset<<2; - - // low 4 bits of memreg are the byte lane(s) involved, negative logic - m_memreg |= 0x0f; + m_parregs[1] = offset<<2; + //printf("Generating parity error, mem_mask %08x\n", mem_mask); switch (mem_mask) { case 0xff000000: - m_memreg &= ~0x08; + m_parregs[0] |= 0x08<<24; break; case 0x00ff0000: - m_memerraddr += 1; - m_memreg &= ~0x04; + m_parregs[1] += 1; + m_parregs[0] |= 0x04<<24; break; case 0x0000ff00: - m_memerraddr += 2; - m_memreg &= ~0x02; + m_parregs[1] += 2; + m_parregs[0] |= 0x02<<24; break; case 0x000000ff: - m_memerraddr += 3; - m_memreg &= ~0x01; + m_parregs[1] += 3; + m_parregs[0] |= 0x01<<24; break; case 0x0000ffff: - m_memerraddr += 2; - m_memreg &= ~0x03; + m_parregs[1] += 2; + m_parregs[0] |= 0x03<<24; break; case 0xffff0000: - m_memreg &= ~0x0c; + m_parregs[0] |= 0x0c<<24; break; case 0xffffffff: // no address adjust, show all 4 lanes as problematic + m_parregs[0] |= 0x0f<<24; break; } - - m_bInBusErr = true; // prevent recursion - m_maincpu->set_input_line_and_vector(M68K_IRQ_7, ASSERT_LINE, 2); + + // indicate parity interrupt + m_parregs[0] |= 0x80000000; + + // and can we take that now? + if (m_parregs[0] & 0x40000000) + { + m_bInBusErr = true; // prevent recursion + m_maincpu->set_input_line(M68K_IRQ_7, ASSERT_LINE); + } } - COMBINE_DATA(&pRAM[offset]); + if (offset < m_ram_size_words) + { + COMBINE_DATA(&m_ram_ptr[offset]); + return; + } + + if (!m_bInBusErr) + { + //printf("ram_w: bus error on timeout, access to invalid addr %08x, PC=%x\n", offset<<2, m_maincpu->pc); + m_buserr = BE_TIMEOUT; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + } } -READ32_MEMBER(sun3_state::enable_r) +READ32_MEMBER( sun3_state::tl_mmu_r ) { - return m_enable; + UINT8 fc = m_maincpu->get_fc(); + + if ((fc == 3) && !space.debugger_access()) + { + int page; + + switch (offset >> 26) + { + case 0: // IDPROM + printf("sun3: Read IDPROM at %x\n", offset); + return 0xffffffff; + + case 1: // page map + page = m_segmap[m_context & 7][(offset >> 15) & 0x7ff] << 4; + page += (offset >> 11) & 0xf; + + //printf("sun3: Read page map at %x (entry %d)\n", offset<<1, page); + return m_pagemap[page]; + + case 2: // segment map + //printf("sun3: Read segment map at %x (entry %d, user ctx %d mask %x)\n", offset<<2, (offset & ~0x3c000000) >> 15, m_context & 7, mem_mask); + return m_segmap[m_context & 7][(offset & ~0x3c000000) >> 15]<<24; + + case 3: // context reg + //printf("sun3: Read context reg\n"); + return m_context<<24; + + case 4: // enable reg + return m_enable; + + case 5: // DVMA enable + return m_dvma_enable<<24; + + case 6: // bus error + m_bInBusErr = false; + return m_buserr<<24; + + case 7: // diagnostic reg + return m_diag<<24; + + case 8: // cache tags + printf("sun3: read cache tags @ %x, PC = %x\n", offset, m_maincpu->pc); + return 0xffffffff; + + case 9: // cache data + printf("sun3: read cache data @ %x, PC = %x\n", offset, m_maincpu->pc); + return 0xffffffff; + + case 10: // flush cache + return 0xffffffff; + + case 11: // block copy + printf("sun3: read block copy @ %x, PC = %x\n", offset, m_maincpu->pc); + return 0xffffffff; + + case 15: // UART bypass + printf("sun3: read UART bypass @ %x, PC = %x\n", offset, m_maincpu->pc); + return 0xffffffff; + } + } + + // boot mode? + if ((fc == M68K_FC_SUPERVISOR_PROGRAM) && !(m_enable & 0x80)) + { + return m_rom_ptr[offset & 0x3fff]; + } + + // debugger hack + if ((space.debugger_access()) && (offset >= (0xfef0000>>2)) && (offset <= (0xfefffff>>2))) + { + return m_rom_ptr[offset & 0x3fff]; + } + + // it's translation time + UINT8 pmeg = m_segmap[m_context & 7][(offset >> 15) & 0x7ff]; + UINT32 entry = (pmeg << 4) + ((offset >> 11) & 0xf); + + // printf("sun3: Context = %d, pmeg = %d, offset >> 14 = %x, entry = %d, page = %d\n", m_context&7, pmeg, offset >> 14, entry, (offset >> 10) & 0xf); + + if (m_pagemap[entry] & PM_VALID) + { + if ((m_pagemap[entry] & PM_SYSMASK) && (fc < M68K_FC_SUPERVISOR_DATA)) + { + m_buserr = BE_PROTERR; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + return 0xffffffff; + } + + m_pagemap[entry] |= PM_ACCESSED; + + UINT32 tmp = (m_pagemap[entry] & 0x7ffff) << 11; + tmp |= (offset & 0x7ff); + + //printf("pmeg %d, entry %d = %08x, virt %08x => tmp %08x\n", pmeg, entry, m_pagemap[entry], offset << 2, tmp); + + // if (!space.debugger_access()) + // printf("sun2: Translated addr: %08x, type %d (page %d page entry %08x, orig virt %08x, FC %d)\n", tmp << 1, (m_pagemap[entry] >> 22) & 7, entry, m_pagemap[entry], offset<<1, fc); + + switch ((m_pagemap[entry] >> 26) & 3) + { + case 0: // type 0 space + return m_type0space->read32(space, tmp, mem_mask); + + case 1: // type 1 space + //printf("read device space @ %x\n", tmp<<1); + return m_type1space->read32(space, tmp, mem_mask); + + case 2: // type 2 space + return m_type2space->read32(space, tmp, mem_mask); + + case 3: // type 3 space + return m_type3space->read32(space, tmp, mem_mask); + } + } + else + { + // uncomment to see real state of driver +/* if (!space.debugger_access()) printf("sun3: pagemap entry not valid! (PC=%x)\n", m_maincpu->pc); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE);*/ + return 0xffffffff; + } + + if (!space.debugger_access()) printf("sun3: Unmapped read @ %08x (FC %d, mask %08x, PC=%x, seg %x)\n", offset<<2, fc, mem_mask, m_maincpu->pc, offset>>15); + + return 0xffffffff; } -WRITE32_MEMBER(sun3_state::enable_w) +WRITE32_MEMBER( sun3_state::tl_mmu_w ) { -// printf("sun3x: %08x to enable (mask %08x)\n", data, mem_mask); - COMBINE_DATA(&m_enable); + UINT8 fc = m_maincpu->get_fc(); + + //printf("sun3: Write %08x (FC %d, mask %08x, PC=%x) to %08x\n", data, fc, mem_mask, m_maincpu->pc, offset<<1); + + if (fc == 3) // control space + { + int page; + + switch (offset >> 26) + { + case 0: // IDPROM + return; + + case 1: // page map fefaf32 + page = m_segmap[m_context & 7][(offset >> 15) & 0x7ff] << 4; + //printf("context = %d, segment = %d, PMEG = %d\n", m_context & 7, (offset >> 15) & 0x7ff, page); + page += (offset >> 11) & 0xf; + //printf("add = %d\n", (offset >> 11) & 0xf); + + //printf("sun3: Write %04x to page map at %x (entry %d), ", data, offset<<2, page); + COMBINE_DATA(&m_pagemap[page]); + + //printf("entry now %08x (adr %08x PC=%x mask %x)\n", m_pagemap[page], (m_pagemap[page] & 0xfffff) << 13, m_maincpu->pc, mem_mask); + return; + + case 2: // segment map + //printf("sun3: Write %02x to segment map at %x (entry %d, user ctx %d PC=%x mask %x)\n", (data>>24) & 0xff, offset<<2, (offset & ~0x3c000000)>>15, m_context & 7, m_maincpu->pc, mem_mask); + m_segmap[m_context & 7][(offset & ~0x3c000000) >> 15] = (data>>24) & 0xff; + //printf("segment map[%d][%d] now %x\n", m_context & 7, (offset & ~0x3c000000) >> 15, m_segmap[m_context & 7][(offset & ~0x3c000000) >> 15] = (data>>24) & 0xff); + return; + + case 3: // context reg + //printf("sun3: Write (%x) %x to context\n", data, data>>24); + m_context = data >> 24; + return; + + case 4: // enable reg + //printf("sun3: Write %x to enable, PC=%x\n", data, m_maincpu->pc); + COMBINE_DATA(&m_enable); + return; + + case 5: // DVMA enable + m_dvma_enable = data>>24; + return; + + case 6: // bus error + m_buserr = data >> 24; + return; + + case 7: // diagnostic reg + m_diag = data >> 24; + printf("sun3: CPU LEDs to %02x (PC=%x) => ", ((data>>24) & 0xff) ^ 0xff, m_maincpu->pc); + for (int i = 0; i < 8; i++) + { + if (m_diag & (1<<i)) + { + printf("."); + } + else + { + printf("*"); + } + } + printf("\n"); + return; + + case 8: // cache tags + printf("sun3: %08x to cache tags @ %x, PC = %x\n", data, offset, m_maincpu->pc); + return; + + case 9: // cache data + printf("sun3: %08x to cache data @ %x, PC = %x\n", data, offset, m_maincpu->pc); + return; + + case 10: // flush cache + return; + + case 11: // block copy + printf("sun3: %08x to block copy @ %x, PC = %x\n", data, offset, m_maincpu->pc); + return; + + case 15: // UART bypass + printf("sun3: %08x to UART bypass @ %x, PC = %x\n", data, offset, m_maincpu->pc); + return; + } + } + + // it's translation time + UINT8 pmeg = m_segmap[m_context & 7][(offset >> 15) & 0x7ff]; + UINT32 entry = (pmeg << 4) + ((offset >> 11) & 0xf); + + if (m_pagemap[entry] & PM_VALID) + { + if ((!(m_pagemap[entry] & PM_WRITEMASK)) || + ((m_pagemap[entry] & PM_SYSMASK) && (fc < M68K_FC_SUPERVISOR_DATA))) + { + m_buserr = BE_PROTERR; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + return; + } + + m_pagemap[entry] |= (PM_ACCESSED | PM_MODIFIED); + + UINT32 tmp = (m_pagemap[entry] & 0x7ffff) << 11; + tmp |= (offset & 0x7ff); + + //if (!space.debugger_access()) printf("sun2: Translated addr: %08x, type %d (page entry %08x, orig virt %08x)\n", tmp << 1, (m_pagemap[entry] >> 22) & 7, m_pagemap[entry], offset<<1); + + //if (((m_pagemap[entry] >> 26) & 3) == 1) + { + //printf("pmeg %d, entry %d = %08x, virt %08x => tmp %08x\n", pmeg, entry, m_pagemap[entry], offset << 2, tmp); + } + + switch ((m_pagemap[entry] >> 26) & 3) + { + case 0: // type 0 + m_type0space->write32(space, tmp, data, mem_mask); + return; + + case 1: // type 1 + //printf("write device space @ %x\n", tmp<<1); + m_type1space->write32(space, tmp, data, mem_mask); + return; + + case 2: // type 2 + m_type2space->write32(space, tmp, data, mem_mask); + return; + + case 3: // type 3 + m_type3space->write32(space, tmp, data, mem_mask); + return; + } + } + else + { + if (!space.debugger_access()) printf("sun3: pagemap entry not valid!\n"); + m_buserr = BE_INVALID; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + } + + printf("sun3: Unmapped write %04x (FC %d, mask %04x, PC=%x) to %08x\n", data, fc, mem_mask, m_maincpu->pc, offset<<2); } -READ32_MEMBER(sun3_state::buserr_r) +READ32_MEMBER(sun3_state::parity_r) { - UINT32 rv = m_buserr; - m_buserr = 0; + UINT32 rv = m_parregs[offset]; + + if (offset == 0) // clear interrupt if any + { + m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); + m_parregs[offset] &= ~0x8f000000; + } + return rv; } -WRITE32_MEMBER(sun3_state::buserr_w) +WRITE32_MEMBER(sun3_state::parity_w) { -// printf("sun3x: %08x to buserr (mask %08x)\n", data, mem_mask); - COMBINE_DATA(&m_buserr); + //printf("sun3: %08x to parity registers @ %x (mask %08x)\n", data, offset, mem_mask); + + if (offset == 0) + { + m_parregs[0] &= 0x8f000000; + + if ((m_parregs[0] & 0x80000000) && (data & 0x40000000)) + { + m_maincpu->set_input_line(M68K_IRQ_7, ASSERT_LINE); + } + + m_parregs[0] |= (data & 0x70000000); + } + else + { + COMBINE_DATA(&m_parregs[offset]); + } } -READ32_MEMBER(sun3_state::diag_r) -{ - return m_diag; -} +static ADDRESS_MAP_START(sun3_mem, AS_PROGRAM, 32, sun3_state) + AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE( tl_mmu_r, tl_mmu_w ) +ADDRESS_MAP_END -WRITE32_MEMBER(sun3_state::diag_w) -{ -// printf("sun3x: %08x to diag (mask %08x)\n", data, mem_mask); - COMBINE_DATA(&m_diag); -} +// type 0 device space +static ADDRESS_MAP_START(vmetype0space_map, AS_PROGRAM, 32, sun3_state) + AM_RANGE(0x00000000, 0x01ffffff) AM_READWRITE(ram_r, ram_w) +ADDRESS_MAP_END -READ32_MEMBER(sun3_state::printer_r) -{ - return m_printer; -} +// type 1 device space +static ADDRESS_MAP_START(vmetype1space_map, AS_PROGRAM, 32, sun3_state) + AM_RANGE(0x00020000, 0x0002000f) AM_DEVREADWRITE8(SCC2_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) + AM_RANGE(0x00060000, 0x0006ffff) AM_WRITE8(rtc7170_w, 0xffffffff) + AM_RANGE(0x00080000, 0x0008000f) AM_READWRITE(parity_r, parity_w) + AM_RANGE(0x000a0000, 0x000a0003) AM_READWRITE(irqctrl_r, irqctrl_w) + AM_RANGE(0x00100000, 0x0010ffff) AM_ROM AM_REGION("user1", 0) +ADDRESS_MAP_END -WRITE32_MEMBER(sun3_state::printer_w) -{ -// printf("sun3x: %08x to printer (mask %08x)\n", data, mem_mask); - COMBINE_DATA(&m_printer); -} +// type 2 device space +static ADDRESS_MAP_START(vmetype2space_map, AS_PROGRAM, 32, sun3_state) +ADDRESS_MAP_END + +// type 3 device space +static ADDRESS_MAP_START(vmetype3space_map, AS_PROGRAM, 32, sun3_state) +ADDRESS_MAP_END READ32_MEMBER(sun3_state::irqctrl_r) { @@ -555,7 +686,7 @@ READ32_MEMBER(sun3_state::irqctrl_r) WRITE32_MEMBER(sun3_state::irqctrl_w) { -// printf("sun3x: %08x to interrupt control (mask %08x)\n", data, mem_mask); + //printf("sun3: %08x to interrupt control (mask %08x)\n", data, mem_mask); COMBINE_DATA(&m_irqctrl); if (data & 0x01000000) @@ -572,10 +703,6 @@ WRITE32_MEMBER(sun3_state::irqctrl_w) { m_maincpu->set_input_line(M68K_IRQ_3, ASSERT_LINE); } - if (!(data & 0x80000000)) - { - m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); - } } else // master enable clear, clear all interrupts { @@ -589,83 +716,22 @@ WRITE32_MEMBER(sun3_state::irqctrl_w) } } -READ32_MEMBER(sun3_state::memreg_r) -{ - return m_memreg; -} - -WRITE32_MEMBER(sun3_state::memreg_w) -{ -// printf("sun3x: %08x to memory control (mask %08x)\n", data, mem_mask); - COMBINE_DATA(&m_memreg); -} - -READ32_MEMBER(sun3_state::memrerraddr_r) -{ - m_bInBusErr = false; - m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); - return m_memerraddr; -} - -WRITE32_MEMBER(sun3_state::memrerraddr_w) -{ -// printf("sun3x: %08x to memory error address (mask %08x)\n", data, mem_mask); - COMBINE_DATA(&m_memerraddr); -} - -READ32_MEMBER(sun3_state::iommu_r) +WRITE8_MEMBER(sun3_state::rtc7170_w) { - return m_iommu[offset]; -} - -// IOMMU entry defs: -// address mask: 0x03ffe000 -// cache inhibit: 0x00000040 -// full block: 0x00000020 -// modified: 0x00000010 -// used: 0x00000008 -// write prot: 0x00000004 -// bad: 0x00000002 -// valid: 0x00000001 -WRITE32_MEMBER(sun3_state::iommu_w) -{ - COMBINE_DATA(&m_iommu[offset]); -} - -READ32_MEMBER(sun3_state::fpa_r) -{ - m_buserr |= 0x04000000; - m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); - m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); - return 0xffffffff; -} - -READ32_MEMBER(sun3_state::cause_buserr_r) -{ - m_buserr |= 0x20000000; - m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); - m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); - return 0xffffffff; -} - -WRITE32_MEMBER(sun3_state::cause_buserr_w) -{ - m_buserr |= 0x20000000; - m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); - m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); -} - -TIMER_DEVICE_CALLBACK_MEMBER(sun3_state::sun380_timer) -{ - if ((m_irqctrl & 0x81000000) == 0x81000000) + //printf("%02x to 7170 @ %x\n", data, offset); + + if ((offset == 0x11) && (data == 0x1c)) { - m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); - m_maincpu->set_input_line(M68K_IRQ_7, ASSERT_LINE); + if ((m_irqctrl & 0x21000000) == 0x21000000) + { + m_maincpu->set_input_line(M68K_IRQ_5, ASSERT_LINE); + } } } UINT32 sun3_state::bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { +#if 0 UINT32 *scanline; int x, y; UINT8 pixels; @@ -689,7 +755,7 @@ UINT32 sun3_state::bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const *scanline++ = palette[(pixels&1)]; } } - +#endif return 0; } @@ -697,93 +763,63 @@ UINT32 sun3_state::bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const static INPUT_PORTS_START( sun3 ) INPUT_PORTS_END - -void sun3_state::machine_reset() +void sun3_state::machine_start() { - UINT8* user1 = memregion("user1")->base(); - - memcpy((UINT8*)m_p_ram.target(),user1,0x10000); + m_rom_ptr = (UINT32 *)m_rom->base(); + m_ram_ptr = (UINT32 *)m_ram->pointer(); + m_ram_size = m_ram->size(); + m_ram_size_words = m_ram_size >> 2; +} +void sun3_state::machine_reset() +{ m_maincpu->reset(); - - memset(m_iommu, 0, sizeof(m_iommu)); - m_enable = 0; m_buserr = 0; m_diag = 0; - m_printer = 0; + m_dvma_enable = 0; m_irqctrl = 0; - m_memreg = 0; - m_memerraddr = 0; m_bInBusErr = false; } -FLOPPY_FORMATS_MEMBER( sun3_state::floppy_formats ) - FLOPPY_PC_FORMAT -FLOPPY_FORMATS_END - -static SLOT_INTERFACE_START( sun_floppies ) - SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) -SLOT_INTERFACE_END - static MACHINE_CONFIG_START( sun3, sun3_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", M68020, 16670000) MCFG_CPU_PROGRAM_MAP(sun3_mem) - MCFG_SCC8530_ADD(SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) - MCFG_SCC8530_ADD(SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_START( sun3_80, sun3_state ) - /* basic machine hardware */ - MCFG_CPU_ADD("maincpu", M68030, 20000000) - MCFG_CPU_PROGRAM_MAP(sun3_80_mem) - - MCFG_M48T02_ADD(TIMEKEEPER_TAG) - - MCFG_SCC8530_ADD(SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) - MCFG_SCC8530_ADD(SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) - MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_txd)) - MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(RS232B_TAG, rs232_port_device, write_txd)) - - MCFG_RS232_PORT_ADD(RS232A_TAG, default_rs232_devices, nullptr) - MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxa_w)) - MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcda_w)) - MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsa_w)) - - MCFG_RS232_PORT_ADD(RS232B_TAG, default_rs232_devices, nullptr) - MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxb_w)) - MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcdb_w)) - MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsb_w)) - - MCFG_DEVICE_ADD("scsi", SCSI_PORT, 0) - MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_6) - MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE2, "harddisk", SCSIHD, SCSI_ID_5) - - MCFG_DEVICE_ADD(ESP_TAG, NCR539X, 20000000/2) - MCFG_LEGACY_SCSI_PORT("scsi") - - MCFG_N82077AA_ADD("fdc", n82077aa_device::MODE_PS2) - MCFG_FLOPPY_DRIVE_ADD("fdc:0", sun_floppies, "35hd", sun3_state::floppy_formats) - - // the timekeeper has no interrupt output, so 3/80 includes a dedicated timer circuit - MCFG_TIMER_DRIVER_ADD_PERIODIC("timer", sun3_state, sun380_timer, attotime::from_hz(100)) - - MCFG_SCREEN_ADD("bwtwo", RASTER) - MCFG_SCREEN_UPDATE_DRIVER(sun3_state, bw2_update) - MCFG_SCREEN_SIZE(1152,900) - MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 900-1) - MCFG_SCREEN_REFRESH_RATE(72) -MACHINE_CONFIG_END - -static MACHINE_CONFIG_START( sun3_460, sun3_state ) - /* basic machine hardware */ - MCFG_CPU_ADD("maincpu", M68030, 33000000) - MCFG_CPU_PROGRAM_MAP(sun3_460_mem) - - MCFG_M48T02_ADD(TIMEKEEPER_TAG) - + MCFG_RAM_ADD(RAM_TAG) + MCFG_RAM_DEFAULT_SIZE("2M") + MCFG_RAM_EXTRA_OPTIONS("4M,6M,8M,12M,16M,20M,24M,28M,32M") + MCFG_RAM_DEFAULT_VALUE(0x00) + + // MMU Type 0 device space + MCFG_DEVICE_ADD("type0", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(vmetype0space_map) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_BIG) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(32) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x80000000) + + // MMU Type 1 device space + MCFG_DEVICE_ADD("type1", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(vmetype1space_map) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_BIG) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(32) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x80000000) + + // MMU Type 2 device space + MCFG_DEVICE_ADD("type2", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(vmetype2space_map) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_BIG) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(32) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x80000000) + + // MMU Type 3 device space + MCFG_DEVICE_ADD("type3", ADDRESS_MAP_BANK, 0) + MCFG_DEVICE_PROGRAM_MAP(vmetype3space_map) + MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_BIG) + MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(32) + MCFG_ADDRESS_MAP_BANK_STRIDE(0x80000000) + MCFG_SCC8530_ADD(SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) MCFG_SCC8530_ADD(SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_txd)) @@ -917,48 +953,6 @@ ROM_START( sun3_e ) ROMX_LOAD( "sun3_e.32", 0x0000, 0x10000, CRC(acedde7e) SHA1(1ab6ec28f4365a613a5e326c34cb37585c3f0ecc), ROM_BIOS(1)) ROM_END -ROM_START( sun3_80 ) - ROM_REGION32_BE( 0x20000, "user1", ROMREGION_ERASEFF ) -/* -Sun 3/80 V1.0 Bootprom -Sun 3/80 V2.2 Bootprom -Sun 3/80 V2.3 Bootprom -Sun 3/80 V2.9.2 Bootprom -Sun 3/80 V3.0 Bootprom -Sun 3/80 V3.0.2 Bootprom -Sun 3/80 V3.0.3 Bootprom -*/ - ROM_SYSTEM_BIOS(0, "rev303", "Rev 3.0.3") - ROMX_LOAD( "sun3_80_v3.0.3", 0x0000, 0x20000, CRC(8f983115) SHA1(e4be2dcbb29fc5c60ed9d838ab241c634fdd24e5), ROM_BIOS(1)) - ROM_SYSTEM_BIOS(1, "rev302", "Rev 3.0.2") - ROMX_LOAD( "sun3_80_v3.0.2", 0x0000, 0x20000, CRC(c09a3592) SHA1(830187dfe58e65289533717a797d2c42da86ac4e), ROM_BIOS(2)) - ROM_SYSTEM_BIOS(2, "rev30", "Rev 3.0") - ROMX_LOAD( "sun3_80_v3.0", 0x0000, 0x20000, CRC(47e3b012) SHA1(1e045b6f542aaf7808d6567c28a9e734a8c5d815), ROM_BIOS(3)) - ROM_SYSTEM_BIOS(3, "rev292", "Rev 2.9.2") - ROMX_LOAD( "sun3_80_v2.9.2", 0x0000, 0x20000, CRC(32bcf711) SHA1(7ecd4a0d0988c1d1d53fd79ac16c8456ed73ace1), ROM_BIOS(4)) - - // default NVRAM: includes valid settings for console on framebuffer, boot from SCSI disk, Ethernet ID, more - ROM_REGION( 0x800, TIMEKEEPER_TAG, 0 ) - ROM_LOAD( "timekpr_380.bin", 0x000000, 0x000800, CRC(e76f1aae) SHA1(8e7c36e3928887a94a8133e8416ee4126c31edd7) ) -ROM_END - -ROM_START( sun3_460 ) - ROM_REGION32_BE( 0x20000, "user1", ROMREGION_ERASEFF ) -/* -Sun 3/460/480 V1.2.3 Bootprom -Sun 3/460/480 V2.9.1 Bootprom (2 Files, one for odd and one for even addresses) -Sun 3/460/480 V2.9.2 Bootprom -Sun 3/460/480 V2.9.3 Bootprom -Sun 3/460/480 V3.0 Bootprom (2 Files, one for odd and one for even addresses) -*/ - ROM_SYSTEM_BIOS(0, "rev30", "Rev 3.0") - ROMX_LOAD( "3_400_l.300", 0x00000, 0x10000, CRC(1312a04b) SHA1(6c3b67ba3567991897a48fe20f589ebbfcf0a35d), ROM_BIOS(1)) - ROMX_LOAD( "3_400_h.300", 0x10000, 0x10000, CRC(8d688672) SHA1(a5593844ce6af6c4f7f39bb653dc8f964b73b095), ROM_BIOS(1)) - ROM_SYSTEM_BIOS(1, "rev291", "Rev 2.9.1") - ROMX_LOAD( "sun3_460_v2.9.1_0", 0x00000, 0x10000, CRC(d62dbf09) SHA1(4a6b5fd7840b44fe93c9058a8973d8dd3c9f7d24), ROM_BIOS(2)) - ROMX_LOAD( "sun3_460_v2.9.1_1", 0x10000, 0x10000, CRC(3b5a5942) SHA1(ed6250e3c07d7cb62d4dd517a8637c8d37e16dc5), ROM_BIOS(2)) -ROM_END - /* Driver */ /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ @@ -968,6 +962,3 @@ COMP( 198?, sun3_110, 0, 0, sun3, sun3, driver_device, 0, COMP( 198?, sun3_150, 0, 0, sun3, sun3, driver_device, 0, "Sun Microsystems", "Sun 3/75/140/150/160/180", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // AKA Carrera COMP( 198?, sun3_260, 0, 0, sun3, sun3, driver_device, 0, "Sun Microsystems", "Sun 3/260/280", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // Prism COMP( 198?, sun3_e, 0, 0, sun3, sun3, driver_device, 0, "Sun Microsystems", "Sun 3/E", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // Polaris - -COMP( 198?, sun3_80, 0, 0, sun3_80, sun3, driver_device, 0, "Sun Microsystems", "Sun 3x/80", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // Hydra -COMP( 198?, sun3_460, 0, 0, sun3_460, sun3, driver_device, 0, "Sun Microsystems", "Sun 3x/460/470/480", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // Pegasus diff --git a/src/mame/drivers/sun3x.cpp b/src/mame/drivers/sun3x.cpp new file mode 100644 index 00000000000..d81688727d2 --- /dev/null +++ b/src/mame/drivers/sun3x.cpp @@ -0,0 +1,684 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic, R. Belmont +/*************************************************************************** + + sun3.c: preliminary driver for Sun 3x models. + + status: 3/80 POSTs, 3/460 needs its unique RTC chip (also used by non-3x Sun 3s). + + TODO: + - Z8530 SCC needs to actually speak serial so we can hook up the mouse and keyboard. + - Improve interrupt controller emulation. + - Figure out how the IOMMU works. + - Intersil 7170 device for 3/460 and 3/480 (they use the same PROMs). + - Sun custom MMU for original Sun 3 models. + - AM7990 LANCE chip support for everyone. + - Figure out how the parallel printer port maps to Centronics and make it so. + - Much more... + + + Sun-3x Models + ------------ + + 3/80 + Processor(s): 68030 @ 20MHz, 68882 @ 20MHz, 68030 on-chip + MMU, 3 MIPS, 0.16 MFLOPS + CPU: 501-1401/1650 + Chassis type: square pizza box + Bus: P4 connector (not same as P4 on 3/60) + Memory: 16M or 40M physical, 4G virtual, 100ns cycle + Notes: Similar packaging to SparcStation 1. Parallel + port, SCSI port, AUI Ethernet, 1.44M 3.5" floppy + (720K on early units?). No onboard framebuffer. + Code-named "Hydra". Type-4 keyboard and Sun-4 + mouse, plugged together and into the machine + with a small DIN plug. 1M x 9 30-pin 100ns + SIMMs. Boot ROM versions 3.0.2 and later allow + using 4M SIMMs in some slots for up to 40M (see + Misc Q&A #15). + + 3/460 + Processor(s): 68030 @ 33 MHz, 68882, 68030 on-chip MMU, + 7 MIPS, 0.6 MFLOPS + CPU: 501-1299/1550 + Bus: VME + Memory: 128M physical with ECC, 4G/process virtual, + 64K cache, 80ns cycle + Notes: A 3/260 upgraded with a 3/4xx CPU board. Uses + original 3/2xx memory boards. + + 3/470 + Processor(s): 68030 @ 33 MHz, 68882, 68030 on-chip MMU, + 7 MIPS, 0.6 MFLOPS + CPU: 501-1299/1550 + Chassis type: deskside + Bus: VME + Memory: 128M physical with ECC, 4G/process virtual, + 64K cache, 80ns cycle + Notes: Rare. Code-named "Pegasus". 8M standard, uses + same memory boards as 3/2xx. + + 3/480 + Processor(s): 68030 @ 33 MHz, 68882, 68030 on-chip MMU, + 7 MIPS, 0.6 MFLOPS + CPU: 501-1299/1550 + Chassis type: rackmount + Bus: VME + Memory: 128M physical with ECC, 4G/process virtual, + 64K cache, 80ns cycle + Notes: Rare. Code-named "Pegasus". 8M standard, uses + same memory boards as 3/2xx. + + Sun3X notes from NetBSD and Linux: + + RAM_END 0x40000000 + P4DAC 0x50200000 + VIDEO_P4ID 0x50300000 + BW2_ADDR 0x50400000 + ENA_PLANE 0x50600000 + FPA_ADDR 0x5c000000 + IOMMU 0x60000000 + ENABLEREG 0x61000000 + BUSERRREG 0x61000400 + DIAGREG 0x61000800 + IDPROM1 0x61000c00 (3/470) + MEMREG 0x61001000 + INTERREG 0x61001400 + SCC1 0x62000000 (keyboard/mouse) + SCC2 0x62002000 (serial console) + EEPROM 0x64000000 + IDPROM2 0x640007d8 (3/80) + CLOCK2 0x640007f8 (3/80 Mostek 48T02) + CLOCK1 0x64002000 (3/470 Intersil 7170) + INTELETH 0x65000000 + LANCEETH 0x65002000 + EMULEXSCSI 0x66000000 (3/80 5394) + EMULLEXDMA 0x66001000 (3/80) + PCACHETAG 0x68000000 + ECCPARREG 0x6a1e0000 + IOCTAGS 0x6c000000 + IOCFLUSH 0x6d000000 + FDC 0x6e000000 (3/80 Intel 82077) + FDC_CNTRL 0x6e000400 + FDC_VEC 0x6e000800 + PRINTER 0x6f00003c (3/80) + + The Sun3x System Enable Register controls the function of a few + on-board devices and general system operation. It is cleared when + the system is reset. + + 15 0 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---.---.---+ + |BT |FPP|DMA| 0 |VID|RES|FPA|DIA| 0 |CCH|IOC|LBK|DCH| UNUSED | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---.---.---+ + + Where: DCH = debug mode for system cache + LBK = VME loopback + IOC = I/O cache enable + CCH = system cache enable + DIA = diagnostic switch + FPA = enable floating-point accelerator + RES = 0 for hi-res, 1 for low res + VID = enable video display + DMA = enable system DVMA + FPP = enable 68881/2 FPU + BT = 0 for boot state, 1 for normal state + + bad '030 MMU mapping: L fef82000 -> P 00000000 + +****************************************************************************/ + +#include "emu.h" +#include "cpu/m68000/m68000.h" +#include "machine/timekpr.h" +#include "machine/z80scc.h" +#include "bus/scsi/scsi.h" +#include "bus/scsi/scsihd.h" +#include "bus/scsi/scsicd.h" +#include "machine/ncr539x.h" +#include "machine/upd765.h" +#include "formats/pc_dsk.h" +#include "formats/mfi_dsk.h" +#include "bus/rs232/rs232.h" + +#define TIMEKEEPER_TAG "timekpr" +#define SCC1_TAG "scc1" +#define SCC2_TAG "scc2" +#define ESP_TAG "esp" +#define FDC_TAG "fdc" +#define RS232A_TAG "rs232a" +#define RS232B_TAG "rs232b" + +class sun3x_state : public driver_device +{ +public: + sun3x_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_scc1(*this, SCC1_TAG), + m_scc2(*this, SCC2_TAG), + m_fdc(*this, FDC_TAG), + m_p_ram(*this, "p_ram"), + m_bw2_vram(*this, "bw2_vram") + { } + + required_device<cpu_device> m_maincpu; + required_device<z80scc_device> m_scc1; + required_device<z80scc_device> m_scc2; + optional_device<n82077aa_device> m_fdc; + virtual void machine_reset() override; + + required_shared_ptr<UINT32> m_p_ram; + optional_shared_ptr<UINT32> m_bw2_vram; + + DECLARE_READ32_MEMBER(enable_r); + DECLARE_WRITE32_MEMBER(enable_w); + DECLARE_READ32_MEMBER(buserr_r); + DECLARE_WRITE32_MEMBER(buserr_w); + DECLARE_READ32_MEMBER(diag_r); + DECLARE_WRITE32_MEMBER(diag_w); + DECLARE_READ32_MEMBER(printer_r); + DECLARE_WRITE32_MEMBER(printer_w); + DECLARE_READ32_MEMBER(iommu_r); + DECLARE_WRITE32_MEMBER(iommu_w); + DECLARE_READ32_MEMBER(irqctrl_r); + DECLARE_WRITE32_MEMBER(irqctrl_w); + DECLARE_READ32_MEMBER(memreg_r); + DECLARE_WRITE32_MEMBER(memreg_w); + DECLARE_READ32_MEMBER(memrerraddr_r); + DECLARE_WRITE32_MEMBER(memrerraddr_w); + DECLARE_READ32_MEMBER(fdc_control_r); + DECLARE_WRITE32_MEMBER(fdc_control_w); + DECLARE_READ32_MEMBER(cause_buserr_r); + DECLARE_WRITE32_MEMBER(cause_buserr_w); + DECLARE_WRITE32_MEMBER(ramwrite_w); + DECLARE_READ32_MEMBER(fpa_r); + DECLARE_READ32_MEMBER(p4id_r); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + TIMER_DEVICE_CALLBACK_MEMBER(sun380_timer); + + UINT32 bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +private: + UINT32 m_enable, m_buserr, m_diag, m_printer, m_irqctrl, m_memreg, m_memerraddr; + UINT32 m_iommu[0x800]; + bool m_bInBusErr; +}; + +static ADDRESS_MAP_START(sun3_80_mem, AS_PROGRAM, 32, sun3x_state) + AM_RANGE(0x00000000, 0x03ffffff) AM_RAM AM_SHARE("p_ram") AM_WRITE(ramwrite_w) + AM_RANGE(0x40000000, 0x40000003) AM_READWRITE(cause_buserr_r, cause_buserr_w) + AM_RANGE(0x50300000, 0x50300003) AM_READ(p4id_r) + AM_RANGE(0x50400000, 0x504fffff) AM_RAM AM_SHARE("bw2_vram") + AM_RANGE(0x60000000, 0x60001fff) AM_READWRITE(iommu_r, iommu_w) + AM_RANGE(0x61000000, 0x61000003) AM_READWRITE(enable_r, enable_w) + AM_RANGE(0x61000400, 0x61000403) AM_READWRITE(buserr_r, buserr_w) + AM_RANGE(0x61000800, 0x61000803) AM_READWRITE(diag_r, diag_w) + AM_RANGE(0x61001000, 0x61001003) AM_READWRITE(memreg_r, memreg_w) + AM_RANGE(0x61001004, 0x61001007) AM_READWRITE(memrerraddr_r, memrerraddr_w) + AM_RANGE(0x61001400, 0x61001403) AM_READWRITE(irqctrl_r, irqctrl_w) + AM_RANGE(0x62000000, 0x6200000f) AM_DEVREADWRITE8(SCC1_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) + AM_RANGE(0x62002000, 0x6200200f) AM_DEVREADWRITE8(SCC2_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) + AM_RANGE(0x63000000, 0x6301ffff) AM_ROM AM_REGION("user1",0) + AM_RANGE(0x64000000, 0x640007ff) AM_DEVREADWRITE8(TIMEKEEPER_TAG, timekeeper_device, read, write, 0xffffffff) + AM_RANGE(0x66000000, 0x6600003f) AM_DEVREADWRITE8(ESP_TAG, ncr539x_device, read, write, 0xff000000) + AM_RANGE(0x6e000000, 0x6e000007) AM_DEVICE8(FDC_TAG, n82077aa_device, map, 0xffffffff) + AM_RANGE(0x6e000400, 0x6e000403) AM_READWRITE(fdc_control_r, fdc_control_w) + AM_RANGE(0x6f00003c, 0x6f00003f) AM_READWRITE(printer_r, printer_w) + AM_RANGE(0xfefe0000, 0xfefeffff) AM_ROM AM_REGION("user1",0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(sun3_460_mem, AS_PROGRAM, 32, sun3x_state) + AM_RANGE(0x00000000, 0x03ffffff) AM_RAM AM_SHARE("p_ram") AM_WRITE(ramwrite_w) + AM_RANGE(0x09000000, 0x09000003) AM_READWRITE(cause_buserr_r, cause_buserr_w) + AM_RANGE(0x50300000, 0x50300003) AM_READ(p4id_r) + AM_RANGE(0x50400000, 0x504fffff) AM_RAM AM_SHARE("bw2_vram") + AM_RANGE(0x5c000f14, 0x5c000f17) AM_READ(fpa_r) + AM_RANGE(0x60000000, 0x60001fff) AM_READWRITE(iommu_r, iommu_w) + AM_RANGE(0x61000000, 0x61000003) AM_READWRITE(enable_r, enable_w) + AM_RANGE(0x61000400, 0x61000403) AM_READWRITE(buserr_r, buserr_w) + AM_RANGE(0x61000800, 0x61000803) AM_READWRITE(diag_r, diag_w) + AM_RANGE(0x61001000, 0x61001003) AM_READWRITE(memreg_r, memreg_w) + AM_RANGE(0x61001004, 0x61001007) AM_READWRITE(memrerraddr_r, memrerraddr_w) + AM_RANGE(0x61001400, 0x61001403) AM_READWRITE(irqctrl_r, irqctrl_w) + AM_RANGE(0x62000000, 0x6200000f) AM_DEVREADWRITE8(SCC1_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) + AM_RANGE(0x62002000, 0x6200200f) AM_DEVREADWRITE8(SCC2_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff00ff00) + AM_RANGE(0x63000000, 0x6301ffff) AM_ROM AM_REGION("user1",0) + + AM_RANGE(0x6f00003c, 0x6f00003f) AM_READWRITE(printer_r, printer_w) + AM_RANGE(0xfefe0000, 0xfefeffff) AM_ROM AM_REGION("user1",0) +ADDRESS_MAP_END + +READ32_MEMBER( sun3x_state::p4id_r ) +{ + return (1<<24); // 0 = hires bw2 1600x1280, 1 = bw2 1152x900, 0x45 is "Ibis" color, blt 0x68 is "Lego" color +} + +WRITE32_MEMBER( sun3x_state::fdc_control_w ) +{ + logerror("FDC write %02x (%08x)\n", data >> 24, space.device().safe_pc()); +} + +READ32_MEMBER( sun3x_state::fdc_control_r ) +{ + // Type of floppy present + // 0 = no floppy in drive + // 1 = ed + // 2 = hd + // 3 = dd + + if(m_fdc) { + floppy_image_device *fdev = machine().device<floppy_connector>(":fdc:0")->get_device(); + if(fdev->exists()) { + UINT32 variant = fdev->get_variant(); + switch(variant) { + case floppy_image::SSSD: + case floppy_image::SSDD: + case floppy_image::DSDD: + return 3 << 24; + + case floppy_image::DSHD: + return 2 << 24; + + case floppy_image::DSED: + return 1 << 24; + } + } + } + + return 0 << 24; +} + +WRITE32_MEMBER(sun3x_state::ramwrite_w) +{ + UINT32 *pRAM = (UINT32 *)m_p_ram.target(); + + if (((m_memreg & 0xf0000000) == 0x70000000) && + (m_irqctrl & 0x01000000) && + !(m_bInBusErr)) + { + m_memerraddr = offset<<2; + + // low 4 bits of memreg are the byte lane(s) involved, negative logic + m_memreg |= 0x0f; + switch (mem_mask) + { + case 0xff000000: + m_memreg &= ~0x08; + break; + + case 0x00ff0000: + m_memerraddr += 1; + m_memreg &= ~0x04; + break; + + case 0x0000ff00: + m_memerraddr += 2; + m_memreg &= ~0x02; + break; + + case 0x000000ff: + m_memerraddr += 3; + m_memreg &= ~0x01; + break; + + case 0x0000ffff: + m_memerraddr += 2; + m_memreg &= ~0x03; + break; + + case 0xffff0000: + m_memreg &= ~0x0c; + break; + + case 0xffffffff: // no address adjust, show all 4 lanes as problematic + break; + } + + m_bInBusErr = true; // prevent recursion + m_maincpu->set_input_line_and_vector(M68K_IRQ_7, ASSERT_LINE, 2); + } + + COMBINE_DATA(&pRAM[offset]); +} + +READ32_MEMBER(sun3x_state::enable_r) +{ + return m_enable; +} + +WRITE32_MEMBER(sun3x_state::enable_w) +{ +// printf("sun3x: %08x to enable (mask %08x)\n", data, mem_mask); + COMBINE_DATA(&m_enable); +} + +READ32_MEMBER(sun3x_state::buserr_r) +{ + UINT32 rv = m_buserr; + m_buserr = 0; + return rv; +} + +WRITE32_MEMBER(sun3x_state::buserr_w) +{ +// printf("sun3x: %08x to buserr (mask %08x)\n", data, mem_mask); + COMBINE_DATA(&m_buserr); +} + +READ32_MEMBER(sun3x_state::diag_r) +{ + return m_diag; +} + +WRITE32_MEMBER(sun3x_state::diag_w) +{ +// printf("sun3x: %08x to diag (mask %08x)\n", data, mem_mask); + COMBINE_DATA(&m_diag); +} + +READ32_MEMBER(sun3x_state::printer_r) +{ + return m_printer; +} + +WRITE32_MEMBER(sun3x_state::printer_w) +{ +// printf("sun3x: %08x to printer (mask %08x)\n", data, mem_mask); + COMBINE_DATA(&m_printer); +} + +READ32_MEMBER(sun3x_state::irqctrl_r) +{ + return m_irqctrl; +} + +WRITE32_MEMBER(sun3x_state::irqctrl_w) +{ +// printf("sun3x: %08x to interrupt control (mask %08x)\n", data, mem_mask); + COMBINE_DATA(&m_irqctrl); + + if (data & 0x01000000) + { + if (data & 0x02000000) + { + m_maincpu->set_input_line(M68K_IRQ_1, ASSERT_LINE); + } + if (data & 0x04000000) + { + m_maincpu->set_input_line(M68K_IRQ_2, ASSERT_LINE); + } + if (data & 0x08000000) + { + m_maincpu->set_input_line(M68K_IRQ_3, ASSERT_LINE); + } + if (!(data & 0x80000000)) + { + m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); + } + } + else // master enable clear, clear all interrupts + { + m_maincpu->set_input_line(M68K_IRQ_1, CLEAR_LINE); + m_maincpu->set_input_line(M68K_IRQ_2, CLEAR_LINE); + m_maincpu->set_input_line(M68K_IRQ_3, CLEAR_LINE); + m_maincpu->set_input_line(M68K_IRQ_4, CLEAR_LINE); + m_maincpu->set_input_line(M68K_IRQ_5, CLEAR_LINE); + m_maincpu->set_input_line(M68K_IRQ_6, CLEAR_LINE); + m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); + } +} + +READ32_MEMBER(sun3x_state::memreg_r) +{ + return m_memreg; +} + +WRITE32_MEMBER(sun3x_state::memreg_w) +{ +// printf("sun3x: %08x to memory control (mask %08x)\n", data, mem_mask); + COMBINE_DATA(&m_memreg); +} + +READ32_MEMBER(sun3x_state::memrerraddr_r) +{ + m_bInBusErr = false; + m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); + return m_memerraddr; +} + +WRITE32_MEMBER(sun3x_state::memrerraddr_w) +{ +// printf("sun3x: %08x to memory error address (mask %08x)\n", data, mem_mask); + COMBINE_DATA(&m_memerraddr); +} + +READ32_MEMBER(sun3x_state::iommu_r) +{ + return m_iommu[offset]; +} + +// IOMMU entry defs: +// address mask: 0x03ffe000 +// cache inhibit: 0x00000040 +// full block: 0x00000020 +// modified: 0x00000010 +// used: 0x00000008 +// write prot: 0x00000004 +// bad: 0x00000002 +// valid: 0x00000001 +WRITE32_MEMBER(sun3x_state::iommu_w) +{ + COMBINE_DATA(&m_iommu[offset]); +} + +READ32_MEMBER(sun3x_state::fpa_r) +{ + m_buserr |= 0x04000000; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + return 0xffffffff; +} + +READ32_MEMBER(sun3x_state::cause_buserr_r) +{ + m_buserr |= 0x20000000; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + return 0xffffffff; +} + +WRITE32_MEMBER(sun3x_state::cause_buserr_w) +{ + m_buserr |= 0x20000000; + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); +} + +TIMER_DEVICE_CALLBACK_MEMBER(sun3x_state::sun380_timer) +{ + if ((m_irqctrl & 0x81000000) == 0x81000000) + { + m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); + m_maincpu->set_input_line(M68K_IRQ_7, ASSERT_LINE); + } +} + +UINT32 sun3x_state::bw2_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels; + static const UINT32 palette[2] = { 0, 0xffffff }; + UINT8 *m_vram = (UINT8 *)m_bw2_vram.target(); + + for (y = 0; y < 900; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 1152/8; x++) + { + pixels = m_vram[(y * (1152/8)) + (BYTE4_XOR_BE(x))]; + + *scanline++ = palette[(pixels>>7)&1]; + *scanline++ = palette[(pixels>>6)&1]; + *scanline++ = palette[(pixels>>5)&1]; + *scanline++ = palette[(pixels>>4)&1]; + *scanline++ = palette[(pixels>>3)&1]; + *scanline++ = palette[(pixels>>2)&1]; + *scanline++ = palette[(pixels>>1)&1]; + *scanline++ = palette[(pixels&1)]; + } + } + + return 0; +} + +/* Input ports */ +static INPUT_PORTS_START( sun3x ) +INPUT_PORTS_END + + +void sun3x_state::machine_reset() +{ + UINT8* user1 = memregion("user1")->base(); + + memcpy((UINT8*)m_p_ram.target(),user1,0x10000); + + m_maincpu->reset(); + + memset(m_iommu, 0, sizeof(m_iommu)); + + m_enable = 0; + m_buserr = 0; + m_diag = 0; + m_printer = 0; + m_irqctrl = 0; + m_memreg = 0; + m_memerraddr = 0; + m_bInBusErr = false; +} + +FLOPPY_FORMATS_MEMBER( sun3x_state::floppy_formats ) + FLOPPY_PC_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( sun_floppies ) + SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_START( sun3_80, sun3x_state ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", M68030, 20000000) + MCFG_CPU_PROGRAM_MAP(sun3_80_mem) + + MCFG_M48T02_ADD(TIMEKEEPER_TAG) + + MCFG_SCC8530_ADD(SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_SCC8530_ADD(SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_txd)) + MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(RS232B_TAG, rs232_port_device, write_txd)) + + MCFG_RS232_PORT_ADD(RS232A_TAG, default_rs232_devices, nullptr) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxa_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcda_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsa_w)) + + MCFG_RS232_PORT_ADD(RS232B_TAG, default_rs232_devices, nullptr) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxb_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcdb_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsb_w)) + + MCFG_DEVICE_ADD("scsi", SCSI_PORT, 0) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_6) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE2, "harddisk", SCSIHD, SCSI_ID_5) + + MCFG_DEVICE_ADD(ESP_TAG, NCR539X, 20000000/2) + MCFG_LEGACY_SCSI_PORT("scsi") + + MCFG_N82077AA_ADD("fdc", n82077aa_device::MODE_PS2) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", sun_floppies, "35hd", sun3x_state::floppy_formats) + + // the timekeeper has no interrupt output, so 3/80 includes a dedicated timer circuit + MCFG_TIMER_DRIVER_ADD_PERIODIC("timer", sun3x_state, sun380_timer, attotime::from_hz(100)) + + MCFG_SCREEN_ADD("bwtwo", RASTER) + MCFG_SCREEN_UPDATE_DRIVER(sun3x_state, bw2_update) + MCFG_SCREEN_SIZE(1152,900) + MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 900-1) + MCFG_SCREEN_REFRESH_RATE(72) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_START( sun3_460, sun3x_state ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", M68030, 33000000) + MCFG_CPU_PROGRAM_MAP(sun3_460_mem) + + MCFG_M48T02_ADD(TIMEKEEPER_TAG) + + MCFG_SCC8530_ADD(SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_SCC8530_ADD(SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(RS232A_TAG, rs232_port_device, write_txd)) + MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(RS232B_TAG, rs232_port_device, write_txd)) + + MCFG_RS232_PORT_ADD(RS232A_TAG, default_rs232_devices, nullptr) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxa_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcda_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsa_w)) + + MCFG_RS232_PORT_ADD(RS232B_TAG, default_rs232_devices, nullptr) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, rxb_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, dcdb_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SCC2_TAG, z80scc_device, ctsb_w)) +MACHINE_CONFIG_END + +/* ROM definition */ + +ROM_START( sun3_80 ) + ROM_REGION32_BE( 0x20000, "user1", ROMREGION_ERASEFF ) +/* +Sun 3/80 V1.0 Bootprom +Sun 3/80 V2.2 Bootprom +Sun 3/80 V2.3 Bootprom +Sun 3/80 V2.9.2 Bootprom +Sun 3/80 V3.0 Bootprom +Sun 3/80 V3.0.2 Bootprom +Sun 3/80 V3.0.3 Bootprom +*/ + ROM_SYSTEM_BIOS(0, "rev303", "Rev 3.0.3") + ROMX_LOAD( "sun3_80_v3.0.3", 0x0000, 0x20000, CRC(8f983115) SHA1(e4be2dcbb29fc5c60ed9d838ab241c634fdd24e5), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "rev302", "Rev 3.0.2") + ROMX_LOAD( "sun3_80_v3.0.2", 0x0000, 0x20000, CRC(c09a3592) SHA1(830187dfe58e65289533717a797d2c42da86ac4e), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(2, "rev30", "Rev 3.0") + ROMX_LOAD( "sun3_80_v3.0", 0x0000, 0x20000, CRC(47e3b012) SHA1(1e045b6f542aaf7808d6567c28a9e734a8c5d815), ROM_BIOS(3)) + ROM_SYSTEM_BIOS(3, "rev292", "Rev 2.9.2") + ROMX_LOAD( "sun3_80_v2.9.2", 0x0000, 0x20000, CRC(32bcf711) SHA1(7ecd4a0d0988c1d1d53fd79ac16c8456ed73ace1), ROM_BIOS(4)) + + // default NVRAM: includes valid settings for console on framebuffer, boot from SCSI disk, Ethernet ID, more + ROM_REGION( 0x800, TIMEKEEPER_TAG, 0 ) + ROM_LOAD( "timekpr_380.bin", 0x000000, 0x000800, CRC(e76f1aae) SHA1(8e7c36e3928887a94a8133e8416ee4126c31edd7) ) +ROM_END + +ROM_START( sun3_460 ) + ROM_REGION32_BE( 0x20000, "user1", ROMREGION_ERASEFF ) +/* +Sun 3/460/480 V1.2.3 Bootprom +Sun 3/460/480 V2.9.1 Bootprom (2 Files, one for odd and one for even addresses) +Sun 3/460/480 V2.9.2 Bootprom +Sun 3/460/480 V2.9.3 Bootprom +Sun 3/460/480 V3.0 Bootprom (2 Files, one for odd and one for even addresses) +*/ + ROM_SYSTEM_BIOS(0, "rev30", "Rev 3.0") + ROMX_LOAD( "3_400_l.300", 0x00000, 0x10000, CRC(1312a04b) SHA1(6c3b67ba3567991897a48fe20f589ebbfcf0a35d), ROM_BIOS(1)) + ROMX_LOAD( "3_400_h.300", 0x10000, 0x10000, CRC(8d688672) SHA1(a5593844ce6af6c4f7f39bb653dc8f964b73b095), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "rev291", "Rev 2.9.1") + ROMX_LOAD( "sun3_460_v2.9.1_0", 0x00000, 0x10000, CRC(d62dbf09) SHA1(4a6b5fd7840b44fe93c9058a8973d8dd3c9f7d24), ROM_BIOS(2)) + ROMX_LOAD( "sun3_460_v2.9.1_1", 0x10000, 0x10000, CRC(3b5a5942) SHA1(ed6250e3c07d7cb62d4dd517a8637c8d37e16dc5), ROM_BIOS(2)) +ROM_END + +/* Driver */ + +/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ +COMP( 198?, sun3_80, 0, 0, sun3_80, sun3x, driver_device, 0, "Sun Microsystems", "Sun 3/80", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // Hydra +COMP( 198?, sun3_460, 0, 0, sun3_460, sun3x, driver_device, 0, "Sun Microsystems", "Sun 3/460/470/480", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // Pegasus diff --git a/src/mame/includes/electron.h b/src/mame/includes/electron.h index bfa6de0f5a7..a2c616c7954 100644 --- a/src/mame/includes/electron.h +++ b/src/mame/includes/electron.h @@ -16,6 +16,7 @@ #include "imagedev/cassette.h" #include "sound/beep.h" +#include "bus/electron/exp.h" #include "bus/generic/slot.h" #include "bus/generic/carts.h" diff --git a/src/mame/includes/sorcerer.h b/src/mame/includes/sorcerer.h index caead4ebb48..fcc64a275df 100644 --- a/src/mame/includes/sorcerer.h +++ b/src/mame/includes/sorcerer.h @@ -15,6 +15,7 @@ #include "sound/wave.h" #include "machine/ay31015.h" #include "bus/centronics/ctronics.h" +#include "bus/rs232/rs232.h" #include "machine/ram.h" #include "imagedev/cassette.h" #include "imagedev/snapquik.h" @@ -25,8 +26,6 @@ #include "bus/generic/slot.h" #include "bus/generic/carts.h" -#define SORCERER_USING_RS232 0 - #define ES_CPU_CLOCK (12638000 / 6) #define ES_UART_CLOCK (ES_CPU_CLOCK / 440) @@ -62,6 +61,7 @@ public: , m_wave1(*this, WAVE_TAG) , m_wave2(*this, WAVE2_TAG) , m_uart(*this, "uart") + , m_rs232(*this, "rs232") , m_centronics(*this, "centronics") , m_cart(*this, "cartslot") , m_ram(*this, RAM_TAG) @@ -80,6 +80,7 @@ public: DECLARE_MACHINE_START(sorcererd); DECLARE_DRIVER_INIT(sorcerer); TIMER_CALLBACK_MEMBER(sorcerer_cassette_tc); + TIMER_CALLBACK_MEMBER(sorcerer_serial_tc); TIMER_CALLBACK_MEMBER(sorcerer_reset); DECLARE_SNAPSHOT_LOAD_MEMBER( sorcerer ); DECLARE_QUICKLOAD_LOAD_MEMBER( sorcerer); @@ -101,6 +102,7 @@ private: required_device<wave_device> m_wave1; required_device<wave_device> m_wave2; required_device<ay31015_device> m_uart; + required_device<rs232_port_device> m_rs232; required_device<centronics_device> m_centronics; required_device<generic_slot_device> m_cart; required_device<ram_device> m_ram; diff --git a/src/mame/machine/dec_lk201.cpp b/src/mame/machine/dec_lk201.cpp index a25facd0e67..d120e3ff46a 100644 --- a/src/mame/machine/dec_lk201.cpp +++ b/src/mame/machine/dec_lk201.cpp @@ -202,7 +202,7 @@ ADDRESS_MAP_END //------------------------------------------------- static MACHINE_CONFIG_FRAGMENT( lk201 ) - MCFG_CPU_ADD(LK201_CPU_TAG, M68HC05EG, 2000000) // actually 68HC05C4 + MCFG_CPU_ADD(LK201_CPU_TAG, M68HC05EG, 4000000) // actually 68HC05C4, clock verified by Lord_Nightmare MCFG_CPU_PROGRAM_MAP(lk201_map) MCFG_SPEAKER_STANDARD_MONO("mono") diff --git a/src/mame/machine/sorcerer.cpp b/src/mame/machine/sorcerer.cpp index 7cf0db6bd8f..b64c86eae9a 100644 --- a/src/mame/machine/sorcerer.cpp +++ b/src/mame/machine/sorcerer.cpp @@ -9,24 +9,22 @@ #include "includes/sorcerer.h" #include "machine/z80bin.h" -#if SORCERER_USING_RS232 - -/* The serial code (which was never connected to the outside) is disabled for now. */ /* timer for sorcerer serial chip transmit and receive */ TIMER_CALLBACK_MEMBER(sorcerer_state::sorcerer_serial_tc) { /* if rs232 is enabled, uart is connected to clock defined by bit6 of port fe. - Transmit and receive clocks are connected to the same clock */ + Transmit and receive clocks are connected to the same clock. */ /* if rs232 is disabled, receive clock is linked to cassette hardware */ - if (m_fe & 0x80) + if BIT(m_fe, 7) { /* connect to rs232 */ + m_rs232->write_txd(m_uart->get_output_pin(AY31015_SO)); + m_uart->set_input_pin(AY31015_SI, m_rs232->rxd_r()); } } -#endif void sorcerer_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) @@ -34,9 +32,7 @@ void sorcerer_state::device_timer(emu_timer &timer, device_timer_id id, int para switch (id) { case TIMER_SERIAL: -#if SORCERER_USING_RS232 sorcerer_serial_tc(ptr, param); -#endif break; case TIMER_CASSETTE: sorcerer_cassette_tc(ptr, param); @@ -181,9 +177,7 @@ WRITE8_MEMBER(sorcerer_state::sorcerer_fe_w) if (!BIT(data, 7)) // cassette operations { -#if SORCERER_USING_RS232 m_serial_timer->adjust(attotime::zero); -#endif bool sound = BIT(m_iop_config->read(), 3); @@ -206,13 +200,11 @@ WRITE8_MEMBER(sorcerer_state::sorcerer_fe_w) else m_cassette_timer->adjust(attotime::zero); } -#if SORCERER_USING_RS232 else { m_serial_timer->adjust(attotime::zero, 0, attotime::from_hz(ES_UART_CLOCK*4)); m_cassette_timer->adjust(attotime::zero); } -#endif // bit 6 baud rate */ if (BIT(changed_bits, 6)) @@ -349,9 +341,7 @@ SNAPSHOT_LOAD_MEMBER( sorcerer_state,sorcerer) void sorcerer_state::machine_start() { m_cassette_timer = timer_alloc(TIMER_CASSETTE); -#if SORCERER_USING_RS232 m_serial_timer = timer_alloc(TIMER_SERIAL); -#endif UINT16 endmem = 0xbfff; @@ -379,9 +369,7 @@ void sorcerer_state::machine_start() MACHINE_START_MEMBER(sorcerer_state,sorcererd) { m_cassette_timer = timer_alloc(TIMER_CASSETTE); -#if SORCERER_USING_RS232 m_serial_timer = timer_alloc(TIMER_SERIAL); -#endif UINT16 endmem = 0xbbff; diff --git a/src/mame/mame.lst b/src/mame/mame.lst index fcd4d5a61cc..b077637a273 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -28125,8 +28125,11 @@ vtenis2c // 2001.10 Virtua Tennis 2 / Power Smash 2 (Rev vtennis // 1999.12 Virtua Tennis / Power Smash (cartridge) vtennis2 // 2001.08.27 Virtua Tennis 2 / Power Smash 2 (GD-ROM) vtennisg // 1999.?? Virtua Tennis / Power Smash (GD-ROM) +wccf116 // 2003.?? World Club Champion Football Serie A 2001-2002 Ver. 2 +wccf1dup // 2002.?? World Club Champion Football Serie A 2001-2002 DIMM FIRM Ver.3.03 wccf212e // 2004.12 World Club Champion Football Serie A 2002-2003 Ver.2.12 wccf234j // 2004.12 World Club Champion Football Serie A 2002-2003 Ver.2.34 +wccf2chk // 2004.?? World Club Champion Football Serie A 2002-2003 Drive Checker wccf310j // 2005.06 World Club Champion Football European Clubs 2004-2005 wccf322e // 2005.11 World Club Champion Football European Clubs 2004-2005 Ver.3.22 wccf331e // 2005.06 World Club Champion Football European Clubs 2004-2005 Ver.1.1 @@ -33969,12 +33972,14 @@ sun2_50 // sun3_110 // sun3_150 // sun3_260 // -sun3_460 // sun3_50 // sun3_60 // -sun3_80 // sun3_e // +@source:sun3x.cpp +sun3_80 // +sun3_460 // + @source:sun4.cpp sun_s10 // sun_s20 // diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 935d993d3ef..3cf1a404654 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -545,6 +545,7 @@ studio2.cpp sun1.cpp sun2.cpp sun3.cpp +sun3x.cpp sun4.cpp super6.cpp super80.cpp diff --git a/src/mame/video/powervr2.cpp b/src/mame/video/powervr2.cpp index b4cade60de7..0c31ce84e22 100644 --- a/src/mame/video/powervr2.cpp +++ b/src/mame/video/powervr2.cpp @@ -1024,7 +1024,7 @@ WRITE32_MEMBER( powervr2_device::startrender_w ) } // printf("ISP START %d %d\n",sanitycount,m_screen->vpos()); /* Fire ISP irq after a set amount of time TODO: timing of this */ - endofrender_timer_isp->adjust(state->m_maincpu->cycles_to_attotime(sanitycount*25)); + endofrender_timer_isp->adjust(state->m_maincpu->cycles_to_attotime(sanitycount*25 + 500000)); // hacky end of render delay for Capcom games, otherwise they works at ~1/10 speed break; } } diff --git a/src/osd/modules/debugger/debugimgui.cpp b/src/osd/modules/debugger/debugimgui.cpp index 76737012076..25f6938f4fa 100644 --- a/src/osd/modules/debugger/debugimgui.cpp +++ b/src/osd/modules/debugger/debugimgui.cpp @@ -261,47 +261,16 @@ void debug_imgui::handle_keys() { ImGuiIO& io = ImGui::GetIO(); ui_event event; + debug_area* focus_view = nullptr; - // global keys - if(m_machine->input().code_pressed_once(KEYCODE_F3)) - { - if(m_machine->input().code_pressed(KEYCODE_LSHIFT)) - m_machine->schedule_hard_reset(); - else - { - m_machine->schedule_soft_reset(); - debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); - } - } + // find view that has focus (should only be one at a time) + for(std::vector<debug_area*>::iterator view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr) + if((*view_ptr)->has_focus) + focus_view = *view_ptr; - if(m_machine->input().code_pressed_once(KEYCODE_F5)) - { - debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); - m_running = true; - } - if(m_machine->input().code_pressed_once(KEYCODE_F6)) - { - debug_cpu_get_visible_cpu(*m_machine)->debug()->go_next_device(); - m_running = true; - } - if(m_machine->input().code_pressed_once(KEYCODE_F7)) - { - debug_cpu_get_visible_cpu(*m_machine)->debug()->go_interrupt(); - m_running = true; - } - if(m_machine->input().code_pressed_once(KEYCODE_F8)) - debug_cpu_get_visible_cpu(*m_machine)->debug()->go_vblank(); - if(m_machine->input().code_pressed_once(KEYCODE_F9)) - debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_out(); - if(m_machine->input().code_pressed_once(KEYCODE_F10)) - debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_over(); - if(m_machine->input().code_pressed_once(KEYCODE_F11)) - debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); - if(m_machine->input().code_pressed_once(KEYCODE_F12)) - { - debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); - m_hide = true; - } + // check views in main views also (only the disassembler view accepts inputs) + if(view_main_disasm->has_focus) + focus_view = view_main_disasm; if(m_machine->input().code_pressed(KEYCODE_LCONTROL)) io.KeyCtrl = true; @@ -331,21 +300,64 @@ void debug_imgui::handle_keys() { case UI_EVENT_CHAR: m_key_char = event.ch; + if(focus_view != nullptr) + focus_view->view->process_char(m_key_char); return; default: break; } } - if(ImGui::IsKeyPressed(ITEM_ID_D) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) + // global keys + if(ImGui::IsKeyPressed(ITEM_ID_F3,false)) + { + if(ImGui::IsKeyDown(ITEM_ID_LSHIFT)) + m_machine->schedule_hard_reset(); + else + { + m_machine->schedule_soft_reset(); + debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); + } + } + + if(ImGui::IsKeyPressed(ITEM_ID_F5,false)) + { + debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); + m_running = true; + } + if(ImGui::IsKeyPressed(ITEM_ID_F6,false)) + { + debug_cpu_get_visible_cpu(*m_machine)->debug()->go_next_device(); + m_running = true; + } + if(ImGui::IsKeyPressed(ITEM_ID_F7,false)) + { + debug_cpu_get_visible_cpu(*m_machine)->debug()->go_interrupt(); + m_running = true; + } + if(ImGui::IsKeyPressed(ITEM_ID_F8,false)) + debug_cpu_get_visible_cpu(*m_machine)->debug()->go_vblank(); + if(ImGui::IsKeyPressed(ITEM_ID_F9,false)) + debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_out(); + if(ImGui::IsKeyPressed(ITEM_ID_F10,false)) + debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_over(); + if(ImGui::IsKeyPressed(ITEM_ID_F11,false)) + debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); + if(ImGui::IsKeyPressed(ITEM_ID_F12,false)) + { + debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); + m_hide = true; + } + + if(ImGui::IsKeyPressed(ITEM_ID_D,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) add_disasm(++m_win_count); - if(ImGui::IsKeyPressed(ITEM_ID_M) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) + if(ImGui::IsKeyPressed(ITEM_ID_M,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) add_memory(++m_win_count); - if(ImGui::IsKeyPressed(ITEM_ID_B) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) + if(ImGui::IsKeyPressed(ITEM_ID_B,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) add_bpoints(++m_win_count); - if(ImGui::IsKeyPressed(ITEM_ID_W) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) + if(ImGui::IsKeyPressed(ITEM_ID_W,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) add_wpoints(++m_win_count); - if(ImGui::IsKeyPressed(ITEM_ID_L) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) + if(ImGui::IsKeyPressed(ITEM_ID_L,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL)) add_log(++m_win_count); } diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index a709a9a8c52..9ba54892f51 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -255,6 +255,7 @@ void osd_common_t::register_options() REGISTER_MODULE(m_mod_man, OUTPUT_NONE); REGISTER_MODULE(m_mod_man, OUTPUT_CONSOLE); REGISTER_MODULE(m_mod_man, OUTPUT_NETWORK); + REGISTER_MODULE(m_mod_man, OUTPUT_WIN32); // after initialization we know which modules are supported @@ -643,6 +644,7 @@ void osd_common_t::init_subsystems() m_midi = select_module_options<midi_module *>(options(), OSD_MIDI_PROVIDER); m_output = select_module_options<output_module *>(options(), OSD_OUTPUT_PROVIDER); + m_output->set_machine(&machine()); machine().output().set_notifier(nullptr, output_notifier_callback, this); m_mod_man.init(options()); diff --git a/src/osd/modules/output/output_module.h b/src/osd/modules/output/output_module.h index 81fcaae2cce..f3461d3e1f6 100644 --- a/src/osd/modules/output/output_module.h +++ b/src/osd/modules/output/output_module.h @@ -20,11 +20,16 @@ class output_module { public: - output_module() { } + output_module(): m_machine(nullptr) { } virtual ~output_module() { } virtual void notify(const char *outname, INT32 value) = 0; + + void set_machine(running_machine *machine) { m_machine = machine; }; + running_machine &machine() const { return *m_machine; } +private: + running_machine *m_machine; }; #endif /* OUTPUT_MODULE_H_ */ diff --git a/src/osd/modules/output/win32_output.cpp b/src/osd/modules/output/win32_output.cpp new file mode 100644 index 00000000000..2525dfa2bb9 --- /dev/null +++ b/src/osd/modules/output/win32_output.cpp @@ -0,0 +1,340 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +//============================================================ +// +// output.c - Win32 implementation of MAME output routines +// +//============================================================ + +#include "output_module.h" +#include "modules/osdmodule.h" +#include "modules/lib/osdobj_common.h" + +#if defined(OSD_WINDOWS) + +// standard windows headers +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +// MAME headers +#include "emu.h" +#include "winmain.h" + +#include "winutil.h" +#include "win32_output.h" + + +//============================================================ +// CONSTANTS +//============================================================ + +// window styles +#define WINDOW_STYLE WS_OVERLAPPEDWINDOW +#define WINDOW_STYLE_EX 0 + + + +//============================================================ +// TYPEDEFS +//============================================================ + +struct registered_client +{ + registered_client * next; // next client in the list + LPARAM id; // client-specified ID + HWND hwnd; // client HWND + running_machine * machine; +}; + + +// message IDs +static UINT om_mame_start; +static UINT om_mame_stop; +static UINT om_mame_update_state; +static UINT om_mame_register_client; +static UINT om_mame_unregister_client; +static UINT om_mame_get_id_string; + + + +//============================================================ +// FUNCTION PROTOTYPES +//============================================================ + +static LRESULT CALLBACK output_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); + +class output_win32 : public osd_module, public output_module +{ +public: + output_win32() + : osd_module(OSD_OUTPUT_PROVIDER, "windows"), output_module() + { + } + virtual ~output_win32() { } + + virtual int init(const osd_options &options) override; + virtual void exit() override; + + // output_module + + virtual void notify(const char *outname, INT32 value) override; + + int create_window_class(void); + LRESULT register_client(HWND hwnd, LPARAM id); + LRESULT unregister_client(HWND hwnd, LPARAM id); + LRESULT send_id_string(HWND hwnd, LPARAM id); + +private: + // our HWND + HWND m_output_hwnd; + + // client list + registered_client * m_clientlist; + +}; + + +//============================================================ +// output_init +//============================================================ + +int output_win32::init(const osd_options &options) +{ + int result; + + // reset globals + m_clientlist = nullptr; + + // create our window class + result = create_window_class(); + assert(result == 0); + (void)result; // to silence gcc 4.6 + + // create a window + m_output_hwnd = CreateWindowEx( + WINDOW_STYLE_EX, + OUTPUT_WINDOW_CLASS, + OUTPUT_WINDOW_NAME, + WINDOW_STYLE, + 0, 0, + 1, 1, + nullptr, + nullptr, + GetModuleHandleUni(), + nullptr); + assert(m_output_hwnd != nullptr); + + // set a pointer to the running machine + SetWindowLongPtr(m_output_hwnd, GWLP_USERDATA, (LONG_PTR)this); + + // allocate message ids + om_mame_start = RegisterWindowMessage(OM_MAME_START); + assert(om_mame_start != 0); + om_mame_stop = RegisterWindowMessage(OM_MAME_STOP); + assert(om_mame_stop != 0); + om_mame_update_state = RegisterWindowMessage(OM_MAME_UPDATE_STATE); + assert(om_mame_update_state != 0); + + om_mame_register_client = RegisterWindowMessage(OM_MAME_REGISTER_CLIENT); + assert(om_mame_register_client != 0); + om_mame_unregister_client = RegisterWindowMessage(OM_MAME_UNREGISTER_CLIENT); + assert(om_mame_unregister_client != 0); + om_mame_get_id_string = RegisterWindowMessage(OM_MAME_GET_ID_STRING); + assert(om_mame_get_id_string != 0); + + // broadcast a startup message + PostMessage(HWND_BROADCAST, om_mame_start, (WPARAM)m_output_hwnd, 0); + + return 0; +} + + +//============================================================ +// output_exit +//============================================================ + +void output_win32::exit() +{ + // free all the clients + while (m_clientlist != nullptr) + { + registered_client *temp = m_clientlist; + m_clientlist = temp->next; + global_free(temp); + } + + // broadcast a shutdown message + PostMessage(HWND_BROADCAST, om_mame_stop, (WPARAM)m_output_hwnd, 0); +} + + +//============================================================ +// create_window_class +//============================================================ + +int output_win32::create_window_class(void) +{ + static UINT8 classes_created = FALSE; + + /* only do this once */ + if (!classes_created) + { + WNDCLASS wc = { 0 }; + + // initialize the description of the window class + wc.lpszClassName = OUTPUT_WINDOW_CLASS; + wc.hInstance = GetModuleHandleUni(); + wc.lpfnWndProc = output_window_proc; + + UnregisterClass(wc.lpszClassName, wc.hInstance); + + // register the class; fail if we can't + if (!RegisterClass(&wc)) + return 1; + classes_created = TRUE; + } + + return 0; +} + + +//============================================================ +// output_window_proc +//============================================================ + +static LRESULT CALLBACK output_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + LONG_PTR ptr = GetWindowLongPtr(wnd, GWLP_USERDATA); + output_win32 &output = *(output_win32 *)ptr; + + // register a new client + if (message == om_mame_register_client) + return output.register_client((HWND)wparam, lparam); + + // unregister a client + else if (message == om_mame_unregister_client) + return output.unregister_client((HWND)wparam, lparam); + + // get a string for an ID + else if (message == om_mame_get_id_string) + return output.send_id_string((HWND)wparam, lparam); + + else + return DefWindowProc(wnd, message, wparam, lparam); +} + + +//============================================================ +// register_client +//============================================================ + +LRESULT output_win32::register_client(HWND hwnd, LPARAM id) +{ + registered_client **client; + + // find the end of the list; if we find ourself already registered, + // return 1 + for (client = &m_clientlist; *client != nullptr; client = &(*client)->next) + if ((*client)->id == id) + { + (*client)->hwnd = hwnd; + machine().output().notify_all(this); + return 1; + } + + // add us to the end + *client = global_alloc(registered_client); + (*client)->next = nullptr; + (*client)->id = id; + (*client)->hwnd = hwnd; + (*client)->machine = &machine(); + + // request a notification for all outputs + machine().output().notify_all(this); + return 0; +} + + +//============================================================ +// unregister_client +//============================================================ + +LRESULT output_win32::unregister_client(HWND hwnd, LPARAM id) +{ + registered_client **client; + int found = FALSE; + + // find any matching IDs in the list and remove them + for (client = &m_clientlist; *client != nullptr; client = &(*client)->next) + if ((*client)->id == id) + { + registered_client *temp = *client; + *client = (*client)->next; + global_free(temp); + found = TRUE; + break; + } + + // return an error if not found + return found ? 0 : 1; +} + + +//============================================================ +// send_id_string +//============================================================ + +LRESULT output_win32::send_id_string(HWND hwnd, LPARAM id) +{ + COPYDATASTRUCT copydata; + const char *name; + int datalen; + + // id 0 is the name of the game + if (id == 0) + name = machine().system().name; + else + name = machine().output().id_to_name(id); + + // a NULL name is an empty string + if (name == nullptr) + name = ""; + + // allocate memory for the message + datalen = sizeof(copydata_id_string) + strlen(name) + 1; + dynamic_buffer buffer(datalen); + copydata_id_string *temp = (copydata_id_string *)&buffer[0]; + temp->id = id; + strcpy(temp->string, name); + + // reply by using SendMessage with WM_COPYDATA + copydata.dwData = COPYDATA_MESSAGE_ID_STRING; + copydata.cbData = datalen; + copydata.lpData = temp; + SendMessage(hwnd, WM_COPYDATA, (WPARAM)m_output_hwnd, (LPARAM)©data); + + return 0; +} + + +//============================================================ +// notifier_callback +//============================================================ + +void output_win32::notify(const char *outname, INT32 value) +{ + registered_client *client; + // loop over clients and notify them + for (client = m_clientlist; client != nullptr; client = client->next) + { + PostMessage(client->hwnd, om_mame_update_state, client->machine->output().name_to_id(outname), value); + } +} + + + +#else + MODULE_NOT_SUPPORTED(output_win32, OSD_OUTPUT_PROVIDER, "windows") +#endif + +MODULE_DEFINITION(OUTPUT_WIN32, output_win32) diff --git a/src/osd/modules/output/win32_output.h b/src/osd/modules/output/win32_output.h new file mode 100644 index 00000000000..9d71332b44b --- /dev/null +++ b/src/osd/modules/output/win32_output.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +//============================================================ +// +// output.h - Win32 implementation of MAME output routines +// +//============================================================ + +#ifndef __WINDOWS_OUTPUT_H__ +#define __WINDOWS_OUTPUT_H__ + + +//============================================================ +// CONSTANTS +//============================================================ + +// window parameters +#define OUTPUT_WINDOW_CLASS TEXT("MAMEOutput") +#define OUTPUT_WINDOW_NAME TEXT("MAMEOutput") + +// +// These messages are sent by MAME: +// + +// OM_MAME_START: broadcast when MAME initializes +// WPARAM = HWND of MAME's output window +// LPARAM = unused +#define OM_MAME_START TEXT("MAMEOutputStart") + +// OM_MAME_STOP: broadcast when MAME shuts down +// WPARAM = HWND of MAME's output window +// LPARAM = unused +#define OM_MAME_STOP TEXT("MAMEOutputStop") + +// OM_MAME_UPDATE_STATE: sent to registered clients when the state +// of an output changes +// WPARAM = ID of the output +// LPARAM = new value for the output +#define OM_MAME_UPDATE_STATE TEXT("MAMEOutputUpdateState") + + +// +// These messages are sent by external clients to MAME: +// + +// OM_MAME_REGISTER_CLIENT: sent to MAME to register a client +// WPARAM = HWND of client's listener window +// LPARAM = client-specified ID (must be unique) +#define OM_MAME_REGISTER_CLIENT TEXT("MAMEOutputRegister") + +// OM_MAME_UNREGISTER_CLIENT: sent to MAME to unregister a client +// WPARAM = HWND of client's listener window +// LPARAM = client-specified ID (must match registration) +#define OM_MAME_UNREGISTER_CLIENT TEXT("MAMEOutputUnregister") + +// OM_MAME_GET_ID_STRING: requests the string associated with a +// given ID. ID=0 is always the name of the game. Other IDs are +// only discoverable from a OM_MAME_UPDATE_STATE message. The +// result will be sent back as a WM_COPYDATA message with MAME's +// output window as the sender, dwData = the ID of the string, +// and lpData pointing to a NULL-terminated string. +// WPARAM = HWND of client's listener window +// LPARAM = ID you wish to know about +#define OM_MAME_GET_ID_STRING TEXT("MAMEOutputGetIDString") + + +// +// These constants are used to identify WM_COPYDATA messages +// coming from MAME: +// + +#define COPYDATA_MESSAGE_ID_STRING 1 + + + +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +struct copydata_id_string +{ + UINT32 id; // ID that was requested + char string[1]; // string array containing the data +}; + +#endif /* __WINDOWS_OUTPUT_H__ */ diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc index d7e1acf8494..be1f6ef43f6 100644 --- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc +++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc @@ -97,19 +97,18 @@ float GetSpotAddend(vec2 coord, float amount) return saturate(SigmoidSpot); } -float GetRoundCornerFactor(vec2 coord, float radiusAmount, float smoothAmount) +float GetRoundCornerFactor(vec2 coord, vec2 bounds, float radiusAmount, float smoothAmount) { // reduce smooth amount down to radius amount smoothAmount = min(smoothAmount, radiusAmount); - vec2 quadDims = (u_swap_xy.x > 0.0) ? u_quad_dims.yx : u_quad_dims.xy; - - float range = min(quadDims.x, quadDims.y) * 0.5; - float radius = range * max(radiusAmount, 0.0025); - float smooth_val = 1.0 / (range * max(smoothAmount, 0.0025)); + float range = min(bounds.x, bounds.y); + float amountMinimum = range > 0.0f ? 1.0f / range : 0.0f; + float radius = range * max(radiusAmount, amountMinimum); + float smooth_val = 1.0f / (range * max(smoothAmount, amountMinimum * 3.0f)); // compute box - float box = roundBox(quadDims * (coord * 2.0f), quadDims, radius); + float box = roundBox(bounds * (coord * 2.0f), bounds, radius); // apply smooth box *= smooth_val; @@ -206,8 +205,11 @@ void main() // Round Corners Simulation vec2 RoundCornerCoord = CornerCoordCentered; + vec2 RoundCornerBounds = (u_swap_xy.x > 0.0) + ? u_quad_dims.yx + : u_quad_dims.xy; - float roundCornerFactor = GetRoundCornerFactor(RoundCornerCoord, u_round_corner.x, u_smooth_border.x); + float roundCornerFactor = GetRoundCornerFactor(RoundCornerCoord, RoundCornerBounds, u_round_corner.x * 0.5f, u_smooth_border.x * 0.5f); BaseColor.rgb *= roundCornerFactor; gl_FragColor = BaseColor; diff --git a/src/osd/modules/render/d3d/d3dhlsl.cpp b/src/osd/modules/render/d3d/d3dhlsl.cpp index 2864d740bb7..5c1bef296cf 100644 --- a/src/osd/modules/render/d3d/d3dhlsl.cpp +++ b/src/osd/modules/render/d3d/d3dhlsl.cpp @@ -722,6 +722,7 @@ void shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *r options->yiq_q = winoptions.screen_yiq_q(); options->yiq_scan_time = winoptions.screen_yiq_scan_time(); options->yiq_phase_count = winoptions.screen_yiq_phase_count(); + options->vector_beam_smooth = winoptions.screen_vector_beam_smooth(); options->vector_length_scale = winoptions.screen_vector_length_scale(); options->vector_length_ratio = winoptions.screen_vector_length_ratio(); options->bloom_blend_mode = winoptions.screen_bloom_blend_mode(); @@ -1524,6 +1525,7 @@ int shaders::vector_pass(d3d_render_target *rt, int source_index, poly_info *pol // curr_effect->set_float("TimeScale", options->vector_time_scale); curr_effect->set_float("LengthRatio", options->vector_length_ratio); curr_effect->set_float("LengthScale", options->vector_length_scale); + curr_effect->set_float("BeamSmooth", options->vector_beam_smooth); blit(rt->target_surface[next_index], true, poly->get_type(), vertnum, poly->get_count()); @@ -2285,7 +2287,8 @@ hlsl_options shaders::last_options = { false }; enum slider_option { - SLIDER_VECTOR_ATT_MAX = 0, + SLIDER_VECTOR_BEAM_SMOOTH = 0, + SLIDER_VECTOR_ATT_MAX, SLIDER_VECTOR_ATT_LEN_MIN, SLIDER_SHADOW_MASK_TILE_MODE, SLIDER_SHADOW_MASK_ALPHA, @@ -2362,6 +2365,7 @@ enum slider_screen_type slider_desc shaders::s_sliders[] = { + { "Vector Beam Smooth Amount", 0, 0, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_VECTOR, SLIDER_VECTOR_BEAM_SMOOTH, 0.01f, "%1.2f", {} }, { "Vector Attenuation Maximum", 0, 50, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_VECTOR, SLIDER_VECTOR_ATT_MAX, 0.01f, "%1.2f", {} }, { "Vector Attenuation Length Minimum", 1, 500, 1000, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_VECTOR, SLIDER_VECTOR_ATT_LEN_MIN, 0.001f, "%1.3f", {} }, { "Shadow Mask Tile Mode", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_SHADOW_MASK_TILE_MODE, 0, "%s", { "Screen", "Source" } }, @@ -2433,6 +2437,7 @@ void *shaders::get_slider_option(int id, int index) { switch (id) { + case SLIDER_VECTOR_BEAM_SMOOTH: return &(options->vector_beam_smooth); case SLIDER_VECTOR_ATT_MAX: return &(options->vector_length_scale); case SLIDER_VECTOR_ATT_LEN_MIN: return &(options->vector_length_ratio); case SLIDER_SHADOW_MASK_TILE_MODE: return &(options->shadow_mask_tile_mode); diff --git a/src/osd/modules/render/d3d/d3dhlsl.h b/src/osd/modules/render/d3d/d3dhlsl.h index abf1e48a549..6f6e31f1933 100644 --- a/src/osd/modules/render/d3d/d3dhlsl.h +++ b/src/osd/modules/render/d3d/d3dhlsl.h @@ -245,6 +245,7 @@ struct hlsl_options int yiq_phase_count; // Vectors + float vector_beam_smooth; float vector_length_scale; float vector_length_ratio; diff --git a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp index e0966fdbd62..dec0110157a 100644 --- a/src/osd/modules/render/drawbgfx.cpp +++ b/src/osd/modules/render/drawbgfx.cpp @@ -624,6 +624,13 @@ void renderer_bgfx::put_line(float x0, float y0, float x1, float y1, float r, UI dy *= d; } + // create diamond shape for points + else + { + // set distance to unit vector length (1,1) + dx = dy = 0.70710678f; + } + float nx = dy; float ny = -dx; float verts[4 * 3]; diff --git a/src/osd/modules/render/drawd3d.cpp b/src/osd/modules/render/drawd3d.cpp index 4490a8c327e..44dd1b10600 100644 --- a/src/osd/modules/render/drawd3d.cpp +++ b/src/osd/modules/render/drawd3d.cpp @@ -42,33 +42,6 @@ enum //============================================================ -// MACROS -//============================================================ - -#define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0) - - -//============================================================ -// GLOBALS -//============================================================ - -static const line_aa_step line_aa_1step[] = -{ - { 0.00f, 0.00f, 1.00f }, - { 0 } -}; - -static const line_aa_step line_aa_4step[] = -{ - { -0.25f, 0.00f, 0.25f }, - { 0.25f, 0.00f, 0.25f }, - { 0.00f, -0.25f, 0.25f }, - { 0.00f, 0.25f, 0.25f }, - { 0 } -}; - - -//============================================================ // INLINES //============================================================ @@ -1388,13 +1361,11 @@ void renderer_d3d9::batch_vectors(int vector_count) { auto win = assert_window(); - windows_options &options = downcast<windows_options &>(win->machine().options()); - float quad_width = 0.0f; float quad_height = 0.0f; - int vertex_count = vector_count * (options.antialias() ? 24 : 6); - int triangle_count = vector_count * (options.antialias() ? 8 : 2); + int vertex_count = vector_count * 6; + int triangle_count = vector_count * 2; m_vectorbatch = mesh_alloc(vertex_count); m_batchindex = 0; @@ -1499,71 +1470,103 @@ void renderer_d3d9::batch_vectors(int vector_count) void renderer_d3d9::batch_vector(const render_primitive &prim) { + // get a pointer to the vertex buffer + if (m_vectorbatch == nullptr) + { + return; + } + // compute the effective width based on the direction of the line float effwidth = prim.width; - if (effwidth < 0.5f) + if (effwidth < 2.0f) { - effwidth = 0.5f; + effwidth = 2.0f; } // determine the bounds of a quad to draw this line render_bounds b0, b1; render_line_to_quad(&prim.bounds, effwidth, effwidth, &b0, &b1); - float dx = b1.x1 - b0.x1; - float dy = b1.y1 - b0.y1; - float line_length = sqrtf(dx * dx + dy * dy); + float lx = b1.x1 - b0.x1; + float ly = b1.y1 - b0.y1; + float wx = b1.x1 - b1.x0; + float wy = b1.y1 - b1.y0; + float line_length = sqrtf(lx * lx + ly * ly); + float line_width = sqrtf(wx * wx + wy * wy); + + m_vectorbatch[m_batchindex + 0].x = b0.x0; + m_vectorbatch[m_batchindex + 0].y = b0.y0; + m_vectorbatch[m_batchindex + 1].x = b0.x1; + m_vectorbatch[m_batchindex + 1].y = b0.y1; + m_vectorbatch[m_batchindex + 2].x = b1.x0; + m_vectorbatch[m_batchindex + 2].y = b1.y0; + + m_vectorbatch[m_batchindex + 3].x = b0.x1; + m_vectorbatch[m_batchindex + 3].y = b0.y1; + m_vectorbatch[m_batchindex + 4].x = b1.x0; + m_vectorbatch[m_batchindex + 4].y = b1.y0; + m_vectorbatch[m_batchindex + 5].x = b1.x1; + m_vectorbatch[m_batchindex + 5].y = b1.y1; - // iterate over AA steps - for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim.flags) ? line_aa_4step : line_aa_1step; - step->weight != 0; step++) + if (m_shaders->enabled()) { - // get a pointer to the vertex buffer - if (m_vectorbatch == nullptr) - { - return; - } - - m_vectorbatch[m_batchindex + 0].x = b0.x0 + step->xoffs; - m_vectorbatch[m_batchindex + 0].y = b0.y0 + step->yoffs; - m_vectorbatch[m_batchindex + 1].x = b0.x1 + step->xoffs; - m_vectorbatch[m_batchindex + 1].y = b0.y1 + step->yoffs; - m_vectorbatch[m_batchindex + 2].x = b1.x0 + step->xoffs; - m_vectorbatch[m_batchindex + 2].y = b1.y0 + step->yoffs; - - m_vectorbatch[m_batchindex + 3].x = b0.x1 + step->xoffs; - m_vectorbatch[m_batchindex + 3].y = b0.y1 + step->yoffs; - m_vectorbatch[m_batchindex + 4].x = b1.x0 + step->xoffs; - m_vectorbatch[m_batchindex + 4].y = b1.y0 + step->yoffs; - m_vectorbatch[m_batchindex + 5].x = b1.x1 + step->xoffs; - m_vectorbatch[m_batchindex + 5].y = b1.y1 + step->yoffs; + // procedural generated texture + m_vectorbatch[m_batchindex + 0].u0 = 0.0f; + m_vectorbatch[m_batchindex + 0].v0 = 0.0f; + m_vectorbatch[m_batchindex + 1].u0 = 0.0f; + m_vectorbatch[m_batchindex + 1].v0 = 1.0f; + m_vectorbatch[m_batchindex + 2].u0 = 1.0f; + m_vectorbatch[m_batchindex + 2].v0 = 0.0f; + + m_vectorbatch[m_batchindex + 3].u0 = 0.0f; + m_vectorbatch[m_batchindex + 3].v0 = 1.0f; + m_vectorbatch[m_batchindex + 4].u0 = 1.0f; + m_vectorbatch[m_batchindex + 4].v0 = 0.0f; + m_vectorbatch[m_batchindex + 5].u0 = 1.0f; + m_vectorbatch[m_batchindex + 5].v0 = 1.0f; + } + else + { + vec2f& start = get_default_texture()->get_uvstart(); + vec2f& stop = get_default_texture()->get_uvstop(); - // determine the color of the line - INT32 r = (INT32)(prim.color.r * step->weight * 255.0f); - INT32 g = (INT32)(prim.color.g * step->weight * 255.0f); - INT32 b = (INT32)(prim.color.b * step->weight * 255.0f); - INT32 a = (INT32)(prim.color.a * 255.0f); - DWORD color = D3DCOLOR_ARGB(a, r, g, b); + m_vectorbatch[m_batchindex + 0].u0 = start.c.x; + m_vectorbatch[m_batchindex + 0].v0 = start.c.y; + m_vectorbatch[m_batchindex + 1].u0 = start.c.x; + m_vectorbatch[m_batchindex + 1].v0 = stop.c.y; + m_vectorbatch[m_batchindex + 2].u0 = stop.c.x; + m_vectorbatch[m_batchindex + 2].v0 = start.c.y; - // set the color, Z parameters to standard values - for (int i = 0; i < 6; i++) - { - m_vectorbatch[m_batchindex + i].x -= 0.5f; - m_vectorbatch[m_batchindex + i].y -= 0.5f; - m_vectorbatch[m_batchindex + i].z = 0.0f; - m_vectorbatch[m_batchindex + i].rhw = 1.0f; - m_vectorbatch[m_batchindex + i].color = color; + m_vectorbatch[m_batchindex + 3].u0 = start.c.x; + m_vectorbatch[m_batchindex + 3].v0 = stop.c.y; + m_vectorbatch[m_batchindex + 4].u0 = stop.c.x; + m_vectorbatch[m_batchindex + 4].v0 = start.c.y; + m_vectorbatch[m_batchindex + 5].u0 = stop.c.x; + m_vectorbatch[m_batchindex + 5].v0 = stop.c.y; + } - // no texture mapping - m_vectorbatch[m_batchindex + i].u0 = 0.0f; - m_vectorbatch[m_batchindex + i].v0 = 0.0f; + // determine the color of the line + INT32 r = (INT32)(prim.color.r * 255.0f); + INT32 g = (INT32)(prim.color.g * 255.0f); + INT32 b = (INT32)(prim.color.b * 255.0f); + INT32 a = (INT32)(prim.color.a * 255.0f); + DWORD color = D3DCOLOR_ARGB(a, r, g, b); - // line length - m_vectorbatch[m_batchindex + i].u1 = line_length; - } + // set the color, Z parameters to standard values + for (int i = 0; i < 6; i++) + { + m_vectorbatch[m_batchindex + i].x -= 0.5f; + m_vectorbatch[m_batchindex + i].y -= 0.5f; + m_vectorbatch[m_batchindex + i].z = 0.0f; + m_vectorbatch[m_batchindex + i].rhw = 1.0f; + m_vectorbatch[m_batchindex + i].color = color; - m_batchindex += 6; + // vector length/width + m_vectorbatch[m_batchindex + i].u1 = line_length; + m_vectorbatch[m_batchindex + i].v1 = line_width; } + + m_batchindex += 6; } @@ -1573,38 +1576,45 @@ void renderer_d3d9::batch_vector(const render_primitive &prim) void renderer_d3d9::draw_line(const render_primitive &prim) { + // get a pointer to the vertex buffer + vertex *vertex = mesh_alloc(4); + if (vertex == nullptr) + { + return; + } + // compute the effective width based on the direction of the line float effwidth = prim.width; - if (effwidth < 0.5f) + if (effwidth < 1.0f) { - effwidth = 0.5f; + effwidth = 1.0f; } // determine the bounds of a quad to draw this line render_bounds b0, b1; render_line_to_quad(&prim.bounds, effwidth, 0.0f, &b0, &b1); - // get a pointer to the vertex buffer - vertex *vertex = mesh_alloc(4); - if (vertex == nullptr) - return; - - // rotate the unit vector by 135 degrees and add to point 0 vertex[0].x = b0.x0; vertex[0].y = b0.y0; - - // rotate the unit vector by -135 degrees and add to point 0 vertex[1].x = b0.x1; vertex[1].y = b0.y1; - - // rotate the unit vector by 45 degrees and add to point 1 vertex[2].x = b1.x0; vertex[2].y = b1.y0; - - // rotate the unit vector by -45 degrees and add to point 1 vertex[3].x = b1.x1; vertex[3].y = b1.y1; + vec2f& start = get_default_texture()->get_uvstart(); + vec2f& stop = get_default_texture()->get_uvstop(); + + vertex[0].u0 = start.c.x; + vertex[0].v0 = start.c.y; + vertex[2].u0 = stop.c.x; + vertex[2].v0 = start.c.y; + vertex[1].u0 = start.c.x; + vertex[1].v0 = stop.c.y; + vertex[3].u0 = stop.c.x; + vertex[3].v0 = stop.c.y; + // determine the color of the line INT32 r = (INT32)(prim.color.r * 255.0f); INT32 g = (INT32)(prim.color.g * 255.0f); @@ -1618,10 +1628,6 @@ void renderer_d3d9::draw_line(const render_primitive &prim) vertex[i].z = 0.0f; vertex[i].rhw = 1.0f; vertex[i].color = color; - - // no texture mapping - vertex[i].u0 = 0.0f; - vertex[i].v0 = 0.0f; } // now add a polygon entry diff --git a/src/osd/modules/render/drawogl.cpp b/src/osd/modules/render/drawogl.cpp index 57173e8e2a4..77acf017790 100644 --- a/src/osd/modules/render/drawogl.cpp +++ b/src/osd/modules/render/drawogl.cpp @@ -1085,22 +1085,14 @@ int renderer_ogl::draw(const int update) // we're doing nothing 3d, so the Z-buffer is currently not interesting glDisable(GL_DEPTH_TEST); - if (win->machine().options().antialias()) - { - // enable antialiasing for lines - glEnable(GL_LINE_SMOOTH); - // enable antialiasing for points - glEnable(GL_POINT_SMOOTH); - - // prefer quality to speed - glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - } - else - { - glDisable(GL_LINE_SMOOTH); - glDisable(GL_POINT_SMOOTH); - } + // enable antialiasing for lines + glEnable(GL_LINE_SMOOTH); + // enable antialiasing for points + glEnable(GL_POINT_SMOOTH); + + // prefer quality to speed + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // enable blending glEnable(GL_BLEND); diff --git a/src/osd/windows/ledutil.cpp b/src/osd/windows/ledutil.cpp new file mode 100644 index 00000000000..60427b4ef8e --- /dev/null +++ b/src/osd/windows/ledutil.cpp @@ -0,0 +1,709 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,Paul Priest +//============================================================ +// +// ledutil.c - Win32 example code that tracks changing +// outputs and updates the keyboard LEDs in response +// +//============================================================ +// +// This is sample code. To use it as a starting point, you +// should do the following: +// +// 1. Change the CLIENT_ID define to something unique. +// +// 2. Change the WINDOW_CLASS and WINDOW_NAME defines to +// something unique. +// +// 3. Delete all the code from the >8 snip 8< comment and +// downward. +// +// 4. Implement the following functions: +// +// output_startup - called at app init time +// output_shutdown - called before the app exits +// output_mame_start - called when MAME starts +// output_mame_stop - called when MAME exits +// output_set_state - called whenever state changes +// +//============================================================ + +// standard windows headers +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winioctl.h> + +// standard C headers +#include <conio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// MAME output header file +typedef int running_machine; +#include "osdcomm.h" +#include "modules/output/win32_output.h" + + +//============================================================ +// DEBUGGING +//============================================================ + +// note you need to compile as a console app to have any of +// these printfs show up +#define DEBUG_VERSION 0 + +#if DEBUG_VERSION +#define DEBUG_PRINTF(x) printf x +#else +#define DEBUG_PRINTF(x) +#endif + + +//============================================================ +// CONSTANTS +//============================================================ + +// unique client ID +#define CLIENT_ID (('M' << 24) | ('L' << 16) | ('E' << 8) | ('D' << 0)) + +// LED methods +#define LED_METHOD_PS2 0 +#define LED_METHOD_USB 1 + +// window parameters +#define WINDOW_CLASS TEXT("LEDSample") +#define WINDOW_NAME TEXT("LEDSample") + +// window styles +#define WINDOW_STYLE WS_OVERLAPPEDWINDOW +#define WINDOW_STYLE_EX 0 + +// Define the keyboard indicators. +// (Definitions borrowed from ntddkbd.h) + +#define IOCTL_KEYBOARD_SET_INDICATORS CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0002, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_KEYBOARD_QUERY_TYPEMATIC CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_KEYBOARD_QUERY_INDICATORS CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define KEYBOARD_SCROLL_LOCK_ON 1 +#define KEYBOARD_NUM_LOCK_ON 2 +#define KEYBOARD_CAPS_LOCK_ON 4 + + + +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +struct KEYBOARD_INDICATOR_PARAMETERS +{ + USHORT UnitId; // Unit identifier. + USHORT LedFlags; // LED indicator state. +}; + + +struct id_map_entry +{ + id_map_entry * next; + const char * name; + WPARAM id; +}; + + + +//============================================================ +// GLOBAL VARIABLES +//============================================================ + +static int ledmethod; +static int original_state; +static int current_state; +static int pause_state; +static HANDLE hKbdDev; + +static HWND mame_target; +static HWND listener_hwnd; + +static id_map_entry * idmaplist; + +// message IDs +static UINT om_mame_start; +static UINT om_mame_stop; +static UINT om_mame_update_state; +static UINT om_mame_register_client; +static UINT om_mame_unregister_client; +static UINT om_mame_get_id_string; + + + +//============================================================ +// FUNCTION PROTOTYPES +//============================================================ + +static int create_window_class(void); +static LRESULT CALLBACK listener_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); +static LRESULT handle_mame_start(WPARAM wparam, LPARAM lparam); +static LRESULT handle_mame_stop(WPARAM wparam, LPARAM lparam); +static LRESULT handle_copydata(WPARAM wparam, LPARAM lparam); +static void reset_id_to_outname_cache(void); +static const char *map_id_to_outname(WPARAM id); +static LRESULT handle_update_state(WPARAM wparam, LPARAM lparam); + +// these functions provide the meat +static void output_startup(const char *commandline); +static void output_mame_start(void); +static void output_set_state(const char *name, INT32 state); +static void output_mame_stop(void); +static void output_shutdown(void); + +static int led_get_state(void); +static void led_set_state(int state); + + +//============================================================ +// main +//============================================================ + +int main(int argc, char *argv[]) +{ + const char *arg = (argc > 1) ? argv[1] : ""; + int exitcode = 1; + HWND otherwnd; + MSG message; + int result; + + // see if there is another instance of us running + otherwnd = FindWindow(WINDOW_CLASS, WINDOW_NAME); + + // if the argument is "-kill", post a close message + if (strcmp(arg, "-kill") == 0) + { + if (otherwnd != nullptr) + PostMessage(otherwnd, WM_QUIT, 0, 0); + return (otherwnd != nullptr) ? 1 : 0; + } + + // if we had another instance, defer to it + if (otherwnd != nullptr) + return 0; + + // call the startup code + output_startup(arg); + + // create our window class + result = create_window_class(); + if (result != 0) + goto error; + + // create a window + listener_hwnd = CreateWindowEx( + WINDOW_STYLE_EX, + WINDOW_CLASS, + WINDOW_NAME, + WINDOW_STYLE, + 0, 0, + 1, 1, + nullptr, + nullptr, + GetModuleHandle(nullptr), + nullptr); + if (listener_hwnd == nullptr) + goto error; + + // allocate message ids + om_mame_start = RegisterWindowMessage(OM_MAME_START); + if (om_mame_start == 0) + goto error; + om_mame_stop = RegisterWindowMessage(OM_MAME_STOP); + if (om_mame_stop == 0) + goto error; + om_mame_update_state = RegisterWindowMessage(OM_MAME_UPDATE_STATE); + if (om_mame_update_state == 0) + goto error; + + om_mame_register_client = RegisterWindowMessage(OM_MAME_REGISTER_CLIENT); + if (om_mame_register_client == 0) + goto error; + om_mame_unregister_client = RegisterWindowMessage(OM_MAME_UNREGISTER_CLIENT); + if (om_mame_unregister_client == 0) + goto error; + om_mame_get_id_string = RegisterWindowMessage(OM_MAME_GET_ID_STRING); + if (om_mame_get_id_string == 0) + goto error; + + // see if MAME is already running + otherwnd = FindWindow(OUTPUT_WINDOW_CLASS, OUTPUT_WINDOW_NAME); + if (otherwnd != nullptr) + handle_mame_start((WPARAM)otherwnd, 0); + + // process messages + while (GetMessage(&message, nullptr, 0, 0)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + + // reset on the way out if still live + if (mame_target != nullptr) + handle_mame_stop((WPARAM)mame_target, 0); + exitcode = 0; + +error: + // call the shutdown code + output_shutdown(); + + return exitcode; +} + + +//============================================================ +// create_window_class +//============================================================ + +static int create_window_class(void) +{ + static int classes_created = FALSE; + + /* only do this once */ + if (!classes_created) + { + WNDCLASS wc = { 0 }; + + // initialize the description of the window class + wc.lpszClassName = WINDOW_CLASS; + wc.hInstance = GetModuleHandle(nullptr); + wc.lpfnWndProc = listener_window_proc; + + // register the class; fail if we can't + if (!RegisterClass(&wc)) + return 1; + classes_created = TRUE; + } + + return 0; +} + + +//============================================================ +// window_proc +//============================================================ + +static LRESULT CALLBACK listener_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + // OM_MAME_START: register ourselves with the new MAME (first instance only) + if (message == om_mame_start) + return handle_mame_start(wparam, lparam); + + // OM_MAME_STOP: no need to unregister, just note that we've stopped caring and reset the LEDs + else if (message == om_mame_stop) + return handle_mame_stop(wparam, lparam); + + // OM_MAME_UPDATE_STATE: update the state of this item if we care + else if (message == om_mame_update_state) + return handle_update_state(wparam, lparam); + + // WM_COPYDATA: extract the string and create an ID map entry + else if (message == WM_COPYDATA) + return handle_copydata(wparam, lparam); + + // everything else is default + else + return DefWindowProc(wnd, message, wparam, lparam); +} + + +//============================================================ +// handle_mame_start +//============================================================ + +static LRESULT handle_mame_start(WPARAM wparam, LPARAM lparam) +{ + DEBUG_PRINTF(("mame_start (%08X)\n", (UINT32)wparam)); + + // make this the targeted version of MAME + mame_target = (HWND)wparam; + + // initialize the LED states + output_mame_start(); + reset_id_to_outname_cache(); + + // register ourselves as a client + PostMessage(mame_target, om_mame_register_client, (WPARAM)listener_hwnd, CLIENT_ID); + + // get the game name + map_id_to_outname(0); + return 0; +} + + +//============================================================ +// handle_mame_stop +//============================================================ + +static LRESULT handle_mame_stop(WPARAM wparam, LPARAM lparam) +{ + DEBUG_PRINTF(("mame_stop (%08X)\n", (UINT32)wparam)); + + // ignore if this is not the instance we care about + if (mame_target != (HWND)wparam) + return 1; + + // clear our target out + mame_target = nullptr; + reset_id_to_outname_cache(); + + // reset the LED states + output_mame_stop(); + return 0; +} + + +//============================================================ +// handle_copydata +//============================================================ + +static LRESULT handle_copydata(WPARAM wparam, LPARAM lparam) +{ + COPYDATASTRUCT *copydata = (COPYDATASTRUCT *)lparam; + copydata_id_string *data = (copydata_id_string *)copydata->lpData; + id_map_entry *entry; + char *string; + + DEBUG_PRINTF(("copydata (%08X)\n", (UINT32)wparam)); + + // ignore requests we don't care about + if (mame_target != (HWND)wparam) + return 1; + + // allocate memory + entry = (id_map_entry *)malloc(sizeof(*entry)); + if (entry == nullptr) + return 0; + + string = (char *)malloc(strlen(data->string) + 1); + if (string == nullptr) + { + free(entry); + return 0; + } + + // if all allocations worked, make a new entry + entry->next = idmaplist; + entry->name = string; + entry->id = data->id; + + // copy the string and hook us into the list + strcpy(string, data->string); + idmaplist = entry; + + DEBUG_PRINTF((" id %d = '%s'\n", (int)entry->id, entry->name)); + + return 0; +} + + +//============================================================ +// reset_id_to_outname_cache +//============================================================ + +static void reset_id_to_outname_cache(void) +{ + // free our ID list + while (idmaplist != nullptr) + { + id_map_entry *temp = idmaplist; + idmaplist = temp->next; + free((void*)temp->name); + free(temp); + } +} + + +//============================================================ +// map_id_to_outname +//============================================================ + +static const char *map_id_to_outname(WPARAM id) +{ + id_map_entry *entry; + + // see if we have an entry in our map + for (entry = idmaplist; entry != nullptr; entry = entry->next) + if (entry->id == id) + return entry->name; + + // no entry yet; we have to ask + SendMessage(mame_target, om_mame_get_id_string, (WPARAM)listener_hwnd, id); + + // now see if we have the entry in our map + for (entry = idmaplist; entry != nullptr; entry = entry->next) + if (entry->id == id) + return entry->name; + + // if not, use an empty string + return ""; +} + + +//============================================================ +// handle_update_state +//============================================================ + +static LRESULT handle_update_state(WPARAM wparam, LPARAM lparam) +{ + DEBUG_PRINTF(("update_state: id=%d state=%d\n", (UINT32)wparam, (UINT32)lparam)); + output_set_state(map_id_to_outname(wparam), lparam); + return 0; +} + + +// +// END BOILERPLATE CODE +// +// ------------------------>8 snip 8<------------------------- +// +// BEGIN LED-SPECIFIC CODE +// + + +//============================================================ +// output_startup +//============================================================ + +static void output_startup(const char *commandline) +{ + // default to PS/2, override if USB is specified as a parameter + ledmethod = LED_METHOD_PS2; + if (commandline != nullptr && strcmp(commandline, "-usb") == 0) + ledmethod = LED_METHOD_USB; + + // output the method + switch (ledmethod) + { + case LED_METHOD_PS2: + DEBUG_PRINTF(("Using PS/2 method\n")); + break; + + case LED_METHOD_USB: + DEBUG_PRINTF(("Using USB method\n")); + break; + } +} + + +//============================================================ +// output_shutdown +//============================================================ + +static void output_shutdown(void) +{ + // nothing to do here +} + + +//============================================================ +// output_mame_start +//============================================================ + +static void output_mame_start(void) +{ + HRESULT error_number; + + // initialize the system based on the method + switch (ledmethod) + { + case LED_METHOD_PS2: + if (!DefineDosDevice(DDD_RAW_TARGET_PATH, TEXT("Kbd"), TEXT("\\Device\\KeyboardClass0"))) + { + error_number = GetLastError(); + fprintf(stderr, "Unable to open the keyboard device. (error %d)\n", (UINT32)error_number); + return; + } + + hKbdDev = CreateFile(TEXT("\\\\.\\Kbd"), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); + if (hKbdDev == INVALID_HANDLE_VALUE) + { + error_number = GetLastError(); + fprintf(stderr, "Unable to open the keyboard device. (error %d)\n", (UINT32)error_number); + return; + } + break; + } + + // remember the initial LED states + original_state = current_state = led_get_state(); +} + + +//============================================================ +// output_mame_stop +//============================================================ + +static void output_mame_stop(void) +{ + int error_number = 0; + + // restore the initial LED states + led_set_state(original_state); + + switch (ledmethod) + { + case LED_METHOD_PS2: + if (!DefineDosDevice(DDD_REMOVE_DEFINITION, TEXT("Kbd"), nullptr)) + { + error_number = GetLastError(); + fprintf(stderr, "Unable to close the keyboard device. (error %d)\n", error_number); + return; + } + if (!CloseHandle(hKbdDev)) + { + error_number = GetLastError(); + fprintf(stderr, "Unable to close the keyboard device. (error %d)\n", error_number); + return; + } + break; + } +} + + +//============================================================ +// output_set_state +//============================================================ + +static void output_set_state(const char *outname, INT32 state) +{ + // look for pause state + if (strcmp(outname, "pause") == 0) + { + if (state) + { + pause_state = led_get_state(); + led_set_state(original_state); + } + else + { + original_state = led_get_state(); + led_set_state(pause_state); + } + } + // look for LED0/LED1/LED2 states and update accordingly + else if (strcmp(outname, "led0") == 0) + led_set_state((current_state & ~1) | (state & 1)); + else if (strcmp(outname, "led1") == 0) + led_set_state((current_state & ~2) | ((state & 1) << 1)); + else if (strcmp(outname, "led2") == 0) + led_set_state((current_state & ~4) | ((state & 1) << 2)); +} + + +//============================================================ +// led_get_state +//============================================================ + +static int led_get_state(void) +{ + int result = 0; + + switch (ledmethod) + { + case LED_METHOD_USB: + { + BYTE key_states[256]; + + // get the current state + GetKeyboardState(&key_states[0]); + + // set the numlock bit + result |= (key_states[VK_NUMLOCK] & 1); + result |= (key_states[VK_CAPITAL] & 1) << 1; + result |= (key_states[VK_SCROLL] & 1) << 2; + break; + } + + case LED_METHOD_PS2: + { + KEYBOARD_INDICATOR_PARAMETERS OutputBuffer; // Output buffer for DeviceIoControl + ULONG DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS); + ULONG ReturnedLength; // Number of bytes returned in output buffer + + // Address first keyboard + OutputBuffer.UnitId = 0; + + DeviceIoControl(hKbdDev, IOCTL_KEYBOARD_QUERY_INDICATORS, + nullptr, 0, + &OutputBuffer, DataLength, + &ReturnedLength, nullptr); + + // Demangle lights to match 95/98 + if (OutputBuffer.LedFlags & KEYBOARD_NUM_LOCK_ON) result |= 0x1; + if (OutputBuffer.LedFlags & KEYBOARD_CAPS_LOCK_ON) result |= 0x2; + if (OutputBuffer.LedFlags & KEYBOARD_SCROLL_LOCK_ON) result |= 0x4; + break; + } + } + + return result; +} + + +//============================================================ +// led_set_state +//============================================================ + +static void led_set_state(int state) +{ + current_state = state; + + switch (ledmethod) + { + case LED_METHOD_USB: + { + static const BYTE vk[3] = { VK_NUMLOCK, VK_CAPITAL, VK_SCROLL }; + BYTE keyState[256]; + int k; + + GetKeyboardState((LPBYTE)&keyState); + for (k = 0; k < 3; k++) + { + if ((((state >> k) & 1) && !(keyState[vk[k]] & 1)) || + (!((state >> k) & 1) && (keyState[vk[k]] & 1))) + { + // Simulate a key press + keybd_event(vk[k], 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0); + + // Simulate a key release + keybd_event(vk[k], 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); + } + } + + keyState[VK_NUMLOCK] = (keyState[VK_NUMLOCK] & ~1) | ((state >> 0) & 1); + keyState[VK_CAPITAL] = (keyState[VK_CAPITAL] & ~1) | ((state >> 1) & 1); + keyState[VK_SCROLL] = (keyState[VK_SCROLL] & ~1) | ((state >> 2) & 1); + SetKeyboardState(&keyState[0]); + break; + } + + case LED_METHOD_PS2: + { + KEYBOARD_INDICATOR_PARAMETERS InputBuffer; // Input buffer for DeviceIoControl + ULONG DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS); + ULONG ReturnedLength; // Number of bytes returned in output buffer + UINT LedFlags=0; + + // Demangle lights to match 95/98 + if (state & 0x1) LedFlags |= KEYBOARD_NUM_LOCK_ON; + if (state & 0x2) LedFlags |= KEYBOARD_CAPS_LOCK_ON; + if (state & 0x4) LedFlags |= KEYBOARD_SCROLL_LOCK_ON; + + // Address first keyboard + InputBuffer.UnitId = 0; + InputBuffer.LedFlags = LedFlags; + DeviceIoControl(hKbdDev, IOCTL_KEYBOARD_SET_INDICATORS, + &InputBuffer, DataLength, + nullptr, 0, + &ReturnedLength, nullptr); + break; + } + } +} diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp index ab8e99b6038..32adaa3156c 100644 --- a/src/osd/windows/winmain.cpp +++ b/src/osd/windows/winmain.cpp @@ -217,6 +217,7 @@ const options_entry windows_options::s_option_entries[] = { WINOPTION_YIQ_PHASE_COUNT";yiqp", "2", OPTION_INTEGER, "Phase Count value for NTSC signal processing" }, /* Vector simulation below this line */ { nullptr, nullptr, OPTION_HEADER, "VECTOR POST-PROCESSING OPTIONS" }, + { WINOPTION_VECTOR_BEAM_SMOOTH";vecsmooth", "0.0", OPTION_FLOAT, "The vector beam smoothness" }, { WINOPTION_VECTOR_LENGTH_SCALE";vecscale", "0.5", OPTION_FLOAT, "The maximum vector attenuation" }, { WINOPTION_VECTOR_LENGTH_RATIO";vecratio", "0.5", OPTION_FLOAT, "The minimum vector length (vector length to screen size ratio) that is affected by the attenuation" }, /* Bloom below this line */ diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index 6935130c30f..f7774922223 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -83,6 +83,7 @@ #define WINOPTION_YIQ_QVALUE "yiq_q" #define WINOPTION_YIQ_SCAN_TIME "yiq_scan_time" #define WINOPTION_YIQ_PHASE_COUNT "yiq_phase_count" +#define WINOPTION_VECTOR_BEAM_SMOOTH "vector_beam_smooth" #define WINOPTION_VECTOR_LENGTH_SCALE "vector_length_scale" #define WINOPTION_VECTOR_LENGTH_RATIO "vector_length_ratio" #define WINOPTION_BLOOM_BLEND_MODE "bloom_blend_mode" @@ -177,6 +178,7 @@ public: float screen_yiq_q() const { return float_value(WINOPTION_YIQ_QVALUE); } float screen_yiq_scan_time() const { return float_value(WINOPTION_YIQ_SCAN_TIME); } int screen_yiq_phase_count() const { return int_value(WINOPTION_YIQ_PHASE_COUNT); } + float screen_vector_beam_smooth() const { return float_value(WINOPTION_VECTOR_BEAM_SMOOTH); } float screen_vector_length_scale() const { return float_value(WINOPTION_VECTOR_LENGTH_SCALE); } float screen_vector_length_ratio() const { return float_value(WINOPTION_VECTOR_LENGTH_RATIO); } int screen_bloom_blend_mode() const { return int_value(WINOPTION_BLOOM_BLEND_MODE); } |