ti99: Added Myarc DDCC-1 disk controller card.

This commit is contained in:
Michael Zapf 2020-03-15 11:46:00 +01:00
parent b1ed8cddbe
commit 5fda8f6406
4 changed files with 622 additions and 0 deletions

View File

@ -3144,6 +3144,8 @@ if (BUSES["TI99"]~=null) then
MAME_DIR .. "src/devices/bus/ti99/peb/bwg.h",
MAME_DIR .. "src/devices/bus/ti99/peb/cc_fdc.cpp",
MAME_DIR .. "src/devices/bus/ti99/peb/cc_fdc.h",
MAME_DIR .. "src/devices/bus/ti99/peb/myarcfdc.cpp",
MAME_DIR .. "src/devices/bus/ti99/peb/myarcfdc.h",
MAME_DIR .. "src/devices/bus/ti99/peb/evpc.cpp",
MAME_DIR .. "src/devices/bus/ti99/peb/evpc.h",
MAME_DIR .. "src/devices/bus/ti99/peb/hfdc.cpp",

View File

@ -0,0 +1,484 @@
// license:LGPL-2.1+
// copyright-holders:Michael Zapf
/*******************************************************************************
Myarc Floppy Disk Controller (DDCC-1)
Double Density, Double-sided
May be used with a 1770 or 1772 controller
EPROM 2764A (8Kx8) in two banks (2x 4000-4fff)
SRAM HM6116 (2Kx8) (5000-57ff)
DIP switches (SW1) set the head step rate. For the 1770 controller, closed
switches mean 20ms, open switches mean 6ms. For the 1772 controller, closed
means 2ms, open means 6 ms. There is an alternative ROM for the 1772 which
allows for slower step rates (6ms-12ms).
Another switch is included (SW2) labeled "Turbo" on schematics, but which
is not present on all boards. It may require a different ROM.
Known issue: On error, the drive may continue spinning.
Michael Zapf
March 2020
*******************************************************************************/
#include "emu.h"
#include "myarcfdc.h"
#include "formats/ti99_dsk.h"
// ----------------------------------
// Flags for debugging
#define LOG_WARN (1U<<1) // Warnings
#define LOG_CONFIG (1U<<2) // Configuration
#define LOG_EPROM (1U<<3) // Access to EPROM
#define LOG_CONTR (1U<<4) // Access to controller
#define LOG_RAM (1U<<5) // Access to SRAM
#define LOG_IRQ (1U<<7) // IRQ line
#define LOG_DRQ (1U<<8) // DRQ line
#define LOG_DRIVE (1U<<9) // Drive operations
#define LOG_CRU (1U<<10) // CRU operations
#define VERBOSE ( LOG_GENERAL | LOG_WARN | LOG_CONFIG )
#include "logmacro.h"
#define BUFFER_TAG "ram"
#define LATCH_TAG "ls259"
#define WD1770_TAG "wd1770"
#define WD1772_TAG "wd1772"
#define PAL_TAG "pal"
DEFINE_DEVICE_TYPE_NS(TI99_DDCC1, bus::ti99::peb, myarc_fdc_device, "ti99_ddcc1", "Myarc Disk Controller Card")
DEFINE_DEVICE_TYPE_NS(DDCC1_PAL, bus::ti99::peb, ddcc1_pal_device, PAL_TAG, "Myarc DDCC-1 PAL u1")
namespace bus { namespace ti99 { namespace peb {
// ----------------------------------
myarc_fdc_device::myarc_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock):
device_t(mconfig, TI99_DDCC1, tag, owner, clock),
device_ti99_peribox_card_interface(mconfig, *this),
m_wdc(nullptr),
m_wd1770(*this, WD1770_TAG),
m_wd1772(*this, WD1772_TAG),
m_drivelatch(*this, LATCH_TAG),
m_buffer_ram(*this, BUFFER_TAG),
m_pal(*this, PAL_TAG),
m_dsrrom(nullptr),
m_banksel(false),
m_cardsel(false),
m_selected_drive(0),
m_address(0)
{ }
SETADDRESS_DBIN_MEMBER( myarc_fdc_device::setaddress_dbin )
{
// Do not allow setaddress for debugger
if (machine().side_effects_disabled()) return;
m_address = offset;
}
bool myarc_fdc_device::card_selected()
{
return m_cardsel;
}
/*
Provides the current address to the PAL.
*/
uint16_t myarc_fdc_device::get_address()
{
return m_address;
}
/*
Debugger access.
*/
void myarc_fdc_device::debug_read(offs_t offset, uint8_t* value)
{
uint16_t addrcopy = m_address;
m_address = offset;
if (m_pal->ramsel())
{
*value = m_buffer_ram->pointer()[m_address & 0x07ff];
}
if (m_pal->romen())
{
// EPROM selected
uint16_t base = m_banksel? 0x1000 : 0;
*value = m_dsrrom[base | (m_address & 0x0fff)];
}
m_address = addrcopy;
}
/*
Debugger access.
*/
void myarc_fdc_device::debug_write(offs_t offset, uint8_t data)
{
uint16_t addrcopy = m_address;
m_address = offset;
if (m_pal->ramsel())
{
m_buffer_ram->pointer()[m_address & 0x07ff] = data;
}
m_address = addrcopy;
}
/*
Read access to the RAM, EPROM, and controller chip.
*/
READ8Z_MEMBER(myarc_fdc_device::readz)
{
if (machine().side_effects_disabled())
{
debug_read(offset, value);
return;
}
if (m_pal->ramsel())
{
// SRAM selected
*value = m_buffer_ram->pointer()[m_address & 0x07ff];
LOGMASKED(LOG_RAM, "Read RAM: %04x -> %02x\n", m_address & 0xffff, *value);
}
if (m_pal->romen())
{
// EPROM selected
uint16_t base = m_banksel? 0x1000 : 0;
uint8_t* rom = &m_dsrrom[base | (m_address & 0x0fff)];
*value = *rom;
if (WORD_ALIGNED(m_address))
{
uint16_t val = (*rom << 8) | (*(rom+1));
LOGMASKED(LOG_EPROM, "Read DSR: %04x (page %d)-> %04x\n", m_address & 0xffff, base>>12, val);
}
}
if (m_pal->fdcsel())
{
// WDC selected
*value = m_wdc->read((m_address >> 1)&0x03);
LOGMASKED(LOG_CONTR, "Read FDC: %04x -> %02x\n", m_address & 0xffff, *value);
}
}
/*
Write access to RAM and the controller chip.
*/
void myarc_fdc_device::write(offs_t offset, uint8_t data)
{
if (machine().side_effects_disabled())
{
debug_write(offset, data);
return;
}
if (m_pal->ramsel())
{
// SRAM selected
LOGMASKED(LOG_RAM, "Write RAM: %04x <- %02x\n", m_address & 0xffff, data);
m_buffer_ram->pointer()[m_address & 0x07ff] = data;
}
if (m_pal->fdcsel())
{
// WDC selected
LOGMASKED(LOG_CONTR, "Write FDC: %04x <- %02x\n", m_address & 0xffff, data);
m_wdc->write((m_address >> 1)&0x03, data);
}
}
/*
CRU read access to the LS251 multiplexer.
*/
READ8Z_MEMBER( myarc_fdc_device::crureadz )
{
const uint8_t dipswitch[] = { 0x00, 0x01, 0x02, 0x04, 0x08 };
uint16_t addrcopy = m_address;
m_address = offset; // Copy the CRU address on the address variable
if (m_pal->cs251())
{
int bitno = ((offset & 0x0e)>>1);
switch (bitno)
{
case 0: // INTRQ
*value = (m_wdc->intrq_r()==ASSERT_LINE)? 1:0;
break;
case 1: // DRQ
*value = (m_wdc->drq_r()==ASSERT_LINE)? 1:0;
break;
case 2: // Turbo (not on every card)
*value = ioport("SW2")->read();
break;
case 3: // NC
break;
default:
// Open = 6ms, close = 20ms (2ms)
*value = ((ioport("SW1")->read() & dipswitch[8-bitno])!=0)? 0:1;
break;
}
LOGMASKED(LOG_CRU, "cru %04x (bit %d) -> %d\n", offset, bitno, *value);
}
m_address = addrcopy;
}
/*
CRU write access to the LS259 latch.
*/
void myarc_fdc_device::cruwrite(offs_t offset, uint8_t data)
{
uint16_t addrcopy = m_address;
m_address = offset; // Copy the CRU address on the address variable
if (m_pal->cs259())
{
int bitno = ((offset & 0x0e)>>1);
LOGMASKED(LOG_CRU, "cru %04x (bit %d) <- %d\n", offset, bitno, data);
m_drivelatch->write_bit(bitno, BIT(data, 0));
}
m_address = addrcopy;
}
/*
Callbacks from the WDC chip
*/
WRITE_LINE_MEMBER( myarc_fdc_device::fdc_irq_w )
{
LOGMASKED(LOG_IRQ, "INTRQ callback = %d\n", state);
}
WRITE_LINE_MEMBER( myarc_fdc_device::fdc_drq_w )
{
LOGMASKED(LOG_DRQ, "DRQ callback = %d\n", state);
}
/*
Callbacks from the 74LS259 latch
*/
WRITE_LINE_MEMBER( myarc_fdc_device::den_w )
{
LOGMASKED(LOG_CRU, "Card enable = %d\n", state);
m_cardsel = (state==1);
}
WRITE_LINE_MEMBER( myarc_fdc_device::wdreset_w )
{
LOGMASKED(LOG_CRU, "Controller reset = %d\n", state);
m_wdc->mr_w(state);
}
WRITE_LINE_MEMBER( myarc_fdc_device::sidsel_w )
{
LOGMASKED(LOG_CRU, "Side select = %d\n", state);
if (m_selected_drive != 0)
{
LOGMASKED(LOG_DRIVE, "Set side = %d on DSK%d\n", state, m_selected_drive);
m_floppy[m_selected_drive-1]->ss_w(state);
}
}
// Selects the EPROM bank, and also controls the DDEN line
WRITE_LINE_MEMBER( myarc_fdc_device::bankdden_w )
{
LOGMASKED(LOG_CRU, "EPROM bank select = %d\n", state);
m_banksel = (state==ASSERT_LINE);
m_wdc->dden_w(state==1);
}
WRITE_LINE_MEMBER( myarc_fdc_device::drivesel_w )
{
int driveno = 0;
// We do not know what happens when two drives are selected
if (m_drivelatch->q7_r() != 0) driveno = 4;
if (m_drivelatch->q6_r() != 0) driveno = 3;
if (m_drivelatch->q5_r() != 0) driveno = 2;
if (m_drivelatch->q4_r() != 0) driveno = 1;
if (state == CLEAR_LINE)
{
// Only when no bit is set, unselect all drives.
// The DSR actually selects the new drive first, then unselects
// the old drive.
if (driveno==0)
{
LOGMASKED(LOG_DRIVE, "Unselect all drives\n");
m_wdc->set_floppy(nullptr);
m_selected_drive = 0;
}
}
else
{
if (m_floppy[driveno-1] != nullptr)
{
m_selected_drive = driveno;
LOGMASKED(LOG_DRIVE, "Select drive DSK%d\n", driveno);
m_wdc->set_floppy(m_floppy[driveno-1]);
m_floppy[driveno-1]->ss_w(m_drivelatch->q2_r());
}
}
}
void myarc_fdc_device::device_start()
{
m_dsrrom = memregion(TI99_DSRROM)->base();
save_item(NAME(m_banksel));
save_item(NAME(m_cardsel));
save_item(NAME(m_selected_drive));
save_item(NAME(m_address));
}
void myarc_fdc_device::device_reset()
{
if (ioport("CONTROLLER")->read()==0)
m_wdc = m_wd1770;
else
m_wdc = m_wd1772;
}
void myarc_fdc_device::device_config_complete()
{
for (auto & elem : m_floppy)
elem = nullptr;
if (subdevice("0")!=nullptr) m_floppy[0] = static_cast<floppy_image_device*>(subdevice("0")->subdevices().first());
if (subdevice("1")!=nullptr) m_floppy[1] = static_cast<floppy_image_device*>(subdevice("1")->subdevices().first());
if (subdevice("2")!=nullptr) m_floppy[2] = static_cast<floppy_image_device*>(subdevice("2")->subdevices().first());
if (subdevice("3")!=nullptr) m_floppy[3] = static_cast<floppy_image_device*>(subdevice("3")->subdevices().first());
}
FLOPPY_FORMATS_MEMBER(myarc_fdc_device::floppy_formats)
FLOPPY_TI99_SDF_FORMAT,
FLOPPY_TI99_TDF_FORMAT
FLOPPY_FORMATS_END
static void ccfdc_floppies(device_slot_interface &device)
{
device.option_add("525dd", FLOPPY_525_DD); // 40 tracks
device.option_add("525qd", FLOPPY_525_QD); // 80 tracks
device.option_add("35dd", FLOPPY_35_DD); // 80 tracks
}
INPUT_PORTS_START(myarc_ddcc )
PORT_START( "CONTROLLER" )
PORT_CONFNAME( 0x01, 0x00, "Controller chip")
PORT_CONFSETTING(0x00, "WD1770")
PORT_CONFSETTING(0x01, "WD1772")
PORT_START( "SW2" )
PORT_DIPNAME( 0x01, 0x00, "Turbo switch" )
PORT_DIPSETTING(0x00, DEF_STR( Off ))
PORT_DIPSETTING(0x01, DEF_STR( On ))
PORT_START( "SW1" )
PORT_DIPNAME( 0x01, 0x01, "DSK1 head step time" )
PORT_DIPSETTING( 0x00, "6ms") // 6 ms for 1770
PORT_DIPSETTING( 0x01, "20ms/2ms") // 20 ms for 1770 and 2ms for 1772
PORT_DIPNAME( 0x02, 0x02, "DSK2 head step time" )
PORT_DIPSETTING( 0x00, "6ms")
PORT_DIPSETTING( 0x02, "20ms/2ms")
PORT_DIPNAME( 0x04, 0x04, "DSK3 head step time" )
PORT_DIPSETTING( 0x00, "6ms")
PORT_DIPSETTING( 0x04, "20ms/2ms")
PORT_DIPNAME( 0x08, 0x08, "DSK4 head step time" )
PORT_DIPSETTING( 0x00, "6ms")
PORT_DIPSETTING( 0x08, "20ms/2ms")
INPUT_PORTS_END
ROM_START( myarc_ddcc )
ROM_REGION(0x2000, TI99_DSRROM, 0)
ROM_LOAD("ddcc1.u3", 0x0000, 0x2000, CRC(042968a9) SHA1(17af3130d3631b1bc1aa4d7e32a1b1feb66bbfb6))
ROM_END
void myarc_fdc_device::device_add_mconfig(machine_config& config)
{
// Cards appeared with one of those controllers
WD1770(config, m_wd1770, 8_MHz_XTAL);
WD1772(config, m_wd1772, 8_MHz_XTAL);
m_wd1770->intrq_wr_callback().set(FUNC(myarc_fdc_device::fdc_irq_w));
m_wd1770->drq_wr_callback().set(FUNC(myarc_fdc_device::fdc_drq_w));
m_wd1772->intrq_wr_callback().set(FUNC(myarc_fdc_device::fdc_irq_w));
m_wd1772->drq_wr_callback().set(FUNC(myarc_fdc_device::fdc_drq_w));
LS259(config, m_drivelatch); // U10
m_drivelatch->q_out_cb<0>().set(FUNC(myarc_fdc_device::den_w));
m_drivelatch->q_out_cb<1>().set(FUNC(myarc_fdc_device::wdreset_w));
m_drivelatch->q_out_cb<2>().set(FUNC(myarc_fdc_device::sidsel_w));
m_drivelatch->q_out_cb<3>().set(FUNC(myarc_fdc_device::bankdden_w));
m_drivelatch->q_out_cb<4>().set(FUNC(myarc_fdc_device::drivesel_w));
m_drivelatch->q_out_cb<5>().set(FUNC(myarc_fdc_device::drivesel_w));
m_drivelatch->q_out_cb<6>().set(FUNC(myarc_fdc_device::drivesel_w));
m_drivelatch->q_out_cb<7>().set(FUNC(myarc_fdc_device::drivesel_w));
// SRAM 6114 2Kx8
RAM(config, BUFFER_TAG).set_default_size("2k").set_default_value(0);
// PAL circuit
DDCC1_PAL(config, PAL_TAG, 0);
// Floppy drives
FLOPPY_CONNECTOR(config, "0", ccfdc_floppies, "525dd", myarc_fdc_device::floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "1", ccfdc_floppies, "525dd", myarc_fdc_device::floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "2", ccfdc_floppies, nullptr, myarc_fdc_device::floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "3", ccfdc_floppies, nullptr, myarc_fdc_device::floppy_formats).enable_sound(true);
}
ioport_constructor myarc_fdc_device::device_input_ports() const
{
return INPUT_PORTS_NAME( myarc_ddcc );
}
const tiny_rom_entry *myarc_fdc_device::device_rom_region() const
{
return ROM_NAME( myarc_ddcc );
}
// ========================================================================
// PAL circuit on the DDCC-1 board
// ========================================================================
ddcc1_pal_device::ddcc1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, DDCC1_PAL, tag, owner, clock),
m_board(nullptr)
{
}
bool ddcc1_pal_device::ramsel()
{
return (((m_board->get_address() & 0xf800)==0x5000) && (m_board->card_selected()));
}
bool ddcc1_pal_device::romen()
{
return (((m_board->get_address() & 0xf000)==0x4000) && (m_board->card_selected()));
}
bool ddcc1_pal_device::fdcsel()
{
// The memory mapping of the DDCC-1 differs from the usual scheme, using
// addresses 5F01, 5F03, 5F05, 5F07
return (((m_board->get_address() & 0xff01)==0x5f01) && (m_board->card_selected()));
}
bool ddcc1_pal_device::cs251()
{
return ((m_board->get_address() & 0xff00)==0x1100);
}
bool ddcc1_pal_device::cs259()
{
return ((m_board->get_address() & 0xff00)==0x1100);
}
void ddcc1_pal_device::device_config_complete()
{
m_board = static_cast<myarc_fdc_device*>(owner());
}
} } } // end namespace bus::ti99::peb

View File

@ -0,0 +1,131 @@
// license:LGPL-2.1+
// copyright-holders:Michael Zapf
/****************************************************************************
Myarc Disk Controller
Double Density, Double-sided
Michael Zapf, March 2020
*****************************************************************************/
#ifndef MAME_BUS_TI99_PEB_DDCC_H
#define MAME_BUS_TI99_PEB_DDCC_H
#pragma once
#include "peribox.h"
#include "imagedev/floppy.h"
#include "machine/wd_fdc.h"
#include "machine/74259.h"
#include "machine/ram.h"
namespace bus { namespace ti99 { namespace peb {
class ddcc1_pal_device;
class myarc_fdc_device : public device_t, public device_ti99_peribox_card_interface
{
friend class ddcc1_pal_device;
public:
myarc_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_READ8Z_MEMBER(readz) override;
void write(offs_t offset, uint8_t data) override;
DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin) override;
DECLARE_READ8Z_MEMBER(crureadz) override;
void cruwrite(offs_t offset, uint8_t data) override;
private:
void device_start() override;
void device_reset() override;
void device_config_complete() override;
const tiny_rom_entry *device_rom_region() const override;
void device_add_mconfig(machine_config &config) override;
ioport_constructor device_input_ports() const override;
DECLARE_FLOPPY_FORMATS( floppy_formats );
// Callback methods
DECLARE_WRITE_LINE_MEMBER( fdc_irq_w );
DECLARE_WRITE_LINE_MEMBER( fdc_drq_w );
DECLARE_WRITE_LINE_MEMBER( den_w );
DECLARE_WRITE_LINE_MEMBER( wdreset_w );
DECLARE_WRITE_LINE_MEMBER( sidsel_w );
DECLARE_WRITE_LINE_MEMBER( bankdden_w );
DECLARE_WRITE_LINE_MEMBER( drivesel_w );
// Deliver the current state of the address bus
uint16_t get_address();
// Polled from the PAL
bool card_selected();
// Link to the WD controller on the board.
wd_fdc_digital_device_base* m_wdc;
// Two options for the controller chip. Can be selected by the configuration switch.
required_device<wd1770_device> m_wd1770;
required_device<wd1772_device> m_wd1772;
// Latch
required_device<ls259_device> m_drivelatch;
// Buffer RAM
required_device<ram_device> m_buffer_ram;
// Decoder PAL
required_device<ddcc1_pal_device> m_pal;
// DSR ROM
uint8_t* m_dsrrom;
// Link to the attached floppy drives
floppy_image_device* m_floppy[4];
// Debugger accessors
void debug_read(offs_t offset, uint8_t* value);
void debug_write(offs_t offset, uint8_t data);
// Upper bank selected
bool m_banksel;
// Card enabled
bool m_cardsel;
// Selected drive
int m_selected_drive;
// Recent address
int m_address;
};
// =========== Decoder PAL circuit ================
class ddcc1_pal_device : public device_t
{
public:
ddcc1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// Selector output lines of the PAL
bool ramsel();
bool romen();
bool fdcsel();
bool cs251();
bool cs259();
private:
void device_start() override { };
void device_config_complete() override;
myarc_fdc_device* m_board;
};
} } } // end namespace bus::ti99::peb
DECLARE_DEVICE_TYPE_NS(TI99_DDCC1, bus::ti99::peb, myarc_fdc_device)
DECLARE_DEVICE_TYPE_NS(DDCC1_PAL, bus::ti99::peb, ddcc1_pal_device)
#endif // MAME_BUS_TI99_PEB_DDCC_H

View File

@ -183,6 +183,7 @@ CRUCLK* 51||52 DBIN
#include "bwg.h"
#include "hfdc.h"
#include "cc_fdc.h"
#include "myarcfdc.h"
#include "pcode.h"
#include "myarcmem.h"
#include "samsmem.h"
@ -493,6 +494,7 @@ void ti99_peribox_slot_standard(device_slot_interface &device)
device.option_add("tifdc", TI99_FDC);
device.option_add("ccdcc", TI99_CCDCC);
device.option_add("ccfdc", TI99_CCFDC);
device.option_add("ddcc1", TI99_DDCC1);
}
void peribox_device::device_add_mconfig(machine_config &config)
@ -534,6 +536,7 @@ void ti99_peribox_slot_evpc(device_slot_interface &device)
device.option_add("tifdc", TI99_FDC);
device.option_add("ccdcc", TI99_CCDCC);
device.option_add("ccfdc", TI99_CCFDC);
device.option_add("ddcc1", TI99_DDCC1);
}
void peribox_ev_device::device_add_mconfig(machine_config &config)
@ -585,6 +588,7 @@ void ti99_peribox_slot_geneve(device_slot_interface &device)
device.option_add("tifdc", TI99_FDC);
device.option_add("ccdcc", TI99_CCDCC);
device.option_add("ccfdc", TI99_CCFDC);
device.option_add("ddcc1", TI99_DDCC1);
}
void peribox_gen_device::device_add_mconfig(machine_config &config)
@ -638,6 +642,7 @@ void ti99_peribox_slot_sgcpu(device_slot_interface &device)
device.option_add("tifdc", TI99_FDC);
device.option_add("ccdcc", TI99_CCDCC);
device.option_add("ccfdc", TI99_CCFDC);
device.option_add("ddcc1", TI99_DDCC1);
}
void peribox_sg_device::device_add_mconfig(machine_config &config)