From 5b3335f88c61bb5fbd2333cf0be5d73b02d8b9f2 Mon Sep 17 00:00:00 2001 From: Angelo Salese Date: Mon, 4 Oct 2021 09:09:51 +0200 Subject: pc6001.cpp: Major rework of PC-6001mk2SR (#8626) * Added a PC-6001 cartridge software list XML, and hooked up to the driver; * Fixed a regression bug with machine_reset fn where PC-6001mkII was implicitly overriding its memory model when a cart was inserted, causing being stuck at POST; * Improved irq handling and removed a couple kludges, fixing hangs caused by multiple irqs being fired at the same time; * Added PC-6601SR "Mr. PC", and improved the specific SR video mode already used by PC-6001mk2SR; * Refactored PC-6001mkIISR / PC-6601SR memory model to use address_map_device, allowing BIOS booting and .cas loading in mode 6. Replace AY8910 with YM2203; * Add keyboard inputs F1-F10, and fixed the specific irq vector dispatch; * Add preliminary FDC internal/external interface. Hooked up PC80S31 to external i/f as a proof of concept; * Fixed timer enable (fixes Yakyukyo and Punchball Mario boots), and fixed different timer resolution with PC-6001mk2SR so that cursor blinking happens at the right frequency; New machines marked as NOT_WORKING ---------------------------------- PC-6601SR "Mr. PC" [anonymous] New NOT_WORKING software list additions --------------------------------------- pc6001_cart.xml: Tutankham [HardcoreHubz, cyberat2600, Gaming Alexandria] --- hash/pc6001_cart.xml | 159 ++++++++ src/mame/drivers/pc6001.cpp | 909 +++++++++++++++++++++++++++++--------------- src/mame/drivers/pc8801.cpp | 4 +- src/mame/includes/pc6001.h | 287 +++++++++----- src/mame/mame.lst | 3 +- src/mame/video/pc6001.cpp | 75 ++-- 6 files changed, 988 insertions(+), 449 deletions(-) create mode 100644 hash/pc6001_cart.xml diff --git a/hash/pc6001_cart.xml b/hash/pc6001_cart.xml new file mode 100644 index 00000000000..4d74e391ba6 --- /dev/null +++ b/hash/pc6001_cart.xml @@ -0,0 +1,159 @@ + + + + + + + + + Canyon Climber + 1982 + + Datasoft + + + + + + + + + + The Curse of Crowley Manor + 19?? + <unknown> + + + + + + + + + + Tutankham + 1982 + Konami + + + + + + + + + + + + + + Moon Raiders + 2010 + + <homebrew> + + + + + + + + + + + + Moon Raiders (older) + 2010 + + <homebrew> + + + + + + + + + + + + + Dawn Patrol (beta) + 2012 + + <homebrew> + + + + + + + + + + + + N60 Extended BASIC + 1981 + NEC / Microsoft + + + + + + + + + + + + + Micro-Painter + 1982 + Datasoft + + + + + + + + + + + Music Editor + 19?? + <unknown> + + + + + + + + + + The Electric Pencil (v2.0R) + 1982 + Racet Computes + + + + + + + + + + Touch Panel Utility + 19?? + <unknown> + + + + + + + diff --git a/src/mame/drivers/pc6001.cpp b/src/mame/drivers/pc6001.cpp index 3672fc61228..b257c17ea54 100644 --- a/src/mame/drivers/pc6001.cpp +++ b/src/mame/drivers/pc6001.cpp @@ -1,25 +1,35 @@ // license:BSD-3-Clause // copyright-holders:Angelo Salese -/************************************************************************************************ +/************************************************************************************************** PC-6001 series (c) 1981 NEC driver by Angelo Salese TODO: - - Hook up tape loading, images that are floating around the net are already - ADC'ed, so they should be easy to implement (but not exactly faithful) - - cassette handling requires a decap of the MCU. It could be possible to - do some tight synch between the master CPU and a code simulation, but maybe - it's not worth the effort... - - Identify and hook-up the FDC device, apparently PC-6001 and PC-6601 doesn't - even use the same thing; + - Move MCU HLE simulation in a device or even make an handcrafted LLE version + (assuming we'll never get the MCS48 dump). Additionally remove the 8255 hacks; + - Proper support for .cas/.wav/.p6/.p6t file formats used by the cassette interface; + - Make FDC to actually load images, also fix .dsk identification; + - Confirm irq model daisy chain behaviour, and add missing irqs and features + (namely the irq dispatch for SR mode should really honor I/O $fb and fallback to legacy + behaviour if masked); + - Several games are decidedly too fast, down to missing waitstates, no screen raw + parameters, crtkill signal and bus request; + - PC-6001mkII: refactor memory model to use address_map_bank_device; + - PC-6001mkII: confirm optional FDC used mapped at 0xd0-0xd3 + (PC-6031? It looks like a 5'25 single drive with 8255 protocol, presumably earlier revision + of PC-80S31 with no dump available); + - PC-6601: current regression caused by an internal FDC sense interrupt status that expects a + DIO high that never occurs; - PC-6601: mon r-0 type games doesn't seem to work at all on this system? - - PC-6001SR: get it to boot, also implement MK-2 compatibility mode (it changes - the memory map to behave like the older versions) - - Hookup MC6847 for vanilla PC-6001 and fix video bugs for that device; + - PC-6001SR: Implement MK-2 compatibility mode via view handler(s) + (it changes the memory map to behave like the older versions); + - Merge PC-6001 video emulation with MC6847 (is it really one or rather a M5C6847P-1?); + - Pinpoint what VDG supersets PC-6001mkII and SR models really uses; - upd7752 voice speech device needs to be properly emulated (device is currently a skeleton), Chrith game is a good test case, it's supposed to talk before title screen; + - Video Telopper (superimposer) & TV tuner functions for later machines; TODO (game specific): - (several AX* games, namely Galaxy Mission Part 1/2 and others): inputs doesn't work; @@ -29,9 +39,8 @@ - AX6 - Powered Knight: doesn't work too well, according to the asm code it asks the player to press either 'B' or 'C' then a number but nothing is shown on screen, other emus behaves the same, bad dump? - - Dawn Patrol (cart): presumably too slow; (Mk2 mode 5 games) - - 3D Golf Simulation Super Version: gameplay / inputs seems broken + - 3D Golf Simulation Super Version: gameplay / inputs seems broken; - American Truck: Screen is offset at the loading screen, loading bug? - Castle Excellent: copyright text drawing is quite bogus, scans text in vertical instead of horizontal? @@ -43,14 +52,16 @@ - (MyCom BASIC games with multiple files): most of them refuses to run ... how to load them? - Grobda: when "get ready" speech plays, screen should be full white but instead it's all black, same issue as AX-6 Demo? - - Pac-Man / Tiny Xevious 2: gameplay is too fast - - Salad no Kunino Tomato-Hime: can't start a play - - Space Harrier: inputs doesn't work properly + - Pac-Man / Tiny Xevious 2: gameplay is too fast (unrelated with timer irq); + - Salad no Kunino Tomato-Hime: can't start a play; + - Space Harrier: very sensitive with sub irq triggers, keyboard joy triggers doesn't work + properly (select F1 after loading), draws garbage on vanilla pc6001 and eventually crashes + MAME; - The Black Onyx: dies when it attempts to save the character, that obviously means saving on the tape; - - Yakyukyo / Punchball Mario: waits for an irq, check which one; + - Yakyukyo / Punchball Mario: waits for an irq (fixed, wrong timer enable behaviour); -================================================================================================= +=================================================================================================== PC-6001 (1981-09): @@ -103,7 +114,7 @@ info from http://www.geocities.jp/retro_zzz/machines/nec/6001/spc60.html -================================================================================================= +=================================================================================================== PC-6001 irq table: irq vector 0x00: writes 0x00 to [$fa19] ;(unused) @@ -116,23 +127,29 @@ irq vector 0x0c: writes 0x00 to [$fa19] irq vector 0x0e: same as 2, (A = 0x03, B = 0x00) ;keyboard data ready, unknown type irq vector 0x10: same as 2, (A = 0x03, B = 0x00) ;(unused) irq vector 0x12: writes 0x10 to [$fa19] ;end of tape reached -irq vector 0x14: same as 2, (A = 0x00, B = 0x01) ;kanji lock enabled -irq vector 0x16: tests ppi port c, writes the result to $feca. ;joystick +irq vector 0x14: same as 2, (A = 0x00, B = 0x01) ;keyboard control irq (function keys) +irq vector 0x16: tests ppi port c, writes the result to $feca. ;joystick / sub irq trigger irq vector 0x18: ;TVR (?) irq vector 0x1a: ;Date irq vector 0x1c: ;(unused) irq vector 0x1e: ;(unused) -irq vector 0x20: ;voice -irq vector 0x22: ;VRTC (?) +irq vector 0x20: ;uPD7752 voice irq +irq vector 0x22: ;VRTC (SR only?) irq vector 0x24: ;(unused) irq vector 0x26: ;(unused) -************************************************************************************************/ +***************************************************************************************************/ #include "emu.h" #include "includes/pc6001.h" -#define IRQ_LOG (0) +#define LOG_IRQ (1U << 1) + +//#define VERBOSE (LOG_IRQ) +#define VERBOSE (0) +#include "logmacro.h" + +#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__) inline void pc6001_state::cassette_latch_control(bool new_state) { @@ -149,7 +166,6 @@ inline void pc6001_state::cassette_latch_control(bool new_state) m_cas_switch = 0; //m_cassette->change_state(CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR); //m_cassette->change_state(CASSETTE_STOPPED,CASSETTE_MASK_UISTATE); - //set_maincpu_irq_line(0x00); } } @@ -176,23 +192,35 @@ inline void pc6001_state::ppi_control_hack_w(uint8_t data) m_port_c_8255 |= 0xa8; } -inline void pc6001_state::set_maincpu_irq_line(uint8_t vector_num) +inline void pc6001_state::set_subcpu_irq_vector(u8 vector_num) { - m_irq_vector = vector_num; + // TODO: if anything the new vector must never override an old one + // sub CPU INT pin is directly connected to the OBFA (PC7) on PPI while WR is connected to INTRA (PC3), + // former should act as an handshake flag to inhibit further irqs until current is processed. + // (Also note tight loops in main CPU code that checks against masks 0x28 or 0x88 for I/O $92) + LOGIRQ("%s: sub CPU new irq vector old: %02x new: %02x\n", machine().describe_context(), m_sub_vector, vector_num); + m_sub_vector = vector_num; + set_irq_level(SUB_CPU_IRQ); +} + +inline void pc6001_state::set_irq_level(int which) +{ + m_irq_pending |= 1 << which; m_maincpu->set_input_line(0, ASSERT_LINE); + LOGIRQ("%s: assert %d, state %02x\n", machine().describe_context(), which, m_irq_pending); } void pc6001_state::system_latch_w(uint8_t data) { static const uint16_t startaddr[] = {0xC000, 0xE000, 0x8000, 0xA000 }; - m_video_base = &m_ram[startaddr[(data >> 1) & 0x03] - 0x8000]; + m_video_base = &m_ram[startaddr[(data >> 1) & 0x03] - 0x8000]; cassette_latch_control((data & 8) == 8); m_sys_latch = data; - m_timer_irq_mask = data & 1; - //printf("%02x\n",data); + m_timer_enable = !(data & 1); + set_timer_divider(); } @@ -242,12 +270,11 @@ void pc6001_state::pc6001_io(address_map &map) map.global_mask(0xff); map(0x80, 0x81).rw("uart", FUNC(i8251_device::read), FUNC(i8251_device::write)); map(0x90, 0x93).mirror(0x0c).rw(FUNC(pc6001_state::nec_ppi8255_r), FUNC(pc6001_state::nec_ppi8255_w)); - map(0xa0, 0xa0).mirror(0x0c).w("ay8910", FUNC(ay8910_device::address_w)); - map(0xa1, 0xa1).mirror(0x0c).w("ay8910", FUNC(ay8910_device::data_w)); - map(0xa2, 0xa2).mirror(0x0c).r("ay8910", FUNC(ay8910_device::data_r)); + map(0xa0, 0xa0).mirror(0x0c).w(m_ay, FUNC(ay8910_device::address_w)); + map(0xa1, 0xa1).mirror(0x0c).w(m_ay, FUNC(ay8910_device::data_w)); + map(0xa2, 0xa2).mirror(0x0c).r(m_ay, FUNC(ay8910_device::data_r)); map(0xa3, 0xa3).mirror(0x0c).nopw(); map(0xb0, 0xb0).mirror(0x0f).w(FUNC(pc6001_state::system_latch_w)); - map(0xd0, 0xd3).mirror(0x0c).noprw(); // disk device } /***************************************** @@ -586,10 +613,10 @@ void pc6001mk2_state::mk2_system_latch_w(uint8_t data) cassette_latch_control((data & 8) == 8); m_sys_latch = data; - m_timer_irq_mask = data & 1; - vram_bank_change((m_ex_vram_bank & 0x06) | ((m_sys_latch & 0x06) << 4)); + m_timer_enable = !(data & 1); + set_timer_divider(); - //printf("%02x B0\n",data); + vram_bank_change((m_ex_vram_bank & 0x06) | ((m_sys_latch & 0x06) << 4)); } inline void pc6001mk2_state::refresh_crtc_params() @@ -643,19 +670,36 @@ void pc6001mk2_state::mk2_0xf3_w(uint8_t data) ---- --x- custom irq 2 mask ---- ---x custom irq 1 mask */ - m_timer_irq_mask2 = data & 4; + m_timer_irq_mask = BIT(data, 2); } -inline void pc6001_state::set_timer_divider(uint8_t data) +inline u8 pc6001_state::get_timer_base_divider() { - m_timer_hz_div = data; - attotime period = attotime::from_hz((487.5*4)/(m_timer_hz_div+1)); + return 4; +} + +inline u8 pc6001mk2sr_state::get_timer_base_divider() +{ +// if (sr_mode == false) +// return pc6001mk2_state::get_timer_base_divider(); + return 0x80; +} + +inline void pc6001_state::set_timer_divider() +{ + if (m_timer_enable == false) + { + m_timer_irq_timer->adjust(attotime::never); + return; + } + attotime period = attotime::from_hz((487.5 * get_timer_base_divider()) / (m_timer_hz_div+1)); m_timer_irq_timer->adjust(period, 0, period); } void pc6001mk2_state::mk2_timer_adj_w(uint8_t data) { - set_timer_divider(data); + m_timer_hz_div = data; + set_timer_divider(); } void pc6001mk2_state::mk2_timer_irqv_w(uint8_t data) @@ -699,9 +743,9 @@ void pc6001mk2_state::pc6001mk2_io(address_map &map) map(0x90, 0x93).mirror(0x0c).rw(FUNC(pc6001mk2_state::nec_ppi8255_r), FUNC(pc6001mk2_state::necmk2_ppi8255_w)); - map(0xa0, 0xa0).mirror(0x0c).w("ay8910", FUNC(ay8910_device::address_w)); - map(0xa1, 0xa1).mirror(0x0c).w("ay8910", FUNC(ay8910_device::data_w)); - map(0xa2, 0xa2).mirror(0x0c).r("ay8910", FUNC(ay8910_device::data_r)); + map(0xa0, 0xa0).mirror(0x0c).w(m_ay, FUNC(ay8910_device::address_w)); + map(0xa1, 0xa1).mirror(0x0c).w(m_ay, FUNC(ay8910_device::data_w)); + map(0xa2, 0xa2).mirror(0x0c).r(m_ay, FUNC(ay8910_device::data_r)); map(0xa3, 0xa3).mirror(0x0c).noprw(); map(0xb0, 0xb0).mirror(0x0f).w(FUNC(pc6001mk2_state::mk2_system_latch_w)); @@ -710,8 +754,6 @@ void pc6001mk2_state::pc6001mk2_io(address_map &map) map(0xc1, 0xc1).w(FUNC(pc6001mk2_state::mk2_vram_bank_w)); map(0xc2, 0xc2).w(FUNC(pc6001mk2_state::mk2_opt_bank_w)); - map(0xd0, 0xd3).mirror(0x0c).noprw(); // disk device - map(0xe0, 0xe3).mirror(0x0c).rw("upd7752", FUNC(upd7752_device::read), FUNC(upd7752_device::write)); map(0xf0, 0xf0).rw(FUNC(pc6001mk2_state::mk2_bank_r0_r), FUNC(pc6001mk2_state::mk2_bank_r0_w)); @@ -730,15 +772,43 @@ void pc6001mk2_state::pc6001mk2_io(address_map &map) * ****************************************/ -// disk device placeholder -// TODO: identify & hook-up this FDC -uint8_t pc6601_state::fdc_r() +// disk device I/F +void pc6601_state::fdc_sel_w(uint8_t data) +{ + // bit 2 selects between internal (0) and external (1) FDC interfaces + // other bits unknown purpose + m_fdc_intf_view.select((data & 4) >> 2); +} + +u8 pc6601_state::fdc_mon_r() +{ + // bit 0 reads the motor line status (active low) + return 0; +} + +void pc6601_state::fdc_mon_w(u8 data) { - return machine().rand(); + m_floppy->get_device()->mon_w(!BIT(data,0)); } -void pc6601_state::fdc_w(uint8_t data) +// TODO: 0xd0, 0xd3 FIFO data buffer from/to FDC (external DMA?) +// PC-6001mk2SR / PC-6601SR tests these FIFO ports first, +// ditching attempt to floppy load if reading doesn't match 0x55aa previous writes. +// PC-6601 ignores this. + +// TODO: hangs at first internal FDC command sense irq status in PC-6601 (and later machines if data buffer is enabled) +// It recalibrate and expects that uPD765 returns a DIO high that never happens. + +void pc6601_state::pc6601_fdc_io(address_map &map) { + map(0xb1, 0xb1).mirror(0x4).w(FUNC(pc6601_state::fdc_sel_w)); +// 0xb0, 0xb3 + map(0xd0, 0xdf).view(m_fdc_intf_view); + m_fdc_intf_view[0](0xd4, 0xd4).r(FUNC(pc6601_state::fdc_mon_r)); + m_fdc_intf_view[0](0xd6, 0xd6).w(FUNC(pc6601_state::fdc_mon_w)); + m_fdc_intf_view[0](0xdc, 0xdd).m(m_fdc, FUNC(upd765a_device::map)); + + m_fdc_intf_view[1](0xd0, 0xd3).mirror(0x4).m(m_pc80s31, FUNC(pc80s31_device::host_map)); } void pc6601_state::pc6601_io(address_map &map) @@ -747,12 +817,7 @@ void pc6601_state::pc6601_io(address_map &map) map.global_mask(0xff); pc6001mk2_io(map); - // these are disk related -// map(0xb1 -// map(0xb2 -// map(0xb3 - - map(0xd0, 0xdf).rw(FUNC(pc6601_state::fdc_r), FUNC(pc6601_state::fdc_w)); + pc6601_fdc_io(map); } /***************************************** @@ -761,137 +826,122 @@ void pc6601_state::pc6601_io(address_map &map) * ****************************************/ -#define SR_SYSROM_1(_v_) \ - 0x10000+(0x1000*_v_) -#define SR_SYSROM_2(_v_) \ - 0x20000+(0x1000*_v_) -#define SR_CGROM1(_v_) \ - 0x30000+(0x1000*_v_) -#define SR_EXROM0(_v_) \ - 0x40000+(0x1000*_v_) -#define SR_EXROM1(_v_) \ - 0x50000+(0x1000*_v_) -#define SR_EXRAM0(_v_) \ - 0x60000+(0x1000*_v_) -#define SR_WRAM0(_v_) \ - 0x70000+(0x1000*_v_) -#define SR_NULL(_v_) \ - 0x80000+(0x1000*_v_) - -uint8_t pc6001sr_state::sr_bank_rn_r(offs_t offset) +u8 pc6001mk2sr_state::sr_bank_reg_r(offs_t offset) { - return m_sr_bank_r[offset]; + return m_sr_bank_reg[offset]; } -void pc6001sr_state::sr_bank_rn_w(offs_t offset, uint8_t data) +// offset & 8 maps to bank writes +void pc6001mk2sr_state::sr_bank_reg_w(offs_t offset, u8 data) { - memory_bank *bank[8] = { m_bank1, m_bank2, m_bank3, m_bank4, m_bank5, m_bank6, m_bank7, m_bank8 }; - uint8_t *ROM = m_region_maincpu->base(); - uint8_t bank_num; - - m_sr_bank_r[offset] = data; - bank_num = data & 0x0f; - - switch(data & 0xf0) - { - case 0xf0: bank[offset]->set_base(&ROM[SR_SYSROM_1(bank_num)]); break; - case 0xe0: bank[offset]->set_base(&ROM[SR_SYSROM_2(bank_num)]); break; - case 0xd0: bank[offset]->set_base(&ROM[SR_CGROM1(bank_num)]); break; - case 0xc0: bank[offset]->set_base(&ROM[SR_EXROM1(bank_num)]); break; - case 0xb0: bank[offset]->set_base(&ROM[SR_EXROM0(bank_num)]); break; - case 0x20: bank[offset]->set_base(&ROM[SR_EXRAM0(bank_num)]); break; - case 0x00: bank[offset]->set_base(&ROM[SR_WRAM0(bank_num)]); break; - default: bank[offset]->set_base(&ROM[SR_NULL(bank_num)]); break; - } + // TODO: is bit 0 truly a NOP? + m_sr_bank_reg[offset] = data & 0xfe; + m_sr_bank[offset]->set_bank(m_sr_bank_reg[offset] >> 1); } -uint8_t pc6001sr_state::sr_bank_wn_r(offs_t offset) +void pc6001mk2sr_state::sr_bitmap_yoffs_w(u8 data) { - return m_sr_bank_w[offset]; + m_bitmap_yoffs = data; } -void pc6001sr_state::sr_bank_wn_w(offs_t offset, uint8_t data) +void pc6001mk2sr_state::sr_bitmap_xoffs_w(u8 data) { - m_sr_bank_w[offset] = data; -} + m_bitmap_xoffs = data; -void pc6001sr_state::sr_bitmap_yoffs_w(uint8_t data) -{ - m_bitmap_yoffs = data; + if (data) + popmessage("xoffs write %02x", data); } -void pc6001sr_state::sr_bitmap_xoffs_w(uint8_t data) +u8 pc6001mk2sr_state::work_ram_r(offs_t offset) { - m_bitmap_xoffs = data; -} +// if (m_sr_text_mode == false && (offset & 0xe000) == 0) && m_sr_mode) + if (m_sr_text_mode == false && (offset & 0xe000) == 0) + return sr_gvram_r(offset); -#define SR_WRAM_BANK_W(_v_) \ -{ \ - uint8_t *ROM = m_region_maincpu->base(); \ - uint8_t bank_num; \ - bank_num = m_sr_bank_w[_v_] & 0x0e; \ - if((m_sr_bank_w[_v_] & 0xf0) == 0x00) \ - ROM[offset+(SR_WRAM0(bank_num))] = data; \ - else if((m_sr_bank_w[_v_] & 0xf0) == 0x20) \ - ROM[offset+(SR_EXRAM0(bank_num))] = data; \ + return m_ram[offset]; } -void pc6001sr_state::sr_work_ram0_w(offs_t offset, uint8_t data) +void pc6001mk2sr_state::work_ram_w(offs_t offset, u8 data) { - // TODO: not entirely correct - if(m_sr_text_mode == false && m_sr_bank_w[0] == 0) +// if (m_sr_text_mode == false && (offset & 0xe000) == 0) && m_sr_mode) + if (m_sr_text_mode == false && (offset & 0xe000) == 0) { - uint32_t real_offs = (m_bitmap_xoffs*16+m_bitmap_yoffs)*256; - real_offs += offset; - - m_gvram[real_offs] = data; + sr_gvram_w(offset, data); return; } - SR_WRAM_BANK_W(0); + m_ram[offset] = data; +} + +// TODO: does this maps to the work RAM in an alt fashion? +// Games that uses GVRAM never writes outside 0-0x13f, and xoffs is unconfirmed. +// Games also expects that GVRAM is read-back as 4-bit, otherwise fill issues happens +// By logic it should be a 320x204 8-bit area -> 0x7f80 +// The interface is otherwise pretty inconvenient, +// and it is unconfirmed if raster effect over SR text mode is even possible (which would halve the time required for drawing) +// or if double buffering is possible (that would require EXRAM installed) +u8 pc6001mk2sr_state::sr_gvram_r(offs_t offset) +{ + uint32_t real_offs = (m_bitmap_xoffs*16+m_bitmap_yoffs)*320; + real_offs += offset; + + return m_gvram[real_offs]; +} + +void pc6001mk2sr_state::sr_gvram_w(offs_t offset, u8 data) +{ + uint32_t real_offs = (m_bitmap_xoffs*16+m_bitmap_yoffs)*320; + real_offs += offset; + + m_gvram[real_offs] = data; } -void pc6001sr_state::sr_work_ram1_w(offs_t offset, uint8_t data){ SR_WRAM_BANK_W(1); } -void pc6001sr_state::sr_work_ram2_w(offs_t offset, uint8_t data){ SR_WRAM_BANK_W(2); } -void pc6001sr_state::sr_work_ram3_w(offs_t offset, uint8_t data){ SR_WRAM_BANK_W(3); } -void pc6001sr_state::sr_work_ram4_w(offs_t offset, uint8_t data){ SR_WRAM_BANK_W(4); } -void pc6001sr_state::sr_work_ram5_w(offs_t offset, uint8_t data){ SR_WRAM_BANK_W(5); } -void pc6001sr_state::sr_work_ram6_w(offs_t offset, uint8_t data){ SR_WRAM_BANK_W(6); } -void pc6001sr_state::sr_work_ram7_w(offs_t offset, uint8_t data){ SR_WRAM_BANK_W(7); } -void pc6001sr_state::sr_mode_w(uint8_t data) +void pc6001mk2sr_state::sr_mode_w(u8 data) { // if 1 text mode else bitmap mode - m_sr_text_mode = bool(BIT(data,3)); + m_sr_text_mode = bool(BIT(data, 3)); + // in theory we need a view, + // in practice this approach doesn't work cause we can't mix views with address banks +// m_gvram_view.select(m_sr_text_mode == false); + m_sr_text_rows = data & 4 ? 20 : 25; + refresh_crtc_params(); + // bit 1: bus request + // bit 4: VRAM bank select +// if (data & 0x10) +// popmessage("VRAM bank select enabled"); if(data & 1) - assert("PC-6001SR in Mk-2 compatibility mode not yet supported!\n"); + throw emu_fatalerror("PC-6601SR in Mk-2 compatibility mode not yet supported!"); } -void pc6001sr_state::sr_vram_bank_w(uint8_t data) +void pc6001mk2sr_state::sr_vram_bank_w(u8 data) { - set_videoram_bank(0x70000 + ((data & 0x0f)*0x1000)); + m_video_base = &m_ram[(data & 0x0f) * 0x1000]; + +// set_videoram_bank(0x70000 + ((data & 0x0f)*0x1000)); } -void pc6001sr_state::sr_system_latch_w(uint8_t data) +void pc6001mk2sr_state::sr_system_latch_w(u8 data) { cassette_latch_control((data & 8) == 8); m_sys_latch = data; - m_timer_irq_mask = data & 1; + m_timer_enable = !(data & 1); + set_timer_divider(); //vram_bank_change((m_ex_vram_bank & 0x06) | ((m_sys_latch & 0x06) << 4)); //printf("%02x B0\n",data); } -void pc6001sr_state::necsr_ppi8255_w(offs_t offset, uint8_t data) +void pc6001mk2sr_state::necsr_ppi8255_w(offs_t offset, u8 data) { if (offset==3) { ppi_control_hack_w(data); - if(0) + #ifdef UNUSED_FUNCTION { //printf("%02x\n",data); @@ -900,74 +950,117 @@ void pc6001sr_state::necsr_ppi8255_w(offs_t offset, uint8_t data) if ((data & 0x0f) == 0x04) m_bank1->set_base(m_region_gfx1->base()); } + #endif } m_ppi->write(offset,data); } -uint8_t pc6001sr_state::hw_rev_r() +u8 pc6001mk2sr_state::hw_rev_r() { - // bit 1 is active for pc6601sr, causes a direct jump to "video telopper" for pc6001mk2sr - return 0; + // bit 1 is active for pc6601sr (and shows the "PC6601SR World" screen in place of the "PC6001mkIISR World"), + // causes a direct jump to "video telopper" for pc6001mk2sr + // bit 0 is related to FDC irq status + return 0 | 1; +} + +u8 pc6601sr_state::hw_rev_r() +{ + return 2 | 1; +} + +void pc6001mk2sr_state::crt_mode_w(u8 data) +{ +// m_bgcol_bank = (data & 8) ^ 8; + m_width80 = !BIT(data, 1); + refresh_crtc_params(); } -void pc6001sr_state::pc6001sr_map(address_map &map) +inline void pc6001mk2sr_state::refresh_crtc_params() +{ + /* Apparently bitmap modes changes the screen res to 320 x 200 */ + rectangle visarea = m_screen->visible_area(); + const int y_height = (m_sr_text_mode) ? 240 : 200; + const int x_width = (m_sr_text_mode) ? (m_width80 ? 640 : 320) : 320; + + visarea.set(0, (x_width) - 1, 0, (y_height) - 1); + + m_screen->configure(m_screen->width(), m_screen->height(), visarea, m_screen->frame_period().attoseconds()); +} + +void pc6001mk2sr_state::pc6001mk2sr_map(address_map &map) { map.unmap_value_high(); - map(0x0000, 0x1fff).bankr("bank1").w(FUNC(pc6001sr_state::sr_work_ram0_w)); - map(0x2000, 0x3fff).bankr("bank2").w(FUNC(pc6001sr_state::sr_work_ram1_w)); - map(0x4000, 0x5fff).bankr("bank3").w(FUNC(pc6001sr_state::sr_work_ram2_w)); - map(0x6000, 0x7fff).bankr("bank4").w(FUNC(pc6001sr_state::sr_work_ram3_w)); - map(0x8000, 0x9fff).bankr("bank5").w(FUNC(pc6001sr_state::sr_work_ram4_w)); - map(0xa000, 0xbfff).bankr("bank6").w(FUNC(pc6001sr_state::sr_work_ram5_w)); - map(0xc000, 0xdfff).bankr("bank7").w(FUNC(pc6001sr_state::sr_work_ram6_w)); - map(0xe000, 0xffff).bankr("bank8").w(FUNC(pc6001sr_state::sr_work_ram7_w)); + for (int bank = 0; bank < 8; bank++) + { + map(bank << 13, (bank << 13) | 0x1fff).r(m_sr_bank[bank], FUNC(address_map_bank_device::read8)); + map(bank << 13, (bank << 13) | 0x1fff).w(m_sr_bank[bank+8], FUNC(address_map_bank_device::write8)); + } +} + +void pc6001mk2sr_state::sr_banked_map(address_map &map) +{ +// map(0x00000, 0x0ffff).view(m_gvram_view); +// m_gvram_view[0](0x0000, 0xffff).ram(); +// m_gvram_view[1](0x0000, 0x1fff).rw(FUNC(pc6001mk2sr_state::sr_gvram_r), FUNC(pc6001mk2sr_state::sr_gvram_w)); + map(0x00000, 0x0ffff).rw(FUNC(pc6001mk2sr_state::work_ram_r), FUNC(pc6001mk2sr_state::work_ram_w)).share("ram"); + + // exram0 + map(0x20000, 0x2ffff).ram(); + // exrom0 + map(0xb4000, 0xb7fff).r(m_cart, FUNC(generic_slot_device::read_rom)); + // exrom1 +// map(0xc0000, 0xcffff).rom(); + // cgrom 1 + map(0xd0000, 0xd3fff).rom().region("cgrom", 0); + // sysrom 1 / 2 + map(0xe0000, 0xfffff).rom().region("sr_sysrom", 0); } -void pc6001sr_state::pc6001sr_io(address_map &map) +void pc6001mk2sr_state::pc6001mk2sr_io(address_map &map) { map.unmap_value_high(); map.global_mask(0xff); -// 0x40-0x43 palette indexes - map(0x60, 0x67).rw(FUNC(pc6001sr_state::sr_bank_rn_r), FUNC(pc6001sr_state::sr_bank_rn_w)); - map(0x68, 0x6f).rw(FUNC(pc6001sr_state::sr_bank_wn_r), FUNC(pc6001sr_state::sr_bank_wn_w)); + map(0x40, 0x43).nopw(); // palette CLUTs + map(0x60, 0x6f).rw(FUNC(pc6001mk2sr_state::sr_bank_reg_r), FUNC(pc6001mk2sr_state::sr_bank_reg_w)); + map(0x80, 0x81).rw("uart", FUNC(i8251_device::read), FUNC(i8251_device::write)); - map(0x90, 0x93).mirror(0x0c).rw(FUNC(pc6001sr_state::nec_ppi8255_r), FUNC(pc6001sr_state::necsr_ppi8255_w)); + map(0x90, 0x93).mirror(0x0c).rw(FUNC(pc6001mk2sr_state::nec_ppi8255_r), FUNC(pc6001mk2sr_state::necsr_ppi8255_w)); - map(0xa0, 0xa0).mirror(0x0c).w("ay8910", FUNC(ay8910_device::address_w)); - map(0xa1, 0xa1).mirror(0x0c).w("ay8910", FUNC(ay8910_device::data_w)); - map(0xa2, 0xa2).mirror(0x0c).r("ay8910", FUNC(ay8910_device::data_r)); - map(0xa3, 0xa3).mirror(0x0c).noprw(); + map(0xa0, 0xa0).mirror(0x0c).w(m_ym, FUNC(ym2203_device::address_w)); + map(0xa1, 0xa1).mirror(0x0c).w(m_ym, FUNC(ym2203_device::data_w)); + map(0xa2, 0xa2).mirror(0x0c).r(m_ym, FUNC(ym2203_device::data_r)); + map(0xa3, 0xa3).mirror(0x0c).r(m_ym, FUNC(ym2203_device::status_r)); - map(0xb0, 0xb0).w(FUNC(pc6001sr_state::sr_system_latch_w)); - /* these are disk related */ -// map(0xb1 - map(0xb2, 0xb2).r(FUNC(pc6001sr_state::hw_rev_r)); -// map(0xb3 + map(0xb0, 0xb0).w(FUNC(pc6001mk2sr_state::sr_system_latch_w)); - map(0xb8, 0xbf).ram().share("irq_vectors"); -// map(0xc0, 0xc0).w(FUNC(pc6001sr_state::mk2_col_bank_w)); -// map(0xc1, 0xc1).w(FUNC(pc6001sr_state::mk2_vram_bank_w)); -// map(0xc2, 0xc2).w(FUNC(pc6001sr_state::opt_bank_w)); - - map(0xc8, 0xc8).w(FUNC(pc6001sr_state::sr_mode_w)); - map(0xc9, 0xc9).w(FUNC(pc6001sr_state::sr_vram_bank_w)); - map(0xce, 0xce).w(FUNC(pc6001sr_state::sr_bitmap_yoffs_w)); - map(0xcf, 0xcf).w(FUNC(pc6001sr_state::sr_bitmap_xoffs_w)); + pc6601_fdc_io(map); + map(0xb2, 0xb2).r(FUNC(pc6001mk2sr_state::hw_rev_r)); - map(0xd0, 0xdf).rw(FUNC(pc6001sr_state::fdc_r), FUNC(pc6001sr_state::fdc_w)); // disk device + map(0xb8, 0xbf).ram().share("irq_vectors"); +// map(0xc0, 0xc0).w(FUNC(pc6001mk2sr_state::mk2_col_bank_w)); + map(0xc1, 0xc1).w(FUNC(pc6001mk2sr_state::crt_mode_w)); +// map(0xc2, 0xc2).w(FUNC(pc6001mk2sr_state::opt_bank_w)); + + map(0xc8, 0xc8).w(FUNC(pc6001mk2sr_state::sr_mode_w)); + map(0xc9, 0xc9).w(FUNC(pc6001mk2sr_state::sr_vram_bank_w)); + // TODO: confirm readback + map(0xca, 0xcb).ram().share("sr_scrollx"); + map(0xcc, 0xcc).ram().share("sr_scrolly"); + map(0xce, 0xce).w(FUNC(pc6001mk2sr_state::sr_bitmap_yoffs_w)); + map(0xcf, 0xcf).w(FUNC(pc6001mk2sr_state::sr_bitmap_xoffs_w)); map(0xe0, 0xe3).mirror(0x0c).rw("upd7752", FUNC(upd7752_device::read), FUNC(upd7752_device::write)); -// map(0xf0, 0xf0).rw(FUNC(pc6001sr_state::mk2_bank_r0_r), FUNC(pc6001sr_state::mk2_bank_r0_w)); -// map(0xf1, 0xf1).rw(FUNC(pc6001sr_state::mk2_bank_r1_r), FUNC(pc6001sr_state::mk2_bank_r1_w)); -// map(0xf2, 0xf2).rw(FUNC(pc6001sr_state::mk2_bank_w0_r), FUNC(pc6001sr_state::mk2_bank_w0_w)); - map(0xf3, 0xf3).w(FUNC(pc6001sr_state::mk2_0xf3_w)); +// map(0xf0, 0xf0).rw(FUNC(pc6001mk2sr_state::mk2_bank_r0_r), FUNC(pc6001mk2sr_state::mk2_bank_r0_w)); +// map(0xf1, 0xf1).rw(FUNC(pc6001mk2sr_state::mk2_bank_r1_r), FUNC(pc6001mk2sr_state::mk2_bank_r1_w)); +// map(0xf2, 0xf2).rw(FUNC(pc6001mk2sr_state::mk2_bank_w0_r), FUNC(pc6001mk2sr_state::mk2_bank_w0_w)); + map(0xf3, 0xf3).w(FUNC(pc6001mk2sr_state::mk2_0xf3_w)); // map(0xf4 // map(0xf5 - map(0xf6, 0xf6).w(FUNC(pc6001sr_state::mk2_timer_adj_w)); - map(0xf7, 0xf7).w(FUNC(pc6001sr_state::mk2_timer_irqv_w)); + map(0xf6, 0xf6).w(FUNC(pc6001mk2sr_state::mk2_timer_adj_w)); + map(0xf7, 0xf7).w(FUNC(pc6001mk2sr_state::mk2_timer_irqv_w)); } /* Input ports */ @@ -1107,6 +1200,13 @@ static INPUT_PORTS_START( pc6001 ) PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("^") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('^') PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("_") + PORT_START("key_fn") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1 / F6") PORT_CODE(KEYCODE_F1) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2 / F7") PORT_CODE(KEYCODE_F2) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3 / F8") PORT_CODE(KEYCODE_F3) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4 / F9") PORT_CODE(KEYCODE_F4) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5 / F10") PORT_CODE(KEYCODE_F5) + PORT_START("key_modifiers") PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) @@ -1118,41 +1218,90 @@ INPUT_PORTS_END TIMER_CALLBACK_MEMBER(pc6001_state::audio_callback) { - if(m_cas_switch == 0 && ((m_timer_irq_mask == 0) || (m_timer_irq_mask2 == 0))) - { - if(IRQ_LOG) printf("Timer IRQ called %02x\n",m_timer_irq_vector); - set_maincpu_irq_line(m_timer_irq_vector); - } + // TODO: shouldn't really need the cas switch check, different thread + if(m_cas_switch == 0 && m_timer_irq_mask == false) + set_irq_level(TIMER_IRQ); } -INTERRUPT_GEN_MEMBER(pc6001_state::vrtc_irq) +TIMER_CALLBACK_MEMBER(pc6001_state::sub_trig_callback) { m_cur_keycode = check_joy_press(); - if(IRQ_LOG) printf("Joystick IRQ called 0x16\n"); - set_maincpu_irq_line(0x16); + // TODO: is sub CPU the actual source of this? + set_irq_level(JOYSTICK_IRQ); } -INTERRUPT_GEN_MEMBER(pc6001sr_state::sr_vrtc_irq) +INTERRUPT_GEN_MEMBER(pc6001mk2sr_state::sr_vrtc_irq) { - m_kludge ^= 1; + set_irq_level(VRTC_IRQ); +} - // TODO: it is unclear who is responsible of the "Joystick IRQ" vs VRTC - if(m_kludge) - { - m_cur_keycode = check_joy_press(); - if(IRQ_LOG) printf("Joystick IRQ called 0x16\n"); - set_maincpu_irq_line(0x16); - } - else - { - set_maincpu_irq_line(m_sr_irq_vectors[VRTC_IRQ]); - } +u8 pc6001_state::sub_ack() +{ + return m_sub_vector; +} + +u8 pc6001_state::joystick_ack() +{ + return 0x16; +} + +u8 pc6001_state::timer_ack() +{ + return m_timer_irq_vector; +} + +u8 pc6001_state::vrtc_ack() +{ + // not present for PC-6001 + throw emu_fatalerror("Vanilla PC-6001 doesn't have VRTC irq ack"); +} + +u8 pc6001mk2_state::vrtc_ack() +{ + // TODO: currently unimplemented, find and verify any software that needs this + return 0x22; +} + +u8 pc6001mk2sr_state::vrtc_ack() +{ + // TODO: bit 0 of sr_mode_w +// if (sr_mode == false) +// return pc6001mk2_state::vrtc_ack(); + + return m_sr_irq_vectors[VRTC_IRQ]; } IRQ_CALLBACK_MEMBER(pc6001_state::irq_callback) { - device.execute().set_input_line(0, CLEAR_LINE); - return m_irq_vector; + u8 result_vector = 0x00; + for (int i = 0; i < 8; i++) + { + u8 mask = m_irq_pending & (1 << i); + if (mask) + { + // TODO: understand how HW implements daisy chain if at all + // priority should be right, i.e. lower level gets serviced first + switch(i) + { + case SUB_CPU_IRQ: result_vector = sub_ack(); break; + case JOYSTICK_IRQ: result_vector = joystick_ack(); break; + case TIMER_IRQ: result_vector = timer_ack(); break; + case VRTC_IRQ: result_vector = vrtc_ack(); break; + default: + throw emu_fatalerror("Unhandled irq ack %d", i); + } + m_irq_pending &= ~mask; + if (m_irq_pending == 0) + device.execute().set_input_line(0, CLEAR_LINE); + LOGIRQ("%s: ack %d, state %02x, vector %02x\n", machine().describe_context(), i, m_irq_pending, result_vector); + + return result_vector; + } + } + + // check if this ever happens + LOGIRQ("%s: spurious IRQ fired!\n", machine().describe_context()); + return 0x06; } uint8_t pc6001_state::ppi_porta_r() @@ -1162,8 +1311,20 @@ uint8_t pc6001_state::ppi_porta_r() void pc6001_state::ppi_porta_w(uint8_t data) { -// if(data != 0x06) -// printf("ppi_porta_w %02x\n",data); + // sub command + // [0x06]: trigger a 0x16 irq + // [0x19/0x39]: Cassette PLAY + // [0x1a]: Cassette STOP + // [0x1d/0x3d]: Cassette baud select 600 + // [0x1e/0x3e]: Cassette baud select 1200 + // [0x38]: Cassette RECord + + if (data == 0x6) + { + // (timing is unknown, 0.1 msec is way too short for Space Harrier) + m_sub_trig_timer->reset(); + m_sub_trig_timer->adjust(attotime::from_usec(3000)); + } } uint8_t pc6001_state::ppi_portb_r() @@ -1186,16 +1347,25 @@ uint8_t pc6001_state::ppi_portc_r() return 0x88; } +// TODO: move to own device, and add remapping tables depending on the mode used uint8_t pc6001_state::check_keyboard_press() { - int i,port_i,scancode; - uint8_t shift_pressed,caps_lock; + int i, port_i, scancode; + u8 shift_pressed, caps_lock; + u8 io_fn = m_io_fn_keys->read(); scancode = 0; shift_pressed = (m_io_key_modifiers->read() & 2)>>1; caps_lock = (m_io_key_modifiers->read() & 8)>>3; - for(port_i=0;port_i<3;port_i++) + if (io_fn) + { + for(i = 0; i < 5; i++) + if (BIT(io_fn, i)) + return (i + 0xf0) + shift_pressed * 5; + } + + for(port_i = 0; port_i < 3; port_i++) { for(i=0;i<32;i++) { @@ -1230,6 +1400,7 @@ uint8_t pc6001_state::check_keyboard_press() uint8_t pc6001_state::check_joy_press() { + // TODO: this may really just rearrange keyboard key presses in a joystick like fashion, somehow akin to Sharp X1 mode uint8_t p1_key = m_io_p1->read() ^ 0xff; uint8_t shift_key = m_io_key_modifiers->read() & 0x02; uint8_t space_key = m_io_keys[1]->read() & 0x01; @@ -1282,7 +1453,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(pc6001_state::cassette_callback) m_cur_keycode = cas_data_poll; cas_data_i = 0x80; /* data ready, poll irq */ - set_maincpu_irq_line(0x08); + set_subcpu_irq_vector(0x08); } else cas_data_i>>=1; @@ -1293,13 +1464,13 @@ TIMER_DEVICE_CALLBACK_MEMBER(pc6001_state::cassette_callback) { m_cas_offset = 0; m_cas_switch = 0; - if(IRQ_LOG) printf("Tape-E IRQ 0x12\n"); - set_maincpu_irq_line(0x12); + // Tape-E + set_subcpu_irq_vector(0x12); } else { - if(IRQ_LOG) printf("Tape-D IRQ 0x08\n"); - set_maincpu_irq_line(0x08); + // Tape-D + set_subcpu_irq_vector(0x08); } #endif } @@ -1310,33 +1481,28 @@ TIMER_DEVICE_CALLBACK_MEMBER(pc6001_state::keyboard_callback) uint32_t key1 = m_io_keys[0]->read(); uint32_t key2 = m_io_keys[1]->read(); uint32_t key3 = m_io_keys[2]->read(); + u8 key_fn = m_io_fn_keys->read(); // uint8_t p1_key = m_io_p1->read(); if(m_cas_switch == 0) { - if((key1 != m_old_key1) || (key2 != m_old_key2) || (key3 != m_old_key3)) + if((key1 != m_old_key1) || (key2 != m_old_key2) || (key3 != m_old_key3) || (key_fn != m_old_key_fn)) { m_cur_keycode = check_keyboard_press(); - if(IRQ_LOG) printf("KEY IRQ 0x02\n"); - set_maincpu_irq_line(0x02); + const u8 key_vector = (m_cur_keycode & 0xf0) == 0xf0 ? 0x14 : 0x02; + set_subcpu_irq_vector(key_vector); m_old_key1 = key1; m_old_key2 = key2; m_old_key3 = key3; + m_old_key_fn = key_fn; } - #if 0 - else /* joypad polling */ - { - m_cur_keycode = check_joy_press(); - if(m_cur_keycode) - set_maincpu_irq_line(0x16); - } - #endif } } void pc6001_state::machine_start() { m_timer_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pc6001_state::audio_callback),this)); + m_sub_trig_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pc6001_state::sub_trig_callback),this)); } inline void pc6001_state::set_videoram_bank(uint32_t offs) @@ -1344,39 +1510,64 @@ inline void pc6001_state::set_videoram_bank(uint32_t offs) m_video_base = m_region_maincpu->base() + offs; } -void pc6001_state::machine_reset() +inline void pc6001_state::default_cartridge_reset() { - set_videoram_bank(0xc000); - - if (m_cart->exists()) - m_maincpu->space(AS_PROGRAM).install_read_handler(0x4000, 0x5fff, read8sm_delegate(*m_cart, FUNC(generic_slot_device::read_rom))); - std::string region_tag; m_cart_rom = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str()); +} - m_port_c_8255=0; - +inline void pc6001_state::default_cassette_hack_reset() +{ m_cas_switch = 0; m_cas_offset = 0; m_cas_maxsize = (m_cas_hack->exists()) ? m_cas_hack->get_rom_size() : 0; - m_timer_irq_mask = 1; - m_timer_irq_mask2 = 1; +} + +inline void pc6001_state::default_keyboard_hle_reset() +{ + m_port_c_8255 = 0; + m_old_key1 = m_old_key2 = m_old_key3 = 0; + m_old_key_fn = 0; +} + +void pc6001_state::irq_reset(u8 timer_default_setting) +{ + m_timer_enable = false; + m_timer_irq_mask = false; // timer irq vector is fixed in plain PC-6001 m_timer_irq_vector = 0x06; - set_timer_divider(3); + m_irq_pending = 0; + m_timer_hz_div = timer_default_setting; + set_timer_divider(); +} + +void pc6001_state::machine_reset() +{ + set_videoram_bank(0xc000); + + default_cartridge_reset(); + if (m_cart->exists()) + m_maincpu->space(AS_PROGRAM).install_read_handler(0x4000, 0x5fff, read8sm_delegate(*m_cart, FUNC(generic_slot_device::read_rom))); + + default_cassette_hack_reset(); + irq_reset(3); + default_keyboard_hle_reset(); } void pc6001mk2_state::machine_reset() { - pc6001_state::machine_reset(); +// pc6001_state::machine_reset(); set_videoram_bank(0xc000 + 0x28000); - std::string region_tag; - m_cart_rom = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str()); + default_cartridge_reset(); // TODO: hackish way to simplify bankswitch handling - if (m_cart_rom) + if (m_cart->exists()) memcpy(m_region_maincpu->base() + 0x48000, m_cart_rom->base(), 0x4000); + default_cassette_hack_reset(); + irq_reset(3); + default_keyboard_hle_reset(); + /* set default bankswitch */ { uint8_t *ROM = m_region_maincpu->base(); @@ -1393,49 +1584,63 @@ void pc6001mk2_state::machine_reset() m_bank_opt = 0x02; //tv rom m_bank_w = 0x50; //enable write to work ram 4,5,6,7 m_gfx_bank_on = 0; + + m_bgcol_bank = 0; } // refresh_crtc_params(); } -void pc6001sr_state::machine_reset() +void pc6601_state::machine_start() { - pc6001_state::machine_reset(); - set_videoram_bank(0x70000); + pc6001mk2_state::machine_start(); - // default to bitmap mode - m_sr_text_mode = false; - m_sr_text_rows = 20; + m_fdc->set_rate(250000); + m_floppy->get_device()->set_rpm(300); +} - m_kludge = 0; +void pc6001mk2sr_state::machine_reset() +{ +// pc6001_state::machine_reset(); + default_cassette_hack_reset(); - std::string region_tag; - m_cart_rom = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str()); - // should this be mirrored into the EXROM regions? hard to tell without an actual cart dump... +// set_videoram_bank(0x70000); + m_video_base = &m_ram[0]; + + default_cartridge_reset(); + // TODO: checkout where cart actually maps in SR model + // should be mirrored into the EXROM regions? + // hard to tell without an actual SR cart dump +// std::string region_tag; +// m_cart_rom = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str()); + default_cassette_hack_reset(); + irq_reset(0x7f); + default_keyboard_hle_reset(); + + // default to text mode + m_sr_text_mode = true; + m_sr_text_rows = 20; + m_width80 = 0; /* set default bankswitch */ { - uint8_t *ROM = m_region_maincpu->base(); - m_sr_bank_r[0] = 0xf8; m_bank1->set_base(&ROM[SR_SYSROM_1(0x08)]); - m_sr_bank_r[1] = 0xfa; m_bank2->set_base(&ROM[SR_SYSROM_1(0x0a)]); - m_sr_bank_r[2] = 0xc0; m_bank3->set_base(&ROM[SR_EXROM1(0x00)]); - m_sr_bank_r[3] = 0xb0; m_bank4->set_base(&ROM[SR_EXROM0(0x00)]); - m_sr_bank_r[4] = 0x08; m_bank5->set_base(&ROM[SR_WRAM0(0x08)]); - m_sr_bank_r[5] = 0x0a; m_bank6->set_base(&ROM[SR_WRAM0(0x0a)]); - m_sr_bank_r[6] = 0x0c; m_bank7->set_base(&ROM[SR_WRAM0(0x0c)]); - m_sr_bank_r[7] = 0x0e; m_bank8->set_base(&ROM[SR_WRAM0(0x0e)]); -// m_bank_opt = 0x02; //tv rom - - /* enable default work RAM writes */ - m_sr_bank_w[0] = 0x00; - m_sr_bank_w[1] = 0x02; - m_sr_bank_w[2] = 0x04; - m_sr_bank_w[3] = 0x06; - m_sr_bank_w[4] = 0x08; - m_sr_bank_w[5] = 0x0a; - m_sr_bank_w[6] = 0x0c; - m_sr_bank_w[7] = 0x0e; - + // TODO: confirm this arrangement + u8 default_banks[16] = { + // read default: + // 0x0000 - 0x3fff sysrom 1 0x8000 - 0xbfff + // 0x4000 - 0x5fff exrom 1 0x0000 - 0x1fff + // 0x6000 - 0x7fff exrom 0 0x0000 - 0x1fff + // 0x8000 - 0xffff RAM 0x8000 - 0xffff + 0xf8, 0xfa, 0xc0, 0xb0, 0x08, 0x0a, 0x0c, 0x0e, + // enable all work RAM writes + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e + }; + + for (int i = 0; i < 16; i++) + { + m_sr_bank_reg[i] = default_banks[i] & 0xfe; + m_sr_bank[i]->set_bank(m_sr_bank_reg[i] >> 1); + } // m_gfx_bank_on = 0; } } @@ -1470,6 +1675,7 @@ static GFXDECODE_START( gfx_pc6001m2 ) GFXDECODE_ENTRY( "gfx2", 0x0000, kanji_layout, 2, 1 ) GFXDECODE_END +// TODO: same as PC-88 / PC-98 31'948'800 ? #define PC6001_MAIN_CLOCK 7987200 void pc6001_state::pc6001(machine_config &config) @@ -1478,7 +1684,7 @@ void pc6001_state::pc6001(machine_config &config) Z80(config, m_maincpu, PC6001_MAIN_CLOCK / 2); // PD 780C-1, ~4 Mhz m_maincpu->set_addrmap(AS_PROGRAM, &pc6001_state::pc6001_map); m_maincpu->set_addrmap(AS_IO, &pc6001_state::pc6001_io); - m_maincpu->set_vblank_int("screen", FUNC(pc6001_state::vrtc_irq)); +// m_maincpu->set_vblank_int("screen", FUNC(pc6001_state::vrtc_irq)); m_maincpu->set_irq_acknowledge_callback(FUNC(pc6001_state::irq_callback)); // I8049(config, "subcpu", 7987200); @@ -1488,7 +1694,7 @@ void pc6001_state::pc6001(machine_config &config) /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_refresh_hz(60); - m_screen->set_screen_update(FUNC(pc6001_state::screen_update_pc6001)); + m_screen->set_screen_update(FUNC(pc6001_state::screen_update)); m_screen->set_size(320, 25+192+26); m_screen->set_visarea(0, 319, 0, 239); m_screen->set_palette(m_palette); @@ -1507,6 +1713,7 @@ void pc6001_state::pc6001(machine_config &config) I8251(config, "uart", 0); GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "pc6001_cart"); + SOFTWARE_LIST(config, "cart_list_pc6001").set_original("pc6001_cart"); // CASSETTE(config, m_cassette); // m_cassette->set_formats(pc6001_cassette_formats); @@ -1515,35 +1722,61 @@ void pc6001_state::pc6001(machine_config &config) GENERIC_CARTSLOT(config, m_cas_hack, generic_plain_slot, "pc6001_cass", "cas,p6"); SPEAKER(config, "mono").front_center(); - ay8910_device &ay8910(AY8910(config, "ay8910", PC6001_MAIN_CLOCK/4)); - ay8910.port_a_read_callback().set_ioport("P1"); - ay8910.port_b_read_callback().set_ioport("P2"); - ay8910.add_route(ALL_OUTPUTS, "mono", 1.00); + AY8910(config, m_ay, PC6001_MAIN_CLOCK/4); + m_ay->port_a_read_callback().set_ioport("P1"); + m_ay->port_b_read_callback().set_ioport("P2"); + m_ay->add_route(ALL_OUTPUTS, "mono", 1.00); /* TODO: accurate timing on this */ TIMER(config, "keyboard_timer").configure_periodic(FUNC(pc6001_state::keyboard_callback), attotime::from_hz(250)); TIMER(config, "cassette_timer").configure_periodic(FUNC(pc6001_state::cassette_callback), attotime::from_hz(1200/12)); } - - void pc6001mk2_state::pc6001mk2(machine_config &config) { pc6001(config); /* basic machine hardware */ m_maincpu->set_addrmap(AS_PROGRAM, &pc6001mk2_state::pc6001mk2_map); m_maincpu->set_addrmap(AS_IO, &pc6001mk2_state::pc6001mk2_io); + m_maincpu->set_irq_acknowledge_callback(FUNC(pc6001mk2_state::irq_callback)); // MCFG_MACHINE_RESET_OVERRIDE(pc6001mk2_state,pc6001mk2) - m_screen->set_screen_update(FUNC(pc6001mk2_state::screen_update_pc6001mk2)); + m_screen->set_screen_update(FUNC(pc6001mk2_state::screen_update)); m_palette->set_entries(16+16); m_palette->set_init(FUNC(pc6001mk2_state::pc6001mk2_palette)); subdevice("gfxdecode")->set_info(gfx_pc6001m2); - UPD7752(config, "upd7752", PC6001_MAIN_CLOCK/4).add_route(ALL_OUTPUTS, "mono", 1.00); + UPD7752(config, "upd7752", PC6001_MAIN_CLOCK / 4).add_route(ALL_OUTPUTS, "mono", 1.00); +} + +void pc6601_state::floppy_formats(format_registration &fr) +{ + fr.add_mfm_containers(); + // TODO: cannot identify .dsk images anyway + // (HxC reports them to be MSX based images) + fr.add(FLOPPY_MSX_FORMAT); + fr.add(FLOPPY_DSK_FORMAT); +} + +static void pc6601_floppies(device_slot_interface &device) +{ + device.option_add("35dd", FLOPPY_35_DD); + device.option_add("35ssdd", FLOPPY_35_SSDD); +} + +void pc6601_state::pc6601_fdc_config(machine_config &config) +{ + UPD765A(config, m_fdc, 8'000'000, true, true); + FLOPPY_CONNECTOR(config, m_floppy, pc6601_floppies, "35ssdd", pc6601_state::floppy_formats).enable_sound(true); + + // TODO: slotify external I/F + // PC-6031 mini disk unit (single 5'25 2D drive) + PC80S31(config, m_pc80s31, XTAL(4'000'000)); + config.set_perfect_quantum(m_maincpu); +// config.set_perfect_quantum("pc80s31:fdc_cpu"); } void pc6601_state::pc6601(machine_config &config) @@ -1554,27 +1787,56 @@ void pc6601_state::pc6601(machine_config &config) Z80(config.replace(), m_maincpu, PC6001_MAIN_CLOCK / 2); m_maincpu->set_addrmap(AS_PROGRAM, &pc6601_state::pc6001mk2_map); m_maincpu->set_addrmap(AS_IO, &pc6601_state::pc6601_io); - m_maincpu->set_vblank_int("screen", FUNC(pc6001_state::vrtc_irq)); - m_maincpu->set_irq_acknowledge_callback(FUNC(pc6001_state::irq_callback)); +// m_maincpu->set_vblank_int("screen", FUNC(pc6001_state::vrtc_irq)); + m_maincpu->set_irq_acknowledge_callback(FUNC(pc6601_state::irq_callback)); + + pc6601_fdc_config(config); } -void pc6001sr_state::pc6001sr(machine_config &config) +void pc6001mk2sr_state::pc6001mk2sr(machine_config &config) { pc6001mk2(config); /* basic machine hardware */ - //*Yes*, PC-6001 SR Z80 CPU is actually slower than older models (better waitstates tho?) + // PC-6001SR clock is actually slower than older models (better waitstates tho?) Z80(config.replace(), m_maincpu, XTAL(3'579'545)); - m_maincpu->set_addrmap(AS_PROGRAM, &pc6001sr_state::pc6001sr_map); - m_maincpu->set_addrmap(AS_IO, &pc6001sr_state::pc6001sr_io); - m_maincpu->set_vblank_int("screen", FUNC(pc6001sr_state::sr_vrtc_irq)); - m_maincpu->set_irq_acknowledge_callback(FUNC(pc6001_state::irq_callback)); + m_maincpu->set_addrmap(AS_PROGRAM, &pc6001mk2sr_state::pc6001mk2sr_map); + m_maincpu->set_addrmap(AS_IO, &pc6001mk2sr_state::pc6001mk2sr_io); + m_maincpu->set_vblank_int("screen", FUNC(pc6001mk2sr_state::sr_vrtc_irq)); + m_maincpu->set_irq_acknowledge_callback(FUNC(pc6001mk2sr_state::irq_callback)); + + for (auto &bank : m_sr_bank) + { + ADDRESS_MAP_BANK(config, bank).set_map(&pc6001mk2sr_state::sr_banked_map).set_options(ENDIANNESS_LITTLE, 8, 20, 0x2000); + } + +// MCFG_MACHINE_RESET_OVERRIDE(pc6001mk2sr_state,pc6001mk2sr) + + m_screen->set_screen_update(FUNC(pc6001mk2sr_state::screen_update)); + + pc6601_fdc_config(config); + + config.device_remove("aysnd"); + YM2203(config, m_ym, PC6001_MAIN_CLOCK/4); + m_ym->port_a_read_callback().set_ioport("P1"); + m_ym->port_b_read_callback().set_ioport("P2"); + m_ym->add_route(ALL_OUTPUTS, "mono", 1.00); + + // TODO: 1D 3'5" floppy drive + // TODO: telopper board (system explicitly asks for missing tape dump tho) +} + +void pc6601sr_state::pc6601sr(machine_config &config) +{ + pc6001mk2sr(config); -// MCFG_MACHINE_RESET_OVERRIDE(pc6001sr_state,pc6001sr) + FLOPPY_CONNECTOR(config.replace(), m_floppy, pc6601_floppies, "35dd", pc6601sr_state::floppy_formats); - m_screen->set_screen_update(FUNC(pc6001sr_state::screen_update_pc6001sr)); + // TODO: IR keyboard (does it have functional differences wrt normal PC-6001?) + // TODO: TV tuner } +// TODO: all labels needs to be checked up /* ROM definition */ ROM_START( pc6001 ) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) @@ -1625,7 +1887,8 @@ ROM_START( pc6001mk2 ) ROM_COPY( "maincpu", 0x20000, 0x00000, 0x8000 ) ROM_END -ROM_START( pc6601 ) /* Variant of pc6001m2 */ +/* Variant of pc6001mk2 */ +ROM_START( pc6601 ) ROM_REGION( 0x50000, "maincpu", ROMREGION_ERASEFF ) ROM_LOAD( "basicrom.66", 0x10000, 0x8000, CRC(c0b01772) SHA1(9240bb6b97fe06f5f07b5d65541c4d2f8758cc2a) ) ROM_LOAD( "voicerom.66", 0x18000, 0x4000, CRC(91d078c1) SHA1(6a93bd7723ef67f461394530a9feee57c8caf7b7) ) @@ -1644,30 +1907,54 @@ ROM_START( pc6601 ) /* Variant of pc6001m2 */ ROM_COPY( "maincpu", 0x20000, 0x00000, 0x8000 ) ROM_END -ROM_START( pc6001sr ) - ROM_REGION( 0x90000, "maincpu", ROMREGION_ERASEFF ) +ROM_START( pc6001mk2sr ) + ROM_REGION( 0x20000, "sr_sysrom", ROMREGION_ERASEFF ) ROM_LOAD( "systemrom1.64", 0x10000, 0x10000, CRC(b6fc2db2) SHA1(dd48b1eee60aa34780f153359f5da7f590f8dff4) ) - ROM_LOAD( "systemrom2.64", 0x20000, 0x10000, CRC(55a62a1d) SHA1(3a19855d290fd4ac04e6066fe4a80ecd81dc8dd7) ) -// cgrom 1 0x30000, 0x10000 -// exrom 0 0x40000, 0x10000 -// exrom 1 0x50000, 0x10000 -// exram 0 0x60000, 0x10000 -// work ram 0 0x70000, 0x10000 -// 0x80000, 0x10000 + ROM_LOAD( "systemrom2.64", 0x00000, 0x10000, CRC(55a62a1d) SHA1(3a19855d290fd4ac04e6066fe4a80ecd81dc8dd7) ) ROM_REGION( 0x1000, "mcu", ROMREGION_ERASEFF ) ROM_LOAD( "i8049", 0x0000, 0x1000, NO_DUMP ) - ROM_REGION( 0x4000, "gfx1", 0 ) + ROM_REGION( 0x4000, "cgrom", 0 ) ROM_LOAD( "cgrom68.64", 0x0000, 0x4000, CRC(73bc3256) SHA1(5f80d62a95331dc39b2fb448a380fd10083947eb) ) + ROM_REGION( 0x4000, "gfx1", 0) + ROM_COPY( "cgrom", 0, 0, 0x4000 ) + + ROM_REGION( 0x8000, "gfx2", 0 ) + ROM_COPY( "sr_sysrom", 0x18000, 0x00000, 0x8000 ) +ROM_END + +ROM_START( pc6601sr ) + ROM_REGION( 0x20000, "sr_sysrom", ROMREGION_ERASEFF ) + // Note: identical to pc6001mk2sr? + ROM_LOAD( "systemrom1.68", 0x10000, 0x010000, CRC(b6fc2db2) SHA1(dd48b1eee60aa34780f153359f5da7f590f8dff4) ) + ROM_LOAD( "systemrom2.68", 0x00000, 0x010000, CRC(55a62a1d) SHA1(3a19855d290fd4ac04e6066fe4a80ecd81dc8dd7) ) + + // mkII compatible ROMs + ROM_REGION( 0x20000, "mk2", ROMREGION_ERASEFF ) + ROM_LOAD( "basicrom.68", 0x00000, 0x008000, CRC(516b1be3) SHA1(e9977fc13f65f009f03d0340b1f1eb9a3e586739) ) + ROM_LOAD( "voicerom.68", 0x08000, 0x004000, CRC(37ff3829) SHA1(f887e95e29d071df8329168b48c07b78e492c837) ) + ROM_LOAD( "cgrom60.68", 0x0c000, 0x002000, CRC(331473a9) SHA1(361836f9758d6d9b5133c9dc7860a7c74f9cf596) ) + ROM_LOAD( "cgrom66.68", 0x0e000, 0x002000, CRC(03ba2cf1) SHA1(6fb32a4332b26aba2f28c3d8872cac5606be3998) ) + ROM_LOAD( "sysrom2.68", 0x10000, 0x002000, CRC(07318218) SHA1(061f3e7d6c85a560846856feb55fdc0a1f561548) ) + + ROM_REGION( 0x1000, "mcu", ROMREGION_ERASEFF ) + ROM_LOAD( "i8049", 0x0000, 0x1000, NO_DUMP ) + + ROM_REGION( 0x4000, "cgrom", 0 ) + ROM_LOAD( "cgrom68.68", 0x000000, 0x004000, CRC(73bc3256) SHA1(5f80d62a95331dc39b2fb448a380fd10083947eb) ) + + ROM_REGION( 0x4000, "gfx1", 0) + ROM_COPY( "cgrom", 0, 0, 0x4000 ) + ROM_REGION( 0x8000, "gfx2", 0 ) - ROM_COPY( "maincpu", 0x28000, 0x00000, 0x8000 ) + ROM_COPY( "sr_sysrom", 0x18000, 0x00000, 0x8000 ) ROM_END -// YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME FLAGS -COMP( 1981, pc6001, 0, 0, pc6001, pc6001, pc6001_state, empty_init, "NEC", "PC-6001 (Japan)", MACHINE_NOT_WORKING ) -COMP( 1981, pc6001a, pc6001, 0, pc6001, pc6001, pc6001_state, empty_init, "NEC", "PC-6001A (US)", MACHINE_NOT_WORKING ) // This version is also known as the NEC Trek -COMP( 1983, pc6001mk2, pc6001, 0, pc6001mk2, pc6001, pc6001mk2_state, empty_init, "NEC", "PC-6001mkII (Japan)", MACHINE_NOT_WORKING ) -COMP( 1983, pc6601, pc6001, 0, pc6601, pc6001, pc6601_state, empty_init, "NEC", "PC-6601 (Japan)", MACHINE_NOT_WORKING ) -COMP( 1984, pc6001sr, pc6001, 0, pc6001sr, pc6001, pc6001sr_state, empty_init, "NEC", "PC-6001mkIISR (Japan)", MACHINE_NOT_WORKING ) +COMP( 1981, pc6001, 0, 0, pc6001, pc6001, pc6001_state, empty_init, "NEC", "PC-6001 (Japan)", MACHINE_NOT_WORKING ) +COMP( 1981, pc6001a, pc6001, 0, pc6001, pc6001, pc6001_state, empty_init, "NEC", "PC-6001A \"NEC Trek\" (US)", MACHINE_NOT_WORKING ) +COMP( 1983, pc6001mk2, 0, 0, pc6001mk2, pc6001, pc6001mk2_state, empty_init, "NEC", "PC-6001mkII (Japan)", MACHINE_NOT_WORKING ) +COMP( 1983, pc6601, pc6001, 0, pc6601, pc6001, pc6601_state, empty_init, "NEC", "PC-6601 (Japan)", MACHINE_NOT_WORKING ) +COMP( 1984, pc6001mk2sr, 0, 0, pc6001mk2sr, pc6001, pc6001mk2sr_state, empty_init, "NEC", "PC-6001mkIISR (Japan)", MACHINE_NOT_WORKING ) +COMP( 1984, pc6601sr, pc6001, 0, pc6601sr, pc6001, pc6601sr_state, empty_init, "NEC", "PC-6601SR \"Mr. PC\" (Japan)", MACHINE_NOT_WORKING ) diff --git a/src/mame/drivers/pc8801.cpp b/src/mame/drivers/pc8801.cpp index 2e975032af3..592c0d50c91 100644 --- a/src/mame/drivers/pc8801.cpp +++ b/src/mame/drivers/pc8801.cpp @@ -8,8 +8,6 @@ TODO: - implement proper i8214 routing, and add irq latch mechanism; - - Fix up Floppy Terminal Count 0 / 1 writes properly, Castle Excellent (and presumably other - games) is very picky about it. - implement proper upd3301 / i8257 text support (currently hacked around); - Add limits for extend work RAM; - waitstates; @@ -18,7 +16,7 @@ - refactor memory banking to use address maps; - video; - double check dipswitches; - - move PC80S31K to device, needed by PC-6601SR, PC-88VA, (vanilla & optional) PC-9801. + - move PC80S31K to device, needed by PC-6601SR, PC-88VA, (vanilla & optional) PC-9801. (in progress) Also notice that there are common points with SPC-1000 and TF-20 FDDs; - backport/merge what is portable to PC-8001; - implement bus slot mechanism for NEC boards ("PC-8800-**"), HAL PCG-8100 & GSX8800, diff --git a/src/mame/includes/pc6001.h b/src/mame/includes/pc6001.h index d0e065707cf..0279a863431 100644 --- a/src/mame/includes/pc6001.h +++ b/src/mame/includes/pc6001.h @@ -7,13 +7,19 @@ #include "cpu/z80/z80.h" +#include "formats/dsk_dsk.h" +#include "formats/msx_dsk.h" #include "imagedev/cassette.h" +#include "imagedev/floppy.h" +#include "machine/bankdev.h" #include "machine/i8251.h" #include "machine/i8255.h" +#include "machine/pc80s31k.h" #include "machine/timer.h" +#include "machine/upd765.h" #include "sound/ay8910.h" #include "sound/upd7752.h" -//#include "sound/ymopn.h" +#include "sound/ymopn.h" #include "video/mc6847.h" #include "bus/generic/slot.h" @@ -28,24 +34,26 @@ class pc6001_state : public driver_device { public: - pc6001_state(const machine_config &mconfig, device_type type, const char *tag) : - driver_device(mconfig, type, tag), - m_ppi(*this, "ppi8255"), - m_ram(*this, "ram"), - m_maincpu(*this, "maincpu"), - m_screen(*this, "screen"), - m_cassette(*this, "cassette"), - m_cas_hack(*this, "cas_hack"), - m_cart(*this, "cartslot"), - m_region_maincpu(*this, "maincpu"), - m_region_gfx1(*this, "gfx1"), - m_io_mode4_dsw(*this, "MODE4_DSW"), - m_io_p1(*this, "P1"), - m_io_p2(*this, "P2"), - m_io_keys(*this, "key%u", 1U), - m_io_key_modifiers(*this, "key_modifiers"), - m_bank1(*this, "bank1"), - m_palette(*this, "palette") + pc6001_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_ppi(*this, "ppi8255") + , m_ram(*this, "ram") + , m_maincpu(*this, "maincpu") + , m_screen(*this, "screen") + , m_cassette(*this, "cassette") + , m_cas_hack(*this, "cas_hack") + , m_cart(*this, "cartslot") + , m_ay(*this, "aysnd") + , m_region_maincpu(*this, "maincpu") + , m_region_gfx1(*this, "gfx1") + , m_io_mode4_dsw(*this, "MODE4_DSW") + , m_io_p1(*this, "P1") + , m_io_p2(*this, "P2") + , m_io_keys(*this, "key%u", 1U) + , m_io_fn_keys(*this, "key_fn") + , m_io_key_modifiers(*this, "key_modifiers") + , m_bank1(*this, "bank1") + , m_palette(*this, "palette") { } void system_latch_w(uint8_t data); @@ -54,10 +62,11 @@ public: void pc6001_palette(palette_device &palette) const; - uint32_t screen_update_pc6001(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + virtual uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - INTERRUPT_GEN_MEMBER(vrtc_irq); +// INTERRUPT_GEN_MEMBER(vrtc_irq); TIMER_CALLBACK_MEMBER(audio_callback); + TIMER_CALLBACK_MEMBER(sub_trig_callback); TIMER_DEVICE_CALLBACK_MEMBER(cassette_callback); TIMER_DEVICE_CALLBACK_MEMBER(keyboard_callback); @@ -68,11 +77,7 @@ public: void ppi_portc_w(uint8_t data); uint8_t ppi_portc_r(); - IRQ_CALLBACK_MEMBER(irq_callback); - void pc6001(machine_config &config); - void pc6001_io(address_map &map); - void pc6001_map(address_map &map); protected: required_device m_ppi; optional_shared_ptr m_ram; @@ -81,14 +86,16 @@ protected: optional_device m_cassette; optional_device m_cas_hack; required_device m_cart; - required_memory_region m_region_maincpu; + optional_device m_ay; + optional_memory_region m_region_maincpu; required_memory_region m_region_gfx1; required_ioport m_io_mode4_dsw; required_ioport m_io_p1; required_ioport m_io_p2; required_ioport_array<3> m_io_keys; + required_ioport m_io_fn_keys; required_ioport m_io_key_modifiers; - required_memory_bank m_bank1; + optional_memory_bank m_bank1; required_device m_palette; memory_region *m_cart_rom; @@ -97,16 +104,24 @@ protected: virtual void machine_start() override; virtual void machine_reset() override; + + void default_cartridge_reset(); + void default_cassette_hack_reset(); + void default_keyboard_hle_reset(); + void irq_reset(u8 timer_default_setting); + virtual void video_start() override; + void pc6001_map(address_map &map); + void pc6001_io(address_map &map); + // i/o functions uint8_t check_joy_press(); uint8_t check_keyboard_press(); inline void cassette_latch_control(bool new_state); inline void ppi_control_hack_w(uint8_t data); - inline void set_timer_divider(uint8_t data); + inline void set_timer_divider(); inline void set_videoram_bank(uint32_t offs); - inline void set_maincpu_irq_line(uint8_t vector_num); // video functions void draw_gfx_mode4(bitmap_ind16 &bitmap,const rectangle &cliprect,int attr); @@ -119,14 +134,13 @@ protected: emu_timer *m_timer_irq_timer; uint8_t *m_video_base; std::unique_ptr m_video_ram; - uint8_t m_irq_vector; uint8_t m_cas_switch; uint8_t m_sys_latch; uint32_t m_cas_offset; uint32_t m_cas_maxsize; uint8_t m_bank_opt; - uint8_t m_timer_irq_mask; - uint8_t m_timer_irq_mask2; + bool m_timer_enable; + bool m_timer_irq_mask; uint8_t m_port_c_8255; uint8_t m_cur_keycode; @@ -134,22 +148,52 @@ private: uint32_t m_old_key1; uint32_t m_old_key2; uint32_t m_old_key3; + u8 m_old_key_fn; + + emu_timer *m_sub_trig_timer; +// IRQ model +protected: + // vanilla PC-6001 just maps sub CPU and Timer IRQs, mapping is otherwise confirmed by $b8-$bf vector setups in SR machines + enum{ + SUB_CPU_IRQ = 0, + JOYSTICK_IRQ, + TIMER_IRQ, + VOICE_IRQ, + VRTC_IRQ, + RS232_IRQ, + PRINTER_IRQ, + EXT_IRQ + }; + + u8 timer_ack(); + u8 joystick_ack(); + u8 sub_ack(); + virtual u8 vrtc_ack(); + void set_irq_level(int which); + void set_subcpu_irq_vector(u8 vector_num); + IRQ_CALLBACK_MEMBER(irq_callback); + + virtual u8 get_timer_base_divider(); + +private: + u8 m_irq_pending; + u8 m_sub_vector; }; class pc6001mk2_state : public pc6001_state { public: - pc6001mk2_state(const machine_config &mconfig, device_type type, const char *tag) : - pc6001_state(mconfig, type, tag), - m_bank2(*this, "bank2"), - m_bank3(*this, "bank3"), - m_bank4(*this, "bank4"), - m_bank5(*this, "bank5"), - m_bank6(*this, "bank6"), - m_bank7(*this, "bank7"), - m_bank8(*this, "bank8") + pc6001mk2_state(const machine_config &mconfig, device_type type, const char *tag) + : pc6001_state(mconfig, type, tag) + , m_bank2(*this, "bank2") + , m_bank3(*this, "bank3") + , m_bank4(*this, "bank4") + , m_bank5(*this, "bank5") + , m_bank6(*this, "bank6") + , m_bank7(*this, "bank7") + , m_bank8(*this, "bank8") { } uint8_t mk2_bank_r0_r(); @@ -178,25 +222,28 @@ public: void pc6001mk2_palette(palette_device &palette) const; void pc6001mk2(machine_config &config); - uint32_t screen_update_pc6001mk2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + virtual uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; - void pc6001mk2_io(address_map &map); - void pc6001mk2_map(address_map &map); protected: + void pc6001mk2_map(address_map &map); + void pc6001mk2_io(address_map &map); + uint8_t m_bgcol_bank; uint8_t m_gfx_bank_on; - required_memory_bank m_bank2; - required_memory_bank m_bank3; - required_memory_bank m_bank4; - required_memory_bank m_bank5; - required_memory_bank m_bank6; - required_memory_bank m_bank7; - required_memory_bank m_bank8; - inline void refresh_crtc_params(); + optional_memory_bank m_bank2; + optional_memory_bank m_bank3; + optional_memory_bank m_bank4; + optional_memory_bank m_bank5; + optional_memory_bank m_bank6; + optional_memory_bank m_bank7; + optional_memory_bank m_bank8; + virtual void refresh_crtc_params(); virtual void video_start() override; virtual void machine_reset() override; + virtual u8 vrtc_ack() override; + private: uint8_t m_bank_r0; uint8_t m_bank_r1; @@ -213,79 +260,113 @@ private: class pc6601_state : public pc6001mk2_state { public: - pc6601_state(const machine_config &mconfig, device_type type, const char *tag) : - pc6001mk2_state(mconfig, type, tag) + pc6601_state(const machine_config &mconfig, device_type type, const char *tag) + : pc6001mk2_state(mconfig, type, tag) + , m_fdc(*this, "fdc") + , m_floppy(*this, "fdc:0") + , m_pc80s31(*this, "pc80s31") + , m_fdc_intf_view(*this, "fdc_intf") { } - uint8_t fdc_r(); - void fdc_w(uint8_t data); - void pc6601(machine_config &config); + +protected: + virtual void machine_start() override; + void pc6601_io(address_map &map); + + void pc6601_fdc_io(address_map &map); + void pc6601_fdc_config(machine_config &config); + static void floppy_formats(format_registration &fr); + + required_device m_fdc; + required_device m_floppy; + required_device m_pc80s31; + memory_view m_fdc_intf_view; + + u8 fdc_mon_r(); + void fdc_mon_w(u8 data); + void fdc_sel_w(u8 data); }; -class pc6001sr_state : public pc6601_state +class pc6001mk2sr_state : public pc6601_state { public: - pc6001sr_state(const machine_config &mconfig, device_type type, const char *tag) : - pc6601_state(mconfig, type, tag), - m_sr_irq_vectors(*this, "irq_vectors") + pc6001mk2sr_state(const machine_config &mconfig, device_type type, const char *tag) + : pc6601_state(mconfig, type, tag) + , m_sr_bank(*this, "sr_bank_%u", 1U) + , m_sr_irq_vectors(*this, "irq_vectors") +// , m_gvram_view(*this, "gvram_view") + , m_sr_scrollx(*this, "sr_scrollx") + , m_sr_scrolly(*this, "sr_scrolly") + , m_ym(*this, "ymsnd") { } - void pc6001sr(machine_config &config); + void pc6001mk2sr(machine_config &config); protected: virtual void video_start() override; virtual void machine_reset() override; + void pc6001mk2sr_map(address_map &map); + void sr_banked_map(address_map &map); + void pc6001mk2sr_io(address_map &map); + + virtual u8 vrtc_ack() override; + virtual u8 get_timer_base_divider() override; + private: - uint8_t m_sr_bank_r[8]; - uint8_t m_sr_bank_w[8]; - uint8_t m_kludge; + required_device_array m_sr_bank; + required_shared_ptr m_sr_irq_vectors; + required_shared_ptr m_sr_scrollx; + required_shared_ptr m_sr_scrolly; + required_device m_ym; + + u8 m_sr_bank_reg[16]; bool m_sr_text_mode; - uint8_t m_sr_text_rows; - std::unique_ptr m_gvram; - uint8_t m_bitmap_yoffs,m_bitmap_xoffs; + u8 m_sr_text_rows; + std::unique_ptr m_gvram; + u8 m_bitmap_yoffs, m_bitmap_xoffs; + u8 m_width80; + +// memory_view m_gvram_view; + + virtual u8 hw_rev_r(); + u8 sr_bank_reg_r(offs_t offset); + void sr_bank_reg_w(offs_t offset, u8 data); + + void sr_mode_w(u8 data); + void sr_vram_bank_w(u8 data); + void sr_system_latch_w(u8 data); + void necsr_ppi8255_w(offs_t offset, u8 data); + + virtual void refresh_crtc_params() override; + void sr_bitmap_yoffs_w(u8 data); + void sr_bitmap_xoffs_w(u8 data); + void refresh_gvram_access(bool is_write); + u8 work_ram_r(offs_t offset); + void work_ram_w(offs_t offset, u8 data); + u8 sr_gvram_r(offs_t offset); + void sr_gvram_w(offs_t offset, u8 data); + void crt_mode_w(u8 data); - enum{ - SUB_CPU_IRQ = 0, - JOYSTICK_IRQ, - TIMER_IRQ, - VOICE_IRQ, - VRTC_IRQ, - RS232_IRQ, - PRINTER_IRQ, - EXT_IRQ - }; + INTERRUPT_GEN_MEMBER(sr_vrtc_irq); - required_shared_ptr m_sr_irq_vectors; - - uint8_t hw_rev_r(); - uint8_t sr_bank_rn_r(offs_t offset); - void sr_bank_rn_w(offs_t offset, uint8_t data); - uint8_t sr_bank_wn_r(offs_t offset); - void sr_bank_wn_w(offs_t offset, uint8_t data); - void sr_work_ram0_w(offs_t offset, uint8_t data); - void sr_work_ram1_w(offs_t offset, uint8_t data); - void sr_work_ram2_w(offs_t offset, uint8_t data); - void sr_work_ram3_w(offs_t offset, uint8_t data); - void sr_work_ram4_w(offs_t offset, uint8_t data); - void sr_work_ram5_w(offs_t offset, uint8_t data); - void sr_work_ram6_w(offs_t offset, uint8_t data); - void sr_work_ram7_w(offs_t offset, uint8_t data); - void sr_mode_w(uint8_t data); - void sr_vram_bank_w(uint8_t data); - void sr_system_latch_w(uint8_t data); - void necsr_ppi8255_w(offs_t offset, uint8_t data); - void sr_bitmap_yoffs_w(uint8_t data); - void sr_bitmap_xoffs_w(uint8_t data); + virtual uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; - INTERRUPT_GEN_MEMBER(sr_vrtc_irq); +}; - uint32_t screen_update_pc6001sr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); +class pc6601sr_state : public pc6001mk2sr_state +{ +public: + pc6601sr_state(const machine_config &mconfig, device_type type, const char *tag) + : pc6001mk2sr_state(mconfig, type, tag) + { } + + void pc6601sr(machine_config &config); - void pc6001sr_io(address_map &map); - void pc6001sr_map(address_map &map); +private: + virtual u8 hw_rev_r() override; }; #endif diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 6794cbcb977..62b8e97f493 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -33853,8 +33853,9 @@ pc4 // pc6001 // pc6001a // pc6001mk2 // -pc6001sr // pc6601 // +pc6001mk2sr // +pc6601sr // @source:pc8001.cpp pc8001 // 1979 diff --git a/src/mame/video/pc6001.cpp b/src/mame/video/pc6001.cpp index e5943be7514..2c3804c6c88 100644 --- a/src/mame/video/pc6001.cpp +++ b/src/mame/video/pc6001.cpp @@ -126,7 +126,7 @@ void pc6001mk2_state::video_start() // ... } -void pc6001sr_state::video_start() +void pc6001mk2sr_state::video_start() { // m_video_ram = std::make_unique(0x4000); m_gvram = std::make_unique(320*256*8); // TODO: size @@ -134,7 +134,6 @@ void pc6001sr_state::video_start() save_pointer(NAME(m_gvram), 320*256*8); } -/* this is known as gfx mode 4 */ void pc6001_state::draw_gfx_mode4(bitmap_ind16 &bitmap,const rectangle &cliprect,int attr) { static const uint8_t pen_gattr[4][4] = { @@ -291,7 +290,6 @@ void pc6001_state::draw_tile_text(bitmap_ind16 &bitmap,const rectangle &cliprect color = pen ? (fgcol+0) : (fgcol+1); else color = pen ? (fgcol+1) : (fgcol+0); - } else { @@ -368,14 +366,14 @@ void pc6001_state::pc6001_screen_draw(bitmap_ind16 &bitmap,const rectangle &clip } } -uint32_t pc6001_state::screen_update_pc6001(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +uint32_t pc6001_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { pc6001_screen_draw(bitmap,cliprect,1); return 0; } -uint32_t pc6001mk2_state::screen_update_pc6001mk2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +uint32_t pc6001mk2_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { /* note: bitmap mode have priority over everything else, check American Truck */ if(m_exgfx_bitmap_mode) @@ -510,7 +508,7 @@ uint32_t pc6001mk2_state::screen_update_pc6001mk2(screen_device &screen, bitmap_ return 0; } -uint32_t pc6001sr_state::screen_update_pc6001sr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +uint32_t pc6001mk2sr_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { uint8_t const *const gfx_data = m_region_gfx1->base(); @@ -518,54 +516,69 @@ uint32_t pc6001sr_state::screen_update_pc6001sr(screen_device &screen, bitmap_in if(m_sr_text_mode == true) // text mode { - for(int y=0;y>(7-xi) & 1; + int res_x = x * 8 + xi; + + int pen = gfx_data[(tile * 0x10) + yi] >> (7 - xi) & 1; int fgcol = (attr & 0x0f) + 0x10; - int bgcol = ((attr & 0x70) >> 4) + 0x10 + ((m_bgcol_bank & 2) << 2); + // TODO: definitely wants bright colors for N66SR BASIC, but quite won't work for "PC-6*01 World" screens + // (can't pinpoint banking on this HW, or maybe it's side effect of CLUT?) + int bgcol = ((attr & 0x70) >> 4) + 0x18; //+ m_bgcol_bank; int color = pen ? fgcol : bgcol; - if (cliprect.contains(x*8+xi, y*12+yi)) - bitmap.pix(((y*12+yi)), (x*8+xi)) = m_palette->pen(color); + if (cliprect.contains(res_x, res_y)) + bitmap.pix(res_y, res_x) = m_palette->pen(color); } } } } } - else //4bpp bitmap mode (TODO) + else { - for(int y=0;y<200;y++) + //4bpp bitmap mode + const u32 scroll_x = (m_sr_scrollx[0]) + (m_sr_scrollx[1] << 8); + const u32 scroll_y = m_sr_scrolly[0]; + const int x_pitch = 320; + const int y_pitch = 204; + + //popmessage("%04x %02x", scroll_x, scroll_y); + + for(int y = cliprect.min_y; y <= cliprect.max_y; y++) { - for(int x=0;x<320;x+=2) + for(int x = cliprect.min_x; x <= cliprect.max_x; x++) { uint32_t vram_addr; - if(x >= 256) - vram_addr = 0x1a00 + (x-256)+y*64; - else - vram_addr = x+y*256; - - int color; + // The Jp emulators maps this for the rightmost X > 256, but it doesn't seem to be the case? +// vram_addr = 0x1a00 + (x-256)+y*64; - color = (m_gvram[vram_addr] & 0xf0) >> 4; - if (cliprect.contains(x, y+0)) - bitmap.pix((y+0), (x+0)) = m_palette->pen(color+0x10); + // TODO: scrolling is preliminary, based off how Pakuridius sets VRAM and scroll regs + // It seems to wraparound at 320x204 + // Title screen scrolling usage is quite jerky, but it sorta makes sense on gameplay ... + vram_addr = ((x + scroll_x) % x_pitch) + ((y + scroll_y) % y_pitch) * x_pitch; - color = (m_gvram[vram_addr] & 0x0f); - if (cliprect.contains(x+1, y+0)) - bitmap.pix((y+0), (x+1)) = m_palette->pen(color+0x10); + // wants RGB -> BRG rotation + // (is it using a different palette bank?) + u8 color = bitswap<4>(m_gvram[vram_addr] & 0x0f, 3, 0, 2, 1) + 0x10; + if (cliprect.contains(x, y)) + bitmap.pix(y, x) = m_palette->pen(color); } } } -- cgit v1.2.3