mirror of
https://github.com/holub/mame
synced 2025-04-22 08:22:15 +03:00
[MESS] DEC Rainbow updates: [Karl-Ludwig Deisenhofer]
- Hard disk R/W support and real-time clock support emulating ClikClok card. -wd2010: provides IRQ / (B)DRQ signals. Honors DRIVE_READY and WRITE FAULT (DRDY / WF) now. Set WF to GND and DRDY to VCC in your driver if signals are not serviced. -ds1315 : Handle chip enable / chip reset / phantom writes to RTC.
This commit is contained in:
parent
b702e6bd3e
commit
0026618a68
@ -1,12 +1,23 @@
|
||||
/*********************************************************************
|
||||
/*****************************************************************************************
|
||||
|
||||
ds1315.c
|
||||
|
||||
Dallas Semiconductor's Phantom Time Chip DS1315.
|
||||
NOTE: writes are decoded, but the host's time will always be returned when asked.
|
||||
|
||||
by tim lindner, November 2001.
|
||||
April 2015: chip enable / chip reset / phantom writes by Karl-Ludwig Deisenhofer
|
||||
|
||||
*********************************************************************/
|
||||
November 2001: implementation by Tim Lindner
|
||||
|
||||
HOW DOES IT WORK?
|
||||
|
||||
READS: pattern recognition (64 bits in correct order). When RTC finally enables
|
||||
64 bits of data can be read. Chance of accidential pattern recognition is minimal.
|
||||
|
||||
WRITES: two different locations (bits 0 and 1) are used to transfer data to the
|
||||
DS1315. 64 bit with time/date info are transmitted directly after recognition
|
||||
of the magic 64 bit pattern (see read above).
|
||||
**************************************************************************************/
|
||||
|
||||
#include "ds1315.h"
|
||||
#include "coreutil.h"
|
||||
@ -47,12 +58,11 @@ void ds1315_device::device_start()
|
||||
|
||||
void ds1315_device::device_reset()
|
||||
{
|
||||
memset(m_raw_data, 0, sizeof(m_raw_data));
|
||||
m_count = 0;
|
||||
m_mode = DS_SEEK_MATCHING;
|
||||
chip_reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
LOCAL VARIABLES
|
||||
***************************************************************************/
|
||||
@ -75,7 +85,7 @@ static const UINT8 ds1315_pattern[] =
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
read_0
|
||||
read_0 (actual data)
|
||||
-------------------------------------------------*/
|
||||
|
||||
READ8_MEMBER( ds1315_device::read_0 )
|
||||
@ -100,7 +110,7 @@ READ8_MEMBER( ds1315_device::read_0 )
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
read_1
|
||||
read_1 (actual data)
|
||||
-------------------------------------------------*/
|
||||
|
||||
READ8_MEMBER( ds1315_device::read_1 )
|
||||
@ -143,36 +153,13 @@ READ8_MEMBER( ds1315_device::read_data )
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
write_data
|
||||
-------------------------------------------------*/
|
||||
|
||||
WRITE8_MEMBER( ds1315_device::write_data )
|
||||
{
|
||||
if (m_mode == DS_CALENDAR_IO)
|
||||
{
|
||||
m_raw_data[m_count++] = data & 0x01;
|
||||
|
||||
if (m_count == 64)
|
||||
{
|
||||
m_mode = DS_SEEK_MATCHING;
|
||||
m_count = 0;
|
||||
input_raw_data();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
fill_raw_data
|
||||
-------------------------------------------------*/
|
||||
|
||||
void ds1315_device::fill_raw_data()
|
||||
{
|
||||
/* This routine will (hopefully) call a standard 'C' library routine to get the current
|
||||
/* This routine calls a standard 'C' library routine to get the current
|
||||
date and time and then fill in the raw data struct.
|
||||
*/
|
||||
|
||||
@ -181,7 +168,7 @@ void ds1315_device::fill_raw_data()
|
||||
|
||||
/* get the current date/time from the core */
|
||||
machine().current_datetime(systime);
|
||||
|
||||
|
||||
raw[0] = 0; /* tenths and hundreths of seconds are always zero */
|
||||
raw[1] = dec_2_bcd(systime.local_time.second);
|
||||
raw[2] = dec_2_bcd(systime.local_time.minute);
|
||||
@ -203,16 +190,86 @@ void ds1315_device::fill_raw_data()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
ds1315_input_raw_data
|
||||
write_data
|
||||
-------------------------------------------------*/
|
||||
|
||||
READ8_MEMBER(ds1315_device::write_data)
|
||||
{
|
||||
static int write_count;
|
||||
if (write_count >= 64)
|
||||
write_count = 0;
|
||||
|
||||
if (m_mode == DS_CALENDAR_IO)
|
||||
{
|
||||
m_raw_data[write_count++] = offset & 0x01;
|
||||
|
||||
if (write_count == 64)
|
||||
{
|
||||
write_count = 0;
|
||||
|
||||
m_mode = DS_SEEK_MATCHING;
|
||||
m_count = 0;
|
||||
input_raw_data();
|
||||
}
|
||||
}
|
||||
return 0; // ignore
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
ds1315_input_raw_data
|
||||
|
||||
Routine is called when new date and time has
|
||||
been written to the clock chip. Currently we
|
||||
ignore setting the date and time in the clock
|
||||
chip.
|
||||
-------------------------------------------------*/
|
||||
|
||||
void ds1315_device::input_raw_data()
|
||||
{
|
||||
/* This routine is called when new date and time has been written to the
|
||||
clock chip. Currently we ignore setting the date and time in the clock
|
||||
chip.
|
||||
int raw[8], i, j=0;
|
||||
raw[0] = raw[1] = raw[2] = raw[3] = raw[4] = raw[5] = raw[6] = raw[7] = 0;
|
||||
UINT8 flag = 1;
|
||||
|
||||
We always return the host's time when asked.
|
||||
*/
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
j = i / 8;
|
||||
if ((i % 8) == 0)
|
||||
flag = 1;
|
||||
|
||||
if (m_raw_data[i] & 1)
|
||||
raw[j] |= flag;
|
||||
flag <<= 1;
|
||||
}
|
||||
raw[0] = bcd_2_dec(raw[0]); // hundreds of seconds
|
||||
raw[1] = bcd_2_dec(raw[1]); // seconds (often set to zero)
|
||||
raw[2] = bcd_2_dec(raw[2]); // minute
|
||||
raw[3] = bcd_2_dec(raw[3]); // hour
|
||||
|
||||
raw[4] = bcd_2_dec(raw[4]); // weekday (10 for Friday ?!)
|
||||
raw[5] = bcd_2_dec(raw[5]); // mday
|
||||
raw[6] = bcd_2_dec(raw[6]); // month
|
||||
raw[7] = bcd_2_dec(raw[7]); // year (two digits)
|
||||
|
||||
printf("\nDS1315 RTC INPUT (WILL BE IGNORED) mm/dd/yy hh:mm:ss - %02d/%02d/%02d %02d/%02d/%02d",
|
||||
raw[6], raw[5], raw[7], raw[3], raw[2], raw[1]
|
||||
);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
query and reset chip status
|
||||
-------------------------------------------------*/
|
||||
bool ds1315_device::chip_enable()
|
||||
{
|
||||
return (m_mode == DS_CALENDAR_IO);
|
||||
}
|
||||
|
||||
// Set a defined state (important for pattern detection)
|
||||
void ds1315_device::chip_reset()
|
||||
{
|
||||
memset(m_raw_data, 0, sizeof(m_raw_data));
|
||||
m_count = 0;
|
||||
m_mode = DS_SEEK_MATCHING;
|
||||
}
|
||||
|
@ -35,7 +35,10 @@ public:
|
||||
DECLARE_READ8_MEMBER(read_0);
|
||||
DECLARE_READ8_MEMBER(read_1);
|
||||
DECLARE_READ8_MEMBER(read_data);
|
||||
DECLARE_WRITE8_MEMBER(write_data);
|
||||
DECLARE_READ8_MEMBER(write_data);
|
||||
|
||||
bool chip_enable();
|
||||
void chip_reset();
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
@ -45,12 +48,12 @@ protected:
|
||||
|
||||
private:
|
||||
// internal state
|
||||
ds1315_mode_t m_mode;
|
||||
|
||||
void fill_raw_data();
|
||||
void input_raw_data();
|
||||
|
||||
int m_count;
|
||||
ds1315_mode_t m_mode;
|
||||
UINT8 m_raw_data[8*8];
|
||||
};
|
||||
|
||||
|
@ -2,24 +2,63 @@
|
||||
// copyright-holders:Curt Coder
|
||||
/**********************************************************************
|
||||
|
||||
Western Digital WD2010 Winchester Disk Controller
|
||||
Western Digital WD2010 Winchester Disk Controller
|
||||
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
Portions (2015) : Karl-Ludwig Deisenhofer
|
||||
**********************************************************************
|
||||
|
||||
Implements WD2010 / WD1010 controller basics.
|
||||
|
||||
Provides IRQ / (B)DRQ signals needed for early MFM cards.
|
||||
Honors DRIVE_READY and WRITE FAULT (DRDY / WF).
|
||||
|
||||
Single sector read / write (format) confirmed to work with
|
||||
Rainbow-100 controller (WD1010, largely compatible to WD2010, see **)
|
||||
|
||||
LIST OF UNIMPLEMENTED FEATURES :
|
||||
- MULTI SECTOR TRANSFERS (M = 1); MULTIPLE DRIVES
|
||||
- AUTO_SCAN_ID / SEEK + INDEX TIMERS / ID NOT FOUND
|
||||
- IMPLIED SEEKS / IMPLIED WRITES / RETRIES
|
||||
- EDGE or LEVEL TRIGGERED SEEK_COMPLETE (SC)
|
||||
- SET_PARAMETER / COMPUTE_CORRECTION (DWC flag!)
|
||||
|
||||
Pseudo code (from datasheet) left in to illustrate
|
||||
the intended instruction flow. Some loops were omitted!
|
||||
|
||||
USAGE: tie WF (write fault) to ground if not needed:
|
||||
MCFG_WD2010_IN_WF_CB(GND)
|
||||
|
||||
Other signals should be set to VCC if not serviced:
|
||||
MCFG_WD2010_IN_DRDY_CB(VCC) // DRIVE READY = VCC
|
||||
MCFG_WD2010_IN_SC_CB(VCC) // SEEK COMPLETE = VCC
|
||||
**********************************************************************/
|
||||
|
||||
// WD 2010 CONFIGURATION (2048 cylinder limit)
|
||||
#define STEP_LIMIT 2048
|
||||
#define CYLINDER_HIGH_MASK 0x07
|
||||
|
||||
// DEC RD51 chip; different STEP / CYLINDER LIMIT (**):
|
||||
|
||||
// WD 1010 CONFIGURATION (1024 cylinder limit)
|
||||
// #define STEP_LIMIT 1024
|
||||
// #define CYLINDER_HIGH_MASK 0x03
|
||||
|
||||
// --------------------------------------------------------
|
||||
#define MAX_MFM_SECTORS 17 // STANDARD MFM SECTORS/TRACK
|
||||
// --------------------------------------------------------
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "machine/wd2010.h"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// MACROS / CONSTANTS
|
||||
//**************************************************************************
|
||||
|
||||
#define LOG 1
|
||||
|
||||
|
||||
// task file
|
||||
enum
|
||||
{
|
||||
@ -44,7 +83,7 @@ enum
|
||||
(m_task_file[TASK_FILE_SECTOR_NUMBER])
|
||||
|
||||
#define CYLINDER \
|
||||
(((m_task_file[TASK_FILE_CYLINDER_HIGH] & 0x07) << 8) | m_task_file[TASK_FILE_CYLINDER_LOW])
|
||||
(((m_task_file[TASK_FILE_CYLINDER_HIGH] & CYLINDER_HIGH_MASK) << 8) | m_task_file[TASK_FILE_CYLINDER_LOW])
|
||||
|
||||
#define HEAD \
|
||||
(m_task_file[TASK_FILE_SDH_REGISTER] & 0x07)
|
||||
@ -57,7 +96,6 @@ static const int SECTOR_SIZES[4] = { 256, 512, 1024, 128 };
|
||||
#define SECTOR_SIZE \
|
||||
SECTOR_SIZES[(m_task_file[TASK_FILE_SDH_REGISTER] >> 5) & 0x03]
|
||||
|
||||
|
||||
// status register
|
||||
#define STATUS_BSY 0x80
|
||||
#define STATUS_RDY 0x40
|
||||
@ -108,22 +146,24 @@ const device_type WD2010 = &device_creator<wd2010_device>;
|
||||
//-------------------------------------------------
|
||||
|
||||
wd2010_device::wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, WD2010, "Western Digital WD2010", tag, owner, clock, "wd2010", __FILE__),
|
||||
m_out_intrq_cb(*this),
|
||||
m_out_bdrq_cb(*this),
|
||||
m_out_bcr_cb(*this),
|
||||
m_in_bcs_cb(*this),
|
||||
m_out_bcs_cb(*this),
|
||||
m_out_dirin_cb(*this),
|
||||
m_out_step_cb(*this),
|
||||
m_out_rwc_cb(*this),
|
||||
m_in_drdy_cb(*this),
|
||||
m_in_index_cb(*this),
|
||||
m_in_wf_cb(*this),
|
||||
m_in_tk000_cb(*this),
|
||||
m_in_sc_cb(*this),
|
||||
m_status(0),
|
||||
m_error(0)
|
||||
: device_t(mconfig, WD2010, "Western Digital WD2010", tag, owner, clock, "wd2010", __FILE__),
|
||||
m_out_intrq_cb(*this),
|
||||
m_out_bdrq_cb(*this),
|
||||
m_out_bcr_cb(*this),
|
||||
m_in_bcs_cb(*this),
|
||||
m_in_brdy_cb(*this),
|
||||
m_out_bcs_cb(*this),
|
||||
m_out_dirin_cb(*this),
|
||||
m_out_step_cb(*this),
|
||||
m_out_rwc_cb(*this),
|
||||
m_out_wg_cb(*this),
|
||||
m_in_drdy_cb(*this),
|
||||
m_in_index_cb(*this),
|
||||
m_in_wf_cb(*this),
|
||||
m_in_tk000_cb(*this),
|
||||
m_in_sc_cb(*this),
|
||||
m_status(0),
|
||||
m_error(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -139,17 +179,33 @@ void wd2010_device::device_start()
|
||||
m_out_bdrq_cb.resolve_safe();
|
||||
m_out_bcr_cb.resolve_safe();
|
||||
m_in_bcs_cb.resolve_safe(0);
|
||||
|
||||
m_in_brdy_cb.resolve_safe(0);
|
||||
|
||||
m_out_bcs_cb.resolve_safe();
|
||||
m_out_dirin_cb.resolve_safe();
|
||||
m_out_step_cb.resolve_safe();
|
||||
m_out_rwc_cb.resolve_safe();
|
||||
m_out_wg_cb.resolve_safe();
|
||||
m_in_drdy_cb.resolve_safe(0);
|
||||
m_in_index_cb.resolve_safe(0);
|
||||
m_in_wf_cb.resolve_safe(0);
|
||||
m_in_tk000_cb.resolve_safe(0);
|
||||
m_in_sc_cb.resolve_safe(0);
|
||||
|
||||
/* allocate a timer for commands */
|
||||
cmd_timer = timer_alloc(0);
|
||||
complete_write_when_buffer_ready_high = timer_alloc(1);
|
||||
deassert_write_when_buffer_ready_low = timer_alloc(2);
|
||||
deassert_read_when_buffer_ready_high = timer_alloc(3);
|
||||
}
|
||||
|
||||
// timers
|
||||
#define COMMAND_TIMER 0
|
||||
#define COMPLETE_WRITE_SECTOR 1
|
||||
#define DE_ASSERT_WRITE 2
|
||||
#define DE_ASSERT_READ 3
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
@ -157,6 +213,11 @@ void wd2010_device::device_start()
|
||||
|
||||
void wd2010_device::device_reset()
|
||||
{
|
||||
m_out_intrq_cb(CLEAR_LINE);
|
||||
|
||||
buffer_ready(false);
|
||||
|
||||
m_present_cylinder = 0; // start somewhere
|
||||
}
|
||||
|
||||
|
||||
@ -164,23 +225,36 @@ void wd2010_device::device_reset()
|
||||
// read -
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( wd2010_device::read )
|
||||
READ8_MEMBER(wd2010_device::read)
|
||||
{
|
||||
UINT8 data = 0;
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case TASK_FILE_ERROR:
|
||||
data = m_error;
|
||||
if (m_status & STATUS_CIP) // "if other registers are read while CIP, the status register contents are returned."
|
||||
data = (m_in_drdy_cb() ? 0x40 : 0) | (m_in_wf_cb() ? 0x20 : 0) | (m_in_sc_cb() ? 0x10 : 0) | m_status;// see STATUS register
|
||||
else
|
||||
data = m_error;
|
||||
break;
|
||||
|
||||
case TASK_FILE_STATUS:
|
||||
m_out_intrq_cb(CLEAR_LINE);
|
||||
data = m_status | STATUS_RDY | STATUS_SC;
|
||||
m_out_intrq_cb(CLEAR_LINE); // "reading the status register clears INTRQ" (-> datasheet)
|
||||
data = (m_in_drdy_cb() ? 0x40 : 0) | (m_in_wf_cb() ? 0x20 : 0) | (m_in_sc_cb() ? 0x10 : 0) | m_status;// see ERROR register
|
||||
break;
|
||||
|
||||
default:
|
||||
data = m_task_file[offset];
|
||||
|
||||
if (offset == TASK_FILE_SDH_REGISTER)
|
||||
{
|
||||
|
||||
logerror("(READ) %s WD2010 '%s' SDH: %u\n", machine().describe_context(), tag(), data);
|
||||
logerror("(READ) %s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD);
|
||||
logerror("(READ) %s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE);
|
||||
logerror("(READ) %s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -192,7 +266,7 @@ READ8_MEMBER( wd2010_device::read )
|
||||
// write -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( wd2010_device::write )
|
||||
WRITE8_MEMBER(wd2010_device::write)
|
||||
{
|
||||
m_task_file[offset] = data;
|
||||
|
||||
@ -211,23 +285,28 @@ WRITE8_MEMBER( wd2010_device::write )
|
||||
break;
|
||||
|
||||
case TASK_FILE_CYLINDER_LOW:
|
||||
if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER);
|
||||
if (LOG) logerror("%s WD2010 '%s' Cylinder (lower bits set): %u\n", machine().describe_context(), tag(), CYLINDER);
|
||||
break;
|
||||
|
||||
case TASK_FILE_CYLINDER_HIGH:
|
||||
if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER);
|
||||
if (LOG) logerror("%s WD2010 '%s' Cylinder (MSB bits set): %u\n", machine().describe_context(), tag(), CYLINDER);
|
||||
break;
|
||||
|
||||
case TASK_FILE_SDH_REGISTER:
|
||||
if (LOG)
|
||||
{
|
||||
logerror("%s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD);
|
||||
logerror("%s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE);
|
||||
logerror("%s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE);
|
||||
logerror("(WRITE) %s WD2010 '%s' SDH: %u\n", machine().describe_context(), tag(), data);
|
||||
logerror("(WRITE) %s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD);
|
||||
logerror("(WRITE) %s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE);
|
||||
logerror("(WRITE) %s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE);
|
||||
}
|
||||
break;
|
||||
|
||||
case TASK_FILE_COMMAND:
|
||||
m_out_intrq_cb(CLEAR_LINE); // "either reading the status register or writing a new command clears INTRQ"
|
||||
m_status &= ~(STATUS_ERR | STATUS_BSY | STATUS_CIP); // "Reset ERR bit in STATUS upon new cmd" (see datasheet)
|
||||
m_error = 0;
|
||||
|
||||
if (data == COMMAND_COMPUTE_CORRECTION)
|
||||
{
|
||||
if (LOG) logerror("%s WD2010 '%s' COMPUTE CORRECTION\n", machine().describe_context(), tag());
|
||||
@ -253,12 +332,12 @@ WRITE8_MEMBER( wd2010_device::write )
|
||||
break;
|
||||
|
||||
case COMMAND_READ_SECTOR:
|
||||
if (LOG) logerror("%s WD2010 '%s' READ SECTOR\n", machine().describe_context(), tag());
|
||||
if (LOG) logerror("%s WD2010 '%s' READ SECTOR (I = %u) (M = %u)\n", machine().describe_context(), tag(), ((data & 8)>0), ((data & 4)>0));
|
||||
read_sector(data);
|
||||
break;
|
||||
|
||||
case COMMAND_WRITE_SECTOR:
|
||||
if (LOG) logerror("%s WD2010 '%s' WRITE SECTOR\n", machine().describe_context(), tag());
|
||||
if (LOG) logerror("%s WD2010 '%s' WRITE SECTOR (M = %u)\n", machine().describe_context(), tag(), ((data & 4) > 0));
|
||||
write_sector(data);
|
||||
break;
|
||||
|
||||
@ -272,136 +351,644 @@ WRITE8_MEMBER( wd2010_device::write )
|
||||
format(data);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// compute_correction -
|
||||
//-------------------------------------------------
|
||||
|
||||
void wd2010_device::compute_correction(UINT8 data)
|
||||
{
|
||||
UINT8 newstatus = STATUS_RDY | STATUS_SC;
|
||||
complete_cmd(newstatus);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// set_parameter -
|
||||
//-------------------------------------------------
|
||||
|
||||
void wd2010_device::set_parameter(UINT8 data)
|
||||
{
|
||||
UINT8 newstatus = STATUS_RDY | STATUS_SC;
|
||||
complete_cmd(newstatus);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// restore -
|
||||
//-------------------------------------------------
|
||||
|
||||
void wd2010_device::restore(UINT8 data)
|
||||
{
|
||||
// reset INTRQ, errors, set BUSY, CIP
|
||||
m_out_intrq_cb(CLEAR_LINE);
|
||||
UINT8 newstatus = STATUS_RDY | STATUS_SC;
|
||||
|
||||
m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP
|
||||
m_error = 0;
|
||||
m_status = STATUS_BSY | STATUS_CIP;
|
||||
|
||||
// reset RWC, set direction=OUT, store step rate
|
||||
m_out_rwc_cb(0);
|
||||
m_out_dirin_cb(0);
|
||||
m_out_rwc_cb(0); // reset RWC, set direction = OUT
|
||||
|
||||
// datasheet: DIRIN HIGH = in ; LOW = out
|
||||
m_out_dirin_cb(0); // 0 = heads move away from the spindle, towards track O.
|
||||
|
||||
// TODO: store step rate
|
||||
|
||||
m_present_cylinder = 0; // (sse WD2010-05 datasheet)
|
||||
m_task_file[TASK_FILE_CYLINDER_HIGH] = 0;
|
||||
m_task_file[TASK_FILE_CYLINDER_LOW] = 0;
|
||||
|
||||
int step_pulses = 0;
|
||||
|
||||
while (step_pulses < 2048)
|
||||
while (step_pulses < STEP_LIMIT)
|
||||
{
|
||||
while (!m_in_sc_cb())
|
||||
{
|
||||
// drive not ready or write fault?
|
||||
if (!m_in_drdy_cb() || m_in_wf_cb())
|
||||
if (!m_in_drdy_cb() || m_in_wf_cb()) // drive not ready or write fault?
|
||||
{
|
||||
// pulse BCR, set AC, INTRQ, reset BSY, CIP
|
||||
m_out_bcr_cb(0);
|
||||
m_out_bcr_cb(0); // pulse BCR
|
||||
m_out_bcr_cb(1);
|
||||
m_error = ERROR_AC;
|
||||
m_status = (m_in_drdy_cb() << 6) | (m_in_wf_cb() << 5) | STATUS_ERR;
|
||||
m_out_intrq_cb(ASSERT_LINE);
|
||||
|
||||
m_error = ERROR_AC; // ERROR : ABORTED COMMAND
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_in_tk000_cb())
|
||||
//if (m_in_tk000_cb())
|
||||
if (step_pulses == STEP_LIMIT - 2) // Simulate TRACK 00 signal (normally from DRIVE)
|
||||
{
|
||||
// pulse BCR, set INTRQ, reset BSY, CIP
|
||||
m_out_bcr_cb(0);
|
||||
m_out_bcr_cb(0); // pulse BCR
|
||||
m_out_bcr_cb(1);
|
||||
m_status &= ~(STATUS_BSY | STATUS_CIP);
|
||||
m_out_intrq_cb(ASSERT_LINE);
|
||||
newstatus &= ~(STATUS_BSY | STATUS_CIP); // prepare new status; (INTRQ later) reset BSY, CIP
|
||||
complete_cmd(newstatus);
|
||||
return;
|
||||
}
|
||||
|
||||
if (step_pulses == 2047)
|
||||
if (step_pulses == STEP_LIMIT - 1) // NOTE: STEP_LIMIT - differs - between WD2010 and WD1010
|
||||
{
|
||||
// set TK000 error
|
||||
m_error = ERROR_TK;
|
||||
m_status |= STATUS_ERR;
|
||||
m_error = ERROR_TK; // ERROR: track 0 not reached within limit
|
||||
newstatus = newstatus | STATUS_ERR;
|
||||
|
||||
// pulse BCR, set INTRQ, reset BSY, CIP
|
||||
m_out_bcr_cb(0);
|
||||
m_out_bcr_cb(0); // pulse BCR
|
||||
m_out_bcr_cb(1);
|
||||
m_status &= ~(STATUS_BSY | STATUS_CIP);
|
||||
m_out_intrq_cb(ASSERT_LINE);
|
||||
newstatus &= ~(STATUS_BSY | STATUS_CIP); // prepare new status; (INTRQ later) reset BSY, CIP
|
||||
complete_cmd(newstatus);
|
||||
return;
|
||||
}
|
||||
|
||||
// issue a step pulse
|
||||
m_out_step_cb(1);
|
||||
m_out_step_cb(1); // issue a step pulse
|
||||
m_out_step_cb(0);
|
||||
step_pulses++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(1);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// seek -
|
||||
//-------------------------------------------------
|
||||
|
||||
void wd2010_device::seek(UINT8 data)
|
||||
{
|
||||
}
|
||||
// FIXME : step rate, drive change (!)
|
||||
|
||||
// NOT IMPLEMENTED: IMPLIED SEEK ("wait until rising edge of SC signal")
|
||||
void wd2010_device::seek(UINT8 data)
|
||||
{
|
||||
UINT8 newstatus = STATUS_RDY | STATUS_SC;
|
||||
|
||||
m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP
|
||||
m_error = 0;
|
||||
m_status = STATUS_BSY | STATUS_CIP;
|
||||
|
||||
// TODO : store STEP RATE.
|
||||
|
||||
auto_scan_id(data); // has drive number changed?
|
||||
|
||||
int direction = 0; // 0 = towards 0
|
||||
int step_pulses = 0;
|
||||
|
||||
// Calculate number of steps by comparing the cylinder registers
|
||||
// HI/LO with the internally stored position.
|
||||
UINT32 cylinder_registers = CYLINDER;
|
||||
if (m_present_cylinder > cylinder_registers)
|
||||
{
|
||||
step_pulses = m_present_cylinder - cylinder_registers;
|
||||
direction = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
step_pulses = cylinder_registers - m_present_cylinder;
|
||||
direction = 1;
|
||||
}
|
||||
logerror("SEEK - direction = %u, step_pulses = %u\n", direction, step_pulses);
|
||||
m_out_dirin_cb(direction);
|
||||
|
||||
if (!m_in_drdy_cb() || m_in_wf_cb()) // DRDY de-asserted or WF asserted?
|
||||
{
|
||||
m_error = ERROR_AC;
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (step_pulses > 0) // issue STEP PULSES
|
||||
{
|
||||
if (direction == 0)
|
||||
{
|
||||
m_out_step_cb(1); // issue a step pulse
|
||||
m_out_step_cb(0);
|
||||
|
||||
if (m_present_cylinder > 0)
|
||||
m_present_cylinder--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_out_step_cb(0);
|
||||
m_out_step_cb(1);
|
||||
|
||||
m_present_cylinder++;
|
||||
}
|
||||
step_pulses--;
|
||||
|
||||
// TODO: delay according to rate field
|
||||
}
|
||||
|
||||
// ALL STEPS ISSUED NOW
|
||||
|
||||
if (!m_in_drdy_cb()) // DRDY not asserted = > ABORTED COMMAND
|
||||
{
|
||||
m_error = ERROR_AC;
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// AFTER ALL STEPS ARE ISSUED ...
|
||||
// UPDATE INTERNAL CYLINDER POSITION REGISTER (from WD1010 spec -> "SEEK COMMAND")
|
||||
m_present_cylinder = cylinder_registers;
|
||||
|
||||
logerror("SEEK (END) - m_present_cylinder = %u\n", m_present_cylinder);
|
||||
|
||||
cmd_timer->adjust(attotime::from_msec(35), newstatus); // 35 msecs makes "SEEK_TIMING" test happy.
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// read_sector -
|
||||
//-------------------------------------------------
|
||||
|
||||
// FIXME: multiple sector transfers, ID / CYL / HEAD / SIZE match
|
||||
// + ERROR HANDLING (...)
|
||||
void wd2010_device::read_sector(UINT8 data)
|
||||
{
|
||||
UINT8 newstatus = STATUS_RDY | STATUS_SC;
|
||||
int intrq_at_end = 0; // (default) : (I = 1 INTRQ occurs when the command
|
||||
|
||||
m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP
|
||||
m_error = 0;
|
||||
m_status = STATUS_BSY | STATUS_CIP;
|
||||
|
||||
// Assume: drive NO # has not changed... (else: SCAN_ID; GET CYL#)
|
||||
auto_scan_id(data); // has drive number changed?
|
||||
|
||||
// CYL REGISTERS and INTERNAL CYL. SAME ?
|
||||
// TODO: < NOT SAME? THEN _SEEK_ >
|
||||
|
||||
// DRIVE NOT READY? OR WF?
|
||||
if ( (!m_in_drdy_cb()) || m_in_wf_cb() )
|
||||
{
|
||||
m_error = ERROR_AC; // ABORTED_COMMAND
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_out_bcs_cb(1); // activate BCS (!)
|
||||
|
||||
m_out_bcr_cb(0); // strobe BCR
|
||||
m_out_bcr_cb(1);
|
||||
|
||||
if (!m_in_drdy_cb()) // DRIVE NOT READY?
|
||||
{
|
||||
m_error = ERROR_AC; // ABORTED_COMMAND
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// < SEARCH FOR ID FIELD >
|
||||
// < CYL / HEAD / SEC.SIZE MATCH ? >
|
||||
|
||||
// < ID NOT FOUND >
|
||||
if (SECTOR_NUMBER > MAX_MFM_SECTORS)
|
||||
{
|
||||
// prepare new status; (later IRQ +) reset BSY, CIP
|
||||
m_error = ERROR_ID;
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// LOOP OVER 10 INDEXES : SCAN_ID / GET CYL.# (not implemented: ID NOT FOUND)
|
||||
|
||||
// CYL / HEAD / SEC.SIZE MATCH ? => (ID FOUND)
|
||||
//
|
||||
// NO "BAD BLOCK DETECT" (** NOT IMPLEMENTED **)
|
||||
// NO "CRC ERROR" (** NOT IMPLEMENTED **)
|
||||
// AND "DAM FOUND" (** NOT IMPLEMENTED **)
|
||||
|
||||
// ====> THEN "TRANSFER SECTOR TO BUFFER" <====
|
||||
|
||||
m_out_bcr_cb(0); // strobe BCR
|
||||
m_out_bcr_cb(1);
|
||||
|
||||
// NO "CRC ERROR"
|
||||
|
||||
// FLAG "M" SET? (MULTIPLE SECTOR TRANSFERS)
|
||||
if (data & 4)
|
||||
logerror("WD2010 (READ): MULTIPLE SECTOR READ (M = 1).\n");
|
||||
|
||||
// Assume: NO "M" (MULTIPLE SECTOR TRANSFERS)
|
||||
|
||||
m_out_bcs_cb(0); // deactivate BCS (!)
|
||||
|
||||
m_out_bcr_cb(0); // strobe BCR
|
||||
m_out_bcr_cb(1);
|
||||
|
||||
// set BDRQ (NOTE: DRQ status bit 3 reflects state of BDRQ)
|
||||
m_status |= STATUS_DRQ;
|
||||
m_out_bdrq_cb(1);
|
||||
|
||||
// reset BUSY (* after * TRANSFER OF SECTOR in READ)
|
||||
m_status &= ~(STATUS_BSY);
|
||||
|
||||
// FLAG "I" SET?
|
||||
if (!(data & 8)) // (I = 0 INTRQ occurs with BDRQ/DRQ indicating the Sector Buffer is full...)
|
||||
{
|
||||
m_out_intrq_cb(ASSERT_LINE);
|
||||
if (!(data & 4)) // (...valid only when M = 0)
|
||||
intrq_at_end = STATUS_DWC; // 'reuse' unused DWC bit!
|
||||
}
|
||||
else
|
||||
{
|
||||
intrq_at_end = 0; // (default): (I = 1 INTRQ occurs when the command is completed and the Host has read the Sector Buffer)
|
||||
}
|
||||
|
||||
// (WAIT FOR): BRDY LOW TO HIGH? (see -> TIMER)
|
||||
|
||||
} // DRIVE_READY ? (inner)
|
||||
|
||||
} // DRIVE_READY ? (outer)
|
||||
|
||||
// NOTE : (intrq_at_end = 0) - INTRQ occurs when the command is completed
|
||||
newstatus |= (m_status & ~(STATUS_CIP | STATUS_DRQ)) | intrq_at_end; // de-assert CIP + DRQ (BSY already reset)
|
||||
|
||||
deassert_read_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus); // complete command ON *RISING EDGE * OF BUFFER_READY
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// write_sector -
|
||||
// write_sector (stage I)
|
||||
//-------------------------------------------------
|
||||
|
||||
// FIXME: SEEK, SEEK_COMPLETE, Drive # change (!)
|
||||
// as well as CYL.register + internal CYL.register comparisons
|
||||
void wd2010_device::write_sector(UINT8 data)
|
||||
{
|
||||
m_error = 0; // De-assert ERROR + DRQ
|
||||
m_status &= ~(STATUS_DRQ);
|
||||
|
||||
m_status = STATUS_BSY | STATUS_CIP; // Assert BUSY + CIP
|
||||
|
||||
m_status |= STATUS_DRQ; // Assert BDRQ + DRQ (= status bit 3)
|
||||
m_out_bdrq_cb(1);
|
||||
|
||||
// WAIT UNTIL BRDY ASSERTED (-> timer):
|
||||
complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), data); // 1 usec
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// write_sector (stage II)
|
||||
//-------------------------------------------------
|
||||
void wd2010_device::complete_write_sector(UINT8 data)
|
||||
{
|
||||
UINT8 newstatus = STATUS_RDY | STATUS_SC;
|
||||
|
||||
m_out_bdrq_cb(0); // DE-Assert BDRQ (...and DRQ !)
|
||||
m_status &= ~(STATUS_DRQ);
|
||||
|
||||
// (When drive changed) : SCAN_ID / GET CYL#
|
||||
auto_scan_id(data); // has drive number changed? (*** UNIMPLEMENTED ***)
|
||||
|
||||
// Assume YES : CYL.register + internal CYL.register SAME? (if NO => SEEK!)
|
||||
// Assume : SEEK_COMPLETE = YES
|
||||
|
||||
if (!m_in_drdy_cb() || m_in_wf_cb()) // DRIVE IS READY / NO WF?
|
||||
{
|
||||
m_error = ERROR_AC; // ABORTED_COMMAND
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ // --------------------------------------------------------
|
||||
// (*** UNIMPLEMENTED ***) Search for ID field...
|
||||
|
||||
// < Correct ID found >
|
||||
|
||||
// (*** UNIMPLEMENTED ***) : 'ID NOT FOUND' - set bit 4 error register
|
||||
// ........................: => SCAN_ID => RE-SEEK (2-10 INDEX PULSES) / Set ERR bit 0 status register ..
|
||||
|
||||
m_status &= ~(STATUS_SC); // "WRITE_GATE valid when SEEK_COMPLETE = 0" (see Rainbow 100 Addendum!)
|
||||
|
||||
m_out_bcs_cb(1);
|
||||
m_out_wg_cb(1); // (!)
|
||||
|
||||
m_out_bcr_cb(0); // strobe BCR
|
||||
m_out_bcr_cb(1);
|
||||
|
||||
// Assume: DRIVE IS READY / NO WF
|
||||
|
||||
if (!m_in_drdy_cb() || m_in_wf_cb()) // DRDY de-asserted or WF asserted?
|
||||
{
|
||||
m_error = ERROR_AC; // ABORTED_COMMAND
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ====> WRITE DATA TO SECTOR <====
|
||||
|
||||
m_out_wg_cb(0); // (!)
|
||||
|
||||
// Assume: (single sector transfer; M = 0)
|
||||
|
||||
} // (INNER IF): No WF and DRIVE IS READY.
|
||||
} // --------------------------------------------------------
|
||||
|
||||
// 'complete_cmd' ON THE FALLING EDGE OF _BUFFER_READY_ ( set by WRITE_SECTOR ) !
|
||||
deassert_write_when_buffer_ready_low->adjust(attotime::from_usec(1), newstatus);
|
||||
}
|
||||
|
||||
// ******************************************************
|
||||
// AUTO SCAN-ID (whenever DRIVE # changes):
|
||||
|
||||
// * does nothing right now *
|
||||
// ******************************************************
|
||||
void wd2010_device::auto_scan_id(UINT8 data)
|
||||
{
|
||||
static int last_drive;
|
||||
|
||||
if (DRIVE != last_drive)
|
||||
{
|
||||
printf("\n(WD2010) : UNSUPPORTED DRIVE CHANGE !\n");
|
||||
logerror("\n(WD2010) : UNSUPPORTED DRIVE CHANGE !\n");
|
||||
|
||||
//update_sdh(new_sector_size, new_head, new_cylinder, new_sectornr);
|
||||
}
|
||||
last_drive = DRIVE;
|
||||
|
||||
return; // AUTO-SCAN CURRENTLY DISABLED (see NOTES)
|
||||
}
|
||||
// ******************************************************
|
||||
|
||||
// What to do here (just update present_cylinder with CYLINDER)...?
|
||||
void wd2010_device::update_sdh(UINT8 new_sector_size, UINT8 new_head, UINT16 new_cylinder, UINT8 new_sectornr)
|
||||
{
|
||||
// "Update SDH"
|
||||
/*
|
||||
// Update SECTOR_SIZE, HEAD in SDH with the ID found -
|
||||
m_task_file[TASK_FILE_SDH_REGISTER] = ???
|
||||
|
||||
// ...update CYLINDER registers with cylinder found -
|
||||
m_task_file[TASK_FILE_CYLINDER_LOW] = (new_cylinder >> 4) & 0x0f;
|
||||
m_task_file[TASK_FILE_CYLINDER_HIGH] = (new_cylinder - ((new_cylinder >> 4) << 4)) & 0x0f;
|
||||
|
||||
// ...update SECTOR_NUMBER with sector nr. found -
|
||||
m_task_file[TASK_FILE_SECTOR_NUMBER] = new_sectornr;
|
||||
*/
|
||||
|
||||
m_present_cylinder = CYLINDER;
|
||||
logerror("UPDATE_SDH - m_present_cylinder = %u\n", m_present_cylinder);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// scan_id -
|
||||
//-------------------------------------------------
|
||||
|
||||
// Reads the cylinder number from the track on which the heads are PRESENTLY located,
|
||||
// and writes this into the Present Cylinder Position Register.
|
||||
|
||||
// FIXME: NO ID HANDLING (ID FOUND / NOT FOUND), NO BAD BLOCK; NO CRC
|
||||
void wd2010_device::scan_id(UINT8 data)
|
||||
{
|
||||
UINT8 newstatus = STATUS_RDY;
|
||||
|
||||
m_out_intrq_cb(CLEAR_LINE);
|
||||
m_error = 0;
|
||||
m_status = STATUS_BSY | STATUS_CIP;
|
||||
|
||||
// Assume DRIVE READY.
|
||||
// < TODO: Search for ANY ID FIELD. >
|
||||
|
||||
// Assume ID FOUND :
|
||||
update_sdh( 32, 0, 0, 1 ); // (NEW:) SECTOR_SIZE, HEAD, CYLINDER, SECTOR_NR
|
||||
|
||||
// NO BAD BLOCK.
|
||||
// NO CRC ERROR.
|
||||
|
||||
complete_cmd(newstatus);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// FORMAT ENTIRE TRACK using the task file + sector buffer
|
||||
|
||||
//-------------------------------------------------
|
||||
// format -
|
||||
//-------------------------------------------------
|
||||
// On real hardware, data fields are filled with FF.
|
||||
// Sector buffer is used for track layout (see datasheet).
|
||||
|
||||
// Routine simulates one single write on each track
|
||||
// - just enough to keep formatter programs happy -
|
||||
|
||||
// < UNIMPLEMENTED: (IMPLIED) SEEKs, INDEX, CRC and GAPs >
|
||||
//--------------------------------------------------------
|
||||
// SECTOR_COUNT REG.= 'total # of sectors to be formatted'
|
||||
// (raw number; no multiplication) = 16 decimal on RD51
|
||||
|
||||
// SECTOR NUMBER REG.= number of bytes - 3 (for GAP 1 + 3)
|
||||
// = 40 decimal on DEC RD51 with WUTIL 3.2
|
||||
//--------------------------------------------------------
|
||||
void wd2010_device::format(UINT8 data)
|
||||
{
|
||||
UINT8 newstatus = STATUS_RDY;
|
||||
|
||||
m_out_intrq_cb(CLEAR_LINE);
|
||||
m_error = 0;
|
||||
m_status = STATUS_BSY | STATUS_CIP;
|
||||
|
||||
m_status |= STATUS_DRQ;
|
||||
m_out_bdrq_cb(1);
|
||||
|
||||
// < WAIT UNTIL BRDY ASSERTED >
|
||||
|
||||
// Datasheet says [DRQ] must go LOW...
|
||||
// ...delayed here _until BRDY goes high_ (=> TIMER EVENT <=):
|
||||
|
||||
// m_out_bdrq_cb(0);
|
||||
// m_status &= ~(STATUS_DRQ);
|
||||
|
||||
auto_scan_id(data); // has drive number changed?
|
||||
|
||||
// TODO: Seek to desired cylinder
|
||||
// Assume : SEEK COMPLETE.
|
||||
|
||||
m_out_bcr_cb(0); // strobe BCR
|
||||
m_out_bcr_cb(1);
|
||||
|
||||
m_out_bcs_cb(1); // activate BCS (!)
|
||||
|
||||
if (!m_in_drdy_cb() || m_in_wf_cb())
|
||||
{
|
||||
m_error = ERROR_AC; // ABORTED_COMMAND
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// WAIT FOR INDEX
|
||||
|
||||
m_out_wg_cb(1); // Have Index, activate WRITE GATE
|
||||
|
||||
// Check for WRITE FAULT (WF)
|
||||
if (m_in_wf_cb())
|
||||
{
|
||||
m_error = ERROR_AC; // ABORTED_COMMAND
|
||||
complete_cmd(newstatus | STATUS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// UINT8 format_sector_count = m_task_file[TASK_FILE_SECTOR_COUNT];
|
||||
// do
|
||||
// {
|
||||
// < WRITE GAP 1 or GAP 3 >
|
||||
|
||||
// < Wait for SEEK_COMPLETE=1 (extend GAP if SEEK_COMPLETE = 0) >
|
||||
// < Assume SEEK COMPLETE >
|
||||
|
||||
// format_sector_count--;
|
||||
// if (format_sector_count != 0)
|
||||
{
|
||||
// The Rainbow 100 driver does ignore multiple sector
|
||||
// transfers so WRITE FORMAT does not actually write -
|
||||
|
||||
m_out_wg_cb(0); // (transition from WG 1 -> 0)
|
||||
|
||||
// NOTE: decrementing TASK_FILE_SECTOR_COUNT does * NOT WORK *
|
||||
}
|
||||
// else
|
||||
// { // < Write 4Es until INDEX (*** UNIMPLEMENTED ****) >
|
||||
// }
|
||||
// } while (format_sector_count > 0);
|
||||
|
||||
// ** DELAY INTRQ UNTIL WRITE IS COMPLETE :
|
||||
complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus | STATUS_DRQ); // 1 USECs
|
||||
}
|
||||
|
||||
|
||||
// *************************************
|
||||
// INTERNAL
|
||||
// *************************************
|
||||
void wd2010_device::buffer_ready(bool state)
|
||||
{
|
||||
is_buffer_ready = state;
|
||||
}
|
||||
|
||||
|
||||
void wd2010_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
|
||||
{
|
||||
switch (tid)
|
||||
{
|
||||
case COMMAND_TIMER:
|
||||
cmd_timer->adjust(attotime::never);
|
||||
complete_immediate(param);
|
||||
break;
|
||||
|
||||
case COMPLETE_WRITE_SECTOR: // when BUFFER_READY -> HIGH
|
||||
if (is_buffer_ready)
|
||||
{
|
||||
complete_write_when_buffer_ready_high->adjust(attotime::never);
|
||||
complete_write_sector(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
complete_write_when_buffer_ready_high->reset();
|
||||
complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
|
||||
}
|
||||
break;
|
||||
|
||||
case DE_ASSERT_WRITE: // waiting for BUFFER_READY -> LOW
|
||||
if (!(is_buffer_ready))
|
||||
{
|
||||
deassert_write_when_buffer_ready_low->adjust(attotime::never);
|
||||
complete_immediate(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
deassert_write_when_buffer_ready_low->reset();
|
||||
deassert_write_when_buffer_ready_low->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
|
||||
}
|
||||
break;
|
||||
|
||||
case DE_ASSERT_READ: // when BUFFER_READY -> HIGH
|
||||
if (is_buffer_ready)
|
||||
{
|
||||
deassert_read_when_buffer_ready_high->adjust(attotime::never);
|
||||
|
||||
m_error &= ~ERROR_ID;
|
||||
param &= ~STATUS_ERR;
|
||||
|
||||
m_out_bdrq_cb(0);
|
||||
complete_immediate(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
deassert_read_when_buffer_ready_high->reset();
|
||||
deassert_read_when_buffer_ready_high->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!)
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Called by 'device_timer' -
|
||||
void wd2010_device::complete_immediate(UINT8 status)
|
||||
{
|
||||
// re-evaluate external signals at end of command
|
||||
status &= ~(STATUS_RDY | STATUS_WF | STATUS_SC); // RDY 0x40 / WF 0x20 / SC 0x10
|
||||
status |= (m_in_drdy_cb() ? 0x40 : 0) | (m_in_wf_cb() ? 0x20 : 0) | (m_in_sc_cb() ? 0x10 : 0);
|
||||
|
||||
if (status & STATUS_DRQ) // if DRQ was set, reset
|
||||
{
|
||||
status &= ~(STATUS_DRQ);
|
||||
m_out_bdrq_cb(0);
|
||||
}
|
||||
|
||||
// Set current status (M_STATUS)
|
||||
m_status = status & (255 - STATUS_DWC); // minus "unused" bit 2 (DWC)
|
||||
|
||||
m_status &= ~(STATUS_BSY | STATUS_CIP); // de-assert BUSY + CIP
|
||||
|
||||
// "IRQ AT END OF COMMAND" when BIT 2 set (DWC 'data was corrected' - unused in this context!)
|
||||
if (!(status & STATUS_DWC)) // interrupt at END OF COMMAND ?
|
||||
m_out_intrq_cb(ASSERT_LINE); // Assert INTRQ (callback).
|
||||
|
||||
m_out_bcs_cb(0); // de-assert BCS (needed)
|
||||
m_out_wg_cb(0); // deactivate WG (required by write / format)
|
||||
|
||||
m_out_bcr_cb(0); // strobe BCR
|
||||
m_out_bcr_cb(1);
|
||||
}
|
||||
|
||||
void wd2010_device::complete_cmd(UINT8 status)
|
||||
{
|
||||
cmd_timer->adjust(attotime::from_msec(1), status);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,9 @@
|
||||
#define MCFG_WD2010_OUT_BCR_CB(_devcb) \
|
||||
devcb = &wd2010_device::set_out_bcr_callback(*device, DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_WD2010_IN_BRDY_CB(_devcb) \
|
||||
devcb = &wd2010_device::set_in_brdy_callback(*device, DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_WD2010_IN_BCS_CB(_devcb) \
|
||||
devcb = &wd2010_device::set_in_bcs_callback(*device, DEVCB_##_devcb);
|
||||
|
||||
@ -47,6 +50,9 @@
|
||||
#define MCFG_WD2010_OUT_RWC_CB(_devcb) \
|
||||
devcb = &wd2010_device::set_out_rwc_callback(*device, DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_WD2010_OUT_WG_CB(_devcb) \
|
||||
devcb = &wd2010_device::set_out_wg_callback(*device, DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_WD2010_IN_DRDY_CB(_devcb) \
|
||||
devcb = &wd2010_device::set_in_drdy_callback(*device, DEVCB_##_devcb);
|
||||
|
||||
@ -77,11 +83,13 @@ public:
|
||||
template<class _Object> static devcb_base &set_out_intrq_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_intrq_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_out_bdrq_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_bdrq_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_out_bcr_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_bcr_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_in_brdy_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_in_brdy_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_in_bcs_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_in_bcs_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_out_bcs_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_bcs_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_out_dirin_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_dirin_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_out_step_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_step_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_out_rwc_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_rwc_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_out_wg_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_out_wg_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_in_drdy_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_in_drdy_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_in_index_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_in_index_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_in_wf_callback(device_t &device, _Object object) { return downcast<wd2010_device &>(device).m_in_wf_cb.set_callback(object); }
|
||||
@ -91,11 +99,15 @@ public:
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
|
||||
void buffer_ready(bool state);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
private:
|
||||
void compute_correction(UINT8 data);
|
||||
void set_parameter(UINT8 data);
|
||||
@ -104,16 +116,20 @@ private:
|
||||
void read_sector(UINT8 data);
|
||||
void write_sector(UINT8 data);
|
||||
void scan_id(UINT8 data);
|
||||
void update_sdh(UINT8 new_sector_size, UINT8 new_head, UINT16 new_cylinder, UINT8 new_sectornr);
|
||||
void auto_scan_id(UINT8 data);
|
||||
void format(UINT8 data);
|
||||
|
||||
devcb_write_line m_out_intrq_cb;
|
||||
devcb_write_line m_out_bdrq_cb;
|
||||
devcb_write_line m_out_bcr_cb;
|
||||
devcb_read8 m_in_bcs_cb;
|
||||
devcb_read_line m_in_brdy_cb;
|
||||
devcb_write8 m_out_bcs_cb;
|
||||
devcb_write_line m_out_dirin_cb;
|
||||
devcb_write_line m_out_step_cb;
|
||||
devcb_write_line m_out_rwc_cb;
|
||||
devcb_write_line m_out_wg_cb;
|
||||
devcb_read_line m_in_drdy_cb;
|
||||
devcb_read_line m_in_index_cb;
|
||||
devcb_read_line m_in_wf_cb;
|
||||
@ -123,8 +139,20 @@ private:
|
||||
UINT8 m_status;
|
||||
UINT8 m_error;
|
||||
UINT8 m_task_file[8];
|
||||
};
|
||||
|
||||
emu_timer *cmd_timer;
|
||||
emu_timer *complete_write_when_buffer_ready_high;
|
||||
emu_timer *deassert_write_when_buffer_ready_low;
|
||||
emu_timer *deassert_read_when_buffer_ready_high;
|
||||
|
||||
void complete_write_sector(UINT8 status);
|
||||
void complete_cmd(UINT8 status);
|
||||
void complete_immediate(UINT8 status);
|
||||
|
||||
bool is_buffer_ready;
|
||||
|
||||
UINT32 m_present_cylinder; // Present Cylinder Position Register
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type WD2010;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -106,7 +106,12 @@
|
||||
</text>
|
||||
</element>
|
||||
|
||||
|
||||
<element name="digit" defstate="0">
|
||||
<led7seg>
|
||||
<color red="0.75" green="0.0" blue="0.0" />
|
||||
</led7seg>
|
||||
</element>
|
||||
|
||||
<view name="Default Layout">
|
||||
<screen index="0">
|
||||
<bounds x="30" y="0" width="640" height="480" />
|
||||
@ -206,6 +211,13 @@
|
||||
<bezel name="label11" element="l11_wait">
|
||||
<bounds x="0" y="282" width="15" height="16" />
|
||||
</bezel>
|
||||
|
||||
<bezel name="digit0" element="digit">
|
||||
<bounds x="0" y="320" width="14" height="20" />
|
||||
</bezel>
|
||||
<bezel name="digit1" element="digit">
|
||||
<bounds x="15" y="320" width="14" height="20" />
|
||||
</bezel>
|
||||
</view>
|
||||
|
||||
<view name="Screen Only">
|
||||
|
@ -230,14 +230,14 @@ const rom_entry *lk201_device::device_rom_region() const
|
||||
|
||||
DEC omitted terms like 'Interrupt', 'Break' and 'Data / Talk' on some keyboards,
|
||||
so Fn numbers are definitely important for end users.
|
||||
|
||||
|
||||
=== CURRENT SPECIAL KEYS ===
|
||||
[PC-AT] ......=> [DEC]
|
||||
LEFT CONTROL..=> Control
|
||||
LEFT ALT .....=> Compose
|
||||
|
||||
RIGHT ALT ....=> Help
|
||||
RIGHT CONTROL => Do
|
||||
[PC-AT] ......=> [DEC]
|
||||
LEFT CONTROL..=> Control
|
||||
LEFT ALT .....=> Compose
|
||||
|
||||
RIGHT ALT ....=> Help
|
||||
RIGHT CONTROL => Do
|
||||
==============================================================================================
|
||||
=== (PC - AT ) keys above cursor block ===
|
||||
* KEYCODE_INSERT * KEYCODE_HOME * KEYCODE_PGUP
|
||||
@ -249,9 +249,9 @@ const rom_entry *lk201_device::device_rom_region() const
|
||||
==============================================================================================
|
||||
=== CURRENT NUM PAD ASSIGNMENTS ===
|
||||
[PF1] to [PF4] are mapped to NUM LOCK, SLASH etc. (=> 4 keys on top on num pad).
|
||||
Num pad '+' gives ',' on the DEC.
|
||||
Num pad '+' gives ',' on the DEC.
|
||||
',' translates to '.' (=> more or less the layout of model 'LK-201-AG')
|
||||
|
||||
|
||||
Switch between 'full' and 'partial keyboard emulation' with Scroll Lock.
|
||||
*/
|
||||
|
||||
@ -276,7 +276,7 @@ INPUT_PORTS_START( lk201 )
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Compose") PORT_CODE(KEYCODE_LALT)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL)
|
||||
|
||||
PORT_START("KBD2")
|
||||
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z)
|
||||
@ -303,7 +303,7 @@ INPUT_PORTS_START( lk201 )
|
||||
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D)
|
||||
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E)
|
||||
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("3") PORT_CODE(KEYCODE_3)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Setup (F3)") PORT_CODE(KEYCODE_F3)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Setup (F3)") PORT_CODE(KEYCODE_PAUSE) // SET UP = Pause on PC
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Print Screen (F2)") PORT_CODE(KEYCODE_F2)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
@ -363,20 +363,20 @@ INPUT_PORTS_START( lk201 )
|
||||
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L)
|
||||
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O)
|
||||
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("9") PORT_CODE(KEYCODE_9)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF (F13)") PORT_CODE(KEYCODE_PRTSCR)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF (F13)") PORT_CODE(KEYCODE_F13)
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BS (F12)") PORT_CODE(KEYCODE_F12)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
|
||||
PORT_START("KBD11")
|
||||
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH)
|
||||
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(";") PORT_CODE(KEYCODE_COLON)
|
||||
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH)
|
||||
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(";") PORT_CODE(KEYCODE_COLON)
|
||||
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) // FIXME - duplicate "Return"
|
||||
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0)
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete <X") PORT_CODE(KEYCODE_BACKSPACE)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Additional Options (F14) [Zusaetze]") PORT_CODE(KEYCODE_PAUSE)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Additional Options (F14) [Zusaetze]") PORT_CODE(KEYCODE_PRTSCR)
|
||||
|
||||
PORT_START("KBD12")
|
||||
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\\") PORT_CODE(KEYCODE_BACKSLASH)
|
||||
@ -394,7 +394,7 @@ INPUT_PORTS_START( lk201 )
|
||||
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("'") PORT_CODE(KEYCODE_QUOTE)
|
||||
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("[") PORT_CODE(KEYCODE_OPENBRACE)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Previous [^]") PORT_CODE(KEYCODE_END)
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Do (F16) [Ausfuehren]") PORT_CODE(KEYCODE_RCONTROL)
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Do (F16) [Ausfuehren]") PORT_CODE(KEYCODE_RCONTROL)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Insert Here") PORT_CODE(KEYCODE_HOME)
|
||||
|
||||
@ -433,7 +433,7 @@ INPUT_PORTS_START( lk201 )
|
||||
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num ,") PORT_CODE(KEYCODE_PLUS_PAD)
|
||||
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) // PORT_NAME("Num -") = duplicate...see KBD13
|
||||
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF4") PORT_CODE(KEYCODE_MINUS_PAD)
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F20")
|
||||
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F20")
|
||||
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F19")
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
@ -623,7 +623,6 @@ void lk201_device::send_port(address_space &space, UINT8 offset, UINT8 data)
|
||||
if (ports[1] & 0x80) kbd_data = m_kbd15->read();
|
||||
if (ports[2] & 0x1) kbd_data = m_kbd16->read();
|
||||
if (ports[2] & 0x2) kbd_data = m_kbd17->read();
|
||||
#endif
|
||||
}
|
||||
// Check for LED update strobe
|
||||
if (((data & 0x80) == 0) && (ports[offset] & 0x80))
|
||||
@ -634,6 +633,8 @@ void lk201_device::send_port(address_space &space, UINT8 offset, UINT8 data)
|
||||
output_set_value("led_hold" , (led_data & 0x4) == 0);
|
||||
output_set_value("led_lock" , (led_data & 0x8) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -755,3 +756,4 @@ WRITE8_MEMBER( lk201_device::spi_w )
|
||||
|
||||
// printf("SPI %02x to %x (PC=%x)\n", data, offset, m_maincpu->pc());
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
01/05/2009 Initial implementation [Miodrag Milanovic]
|
||||
Portions (2013, 2014) by Karl-Ludwig Deisenhofer.
|
||||
Enhancements (2013 - 2015) by Karl-Ludwig Deisenhofer.
|
||||
|
||||
DEC VIDEO : STATE AS OF JULY 2014
|
||||
---------------------------------
|
||||
@ -21,27 +21,27 @@ FIXME: work out the differences and identify common code between VT and Rainbow.
|
||||
- REQUIRED TODOS / TESTS :
|
||||
* do line and character attributes (plus combinations) match real hardware?
|
||||
* how does the AVO fit in?
|
||||
|
||||
|
||||
- SCROLLING REGIONS / SPLIT SCREEN SCROLLING UNTESTED (if you open > 1 file with the VAX editor EDT)
|
||||
See VT100 Technical Manual: 4.7.4 Address Shuffling to 4.7.9 Split Screen Smooth Scrolling.
|
||||
More on scrolling regions: Rainbow 100 B technical documentation (QV069-GZ) April 1985 page 22
|
||||
|
||||
|
||||
- NEW - INTERLACED MODE (Rainbow only):
|
||||
Vertical resolution increases from 240 to 480, while the refresh rate halves (flickers on CRTs).
|
||||
To accomplish this, the display controller repeats even lines in odd scans.
|
||||
VTVIDEO activates line doubling in 24 line, interlaced mode only.
|
||||
|
||||
|
||||
Although the DC12 has the ability to display 48 lines, most units are low on screen RAM and
|
||||
won't even show 80 x 48. -> REASON: (83 x 48 = 3984 Byte) > (screen RAM) minus 'scratch area'
|
||||
won't even show 80 x 48. -> REASON: (83 x 48 = 3984 Byte) > (screen RAM) minus 'scratch area'
|
||||
On a VT-180, BIOS scratch requires up to 700 bytes used for SETUP, flags, SILO, keyboard.
|
||||
|
||||
|
||||
- POSSIBLE IMPROVEMENTS:
|
||||
|
||||
* exact colors for different VR201 monitors ('paper white', green and amber)
|
||||
|
||||
* exact colors for different VR201 monitors (for white, green and amber)
|
||||
|
||||
* ACCURATE VIDEO DELAYS:
|
||||
Position of the first visible scanline (relative to the vertical reset) depends on
|
||||
content of fill bytes at the beginning of screen RAM.
|
||||
Position of the first visible scanline (relative to the vertical reset) depends on
|
||||
content of fill bytes at the beginning of screen RAM.
|
||||
|
||||
Six invisible, linked lines are initially provided (at location $EE000+ on a Rainbow).
|
||||
Real-world DC hardware parses the (circular) chain until interrupted by blanking.
|
||||
@ -65,7 +65,7 @@ FIXME: work out the differences and identify common code between VT and Rainbow.
|
||||
PARAMETERS
|
||||
***************************************************************************/
|
||||
|
||||
#define VERBOSE 0
|
||||
#define VERBOSE 1
|
||||
|
||||
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
||||
|
||||
@ -185,10 +185,10 @@ void rainbow_video_device::device_reset()
|
||||
m_basic_attribute = 0;
|
||||
|
||||
m_columns = 80;
|
||||
|
||||
m_frequency = 60;
|
||||
|
||||
m_frequency = 60;
|
||||
|
||||
m_interlaced = 1;
|
||||
m_interlaced = 1;
|
||||
m_fill_lines = 2; // for 60Hz (not in use any longer -> detected)
|
||||
recompute_parameters();
|
||||
}
|
||||
@ -210,8 +210,8 @@ void vt100_video_device::recompute_parameters()
|
||||
|
||||
int vert_pix_total = ((m_linedoubler == false) ? m_height : m_height_MAX) * 10;
|
||||
|
||||
if (m_columns == 132)
|
||||
horiz_pix_total = m_columns * 9; // display 1 less filler pixel in 132 char. mode
|
||||
if (m_columns == 132)
|
||||
horiz_pix_total = m_columns * 9; // display 1 less filler pixel in 132 char. mode
|
||||
else
|
||||
horiz_pix_total = m_columns * 10; // normal 80 character mode.
|
||||
|
||||
@ -239,30 +239,57 @@ READ8_MEMBER(vt100_video_device::lba7_r)
|
||||
// Also used by Rainbow-100 ************
|
||||
WRITE8_MEMBER(vt100_video_device::dc012_w)
|
||||
{
|
||||
// TODO: writes to 10C/0C should be treated differently (emulation disables the watchdog too often).
|
||||
// Writes to [10C] and [0C] are treated differently
|
||||
// - see 3.1.3.9.5 DC012 Programming Information (PC-100 spec)
|
||||
if (data == 0) // MHFU is disabled by writing 00 to port 010C.
|
||||
{
|
||||
MHFU_FLAG = false;
|
||||
MHFU_counter = 0;
|
||||
|
||||
if (VERBOSE)
|
||||
{
|
||||
if (MHFU_FLAG == true)
|
||||
printf("MHFU *** DISABLED *** %ul \n", offset);
|
||||
}
|
||||
}
|
||||
// MHFU is disabled by writing 00 to port 010C.
|
||||
|
||||
// Code recognition is abysmal - sorry for that.
|
||||
if (data == 0)
|
||||
{
|
||||
UINT8 *rom = machine().root_device().memregion("maincpu")->base();
|
||||
if (rom != NULL)
|
||||
{
|
||||
UINT32 PC = space.device().safe_pc();
|
||||
if ((rom[ PC - 1] == 0xe6) &&
|
||||
(rom[ PC ] == 0x0c)
|
||||
)
|
||||
{
|
||||
// OUT 0C,al < DO NOTHING >
|
||||
}
|
||||
else
|
||||
{
|
||||
//UINT8 magic1= rom[PC - 1];
|
||||
//printf("\n PC %05x - MHFU MAGIC -1 %02x\n", PC, magic1);
|
||||
//UINT8 magic2 = rom[PC - 2];
|
||||
//printf("\n PC %05x - MHFU MAGIC -2 %02x\n", PC, magic2);
|
||||
//if (VERBOSE)
|
||||
|
||||
//if(1 )
|
||||
if ((rom[PC - 2] == 0x0C) &&
|
||||
(rom[PC - 1] == 0x01)
|
||||
)
|
||||
{
|
||||
if (MHFU_FLAG == true)
|
||||
printf("MHFU *** DISABLED *** %05x \n", PC);
|
||||
|
||||
MHFU_FLAG = false;
|
||||
MHFU_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // DATA == 0 ONLY ....
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// RESET
|
||||
MHFU_FLAG = true;
|
||||
MHFU_counter = 0;
|
||||
//if (VERBOSE)
|
||||
if (MHFU_FLAG == false)
|
||||
printf("MHFU ___ENABLED___ %05x \n", space.device().safe_pc());
|
||||
|
||||
if (VERBOSE)
|
||||
{
|
||||
if (MHFU_FLAG == false)
|
||||
printf("MHFU ___ENABLED___ %ul \n", offset);
|
||||
}
|
||||
// RESET
|
||||
MHFU_FLAG = true;
|
||||
MHFU_counter = 0;
|
||||
}
|
||||
|
||||
if (!(data & 0x08))
|
||||
@ -284,57 +311,57 @@ WRITE8_MEMBER(vt100_video_device::dc012_w)
|
||||
{
|
||||
switch (data & 0x0f)
|
||||
{
|
||||
case 0x08:
|
||||
// toggle blink flip flop
|
||||
m_blink_flip_flop = !(m_blink_flip_flop) ? 1 : 0;
|
||||
break;
|
||||
case 0x09:
|
||||
// clear vertical frequency interrupt;
|
||||
m_write_clear_video_interrupt(0);
|
||||
break;
|
||||
case 0x0a:
|
||||
// set reverse field on
|
||||
m_reverse_field = 1;
|
||||
break;
|
||||
case 0x0b:
|
||||
// set reverse field off
|
||||
m_reverse_field = 0;
|
||||
break;
|
||||
case 0x08:
|
||||
// toggle blink flip flop
|
||||
m_blink_flip_flop = !(m_blink_flip_flop) ? 1 : 0;
|
||||
break;
|
||||
case 0x09:
|
||||
// clear vertical frequency interrupt;
|
||||
m_write_clear_video_interrupt(0);
|
||||
break;
|
||||
case 0x0a:
|
||||
// set reverse field on
|
||||
m_reverse_field = 1;
|
||||
break;
|
||||
case 0x0b:
|
||||
// set reverse field off
|
||||
m_reverse_field = 0;
|
||||
break;
|
||||
|
||||
// Writing a 11XX bit combination clears the blink-flip flop (valid for 0x0C - 0x0F):
|
||||
case 0x0c:
|
||||
// set basic attribute to underline / blink flip-flop off
|
||||
m_blink_flip_flop = 0;
|
||||
m_basic_attribute = 0; // (VT-100 without AVO): reverse video is interpreted as underline (basic_attribute 0)
|
||||
break;
|
||||
case 0x0c:
|
||||
// set basic attribute to underline / blink flip-flop off
|
||||
m_blink_flip_flop = 0;
|
||||
m_basic_attribute = 0; // (VT-100 without AVO): reverse video is interpreted as underline (basic_attribute 0)
|
||||
break;
|
||||
|
||||
case 0x0d:
|
||||
// (DEC Rainbow 100 DEFAULT) : reverse video with 24 lines / blink flip-flop off
|
||||
m_blink_flip_flop = 0;
|
||||
m_basic_attribute = 1; // (VT-100 without AVO): reverse video is interpreted as reverse (basic_attribute 1)
|
||||
case 0x0d:
|
||||
// (DEC Rainbow 100 DEFAULT) : reverse video with 24 lines / blink flip-flop off
|
||||
m_blink_flip_flop = 0;
|
||||
m_basic_attribute = 1; // (VT-100 without AVO): reverse video is interpreted as reverse (basic_attribute 1)
|
||||
|
||||
if (m_height_MAX == 25) break; // Abort on VT-100 for now.
|
||||
if (m_height_MAX == 25) break; // Abort on VT-100 for now.
|
||||
|
||||
m_height = 24; // (DEC Rainbow 100) : 24 line display
|
||||
recompute_parameters();
|
||||
break;
|
||||
m_height = 24; // (DEC Rainbow 100) : 24 line display
|
||||
recompute_parameters();
|
||||
break;
|
||||
|
||||
case 0x0e:
|
||||
case 0x0e:
|
||||
m_blink_flip_flop = 0; // 'unsupported' DC012 command. Turns blink flip-flop off (11XX).
|
||||
break;
|
||||
break;
|
||||
|
||||
case 0x0f:
|
||||
// (DEC Rainbow 100): reverse video with 48 lines / blink flip-flop off
|
||||
m_blink_flip_flop = 0;
|
||||
m_basic_attribute = 1;
|
||||
case 0x0f:
|
||||
// (DEC Rainbow 100): reverse video with 48 lines / blink flip-flop off
|
||||
m_blink_flip_flop = 0;
|
||||
m_basic_attribute = 1;
|
||||
|
||||
// 0x0f = 'reserved' on VT 100
|
||||
// Abort on VT-100 for now.
|
||||
if (m_height_MAX == 25) break;
|
||||
// 0x0f = 'reserved' on VT 100
|
||||
// Abort on VT-100 for now.
|
||||
if (m_height_MAX == 25) break;
|
||||
|
||||
m_height = 48; // (DEC Rainbow 100) : 48 line display
|
||||
recompute_parameters();
|
||||
break;
|
||||
m_height = 48; // (DEC Rainbow 100) : 48 line display
|
||||
recompute_parameters();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -342,15 +369,15 @@ WRITE8_MEMBER(vt100_video_device::dc012_w)
|
||||
// Writing to DC011 resets internal counters (& disturbs display) on real hardware.
|
||||
WRITE8_MEMBER(vt100_video_device::dc011_w)
|
||||
{
|
||||
if (!BIT(data, 5))
|
||||
if (!BIT(data, 5))
|
||||
{
|
||||
m_interlaced = 1;
|
||||
m_interlaced = 1;
|
||||
|
||||
if (!BIT(data, 4))
|
||||
m_columns = 80;
|
||||
else
|
||||
m_columns = 132;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_interlaced = 0;
|
||||
@ -358,16 +385,16 @@ WRITE8_MEMBER(vt100_video_device::dc011_w)
|
||||
if (!BIT(data, 4))
|
||||
{
|
||||
m_frequency = 60;
|
||||
m_fill_lines = 2;
|
||||
m_fill_lines = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frequency = 50;
|
||||
m_fill_lines = 5;
|
||||
m_fill_lines = 5;
|
||||
}
|
||||
}
|
||||
|
||||
recompute_parameters();
|
||||
recompute_parameters();
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(vt100_video_device::brightness_w)
|
||||
@ -388,12 +415,12 @@ void vt100_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x, i
|
||||
switch (display_type)
|
||||
{
|
||||
case 0: // bottom half, double height
|
||||
j = (i >> 1) + 5; break;
|
||||
j = (i >> 1) + 5; break;
|
||||
case 1: // top half, double height
|
||||
j = (i >> 1); break;
|
||||
j = (i >> 1); break;
|
||||
case 2: // double width
|
||||
case 3: // normal
|
||||
j = i; break;
|
||||
j = i; break;
|
||||
default: j = 0; break;
|
||||
}
|
||||
// modify line since that is how it is stored in rom
|
||||
@ -415,27 +442,27 @@ void vt100_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x, i
|
||||
bit = BIT((line << b), 7);
|
||||
if (double_width)
|
||||
{
|
||||
bitmap.pix16(y * 10 + i, x * 20 + b * 2) = (bit | prevbit) ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + b * 2 + 1) = bit ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + b * 2) = (bit | prevbit) ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + b * 2 + 1) = bit ^ invert;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap.pix16(y * 10 + i, x * 10 + b) = (bit | prevbit) ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 10 + b) = (bit | prevbit) ^ invert;
|
||||
}
|
||||
}
|
||||
prevbit = bit;
|
||||
// char interleave is filled with last bit
|
||||
if (double_width)
|
||||
{
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 16) = (bit | prevbit) ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 17) = bit ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 18) = bit ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 19) = bit ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 16) = (bit | prevbit) ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 17) = bit ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 18) = bit ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 20 + 19) = bit ^ invert;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap.pix16(y * 10 + i, x * 10 + 8) = (bit | prevbit) ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 10 + 9) = bit ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 10 + 8) = (bit | prevbit) ^ invert;
|
||||
bitmap.pix16(y * 10 + i, x * 10 + 9) = bit ^ invert;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -474,7 +501,7 @@ void vt100_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &cli
|
||||
// if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO)
|
||||
if (addr & 0x1000) addr &= 0xfff; else addr |= 0x2000;
|
||||
scroll_region = (temp >> 15) & 1;
|
||||
display_type = (temp >> 13) & 3;
|
||||
display_type = (temp >> 13) & 3;
|
||||
if (line >= m_fill_lines)
|
||||
{
|
||||
ypos++;
|
||||
@ -533,7 +560,7 @@ void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x,
|
||||
|
||||
UINT16 y_preset;
|
||||
|
||||
UINT16 CHARPOS_y_preset = y << 3; // CHARPOS_y_preset = y * 10;
|
||||
UINT16 CHARPOS_y_preset = y << 3; // CHARPOS_y_preset = y * 10;
|
||||
CHARPOS_y_preset += y;
|
||||
CHARPOS_y_preset += y;
|
||||
|
||||
@ -545,10 +572,10 @@ void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x,
|
||||
int back_intensity, back_default_intensity;
|
||||
|
||||
int invert = (display_type & 8) ? 1 : 0; // REVERSE
|
||||
int bold = (display_type & 16) ? 0 : 1; // BIT 4
|
||||
int bold = (display_type & 16) ? 0 : 1; // BIT 4
|
||||
int blink = (display_type & 32) ? 0 : 1; // BIT 5
|
||||
int underline = (display_type & 64) ? 0 : 1; // BIT 6
|
||||
bool blank = (display_type & 128) ? true : false; // BIT 7
|
||||
int underline = (display_type & 64) ? 0 : 1; // BIT 6
|
||||
bool blank = (display_type & 128) ? true : false; // BIT 7
|
||||
|
||||
display_type = display_type & 3;
|
||||
|
||||
@ -580,8 +607,8 @@ void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x,
|
||||
// BG: DEFAULT for entire character (underline overrides this for 1 line) -
|
||||
back_default_intensity = back_intensity;
|
||||
|
||||
bool double_width = (display_type != 3) ? true : false; // all except normal: double width
|
||||
bool double_height = (display_type & 1) ? false : true; // 0,2 = double height
|
||||
bool double_width = (display_type != 3) ? true : false; // all except normal: double width
|
||||
bool double_height = (display_type & 1) ? false : true; // 0,2 = double height
|
||||
|
||||
int smooth_offset = 0;
|
||||
if (scroll_region != 0)
|
||||
@ -610,24 +637,24 @@ void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x,
|
||||
else
|
||||
{
|
||||
y_preset = (m_linedoubler ? 480 : 240) - extra_scan_line;
|
||||
i = 0; // (should be always empty)
|
||||
i = 0; // blank line. Might not work with TCS or other charsets (FIXME)
|
||||
}
|
||||
}
|
||||
|
||||
switch (display_type)
|
||||
{
|
||||
case 0: // bottom half of 'double height, double width' char.
|
||||
j = (i >> 1) + 5;
|
||||
break;
|
||||
j = (i >> 1) + 5;
|
||||
break;
|
||||
|
||||
case 2: // top half of 'double height, double width' char.
|
||||
j = (i >> 1);
|
||||
break;
|
||||
j = (i >> 1);
|
||||
break;
|
||||
|
||||
default: // 1: double width
|
||||
// 3: normal
|
||||
j = i;
|
||||
break;
|
||||
// 3: normal
|
||||
j = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// modify line since that is how it is stored in rom
|
||||
@ -641,13 +668,13 @@ void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x,
|
||||
{
|
||||
if (i == 8)
|
||||
{
|
||||
if (invert == 0)
|
||||
line = 0xff; // CASE 5 A)
|
||||
else
|
||||
if (invert == 0)
|
||||
line = 0xff; // CASE 5 A)
|
||||
else
|
||||
{
|
||||
line = 0x00; // CASE 5 B)
|
||||
back_intensity = 0; // OVERRIDE: BLACK BACKGROUND
|
||||
}
|
||||
back_intensity = 0; // OVERRIDE: BLACK BACKGROUND
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -659,12 +686,12 @@ void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x,
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = BIT((line << b), 7);
|
||||
bit = BIT((line << b), 7);
|
||||
|
||||
if (bit > 0)
|
||||
bit = fg_intensity;
|
||||
else
|
||||
bit = back_intensity;
|
||||
if (bit > 0)
|
||||
bit = fg_intensity;
|
||||
else
|
||||
bit = back_intensity;
|
||||
}
|
||||
|
||||
// Double, 'double_height + double_width', then normal.
|
||||
@ -729,7 +756,7 @@ void rainbow_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &c
|
||||
// Skip fill (0xFF) lines and put result in ADDR.
|
||||
for (int xp = 1; xp <= 6; xp += 1) // beware of circular references
|
||||
{
|
||||
// Fetch LINE ATTRIBUTE before it is gone
|
||||
// Fetch LINE ATTRIBUTE before it is gone
|
||||
attr_addr = 0x1000 | ((addr + 1) & 0x0fff);
|
||||
|
||||
temp = m_read_ram(addr + 2) * 256 + m_read_ram(addr + 1);
|
||||
@ -749,9 +776,9 @@ void rainbow_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &c
|
||||
code = m_read_ram(addr + xpos);
|
||||
|
||||
if (code == 0x00) // TODO: investigate side effect on regular zero character!
|
||||
display_type |= 0x80; // DEFAULT: filler chars (till end of line) and empty lines (00) will be blanked
|
||||
display_type |= 0x80; // DEFAULT: filler chars (till end of line) and empty lines (00) will be blanked
|
||||
else
|
||||
display_type &= 0x7f; // else activate display.
|
||||
display_type &= 0x7f; // else activate display.
|
||||
|
||||
if (code == 0xff) // end of line, fill empty till end of line
|
||||
{
|
||||
@ -759,7 +786,7 @@ void rainbow_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &c
|
||||
for (x = xpos; x < ((display_type != 3) ? (m_columns / 2) : m_columns); x++)
|
||||
{
|
||||
display_char(bitmap, code, x, ypos, scroll_region, display_type | 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
// LINE ATTRIBUTE - valid for all chars on next line ** DO NOT SHUFFLE **
|
||||
attr_addr = 0x1000 | ((addr + xpos + 1) & 0x0fff);
|
||||
@ -770,7 +797,7 @@ void rainbow_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &c
|
||||
|
||||
temp = m_read_ram(attr_addr);
|
||||
scroll_region = (temp)& 1;
|
||||
display_type = (temp >> 1) & 3;
|
||||
display_type = (temp >> 1) & 3;
|
||||
|
||||
ypos++; // Y + 1 in non-interlaced mode
|
||||
if (m_linedoubler)
|
||||
@ -821,24 +848,24 @@ void rainbow_video_device::palette_select(int choice)
|
||||
{
|
||||
switch (choice)
|
||||
{
|
||||
default:
|
||||
case 0x01:
|
||||
default:
|
||||
case 0x01:
|
||||
m_palette->set_pen_color(1, 0xff - 100, 0xff - 100, 0xff - 100); // WHITE (dim)
|
||||
m_palette->set_pen_color(2, 0xff - 50, 0xff - 50, 0xff - 50); // WHITE NORMAL
|
||||
m_palette->set_pen_color(3, 0xff, 0xff, 0xff); // WHITE (brighter)
|
||||
break;
|
||||
m_palette->set_pen_color(3, 0xff, 0xff, 0xff); // WHITE (brighter)
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
case 0x02:
|
||||
m_palette->set_pen_color(1, 35, 200 - 55, 75); // GREEN (dim)
|
||||
m_palette->set_pen_color(2, 35 + 55, 200, 75 + 55); // GREEN (NORMAL)
|
||||
m_palette->set_pen_color(3, 35 + 110, 200 + 55, 75 + 110); // GREEN (brighter)
|
||||
break;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
m_palette->set_pen_color(1, 213 - 47, 146 - 47, 82 - 47); // AMBER (dim)
|
||||
case 0x03:
|
||||
m_palette->set_pen_color(1, 213 - 47, 146 - 47, 82 - 47); // AMBER (dim)
|
||||
m_palette->set_pen_color(2, 213, 146, 82); // AMBER (NORMAL)
|
||||
m_palette->set_pen_color(3, 255, 193, 129); // AMBER (brighter)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -856,31 +883,43 @@ int rainbow_video_device::MHFU(int ASK)
|
||||
{
|
||||
switch (ASK)
|
||||
{
|
||||
case 1: // "true": RETURN BOOLEAN (MHFU disabled or enabled?)
|
||||
return MHFU_FLAG;
|
||||
case 1: // "true": RETURN BOOLEAN (MHFU disabled or enabled?)
|
||||
return MHFU_FLAG;
|
||||
|
||||
case -1: // -1: increment, return counter value (=> Rainbow.c)
|
||||
if (MHFU_FLAG == true)
|
||||
MHFU_counter++;
|
||||
return MHFU_counter;
|
||||
case -1: // -1: increment IF ENABLED, return counter value (=> Rainbow.c)
|
||||
if (MHFU_FLAG == true)
|
||||
MHFU_counter++;
|
||||
return MHFU_counter;
|
||||
|
||||
case -100: // -100 : RESET and ENABLE MHFU counter
|
||||
if (VERBOSE)
|
||||
case -100: // -100 : RESET and ENABLE MHFU counter
|
||||
MHFU_counter = 0;
|
||||
if(1) //if (VERBOSE)
|
||||
printf("-100 MHFU * reset and ENABLE * \n");
|
||||
MHFU_counter = 0;
|
||||
|
||||
if (VERBOSE)
|
||||
if(1) // if (VERBOSE)
|
||||
{
|
||||
if (MHFU_FLAG == false)
|
||||
printf("-100 MHFU ___ENABLED___\n");
|
||||
}
|
||||
MHFU_FLAG = true;
|
||||
MHFU_FLAG = true;
|
||||
|
||||
return -100;
|
||||
return -100;
|
||||
|
||||
case -200: // -200 : RESET and DISABLE MHFU
|
||||
MHFU_counter = 0;
|
||||
|
||||
default:
|
||||
assert(1);
|
||||
return -255;
|
||||
if(1) //if (VERBOSE)
|
||||
{
|
||||
if (MHFU_FLAG == true)
|
||||
printf("MHFU *** DISABLED *** \n");
|
||||
}
|
||||
MHFU_FLAG = false;
|
||||
|
||||
return -200;
|
||||
|
||||
default:
|
||||
assert(1);
|
||||
return -255;
|
||||
} // switch
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
/**********************************************************************
|
||||
|
||||
DEC VT Terminal video emulation
|
||||
[ DC012 and DC011 emulation ]
|
||||
DEC VT Terminal video emulation
|
||||
[ DC012 and DC011 emulation ]
|
||||
|
||||
01/05/2009 Initial implementation [Miodrag Milanovic]
|
||||
01/05/2009 Initial implementation [Miodrag Milanovic]
|
||||
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
#include "emu.h"
|
||||
|
||||
class vt100_video_device : public device_t,
|
||||
public device_video_interface
|
||||
public device_video_interface
|
||||
{
|
||||
public:
|
||||
vt100_video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
|
Loading…
Reference in New Issue
Block a user