diff options
| author | 2021-09-25 16:00:29 +0200 | |
|---|---|---|
| committer | 2021-09-25 16:00:29 +0200 | |
| commit | ec33fac7c77e3f9654d83c15f7c03f1cef79ad34 (patch) | |
| tree | e19da19abfe0ceddcc3550f3464b420f4fc72aa0 /src | |
| parent | e2331a7eed73fd6fec837378ac7a47db9388ed18 (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.cpp | 537 | ||||
| -rw-r--r-- | src/devices/video/upd3301.h | 31 | ||||
| -rw-r--r-- | src/mame/drivers/olyboss.cpp | 7 | ||||
| -rw-r--r-- | src/mame/drivers/pc8001.cpp | 539 | ||||
| -rw-r--r-- | src/mame/drivers/pc8801.cpp | 280 | ||||
| -rw-r--r-- | src/mame/drivers/pc88va.cpp | 2 | ||||
| -rw-r--r-- | src/mame/includes/pc8001.h | 147 | ||||
| -rw-r--r-- | src/mame/includes/pc8801.h | 37 | ||||
| -rw-r--r-- | src/mame/machine/pc80s31k.cpp | 460 | ||||
| -rw-r--r-- | src/mame/machine/pc80s31k.h | 86 | ||||
| -rw-r--r-- | src/mame/mame.lst | 5 |
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 |
