Merge pull request #563 from meesokim/patch-5

[spc1500] some feature fixed for the official demo application [Miso Kim]
This commit is contained in:
Miodrag Milanović 2016-01-13 17:46:31 +01:00
commit 2204ccc92c

View File

@ -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<palette_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<<hs)+n];
UINT8 *pa = &m_pcgram[(ascii*(m_crtc_vreg[0x9]+1))+n];
UINT8 b = *pa;
UINT8 r = *(pa+0x800);
UINT8 g = *(pa+0x1000);
@ -557,7 +597,6 @@ MC6845_UPDATE_ROW(spc1500_state::crtc_update_row)
}
else
{
//printf("%c", ascii);
UINT8 fnt = m_font[(hs == 4 ? 0x1000 : (attr & (1<<6) ? 0x80<<4 : 0)) + (ascii<<4) + n];
if (ascii == 0 && (attr & 0x08) && inv)
{
@ -821,6 +860,8 @@ void spc1500_state::machine_start()
// intialize banks 2, 3, 4 (write banks)
membank("bank2")->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")