diff --git a/src/mame/drivers/spc1500.cpp b/src/mame/drivers/spc1500.cpp index ac990ff514d..2017c27f3e7 100644 --- a/src/mame/drivers/spc1500.cpp +++ b/src/mame/drivers/spc1500.cpp @@ -12,9 +12,12 @@ Samsung SPC-1500 driver by Miso Kim 2016-01-03 user defined char (PCG, Programmable Character Generator) support 2016-01-05 detection of color palette initialization 2016-01-06 80x16 mode graphic mode support + 2016-01-10 double character support + 2016-01-12 PCG adressing improved + 2016-01-13 Cassette tape motor improved TODO: - - Verify PCG ram read + - Verify PCG ram read for Korean character (english character is fine) - Support floppy disk drive with SD-1500A controller card ****************************************************************************/ @@ -249,8 +252,8 @@ public: , m_pio(*this, "ppi8255") , m_sound(*this, "ay8910") , m_palette(*this, "palette") + , m_timer(nullptr) {} - DECLARE_WRITE_LINE_MEMBER(irq_w); DECLARE_READ8_MEMBER(psga_r); DECLARE_READ8_MEMBER(porta_r); DECLARE_WRITE_LINE_MEMBER( centronics_busy_w ) { m_centronics_busy = state; } @@ -280,19 +283,22 @@ public: DECLARE_VIDEO_START(spc); MC6845_UPDATE_ROW(crtc_update_row); MC6845_RECONFIGURE(crtc_reconfig); + TIMER_DEVICE_CALLBACK_MEMBER(timer); private: UINT8 *m_p_ram; UINT8 m_ipl; UINT8 m_palet[3]; UINT8 m_paltbl[8]; UINT16 m_page; - UINT16 m_pcg_addr; - UINT8 m_pcg_char, m_pcg_attr; + UINT8 m_pcg_char, m_pcg_attr, m_char_change, m_pcg_char0; + UINT16 m_pcg_offset[3]; + int m_char_count; attotime m_time; bool m_romsel; bool m_double_mode; bool m_p5bit; bool m_motor; + bool m_motor_toggle; UINT8 m_crtc_vreg[0x100]; bool m_centronics_busy; virtual void machine_start() override; @@ -312,6 +318,7 @@ private: required_device m_palette; UINT8 *m_font; UINT8 m_priority; + emu_timer *m_timer; void get_pcg_addr(); }; @@ -347,17 +354,17 @@ WRITE8_MEMBER( spc1500_state::portb_w) WRITE8_MEMBER( spc1500_state::psgb_w) { - attotime time = machine().scheduler().time(); + int elapsed_time = m_timer->elapsed().as_attoseconds()/ATTOSECONDS_PER_MICROSECOND; if (m_ipl != ((data>>1)&1)) { m_ipl = ((data>>1)&1); membank("bank1")->set_entry(m_ipl ? 0 : 1); } m_cass->set_state(BIT(data, 6) ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED); - if (!m_motor && BIT(data, 7) && ATTOSECONDS_IN_MSEC((time - m_time).as_attoseconds()) > 1000) + if (m_motor && !BIT(data, 7) && (elapsed_time > 100)) { m_cass->change_state((m_cass->get_state() & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); - m_time = time; + m_timer->reset(); } m_motor = BIT(data, 7); } @@ -369,13 +376,12 @@ WRITE8_MEMBER( spc1500_state::portc_w) m_double_mode = (!m_p5bit && BIT(data, 5)); // double access I/O mode m_p5bit = BIT(data, 5); m_vdg->set_clock(VDP_CLOCK/(BIT(data, 2) ? 48 : 24)); - } READ8_MEMBER( spc1500_state::portb_r) { UINT8 data = 0; - data |= ((m_cass->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) && ((m_cass->get_state() & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_ENABLED) ? 0x0 : 0x1; + data |= ((m_cass->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED || ((m_cass->get_state() & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED)); data |= (m_dipsw->read() & 1) << 4; data |= (m_cass->input() > 0.0038)<<1; data |= m_vdg->vsync_r()<<7; @@ -407,21 +413,15 @@ READ8_MEMBER( spc1500_state::crtc_r) return 0; } -READ8_MEMBER( spc1500_state::pcg_r) +TIMER_DEVICE_CALLBACK_MEMBER(spc1500_state::timer) { - get_pcg_addr(); - if (BIT(m_pcg_attr,5)) // PCG font + if(m_motor_toggle == true) { - if ((offset&0x1f00) == 0x1400) - offset += 0x300; - return m_pcgram[m_pcg_addr+(offset&0xf)+(((offset & 0x1f00) - 0x1500)<<3)]; + m_cass->change_state((m_cass->get_state() & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); + m_motor_toggle = false; } - else // ROM font - { - return m_font[(m_crtc_vreg[0x9]==15?0x1000:0)+m_pcg_addr+(offset&0xf)]; - } - return 0; } + void spc1500_state::get_pcg_addr() { UINT16 vaddr = 0; @@ -438,14 +438,44 @@ void spc1500_state::get_pcg_addr() } m_pcg_char = m_p_videoram[0x1000 + vaddr]; m_pcg_attr = m_p_videoram[vaddr]; - m_pcg_addr = m_pcg_char * (m_crtc_vreg[0x9]+1); + if (m_pcg_char != m_char_change) + { + m_char_change = m_pcg_char; + m_pcg_offset[0] = 0; + m_pcg_offset[1] = 0; + m_pcg_offset[2] = 0; + } } + WRITE8_MEMBER( spc1500_state::pcg_w) { + int reg = (offset>>8)-0x15; get_pcg_addr(); - m_pcg_addr=m_pcg_addr+(offset&0xf)+(((offset & 0x1f00) - 0x1500)<<3); - m_pcgram[m_pcg_addr] = data; -// printf("pcgram:0x%04x 0x%02x\n",m_pcg_addr, data); + + m_pcgram[m_pcg_char * 8 + m_pcg_offset[reg] + (reg*0x800)] = data; + if (m_pcg_offset[reg] == 7) + m_pcg_offset[reg] = 0; + else + m_pcg_offset[reg]++; +} + +READ8_MEMBER( spc1500_state::pcg_r) +{ + int reg = (offset>>8)-0x15; + UINT8 data = 0; + get_pcg_addr(); + if (reg < 0) reg = 2; + if (BIT(m_pcg_attr,5)) // PCG font + { + data = m_pcgram[m_pcg_char * 8 + m_pcg_offset[reg]+(reg*0x800)]; + } + else // ROM font + { + data = m_font[(m_crtc_vreg[0x9]==15?0x1000:0)+(m_pcg_char * 16)+m_pcg_offset[reg]]; + } + if (m_pcg_offset[reg]++ > m_crtc_vreg[0x9]-1) + m_pcg_offset[reg] = 0; + return data; } WRITE8_MEMBER( spc1500_state::priority_w) @@ -457,7 +487,9 @@ WRITE8_MEMBER( spc1500_state::palet_w) { m_palet[(offset>>8)&0x0f] = data; for(int i=1, j=0; i < 0x100; i<<=1, j++) + { m_paltbl[j] = (m_palet[0]&i?1:0)|(m_palet[1]&i?2:0)|(m_palet[2]&i?4:0); + } } PALETTE_INIT_MEMBER(spc1500_state,spc) @@ -515,23 +547,31 @@ MC6845_UPDATE_ROW(spc1500_state::crtc_update_row) UINT8 pen = (nopalet ? color : m_paltbl[color]); UINT8 pixelpen = 0; UINT8 pixel = 0; - if (hs == 4 && ascii & 0x80) + if (hs == 4 && (ascii & 0x80)) { UINT16 wpixelb = (pixelb << 8) + (*(pp+1)); UINT16 wpixelr = (pixelr << 8) + (*(pp+0x4001)); UINT16 wpixelg = (pixelg << 8) + (*(pp+0x8001)); - han2 = *(pv+0x1001); - h1 = (ascii>>2)&0x1f; - h2 = ((ascii<<3)|(han2>>5))&0x1f; - h3 = (han2)&0x1f; - pf = &m_font[0x2000+(h1 * 32) + (cho[h2] + (h3 != 0) -1) * 16 * 2 * 32 + n]; - hfnt = (*pf << 8) | (*(pf+16)); - pf = &m_font[0x4000+(h2 * 32) + (h3 == 0 ? 0 : 1) * 16 * 2 * 32 + n]; - hfnt = hfnt & ((*pf << 8) | (*(pf+16))); - pf = &m_font[0x6000+(h3 * 32) + (jong[h2]-1) * 16 * 2 * 32 + n]; - hfnt = hfnt & ((*pf << 8) | (*(pf+16))); + if (ascii != 0xfa) + { + han2 = *(pv+0x1001); + h1 = (ascii>>2)&0x1f; + h2 = ((ascii<<3)|(han2>>5))&0x1f; + h3 = (han2)&0x1f; + pf = &m_font[0x2000+(h1 * 32) + (cho[h2] + (h3 != 0) -1) * 16 * 2 * 32 + n]; + hfnt = (*pf << 8) | (*(pf+16)); + pf = &m_font[0x4000+(h2 * 32) + (h3 == 0 ? 0 : 1) * 16 * 2 * 32 + n]; + hfnt = hfnt & ((*pf << 8) | (*(pf+16))); + pf = &m_font[0x6000+(h3 * 32) + (jong[h2]-1) * 16 * 2 * 32 + n]; + hfnt = hfnt & ((*pf << 8) | (*(pf+16))); + } + else + { + ascii = *(pv+0x1001); + pf = &m_font[0x6000+(ascii*32) + n]; + hfnt = (*pf << 8) | (*(pf+16)); + } hfnt = (inv ? 0xffff - hfnt : hfnt); - //printf("0x%04x\n" , hfnt); for (j = 0x8000; j > 0; j>>=1) { pixel = ((wpixelg&j ? 4:0 )|(wpixelr&j? 2:0)|(wpixelb&j ? 1:0)); @@ -542,7 +582,7 @@ MC6845_UPDATE_ROW(spc1500_state::crtc_update_row) } else if (attr & 0x20) { - UINT8 *pa = &m_pcgram[(ascii<set_base(m_p_ram); membank("bank4")->set_base(m_p_ram + 0x8000); + m_timer = timer_alloc(0); + m_timer->adjust(attotime::zero); } void spc1500_state::machine_reset() @@ -829,6 +870,7 @@ void spc1500_state::machine_reset() m_time = machine().scheduler().time(); m_double_mode = false; memset(&m_paltbl[0], 1, 8); + m_char_count = 0; } READ8_MEMBER(spc1500_state::mc6845_videoram_r) @@ -853,11 +895,6 @@ READ8_MEMBER( spc1500_state::porta_r ) return data; } -WRITE_LINE_MEMBER( spc1500_state::irq_w ) -{ - m_maincpu->set_input_line(0, state ? CLEAR_LINE : HOLD_LINE); -} - static MACHINE_CONFIG_START( spc1500, spc1500_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu",Z80, XTAL_4MHz) @@ -873,7 +910,6 @@ static MACHINE_CONFIG_START( spc1500, spc1500_state ) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ MCFG_SCREEN_SIZE(640, 400) MCFG_SCREEN_VISIBLE_AREA(0,640-1,0,400-1) - //MCFG_MC6845_VISAREA_ADJUST(50,50,640-50,400-50) MCFG_SCREEN_UPDATE_DEVICE("mc6845", mc6845_device, screen_update ) MCFG_PALETTE_ADD("palette", 8) MCFG_PALETTE_INIT_OWNER(spc1500_state, spc) @@ -890,6 +926,8 @@ static MACHINE_CONFIG_START( spc1500, spc1500_state ) MCFG_I8255_OUT_PORTB_CB(WRITE8(spc1500_state, portb_w)) MCFG_I8255_OUT_PORTC_CB(WRITE8(spc1500_state, portc_w)) + MCFG_TIMER_DRIVER_ADD_PERIODIC("1hz", spc1500_state, timer, attotime::from_hz(1)) + /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("ay8910", AY8910, XTAL_4MHz / 2) @@ -906,7 +944,7 @@ static MACHINE_CONFIG_START( spc1500, spc1500_state ) MCFG_CASSETTE_ADD("cassette") MCFG_CASSETTE_FORMATS(spc1000_cassette_formats) - MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_DISABLED) + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_SPEAKER_MUTED | CASSETTE_MOTOR_DISABLED) MCFG_SOFTWARE_LIST_ADD("cass_list", "spc1500_cass")