summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Angelo Salese <angelosa@users.noreply.github.com>2021-09-25 16:00:29 +0200
committer GitHub <noreply@github.com>2021-09-25 16:00:29 +0200
commitec33fac7c77e3f9654d83c15f7c03f1cef79ad34 (patch)
treee19da19abfe0ceddcc3550f3464b420f4fc72aa0 /src
parente2331a7eed73fd6fec837378ac7a47db9388ed18 (diff)
Add floppy support to NEC PC-8001 (#8532)
New clones marked as NOT_WORKING -------------------------------- PC-8001mkIISR [anonymous] * Generate a new pc8001_flop.xml list, based off Neo Kobe dumps; * Move several items from pc8801_flop.xml to the new pc8001_flop.xml; * Generate new lists for pc8001mk2_flop.xml and pc8001mk2sr_flop.xml; * Hook aforementioned lists where they belongs ( i.e. N-Basic list is now shared between pc8801.cpp and pc8001.cpp, N80 list belongs to pc8001mk2 and pc8001mk2sr, N80SR list belongs to pc8001mk2sr alone) * upd3301.cpp: fix scrolling glitch when unthrottled * pc8001.cpp: fix machine configs inheritance * pc8001.cpp: constexpr the XTALs * pc8001.cpp: allow to enter into N80 BASIC mode for mk2 machines * Ported pc80s31k to device interface, and hooked it up to pc8001 * Fix validation errors * Misc documentation updates * uPD3301.cpp: implement bulk of attribute fields * upd3301: fix olyboss compile and crashing, add rvv signal * upd3301.cpp: fix last value of attribute row (7narabe), fix graphic mode when in width 40 (15puzzle) * upd3301.cpp: consider an attribute end of 0 equal to max size, fixes starfire * upd3301.cpp: rvv is definitely a global reverse rather than acting on palette for PC8001, document flgworld attribute weirdness (double somersault) * pc8001_flop.xml: QA selected SW * pc80s31k.cpp: split into PC80S31 (2d) and PC80S31K (2d/2dd/2hd) devices, rearrange disk bioses * pc8801.cpp: inherit pc80s31k device and kill off FDC legacy code * pc80s31k.cpp: documentation updates * pc8001_flop: move Magic Copy and a alt versions of ay1 and 4d house in here * pc98.xml: move daivacal from PC88 since it really belongs here * pc8801_flop.xml: major QA testing on suspicious floppy activities * pc8801.cpp: remove logging of High [TV]RAM * pc8801_flop.xml: fix rogue extra comment closing * pc80s31k.cpp: mailbox the PPI ports, fix barbatus booting; pc80s31k.cpp: allow filemst to boot, and add note about its unemulated extended HW; * upd3301.cpp: convert AT1/AT0/SC to an aggregate variable * upd3301.cpp: convert attribute fetch to be a client delegate * pc8001.cpp: move some shared functions to pc8001_base_state * pc8001.cpp: add DMA functions * pc8001.cpp: add extension setter for 24KHz mode (which will be used by PC-8801 once implementation is merged) * pc8801_flop.xml: fix description duplicate * Bulk replace pc8*_flop.xml capitalized Alt into lowercase * pc80s31k.cpp: add space.unmap() for terminal_count_r, reorder headers, make constructor trampoline protected * Standardize Daiva titles across XMLs * pc8801_cass.xml: revert of software name t[ape] postfixes * pc8801_flop.xml: more identification of N/V1 BASIC SWs
Diffstat (limited to 'src')
-rw-r--r--src/devices/video/upd3301.cpp537
-rw-r--r--src/devices/video/upd3301.h31
-rw-r--r--src/mame/drivers/olyboss.cpp7
-rw-r--r--src/mame/drivers/pc8001.cpp539
-rw-r--r--src/mame/drivers/pc8801.cpp280
-rw-r--r--src/mame/drivers/pc88va.cpp2
-rw-r--r--src/mame/includes/pc8001.h147
-rw-r--r--src/mame/includes/pc8801.h37
-rw-r--r--src/mame/machine/pc80s31k.cpp460
-rw-r--r--src/mame/machine/pc80s31k.h86
-rw-r--r--src/mame/mame.lst5
11 files changed, 1479 insertions, 652 deletions
diff --git a/src/devices/video/upd3301.cpp b/src/devices/video/upd3301.cpp
index 9da9f70af7c..1608b3c74a2 100644
--- a/src/devices/video/upd3301.cpp
+++ b/src/devices/video/upd3301.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Curt Coder
+// copyright-holders:Curt Coder, Angelo Salese
/**********************************************************************
NEC uPD3301 Programmable CRT Controller emulation
@@ -10,12 +10,20 @@
TODO:
- - attributes
- - N interrupt
+ - pinpoint how much of pc8001/pc8801 drawing functions should actually be inherited
+ here;
+ - N interrupt (special control character)
- light pen
- reset counters
- proper DMA timing (now the whole screen is transferred at the end of the frame,
accurate timing requires CCLK timer which kills performance)
+ - DMA burst mode;
+ - cleanup: variable namings should be more verbose
+ (i.e. not be a single letter like m_y, m_z, m_b ...);
+ - sorcerml (pc8801) has buggy DMA burst mode, causing an underrun (hence a status U interrupt);
+ - jettermi (pc8801) expects to colorize its underlying 400 b&w mode by masking with the
+ text color attributes here;
+ - xak2 (pc8801) throws text garbage on legacy renderer (verify);
*/
@@ -77,33 +85,35 @@ DEFINE_DEVICE_TYPE(UPD3301, upd3301_device, "upd3301", "NEC uPD3301")
// upd3301_device - constructor
//-------------------------------------------------
-upd3301_device::upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, UPD3301, tag, owner, clock),
- device_video_interface(mconfig, *this),
- m_write_int(*this),
- m_write_drq(*this),
- m_write_hrtc(*this),
- m_write_vrtc(*this),
- m_display_cb(*this),
- m_width(0),
- m_status(0),
- m_param_count(0),
- m_data_fifo_pos(0),
- m_attr_fifo_pos(0),
- m_input_fifo(0),
- m_me(0),
- m_h(80),
- m_l(20),
- m_r(10),
- m_v(6),
- m_z(32),
- m_attr_blink(0),
- m_attr_frame(0),
- m_cm(0),
- m_cx(0),
- m_cy(0),
- m_cursor_blink(0),
- m_cursor_frame(0)
+upd3301_device::upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, UPD3301, tag, owner, clock)
+ , device_video_interface(mconfig, *this)
+ , m_write_int(*this)
+ , m_write_drq(*this)
+ , m_write_hrtc(*this)
+ , m_write_vrtc(*this)
+ , m_write_rvv(*this)
+ , m_display_cb(*this)
+ , m_attr_fetch_cb(*this)
+ , m_width(0)
+ , m_status(0)
+ , m_param_count(0)
+ , m_data_fifo_pos(0)
+ , m_attr_fifo_pos(0)
+ , m_input_fifo(0)
+ , m_me(0)
+ , m_h(80)
+ , m_l(20)
+ , m_r(10)
+ , m_v(6)
+ , m_z(32)
+ , m_attr_blink(0)
+ , m_attr_frame(0)
+ , m_cm(0)
+ , m_cx(0)
+ , m_cy(0)
+ , m_cursor_blink(0)
+ , m_cursor_frame(0)
{
}
@@ -120,7 +130,9 @@ void upd3301_device::device_start()
m_write_int.resolve_safe();
m_write_hrtc.resolve_safe();
m_write_vrtc.resolve_safe();
+ m_write_rvv.resolve();
m_display_cb.resolve();
+ m_attr_fetch_cb.resolve();
// allocate timers
m_hrtc_timer = timer_alloc(TIMER_HRTC);
@@ -148,9 +160,7 @@ void upd3301_device::device_start()
save_item(NAME(m_r));
save_item(NAME(m_v));
save_item(NAME(m_z));
- save_item(NAME(m_at1));
- save_item(NAME(m_at0));
- save_item(NAME(m_sc));
+ save_item(NAME(m_gfx_mode));
save_item(NAME(m_attr));
save_item(NAME(m_attr_blink));
save_item(NAME(m_attr_frame));
@@ -161,6 +171,7 @@ void upd3301_device::device_start()
save_item(NAME(m_cursor_frame));
save_item(NAME(m_data_fifo));
save_item(NAME(m_attr_fifo));
+ save_item(NAME(m_reverse_display));
}
@@ -173,6 +184,10 @@ void upd3301_device::device_reset()
set_interrupt(0);
set_drq(0);
+ m_cm = 0;
+ m_b = 48;
+ m_reverse_display = false;
+
recompute_parameters();
}
@@ -191,40 +206,68 @@ void upd3301_device::device_clock_changed()
// device_timer - handle timer events
//-------------------------------------------------
+// this snipped was inside screen_update fn
+// bad idea: it causes all sort of desync glitches when emulation unthrottles
+// TODO: verify if FIFO clear-out happens on vblank-in or -out
+inline void upd3301_device::reset_fifo_vrtc()
+{
+ m_y = 0;
+ m_data_fifo_pos = 0;
+ m_attr_fifo_pos = 0;
+
+ m_cursor_frame++;
+
+ if (m_cursor_frame == m_b)
+ {
+ m_cursor_frame = 0;
+ m_cursor_blink = !m_cursor_blink;
+ }
+
+ m_attr_frame++;
+ if (m_attr_frame == (m_b << 1))
+ {
+ m_attr_frame = 0;
+ m_attr_blink = !m_attr_blink;
+ }
+}
+
void upd3301_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
- case TIMER_HRTC:
- LOG("UPD3301 HRTC: %u\n", param);
+ case TIMER_HRTC:
+ LOG("UPD3301 HRTC: %u\n", param);
- m_write_hrtc(param);
- m_hrtc = param;
+ m_write_hrtc(param);
+ m_hrtc = param;
- update_hrtc_timer(param);
- break;
+ update_hrtc_timer(param);
+ break;
- case TIMER_VRTC:
- LOG("UPD3301 VRTC: %u\n", param);
+ case TIMER_VRTC:
+ LOG("UPD3301 VRTC: %u\n", param);
- m_write_vrtc(param);
- m_vrtc = param;
+ m_write_vrtc(param);
+ m_vrtc = param;
- update_vrtc_timer(param);
- if(!(m_status & STATUS_VE))
- break;
+ update_vrtc_timer(param);
+ if(!(m_status & STATUS_VE))
+ break;
- if (param && !m_me)
- {
- m_status |= STATUS_E;
- set_interrupt(1);
- }
- else if(!param)
- set_drq(1);
- break;
+ if(!param)
+ reset_fifo_vrtc();
+
+ if (param && !m_me)
+ {
+ m_status |= STATUS_E;
+ set_interrupt(1);
+ }
+ else if(!param)
+ set_drq(1);
+ break;
- case TIMER_DRQ:
- break;
+ case TIMER_DRQ:
+ break;
}
}
@@ -239,13 +282,16 @@ uint8_t upd3301_device::read(offs_t offset)
switch (offset & 0x01)
{
- case 0: // data
- break;
+ case 0: // data
+ // TODO: light pen
+ if (!machine().side_effects_disabled())
+ popmessage("light pen reading");
+ break;
- case 1: // status
- data = m_status;
- m_status &= ~(STATUS_LP | STATUS_E |STATUS_N | STATUS_U);
- break;
+ case 1: // status
+ data = m_status;
+ m_status &= ~(STATUS_LP | STATUS_E |STATUS_N | STATUS_U);
+ break;
}
return data;
@@ -260,135 +306,185 @@ void upd3301_device::write(offs_t offset, uint8_t data)
{
switch (offset & 0x01)
{
- case 0: // data
- switch (m_mode)
- {
- case MODE_RESET:
- switch (m_param_count)
+ case 0: // data
+ switch (m_mode)
{
- case 0:
- m_dma_mode = BIT(data, 7);
- m_h = (data & 0x7f) + 2;
- LOG("UPD3301 DMA Mode: %s\n", m_dma_mode ? "character" : "burst");
- LOG("UPD3301 H: %u\n", m_h);
+ case MODE_RESET:
+ switch (m_param_count)
+ {
+ case 0:
+ m_dma_mode = BIT(data, 7);
+ // number of characters per line -2
+ // TODO: doesn't seem to like anything beyond 80
+ m_h = (data & 0x7f) + 2;
+ if (m_h > 80)
+ popmessage("Illegal width set %d", m_h);
+ LOG("UPD3301 DMA Mode: %s\n", m_dma_mode ? "character" : "burst");
+ LOG("UPD3301 H: %u\n", m_h);
+ break;
+
+ case 1:
+ // cursor/attribute blink rate
+ m_b = ((data >> 6) + 1) * 16;
+ // number of lines displayed -1
+ // (or in other words, tilemap y size)
+ m_l = (data & 0x3f) + 1;
+ LOG("UPD3301 B: %u\n", m_b);
+ LOG("UPD3301 L: %u\n", m_l);
+ break;
+
+ case 2:
+ // skip line (pseudo-interlace?)
+ m_s = BIT(data, 7);
+ if (m_s)
+ popmessage("skip line enable");
+ // cursor mode
+ // (00) not blinking underline cursor
+ // (01) blinking underline cursor
+ // (10) not blinking solid cursor
+ // (11) blinking solid cursor
+ // NB: there must be at least 14 lines per char to make underline valid
+ m_c = (data >> 5) & 0x03;
+ if (m_c != 3)
+ popmessage("cursor mode %02x", m_c);
+ // Number of lines per character -1
+ m_r = (data & 0x1f) + 1;
+ LOG("UPD3301 S: %u\n", m_s);
+ LOG("UPD3301 C: %u\n", m_c);
+ LOG("UPD3301 R: %u\n", m_r);
+ break;
+
+ case 3:
+ // vblank lines -1 (1 to 8)
+ m_v = (data >> 5) + 1;
+ // hblank width -2 (6 to 33)
+ m_z = (data & 0x1f) + 2;
+ LOG("UPD3301 V: %u\n", m_v);
+ LOG("UPD3301 Z: %u\n", m_z);
+ recompute_parameters();
+ break;
+
+ case 4:
+ // AT|SC
+ // (00|0) transparent b&w with special control character
+ // (00|1) no attributes, no special control
+ // (01|0) transparent color
+ // (10|0) non-transparent b&w, special control
+ // (10|1) non-transparent b&w, no special control
+ // any other setting are invalid
+ //m_at1 = BIT(data, 7);
+ //m_at0 = BIT(data, 6);
+ //m_sc = BIT(data, 5);
+ m_gfx_mode = (data & 0xe0) >> 5;
+ if (m_gfx_mode & 0x5)
+ popmessage("attr mode %02x", m_gfx_mode);
+ // Max number of attributes per line -1
+ // can't be higher than 20
+ m_attr = std::min((data & 0x1f) + 1, 20);
+ LOG("UPD3301 AT1: %u AT0: %u SC: %u\n", BIT(data, 7), BIT(data, 6), BIT(data, 5));
+ LOG("UPD3301 ATTR: %u\n", m_attr);
+
+ m_mode = MODE_NONE;
+ break;
+ }
+
+ m_param_count++;
break;
- case 1:
- m_b = ((data >> 6) + 1) * 16;
- m_l = (data & 0x3f) + 1;
- LOG("UPD3301 B: %u\n", m_b);
- LOG("UPD3301 L: %u\n", m_l);
- break;
+ case MODE_LOAD_CURSOR_POSITION:
+ switch (m_param_count)
+ {
+ case 0:
+ m_cx = data & 0x7f;
+ LOG("UPD3301 CX: %u\n", m_cx);
+ break;
- case 2:
- m_s = BIT(data, 7);
- m_c = (data >> 4) & 0x03;
- m_r = (data & 0x1f) + 1;
- LOG("UPD3301 S: %u\n", m_s);
- LOG("UPD3301 C: %u\n", m_c);
- LOG("UPD3301 R: %u\n", m_r);
- break;
+ case 1:
+ m_cy = data & 0x3f;
+ LOG("UPD3301 CY: %u\n", m_cy);
- case 3:
- m_v = (data >> 5) + 1;
- m_z = (data & 0x1f) + 2;
- LOG("UPD3301 V: %u\n", m_v);
- LOG("UPD3301 Z: %u\n", m_z);
- recompute_parameters();
- break;
+ m_mode = MODE_NONE;
+ break;
+ }
- case 4:
- m_at1 = BIT(data, 7);
- m_at0 = BIT(data, 6);
- m_sc = BIT(data, 5);
- m_attr = (data & 0x1f) + 1;
- LOG("UPD3301 AT1: %u\n", m_at1);
- LOG("UPD3301 AT0: %u\n", m_at0);
- LOG("UPD3301 SC: %u\n", m_sc);
- LOG("UPD3301 ATTR: %u\n", m_attr);
-
- m_mode = MODE_NONE;
+ m_param_count++;
break;
- }
- m_param_count++;
+ default:
+ LOG("UPD3301 Invalid Parameter Byte %02x!\n", data);
+ }
break;
- case MODE_LOAD_CURSOR_POSITION:
- switch (m_param_count)
+ case 1: // command
+ m_mode = MODE_NONE;
+ m_param_count = 0;
+
+ switch (data & 0xe0)
{
- case 0:
- m_cx = data & 0x7f;
- LOG("UPD3301 CX: %u\n", m_cx);
+ case COMMAND_RESET:
+ LOG("UPD3301 Reset\n");
+ m_mode = MODE_RESET;
+ // TODO: this also disables external display such as Graphic VRAM in PC-8801
+ set_display(0);
+ set_interrupt(0);
break;
- case 1:
- m_cy = data & 0x3f;
- LOG("UPD3301 CY: %u\n", m_cy);
-
- m_mode = MODE_NONE;
+ case COMMAND_START_DISPLAY:
+ {
+ LOG("UPD3301 Start Display\n");
+ bool new_rvv = bool(BIT(data, 0));
+ // misscmd (pc8001) enables this
+ if (m_reverse_display != new_rvv)
+ {
+ m_reverse_display = new_rvv;
+ if (!m_write_rvv.isnull())
+ m_write_rvv(m_reverse_display);
+ else if (m_reverse_display == true)
+ logerror("%s: reverse display enabled (warning)\n", machine().describe_context());
+ }
+ set_display(1);
+ reset_counters();
break;
}
- m_param_count++;
- break;
-
- default:
- LOG("UPD3301 Invalid Parameter Byte %02x!\n", data);
- }
- break;
-
- case 1: // command
- m_mode = MODE_NONE;
- m_param_count = 0;
-
- switch (data & 0xe0)
- {
- case COMMAND_RESET:
- LOG("UPD3301 Reset\n");
- m_mode = MODE_RESET;
- set_display(0);
- set_interrupt(0);
- break;
-
- case COMMAND_START_DISPLAY:
- LOG("UPD3301 Start Display\n");
- set_display(1);
- reset_counters();
- break;
-
- case COMMAND_SET_INTERRUPT_MASK:
- LOG("UPD3301 Set Interrupt Mask\n");
- m_me = BIT(data, 0);
- m_mn = BIT(data, 1);
- LOG("UPD3301 ME: %u\n", m_me);
- LOG("UPD3301 MN: %u\n", m_mn);
- break;
+ case COMMAND_SET_INTERRUPT_MASK:
+ LOG("UPD3301 Set Interrupt Mask\n");
+ // vblank irq mask
+ m_me = BIT(data, 0);
+ // special control character irq mask
+ m_mn = BIT(data, 1);
+ // TODO: writing a negated bit 0 makes status bit 7 to be held high?
+ LOG("UPD3301 ME: %u\n", m_me);
+ LOG("UPD3301 MN: %u\n", m_mn);
+ break;
- case COMMAND_READ_LIGHT_PEN:
- LOG("UPD3301 Read Light Pen\n");
- m_mode = MODE_READ_LIGHT_PEN;
- break;
+ case COMMAND_READ_LIGHT_PEN:
+ LOG("UPD3301 Read Light Pen\n");
+ // TODO: similar to cursor parameters except on read
+ // (plus an HR to bit 7 param [0])
+ m_mode = MODE_READ_LIGHT_PEN;
+ break;
- case COMMAND_LOAD_CURSOR_POSITION:
- LOG("UPD3301 Load Cursor Position\n");
- m_mode = MODE_LOAD_CURSOR_POSITION;
- m_cm = BIT(data, 0);
- LOG("UPD3301 CM: %u\n", m_cm);
- break;
+ case COMMAND_LOAD_CURSOR_POSITION:
+ LOG("UPD3301 Load Cursor Position\n");
+ m_mode = MODE_LOAD_CURSOR_POSITION;
+ // (1) show cursor (0) disable cursor
+ m_cm = BIT(data, 0);
+ LOG("UPD3301 CM: %u\n", m_cm);
+ break;
- case COMMAND_RESET_INTERRUPT:
- LOG("UPD3301 Reset Interrupt\n");
- set_interrupt(0);
- break;
+ case COMMAND_RESET_INTERRUPT:
+ LOG("UPD3301 Reset Interrupt\n");
+ set_interrupt(0);
+ break;
- case COMMAND_RESET_COUNTERS:
- LOG("UPD3301 Reset Counters\n");
- m_mode = MODE_RESET_COUNTERS;
- reset_counters();
+ case COMMAND_RESET_COUNTERS:
+ LOG("UPD3301 Reset Counters\n");
+ m_mode = MODE_RESET_COUNTERS;
+ reset_counters();
+ break;
+ }
break;
- }
- break;
}
}
@@ -406,17 +502,23 @@ void upd3301_device::dack_w(uint8_t data)
if (m_data_fifo_pos < m_h)
{
- m_data_fifo[m_data_fifo_pos][m_input_fifo] = data;
+ m_data_fifo[m_input_fifo][m_data_fifo_pos] = data;
m_data_fifo_pos++;
}
else
{
- m_attr_fifo[m_attr_fifo_pos][m_input_fifo] = data;
+ m_attr_fifo[m_input_fifo][m_attr_fifo_pos] = data;
m_attr_fifo_pos++;
}
if ((m_data_fifo_pos == m_h) && (m_attr_fifo_pos == (m_attr << 1)))
{
+ const u8 attr_max_size = 80;
+ // first attribute start is always overwritten with a 0
+ m_attr_fifo[m_input_fifo][0] = 0;
+ // last parameter always extends up to the end of the row
+ // (7narabe (pc8001) fills last row value with white when exausting available slots)
+ m_attr_fifo[m_input_fifo][40] = attr_max_size;
m_input_fifo = !m_input_fifo;
m_data_fifo_pos = 0;
@@ -466,23 +568,70 @@ int upd3301_device::vrtc_r()
// draw_scanline -
//-------------------------------------------------
+UPD3301_FETCH_ATTRIBUTE( upd3301_device::default_attr_fetch )
+{
+ const u8 attr_max_size = 80;
+ std::array<u16, attr_max_size> attr_extend_info;
+
+ // TODO: uPD3301 may actually fetch in LIFO order
+ for (int ex = 0; ex < attr_fifo_size; ex+=2)
+ {
+ u8 attr_start = std::min(attr_row[ex], attr_max_size);
+ u8 attr_value = attr_row[ex+1];
+ u8 attr_end = std::min(attr_row[ex+2], attr_max_size);
+ // if the target is == 0 then just consider max size instead
+ // (starfire (pc8001) wants this otherwise will black screen on gameplay)
+ if (attr_end == 0)
+ attr_end = attr_max_size;
+
+ //printf("%04x %d %d [%02x]\n", ex, attr_start, attr_end, attr_value);
+
+ for (int i = attr_start; i < attr_end; i++)
+ attr_extend_info[i] = attr_value;
+
+ if (attr_end == attr_max_size)
+ break;
+ }
+
+ return attr_extend_info;
+}
+
void upd3301_device::draw_scanline()
{
+ // Olympia Boss never bothers in writing a correct attribute table for rows on resident OS,
+ // it just extends the full attribute RAM with a start: 0 end: 0xff value: 0.
+ // According to doc notes anything beyond width 80 is puked by the CRTC, therefore we clamp.
+ const u8 attr_max_size = 80;
+ const std::array<u8, 41> attr_fifo = m_attr_fifo[!m_input_fifo];
+
+ // expose attribute handling to our client
+ // PC-8801 schematics definitely shows extra TTL connections for handling its "8 to 16-bit" attribute conversion.
+ // It also practically needs to read the attribute mapping for various extra side-effects such as colorized 400 line 1bpp
+ // cfr. "その他 / other" section at http://mydocuments.g2.xrea.com/html/p8/vraminfo.html
+ std::array<u16, attr_max_size> extend_attr = m_attr_fetch_cb(attr_fifo, m_gfx_mode, m_y, m_attr << 1, m_h);
+
for (int lc = 0; lc < m_r; lc++)
{
+ bool is_lowestline = lc == m_r - 1;
for (int sx = 0; sx < m_h; sx++)
{
int y = m_y + lc;
- uint8_t cc = m_data_fifo[sx][!m_input_fifo];
- int hlgt = 0; // TODO
- int rvv = 0; // TODO
- int vsp = 0; // TODO
- int sl0 = 0; // TODO
- int sl12 = 0; // TODO
+ uint8_t cc = m_data_fifo[!m_input_fifo][sx];
int csr = m_cm && m_cursor_blink && ((y / m_r) == m_cy) && (sx == m_cx);
- int gpa = 0; // TODO
- m_display_cb(m_bitmap, y, sx, cc, lc, hlgt, rvv, vsp, sl0, sl12, csr, gpa);
+ // datasheet mentions these but I find zero unambiguous information for PC-8001/PC-8801, i.e.:
+ // - "highlight" should be attribute blinking?
+ // - is "gpa" actually NEC-ese for attr bus?
+ // - is sl0 / sl12 NEC names for upper/lower line?
+// int hlgt = 0;
+// int rvv = 0;
+// int vsp = 0;
+// int sl0 = 0;
+// int sl12 = 0;
+// int gpa = 0;
+
+// m_display_cb(m_bitmap, y, sx, cc, lc, hlgt, rvv, vsp, sl0, sl12, csr, gpa);
+ m_display_cb(m_bitmap, y, sx, cc, lc, csr, m_attr_blink, extend_attr[sx], m_gfx_mode, is_lowestline);
}
}
@@ -496,33 +645,13 @@ void upd3301_device::draw_scanline()
uint32_t upd3301_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- if (m_status & STATUS_VE)
- {
- m_y = 0;
- m_data_fifo_pos = 0;
- m_attr_fifo_pos = 0;
+ bitmap.fill(rgb_t(0x00,0x00,0x00), cliprect);
- m_cursor_frame++;
+ if (!(m_status & STATUS_VE))
+ return 0;
- if (m_cursor_frame == m_b)
- {
- m_cursor_frame = 0;
- m_cursor_blink = !m_cursor_blink;
- }
-
- m_attr_frame++;
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
- if (m_attr_frame == (m_b << 1))
- {
- m_attr_frame = 0;
- m_attr_blink = !m_attr_blink;
- }
- copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
- }
- else
- {
- bitmap.fill(rgb_t(0x00,0x00,0x00), cliprect);
- }
return 0;
}
diff --git a/src/devices/video/upd3301.h b/src/devices/video/upd3301.h
index 281c17a9980..4388f730d0f 100644
--- a/src/devices/video/upd3301.h
+++ b/src/devices/video/upd3301.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Curt Coder
+// copyright-holders:Curt Coder, Angelo Salese
/**********************************************************************
NEC uPD3301 Programmable CRT Controller emulation
@@ -40,8 +40,10 @@
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
-#define UPD3301_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa)
+//#define UPD3301_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa)
+#define UPD3301_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int csr, bool attr_blink_on, u16 attr, u8 gfx_mode, bool is_lowestline)
+#define UPD3301_FETCH_ATTRIBUTE(_name) std::array<u16, 80> _name(const std::array<u8, 41> attr_row, u8 gfx_mode, int y, u8 attr_fifo_size, u8 row_size)
//**************************************************************************
// TYPE DEFINITIONS
@@ -54,18 +56,24 @@ class upd3301_device : public device_t,
public device_video_interface
{
public:
- typedef device_delegate<void (bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa)> draw_character_delegate;
+// typedef device_delegate<void (bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa)> draw_character_delegate;
+ typedef device_delegate<void (bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int csr, bool attr_blink_on, u16 attr, u8 gfx_mode, bool is_lowerline)> draw_character_delegate;
+ typedef device_delegate<std::array<u16, 80> (const std::array<u8, 41> attr_row, u8 gfx_mode, int y, u8 attr_fifo_size, u8 row_size)> fetch_attribute_delegate;
// construction/destruction
upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void set_character_width(int value) { m_width = value; }
template <typename... T> void set_display_callback(T &&... args) { m_display_cb.set(std::forward<T>(args)...); }
+ template <typename... T> void set_attribute_fetch_callback(T &&... args) { m_attr_fetch_cb.set(std::forward<T>(args)...); }
+
+ UPD3301_FETCH_ATTRIBUTE( default_attr_fetch );
auto drq_wr_callback() { return m_write_drq.bind(); }
auto int_wr_callback() { return m_write_int.bind(); }
auto hrtc_wr_callback() { return m_write_hrtc.bind(); }
auto vrtc_wr_callback() { return m_write_vrtc.bind(); }
+ auto rvv_wr_callback() { return m_write_rvv.bind(); }
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
@@ -100,13 +108,16 @@ private:
void recompute_parameters();
void draw_scanline();
+ inline void reset_fifo_vrtc();
devcb_write_line m_write_int;
devcb_write_line m_write_drq;
devcb_write_line m_write_hrtc;
devcb_write_line m_write_vrtc;
+ devcb_write_line m_write_rvv;
draw_character_delegate m_display_cb;
+ fetch_attribute_delegate m_attr_fetch_cb;
int m_width;
// screen drawing
@@ -121,8 +132,8 @@ private:
int m_param_count; // parameter count
// FIFOs
- uint8_t m_data_fifo[80][2]; // row data FIFO
- uint8_t m_attr_fifo[40][2]; // attribute FIFO
+ u8 m_data_fifo[2][80]; // row data FIFO
+ std::array<std::array<u8, 40+1>, 2> m_attr_fifo; // attribute FIFO (+1 for extending to end of row)
int m_data_fifo_pos; // row data FIFO position
int m_attr_fifo_pos; // attribute FIFO position
int m_input_fifo; // which FIFO is in input mode
@@ -143,9 +154,10 @@ private:
int m_z; // horizontal blanking width
// attributes
- int m_at1; //
- int m_at0; //
- int m_sc; //
+// int m_at1; //
+// int m_at0; //
+// int m_sc; //
+ u8 m_gfx_mode; // AT1 + AT0 + SC
int m_attr; // attributes per row
int m_attr_blink; // attribute blink
int m_attr_frame; // attribute blink frame counter
@@ -157,6 +169,9 @@ private:
int m_cursor_blink; // cursor blink
int m_cursor_frame; // cursor blink frame counter
+ // misc
+ bool m_reverse_display;
+
// timers
emu_timer *m_hrtc_timer;
emu_timer *m_vrtc_timer;
diff --git a/src/mame/drivers/olyboss.cpp b/src/mame/drivers/olyboss.cpp
index df710367f37..b711c8a0ac6 100644
--- a/src/mame/drivers/olyboss.cpp
+++ b/src/mame/drivers/olyboss.cpp
@@ -172,7 +172,7 @@ void olyboss_state::olyboss_io(address_map &map)
{
map.global_mask(0xff);
map.unmap_value_high();
- map(0x0, 0x8).rw(m_dma, FUNC(i8257_device::read), FUNC(i8257_device::write));
+ map(0x00, 0x08).rw(m_dma, FUNC(i8257_device::read), FUNC(i8257_device::write));
map(0x10, 0x11).m(m_fdc, FUNC(upd765a_device::map));
//map(0x20, 0x20) //beeper?
map(0x30, 0x30).rw(m_uic, FUNC(am9519_device::data_r), FUNC(am9519_device::data_w));
@@ -269,8 +269,8 @@ UPD3301_DRAW_CHARACTER_MEMBER( olyboss_state::olyboss_display_pixels )
for (int i = 0; i < 8; i++)
{
- int color = BIT(data, 7) ^ rvv;
- bitmap.pix(y, (sx * 8) + i) = color?0xffffff:0;
+ int color = BIT(data, 7);
+ bitmap.pix(y, (sx * 8) + i) = color ? 0xffffff : 0;
data <<= 1;
}
}
@@ -458,6 +458,7 @@ void olyboss_state::olybossd(machine_config &config)
UPD3301(config, m_crtc, XTAL(14'318'181));
m_crtc->set_character_width(8);
m_crtc->set_display_callback(FUNC(olyboss_state::olyboss_display_pixels));
+ m_crtc->set_attribute_fetch_callback(m_crtc, FUNC(upd3301_device::default_attr_fetch));
m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w));
m_crtc->int_wr_callback().set(m_uic, FUNC(am9519_device::ireq0_w)).invert();
m_crtc->set_screen(SCREEN_TAG);
diff --git a/src/mame/drivers/pc8001.cpp b/src/mame/drivers/pc8001.cpp
index f34f2cd00ad..1e48dde03ac 100644
--- a/src/mame/drivers/pc8001.cpp
+++ b/src/mame/drivers/pc8001.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Curt Coder
+// copyright-holders:Curt Coder, Angelo Salese
/*
http://www2.odn.ne.jp/~haf09260/Pc80/EnrPc.htm
@@ -12,14 +12,28 @@
TODO:
- - uPD3301 attributes
- - PCG1000
- - Intel 8251
- - cassette
- - floppy
- - PC-8011
- - PC-8021
- - PC-8031
+ - uPD3301 attributes;
+ - PCG-1000;
+ - Intel 8251;
+ - cassette;
+ - dip-switches;
+ - PC-8011 (expansion unit)
+ - PC-8021;
+ - PC-8031 (mini disk unit, in progress)
+ - pc8001mk2sr: verify how much needs to be ported from pc8801.cpp code
+ (Has 3 bitplane GVRAM like PC-8801 V1 mode);
+ - waitstates & DMA penalty (some games are suspciously fast);
+ - buzzer has pretty ugly aliasing in places;
+
+ Notes:
+ - pc8001 v1.01 / v1.02 sports a buggy readout of the expansion ROM at PC=17a1:
+ It expects an header read of 0x41-0x42 at offset $6000-6001, but second read at
+ PC=0x17aa is just a comparison to $6000 == 0x42, which is impossible at that point
+ unless external aid is given. This has been fixed in v1.10;
+ - Color Magical (pc8001gp:flop5 option 7) transfers two 8 color screens at
+ even/odd frame intervals, effectively boosting the number of available colors to 27.
+ This trick is kinda flickery even on real HW, no wonder it looks ugly in MAME,
+ can it be improved?
*/
@@ -28,6 +42,150 @@
#include "screen.h"
#include "speaker.h"
+WRITE_LINE_MEMBER( pc8001_base_state::crtc_reverse_w )
+{
+ // rvv acts as a global flip for reverse attribute meaning
+ // (does not act on underlying palette)
+ // TODO: what happens if RVV changes mid-frame?
+ // I suspect monitor resync more likely than rasters.
+ m_screen_reverse = state;
+}
+
+UPD3301_FETCH_ATTRIBUTE( pc8001_base_state::attr_fetch )
+{
+ const u8 attr_max_size = 80;
+ const bool is_color_mode = gfx_mode == 0x2;
+ std::array<u16, attr_max_size> attr_extend_info = m_crtc->default_attr_fetch(attr_row, gfx_mode, y, attr_fifo_size, row_size);
+
+ // further extend the attributes if we are in color mode
+ if (is_color_mode)
+ {
+ // TODO: defaults
+ // flgworld (pc8001) gameplay sets up:
+ // - 0x00 0x00 0x02 0x88 on playfield
+ // \- (wanting the default from the first defined color)
+ // - 0x00 0x00 0x00 0x48 0x12 0x88 for first row
+ // \- (Expecting "FLAG WORLD" wording to be red while the "P"s in green wtf)
+ // undermon (pc8001) instruction screen sets up:
+ // - 0x00 0x00 0x06 0xb8
+ // \- (expecting blue fill up to 0x06)
+ u8 attr_color = 0xe8;
+ u8 attr_decoration = 0x00;
+
+ for (int ex = 0; ex < row_size; ex++)
+ {
+ u16 cur_attr = attr_extend_info[ex];
+ if (BIT(cur_attr, 3))
+ attr_color = cur_attr;
+ else
+ attr_decoration = cur_attr;
+ attr_extend_info[ex] = (attr_color << 8) | attr_decoration;
+ }
+ }
+
+ return attr_extend_info;
+}
+
+UPD3301_DRAW_CHARACTER_MEMBER( pc8001_base_state::draw_text )
+{
+ // punt if we are in width 40 (discarded on this end)
+ if (sx % 2 && !m_width80)
+ return;
+
+ const bool is_color_mode = gfx_mode == 0x2;
+ u8 tile;
+ const u8 tile_width = m_width80 ? 8 : 16;
+ const u8 dot_width = (m_width80 ^ 1) + 1;
+ const u8 y_double = m_screen_is_24KHz ? 2 : 1;
+ const u8 y_height = y_double * 8;
+
+ bool semigfx_tile, reverse, attr_blink, secret;
+ bool upperline, lowerline;
+ u8 color;
+
+ if (is_color_mode)
+ {
+ color = (attr & 0xe000) >> 13;
+ semigfx_tile = bool(BIT(attr, 12));
+ // bit 7 is used by 2001spc and many others, no effect?
+ }
+ else
+ {
+ color = 7;
+ semigfx_tile = bool(BIT(attr, 7));
+ }
+
+ lowerline = bool(BIT(attr, 5));
+ upperline = bool(BIT(attr, 4));
+ reverse = bool(BIT(attr, 2));
+ attr_blink = bool(BIT(attr, 1));
+ secret = bool(BIT(attr, 0));
+
+ if (semigfx_tile)
+ tile = cc;
+ else
+ {
+ if (lc > y_height - 1)
+ tile = 0;
+ else
+ tile = m_cgrom->base()[(cc << 3) | (lc >> (y_double-1))];
+ }
+
+ // secret blacks out every tile connections,
+ // has lower priority over blinking and other attribute decorations
+ if (secret)
+ tile = 0;
+
+ if (csr)
+ tile ^= 0xff;
+ else if (attr_blink_on && attr_blink)
+ tile = 0;
+
+ // upper/lower line aren't affected by secret and blinking, only reverse
+ // TODO: should downshift chars by one
+ if (lc == 0 && upperline)
+ tile = 0xff;
+
+ if (is_lowestline && lowerline)
+ tile = 0xff;
+
+ if (reverse ^ m_screen_reverse)
+ tile ^= 0xff;
+
+// if (m_width80)
+ {
+ u8 pen;
+
+ for (int xi = 0; xi < tile_width; xi += dot_width)
+ {
+ int res_x = (sx * 8) + xi;
+ if (semigfx_tile)
+ {
+ u8 mask = (xi & (4 << (dot_width - 1))) ? 0x10 : 0x01;
+ mask <<= (lc & (0x3 << y_double)) >> y_double;
+ pen = tile & mask;
+ }
+ else
+ {
+ pen = tile;
+ pen = (pen >> (7 - (xi >> (dot_width - 1)))) & 1;
+ }
+
+ for (int di = 0; di < dot_width; di++)
+ bitmap.pix(y, res_x + di) = m_crtc_palette->pen(pen ? color : 0);
+ }
+ }
+}
+
+uint32_t pc8001_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0, cliprect);
+ // TODO: superimposing
+ // TODO: merging with previous frame for Color Magical (is it driver area?)
+ m_crtc->screen_update(screen, bitmap, cliprect);
+ return 0;
+}
+
/* Read/Write Handlers */
void pc8001_state::port10_w(uint8_t data)
@@ -57,7 +215,7 @@ void pc8001_state::port10_w(uint8_t data)
m_cent_data_out->write(data);
}
-void pc8001_state::port30_w(uint8_t data)
+void pc8001_base_state::port30_w(uint8_t data)
{
/*
@@ -79,9 +237,8 @@ void pc8001_state::port30_w(uint8_t data)
/* color mode */
m_color = BIT(data, 1);
-
- /* cassette motor */
- m_cassette->change_state(BIT(data,3) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+
+ m_cassette->change_state(BIT(data, 3) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
}
void pc8001mk2_state::port31_w(uint8_t data)
@@ -100,6 +257,7 @@ void pc8001mk2_state::port31_w(uint8_t data)
7 background color
*/
+ membank("bank2")->set_entry(data & 1);
}
WRITE_LINE_MEMBER( pc8001_state::write_centronics_busy )
@@ -129,12 +287,13 @@ uint8_t pc8001_state::port40_r()
*/
- uint8_t data = 0x08;
+ uint8_t data = 0x00;
data |= m_centronics_busy;
data |= m_centronics_ack << 1;
data |= m_rtc->data_out_r() << 4;
data |= m_crtc->vrtc_r() << 5;
+ // TODO: enable line from pc80s31k (bit 3, active_low)
return data;
}
@@ -158,15 +317,15 @@ void pc8001_state::port40_w(uint8_t data)
m_centronics->write_strobe(BIT(data, 0));
- m_rtc->clk_w(BIT(data, 2));
m_rtc->stb_w(BIT(data, 1));
+ m_rtc->clk_w(BIT(data, 2));
m_beep->set_state(BIT(data, 5));
}
/* Memory Maps */
-void pc8001_state::pc8001_mem(address_map &map)
+void pc8001_state::pc8001_map(address_map &map)
{
map(0x0000, 0x5fff).bankrw("bank1");
map(0x6000, 0x7fff).bankrw("bank2");
@@ -217,10 +376,10 @@ void pc8001_state::pc8001_io(address_map &map)
// map(0xe6, 0xe6).w(FUNC(pc8001_state::irq_mask_w));
// map(0xe7, 0xe7).w(FUNC(pc8001_state::pc8012_memory_mode_w));
// map(0xe8, 0xfb) unused
- map(0xfc, 0xff).rw(I8255A_TAG, FUNC(i8255_device::read), FUNC(i8255_device::write));
+ map(0xfc, 0xff).m(m_pc80s31, FUNC(pc80s31_device::host_map));
}
-void pc8001mk2_state::pc8001mk2_mem(address_map &map)
+void pc8001mk2_state::pc8001mk2_map(address_map &map)
{
map(0x0000, 0x5fff).bankrw("bank1");
map(0x6000, 0x7fff).bankrw("bank2");
@@ -231,8 +390,8 @@ void pc8001mk2_state::pc8001mk2_mem(address_map &map)
void pc8001mk2_state::pc8001mk2_io(address_map &map)
{
pc8001_io(map);
- map(0x30, 0x30).w(FUNC(pc8001mk2_state::port30_w));
- map(0x31, 0x31).w(FUNC(pc8001mk2_state::port31_w));
+ map(0x30, 0x30).portr("DSW1").w(FUNC(pc8001mk2_state::port30_w));
+ map(0x31, 0x31).portr("DSW2").w(FUNC(pc8001mk2_state::port31_w));
// map(0x5c, 0x5c).w(FUNC(pc8001mk2_state::gram_on_w));
// map(0x5f, 0x5f).w(FUNC(pc8001mk2_state::gram_off_w));
// map(0xe8, 0xe8) kanji_address_lo_w, kanji_data_lo_r
@@ -250,6 +409,40 @@ void pc8001mk2_state::pc8001mk2_io(address_map &map)
// map(0xfb, 0xfb) DMA type 5 inch FDC data register
}
+void pc8001mk2sr_state::port33_w(u8 data)
+{
+ // TODO: needs progressive flush
+#ifdef UNUSED_FUNCTION
+ if (data & 0x80)
+ {
+ membank("bank1")->set_entry(2);
+ membank("bank2")->set_entry(2 | (m_n80sr_bank & 1));
+ }
+ else
+ {
+ membank("bank1")->set_entry(0);
+ membank("bank2")->set_entry(0);
+ }
+#endif
+}
+
+u8 pc8001mk2sr_state::port71_r()
+{
+ return m_n80sr_bank;
+}
+
+void pc8001mk2sr_state::port71_w(u8 data)
+{
+ m_n80sr_bank = data;
+}
+
+void pc8001mk2sr_state::pc8001mk2sr_io(address_map &map)
+{
+ pc8001mk2_io(map);
+ map(0x33, 0x33).w(FUNC(pc8001mk2sr_state::port33_w));
+ map(0x71, 0x71).rw(FUNC(pc8001mk2sr_state::port71_r), FUNC(pc8001mk2sr_state::port71_w));
+}
+
/* Input Ports */
static INPUT_PORTS_START( pc8001 )
@@ -353,60 +546,84 @@ static INPUT_PORTS_START( pc8001 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
- PORT_START("DSW1")
+// PORT_START("DSW1")
INPUT_PORTS_END
-/* uPD3301 Interface */
-
-static const rgb_t PALETTE_PC8001[] =
-{
- rgb_t::black(),
- rgb_t(0x00, 0x00, 0xff),
- rgb_t(0xff, 0x00, 0x00),
- rgb_t(0xff, 0x00, 0xff),
- rgb_t(0x00, 0xff, 0x00),
- rgb_t(0x00, 0xff, 0xff),
- rgb_t(0xff, 0xff, 0x00),
- rgb_t::white()
-};
-
-UPD3301_DRAW_CHARACTER_MEMBER( pc8001_state::pc8001_display_pixels )
-{
- uint8_t data = m_char_rom->base()[(cc << 3) | lc];
-
- if (lc >= 8) return;
- if (csr) data = 0xff;
-
- if (m_width80)
- {
- for (int i = 0; i < 8; i++)
- {
- int color = BIT(data, 7) ^ rvv;
-
- bitmap.pix(y, (sx * 8) + i) = PALETTE_PC8001[color ? 7 : 0];
-
- data <<= 1;
- }
- }
- else
- {
- if (sx % 2) return;
-
- for (int i = 0; i < 8; i++)
- {
- int color = BIT(data, 7) ^ rvv;
-
- bitmap.pix(y, (sx/2 * 16) + (i * 2)) = PALETTE_PC8001[color ? 7 : 0];
- bitmap.pix(y, (sx/2 * 16) + (i * 2) + 1) = PALETTE_PC8001[color ? 7 : 0];
+static INPUT_PORTS_START( pc8001mk2 )
+ PORT_INCLUDE( pc8001 )
+
+ PORT_START("DSW1")
+ PORT_DIPNAME( 0x01, 0x00, "Boot Mode" )
+ PORT_DIPSETTING( 0x00, "N-BASIC" )
+ PORT_DIPSETTING( 0x01, "N80-BASIC" )
+ PORT_DIPNAME( 0x02, 0x02, "DSW1" )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("DSW2")
+ PORT_DIPNAME( 0x01, 0x01, "DSW2" )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+INPUT_PORTS_END
- data <<= 1;
- }
- }
-}
+static INPUT_PORTS_START( pc8001mk2sr )
+ PORT_INCLUDE( pc8001mk2 )
+
+ PORT_MODIFY("DSW1")
+ // This is really a tri-state dip on front panel
+ // BIOS just expects bit 1 to be off for SR mode
+ PORT_DIPNAME( 0x03, 0x02, "Boot Mode" )
+ PORT_DIPSETTING( 0x00, "N80SR-BASIC (duplicate)")
+ PORT_DIPSETTING( 0x01, "N80SR-BASIC" )
+ PORT_DIPSETTING( 0x02, "N-BASIC" )
+ PORT_DIPSETTING( 0x03, "N80-BASIC" )
+ PORT_DIPNAME( 0x04, 0x04, "DSW1" )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+INPUT_PORTS_END
/* 8257 Interface */
-WRITE_LINE_MEMBER( pc8001_state::hrq_w )
+WRITE_LINE_MEMBER( pc8001_base_state::hrq_w )
{
/* HACK - this should be connected to the BUSREQ line of Z80 */
m_maincpu->set_input_line(INPUT_LINE_HALT, state);
@@ -415,7 +632,7 @@ WRITE_LINE_MEMBER( pc8001_state::hrq_w )
m_dma->hlda_w(state);
}
-uint8_t pc8001_state::dma_mem_r(offs_t offset)
+uint8_t pc8001_base_state::dma_mem_r(offs_t offset)
{
address_space &program = m_maincpu->space(AS_PROGRAM);
@@ -424,6 +641,14 @@ uint8_t pc8001_state::dma_mem_r(offs_t offset)
/* Machine Initialization */
+void pc8001_base_state::machine_start()
+{
+ save_item(NAME(m_width80));
+ save_item(NAME(m_color));
+ save_item(NAME(m_screen_reverse));
+ save_item(NAME(m_screen_is_24KHz));
+}
+
void pc8001_state::machine_start()
{
address_space &program = m_maincpu->space(AS_PROGRAM);
@@ -441,6 +666,7 @@ void pc8001_state::machine_start()
membank("bank1")->configure_entry(1, m_rom->base());
program.install_read_bank(0x0000, 0x5fff, membank("bank1"));
program.unmap_write(0x0000, 0x5fff);
+ membank("bank2")->configure_entry(1, m_rom->base() + 0x6000);
switch (m_ram->size())
{
@@ -464,55 +690,81 @@ void pc8001_state::machine_start()
program.install_readwrite_bank(0x0000, 0x5fff, membank("bank1"));
program.install_readwrite_bank(0x6000, 0xbfff, membank("bank2"));
program.install_readwrite_bank(0x8000, 0xffff, membank("bank3"));
- membank("bank2")->set_entry(0);
+// membank("bank2")->set_entry(0);
break;
}
+
+ // PC8001 is 15KHz only
+ set_screen_frequency(false);
+}
+void pc8001_state::machine_reset()
+{
membank("bank1")->set_entry(1);
+ membank("bank2")->set_entry(1);
membank("bank3")->set_entry(0);
+}
- /* register for state saving */
- save_item(NAME(m_width80));
- save_item(NAME(m_color));
+void pc8001mk2sr_state::machine_start()
+{
+ pc8001_state::machine_start();
+
+ membank("bank1")->configure_entry(2, m_n80sr_rom->base());
+ membank("bank2")->configure_entry(2, m_n80sr_rom->base() + 0x6000);
+ membank("bank2")->configure_entry(3, m_n80sr_rom->base() + 0x8000);
+
+ save_item(NAME(m_n80sr_bank));
+}
+
+void pc8001mk2sr_state::machine_reset()
+{
+ pc8001_state::machine_reset();
+
+ //membank("bank1")->set_entry(2);
+ //membank("bank2")->set_entry(2);
}
/* Machine Drivers */
void pc8001_state::pc8001(machine_config &config)
{
+ constexpr XTAL MASTER_CLOCK = XTAL(4'000'000);
+ constexpr XTAL VIDEO_CLOCK = XTAL(14'318'181);
+
/* basic machine hardware */
- Z80(config, m_maincpu, XTAL(4'000'000));
- m_maincpu->set_addrmap(AS_PROGRAM, &pc8001_state::pc8001_mem);
+ Z80(config, m_maincpu, MASTER_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &pc8001_state::pc8001_map);
m_maincpu->set_addrmap(AS_IO, &pc8001_state::pc8001_io);
+ PC80S31(config, m_pc80s31, MASTER_CLOCK);
+ config.set_perfect_quantum(m_maincpu);
+ config.set_perfect_quantum("pc80s31:fdc_cpu");
+
/* video hardware */
- screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER));
- screen.set_refresh_hz(60);
- screen.set_screen_update(UPD3301_TAG, FUNC(upd3301_device::screen_update));
- screen.set_size(640, 220);
- screen.set_visarea(0, 640-1, 0, 200-1);
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_raw(VIDEO_CLOCK, 896, 0, 640, 260, 0, 200);
+ m_screen->set_screen_update(FUNC(pc8001_state::screen_update));
+// m_screen->set_palette(m_crtc_palette);
- /* sound hardware */
- SPEAKER(config, "mono").front_center();
- BEEP(config, m_beep, 2000).add_route(ALL_OUTPUTS, "mono", 0.25);
+ PALETTE(config, m_crtc_palette, palette_device::BRG_3BIT);
- /* devices */
- I8251(config, I8251_TAG, 0);
-
- I8255A(config, I8255A_TAG, 0);
+ UPD3301(config, m_crtc, VIDEO_CLOCK);
+ m_crtc->set_character_width(8);
+ m_crtc->set_display_callback(FUNC(pc8001_state::draw_text));
+ m_crtc->set_attribute_fetch_callback(FUNC(pc8001_state::attr_fetch));
+ m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w));
+ m_crtc->rvv_wr_callback().set(FUNC(pc8001_state::crtc_reverse_w));
+ m_crtc->set_screen(m_screen);
- I8257(config, m_dma, XTAL(4'000'000));
+ I8257(config, m_dma, MASTER_CLOCK);
m_dma->out_hrq_cb().set(FUNC(pc8001_state::hrq_w));
m_dma->in_memr_cb().set(FUNC(pc8001_state::dma_mem_r));
m_dma->out_iow_cb<2>().set(m_crtc, FUNC(upd3301_device::dack_w));
- UPD1990A(config, m_rtc);
+ /* devices */
+ I8251(config, I8251_TAG, 0);
- UPD3301(config, m_crtc, XTAL(14'318'181));
- m_crtc->set_character_width(8);
- m_crtc->set_display_callback(FUNC(pc8001_state::pc8001_display_pixels));
- m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w));
- m_crtc->set_screen(SCREEN_TAG);
+ UPD1990A(config, m_rtc);
CENTRONICS(config, m_centronics, centronics_devices, "printer");
m_centronics->ack_handler().set(FUNC(pc8001_state::write_centronics_ack));
@@ -526,84 +778,91 @@ void pc8001_state::pc8001(machine_config &config)
m_cassette->add_route(ALL_OUTPUTS, "mono", 0.05);
RAM(config, RAM_TAG).set_default_size("16K").set_extra_options("32K,64K");
-}
-
-void pc8001mk2_state::pc8001mk2(machine_config &config)
-{
- /* basic machine hardware */
- Z80(config, m_maincpu, XTAL(4'000'000));
- m_maincpu->set_addrmap(AS_PROGRAM, &pc8001mk2_state::pc8001mk2_mem);
- m_maincpu->set_addrmap(AS_IO, &pc8001mk2_state::pc8001mk2_io);
- /* video hardware */
- screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER));
- screen.set_refresh_hz(60);
- screen.set_screen_update(UPD3301_TAG, FUNC(upd3301_device::screen_update));
- screen.set_size(640, 220);
- screen.set_visarea(0, 640-1, 0, 200-1);
+ SOFTWARE_LIST(config, "disk_n_list").set_original("pc8001_flop");
/* sound hardware */
SPEAKER(config, "mono").front_center();
- BEEP(config, m_beep, 2000).add_route(ALL_OUTPUTS, "mono", 0.25);
-
- /* devices */
- I8251(config, I8251_TAG, 0);
+ // TODO: unknown clock, is it really a beeper?
+ BEEP(config, m_beep, 2400).add_route(ALL_OUTPUTS, "mono", 0.25);
+}
- I8255A(config, I8255A_TAG, 0);
+void pc8001mk2_state::pc8001mk2(machine_config &config)
+{
+ pc8001(config);
+ m_maincpu->set_addrmap(AS_PROGRAM, &pc8001mk2_state::pc8001mk2_map);
+ m_maincpu->set_addrmap(AS_IO, &pc8001mk2_state::pc8001mk2_io);
- I8257(config, m_dma, XTAL(4'000'000));
- m_dma->out_hrq_cb().set(FUNC(pc8001_state::hrq_w));
- m_dma->in_memr_cb().set(FUNC(pc8001_state::dma_mem_r));
- m_dma->out_iow_cb<2>().set(m_crtc, FUNC(upd3301_device::dack_w));
+ // TODO: video HW has extra GVRAM setup
- UPD1990A(config, m_rtc);
+ RAM(config.replace(), RAM_TAG).set_default_size("64K");
- UPD3301(config, m_crtc, XTAL(14'318'181));
- m_crtc->set_character_width(8);
- m_crtc->set_display_callback(FUNC(pc8001_state::pc8001_display_pixels));
- m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w));
- m_crtc->set_screen(SCREEN_TAG);
-
- CENTRONICS(config, m_centronics, centronics_devices, "printer");
+ SOFTWARE_LIST(config, "disk_n80_list").set_original("pc8001mk2_flop");
+}
- OUTPUT_LATCH(config, m_cent_data_out);
- m_centronics->set_output_latch(*m_cent_data_out);
+void pc8001mk2sr_state::pc8001mk2sr(machine_config &config)
+{
+ pc8001mk2(config);
+ m_maincpu->set_addrmap(AS_IO, &pc8001mk2sr_state::pc8001mk2sr_io);
- CASSETTE(config, m_cassette);
- m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
- m_cassette->add_route(ALL_OUTPUTS, "mono", 0.05);
+ // TODO: mods for SR mode support
- RAM(config, RAM_TAG).set_default_size("64K");
+ SOFTWARE_LIST(config, "disk_n80sr_list").set_original("pc8001mk2sr_flop");
}
/* ROMs */
ROM_START( pc8001 )
- ROM_REGION( 0x6000, Z80_TAG, 0 )
+ ROM_REGION( 0x8000, Z80_TAG, ROMREGION_ERASEFF )
+ // PCB pictures shows divided by 3 ROMs (and 4th socket unpopulated)
ROM_SYSTEM_BIOS( 0, "v101", "N-BASIC v1.01" )
- ROMX_LOAD( "n80v101.rom", 0x00000, 0x6000, CRC(a2cc9f22) SHA1(6d2d838de7fea20ddf6601660d0525d5b17bf8a3), ROM_BIOS(0) )
+ ROMX_LOAD( "n80v101.rom", 0x00000, 0x6000, BAD_DUMP CRC(a2cc9f22) SHA1(6d2d838de7fea20ddf6601660d0525d5b17bf8a3), ROM_BIOS(0) )
ROM_SYSTEM_BIOS( 1, "v102", "N-BASIC v1.02" )
- ROMX_LOAD( "n80v102.rom", 0x00000, 0x6000, CRC(ed01ca3f) SHA1(b34a98941499d5baf79e7c0e5578b81dbede4a58), ROM_BIOS(1) )
+ ROMX_LOAD( "n80v102.rom", 0x00000, 0x6000, BAD_DUMP CRC(ed01ca3f) SHA1(b34a98941499d5baf79e7c0e5578b81dbede4a58), ROM_BIOS(1) )
ROM_SYSTEM_BIOS( 2, "v110", "N-BASIC v1.10" )
- ROMX_LOAD( "n80v110.rom", 0x00000, 0x6000, CRC(1e02d93f) SHA1(4603cdb7a3833e7feb257b29d8052c872369e713), ROM_BIOS(2) )
+ ROMX_LOAD( "n80v110.rom", 0x00000, 0x6000, BAD_DUMP CRC(1e02d93f) SHA1(4603cdb7a3833e7feb257b29d8052c872369e713), ROM_BIOS(2) )
- ROM_REGION( 0x800, UPD3301_TAG, 0)
+ ROM_REGION( 0x800, CGROM_TAG, 0)
ROM_LOAD( "font.rom", 0x000, 0x800, CRC(56653188) SHA1(84b90f69671d4b72e8f219e1fe7cd667e976cf7f) )
ROM_END
ROM_START( pc8001mk2 )
ROM_REGION( 0x8000, Z80_TAG, 0 )
- ROM_LOAD( "n80_2.rom", 0x00000, 0x8000, CRC(03cce7b6) SHA1(c12d34e42021110930fed45a8af98db52136f1fb) )
+ // N-BASIC v1.3
+ // N80-BASIC v1.0
+ ROM_LOAD( "n80_2.rom", 0x0000, 0x8000, CRC(03cce7b6) SHA1(c12d34e42021110930fed45a8af98db52136f1fb) )
- ROM_REGION( 0x800, UPD3301_TAG, 0)
+ ROM_REGION( 0x800, CGROM_TAG, 0)
ROM_LOAD( "font.rom", 0x0000, 0x0800, CRC(56653188) SHA1(84b90f69671d4b72e8f219e1fe7cd667e976cf7f) )
ROM_REGION( 0x20000, "kanji", 0)
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_END
+ROM_START( pc8001mk2sr )
+ ROM_REGION( 0x8000, Z80_TAG, 0 )
+ // N-BASIC v1.6
+ // N80-BASIC v1.2
+ ROM_LOAD( "n80_2sr.rom", 0x0000, 0x8000, CRC(dcb71282) SHA1(e8db5dc5eae11da14e48656d324874e59f2e3844) )
+
+ ROM_REGION (0x10000, N80SR_ROM_TAG, ROMREGION_ERASEFF )
+ // N80SR-BASIC v1.0
+ ROM_LOAD( "n80_3.rom", 0x0000, 0xa000, BAD_DUMP CRC(d99ef247) SHA1(9bfa5009d703cd31caa734d932d2a847d74cbfa6) )
+
+ ROM_REGION( 0x2000, CGROM_TAG, 0)
+ ROM_LOAD( "font80sr.rom", 0x000000, 0x001000, CRC(784c0b17) SHA1(565dc8e5e46b1633cb434d12b4d8b3a662546b33) )
+ ROM_LOAD( "fonthira.rom", 0x001000, 0x000800, CRC(fe7059d5) SHA1(10c5f85adcce540cbd0a11352e2c38a84c989a26) )
+ ROM_LOAD( "fontkata.rom", 0x001800, 0x000800, CRC(56653188) SHA1(84b90f69671d4b72e8f219e1fe7cd667e976cf7f) )
+
+ ROM_REGION( 0x20000, "kanji", 0)
+ ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
+ROM_END
+
/* System Drivers */
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
-COMP( 1979, pc8001, 0, 0, pc8001, pc8001, pc8001_state, empty_init, "NEC", "PC-8001", MACHINE_NOT_WORKING )
-COMP( 1983, pc8001mk2, pc8001, 0, pc8001mk2, pc8001, pc8001mk2_state, empty_init, "NEC", "PC-8001mkII", MACHINE_NOT_WORKING )
+// 1978?, pc8001g, Wirewrapped prototype version
+COMP( 1979, pc8001, 0, 0, pc8001, pc8001, pc8001_state, empty_init, "NEC", "PC-8001", MACHINE_NOT_WORKING )
+// 1981 pc8001a, US version of PC-8001 with Greek alphabet instead of Kana
+COMP( 1983, pc8001mk2, pc8001, 0, pc8001mk2, pc8001mk2, pc8001mk2_state, empty_init, "NEC", "PC-8001mkII", MACHINE_NOT_WORKING )
+COMP( 1985, pc8001mk2sr, pc8001, 0, pc8001mk2sr, pc8001mk2sr, pc8001mk2sr_state, empty_init, "NEC", "PC-8001mkIISR", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/pc8801.cpp b/src/mame/drivers/pc8801.cpp
index a50c1d6317f..8746a52fb41 100644
--- a/src/mame/drivers/pc8801.cpp
+++ b/src/mame/drivers/pc8801.cpp
@@ -25,29 +25,17 @@
probably others (does bus have an actual codename or just "PC-8801 bus"?);
- below notes states that plain PC-8801 doesn't have a disk CPU, but the BIOS clearly checks
the floppy ports. Wrong info or check for external board anyway?
- - fix "jumps" in mouse support pointer (noticeable in Balance of Power);
-
- per-game specific TODO:
- - 100yen Soft 8 Revival Special: tight loop with vblank bit, but vblank irq takes too much time to execute its code;
- - 177: gameplay is too fast (parent pc8801 only);
- - 1942: missing sound, enables a masked irq;
- - Acro Jet: hangs waiting for an irq (floppy issue);
- - Arcus: doesn't surpass Wolf Team logo;
- - Advanced Fantasian: garbage during gameplay (floppy?)
- - American Success: reads the light pen?
- - Attacker: resets after a bunch of animation frames;
- - Balance of Power: uses the SIO port for something ...
+ - fix "jumps" in PC-8872 mouse pointer (noticeable in balpower);
+
+ per-game specific TODO (move to XML):
- Belloncho Shintai Kensa: hangs
- Bishoujo Baseball Gakuen: checks ym2608 after intro screen;
- The Black Onyx: writes a katakana msg: "sono kata ha koko ni orimasen" then doesn't show up anything. (Needs user disk?)
- - Boukenshatachi: dies after the intro.
- Campaign Ban Daisenryaku 2: Hangs at title screen?
- - Carigraph: inputs doesn't work?
- Can Can Bunny: bitmap artifacts on intro, caused by a fancy usage of the attribute vram;
- Can Can Bunny: no sound (regression);
- Can Can Bunny Superior: black screen during the intro
- Chou Bishoujo Densetsu CROQUIS: accesses ports 0xa0-0xa3 and 0xc2-0xc3
- - Combat: mono gfx mode enabled, but I don't see any noticeable quirk?
- Cranston Manor (actually N88-Basic demo): no sound
- Datenshi Kyouko: gfx garbage on the right edge?
- Final Crisis: sound stuck with OPNA?
@@ -56,10 +44,7 @@
- Gaudi - Barcelona no Kaze: fails PCM loading
- GeGeGe no Kitarou: title screen text/bitmap contrast is pretty ugly (BTANB?);
- Grobda: palette is ugly (parent pc8801 only);
- - Makaimura: after losing a life the game doesn't work properly anymore, copy protection?
- Music Collection Vol. 2 - Final Fantasy Tokushuu: sound irq dies pretty soon
- - N-BASIC: cursor doesn't show up;
- - The Return of Ishtar: z80 exception after entering the name.
- Star Cruiser: bad kanji data?
- Star Cruiser: reads at i/o 0x8e?
- Wanderers from Ys: user data disk looks screwed? It loads with everything as maximum as per now ...
@@ -120,11 +105,6 @@
- Fruit Panic
- FSD Sample Ongaku Shuu Vol. 1-7
- Gaia no Kiba (Disk I/O error at 150)
- - Gaiflame
- - Gambler Jiko Chuushin ha
- - Gambler Jiko Chuushin ha 2
- - Gambler Jiko Chuushin ha 3
- - Gambler Jiko Chuushin ha 3 (demo)
- Gambler Jiko Chuushin ha Mahjong Puzzle Collection
- Gambler Jiko Chuushin ha Mahjong Puzzle Collection (demo)
* Game Music Library
@@ -142,14 +122,12 @@
* MakaiMura (attempts to r/w the sio ports, but it's clearly crashed)
* Mugen Senshi Valis (at Telenet logo, it also appears to have a nasty copy protection when taking a specific item (untested))
- Mr. Pro Yakyuu
- - Panorama Toh
- PC-8034 (app)
- PC-8037SR (app)
- P1 (app)
- Pattern Editor 88 (app)
- Super Shunbo II (app) (Load error)
- Super TII (app)
- * The Return of Ishtar
- Tobira wo Akete (random crashes in parent pc8801 only)
list of games that doesn't like i8214_irq_level == 5 in sound irq
@@ -360,6 +338,8 @@ void pc8801_state::draw_bitmap_3bpp(bitmap_ind16 &bitmap,const rectangle &clipre
void pc8801_state::draw_bitmap_1bpp(bitmap_ind16 &bitmap,const rectangle &cliprect)
{
+ // TODO: jettermi really masks the color attribute from 3301
+ // (we currently draw it in b&w, should be colorized)
uint32_t count = 0;
uint8_t color = (m_gfx_ctrl & 1) ? 7 & ((m_layer_mask ^ 0xe) >> 1) : 7;
uint8_t is_cursor = 0;
@@ -675,7 +655,7 @@ void pc8801_state::pc8801_alu_w(offs_t offset, uint8_t data)
for(i=0;i<3;i++)
{
logic_op = (m_alu_ctrl1 & (0x11 << i)) >> i;
-
+
switch(logic_op)
{
case 0x00: { m_gvram[i*0x4000 + offset] &= ~data; } break;
@@ -803,9 +783,7 @@ uint8_t pc8801_state::pc8801_mem_r(offs_t offset)
window_offset = (offset & 0x3ff) + (m_window_offset_bank << 8);
- if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10))
- printf("Read from 0xf000 - 0xffff window offset\n"); //accessed by Castle Excellent, no noticeable quirk
-
+ // castlex and imenes accesses this
if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10))
return pc8801_high_wram_r(window_offset & 0xfff);
@@ -864,9 +842,9 @@ void pc8801_state::pc8801_mem_w(offs_t offset, uint8_t data)
window_offset = (offset & 0x3ff) + (m_window_offset_bank << 8);
- if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10))
- printf("Write to 0xf000 - 0xffff window offset\n"); //accessed by Castle Excellent, no noticeable quirk
-
+ // castlex and imenes accesses this
+ // TODO: high TVRAM even
+ // (uPD3301 reads from this instead of the regular work RAM)
if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10))
pc8801_high_wram_w(window_offset & 0xfff,data);
else
@@ -1117,6 +1095,20 @@ void pc8801_state::pc8801_window_bank_inc_w(uint8_t data)
m_window_offset_bank&=0xff;
}
+/*
+ * I/O Port $32 (R/W)
+ *
+ * x--- ---- sound irq mask (0) irq enabled (1) irq masked
+ * -x-- ---- Graphic VRAM access mode (0) independent access mode (1) ALU mode
+ * --x- ---- analog (1) / digital (0) palette select
+ * ---x ---- high speed RAM select (for TVRAM) (1) main RAM bank (0) dedicated Text RAM
+ * ---- xx-- Screen output mode
+ * ---- 00-- TV / video mode
+ * ---- 01-- None (as in disabling the screen entirely?)
+ * ---- 10-- Analog RGB mode
+ * ---- 11-- Optional mode
+ * ---- --xx internal EROM selection
+ */
uint8_t pc8801_state::pc8801_misc_ctrl_r()
{
return m_misc_ctrl;
@@ -1124,11 +1116,6 @@ uint8_t pc8801_state::pc8801_misc_ctrl_r()
void pc8801_state::pc8801_misc_ctrl_w(uint8_t data)
{
- /*
- x--- ---- sound irq mask, active low
- --x- ---- analog (1) / digital (0) palette select
- */
-
m_misc_ctrl = data;
#if USE_PROPER_I8214
@@ -1182,6 +1169,7 @@ void pc8801_state::pc8801_palram_w(offs_t offset, uint8_t data)
// TODO: What happens to the palette contents when the analog/digital palette mode changes?
// Preserve content? Translation? Undefined?
m_palette->set_pen_color(offset, pal3bit(m_palram[offset].r), pal3bit(m_palram[offset].g), pal3bit(m_palram[offset].b));
+ // TODO: at least analog mode can do rasters
}
void pc8801_state::pc8801_layer_masking_w(uint8_t data)
@@ -1472,7 +1460,7 @@ uint8_t pc8801_state::pc8801_sound_board_r(offs_t offset)
void pc8801_state::pc8801_sound_board_w(offs_t offset, uint8_t data)
{
if(m_has_opna)
- m_opna->write(offset,data);
+ m_opna->write(offset, data);
else if((offset & 2) == 0)
m_opn->write(offset, data);
}
@@ -1590,95 +1578,7 @@ void pc8801_state::pc8801_io(address_map &map)
// map(0xf3, 0xf3).noprw(); /* DMA floppy (unknown) */
// map(0xf4, 0xf7).noprw(); /* DMA 5'floppy (may be not released) */
// map(0xf8, 0xfb).noprw(); /* DMA 8'floppy (unknown) */
- map(0xfc, 0xff).rw("d8255_master", FUNC(i8255_device::read), FUNC(i8255_device::write));
-}
-
-uint8_t pc8801_state::cpu_8255_c_r()
-{
-// machine().scheduler().synchronize(); // force resync
-
- return m_i8255_1_pc >> 4;
-}
-
-void pc8801_state::cpu_8255_c_w(uint8_t data)
-{
-// machine().scheduler().synchronize(); // force resync
-
- m_i8255_0_pc = data;
-}
-
-
-uint8_t pc8801_state::fdc_8255_c_r()
-{
-// machine().scheduler().synchronize(); // force resync
-
- return m_i8255_0_pc >> 4;
-}
-
-void pc8801_state::fdc_8255_c_w(uint8_t data)
-{
-// machine().scheduler().synchronize(); // force resync
-
- m_i8255_1_pc = data;
-}
-
-void pc8801_state::pc8801fdc_mem(address_map &map)
-{
- map(0x0000, 0x1fff).rom();
- map(0x4000, 0x7fff).ram();
-}
-
-TIMER_CALLBACK_MEMBER(pc8801_state::pc8801fd_upd765_tc_to_zero)
-{
- // TODO: holein1 explictly reads TC port at PC=504e followed by an HALT opcode, failing to boot
- // is this gonna unbreak HALT state too?
- m_fdc->tc_w(false);
-}
-
-void pc8801_state::upd765_mc_w(uint8_t data)
-{
- m_fdd[0]->get_device()->mon_w(!(data & 1));
- m_fdd[1]->get_device()->mon_w(!(data & 2));
-}
-
-uint8_t pc8801_state::upd765_tc_r()
-{
- //printf("%04x 1\n",m_fdccpu->pc());
-
- if (!machine().side_effects_disabled())
- {
- m_fdc->tc_w(true);
- //TODO: I'm not convinced that this works correctly with current hook-up ... 1000 usec is needed by Aploon, a bigger value breaks Alpha.
- //OTOH, 50 seems more than enough for the new upd...
- machine().scheduler().timer_set(attotime::from_usec(50), timer_expired_delegate(FUNC(pc8801_state::pc8801fd_upd765_tc_to_zero),this));
- }
- return 0xff; // value is meaningless
-}
-
-void pc8801_state::fdc_irq_vector_w(uint8_t data)
-{
- popmessage("Write to FDC IRQ vector I/O %02x, contact MESSdev\n",data);
- m_fdc_irq_opcode = data;
-}
-
-void pc8801_state::fdc_drive_mode_w(uint8_t data)
-{
- logerror("FDC drive mode %02x\n", data);
- m_fdd[0]->get_device()->set_rpm(data & 0x01 ? 360 : 300);
- m_fdd[1]->get_device()->set_rpm(data & 0x02 ? 360 : 300);
-
- m_fdc->set_rate(data & 0x20 ? 500000 : 250000);
-}
-
-void pc8801_state::pc8801fdc_io(address_map &map)
-{
- map.global_mask(0xff);
- map(0xf0, 0xf0).w(FUNC(pc8801_state::fdc_irq_vector_w)); // Interrupt Opcode Port
- map(0xf4, 0xf4).w(FUNC(pc8801_state::fdc_drive_mode_w)); // Drive mode, 2d, 2dd, 2hd
- map(0xf7, 0xf7).nopw(); // printer port output
- map(0xf8, 0xf8).rw(FUNC(pc8801_state::upd765_tc_r), FUNC(pc8801_state::upd765_mc_w)); // (R) Terminal Count Port (W) Motor Control Port
- map(0xfa, 0xfb).m(m_fdc, FUNC(upd765a_device::map));
- map(0xfc, 0xff).rw("d8255_slave", FUNC(i8255_device::read), FUNC(i8255_device::write));
+ map(0xfc, 0xff).m(m_pc80s31, FUNC(pc80s31_device::host_map));
}
void pc8801_state::opna_map(address_map &map)
@@ -2005,12 +1905,6 @@ static GFXDECODE_START( gfx_pc8801 )
GFXDECODE_ENTRY( "kanji", 0, kanji_layout, 0, 8 )
GFXDECODE_END
-/* Floppy Configuration */
-
-static void pc88_floppies(device_slot_interface &device)
-{
- device.option_add("525hd", FLOPPY_525_HD);
-}
#if 0
/* Cassette Configuration */
@@ -2164,10 +2058,6 @@ INTERRUPT_GEN_MEMBER(pc8801_state::pc8801_vrtc_irq)
void pc8801_state::machine_start()
{
- m_fdd[0]->get_device()->set_rpm(300);
- m_fdd[1]->get_device()->set_rpm(300);
- m_fdc->set_rate(250000);
-
m_rtc->cs_w(1);
m_rtc->oe_w(1);
@@ -2203,11 +2093,8 @@ void pc8801_state::machine_reset()
// pc8801_dynamic_res_change(machine());
- m_fdc_irq_opcode = 0; //TODO: copied from PC-88VA, could be wrong here ... should be 0x7f ld a,a in the latter case
m_mouse.phase = 0;
- m_fdccpu->set_input_line_vector(0, 0); // Z80
-
{
m_txt_color = 2;
}
@@ -2277,7 +2164,8 @@ MACHINE_RESET_MEMBER(pc8801_state,pc8801_clock_speed)
m_clock_setting = ioport("CFG")->read() & 0x80;
m_maincpu->set_unscaled_clock(m_clock_setting ? XTAL(4'000'000) : XTAL(8'000'000));
- m_fdccpu->set_unscaled_clock(m_clock_setting ? XTAL(4'000'000) : XTAL(8'000'000)); // correct?
+ // TODO: FDC board shouldn't be connected to the clock setting, verify
+// m_fdccpu->set_unscaled_clock(m_clock_setting ? XTAL(4'000'000) : XTAL(8'000'000));
m_baudrate_val = 0;
}
@@ -2348,28 +2236,11 @@ void pc8801_state::pc8801(machine_config &config)
m_maincpu->set_vblank_int("screen", FUNC(pc8801_state::pc8801_vrtc_irq));
m_maincpu->set_irq_acknowledge_callback(FUNC(pc8801_state::pc8801_irq_callback));
- /* sub CPU(5 inch floppy drive) */
- Z80(config, m_fdccpu, MASTER_CLOCK); /* 4 MHz */
- m_fdccpu->set_addrmap(AS_PROGRAM, &pc8801_state::pc8801fdc_mem);
- m_fdccpu->set_addrmap(AS_IO, &pc8801_state::pc8801fdc_io);
-
- //config.set_maximum_quantum(attotime::from_hz(300000));
+ PC80S31(config, m_pc80s31, MASTER_CLOCK);
config.set_perfect_quantum(m_maincpu);
+ config.set_perfect_quantum("pc80s31:fdc_cpu");
- i8255_device &d8255_master(I8255(config, "d8255_master"));
- d8255_master.in_pa_callback().set("d8255_slave", FUNC(i8255_device::pb_r));
- d8255_master.in_pb_callback().set("d8255_slave", FUNC(i8255_device::pa_r));
- d8255_master.in_pc_callback().set(FUNC(pc8801_state::cpu_8255_c_r));
- d8255_master.out_pc_callback().set(FUNC(pc8801_state::cpu_8255_c_w));
-
- i8255_device &d8255_slave(I8255(config, "d8255_slave"));
- d8255_slave.in_pa_callback().set("d8255_master", FUNC(i8255_device::pb_r));
- d8255_slave.in_pb_callback().set("d8255_master", FUNC(i8255_device::pa_r));
- d8255_slave.in_pc_callback().set(FUNC(pc8801_state::fdc_8255_c_r));
- d8255_slave.out_pc_callback().set(FUNC(pc8801_state::fdc_8255_c_w));
-
- UPD765A(config, m_fdc, 8'000'000, true, true);
- m_fdc->intrq_wr_callback().set_inputline(m_fdccpu, INPUT_LINE_IRQ0);
+// config.set_maximum_quantum(attotime::from_hz(MASTER_CLOCK/1024));
#if USE_PROPER_I8214
I8214(config, I8214_TAG, MASTER_CLOCK);
@@ -2386,9 +2257,8 @@ void pc8801_state::pc8801(machine_config &config)
i8251.txd_handler().set(FUNC(pc8801_state::txdata_callback));
i8251.rts_handler().set(FUNC(pc8801_state::rxrdy_w));
- FLOPPY_CONNECTOR(config, "upd765:0", pc88_floppies, "525hd", floppy_image_device::default_mfm_floppy_formats);
- FLOPPY_CONNECTOR(config, "upd765:1", pc88_floppies, "525hd", floppy_image_device::default_mfm_floppy_formats);
- SOFTWARE_LIST(config, "disk_list").set_original("pc8801_flop");
+ SOFTWARE_LIST(config, "disk_n88_list").set_original("pc8801_flop");
+ SOFTWARE_LIST(config, "disk_n_list").set_original("pc8001_flop");
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
@@ -2431,21 +2301,27 @@ void pc8801_state::pc8801(machine_config &config)
TIMER(config, "rtc_timer").configure_periodic(FUNC(pc8801_state::pc8801_rtc_irq), attotime::from_hz(600));
}
-void pc8801_state::pc8801fh(machine_config &config)
+void pc8801_state::pc8801mk2mr(machine_config &config)
{
pc8801(config);
+ PC80S31K(config.replace(), m_pc80s31, MASTER_CLOCK);
+}
+
+void pc8801_state::pc8801fh(machine_config &config)
+{
+ pc8801mk2mr(config);
MCFG_MACHINE_RESET_OVERRIDE(pc8801_state, pc8801_clock_speed )
}
void pc8801_state::pc8801ma(machine_config &config)
{
- pc8801(config);
+ pc8801fh(config);
MCFG_MACHINE_RESET_OVERRIDE(pc8801_state, pc8801_dic )
}
void pc8801_state::pc8801mc(machine_config &config)
{
- pc8801(config);
+ pc8801ma(config);
MCFG_MACHINE_RESET_OVERRIDE(pc8801_state, pc8801_cdrom )
}
@@ -2457,9 +2333,6 @@ ROM_START( pc8801 )
ROM_LOAD( "n88.rom", 0x0000, 0x8000, CRC(ffd68be0) SHA1(3518193b8207bdebf22c1380c2db8c554baff329) )
ROM_LOAD( "n88_0.rom", 0x8000, 0x2000, CRC(61984bab) SHA1(d1ae642aed4f0584eeb81ff50180db694e5101d4) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f) )
-
ROM_REGION( 0x40000, "kanji", ROMREGION_ERASEFF)
ROM_LOAD_OPTIONAL( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
@@ -2477,9 +2350,6 @@ ROM_START( pc8801mk2 )
ROM_LOAD( "m2_n88.rom", 0x0000, 0x8000, CRC(f35169eb) SHA1(ef1f067f819781d9fb2713836d195866f0f81501) )
ROM_LOAD( "m2_n88_0.rom", 0x8000, 0x2000, CRC(5eb7a8d0) SHA1(95a70af83b0637a5a0f05e31fb0452bb2cb68055) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f) )
-
ROM_REGION( 0x40000, "kanji", ROMREGION_ERASEFF)
ROM_LOAD_OPTIONAL( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
@@ -2498,13 +2368,6 @@ ROM_START( pc8801mk2sr )
ROM_LOAD( "n88_2.rom", 0xc000, 0x2000, CRC(af2b6efa) SHA1(b7c8bcea219b77d9cc3ee0efafe343cc307425d1) )
ROM_LOAD( "n88_3.rom", 0xe000, 0x2000, CRC(7713c519) SHA1(efce0b51cab9f0da6cf68507757f1245a2867a72) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f) )
-
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0)
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_LOAD( "kanji2.rom", 0x20000, 0x20000, CRC(154803cc) SHA1(7e6591cd465cbb35d6d3446c5a83b46d30fafe95) ) // it should not be here
@@ -2524,13 +2387,6 @@ ROM_START( pc8801mk2fr )
ROM_LOAD( "m2fr_n88_2.rom", 0xc000, 0x2000, CRC(98c3a7b2) SHA1(fc4980762d3caa56964d0ae583424756f511d186) )
ROM_LOAD( "m2fr_n88_3.rom", 0xe000, 0x2000, CRC(0ca08abd) SHA1(a5a42d0b7caa84c3bc6e337c9f37874d82f9c14b) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "m2fr_disk.rom", 0x0000, 0x0800, CRC(2163b304) SHA1(80da2dee49d4307f00895a129a5cfeff00cf5321) )
-
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0)
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
@@ -2549,13 +2405,6 @@ ROM_START( pc8801mk2mr )
ROM_LOAD( "m2mr_n88_2.rom", 0xc000, 0x2000, CRC(11176e0b) SHA1(f13f14f3d62df61498a23f7eb624e1a646caea45) )
ROM_LOAD( "m2mr_n88_3.rom", 0xe000, 0x2000, CRC(0ca08abd) SHA1(a5a42d0b7caa84c3bc6e337c9f37874d82f9c14b) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "m2mr_disk.rom", 0x0000, 0x2000, CRC(2447516b) SHA1(1492116f15c426f9796dc2bb6fcccf2656c0ca75) )
-
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0)
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_LOAD( "m2mr_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) )
@@ -2575,13 +2424,6 @@ ROM_START( pc8801mh )
ROM_LOAD( "mh_n88_2.rom", 0xc000, 0x2000, CRC(6aa6b6d8) SHA1(2a077ab444a4fd1470cafb06fd3a0f45420c39cc) )
ROM_LOAD( "mh_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "mh_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) )
-
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0)
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_LOAD( "mh_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) )
@@ -2601,13 +2443,6 @@ ROM_START( pc8801fa )
ROM_LOAD( "fa_n88_2.rom", 0xc000, 0x2000, CRC(6aee9a4e) SHA1(e94278682ef9e9bbb82201f72c50382748dcea2a) )
ROM_LOAD( "fa_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "fa_disk.rom", 0x0000, 0x0800, CRC(2163b304) SHA1(80da2dee49d4307f00895a129a5cfeff00cf5321) )
-
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0 )
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_LOAD( "fa_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) )
@@ -2627,13 +2462,6 @@ ROM_START( pc8801ma ) // newer floppy BIOS and Jisyo (dictionary) ROM
ROM_LOAD( "ma_n88_2.rom", 0xc000, 0x2000, CRC(6aee9a4e) SHA1(e94278682ef9e9bbb82201f72c50382748dcea2a) )
ROM_LOAD( "ma_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "ma_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) )
-
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0 )
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_LOAD( "ma_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) )
@@ -2657,13 +2485,6 @@ ROM_START( pc8801ma2 )
ROM_LOAD( "ma2_n88_2.rom", 0xc000, 0x2000, CRC(1d6277b6) SHA1(dd9c3e50169b75bb707ef648f20d352e6a8bcfe4) )
ROM_LOAD( "ma2_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "ma2_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) )
-
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0)
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_LOAD( "ma2_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) )
@@ -2686,16 +2507,9 @@ ROM_START( pc8801mc )
ROM_LOAD( "mc_n88_2.rom", 0xc000, 0x2000, CRC(1d6277b6) SHA1(dd9c3e50169b75bb707ef648f20d352e6a8bcfe4) )
ROM_LOAD( "mc_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) )
- ROM_REGION( 0x10000, "fdccpu", 0)
- ROM_LOAD( "mc_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) )
-
ROM_REGION( 0x10000, "cdrom", 0 )
ROM_LOAD( "cdbios.rom", 0x0000, 0x10000, CRC(5c230221) SHA1(6394a8a23f44ea35fcfc3e974cf940bc8f84d62a) )
- /* No idea of the proper size: it has never been dumped */
- ROM_REGION( 0x2000, "audiocpu", 0)
- ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP )
-
ROM_REGION( 0x40000, "kanji", 0 )
ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) )
ROM_LOAD( "mc_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) )
@@ -2716,15 +2530,15 @@ COMP( 1983, pc8801mk2, pc8801, 0, pc8801, pc88sr, pc8801_state, empt
COMP( 1985, pc8801mk2sr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIISR", MACHINE_NOT_WORKING )
//COMP( 1985, pc8801mk2tr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIITR", MACHINE_NOT_WORKING )
COMP( 1985, pc8801mk2fr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIIFR", MACHINE_NOT_WORKING )
-COMP( 1985, pc8801mk2mr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIIMR", MACHINE_NOT_WORKING )
+COMP( 1985, pc8801mk2mr, pc8801, 0, pc8801mk2mr, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIIMR", MACHINE_NOT_WORKING )
-//COMP( 1986, pc8801fh, 0, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FH", MACHINE_NOT_WORKING )
+//COMP( 1986, pc8801fh, 0, 0, pc8801mk2fr, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FH", MACHINE_NOT_WORKING )
COMP( 1986, pc8801mh, pc8801, 0, pc8801fh, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MH", MACHINE_NOT_WORKING )
COMP( 1987, pc8801fa, pc8801, 0, pc8801fh, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FA", MACHINE_NOT_WORKING )
COMP( 1987, pc8801ma, pc8801, 0, pc8801ma, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MA", MACHINE_NOT_WORKING )
-//COMP( 1988, pc8801fe, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE", MACHINE_NOT_WORKING )
+//COMP( 1988, pc8801fe, pc8801, 0, pc8801fa, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE", MACHINE_NOT_WORKING )
COMP( 1988, pc8801ma2, pc8801, 0, pc8801ma, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MA2", MACHINE_NOT_WORKING )
-//COMP( 1989, pc8801fe2, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE2", MACHINE_NOT_WORKING )
+//COMP( 1989, pc8801fe2, pc8801, 0, pc8801fa, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE2", MACHINE_NOT_WORKING )
COMP( 1989, pc8801mc, pc8801, 0, pc8801mc, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MC", MACHINE_NOT_WORKING )
//COMP( 1989, pc98do, 0, 0, pc88va, pc88sr, pc8801_state, empty_init, "NEC", "PC-98DO", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/pc88va.cpp b/src/mame/drivers/pc88va.cpp
index 7e6bc817e80..7e2dbb70afa 100644
--- a/src/mame/drivers/pc88va.cpp
+++ b/src/mame/drivers/pc88va.cpp
@@ -13,7 +13,7 @@
- What exact kind of garbage happens if you try to enable both direct and palette color
modes to a graphic layer?
- unemulated upd71071 demand mode;
- - What is exactly supposed to be a "bus slot"?
+ - What is exactly supposed to be a "bus slot"? Does it have an official name?
- fdc "intelligent mode" has 0x7f as irq vector ... 0x7f is ld a,a and it IS NOT correctly
hooked up by the current z80 core
- PC-88VA stock version has two bogus opcodes. One is at 0xf0b15, another at 0xf0b31.
diff --git a/src/mame/includes/pc8001.h b/src/mame/includes/pc8001.h
index 12002ed8dcd..6a68ab80321 100644
--- a/src/mame/includes/pc8001.h
+++ b/src/mame/includes/pc8001.h
@@ -1,11 +1,11 @@
// license:BSD-3-Clause
-// copyright-holders:Curt Coder
+// copyright-holders:Curt Coder, Angelo Salese
+
#pragma once
#ifndef MAME_INCLUDES_PC8001_H
#define MAME_INCLUDES_PC8001_H
-
#include "cpu/z80/z80.h"
#include "imagedev/cassette.h"
#include "machine/buffer.h"
@@ -15,86 +15,151 @@
#include "machine/i8251.h"
#include "machine/ram.h"
#include "machine/upd1990a.h"
+#include "machine/pc80s31k.h"
#include "sound/beep.h"
#include "video/upd3301.h"
+#include "emupal.h"
+#include "screen.h"
#define Z80_TAG "z80"
+#define N80SR_ROM_TAG "n80sr_rom"
#define I8251_TAG "i8251"
-#define I8255A_TAG "i8255"
#define I8257_TAG "i8257"
#define UPD1990A_TAG "upd1990a"
#define UPD3301_TAG "upd3301"
+#define CGROM_TAG "cgrom"
#define CENTRONICS_TAG "centronics"
-#define SCREEN_TAG "screen"
-class pc8001_state : public driver_device
+class pc8001_base_state : public driver_device
{
public:
- pc8001_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, Z80_TAG),
- m_rtc(*this, UPD1990A_TAG),
- m_dma(*this, I8257_TAG),
- m_crtc(*this, UPD3301_TAG),
- m_cassette(*this, "cassette"),
- m_centronics(*this, CENTRONICS_TAG),
- m_cent_data_out(*this, "cent_data_out"),
- m_beep(*this, "beeper"),
- m_ram(*this, RAM_TAG),
- m_rom(*this, Z80_TAG),
- m_char_rom(*this, UPD3301_TAG)
- { }
+ pc8001_base_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, Z80_TAG)
+ , m_crtc(*this, UPD3301_TAG)
+ , m_crtc_palette(*this, "crtc_palette")
+ , m_dma(*this, I8257_TAG)
+ , m_cassette(*this, "cassette")
+ , m_cgrom(*this, CGROM_TAG)
+ {}
+protected:
required_device<cpu_device> m_maincpu;
- required_device<upd1990a_device> m_rtc;
- required_device<i8257_device> m_dma;
required_device<upd3301_device> m_crtc;
+ required_device<palette_device> m_crtc_palette;
+ required_device<i8257_device> m_dma;
required_device<cassette_image_device> m_cassette;
- required_device<centronics_device> m_centronics;
- required_device<output_latch_device> m_cent_data_out;
- required_device<beep_device> m_beep;
- required_device<ram_device> m_ram;
- required_memory_region m_rom;
- required_memory_region m_char_rom;
+ required_memory_region m_cgrom;
+ void port30_w(u8 data);
virtual void machine_start() override;
+ void set_screen_frequency(bool is_24KHz) { m_screen_is_24KHz = is_24KHz; };
- void port10_w(uint8_t data);
- void port30_w(uint8_t data);
- uint8_t port40_r();
- void port40_w(uint8_t data);
+ DECLARE_WRITE_LINE_MEMBER( crtc_reverse_w );
+ UPD3301_DRAW_CHARACTER_MEMBER( draw_text );
+ UPD3301_FETCH_ATTRIBUTE( attr_fetch );
DECLARE_WRITE_LINE_MEMBER( hrq_w );
uint8_t dma_mem_r(offs_t offset);
+private:
+ bool m_screen_reverse;
+ bool m_screen_is_24KHz;
+
/* video state */
int m_width80;
int m_color;
+};
+
+class pc8001_state : public pc8001_base_state
+{
+public:
+ pc8001_state(const machine_config &mconfig, device_type type, const char *tag)
+ : pc8001_base_state(mconfig, type, tag)
+ , m_pc80s31(*this, "pc80s31")
+ , m_rtc(*this, UPD1990A_TAG)
+ , m_screen(*this, "screen")
+ , m_centronics(*this, CENTRONICS_TAG)
+ , m_cent_data_out(*this, "cent_data_out")
+ , m_beep(*this, "beeper")
+ , m_ram(*this, RAM_TAG)
+ , m_rom(*this, Z80_TAG)
+ { }
+
+ void pc8001(machine_config &config);
+
+protected:
+ void pc8001_io(address_map &map);
+ void pc8001_map(address_map &map);
+
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ required_device<pc80s31_device> m_pc80s31;
+ required_device<upd1990a_device> m_rtc;
+ required_device<screen_device> m_screen;
+ required_device<centronics_device> m_centronics;
+ required_device<output_latch_device> m_cent_data_out;
+ required_device<beep_device> m_beep;
+ required_device<ram_device> m_ram;
+ required_memory_region m_rom;
+
+private:
+ void port10_w(uint8_t data);
+ uint8_t port40_r();
+ void port40_w(uint8_t data);
int m_centronics_busy;
int m_centronics_ack;
DECLARE_WRITE_LINE_MEMBER(write_centronics_busy);
DECLARE_WRITE_LINE_MEMBER(write_centronics_ack);
- UPD3301_DRAW_CHARACTER_MEMBER( pc8001_display_pixels );
- void pc8001(machine_config &config);
- void pc8001_io(address_map &map);
- void pc8001_mem(address_map &map);
};
class pc8001mk2_state : public pc8001_state
{
public:
pc8001mk2_state(const machine_config &mconfig, device_type type, const char *tag)
- : pc8001_state(mconfig, type, tag),
- m_kanji_rom(*this, "kanji")
+ : pc8001_state(mconfig, type, tag)
+ , m_kanji_rom(*this, "kanji")
+ , m_dsw(*this, "DSW%d", 1U)
{ }
- required_memory_region m_kanji_rom;
-
- void port31_w(uint8_t data);
void pc8001mk2(machine_config &config);
+
+protected:
void pc8001mk2_io(address_map &map);
- void pc8001mk2_mem(address_map &map);
+ void pc8001mk2_map(address_map &map);
+
+ required_memory_region m_kanji_rom;
+ required_ioport_array<2> m_dsw;
+private:
+ void port31_w(uint8_t data);
+};
+
+class pc8001mk2sr_state : public pc8001mk2_state
+{
+public:
+ pc8001mk2sr_state(const machine_config &mconfig, device_type type, const char *tag)
+ : pc8001mk2_state(mconfig, type, tag)
+ , m_n80sr_rom(*this, N80SR_ROM_TAG)
+ { }
+
+ void pc8001mk2sr(machine_config &config);
+
+private:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+ void pc8001mk2sr_io(address_map &map);
+
+ required_memory_region m_n80sr_rom;
+
+ void port33_w(u8 data);
+ u8 port71_r();
+ void port71_w(u8 data);
+
+ u8 m_n80sr_bank;
};
#endif
diff --git a/src/mame/includes/pc8801.h b/src/mame/includes/pc8801.h
index 5365f1d6094..5b76aeb2945 100644
--- a/src/mame/includes/pc8801.h
+++ b/src/mame/includes/pc8801.h
@@ -5,12 +5,12 @@
PC-8801 (c) 1981 NEC
********************************************************************************************/
+
#ifndef MAME_INCLUDES_PC8801_H
#define MAME_INCLUDES_PC8801_H
#pragma once
-
#include "cpu/z80/z80.h"
#include "bus/centronics/ctronics.h"
#include "imagedev/cassette.h"
@@ -20,7 +20,7 @@
#include "machine/i8255.h"
#include "machine/timer.h"
#include "machine/upd1990a.h"
-#include "machine/upd765.h"
+#include "machine/pc80s31k.h"
#include "sound/beep.h"
#include "sound/ymopn.h"
#include "emupal.h"
@@ -41,9 +41,7 @@ public:
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_screen(*this, "screen")
- , m_fdccpu(*this, "fdccpu")
- , m_fdc(*this, "upd765")
- , m_fdd(*this, "upd765:%u", 0U)
+ , m_pc80s31(*this, "pc80s31")
, m_pic(*this, I8214_TAG)
, m_rtc(*this, UPD1990A_TAG)
, m_cassette(*this, "cassette")
@@ -53,16 +51,28 @@ public:
, m_palette(*this, "palette")
{ }
- void pc8801mc(machine_config &config);
- void pc8801fh(machine_config &config);
void pc8801(machine_config &config);
+ void pc8801mk2mr(machine_config &config);
+ void pc8801fh(machine_config &config);
void pc8801ma(machine_config &config);
+ void pc8801mc(machine_config &config);
protected:
virtual void video_start() override;
virtual void machine_start() override;
virtual void machine_reset() override;
+ required_device<cpu_device> m_maincpu;
+ required_device<screen_device> m_screen;
+ required_device<pc80s31_device> m_pc80s31;
+ optional_device<i8214_device> m_pic;
+ required_device<upd1990a_device> m_rtc;
+ required_device<cassette_image_device> m_cassette;
+ required_device<beep_device> m_beeper;
+ required_device<ym2608_device> m_opna;
+ required_device<ym2203_device> m_opn;
+ required_device<palette_device> m_palette;
+
private:
struct crtc_t
{
@@ -78,19 +88,6 @@ private:
attotime time;
};
- required_device<cpu_device> m_maincpu;
- required_device<screen_device> m_screen;
- required_device<cpu_device> m_fdccpu;
- required_device<upd765a_device> m_fdc;
- required_device_array<floppy_connector, 2> m_fdd;
- optional_device<i8214_device> m_pic;
- required_device<upd1990a_device> m_rtc;
- required_device<cassette_image_device> m_cassette;
- required_device<beep_device> m_beeper;
- required_device<ym2608_device> m_opna;
- required_device<ym2203_device> m_opn;
- required_device<palette_device> m_palette;
-
std::unique_ptr<uint8_t[]> m_work_ram;
std::unique_ptr<uint8_t[]> m_hi_work_ram;
std::unique_ptr<uint8_t[]> m_ext_work_ram;
diff --git a/src/mame/machine/pc80s31k.cpp b/src/mame/machine/pc80s31k.cpp
new file mode 100644
index 00000000000..317a9edd988
--- /dev/null
+++ b/src/mame/machine/pc80s31k.cpp
@@ -0,0 +1,460 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese, Olivier Galibert
+/**************************************************************************************************
+
+ NEC PC-80S31(K) Mini Disk Unit
+
+ Z80 + μPD765 + PPI that connects in cross with an host PPI
+
+ "Mini" as compared to the PC-8881 8-inch floppy I/F
+
+ Design is decidedly derived from Epson TF-20 and friends,
+ cfr. devices/bus/epson_sio/tf20.cpp
+
+ TODO:
+ - What's PC-80S32? Is it the 88VA version or a different beast?
+ - PC=0x7dd reads from FDC bit 3 in ST3 (twosid_r fn),
+ expecting a bit 3 high for all the PC8001 games otherwise keeps looping and eventually dies.
+ Are those incorrectly identified as 2DD? Hacked to work for now;
+ - set_input_line_vector fn doesn't work properly when issued from a device_reset,
+ we currently just implement the irq_callback instead;
+ - Bus option;
+ - Cascade mode, i.e. the CN2 connector used to accept a second disk unit for drive 2 & 3;
+ - pc80s31k: verify that irq vector write (I/O port $f0) belongs here or just
+ whatever PC88VA uses.
+ - printer interface (used for debugging? 4-bit serial?)
+ - Pinpoint what host I/O ports $f6, $f7 truly are
+ (direct FDC access from this device or a different beast? cfr. play6lim with pc8001mk2)
+ - filemst tries to access undocumented I/O port $09 at PC=5000:
+ \- If that's 0 then it tries to read a vector at [0x8000];
+ \- It then tries to read at memory [0xc0ff], set the value read in [0xf012];
+ \- Expects that ROM [0x0000] is not equal to 0xc3;
+ Bottom line: Is it trying to access some custom HW?
+
+===================================================================================================
+
+PCB (PC-80S31K)
+
+===================================================================================================
+
+ |--------------------------------------|
+ | P1 P2 P3 X1 |
+ | |
+ | CN2 |
+ | B6102C022 |
+ | FD1 FD2 (**) |
+ | | | |
+ | CN1 ------- D765AC D2364EC (*)|
+ | (*)|
+ | D8255AC-2 B6101C017 D780C-1 |
+ | |
+ |--------------------------------------|
+
+ PCB is marked PC-80S31KFDC NEC-14T
+ P1, P2, P3 are power supplies (+5V, +12V, -5V for P1, lacks -5V for the other two)
+ μPD2364EC is at position IC13, it's a 8192 size ROM. (***)
+ (*) are μPD41416C
+ (**) marked as JP, unpopulated x 3;
+ μPB6101/2 are bipolar TTL gate arrays, presumably
+ Cannot read marking of X1 (8 MHz?)
+
+ (***) Given this, we guess that PC80S31 is the 2D version while the 'K
+ variant is the 2D/2DD/2HD version.
+
+===================================================================================================
+
+Command Protocol
+
+===================================================================================================
+
+Command & parameters are normally communicated from Host via port B
+(read on port A on FDC side)
+An RPi implementation can be seen at https://github.com/MinatsuT/RPi_PC-80S31
+
+[0x00] Initialize
+[0x01] Write to disk
+ %1 number of sectors
+ %2 drive number
+ %3 track number
+ %4 sector number +1
+[0x02] Read from disk
+ %1 number of sectors
+ %2 drive number
+ %3 track number
+ %4 sector number +1
+[0x03] Send data to host
+[0x04] Copy data in-place
+ %1 number of sectors
+ %2 source drive
+ %3 source track
+ %4 source sector number +1
+ %5 destination drive
+ %6 destination track
+ %7 destination sector number +1
+[0x05] Format
+ %1 drive number
+[0x06] Send result status to Host
+ x--- ---- I/O complete
+ -x-- ---- has unread buffer
+ ---- ---x error occurred
+[0x07] Drive status
+[0x0b] Send memory data
+%1-%2 address start
+%3-%4 length
+[0x11] Fast write to disk
+ %1 number of sectors
+ %2 drive number
+ %3 track number
+ %4 sector number +1
+[0x12] Fast send data
+ (picks up number of sector etc. from previous issued commands?)
+[0x14] Device status
+ x--- ---- ESIG: error
+ -x-- ---- WPDR: write protected
+ --x- ---- RDY: ready
+ ---x ---- TRK0: track 0
+ ---- x--- DSDR: double sided drive
+ ---- -x-- HDDR: head
+ ---- --xx DS1, DS2: drive select
+ (same as 765 ST3?)
+[0x17] Mode change
+ %1 ---- xxxx mode select
+
+FDC normally puts ST0-1-2 to RAM buffers $7f0d-f, CHRN data in $7f10-13
+
+===================================================================================================
+
+Port C
+Used as a communication protocol flags
+
+===================================================================================================
+
+ Host side
+ (swap 4-bit nibbles and r/w direction for FDC side, all bits are active high):
+ x--- ---- (w) ATN AtenTioN:
+ host sends a command to FDC, interrupts current one
+ (looks unconnected the other way around?)
+ -x-- ---- (w) DAC DAta aCcepted:
+ host just picked up data from FDC
+ --x- ---- (w) RFD Ready For Data:
+ host requests data from FDC
+ ---x ---- (w) DAV DAta Valid:
+ host outputs data to port B
+ ---- -x-- (r) DAC DAta aCcepted:
+ FDC has accepted data from port B
+ ---- --x- (r) RFD Ready For Data:
+ FDC requests data from host
+ ---- ---x (r) DAV DAta Valid:
+ FDC has output data to port A
+
+**************************************************************************************************/
+
+#include "emu.h"
+#include "pc80s31k.h"
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+
+// device type definition
+DEFINE_DEVICE_TYPE(PC80S31, pc80s31_device, "pc80s31", "NEC PC-80S31 Mini Disk Unit I/F")
+DEFINE_DEVICE_TYPE(PC80S31K, pc80s31k_device, "pc80s31k", "NEC PC-80S31K Mini Disk Unit I/F")
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// pc80s31_device - constructor
+//-------------------------------------------------
+
+
+pc80s31_device::pc80s31_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_fdc(*this, "fdc")
+ , m_floppy(*this, "fdc:%u", 0U)
+ , m_fdc_cpu(*this, "fdc_cpu")
+ , m_fdc_rom(*this, "fdc_rom")
+ , m_ppi_host(*this, "ppi_host")
+ , m_ppi_fdc(*this, "ppi_fdc")
+ , m_latch(*this, "latch_%u", 0U)
+{
+}
+
+
+pc80s31_device::pc80s31_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pc80s31_device(mconfig, PC80S31, tag, owner, clock)
+{
+
+}
+
+ROM_START( pc80s31 )
+ // TODO: exact identification of these
+ ROM_REGION( 0x2000, "fdc_rom", ROMREGION_ERASEFF )
+ ROM_SYSTEM_BIOS( 0, "disk", "disk BIOS" )
+ ROMX_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f), ROM_BIOS(0) )
+ ROM_SYSTEM_BIOS( 1, "mk2fr", "mkIIFR disk BIOS" )
+ ROMX_LOAD( "mk2fr_disk.rom", 0x0000, 0x0800, CRC(2163b304) SHA1(80da2dee49d4307f00895a129a5cfeff00cf5321), ROM_BIOS(1) )
+
+ ROM_FILL( 0x7df, 1, 0x00 )
+ ROM_FILL( 0x7e0, 1, 0x00 )
+ROM_END
+
+const tiny_rom_entry *pc80s31_device::device_rom_region() const
+{
+ return ROM_NAME( pc80s31 );
+}
+
+//-------------------------------------------------
+// device_add_mconfig - device-specific machine
+// configuration addiitons
+//-------------------------------------------------
+
+void pc80s31_device::host_map(address_map &map)
+{
+ map(0, 3).rw(m_ppi_host, FUNC(i8255_device::read), FUNC(i8255_device::write));
+}
+
+void pc80s31_device::fdc_map(address_map &map)
+{
+ map(0x0000, 0x1fff).rom().region("fdc_rom", 0);
+ map(0x4000, 0x7fff).ram();
+}
+
+void pc80s31_device::fdc_io(address_map &map)
+{
+ map.unmap_value_high();
+ map.global_mask(0xff);
+// map(0x09, 0x09).r accessed by filemst (pc8801), cfr. notes
+
+// map(0xf0, 0xf0).w(FUNC(pc8801_state::fdc_irq_vector_w)); // Interrupt Opcode Port
+// map(0xf4, 0xf4).w(FUNC(pc8801_state::fdc_drive_mode_w)); // Drive mode, 2d, 2dd, 2hd
+// map(0xf6, 0xf6).nopw(); // printer related
+ map(0xf7, 0xf7).nopw(); // printer port output
+ map(0xf8, 0xf8).rw(FUNC(pc80s31_device::terminal_count_r), FUNC(pc80s31_device::motor_control_w));
+ map(0xfa, 0xfb).m(m_fdc, FUNC(upd765a_device::map));
+ map(0xfc, 0xff).rw(m_ppi_fdc, FUNC(i8255_device::read), FUNC(i8255_device::write));
+}
+
+static void pc88_floppies(device_slot_interface &device)
+{
+ // TODO: definitely not correct for base device
+ device.option_add("525hd", FLOPPY_525_HD);
+}
+
+IRQ_CALLBACK_MEMBER(pc80s31_device::irq_cb)
+{
+ return m_irq_vector;
+}
+
+void pc80s31_device::device_add_mconfig(machine_config &config)
+{
+ constexpr XTAL fdc_xtal = XTAL(4'000'000);
+ Z80(config, m_fdc_cpu, fdc_xtal);
+ m_fdc_cpu->set_addrmap(AS_PROGRAM, &pc80s31_device::fdc_map);
+ m_fdc_cpu->set_addrmap(AS_IO, &pc80s31_device::fdc_io);
+ m_fdc_cpu->set_irq_acknowledge_callback(FUNC(pc80s31_device::irq_cb));
+
+ UPD765A(config, m_fdc, XTAL(4'000'000), true, true);
+ m_fdc->intrq_wr_callback().set_inputline(m_fdc_cpu, INPUT_LINE_IRQ0);
+
+ for (auto &floppy : m_floppy)
+ {
+ FLOPPY_CONNECTOR(config, floppy, pc88_floppies, "525hd", floppy_image_device::default_mfm_floppy_formats);
+ floppy->enable_sound(true);
+ }
+
+ for (auto &latch : m_latch)
+ GENERIC_LATCH_8(config, latch);
+
+ I8255A(config, m_ppi_host);
+ m_ppi_host->in_pa_callback().set(FUNC(pc80s31_device::latch_r<0>));
+ m_ppi_host->out_pa_callback().set(FUNC(pc80s31_device::latch_w<1>));
+ m_ppi_host->in_pb_callback().set(FUNC(pc80s31_device::latch_r<2>));
+ m_ppi_host->out_pb_callback().set(FUNC(pc80s31_device::latch_w<3>));
+ m_ppi_host->in_pc_callback().set(FUNC(pc80s31_device::latch_r<4>));
+ m_ppi_host->out_pc_callback().set(FUNC(pc80s31_device::latch_w<5>));
+
+ // 8255AC-2
+ I8255A(config, m_ppi_fdc);
+ m_ppi_fdc->in_pa_callback().set(FUNC(pc80s31_device::latch_r<3>));
+ m_ppi_fdc->out_pa_callback().set(FUNC(pc80s31_device::latch_w<2>));
+ m_ppi_fdc->in_pb_callback().set(FUNC(pc80s31_device::latch_r<1>));
+ m_ppi_fdc->out_pb_callback().set(FUNC(pc80s31_device::latch_w<0>));
+ m_ppi_fdc->in_pc_callback().set(FUNC(pc80s31_device::latch_r<5>));
+ m_ppi_fdc->out_pc_callback().set(FUNC(pc80s31_device::latch_w<4>));
+}
+
+//-------------------------------------------------
+// device_timer - device-specific timers
+//-------------------------------------------------
+
+void pc80s31_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ assert(id == 0);
+
+ m_fdc->tc_w(false);
+
+ // several games tries to scan invalid IDs from their structures, if this hits then
+ // it's possibly an attempt to scan a missing sector from the floppy structure.
+ // cfr. acrojet: the third read data command issued tries to access a CHRN of (0, 0, 16, 256)
+ // and checks at PC=500B if any of these status flags are satisfied:
+ // ST0 & 0xdf
+ // ST1 & 0xff
+ // ST2 & 0x73
+ // Data doesn't matter, it also seems to have some activity to the printer port
+ // (debugging left on?)
+ if ((u8)m_fdc_cpu->state_int(Z80_HALT) == 1)
+ {
+ logerror("%s: attempt to trigger TC while in HALT state (read ID copy protection warning)\n", machine().describe_context());
+// throw emu_fatalerror("copy protection hit");
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void pc80s31_device::device_start()
+{
+ m_tc_zero_timer = timer_alloc(0);
+
+ save_item(NAME(m_irq_vector));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+
+void pc80s31_device::device_reset()
+{
+ m_floppy[0]->get_device()->set_rpm(300);
+ m_floppy[1]->get_device()->set_rpm(300);
+ m_fdc->set_rate(250000);
+
+ // TODO: doesn't seem to work for devices?
+ m_fdc_cpu->set_input_line_vector(0, 0);
+ m_irq_vector = 0;
+
+ m_tc_zero_timer->adjust(attotime::never);
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+// Comms are simple dual port connected in cross fashion.
+// Even at "perfect" interleave tho we need to mailbox the connections.
+// - barbatus will hang at Artec logo the first time around (works if you soft reset);
+template <unsigned N> u8 pc80s31_device::latch_r()
+{
+ const int port_mask = N & 4 ? 0x0f : 0xff;
+// machine().scheduler().synchronize();
+ return m_latch[N]->read() & port_mask;
+}
+
+template <unsigned N> void pc80s31_device::latch_w(u8 data)
+{
+ const int lower_nibble = N & 4;
+// machine().scheduler().synchronize();
+ if (lower_nibble)
+ {
+ LOG("%s: %s port C write %02x (ATN=%d DAC=%d RFD=%d DAV=%d)\n"
+ , N & 1 ? "host" : "fdc"
+ , machine().describe_context()
+ , data
+ , BIT(data, 7)
+ , BIT(data, 6)
+ , BIT(data, 5)
+ , BIT(data, 4)
+ );
+ }
+ return m_latch[N]->write(data >> lower_nibble);
+}
+
+u8 pc80s31_device::terminal_count_r(address_space &space)
+{
+ if (!machine().side_effects_disabled())
+ {
+ m_fdc->tc_w(true);
+ // TODO: accurate time of this going off
+ m_tc_zero_timer->reset();
+ m_tc_zero_timer->adjust(attotime::from_usec(50));
+ }
+ // value is meaningless (never readback)
+ // TODO: verify this being 0xff or open bus
+ return space.unmap();
+}
+
+void pc80s31_device::motor_control_w(uint8_t data)
+{
+ // FIXME: on pc80s31k device (particularly on later releases) this stays always on
+ // babylon: just spins indefinitely at PC=6d8 (using the internal routines),
+ // waiting for DAV or ATN being on. Never hits the port until a flag is issued.
+ // prajator: on idle times it spins at PC=7060, waiting for ATN and keep issuing a 0xff here.
+ // valis2: calls PC=7009 subroutine for idle, waits for ATN on.
+ // It eventually writes a 0 here, not before an extremely long time
+ // (~10000 frames!)
+ m_floppy[0]->get_device()->mon_w(!(data & 1));
+ m_floppy[1]->get_device()->mon_w(!(data & 2));
+
+ // TODO: according to docs a value of 0x07 enables precompensation to tracks 0-19, 0xf enables it on 20-39
+}
+
+//**************************************************************************
+//
+// PC80S31K device overrides
+//
+//**************************************************************************
+
+pc80s31k_device::pc80s31k_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : pc80s31_device(mconfig, PC80S31K, tag, owner, clock)
+{
+
+}
+
+ROM_START( pc80s31k )
+ // TODO: exact identification of these
+ ROM_REGION( 0x2000, "fdc_rom", ROMREGION_ERASEFF )
+ ROM_SYSTEM_BIOS( 0, "ma", "MA disk BIOS")
+ ROMX_LOAD( "ma_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004), ROM_BIOS(0) )
+ ROM_SYSTEM_BIOS( 1, "mk2mr", "mkIIMR disk BIOS" )
+ ROMX_LOAD( "m2mr_disk.rom", 0x0000, 0x2000, CRC(2447516b) SHA1(1492116f15c426f9796dc2bb6fcccf2656c0ca75), ROM_BIOS(1) )
+ ROM_SYSTEM_BIOS( 2, "mh", "MH disk BIOS" )
+ ROMX_LOAD( "mh_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004), ROM_BIOS(2) )
+ // TODO: this may belong to PC-80S32
+ ROM_SYSTEM_BIOS( 3, "88va", "PC88VA disk BIOS")
+ ROMX_LOAD( "vasubsys.rom", 0x0000, 0x2000, CRC(08962850) SHA1(a9375aa480f85e1422a0e1385acb0ea170c5c2e0), ROM_BIOS(3) )
+ROM_END
+
+const tiny_rom_entry *pc80s31k_device::device_rom_region() const
+{
+ return ROM_NAME( pc80s31k );
+}
+
+void pc80s31k_device::drive_mode_w(uint8_t data)
+{
+ // TODO: fix implementation
+ // anything that isn't a 2D doesn't really set proper parameters in here
+ logerror("FDC drive mode %02x\n", data);
+ m_floppy[0]->get_device()->set_rpm(BIT(data, 0) ? 360 : 300);
+ m_floppy[1]->get_device()->set_rpm(BIT(data, 1) ? 360 : 300);
+
+ m_fdc->set_rate(BIT(data, 5) ? 500000 : 250000);
+}
+
+void pc80s31k_device::fdc_io(address_map &map)
+{
+ pc80s31_device::fdc_io(map);
+
+ map(0xf0, 0xf0).lw8(NAME([this] (u8 data) { m_irq_vector = data; }));
+ map(0xf4, 0xf4).w(FUNC(pc80s31k_device::drive_mode_w));
+}
diff --git a/src/mame/machine/pc80s31k.h b/src/mame/machine/pc80s31k.h
new file mode 100644
index 00000000000..a1f9209e75e
--- /dev/null
+++ b/src/mame/machine/pc80s31k.h
@@ -0,0 +1,86 @@
+// license:BSD-3-Clause
+// copyright-holders:Angelo Salese
+/***************************************************************************
+
+NEC PC-80S31K
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_PC80S31K_H
+#define MAME_MACHINE_PC80S31K_H
+
+#pragma once
+
+#include "cpu/z80/z80.h"
+#include "imagedev/floppy.h"
+#include "machine/gen_latch.h"
+#include "machine/i8255.h"
+#include "machine/upd765.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class pc80s31_device : public device_t
+{
+public:
+ // construction/destruction
+ pc80s31_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void host_map(address_map &map);
+
+protected:
+ pc80s31_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device-level overrides
+ //virtual void device_validity_check(validity_checker &valid) const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ virtual void fdc_io(address_map &map);
+
+ required_device<upd765a_device> m_fdc;
+ required_device_array<floppy_connector, 2> m_floppy;
+ u8 m_irq_vector;
+
+private:
+ required_device<z80_device> m_fdc_cpu;
+ required_memory_region m_fdc_rom;
+ required_device<i8255_device> m_ppi_host;
+ required_device<i8255_device> m_ppi_fdc;
+ required_device_array<generic_latch_8_device, 6> m_latch;
+
+ void fdc_map(address_map &map);
+
+ template <unsigned N> u8 latch_r();
+ template <unsigned N> void latch_w(u8 data);
+
+ u8 terminal_count_r(address_space &space);
+ void motor_control_w(u8 data);
+
+ emu_timer *m_tc_zero_timer;
+
+ IRQ_CALLBACK_MEMBER(irq_cb);
+};
+
+class pc80s31k_device : public pc80s31_device
+{
+public:
+ pc80s31k_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual void fdc_io(address_map &map) override;
+
+private:
+ void drive_mode_w(u8 data);
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(PC80S31, pc80s31_device)
+DECLARE_DEVICE_TYPE(PC80S31K, pc80s31k_device)
+
+#endif // MAME_MACHINE_PC80S31K_H
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 6d1b6521470..09e5c9fa63c 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -33855,8 +33855,9 @@ pc6001sr //
pc6601 //
@source:pc8001.cpp
-pc8001 //
-pc8001mk2 //
+pc8001 // 1979
+pc8001mk2 // 1983
+pc8001mk2sr // 1985
@source:pc8401a.cpp
pc8401a // roms needed