mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
accomm: Added PCF8573 RTC.
- Added RTC interrupt, fixes TIME function. - Realigned video handling with the Electron.
This commit is contained in:
parent
84264c5efb
commit
f25283c81f
@ -2430,6 +2430,18 @@ if (MACHINES["NSCSI"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/pcf8573.h,MACHINES["PCF8573"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["PCF8573"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/pcf8573.cpp",
|
||||
MAME_DIR .. "src/devices/machine/pcf8573.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/pcf8583.h,MACHINES["PCF8583"] = true
|
||||
|
@ -619,6 +619,7 @@ MACHINES["OUTPUT_LATCH"] = true
|
||||
MACHINES["PC_FDC"] = true
|
||||
MACHINES["PC_LPT"] = true
|
||||
MACHINES["PCCARD"] = true
|
||||
MACHINES["PCF8573"] = true
|
||||
MACHINES["PCF8583"] = true
|
||||
--MACHINES["PCF8584"] = true
|
||||
MACHINES["PCF8593"] = true
|
||||
|
356
src/devices/machine/pcf8573.cpp
Normal file
356
src/devices/machine/pcf8573.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Nigel Barnes
|
||||
/*********************************************************************
|
||||
|
||||
Philips PCF8573 Clock and Calendar with Power Fail Detector
|
||||
|
||||
TODO:
|
||||
- status bits 3/4 seconds/minutes are not set.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "pcf8573.h"
|
||||
|
||||
#define LOG_DATA (1 << 1)
|
||||
#define LOG_LINE (1 << 2)
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(PCF8573, pcf8573_device, "pcf8573", "PCF8573 RTC with Power Fail Detector")
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// pcf8573_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
pcf8573_device::pcf8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, PCF8573, tag, owner, clock)
|
||||
, device_rtc_interface(mconfig, *this)
|
||||
, m_comp_cb(*this)
|
||||
, m_min_cb(*this)
|
||||
, m_sec_cb(*this)
|
||||
, m_clock_timer(nullptr)
|
||||
, m_slave_address(PCF8573_SLAVE_ADDRESS)
|
||||
, m_scl(0)
|
||||
, m_sdaw(0)
|
||||
, m_sdar(1)
|
||||
, m_state(STATE_IDLE)
|
||||
, m_bits(0)
|
||||
, m_shift(0)
|
||||
, m_devsel(0)
|
||||
, m_mode_pointer(0)
|
||||
, m_address(0)
|
||||
, m_status(0)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void pcf8573_device::device_start()
|
||||
{
|
||||
m_comp_cb.resolve_safe();
|
||||
m_min_cb.resolve_safe();
|
||||
m_sec_cb.resolve_safe();
|
||||
|
||||
// allocate timers
|
||||
m_clock_timer = timer_alloc();
|
||||
m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
|
||||
|
||||
// state saving
|
||||
save_item(NAME(m_scl));
|
||||
save_item(NAME(m_sdaw));
|
||||
save_item(NAME(m_sdar));
|
||||
save_item(NAME(m_state));
|
||||
save_item(NAME(m_bits));
|
||||
save_item(NAME(m_shift));
|
||||
save_item(NAME(m_devsel));
|
||||
save_item(NAME(m_mode_pointer));
|
||||
save_item(NAME(m_address));
|
||||
save_item(NAME(m_status));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_slave_address));
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_timer - handler timer events
|
||||
//-------------------------------------------------
|
||||
|
||||
void pcf8573_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
advance_seconds();
|
||||
|
||||
// one pulse per second output
|
||||
m_sec_cb(1);
|
||||
m_sec_cb(0);
|
||||
}
|
||||
|
||||
void pcf8573_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
|
||||
{
|
||||
if (m_data[REG_MINUTES] == convert_to_bcd(minute))
|
||||
return;
|
||||
|
||||
// update registers
|
||||
set_time_minute(minute);
|
||||
set_time_hour(hour);
|
||||
set_date_day(day);
|
||||
set_date_month(month);
|
||||
|
||||
// one pulse per minute output
|
||||
m_min_cb(1);
|
||||
m_min_cb(0);
|
||||
|
||||
// comparator output
|
||||
if (m_data[REG_HOURS] == m_data[REG_ALARM_HOURS] && m_data[REG_MINUTES] == m_data[REG_ALARM_MINUTES])
|
||||
{
|
||||
if (BIT(m_status, 2) || (m_data[REG_DAYS] == m_data[REG_ALARM_DAYS] && m_data[REG_MONTHS] == m_data[REG_ALARM_MONTHS]))
|
||||
{
|
||||
// set COMP flag
|
||||
m_status |= 1 << 1;
|
||||
m_comp_cb(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// READ/WRITE HANDLERS
|
||||
//**************************************************************************
|
||||
|
||||
WRITE_LINE_MEMBER(pcf8573_device::a0_w)
|
||||
{
|
||||
state &= 1;
|
||||
if (BIT(m_slave_address, 1) != state)
|
||||
{
|
||||
LOGMASKED(LOG_LINE, "set a0 %d\n", state );
|
||||
m_slave_address = (m_slave_address & 0xfd) | (state << 1);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(pcf8573_device::a1_w)
|
||||
{
|
||||
state &= 1;
|
||||
if (BIT(m_slave_address, 2) != state)
|
||||
{
|
||||
LOGMASKED(LOG_LINE, "set a1 %d\n", state );
|
||||
m_slave_address = (m_slave_address & 0xfb) | (state << 2);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(pcf8573_device::scl_w)
|
||||
{
|
||||
if (m_scl != state)
|
||||
{
|
||||
m_scl = state;
|
||||
LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_scl);
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_ADDRESS:
|
||||
case STATE_MODE:
|
||||
case STATE_DATAIN:
|
||||
if (m_bits < 8)
|
||||
{
|
||||
if (m_scl)
|
||||
{
|
||||
m_shift = ((m_shift << 1) | m_sdaw) & 0xff;
|
||||
m_bits++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_scl)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_ADDRESS:
|
||||
m_devsel = m_shift;
|
||||
|
||||
if ((m_devsel & 0xfe) != m_slave_address)
|
||||
{
|
||||
LOGMASKED(LOG_DATA, "address %02x: not this device\n", m_devsel);
|
||||
m_state = STATE_IDLE;
|
||||
}
|
||||
else if ((m_devsel & 1) == 0)
|
||||
{
|
||||
LOGMASKED(LOG_DATA, "address %02x: write\n", m_devsel);
|
||||
m_state = STATE_MODE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_DATA, "address %02x: read\n", m_devsel);
|
||||
m_state = STATE_DATAOUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_MODE:
|
||||
m_mode_pointer = m_shift;
|
||||
|
||||
LOGMASKED(LOG_DATA, "mode pointer %02x\n", m_shift);
|
||||
|
||||
switch (m_mode_pointer & 0x70)
|
||||
{
|
||||
case 0x00: // execute address
|
||||
m_address = m_mode_pointer & 0x07;
|
||||
break;
|
||||
case 0x10: // read control/status flags
|
||||
break;
|
||||
case 0x20: // reset prescaler
|
||||
set_clock_register(RTC_SECOND, 0);
|
||||
adjust_seconds();
|
||||
break;
|
||||
case 0x30: // time adjust
|
||||
adjust_seconds();
|
||||
break;
|
||||
case 0x40: // reset NODA flag
|
||||
m_status &= ~(1 << 2);
|
||||
break;
|
||||
case 0x50: // set NODA flag
|
||||
m_status |= 1 << 2;
|
||||
break;
|
||||
case 0x60: // reset COMP flag
|
||||
m_status &= ~(1 << 1);
|
||||
m_comp_cb(0);
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = STATE_DATAIN;
|
||||
break;
|
||||
|
||||
case STATE_DATAIN:
|
||||
switch (m_mode_pointer & 0x70)
|
||||
{
|
||||
case 0x00: // execute address
|
||||
m_data[m_address] = m_shift;
|
||||
|
||||
LOGMASKED(LOG_DATA, "data[ %02x ] <- %02x\n", m_address, m_shift);
|
||||
|
||||
switch (m_address)
|
||||
{
|
||||
case REG_HOURS: set_clock_register(RTC_HOUR, bcd_to_integer(m_data[REG_HOURS])); break;
|
||||
case REG_MINUTES: set_clock_register(RTC_MINUTE, bcd_to_integer(m_data[REG_MINUTES])); break;
|
||||
case REG_DAYS: set_clock_register(RTC_DAY, bcd_to_integer(m_data[REG_DAYS])); break;
|
||||
case REG_MONTHS: set_clock_register(RTC_MONTH, bcd_to_integer(m_data[REG_MONTHS])); break;
|
||||
}
|
||||
|
||||
m_address = (m_address & 0x04) | ((m_address + 1) & 0x03);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_bits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bits == 8)
|
||||
{
|
||||
m_sdar = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bits = 0;
|
||||
m_sdar = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_DATAOUT:
|
||||
if (m_bits < 8)
|
||||
{
|
||||
if (m_scl)
|
||||
{
|
||||
if (m_bits == 0)
|
||||
{
|
||||
switch (m_mode_pointer & 0x70)
|
||||
{
|
||||
case 0x00: // execute address
|
||||
m_shift = m_data[m_address];
|
||||
LOGMASKED(LOG_DATA, "data[ %02x ] -> %02x\n", m_address, m_shift);
|
||||
m_address = (m_address & 0x04) | ((m_address + 1) & 0x03);
|
||||
break;
|
||||
|
||||
case 0x10: // read control/status flags
|
||||
m_shift = m_status;
|
||||
LOGMASKED(LOG_DATA, "status -> %02x\n", m_address, m_shift);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_sdar = (m_shift >> 7) & 1;
|
||||
|
||||
m_shift = (m_shift << 1) & 0xff;
|
||||
m_bits++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_scl)
|
||||
{
|
||||
if (m_sdaw)
|
||||
{
|
||||
LOGMASKED(LOG_DATA, "nack\n");
|
||||
m_state = STATE_IDLE;
|
||||
}
|
||||
|
||||
m_bits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bits == 8)
|
||||
{
|
||||
m_sdar = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bits = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(pcf8573_device::sda_w)
|
||||
{
|
||||
state &= 1;
|
||||
if (m_sdaw != state)
|
||||
{
|
||||
LOGMASKED(LOG_LINE, "set sda %d\n", state);
|
||||
m_sdaw = state;
|
||||
|
||||
if (m_scl)
|
||||
{
|
||||
if (m_sdaw)
|
||||
{
|
||||
LOGMASKED(LOG_DATA, "stop\n");
|
||||
m_state = STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_DATA, "start\n");
|
||||
m_state = STATE_ADDRESS;
|
||||
m_bits = 0;
|
||||
}
|
||||
|
||||
m_sdar = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
READ_LINE_MEMBER(pcf8573_device::sda_r)
|
||||
{
|
||||
int res = m_sdar & 1;
|
||||
|
||||
LOGMASKED(LOG_LINE, "read sda %d\n", res);
|
||||
|
||||
return res;
|
||||
}
|
131
src/devices/machine/pcf8573.h
Normal file
131
src/devices/machine/pcf8573.h
Normal file
@ -0,0 +1,131 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Nigel Barnes
|
||||
/*********************************************************************
|
||||
|
||||
Philips PCF8573 Clock and Calendar with Power Fail Detector
|
||||
|
||||
**********************************************************************
|
||||
|
||||
The PCF8573 comes in two package configurations:
|
||||
|
||||
PCF8573P - 16-pin dual-inline package (DIP16)
|
||||
PCF8573T - 16-pin small-outline package (SO16)
|
||||
|
||||
**********************************************************************
|
||||
|
||||
Pinning: ____ ____
|
||||
| \/ |
|
||||
A0 1 | | 16 Vdd
|
||||
A1 2 | | 15 Vss1
|
||||
COMP 3 | | 14 OSC0
|
||||
SDA 4 | PCF8573P | 13 OSC1
|
||||
SDL 5 | PCF8573T | 12 TEST
|
||||
EXTPF 6 | | 11 FSET
|
||||
PFIN 7 | | 10 SEC
|
||||
Vss2 8 | | 9 MIN
|
||||
|__________|
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_PCF8573_H
|
||||
#define MAME_MACHINE_PCF8573_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dirtc.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
#define PCF8573_SLAVE_ADDRESS ( 0xd0 )
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> pcf8573_device
|
||||
|
||||
class pcf8573_device :
|
||||
public device_t,
|
||||
public device_rtc_interface
|
||||
{
|
||||
public:
|
||||
pcf8573_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto comp_cb() { return m_comp_cb.bind(); }
|
||||
auto min_cb() { return m_min_cb.bind(); }
|
||||
auto sec_cb() { return m_sec_cb.bind(); }
|
||||
|
||||
void set_a0(int a0) { m_slave_address = (m_slave_address & 0xfd) | (a0 << 1); }
|
||||
void set_a1(int a1) { m_slave_address = (m_slave_address & 0xfb) | (a1 << 2); }
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(a0_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(a1_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(scl_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(sda_w);
|
||||
DECLARE_READ_LINE_MEMBER(sda_r);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
// device_rtc_interface overrides
|
||||
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
REG_HOURS = 0x00,
|
||||
REG_MINUTES = 0x01,
|
||||
REG_DAYS = 0x02,
|
||||
REG_MONTHS = 0x03,
|
||||
REG_ALARM_HOURS = 0x04,
|
||||
REG_ALARM_MINUTES = 0x05,
|
||||
REG_ALARM_DAYS = 0x06,
|
||||
REG_ALARM_MONTHS = 0x07
|
||||
};
|
||||
|
||||
// get/set time
|
||||
uint8_t get_time_minute() { return bcd_to_integer(m_data[REG_MINUTES]); }
|
||||
void set_time_minute(uint8_t minute){ m_data[REG_MINUTES] = convert_to_bcd(minute); }
|
||||
uint8_t get_time_hour() { return bcd_to_integer(m_data[REG_HOURS]); }
|
||||
void set_time_hour(uint8_t hour) { m_data[REG_HOURS] = convert_to_bcd(hour); }
|
||||
|
||||
// get/set date
|
||||
uint8_t get_date_day() { return bcd_to_integer(m_data[REG_DAYS]); }
|
||||
void set_date_day(uint8_t day) { m_data[REG_DAYS] = convert_to_bcd(day); }
|
||||
uint8_t get_date_month() { return bcd_to_integer(m_data[REG_MONTHS]); }
|
||||
void set_date_month(uint8_t month) { m_data[REG_MONTHS] = convert_to_bcd(month); }
|
||||
|
||||
devcb_write_line m_comp_cb;
|
||||
devcb_write_line m_min_cb;
|
||||
devcb_write_line m_sec_cb;
|
||||
|
||||
// timers
|
||||
emu_timer *m_clock_timer;
|
||||
|
||||
// internal state
|
||||
uint8_t m_data[8];
|
||||
int m_slave_address;
|
||||
int m_scl;
|
||||
int m_sdaw;
|
||||
int m_sdar;
|
||||
int m_state;
|
||||
int m_bits;
|
||||
int m_shift;
|
||||
int m_devsel;
|
||||
int m_mode_pointer;
|
||||
int m_address;
|
||||
int m_status;
|
||||
|
||||
enum { STATE_IDLE, STATE_ADDRESS, STATE_MODE, STATE_DATAIN, STATE_DATAOUT };
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(PCF8573, pcf8573_device)
|
||||
|
||||
#endif // MAME_MACHINE_PCF8573_H
|
@ -8,7 +8,7 @@
|
||||
Electron ULA emulation by Wilbert Pol
|
||||
|
||||
Main CPU: 65C816
|
||||
Other chips: 6850 UART, 6522 VIA, SAA5240(video?), AM7910 modem, PCF0335(?), PCF8573P
|
||||
Other chips: 6850 UART, 6522 VIA, SAA5240(teletext), AM7910(modem), PCF0335(dialler?), PCF8573P(RTC)
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
@ -17,9 +17,11 @@
|
||||
#include "machine/6522via.h"
|
||||
#include "machine/6850acia.h"
|
||||
#include "machine/clock.h"
|
||||
#include "machine/input_merger.h"
|
||||
#include "machine/mc6854.h"
|
||||
#include "machine/ram.h"
|
||||
#include "machine/nvram.h"
|
||||
#include "machine/pcf8573.h"
|
||||
#include "machine/bankdev.h"
|
||||
#include "sound/beep.h"
|
||||
#include "bus/econet/econet.h"
|
||||
@ -47,8 +49,11 @@ public:
|
||||
driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_maincpu_region(*this, "maincpu"),
|
||||
m_irqs(*this, "irqs"),
|
||||
m_screen(*this, "screen"),
|
||||
m_beeper(*this, "beeper"),
|
||||
m_ram(*this, RAM_TAG),
|
||||
m_rtc(*this, "rtc"),
|
||||
m_via(*this, "via6522"),
|
||||
m_acia(*this, "acia"),
|
||||
m_acia_clock(*this, "acia_clock"),
|
||||
@ -71,6 +76,8 @@ protected:
|
||||
virtual void machine_start() override;
|
||||
virtual void video_start() override;
|
||||
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
private:
|
||||
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
|
||||
@ -83,15 +90,17 @@ private:
|
||||
void sheila_w(offs_t offset, uint8_t data);
|
||||
|
||||
void accomm_palette(palette_device &palette) const;
|
||||
INTERRUPT_GEN_MEMBER(vbl_int);
|
||||
|
||||
void main_map(address_map &map);
|
||||
|
||||
// devices
|
||||
required_device<g65816_device> m_maincpu;
|
||||
required_memory_region m_maincpu_region;
|
||||
required_device<input_merger_device> m_irqs;
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<beep_device> m_beeper;
|
||||
required_device<ram_device> m_ram;
|
||||
required_device<pcf8573_device> m_rtc;
|
||||
required_device<via6522_device> m_via;
|
||||
required_device<acia6850_device> m_acia;
|
||||
required_device<clock_device> m_acia_clock;
|
||||
@ -107,6 +116,11 @@ private:
|
||||
|
||||
bool m_ch00rom_enabled;
|
||||
|
||||
enum
|
||||
{
|
||||
TIMER_SCANLINE_INTERRUPT
|
||||
};
|
||||
|
||||
/* ULA context */
|
||||
|
||||
struct ULA
|
||||
@ -116,15 +130,14 @@ private:
|
||||
uint8_t rompage;
|
||||
uint16_t screen_start;
|
||||
uint16_t screen_base;
|
||||
int screen_size;
|
||||
uint16_t screen_size;
|
||||
uint16_t screen_addr;
|
||||
uint8_t *vram;
|
||||
int screen_dispend;
|
||||
int current_pal[16];
|
||||
int communication_mode;
|
||||
int screen_mode;
|
||||
int shiftlock_mode;
|
||||
int capslock_mode;
|
||||
// int scanline;
|
||||
/* tape reading related */
|
||||
uint32_t tape_value;
|
||||
int tape_steps;
|
||||
@ -136,27 +149,18 @@ private:
|
||||
uint8_t tape_byte;
|
||||
};
|
||||
|
||||
|
||||
ULA m_ula;
|
||||
int m_map4[256];
|
||||
int m_map16[256];
|
||||
};
|
||||
|
||||
static const rgb_t electron_palette[8]=
|
||||
{
|
||||
rgb_t(0x0ff,0x0ff,0x0ff),
|
||||
rgb_t(0x000,0x0ff,0x0ff),
|
||||
rgb_t(0x0ff,0x000,0x0ff),
|
||||
rgb_t(0x000,0x000,0x0ff),
|
||||
rgb_t(0x0ff,0x0ff,0x000),
|
||||
rgb_t(0x000,0x0ff,0x000),
|
||||
rgb_t(0x0ff,0x000,0x000),
|
||||
rgb_t(0x000,0x000,0x000)
|
||||
emu_timer *m_scanline_timer;
|
||||
};
|
||||
|
||||
void accomm_state::accomm_palette(palette_device &palette) const
|
||||
{
|
||||
palette.set_pen_colors(0, electron_palette);
|
||||
for (int i = 0; i < palette.entries(); i++)
|
||||
{
|
||||
palette.set_pen_color(i ^ 7, rgb_t(pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2)));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t accomm_state::read_keyboard1(offs_t offset)
|
||||
@ -187,11 +191,6 @@ uint8_t accomm_state::read_keyboard2(offs_t offset)
|
||||
return data;
|
||||
}
|
||||
|
||||
INTERRUPT_GEN_MEMBER(accomm_state::vbl_int)
|
||||
{
|
||||
interrupt_handler( INT_SET, INT_DISPLAY_END );
|
||||
}
|
||||
|
||||
void accomm_state::machine_reset()
|
||||
{
|
||||
m_ula.communication_mode = 0x04;
|
||||
@ -201,11 +200,10 @@ void accomm_state::machine_reset()
|
||||
m_ula.screen_start = 0x3000;
|
||||
m_ula.screen_base = 0x3000;
|
||||
m_ula.screen_size = 0x8000 - 0x3000;
|
||||
m_ula.screen_addr = 0;
|
||||
m_ula.screen_addr = 0x3000;
|
||||
m_ula.tape_running = 0;
|
||||
m_ula.interrupt_status = 0x82;
|
||||
m_ula.interrupt_control = 0;
|
||||
m_ula.vram = (uint8_t *)m_vram.target() + m_ula.screen_base;
|
||||
|
||||
m_ch00rom_enabled = true;
|
||||
}
|
||||
@ -217,6 +215,21 @@ void accomm_state::machine_start()
|
||||
|
||||
m_ula.interrupt_status = 0x82;
|
||||
m_ula.interrupt_control = 0x00;
|
||||
|
||||
save_item(STRUCT_MEMBER(m_ula, interrupt_status));
|
||||
save_item(STRUCT_MEMBER(m_ula, interrupt_control));
|
||||
save_item(STRUCT_MEMBER(m_ula, rompage));
|
||||
save_item(STRUCT_MEMBER(m_ula, screen_start));
|
||||
save_item(STRUCT_MEMBER(m_ula, screen_base));
|
||||
save_item(STRUCT_MEMBER(m_ula, screen_size));
|
||||
save_item(STRUCT_MEMBER(m_ula, screen_addr));
|
||||
save_item(STRUCT_MEMBER(m_ula, screen_dispend));
|
||||
save_item(STRUCT_MEMBER(m_ula, current_pal));
|
||||
save_item(STRUCT_MEMBER(m_ula, communication_mode));
|
||||
save_item(STRUCT_MEMBER(m_ula, screen_mode));
|
||||
save_item(STRUCT_MEMBER(m_ula, shiftlock_mode));
|
||||
save_item(STRUCT_MEMBER(m_ula, capslock_mode));
|
||||
save_item(NAME(m_ch00rom_enabled));
|
||||
}
|
||||
|
||||
void accomm_state::video_start()
|
||||
@ -226,6 +239,8 @@ void accomm_state::video_start()
|
||||
m_map4[i] = ( ( i & 0x10 ) >> 3 ) | ( i & 0x01 );
|
||||
m_map16[i] = ( ( i & 0x40 ) >> 3 ) | ( ( i & 0x10 ) >> 2 ) | ( ( i & 0x04 ) >> 1 ) | ( i & 0x01 );
|
||||
}
|
||||
m_scanline_timer = timer_alloc(TIMER_SCANLINE_INTERRUPT);
|
||||
m_scanline_timer->adjust( m_screen->time_until_pos(0), 0, m_screen->scan_period() );
|
||||
}
|
||||
|
||||
void accomm_state::ch00switch_w(offs_t offset, uint8_t data)
|
||||
@ -237,7 +252,8 @@ void accomm_state::ch00switch_w(offs_t offset, uint8_t data)
|
||||
|
||||
inline uint8_t accomm_state::read_vram(uint16_t addr)
|
||||
{
|
||||
return m_ula.vram[ addr % m_ula.screen_size ];
|
||||
if ( addr & 0x8000 ) addr -= m_ula.screen_size;
|
||||
return m_vram[ addr ];
|
||||
}
|
||||
|
||||
inline void accomm_state::plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color)
|
||||
@ -253,9 +269,6 @@ uint32_t accomm_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap
|
||||
rectangle r = cliprect;
|
||||
r.sety(scanline, scanline);
|
||||
|
||||
if (scanline == 0)
|
||||
m_ula.screen_addr = m_ula.screen_start - m_ula.screen_base;
|
||||
|
||||
/* set up palette */
|
||||
int pal[16];
|
||||
switch( m_ula.screen_mode )
|
||||
@ -439,11 +452,35 @@ uint32_t accomm_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( m_ula.screen_addr & 0x8000 )
|
||||
m_ula.screen_addr -= m_ula.screen_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void accomm_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
if (id == TIMER_SCANLINE_INTERRUPT)
|
||||
{
|
||||
switch (m_screen->vpos())
|
||||
{
|
||||
case 99:
|
||||
interrupt_handler( INT_SET, INT_RTC );
|
||||
break;
|
||||
case 249:
|
||||
case 255:
|
||||
if ( m_screen->vpos() == m_ula.screen_dispend )
|
||||
interrupt_handler( INT_SET, INT_DISPLAY_END );
|
||||
break;
|
||||
case 311:
|
||||
m_ula.screen_addr = m_ula.screen_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t accomm_state::ram_r(offs_t offset)
|
||||
{
|
||||
uint8_t data = 0xff;
|
||||
@ -499,17 +536,17 @@ uint8_t accomm_state::sheila_r(offs_t offset)
|
||||
data = m_ula.tape_byte;
|
||||
break;
|
||||
}
|
||||
logerror( "ULA: read offset %02x: %02x\n", offset, data );
|
||||
return data;
|
||||
}
|
||||
|
||||
static const int palette_offset[4] = { 0, 4, 5, 1 };
|
||||
static const uint16_t screen_base[8] = { 0x3000, 0x3000, 0x3000, 0x4000, 0x5800, 0x5800, 0x6000, 0x5800 };
|
||||
static const uint16_t screen_base[8] = { 0x3000, 0x3000, 0x3000, 0x4000, 0x5800, 0x5800, 0x6000, 0x6000 };
|
||||
static const int mode_end[8] = { 255, 255, 255 ,249 ,255, 255, 249, 249 };
|
||||
|
||||
void accomm_state::sheila_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
int i = palette_offset[(( offset >> 1 ) & 0x03)];
|
||||
logerror( "ULA: write offset %02x <- %02x\n", offset & 0x0f, data );
|
||||
|
||||
switch( offset & 0x0f )
|
||||
{
|
||||
case 0x00: /* Interrupt control */
|
||||
@ -519,11 +556,9 @@ void accomm_state::sheila_w(offs_t offset, uint8_t data)
|
||||
break;
|
||||
case 0x02: /* Screen start address #1 */
|
||||
m_ula.screen_start = ( m_ula.screen_start & 0x7e00 ) | ( ( data & 0xe0 ) << 1 );
|
||||
logerror( "screen_start changed to %04x\n", m_ula.screen_start );
|
||||
break;
|
||||
case 0x03: /* Screen start address #2 */
|
||||
m_ula.screen_start = ( m_ula.screen_start & 0x1c0 ) | ( ( data & 0x3f ) << 9 );
|
||||
logerror( "screen_start changed to %04x\n", m_ula.screen_start );
|
||||
m_ula.screen_start = ( m_ula.screen_start & 0x1ff ) | ( ( data & 0x3f ) << 9 );
|
||||
break;
|
||||
case 0x04: /* Cassette data shift register */
|
||||
break;
|
||||
@ -585,23 +620,22 @@ void accomm_state::sheila_w(offs_t offset, uint8_t data)
|
||||
m_ula.screen_mode = ( data >> 3 ) & 0x07;
|
||||
m_ula.screen_base = screen_base[ m_ula.screen_mode ];
|
||||
m_ula.screen_size = 0x8000 - m_ula.screen_base;
|
||||
m_ula.vram = (uint8_t *)m_vram.target() + m_ula.screen_base;
|
||||
logerror( "ULA: screen mode set to %d\n", m_ula.screen_mode );
|
||||
m_ula.screen_dispend = mode_end[ m_ula.screen_mode ];
|
||||
m_ula.shiftlock_mode = !BIT(data, 6);
|
||||
m_shiftlock_led = m_ula.shiftlock_mode;
|
||||
m_ula.capslock_mode = BIT(data, 7);
|
||||
m_capslock_led = m_ula.capslock_mode;
|
||||
break;
|
||||
case 0x08: case 0x0A: case 0x0C: case 0x0E:
|
||||
// video_update
|
||||
m_ula.current_pal[i+10] = (m_ula.current_pal[i+10] & 0x01) | (((data & 0x80) >> 5) | ((data & 0x08) >> 1));
|
||||
case 0x08: case 0x0a: case 0x0c: case 0x0e:
|
||||
/* colour palette */
|
||||
m_ula.current_pal[i+10] = (m_ula.current_pal[i+10] & 0x01) | (((data & 0x80) >> 5) | ((data & 0x08) >> 2));
|
||||
m_ula.current_pal[i+8] = (m_ula.current_pal[i+8] & 0x01) | (((data & 0x40) >> 4) | ((data & 0x04) >> 1));
|
||||
m_ula.current_pal[i+2] = (m_ula.current_pal[i+2] & 0x03) | ((data & 0x20) >> 3);
|
||||
m_ula.current_pal[i] = (m_ula.current_pal[
|
||||
i] & 0x03) | ((data & 0x10) >> 2);
|
||||
break;
|
||||
case 0x09: case 0x0B: case 0x0D: case 0x0F:
|
||||
// video_update
|
||||
case 0x09: case 0x0b: case 0x0d: case 0x0f:
|
||||
/* colour palette */
|
||||
m_ula.current_pal[i+10] = (m_ula.current_pal[i+10] & 0x06) | ((data & 0x08) >> 3);
|
||||
m_ula.current_pal[i+8] = (m_ula.current_pal[i+8] & 0x06) | ((data & 0x04) >> 2);
|
||||
m_ula.current_pal[i+2] = (m_ula.current_pal[i+2] & 0x04) | (((data & 0x20) >> 4) | ((data & 0x02) >> 1));
|
||||
@ -840,15 +874,14 @@ void accomm_state::accomm(machine_config &config)
|
||||
{
|
||||
G65816(config, m_maincpu, 16_MHz_XTAL / 8);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &accomm_state::main_map);
|
||||
m_maincpu->set_vblank_int("screen", FUNC(accomm_state::vbl_int));
|
||||
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
|
||||
screen.set_refresh_hz(50.08);
|
||||
screen.set_size(640, 312);
|
||||
screen.set_visarea(0, 640 - 1, 0, 256 - 1);
|
||||
screen.set_screen_update(FUNC(accomm_state::screen_update));
|
||||
screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
|
||||
screen.set_palette("palette");
|
||||
INPUT_MERGER_ANY_HIGH(config, m_irqs).output_handler().set_inputline(m_maincpu, G65816_LINE_IRQ);
|
||||
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
m_screen->set_raw(16_MHz_XTAL, 1024, 0, 640, 312, 0, 256);
|
||||
m_screen->set_screen_update(FUNC(accomm_state::screen_update));
|
||||
m_screen->set_video_attributes(VIDEO_UPDATE_SCANLINE);
|
||||
m_screen->set_palette("palette");
|
||||
|
||||
PALETTE(config, "palette", FUNC(accomm_state::accomm_palette), 16);
|
||||
|
||||
@ -863,18 +896,27 @@ void accomm_state::accomm(machine_config &config)
|
||||
SPEAKER(config, "mono").front_center();
|
||||
BEEP(config, m_beeper, 300).add_route(ALL_OUTPUTS, "mono", 1.00);
|
||||
|
||||
/* rtc pcf8573 */
|
||||
/* rtc */
|
||||
PCF8573(config, m_rtc, 32.768_kHz_XTAL);
|
||||
m_rtc->comp_cb().set(m_via, FUNC(via6522_device::write_cb1));
|
||||
|
||||
/* teletext */
|
||||
//SAA5240(config, m_cct);
|
||||
|
||||
/* via */
|
||||
VIA6522(config, m_via, 16_MHz_XTAL / 16);
|
||||
m_via->writepa_handler().set("cent_data_out", FUNC(output_latch_device::write));
|
||||
m_via->ca2_handler().set("centronics", FUNC(centronics_device::write_strobe));
|
||||
m_via->readpb_handler().set(m_rtc, FUNC(pcf8573_device::sda_r)).bit(0);
|
||||
m_via->writepb_handler().set(m_rtc, FUNC(pcf8573_device::sda_w)).bit(1).invert();
|
||||
m_via->writepb_handler().append(m_rtc, FUNC(pcf8573_device::scl_w)).bit(2).invert();
|
||||
m_via->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<0>));
|
||||
|
||||
/* acia */
|
||||
ACIA6850(config, m_acia, 0);
|
||||
m_acia->txd_handler().set("serial", FUNC(rs232_port_device::write_txd));
|
||||
m_acia->rts_handler().set("serial", FUNC(rs232_port_device::write_rts));
|
||||
m_acia->irq_handler().set_inputline("maincpu", G65816_LINE_IRQ);
|
||||
m_acia->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<1>));
|
||||
|
||||
rs232_port_device &serial(RS232_PORT(config, "serial", default_rs232_devices, nullptr));
|
||||
serial.rxd_handler().set(m_acia, FUNC(acia6850_device::write_rxd));
|
||||
|
Loading…
Reference in New Issue
Block a user