summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/pc6001.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/pc6001.cpp')
-rw-r--r--src/mame/drivers/pc6001.cpp909
1 files changed, 598 insertions, 311 deletions
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_device>("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
-// <invalid> 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 )