vectorgraphic/vector4.cpp: Added Vector 4 driver. (#10710)
* bus/s100: Added Vector Dual-Mode Disk Controller (only floppy supported for now). * formats/vgi_dsk.cpp: Addec Micropolis VGI floppy disk image format.
This commit is contained in:
parent
daaf8645e0
commit
369ecb2f77
@ -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",
|
||||
}
|
||||
|
@ -2052,6 +2052,18 @@ if opt_tool(FORMATS, "VG5K_CAS") then
|
||||
}
|
||||
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
|
||||
|
327
src/devices/bus/s100/vectordualmode.cpp
Normal file
327
src/devices/bus/s100/vectordualmode.cpp
Normal file
@ -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")
|
55
src/devices/bus/s100/vectordualmode.h
Normal file
55
src/devices/bus/s100/vectordualmode.h
Normal file
@ -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
|
@ -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 */
|
||||
|
@ -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
|
||||
|
146
src/lib/formats/vgi_dsk.cpp
Normal file
146
src/lib/formats/vgi_dsk.cpp
Normal file
@ -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;
|
34
src/lib/formats/vgi_dsk.h
Normal file
34
src/lib/formats/vgi_dsk.h
Normal file
@ -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
|
@ -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)
|
||||
|
@ -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
|
||||
|
183
src/mame/vectorgraphic/sbcvideo.cpp
Normal file
183
src/mame/vectorgraphic/sbcvideo.cpp
Normal file
@ -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")
|
43
src/mame/vectorgraphic/sbcvideo.h
Normal file
43
src/mame/vectorgraphic/sbcvideo.h
Normal file
@ -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
|
315
src/mame/vectorgraphic/vector4.cpp
Normal file
315
src/mame/vectorgraphic/vector4.cpp
Normal file
@ -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 )
|
Loading…
Reference in New Issue
Block a user