diff options
-rw-r--r-- | scripts/src/bus.lua | 2 | ||||
-rw-r--r-- | scripts/src/formats.lua | 12 | ||||
-rw-r--r-- | src/devices/bus/s100/vectordualmode.cpp | 327 | ||||
-rw-r--r-- | src/devices/bus/s100/vectordualmode.h | 55 | ||||
-rw-r--r-- | src/emu/xtal.cpp | 1 | ||||
-rw-r--r-- | src/lib/formats/all.cpp | 9 | ||||
-rw-r--r-- | src/lib/formats/vgi_dsk.cpp | 146 | ||||
-rw-r--r-- | src/lib/formats/vgi_dsk.h | 34 | ||||
-rw-r--r-- | src/mame/mame.lst | 3 | ||||
-rw-r--r-- | src/mame/mess.flt | 1 | ||||
-rw-r--r-- | src/mame/vectorgraphic/sbcvideo.cpp | 183 | ||||
-rw-r--r-- | src/mame/vectorgraphic/sbcvideo.h | 43 | ||||
-rw-r--r-- | src/mame/vectorgraphic/vector4.cpp | 315 |
13 files changed, 1131 insertions, 0 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 154370c0759..315b14927ca 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -2270,6 +2270,8 @@ if (BUSES["S100"]~=null) then MAME_DIR .. "src/devices/bus/s100/polyvti.h", MAME_DIR .. "src/devices/bus/s100/seals8k.cpp", MAME_DIR .. "src/devices/bus/s100/seals8k.h", + MAME_DIR .. "src/devices/bus/s100/vectordualmode.cpp", + MAME_DIR .. "src/devices/bus/s100/vectordualmode.h", MAME_DIR .. "src/devices/bus/s100/wunderbus.cpp", MAME_DIR .. "src/devices/bus/s100/wunderbus.h", } diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index 0fc21bb1941..92055468830 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -2054,6 +2054,18 @@ end -------------------------------------------------- -- +--@src/lib/formats/vgi_dsk.h,FORMATS["VGI_DSK"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "VGI_DSK") then + files { + MAME_DIR.. "src/lib/formats/vgi_dsk.cpp", + MAME_DIR.. "src/lib/formats/vgi_dsk.h", + } +end + +-------------------------------------------------- +-- --@src/lib/formats/victor9k_dsk.h,FORMATS["VICTOR9K_DSK"] = true -------------------------------------------------- diff --git a/src/devices/bus/s100/vectordualmode.cpp b/src/devices/bus/s100/vectordualmode.cpp new file mode 100644 index 00000000000..00e80cadef5 --- /dev/null +++ b/src/devices/bus/s100/vectordualmode.cpp @@ -0,0 +1,327 @@ +// license:BSD-3-Clause +// copyright-holders:Eric Anderson +/*************************************************************************** + +Vector Graphic had two related disk controllers for the Vector 4. There was +the "dual-mode" ST506-interface HDD/5.25" FDD controller and a stripped-down +5.25" FDD-only controller. Both can handle four FDD. The dual-mode version +supports a HDD as drive 0, replacing a FDD when used. + +The floppy and hard drive formatting is not IBM compatible. Instead they are +based on the Micropolis MFM hard-sectored format which starts and ends the +sector with 0x00 preamble and postable bytes and starts sector data with a +0xFF sync byte. The FDD has 16 hard sectors, but the HDD uses a normal +soft-sectored drive with a PLL on the controller to emulate 32 hard sectors. +No abnormal MFM clock bits are used. + +https://www.bitsavers.org/pdf/vectorGraphic/hardware/7200-1200-02-1_Dual-Mode_Disk_Controller_Board_Engineering_Documentation_Feb81.pdf +https://archive.org/details/7200-0001-vector-4-technical-information-sep-82 + +TODO: +- HDD support +- ECC + +****************************************************************************/ + +#include "emu.h" +#include "vectordualmode.h" + +#include "formats/vgi_dsk.h" + +static const attotime half_bitcell_size = attotime::from_usec(2); + +/* Interleave 8 bits with zeros. abcdefgh -> 0a0b0c0d0e0f0g0h */ +static int deposit8(int data) +{ + int d = data; + d = ((d & 0xf0) << 4) | (d & 0x0f); + d = ((d << 2) | d) & 0x3333; + d = ((d << 1) | d) & 0x5555; + return d; +} + +static uint16_t mfm_byte(uint8_t data, unsigned int prev_data) +{ + const unsigned int ext_data = data | (prev_data << 8); + const unsigned int clock = ~(ext_data | (ext_data >> 1)); + return (deposit8(clock) << 1) | deposit8(ext_data); +} + +static uint8_t unmfm_byte(uint16_t mfm) +{ + unsigned int d = mfm; + d &= 0x5555; + d = ((d >> 1) | d) & 0x3333; + d = ((d >> 2) | d) & 0x0f0f; + d = ((d >> 4) | d) & 0x00ff; + return d; +} + +s100_vector_dualmode_device::s100_vector_dualmode_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, S100_VECTOR_DUALMODE, tag, owner, clock) + , device_s100_card_interface(mconfig, *this) + , m_floppy(*this, "floppy%u", 0U) + , m_ram{0} + , m_cmar(0) + , m_drive(0) + , m_sector(0) + , m_read(false) + , m_pll() + , m_byte_timer(nullptr) + , m_sector_timer(nullptr) + , m_pending_byte(0) + , m_pending_size(0) +{ +} + +TIMER_CALLBACK_MEMBER(s100_vector_dualmode_device::motor_off) +{ + for (int i = 0; i < m_floppy.size(); i++) { + floppy_image_device* flop = m_floppy[m_drive]->get_device(); + if (flop) + flop->mon_w(1); + } +} + +bool s100_vector_dualmode_device::hdd_selected() +{ + // TODO: HDD support + return m_drive == 0 && false; +} + +uint8_t s100_vector_dualmode_device::s100_sinp_r(offs_t offset) +{ + // 7200-1200-02-1 page 16 (1-10) + uint8_t data; + if (offset == 0xc0) { // status (0) port + bool write_protect; // FDD + bool ready; // HDD + bool track0; + bool write_fault = false; // HDD + bool seek_complete; // HDD + bool loss_of_sync; // HDD + if (hdd_selected()) { + write_protect = false; + ready = true; + track0 = false; + seek_complete = true; + loss_of_sync = true; + } else { + floppy_image_device* flop = m_floppy[m_drive]->get_device(); + write_protect = flop && flop->wpt_r(); + ready = false; + track0 = flop && !flop->trk00_r(); + seek_complete = false; + loss_of_sync = false; + } + + data = (write_protect ? 0x01 : 0) + | (ready ? 0x02 : 0) + | (track0 ? 0x04 : 0) + | (write_fault ? 0x08 : 0) + | (seek_complete ? 0x10 : 0) + | (loss_of_sync ? 0x20 : 0) + | 0xc0; + } else if (offset == 0xc1) { // status (1) port + bool floppy_disk_selected; + bool controller_busy = m_sector_timer->enabled(); + bool motor_on; // FDD + bool type_of_hard_disk = true; + if (hdd_selected()) { + floppy_disk_selected = false; + motor_on = false; + } else { + floppy_disk_selected = true; + motor_on = m_motor_on_timer->enabled(); + } + data = (floppy_disk_selected ? 0x01 : 0) + | (controller_busy ? 0x02 : 0) + | (motor_on ? 0x04 : 0) + | (type_of_hard_disk ? 0x08 : 0) + | 0xf0; + } else if (offset == 0xc2) { // data port + data = m_ram[m_cmar]; + if (!machine().side_effects_disabled()) { + m_cmar++; + m_cmar &= 0x1ff; + } + } else if (offset == 0xc3) { // reset port + if (!machine().side_effects_disabled()) + m_cmar = 0; + data = 0xff; + } else { + data = 0xff; + } + return data; +} + +void s100_vector_dualmode_device::s100_sout_w(offs_t offset, uint8_t data) +{ + // TODO: check actual behavior when controller is busy + if (m_sector_timer->enabled()) { + return; + } + // 7200-1200-02-1 page 14 (1-8) + if (offset == 0xc0) { // control (0) port + m_drive = BIT(data, 0, 2); + const uint8_t head = BIT(data, 2, 3); + const bool step = BIT(data, 5); + const bool step_in = BIT(data, 6); + //uint8_t low_current = BIT(data, 7); + + for (int i = 0; i < m_floppy.size(); i++) { + floppy_image_device* flop = m_floppy[m_drive]->get_device(); + if (flop) + flop->mon_w(0); + } + // WR0| triggers U60, a 74LS123 with 100uF cap and 100k res + m_motor_on_timer->adjust(attotime::from_usec(2819600)); + + floppy_image_device* flop = m_floppy[m_drive]->get_device(); + if (flop) { + flop->ss_w(head & 1); + // Software should not change other bits when pulsing step + flop->stp_w(!step); + flop->dir_w(!step_in); + } + } else if (offset == 0xc1) { // control (1) port + m_sector = BIT(data, 0, 5); + m_read = BIT(data, 5); + } else if (offset == 0xc2) { // data port + m_ram[m_cmar++] = data; + m_cmar &= 0x1ff; + } else if (offset == 0xc3) { // start port + floppy_image_device* flop = m_floppy[m_drive]->get_device(); + if (!flop || flop->time_next_index().is_never()) + return; + const attotime rot_time = attotime::from_msec(200); + attotime sector_time = flop->time_next_index() - machine().time() + (rot_time / 16) * m_sector; + if (sector_time > rot_time) + sector_time -= rot_time; + m_sector_timer->adjust(sector_time, SECTOR_START); + } +} + +bool s100_vector_dualmode_device::get_next_bit(attotime &tm, const attotime &limit) +{ + int bit = m_pll.get_next_bit(tm, m_floppy[m_drive]->get_device(), limit); + if (bit < 0) + return false; + m_pending_byte <<= 1; + m_pending_byte |= bit; + m_pending_size++; + return true; +} + +TIMER_CALLBACK_MEMBER(s100_vector_dualmode_device::sector_cb) +{ + switch (param) { + case SECTOR_START: + if (m_read) { + m_pll.set_clock(half_bitcell_size); + m_pll.read_reset(machine().time()); + attotime tm; + attotime limit = machine().time() + half_bitcell_size*512; + while (get_next_bit(tm, limit)) {} // init PLL + limit += half_bitcell_size*16*30; + while (get_next_bit(tm, limit) && m_pending_byte != 0x5554) {} + if (m_pending_byte == 0x5554) { + m_pending_size = 1; + m_byte_timer->adjust(tm - machine().time()); + } + } else { + m_pending_size = 0; + m_byte_timer->adjust(attotime::zero); + } + m_sector_timer->adjust(attotime::from_msec(200)/16, SECTOR_END); + break; + + case SECTOR_END: + m_byte_timer->enable(false); + if (m_read) + m_ram[274] = 0; // Ignore ECC + break; + } +} + +TIMER_CALLBACK_MEMBER(s100_vector_dualmode_device::byte_cb) +{ + if (m_read) { + if (m_pending_size == 16) { + m_pending_size = 0; + m_ram[m_cmar++] = unmfm_byte(m_pending_byte); + m_cmar &= 0x1ff; + } + attotime tm; + while (m_pending_size != 16 && get_next_bit(tm, attotime::never)) {} + m_byte_timer->adjust(tm - machine().time()); + } else { + if (m_pending_size == 16) { + attotime start_time = machine().time() - half_bitcell_size*m_pending_size; + attotime tm = start_time + attotime::from_usec(1); + attotime buf[8]; + int pos = 0; + while (m_pending_size) { + if (m_pending_byte & (1 << --m_pending_size)) + buf[pos++] = tm; + tm += half_bitcell_size; + } + floppy_image_device *floppy = m_floppy[m_drive]->get_device(); + if (floppy) + floppy->write_flux(start_time, machine().time(), pos, buf); + } + uint8_t last = m_cmar ? m_ram[m_cmar-1] : 0; + m_pending_byte = mfm_byte(m_ram[m_cmar++], last); + m_pending_size = 16; + m_cmar &= 0x1ff; + m_byte_timer->adjust(half_bitcell_size*16); + } +} + +void s100_vector_dualmode_device::device_start() +{ + m_motor_on_timer = timer_alloc(FUNC(s100_vector_dualmode_device::motor_off), this); + m_byte_timer = timer_alloc(FUNC(s100_vector_dualmode_device::byte_cb), this); + m_sector_timer = timer_alloc(FUNC(s100_vector_dualmode_device::sector_cb), this); + + save_item(NAME(m_ram)); + save_item(NAME(m_cmar)); + save_item(NAME(m_drive)); + save_item(NAME(m_sector)); + save_item(NAME(m_read)); + save_item(NAME(m_pending_byte)); + save_item(NAME(m_pending_size)); +} + +void s100_vector_dualmode_device::device_reset() +{ + // POC| resets + // U9 + m_drive = 0; + // U18 + m_sector = 0; + m_read = false; + // U60 + m_motor_on_timer->enable(false); +} + +static void vector4_floppies(device_slot_interface &device) +{ + device.option_add("525", FLOPPY_525_QD); +} + +static void vector4_formats(format_registration &fr) +{ + fr.add_mfm_containers(); + fr.add(FLOPPY_VGI_FORMAT); +} + +void s100_vector_dualmode_device::device_add_mconfig(machine_config &config) +{ + FLOPPY_CONNECTOR(config, m_floppy[0], vector4_floppies, "525", vector4_formats).enable_sound(true); + FLOPPY_CONNECTOR(config, m_floppy[1], vector4_floppies, "525", vector4_formats).enable_sound(true); + FLOPPY_CONNECTOR(config, m_floppy[2], vector4_floppies, "525", vector4_formats).enable_sound(true); + FLOPPY_CONNECTOR(config, m_floppy[3], vector4_floppies, "525", vector4_formats).enable_sound(true); +} + +DEFINE_DEVICE_TYPE(S100_VECTOR_DUALMODE, s100_vector_dualmode_device, "vectordualmode", "Vector Dual-Mode Disk Controller") diff --git a/src/devices/bus/s100/vectordualmode.h b/src/devices/bus/s100/vectordualmode.h new file mode 100644 index 00000000000..e3a924a94c3 --- /dev/null +++ b/src/devices/bus/s100/vectordualmode.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Eric Anderson +#ifndef MAME_BUS_S100_VECTORDUALMODE_H +#define MAME_BUS_S100_VECTORDUALMODE_H + +#pragma once + +#include "bus/s100/s100.h" +#include "imagedev/floppy.h" +#include "machine/fdc_pll.h" + +class s100_vector_dualmode_device : + public device_t, + public device_s100_card_interface +{ +public: + s100_vector_dualmode_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + void device_start() override; + void device_reset() override; + void device_add_mconfig(machine_config &config) override; + + uint8_t s100_sinp_r(offs_t offset) override; + void s100_sout_w(offs_t offset, uint8_t data) override; + +private: + TIMER_CALLBACK_MEMBER(motor_off); + TIMER_CALLBACK_MEMBER(sector_cb); + TIMER_CALLBACK_MEMBER(byte_cb); + bool hdd_selected(); + bool get_next_bit(attotime &tm, const attotime &limit); + + required_device_array<floppy_connector, 4> m_floppy; + uint8_t m_ram[512]; + uint16_t m_cmar; + uint8_t m_drive; + uint8_t m_sector; + bool m_read; + emu_timer *m_motor_on_timer; + + enum sector_timer_state { + SECTOR_START, + SECTOR_END, + }; + fdc_pll_t m_pll; + emu_timer *m_byte_timer; + emu_timer *m_sector_timer; + uint16_t m_pending_byte; + uint8_t m_pending_size; +}; + +DECLARE_DEVICE_TYPE(S100_VECTOR_DUALMODE, s100_vector_dualmode_device) + +#endif // MAME_BUS_S100_VECTORDUALMODE_H diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp index 9505cad64c5..8367a55cfb4 100644 --- a/src/emu/xtal.cpp +++ b/src/emu/xtal.cpp @@ -402,6 +402,7 @@ const double XTAL::known_xtals[] = { 32'256'000, /* 32.256_MHz_XTAL Hitachi MB-6890 */ 32'317'400, /* 32.3174_MHz_XTAL DEC VT330, VT340 */ 32'530'470, /* 32.53047_MHz_XTAL Seta 2 */ + 32'640'000, /* 32.64_MHz_XTAL Vector 4 */ 32'768'000, /* 32.768_MHz_XTAL Roland D-50 audio clock */ 33'000'000, /* 33_MHz_XTAL Sega Model 3 video board */ 33'264'000, /* 33.264_MHz_XTAL Hazeltine 1500 terminal */ diff --git a/src/lib/formats/all.cpp b/src/lib/formats/all.cpp index b8d0089f3f9..017c81b3ce9 100644 --- a/src/lib/formats/all.cpp +++ b/src/lib/formats/all.cpp @@ -680,6 +680,10 @@ #include "vg5k_cas.h" #endif +#ifdef HAS_FORMATS_VGI_DSK +#include "vgi_dsk.h" +#endif + #ifdef HAS_FORMATS_VICTOR9K_DSK #include "victor9k_dsk.h" #endif @@ -1396,6 +1400,11 @@ void mame_formats_full_list(mame_formats_enumerator &en) en.add(mbee_cassette_formats); // mbee_cas.h #endif + en.category("Micropolis"); +#ifdef HAS_FORMATS_VGI_DSK + en.add(FLOPPY_VGI_FORMAT); // vgi_dsk.h +#endif + en.category("Orao"); #ifdef HAS_FORMATS_ORAO_CAS en.add(orao_cassette_formats); // orao_cas.h diff --git a/src/lib/formats/vgi_dsk.cpp b/src/lib/formats/vgi_dsk.cpp new file mode 100644 index 00000000000..c15bba33d86 --- /dev/null +++ b/src/lib/formats/vgi_dsk.cpp @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Eric Anderson +/********************************************************************* + +Micropolis VGI disk image format + +The format is essentially an HCS-ordered sector image, but with raw +275 byte sectors. The sector format is: SYNC (0xFF), track, sector, +10 byte "user data", 256 byte data, checksum, 4 byte ECC, ECC present +flag. + +http://www.bitsavers.org/pdf/micropolis/metafloppy/1084-01_1040_1050_Users_Manual_Apr79.pdf + +*********************************************************************/ + +#include "vgi_dsk.h" +#include "ioprocs.h" + +#include <cstring> + +static const int track_size = 100'000; +static const int half_bitcell_size = 2000; + +micropolis_vgi_format::micropolis_vgi_format() : floppy_image_format_t() +{ +} + +struct format { + int head_count; + int track_count; + uint32_t variant; +}; + +static const format formats[] = { + {1, 35, floppy_image::SSDD}, // MOD-I + {2, 35, floppy_image::DSDD}, + {1, 77, floppy_image::SSQD}, // MOD-II + {2, 77, floppy_image::DSQD}, + {} +}; + +static format find_format(int file_size) +{ + for (int i = 0; formats[i].head_count; i++) + if (file_size == formats[i].head_count * formats[i].track_count * 16 * 275) + return formats[i]; + return {}; +} + +int micropolis_vgi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + uint64_t file_size; + if (io.length(file_size)) + return 0; + format fmt = find_format(file_size); + if (!fmt.head_count) + return 0; + if (!has_variant(variants, fmt.variant)) + return 0; + return FIFID_SIZE; +} + +bool micropolis_vgi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) const +{ + uint64_t file_size; + if (io.length(file_size)) + return false; + const format fmt = find_format(file_size); + if (!fmt.head_count) + return false; + image->set_variant(fmt.variant); + + std::vector<uint32_t> buf; + uint8_t sector_bytes[275]; + for (int head = 0; head < fmt.head_count; head++) { + for (int track = 0; track < fmt.track_count; track++) { + for (int sector = 0; sector < 16; sector++) { + for (int i = 0; i < 40; i++) + mfm_w(buf, 8, 0, half_bitcell_size); + std::size_t actual; + if (io.read(sector_bytes, std::size(sector_bytes), actual)) + return false; + for (int i = 0; i < std::size(sector_bytes); i++) + mfm_w(buf, 8, sector_bytes[i], half_bitcell_size); + while (buf.size() < track_size/16 * (sector+1)) + mfm_w(buf, 8, 0, half_bitcell_size); + } + generate_track_from_levels(track, head, buf, 0, image); + buf.clear(); + } + } + return true; +} + +bool micropolis_vgi_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) const +{ + uint32_t variant = image->get_variant(); + format fmt = {}; + for (int i = 0; formats[i].head_count; i++) + if (variant == formats[i].variant) + fmt = formats[i]; + if (!fmt.head_count) { + int heads, tracks; + image->get_actual_geometry(tracks, heads); + if (heads == 0 && tracks == 0) + return false; // Brand-new image; we don't know the size yet + for (int i = 0; formats[i].head_count; i++) + if (heads <= formats[i].head_count && tracks <= formats[i].track_count) + fmt = formats[i]; + } + if (!fmt.head_count) + return false; + + if (io.seek(0, SEEK_SET)) + return false; + uint8_t sector_bytes[275]; + for (int head = 0; head < fmt.head_count; head++) { + for (int track = 0; track < fmt.track_count; track++) { + std::vector<bool> bitstream = generate_bitstream_from_track(track, head, half_bitcell_size, image); + for (int sector = 0; sector < 16; sector++) { + int sector_start = track_size/16 * sector; + uint32_t pos = sector_start + 512 - 16; + uint16_t shift_reg = 0; + while (pos < sector_start + 60*16 && pos < bitstream.size()) { + shift_reg = (shift_reg << 1) | bitstream[pos++]; + if (shift_reg == 0x5554) + break; + } + if (shift_reg == 0x5554) { + pos--; + for (int i = 0; i < std::size(sector_bytes); i++) + sector_bytes[i] = sbyte_mfm_r(bitstream, pos); + } else { + memset(sector_bytes, 0, std::size(sector_bytes)); + } + + std::size_t actual; + if (io.write(sector_bytes, std::size(sector_bytes), actual)) + return false; + } + } + } + return true; +} + +const micropolis_vgi_format FLOPPY_VGI_FORMAT; diff --git a/src/lib/formats/vgi_dsk.h b/src/lib/formats/vgi_dsk.h new file mode 100644 index 00000000000..876481f10f0 --- /dev/null +++ b/src/lib/formats/vgi_dsk.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Eric Anderson +/********************************************************************* + +Micropolis VGI disk image format + +The Micropolis disk format was used in Vector Graphic machines. + +*********************************************************************/ +#ifndef MAME_FORMATS_VGI_DSK_H +#define MAME_FORMATS_VGI_DSK_H + +#pragma once + +#include "flopimg.h" + +class micropolis_vgi_format : public floppy_image_format_t +{ +public: + micropolis_vgi_format(); + + int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; + bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) const override; + bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) const override; + + const char *name() const override { return "vgi"; } + const char *description() const override { return "Micropolis VGI disk image"; } + const char *extensions() const override { return "vgi"; } + bool supports_save() const override { return true; } +}; + +extern const micropolis_vgi_format FLOPPY_VGI_FORMAT; + +#endif // MAME_FORMATS_VGI_DSK_H diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 9fff4d896a9..86318e114e9 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -44640,6 +44640,9 @@ squaitsa // (c) 1985 @source:valadon/tankbust.cpp tankbust // (c) 1985 +@source:vectorgraphic/vector4.cpp +vector4 // + @source:venture/looping.cpp looping // (c) 1982 Video Games GmbH loopingv // (c) 1982 Video Games GmbH (Venture Line license) diff --git a/src/mame/mess.flt b/src/mame/mess.flt index c53fd35580a..374e899a402 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -1221,6 +1221,7 @@ ussr/unior.cpp ussr/ut88.cpp ussr/vector06.cpp ussr/vta2000.cpp +vectorgraphic/vector4.cpp verifone/tranz330.cpp vidbrain/vidbrain.cpp videoton/tvc.cpp diff --git a/src/mame/vectorgraphic/sbcvideo.cpp b/src/mame/vectorgraphic/sbcvideo.cpp new file mode 100644 index 00000000000..eb9a7918f66 --- /dev/null +++ b/src/mame/vectorgraphic/sbcvideo.cpp @@ -0,0 +1,183 @@ +// license:BSD-3-Clause +// copyright-holders:Eric Anderson +#include "emu.h" + +#include "sbcvideo.h" + +#include "video/cgapal.h" + +#include "screen.h" + +vector_sbc_video_device::vector_sbc_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, SBC_VIDEO, tag, owner, clock) + , m_io_sbc_video_conf(*this, "SBC_VIDEO_CONF") + , m_buffer(*this, finder_base::DUMMY_TAG) + , m_chrroml(*this, finder_base::DUMMY_TAG) + , m_chrromr(*this, finder_base::DUMMY_TAG) + , m_res320_ram{0} +{ +} + +void vector_sbc_video_device::spr_w(uint8_t data) +{ + m_spr = data; +} + +void vector_sbc_video_device::res320_mapping_ram_w(offs_t offset, uint8_t data) +{ + // 7200-0001 page 209 (VI A-6) C6 + m_res320_ram[offset & 0x3] = data & 0x0F; +} + +static inline rgb_t raw_4bit_to_rgb(uint8_t enc, bool color) +{ + if (color) { + return rgb_t(cga_palette[enc][0], cga_palette[enc][1], cga_palette[enc][2]); + } else { + // 7200-0001 page 209 C1. Flip R and G + enc = (enc & 0xc) | (BIT(enc, 0, 1) << 1) | BIT(enc, 1, 1); + uint8_t px = enc | (enc << 4); + return rgb_t(0, px, 0); + } +} + +MC6845_UPDATE_ROW(vector_sbc_video_device::update_row) +{ + uint32_t monochrome_color = rgb_t(0x00, 0xff, 0x00); + bool graph = BIT(m_spr, 1); // ALPHA|/GRAPH + bool gry = BIT(m_spr, 2); // DIG|/GRY + bool res320 = BIT(m_spr, 3); // 320/160| + bool chr1 = BIT(m_spr, 4); // CHR0|/CHR1 + // Color is available only on an external/second monitor, via a CGA + // connector. But the color monitor is not provided output for + // monochrome modes (only if GRAPH and GRY). The same pixel value is used + // by the builtin monitor and RGBI monitor, but they interpret the value + // differently. + bool color = (m_io_sbc_video_conf->read() & 0x1) == 0x1; + // video never uses MA17. 7200-0001 209 B5 + uint32_t addr = BIT(ma, 0, 10); // U82 U100 + uint8_t jumper_c = (m_io_sbc_video_conf->read() >> 1) & 0x7; + if (graph) + addr |= (ra | (BIT(ma, 11, 2) << 4)) << 10; // U81 + else + addr |= (BIT(ma, 10, 4) | (jumper_c << 4)) << 10; // U99 + addr <<= 1; + + // The display is always 312 scanlines. + // The horizonal resolution is 1280 in alpha mode, 640 in high res mode + // (monochrome), and 320 or 160 in gray/color scale mode. 320 and 160 modes + // have the same color space, but the 320 mode uses a palette. + // Buffer is 1920 bytes for Alpha mode, and 24960 bytes for Graphic mode. + + uint32_t *p = &bitmap.pix(y); + + if (graph) { + if (gry) { + // 7200-0001 page 83 (II 3-20) + if (res320) { + for (uint16_t x = 0; x < x_count*2; x++) { + uint8_t cell = m_buffer->read(x+addr); + rgb_t px1 = raw_4bit_to_rgb(m_res320_ram[BIT(cell, 0, 2)], color); + for (int i = 0; i < 4; i++) + *p++ = px1; + rgb_t px2 = raw_4bit_to_rgb(m_res320_ram[BIT(cell, 2, 2)], color); + for (int i = 0; i < 4; i++) + *p++ = px2; + rgb_t px3 = raw_4bit_to_rgb(m_res320_ram[BIT(cell, 4, 2)], color); + for (int i = 0; i < 4; i++) + *p++ = px3; + rgb_t px4 = raw_4bit_to_rgb(m_res320_ram[BIT(cell, 6, 2)], color); + for (int i = 0; i < 4; i++) + *p++ = px4; + } + } else { // 160 + for (uint16_t x = 0; x < x_count*2; x++) { + uint8_t cell = m_buffer->read(x+addr); + rgb_t px1 = raw_4bit_to_rgb(BIT(cell, 0, 4), color); + for (int i = 0; i < 8; i++) + *p++ = px1; + rgb_t px2 = raw_4bit_to_rgb(BIT(cell, 4, 4), color); + for (int i = 0; i < 8; i++) + *p++ = px2; + } + } + } else { // DIG + for (uint16_t x = 0; x < x_count*2; x++) { + uint8_t cell = m_buffer->read(x+addr); + for (int i = 0; i < 8; i++) { + *p++ = BIT(cell, i) ? monochrome_color : 0; + *p++ = BIT(cell, i) ? monochrome_color : 0; + } + } + } + } else { // ALPHA + for (uint16_t x = 0; x < x_count*2; x++) { + // Character Generators. 7200-0001 page 69 (II 3-6) C4 + uint8_t cell = m_buffer->read(x+addr); + uint8_t chr = cell & 0x7F; + uint8_t invert = BIT(cell, 7); + uint8_t gfxl = m_chrroml[chr | (ra << 7) | (chr1 << 11)]; + uint8_t gfxr = m_chrromr[chr | (ra << 7) | (chr1 << 11)]; + + if (!invert) { + gfxl ^= 0xff; + gfxr ^= 0xff; + } + + // Alpha Mode Shift Registers. C3 + for (int i = 0; i < 8; i++) + *p++ = BIT(gfxr, i) ? monochrome_color : 0; + for (int i = 0; i < 8; i++) + *p++ = BIT(gfxl, i) ? monochrome_color : 0; + } + } +} + +void vector_sbc_video_device::device_add_mconfig(machine_config &config) +{ + // CPU|/VID used as a clock + c6545_1_device &crtc(C6545_1(config, "crtc", DERIVED_CLOCK(1, 32))); + crtc.set_screen("screen"); + crtc.set_show_border_area(false); + crtc.set_char_width(16*2); + crtc.set_update_row_callback(FUNC(vector_sbc_video_device::update_row)); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_raw(32'640'000, 1600, 0, 1280, 340, 0, 312); + screen.set_screen_update(crtc, FUNC(c6545_1_device::screen_update)); +} + +void vector_sbc_video_device::device_start() +{ + save_item(NAME(m_spr)); + save_item(NAME(m_res320_ram)); +} + +void vector_sbc_video_device::device_reset() +{ + m_spr = 0; +} + +INPUT_PORTS_START( sbc_video ) + PORT_START("SBC_VIDEO_CONF") + PORT_CONFNAME(0x001, 0x000, "Color Monitor") + PORT_CONFSETTING(0x000, DEF_STR(No)) + PORT_CONFSETTING(0x001, DEF_STR(Yes)) + + PORT_CONFNAME(0x00e, 0x002, "Alpha Graphic Memory Block") + PORT_CONFSETTING(0x000, "0x00000-0x07FFFF") + PORT_CONFSETTING(0x002, "0x08000-0x0FFFFF") + PORT_CONFSETTING(0x004, "0x10000-0x17FFFF") + PORT_CONFSETTING(0x006, "0x18000-0x1FFFFF") + PORT_CONFSETTING(0x008, "0x20000-0x27FFFF") + PORT_CONFSETTING(0x00a, "0x28000-0x2FFFFF") + PORT_CONFSETTING(0x00c, "0x30000-0x37FFFF") + PORT_CONFSETTING(0x00e, "0x38000-0x3FFFFF") +INPUT_PORTS_END + +ioport_constructor vector_sbc_video_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(sbc_video); +} + +DEFINE_DEVICE_TYPE(SBC_VIDEO, vector_sbc_video_device, "vectorsbcvideo", "Vector SBC Video Output") diff --git a/src/mame/vectorgraphic/sbcvideo.h b/src/mame/vectorgraphic/sbcvideo.h new file mode 100644 index 00000000000..490ecb9fa75 --- /dev/null +++ b/src/mame/vectorgraphic/sbcvideo.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Eric Anderson +#ifndef MAME_VECTORGRAPHIC_SBCVIDEO_H +#define MAME_VECTORGRAPHIC_SBCVIDEO_H + +#pragma once + +#include "machine/ram.h" +#include "video/mc6845.h" + + +class vector_sbc_video_device : public device_t +{ +public: + vector_sbc_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template <typename T> void set_buffer(T &&tag) { m_buffer.set_tag(std::forward<T>(tag)); } + template <typename T> void set_chrroml(T &&tag) { m_chrroml.set_tag(std::forward<T>(tag)); } + template <typename T> void set_chrromr(T &&tag) { m_chrromr.set_tag(std::forward<T>(tag)); } + + void spr_w(uint8_t data); + void res320_mapping_ram_w(offs_t offset, uint8_t data); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + +private: + MC6845_UPDATE_ROW(update_row); + + required_ioport m_io_sbc_video_conf; + required_device<ram_device> m_buffer; + required_region_ptr<uint8_t> m_chrroml; + required_region_ptr<uint8_t> m_chrromr; + uint8_t m_spr; + uint8_t m_res320_ram[4]; +}; + +DECLARE_DEVICE_TYPE(SBC_VIDEO, vector_sbc_video_device) + +#endif // MAME_VECTORGRAPHIC_SBCVIDEO_H diff --git a/src/mame/vectorgraphic/vector4.cpp b/src/mame/vectorgraphic/vector4.cpp new file mode 100644 index 00000000000..0abd2d6586e --- /dev/null +++ b/src/mame/vectorgraphic/vector4.cpp @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:Eric Anderson +/*************************************************************************** + +Vector Graphic Vector 4. Vector Graphic, Inc was a Californian company that +made a personal computers before the IBM PC disrupted the industry. The +Vector 4 was an office computer with word processing, spreadsheeting, +database, and eventually networked drives. + +The ROM boots from the second floppy. "Winchester" boots from the hard drive +(currently unsupported), which is the first device when in use. + +On power on the system uses a Z80B, but it also contains an 8088-2 for limited +IBM compatibility. Only one processor is running at a time and reading from a +port can toggle the active processor. They share memory with each other and the +video subsystem. The active processor and the video subsystem alternate access to +the RAM. The BDOS for CP/M makes use of the 8088, so both processors are +necessary for any of the OSes to boot: CP/M, CP/M 86, MS-DOS. + +The system had three S-100 slots, with the floppy controller using one. It was a +modified bus since it provided regulated power. The system had 128K RAM and +could be extended to 256K. The keyboard plugged in to a 6P6C jack. There were +female ports for two DB-25 RS-232, a 36-pin micro ribbon (aka, telco, +centronics) parallel, a 50-pin micro ribbon parallel, and a DE-9 RGBI/CGA +monitor. + +The 7100-0001 User's Manual provides some overview specifications starting on +page 171 (X A-1) including ports and devices. But it provides few details. The +7200-0001 Technical Information provides thorough descriptions and schematics. + +"Executive" is the name of the boot ROM, not to be confused with a model name. +The motherboard is called the Single Board Computer (SBC) and includes all +functionality except for the disk controller. + +https://archive.org/details/7200-0001-vector-4-technical-information-sep-82 +https://www.bitsavers.org/pdf/vectorGraphic/vector_4/7100-0001_Vector_4_Users_Manual_Feb83.pdf + +TODO: +- keyboard mcu +- S-100 interrupts and ready +- parallel port +- WAIT CPU states +- CPM-86 and MS-DOS 2.0 don't boot + +****************************************************************************/ + +#include "emu.h" + +#include "sbcvideo.h" + +#include "bus/rs232/rs232.h" +#include "bus/s100/s100.h" +#include "bus/s100/vectordualmode.h" +#include "cpu/i86/i86.h" +#include "cpu/z80/z80.h" +#include "machine/bankdev.h" +#include "machine/clock.h" +#include "machine/i8251.h" +#include "machine/i8255.h" +#include "machine/ram.h" +#include "machine/pit8253.h" +#include "sound/sn76496.h" + +#include "speaker.h" + +namespace { + +class vector4_state : public driver_device +{ +public: + vector4_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_8088cpu(*this, "8088cpu") + , m_rambanks(*this, "rambank%u", 0U) + , m_256k(false) + , m_ram(*this, RAM_TAG) + , m_romenbl(*this, "romenbl") + , m_sbc_video(*this, "video") + , m_s100(*this, "s100") + { } + + void vector4(machine_config &config); + +private: + void vector4_io(address_map &map); + void vector4_z80mem(address_map &map); + void vector4_8088mem(address_map &map); + void spr_w(uint8_t data); + uint8_t msc_r(); + void msc_w(uint8_t data) { machine_reset(); } + void addrmap_w(offs_t offset, uint8_t data); + uint8_t s100_r(offs_t offset) { return m_s100->sinp_r(offset+0x20); } + void s100_w(offs_t offset, uint8_t data) { m_s100->sout_w(offset+0x20, data); } + void machine_start() override; + void machine_reset() override; + + required_device<cpu_device> m_maincpu; + required_device<cpu_device> m_8088cpu; + required_memory_bank_array<32> m_rambanks; + bool m_256k; + required_device<ram_device> m_ram; + memory_view m_romenbl; + required_device<vector_sbc_video_device> m_sbc_video; + required_device<s100_bus_device> m_s100; +}; + + +void vector4_state::vector4_z80mem(address_map &map) +{ + map.unmap_value_high(); + for (int bank = 0; bank < (1<<5); bank++) + map(bank << 11, ((bank+1) << 11)-1).bankrw(m_rambanks[bank]); + // 7200-0001 page 209 (VI A-6) B6 + // ROM mapping only applies to the z80 and does not use address mapping. + map(0x0000, 0x0fff).view(m_romenbl); + m_romenbl[0](0x0000, 0x0fff).rom().region("maincpu", 0); +} + +void vector4_state::vector4_8088mem(address_map &map) +{ + map.unmap_value_high(); + map.global_mask(0x3ffff); +} + +void vector4_state::vector4_io(address_map &map) +{ + map.unmap_value_high(); + map(0x00, 0x01).mirror(0xff00).rw("uart0", FUNC(i8251_device::read), FUNC(i8251_device::write)); // keyboard + map(0x02, 0x03).mirror(0xff00).w(FUNC(vector4_state::spr_w)); // subsystem port register + map(0x04, 0x05).mirror(0xff00).rw("uart1", FUNC(i8251_device::read), FUNC(i8251_device::write)); // modem + map(0x06, 0x07).mirror(0xff00).rw("uart2", FUNC(i8251_device::read), FUNC(i8251_device::write)); // serial printer + map(0x08, 0x0b).mirror(0xff00).rw("ppi", FUNC(i8255_device::read), FUNC(i8255_device::write)); // parallel printer + map(0x0c, 0x0d).mirror(0xff00).rw(FUNC(vector4_state::msc_r), FUNC(vector4_state::msc_w)); // select Z80/8088-2 + map(0x0e, 0x0e).mirror(0xff00).rw("video:crtc", FUNC(c6545_1_device::status_r), FUNC(c6545_1_device::address_w)); // video controller + map(0x0f, 0x0f).mirror(0xff00).rw("video:crtc", FUNC(c6545_1_device::register_r), FUNC(c6545_1_device::register_w)); + map(0x10, 0x13).mirror(0xff00).rw("pit", FUNC(pit8253_device::read), FUNC(pit8253_device::write)); // baud generator and timer + map(0x16, 0x17).select(0xff00).w(FUNC(vector4_state::addrmap_w)); // RAM address map + map(0x18, 0x19).mirror(0xff00).w("sn", FUNC(sn76489_device::write)); // tone generator + map(0x1c, 0x1f).mirror(0xff00).w(m_sbc_video, FUNC(vector_sbc_video_device::res320_mapping_ram_w)); // resolution 320 mapping RAM + map(0x20, 0xff).mirror(0xff00).rw(FUNC(vector4_state::s100_r), FUNC(vector4_state::s100_w)); +} + +static void vector4_s100_devices(device_slot_interface &device) +{ + device.option_add("dualmodedisk", S100_VECTOR_DUALMODE); +} + +static INPUT_PORTS_START( vector4 ) +INPUT_PORTS_END + +// 7200-0001 page 102 (II 5-11) +DEVICE_INPUT_DEFAULTS_START(keyboard) + DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0x00ff, RS232_BAUD_300) + DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0x00ff, RS232_BAUD_300) + DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0x00ff, RS232_DATABITS_8) + DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0x00ff, RS232_PARITY_NONE) + DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0x00ff, RS232_STOPBITS_2) +DEVICE_INPUT_DEFAULTS_END + +void vector4_state::vector4(machine_config &config) +{ + const XTAL _32m(32'640'000); + const XTAL _2m = _32m/16; + + /* processors */ + // Manual says 5.1 MHz. To do so, schematic shows (A1) it is driven by the + // 32.64 MHz xtal, 1/16 of the cycles are skipped, and it is divided by 6. + Z80(config, m_maincpu, 5'100'000); + m_maincpu->set_addrmap(AS_PROGRAM, &vector4_state::vector4_z80mem); + m_maincpu->set_addrmap(AS_IO, &vector4_state::vector4_io); + + I8088(config, m_8088cpu, 5'100'000); + m_8088cpu->set_addrmap(AS_PROGRAM, &vector4_state::vector4_8088mem); + m_8088cpu->set_addrmap(AS_IO, &vector4_state::vector4_io); + + RAM(config, m_ram).set_default_size("128K").set_extra_options("256K"); + + /* video hardware */ + SBC_VIDEO(config, m_sbc_video, _32m); + m_sbc_video->set_buffer(m_ram); + m_sbc_video->set_chrroml("chargenl"); + m_sbc_video->set_chrromr("chargenr"); + + /* i/o */ + XTAL _2mclk(2'000'000); // 7200-0001 page 210 (VI A-7) D13 + + S100_BUS(config, m_s100, _2mclk); + S100_SLOT(config, "s100:1", vector4_s100_devices, "dualmodedisk"); + S100_SLOT(config, "s100:2", vector4_s100_devices, nullptr); + S100_SLOT(config, "s100:3", vector4_s100_devices, nullptr); + + pit8253_device &pit(PIT8253(config, "pit", 0)); + // 7200-0001 page 210 D7, 208 (VI A-5) A1 + pit.set_clk<0>(_2mclk); + pit.set_clk<1>(_2mclk); + pit.set_clk<2>(_2mclk); + // 7200-0001 page 107 (II 5-16) + pit.out_handler<0>().set_inputline(m_maincpu, INPUT_LINE_IRQ0); + pit.out_handler<0>().append_inputline(m_8088cpu, INPUT_LINE_IRQ0); + + // 7200-0001 page 210 D13, D1 + clock_device &keyboard_clock(CLOCK(config, "keyboard_clock", _2mclk/26/16)); + i8251_device &uart0(I8251(config, "uart0", 0)); + rs232_port_device &rs232keyboard(RS232_PORT(config, "rs232keyboard", default_rs232_devices, "keyboard")); + keyboard_clock.signal_handler().set(uart0, FUNC(i8251_device::write_txc)); + keyboard_clock.signal_handler().append(uart0, FUNC(i8251_device::write_rxc)); + uart0.txd_handler().set(rs232keyboard, FUNC(rs232_port_device::write_txd)); + rs232keyboard.rxd_handler().set(uart0, FUNC(i8251_device::write_rxd)); + rs232keyboard.set_option_device_input_defaults("keyboard", DEVICE_INPUT_DEFAULTS_NAME(keyboard)); + + // D3 + i8251_device &uart1(I8251(config, "uart1", 0)); + rs232_port_device &rs232com(RS232_PORT(config, "rs232com", default_rs232_devices, nullptr)); + pit.out_handler<1>().set(uart1, FUNC(i8251_device::write_txc)); + pit.out_handler<1>().append(uart1, FUNC(i8251_device::write_rxc)); + uart1.txd_handler().set(rs232com, FUNC(rs232_port_device::write_txd)); + uart1.dtr_handler().set(rs232com, FUNC(rs232_port_device::write_dtr)); + uart1.rts_handler().set(rs232com, FUNC(rs232_port_device::write_rts)); + rs232com.rxd_handler().set(uart1, FUNC(i8251_device::write_rxd)); + rs232com.dsr_handler().set(uart1, FUNC(i8251_device::write_dsr)); + rs232com.cts_handler().set(uart1, FUNC(i8251_device::write_cts)); + + // D2 + i8251_device &uart2(I8251(config, "uart2", 0)); + rs232_port_device &rs232prtr(RS232_PORT(config, "rs232prtr", default_rs232_devices, nullptr)); + pit.out_handler<2>().set(uart2, FUNC(i8251_device::write_txc)); + pit.out_handler<2>().append(uart2, FUNC(i8251_device::write_rxc)); + uart2.txd_handler().set(rs232prtr, FUNC(rs232_port_device::write_txd)); + uart2.dtr_handler().set(rs232prtr, FUNC(rs232_port_device::write_dtr)); + uart2.rts_handler().set(rs232prtr, FUNC(rs232_port_device::write_rts)); + rs232prtr.rxd_handler().set(uart2, FUNC(i8251_device::write_rxd)); + rs232prtr.dsr_handler().set(uart2, FUNC(i8251_device::write_dsr)); + rs232prtr.cts_handler().set(uart2, FUNC(i8251_device::write_cts)); + + // 7200-0001 page 110 (II 5-19), 210 D8 + // TODO: Qume (50 pin) and Centronics (36 pin) + I8255A(config, "ppi"); + + SPEAKER(config, "mono").front_center(); + sn76489_device &sn(SN76489(config, "sn", _2m)); + sn.add_route(ALL_OUTPUTS, "mono", 1.0); +} + +void vector4_state::machine_start() +{ + m_256k = (m_ram->size() == 256 * 1024); + m_8088cpu->space(AS_PROGRAM).install_ram(0, m_ram->mask(), m_ram->size() & 0x20000, m_ram->pointer()); + for (int bank = 0; bank < (1<<5); bank++) + m_rambanks[bank]->configure_entries(0, 1<<7, m_ram->pointer(), 1<<11); +} + +void vector4_state::machine_reset() +{ + // 7200-0001 page 39 (II 1-10), page 210 D11 + spr_w(0); + m_8088cpu->suspend(SUSPEND_REASON_HALT, true); + m_maincpu->resume(SUSPEND_REASON_HALT); +} + +/* Subsystem Port Register */ +void vector4_state::spr_w(uint8_t data) +{ + // 7200-0001 page 81 (II 3-18) + if (BIT(data, 0)) + m_romenbl.disable(); + else + m_romenbl.select(0); + m_sbc_video->spr_w(data); +} + +/* Microprocessor Switching Control */ +uint8_t vector4_state::msc_r() +{ + // 7200-0001 page 40 (II 1-11), 208 A3 + if (m_maincpu->suspended(SUSPEND_REASON_HALT)) { + m_8088cpu->suspend(SUSPEND_REASON_HALT, false); + m_maincpu->resume(SUSPEND_REASON_HALT); + } else { + m_maincpu->suspend(SUSPEND_REASON_HALT, false); + m_8088cpu->resume(SUSPEND_REASON_HALT); + } + return 0xff; +} + +/* Address mapping RAM Subsystem */ +void vector4_state::addrmap_w(offs_t offset, uint8_t data) +{ + // 7200-0001 page 50 (II 2-7), page 208 B1 + // m_256k is for jumper area B. 7200-0001 page 170 (IV 2-1), page 209 coord A8 + m_rambanks[BIT(offset, 11, 5)]->set_entry(data & (m_256k ? 0x7f : 0x3f)); +} + +/* ROM definition */ +ROM_START( vector4 ) + ROM_REGION( 0x1000, "maincpu", ROMREGION_ERASEFF ) + ROM_SYSTEM_BIOS( 0, "v11", "SBC ver 1.1" ) // VECTOR 4 SBC EXECUTIVE 1.1 + ROMX_LOAD( "sbcv11.bin", 0x0000, 0x1000, CRC(56c80656) SHA1(a381bdbb6cdee0ac1dc8b1c1359361a19ba6fe46), ROM_BIOS(0)) + ROM_SYSTEM_BIOS( 1, "v111", "SBC ver 1.11" ) // VECTOR 4 SBC EXECUTIVE 1.11 + ROMX_LOAD( "u35_sbc_v111_4f11.bin", 0x0000, 0x1000, CRC(fcfd42c6) SHA1(11cd5cf0c3f2d2a30864b8a4b4be51ade03d02ea), ROM_BIOS(1)) + ROM_SYSTEM_BIOS( 2, "v200", "SBC ver 2.00" ) // VECTOR GRAPHIC V4/40 [F] SBC EXECUTIVE - REVISION 2.00 (AA) + ROMX_LOAD( "sbcexecf.bin", 0x0000, 0x1000, CRC(738e10b5) SHA1(abce22abe9bac6241b1996d078647fe36b638769), ROM_BIOS(2)) + + ROM_REGION( 0x1000, "chargenl", ROMREGION_ERASEFF ) + ROM_LOAD( "cgst60l.bin", 0x0000, 0x1000, CRC(e55a404c) SHA1(4dafd6f588c42081212928d3c4448f10dd461a7a)) + ROM_REGION( 0x1000, "chargenr", ROMREGION_ERASEFF ) + ROM_LOAD( "cgst60r.bin", 0x0000, 0x1000, CRC(201d783c) SHA1(7c2b8988c27b5fa435d31c9b7d4d9ed176c9b8a3)) +ROM_END + +} // anonymous namespace + +/* Driver */ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1982, vector4, 0, 0, vector4, vector4, vector4_state, empty_init, "Vector Graphic", "Vector 4", MACHINE_NODEVICE_PRINTER | MACHINE_IMPERFECT_TIMING | MACHINE_SUPPORTS_SAVE ) |