summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/at.cpp
blob: 237f0770d9ab00040cb30d98429974f54f52b358 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                                         





                                                                            
                




                               
                         
                    
 
                     
 
                                                                     
 

                                                                                                             





















                                                         
                                                                                                                                             

 

                                                       
                            


                                                                             
                                                                         
                                                                            
 
 

                                                             





                                                                                            
 
















                                                                                         
 














                                                                                     
 



                                                                                        
 


                                                                                               
 
                                   

                                                       

















                                                                                                                             
                                                                      

                                                      
                                                                            
                                            

                            
                                               
                                                                              
 
                                                                                                   





                                                                                  



                                                                                            
 
 



                                                                                                                          
                                                                                                                   
                                                                                         

                                                                                                                                       

                                                                                                                                   


                                                                                                                         
 




                                                               
                                                  

                                 
                                                      



                    





                                                                           
                                                     

                                     
                                                       









                                                               
                                                       
 

                                                       


 





                                                                           
                                            
 
                                                 



















                                                       
                                                       





                                                                                  
                                                                                    



















                                                       
                                                  
 
                                                                                     




                                   
                                                  
 
                                                                                                

                               
                       
                                                                             
 
                                                            



                      
                                                              
 
                                                                                                

                               
                                                                             
 
                                                          


 
                                                  
 
                                                                                                

                               
                        
                                                                                 
 
                                                                                
                                          
 
                             


 
                                                              
 
                                                                                                

                               
                                                                                 
 
                                                                                                

 






                                                                                                                              

 






                                                                                                    
 
                                                  


                                         
                                                                                      
 
 






                                                                                       
                                                          
 









                                                               

 
                                                         
 

                                            


                                                                              

              
                                               
         

 
                                          
 
                                             

 













                                                                                                   
                               
 
                                    


                                                               
                                                                   
 
                       






                                                      
                                        
 



                                             







                                                                       
 
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol, Miodrag Milanovic, Carl
/***************************************************************************

    IBM AT Compatibles

***************************************************************************/

#include "emu.h"
#include "machine/at.h"
#include "cpu/i86/i286.h"
#include "cpu/i386/i386.h"
#include "machine/at_keybc.h"
#include "bus/pc_kbd/pc_kbdc.h"
#include "softlist_dev.h"
#include "speaker.h"

#define LOG_PORT80  0

DEFINE_DEVICE_TYPE(AT_MB, at_mb_device, "at_mb", "PC/AT Motherboard")

at_mb_device::at_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, AT_MB, tag, owner, clock),
	m_maincpu(*this, ":maincpu"),
	m_isabus(*this, "isabus"),
	m_pic8259_slave(*this, "pic8259_slave"),
	m_dma8237_1(*this, "dma8237_1"),
	m_dma8237_2(*this, "dma8237_2"),
	m_pit8254(*this, "pit8254"),
	m_speaker(*this, "speaker"),
	m_mc146818(*this, "rtc")
{
}

void at_mb_device::device_reset()
{
	m_at_spkrdata = 0;
	m_pit_out2 = 1;
	m_dma_channel = -1;
	m_cur_eop = false;
}

void at_mb_device::device_start()
{
	if(!strncmp(m_maincpu->shortname(), "i80286", 6))
		downcast<i80286_cpu_device *>(m_maincpu.target())->set_a20_callback(i80286_cpu_device::a20_cb(&at_mb_device::a20_286, this));
}

void at_mb_device::at_softlists(machine_config &config)
{
	/* software lists */
	SOFTWARE_LIST(config, "pc_disk_list").set_original("ibm5150");
	SOFTWARE_LIST(config, "at_disk_list").set_original("ibm5170");
	SOFTWARE_LIST(config, "at_cdrom_list").set_original("ibm5170_cdrom");
	SOFTWARE_LIST(config, "at_hdd_list").set_original("ibm5170_hdd");
	SOFTWARE_LIST(config, "midi_disk_list").set_compatible("midi_flop");
}

void at_mb_device::device_add_mconfig(machine_config &config)
{
	PIT8254(config, m_pit8254, 0);
	m_pit8254->set_clk<0>(4772720/4); /* heartbeat IRQ */
	m_pit8254->out_handler<0>().set("pic8259_master", FUNC(pic8259_device::ir0_w));
	m_pit8254->set_clk<1>(4772720/4); /* dram refresh */
	m_pit8254->set_clk<2>(4772720/4); /* pio port c pin 4, and speaker polling enough */
	m_pit8254->out_handler<2>().set(FUNC(at_mb_device::pit8254_out2_changed));

	AM9517A(config, m_dma8237_1, 14.318181_MHz_XTAL / 3);
	m_dma8237_1->out_hreq_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq0_w));
	m_dma8237_1->out_eop_callback().set(FUNC(at_mb_device::dma8237_out_eop));
	m_dma8237_1->in_memr_callback().set(FUNC(at_mb_device::dma_read_byte));
	m_dma8237_1->out_memw_callback().set(FUNC(at_mb_device::dma_write_byte));
	m_dma8237_1->in_ior_callback<0>().set(FUNC(at_mb_device::dma8237_0_dack_r));
	m_dma8237_1->in_ior_callback<1>().set(FUNC(at_mb_device::dma8237_1_dack_r));
	m_dma8237_1->in_ior_callback<2>().set(FUNC(at_mb_device::dma8237_2_dack_r));
	m_dma8237_1->in_ior_callback<3>().set(FUNC(at_mb_device::dma8237_3_dack_r));
	m_dma8237_1->out_iow_callback<0>().set(FUNC(at_mb_device::dma8237_0_dack_w));
	m_dma8237_1->out_iow_callback<1>().set(FUNC(at_mb_device::dma8237_1_dack_w));
	m_dma8237_1->out_iow_callback<2>().set(FUNC(at_mb_device::dma8237_2_dack_w));
	m_dma8237_1->out_iow_callback<3>().set(FUNC(at_mb_device::dma8237_3_dack_w));
	m_dma8237_1->out_dack_callback<0>().set(FUNC(at_mb_device::dack0_w));
	m_dma8237_1->out_dack_callback<1>().set(FUNC(at_mb_device::dack1_w));
	m_dma8237_1->out_dack_callback<2>().set(FUNC(at_mb_device::dack2_w));
	m_dma8237_1->out_dack_callback<3>().set(FUNC(at_mb_device::dack3_w));

	AM9517A(config, m_dma8237_2, 14.318181_MHz_XTAL / 3);
	m_dma8237_2->out_hreq_callback().set(FUNC(at_mb_device::dma_hrq_changed));
	m_dma8237_2->out_eop_callback().set(FUNC(at_mb_device::dma8237_2_out_eop));
	m_dma8237_2->in_memr_callback().set(FUNC(at_mb_device::dma_read_word));
	m_dma8237_2->out_memw_callback().set(FUNC(at_mb_device::dma_write_word));
	m_dma8237_2->in_ior_callback<1>().set(FUNC(at_mb_device::dma8237_5_dack_r));
	m_dma8237_2->in_ior_callback<2>().set(FUNC(at_mb_device::dma8237_6_dack_r));
	m_dma8237_2->in_ior_callback<3>().set(FUNC(at_mb_device::dma8237_7_dack_r));
	m_dma8237_2->out_iow_callback<1>().set(FUNC(at_mb_device::dma8237_5_dack_w));
	m_dma8237_2->out_iow_callback<2>().set(FUNC(at_mb_device::dma8237_6_dack_w));
	m_dma8237_2->out_iow_callback<3>().set(FUNC(at_mb_device::dma8237_7_dack_w));
	m_dma8237_2->out_dack_callback<0>().set(FUNC(at_mb_device::dack4_w));
	m_dma8237_2->out_dack_callback<1>().set(FUNC(at_mb_device::dack5_w));
	m_dma8237_2->out_dack_callback<2>().set(FUNC(at_mb_device::dack6_w));
	m_dma8237_2->out_dack_callback<3>().set(FUNC(at_mb_device::dack7_w));

	pic8259_device &pic8259_master(PIC8259(config, "pic8259_master", 0));
	pic8259_master.out_int_callback().set_inputline(":maincpu", 0);
	pic8259_master.in_sp_callback().set_constant(1);
	pic8259_master.read_slave_ack_callback().set(FUNC(at_mb_device::get_slave_ack));

	PIC8259(config, m_pic8259_slave, 0);
	m_pic8259_slave->out_int_callback().set("pic8259_master", FUNC(pic8259_device::ir2_w));
	m_pic8259_slave->in_sp_callback().set_constant(0);

	ISA16(config, m_isabus, 0);
	m_isabus->set_memspace(":maincpu", AS_PROGRAM);
	m_isabus->set_iospace(":maincpu", AS_IO);
	m_isabus->irq2_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir2_w)); // in place of irq 2 on at irq 9 is used
	m_isabus->irq3_callback().set("pic8259_master", FUNC(pic8259_device::ir3_w));
	m_isabus->irq4_callback().set("pic8259_master", FUNC(pic8259_device::ir4_w));
	m_isabus->irq5_callback().set("pic8259_master", FUNC(pic8259_device::ir5_w));
	m_isabus->irq6_callback().set("pic8259_master", FUNC(pic8259_device::ir6_w));
	m_isabus->irq7_callback().set("pic8259_master", FUNC(pic8259_device::ir7_w));
	m_isabus->irq10_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir3_w));
	m_isabus->irq11_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir4_w));
	m_isabus->irq12_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir5_w));
	m_isabus->irq14_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir6_w));
	m_isabus->irq15_callback().set(m_pic8259_slave, FUNC(pic8259_device::ir7_w));
	m_isabus->drq0_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq0_w));
	m_isabus->drq1_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq1_w));
	m_isabus->drq2_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq2_w));
	m_isabus->drq3_callback().set(m_dma8237_1, FUNC(am9517a_device::dreq3_w));
	m_isabus->drq5_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq1_w));
	m_isabus->drq6_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq2_w));
	m_isabus->drq7_callback().set(m_dma8237_2, FUNC(am9517a_device::dreq3_w));
	m_isabus->iochck_callback().set(FUNC(at_mb_device::iochck_w));

	MC146818(config, m_mc146818, 32.768_kHz_XTAL);
	m_mc146818->irq().set(m_pic8259_slave, FUNC(pic8259_device::ir0_w));
	m_mc146818->set_century_index(0x32);

	/* sound hardware */
	SPEAKER(config, "mono").front_center();
	SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);

	at_keyboard_controller_device &keybc(AT_KEYBOARD_CONTROLLER(config, "keybc", 12_MHz_XTAL));
	keybc.hot_res().set_inputline(":maincpu", INPUT_LINE_RESET);
	keybc.gate_a20().set_inputline(":maincpu", INPUT_LINE_A20);
	keybc.kbd_irq().set("pic8259_master", FUNC(pic8259_device::ir1_w));
	keybc.kbd_clk().set("pc_kbdc", FUNC(pc_kbdc_device::clock_write_from_mb));
	keybc.kbd_data().set("pc_kbdc", FUNC(pc_kbdc_device::data_write_from_mb));

	pc_kbdc_device &pc_kbdc(PC_KBDC(config, "pc_kbdc", 0));
	pc_kbdc.out_clock_cb().set("keybc", FUNC(at_keyboard_controller_device::kbd_clk_w));
	pc_kbdc.out_data_cb().set("keybc", FUNC(at_keyboard_controller_device::kbd_data_w));
}


void at_mb_device::map(address_map &map)
{
	map(0x0000, 0x001f).rw("dma8237_1", FUNC(am9517a_device::read), FUNC(am9517a_device::write)).umask16(0xffff);
	map(0x0020, 0x003f).rw("pic8259_master", FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0xffff);
	map(0x0040, 0x005f).rw(m_pit8254, FUNC(pit8254_device::read), FUNC(pit8254_device::write)).umask16(0xffff);
	map(0x0061, 0x0061).rw(FUNC(at_mb_device::portb_r), FUNC(at_mb_device::portb_w));
	map(0x0060, 0x0060).rw("keybc", FUNC(at_keyboard_controller_device::data_r), FUNC(at_keyboard_controller_device::data_w));
	map(0x0064, 0x0064).rw("keybc", FUNC(at_keyboard_controller_device::status_r), FUNC(at_keyboard_controller_device::command_w));
	map(0x0070, 0x007f).r("rtc", FUNC(mc146818_device::read)).umask16(0xffff).w(FUNC(at_mb_device::write_rtc)).umask16(0xffff);
	map(0x0080, 0x009f).rw(FUNC(at_mb_device::page8_r), FUNC(at_mb_device::page8_w)).umask16(0xffff);
	map(0x00a0, 0x00bf).rw("pic8259_slave", FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0xffff);
	map(0x00c0, 0x00df).rw("dma8237_2", FUNC(am9517a_device::read), FUNC(am9517a_device::write)).umask16(0x00ff);
}

/*************************************************************
 *
 * pic8259 configuration
 *
 *************************************************************/
uint8_t at_mb_device::get_slave_ack(offs_t offset)
{
	if (offset==2) // IRQ = 2
		return m_pic8259_slave->acknowledge();

	return 0x00;
}

/*************************************************************************
 *
 *      PC Speaker related
 *
 *************************************************************************/

void at_mb_device::speaker_set_spkrdata(uint8_t data)
{
	m_at_spkrdata = data ? 1 : 0;
	m_speaker->level_w(m_at_spkrdata & m_pit_out2);
}



/*************************************************************
 *
 * pit8254 configuration
 *
 *************************************************************/

WRITE_LINE_MEMBER( at_mb_device::pit8254_out2_changed )
{
	m_pit_out2 = state ? 1 : 0;
	m_speaker->level_w(m_at_spkrdata & m_pit_out2);
}


/*************************************************************************
 *
 *      PC DMA stuff
 *
 *************************************************************************/

uint8_t at_mb_device::page8_r(offs_t offset)
{
	uint8_t data = m_at_pages[offset % 0x10];

	switch(offset % 8)
	{
	case 1:
		data = m_dma_offset[BIT(offset, 3)][2];
		break;
	case 2:
		data = m_dma_offset[BIT(offset, 3)][3];
		break;
	case 3:
		data = m_dma_offset[BIT(offset, 3)][1];
		break;
	case 7:
		data = m_dma_offset[BIT(offset, 3)][0];
		break;
	}
	return data;
}


void at_mb_device::page8_w(offs_t offset, uint8_t data)
{
	m_at_pages[offset % 0x10] = data;

	if (LOG_PORT80 && (offset == 0))
	{
		logerror(" at_page8_w(): Port 80h <== 0x%02x (PC=0x%08x)\n", data,
							(unsigned) m_maincpu->pc());
	}

	switch(offset % 8)
	{
	case 1:
		m_dma_offset[BIT(offset, 3)][2] = data;
		break;
	case 2:
		m_dma_offset[BIT(offset, 3)][3] = data;
		break;
	case 3:
		m_dma_offset[BIT(offset, 3)][1] = data;
		break;
	case 7:
		m_dma_offset[BIT(offset, 3)][0] = data;
		break;
	}
}


WRITE_LINE_MEMBER( at_mb_device::dma_hrq_changed )
{
	m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);

	/* Assert HLDA */
	m_dma8237_2->hack_w(state);
}

uint8_t at_mb_device::dma_read_byte(offs_t offset)
{
	address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
	if(m_dma_channel == -1)
		return 0xff;
	uint8_t result;
	offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;

	result = prog_space.read_byte(page_offset + offset);
	return result;
}


void at_mb_device::dma_write_byte(offs_t offset, uint8_t data)
{
	address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
	if(m_dma_channel == -1)
		return;
	offs_t page_offset = ((offs_t) m_dma_offset[0][m_dma_channel]) << 16;

	prog_space.write_byte(page_offset + offset, data);
}


uint8_t at_mb_device::dma_read_word(offs_t offset)
{
	address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
	if(m_dma_channel == -1)
		return 0xff;
	uint16_t result;
	offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;

	result = prog_space.read_word((page_offset & 0xfe0000) | (offset << 1));
	m_dma_high_byte = result & 0xff00;

	return result & 0xff;
}


void at_mb_device::dma_write_word(offs_t offset, uint8_t data)
{
	address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
	if(m_dma_channel == -1)
		return;
	offs_t page_offset = ((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16;

	prog_space.write_word((page_offset & 0xfe0000) | (offset << 1), m_dma_high_byte | data);
}

uint8_t at_mb_device::dma8237_0_dack_r() { return m_isabus->dack_r(0); }
uint8_t at_mb_device::dma8237_1_dack_r() { return m_isabus->dack_r(1); }
uint8_t at_mb_device::dma8237_2_dack_r() { return m_isabus->dack_r(2); }
uint8_t at_mb_device::dma8237_3_dack_r() { return m_isabus->dack_r(3); }
uint8_t at_mb_device::dma8237_5_dack_r() { uint16_t ret = m_isabus->dack16_r(5); m_dma_high_byte = ret & 0xff00; return ret; }
uint8_t at_mb_device::dma8237_6_dack_r() { uint16_t ret = m_isabus->dack16_r(6); m_dma_high_byte = ret & 0xff00; return ret; }
uint8_t at_mb_device::dma8237_7_dack_r() { uint16_t ret = m_isabus->dack16_r(7); m_dma_high_byte = ret & 0xff00; return ret; }


void at_mb_device::dma8237_0_dack_w(uint8_t data) { m_isabus->dack_w(0, data); }
void at_mb_device::dma8237_1_dack_w(uint8_t data) { m_isabus->dack_w(1, data); }
void at_mb_device::dma8237_2_dack_w(uint8_t data) { m_isabus->dack_w(2, data); }
void at_mb_device::dma8237_3_dack_w(uint8_t data) { m_isabus->dack_w(3, data); }
void at_mb_device::dma8237_5_dack_w(uint8_t data) { m_isabus->dack16_w(5, m_dma_high_byte | data); }
void at_mb_device::dma8237_6_dack_w(uint8_t data) { m_isabus->dack16_w(6, m_dma_high_byte | data); }
void at_mb_device::dma8237_7_dack_w(uint8_t data) { m_isabus->dack16_w(7, m_dma_high_byte | data); }

WRITE_LINE_MEMBER( at_mb_device::dma8237_out_eop )
{
	m_cur_eop = state == ASSERT_LINE;
	if(m_dma_channel != -1)
		m_isabus->eop_w(m_dma_channel, m_cur_eop ? ASSERT_LINE : CLEAR_LINE );
}

WRITE_LINE_MEMBER( at_mb_device::dma8237_2_out_eop )
{
	m_cur_eop2 = state == ASSERT_LINE;
	if(m_dma_channel != -1)
		m_isabus->eop_w(m_dma_channel, m_cur_eop2 ? ASSERT_LINE : CLEAR_LINE );
}

void at_mb_device::set_dma_channel(int channel, int state)
{
	if(!state) {
		m_dma_channel = channel;
		if(m_cur_eop)
			m_isabus->eop_w(channel, ASSERT_LINE );

	} else if(m_dma_channel == channel) {
		m_dma_channel = -1;
		if(m_cur_eop)
			m_isabus->eop_w(channel, CLEAR_LINE );
	}
}

void at_mb_device::write_rtc(offs_t offset, uint8_t data)
{
	if (offset==0) {
		m_nmi_enabled = BIT(data,7);
		if (!m_nmi_enabled)
			m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
		m_mc146818->write(0,data);
	}
	else {
		m_mc146818->write(offset,data);
	}
}

uint32_t at_mb_device::a20_286(bool state)
{
	return (state ? 0xffffff : 0xefffff);
}

WRITE_LINE_MEMBER( at_mb_device::shutdown )
{
	if(state)
		m_maincpu->reset();
}
WRITE_LINE_MEMBER( at_mb_device::dack0_w ) { set_dma_channel(0, state); }
WRITE_LINE_MEMBER( at_mb_device::dack1_w ) { set_dma_channel(1, state); }
WRITE_LINE_MEMBER( at_mb_device::dack2_w ) { set_dma_channel(2, state); }
WRITE_LINE_MEMBER( at_mb_device::dack3_w ) { set_dma_channel(3, state); }
WRITE_LINE_MEMBER( at_mb_device::dack4_w ) { m_dma8237_1->hack_w(state ? 0 : 1); } // it's inverted
WRITE_LINE_MEMBER( at_mb_device::dack5_w ) { set_dma_channel(5, state); }
WRITE_LINE_MEMBER( at_mb_device::dack6_w ) { set_dma_channel(6, state); }
WRITE_LINE_MEMBER( at_mb_device::dack7_w ) { set_dma_channel(7, state); }

uint8_t at_mb_device::portb_r()
{
	uint8_t data = m_at_speaker;
	data &= ~0xd0; /* AT BIOS don't likes this being set */

	/* 0x10 is the dram refresh line bit, 15.085us. */
	data |= (machine().time().as_ticks(110000) & 1) ? 0x10 : 0;

	if (m_pit_out2)
		data |= 0x20;
	else
		data &= ~0x20; /* ps2m30 wants this */

	return data;
}

void at_mb_device::portb_w(uint8_t data)
{
	m_at_speaker = data;
	m_pit8254->write_gate2(BIT(data, 0));
	speaker_set_spkrdata( BIT(data, 1));
	m_channel_check = BIT(data, 3);
	if (m_channel_check)
		m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
}

WRITE_LINE_MEMBER( at_mb_device::iochck_w )
{
	if (!state && m_nmi_enabled && !m_channel_check)
		m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
}