summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/nforcepc.cpp
blob: 59d5ca5d712d22cff42275ed104f2f2ba66700ed (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11





                                                                                                 
                                      



                                                    
                        



                              
                            






                                      
                           
                            

                            
                             
                            




                                 
                              

                              
     

                                                                                       





                                                                                        
  












                                                                                        
 



             

                                       
                                                                                                   



                                                      
                                                                                               

                                                                                                         

 




                                                


                                                                                                                         
                                                
                     


 


                                        
                                       
                                            







                                       
                        















                                                                                                                                                  

                                                                                           
 



                                                                                                             

 
                                            
 
                 

 
                                             



                                        









                                                    


































                                                                                                                                           

                                                 
                                   
                                       
                                                   

                                                      
                        




                                          
                                         




                                                      

                                  




                                                                                                                                                    
                                                                                    

 
  


























































































                                                                                                                                                    




                                                                        

















































                                                                                                                                 











                                                                                                               








                                            
                                  

                                  

                                                                                          


                                                                          


                                                                            







                                            





                                        



















                                                                                                                                      
















                                                                                       
























































































                                                                                       
                                    
                                                                  

                                    
                                                                  

                                     



                                                                   









                                                         


         































































































                                                                                                           
















                                                                                 





































































































































                                                                                                                            






















                                                                                                                            

































































                                                                                                  









































                                                                                                      






                                                                                      




                                                                                     





                                                             









                                                                     
  

               



                                           

                              













                                                                                         

                                                     


                                              



                                                    

  




                                                                                                  




                                    
                                              






                                                                                  
                                               





                                                 


                                                               



                                                                 





                                                 
 


                                                                     

 


                                                 






                                                    











                                                                         



                       




                                                                        
                                                                                 
                                                                             
 
                                    
                                                                                                             


                                                                                                                   
                                                                                                                                             
                                                            

                                                                            


                                                                    





                                                                         







                                                                                                                     

                                                                                                                        





                                                                                                                   


                                                                                                          
                                                                                                                     
                                                                                                                 
                                            
                                       













                                                                                      
 

                   
                                                         
                                                                                                                                                          


                                                                                                                        









                                                                                                                        


                                  
                                 


                                                                                                                                          
// license:BSD-3-Clause
// copyright-holders: Samuele Zannoli

/*
  Computer based on a motherboard utilizing the nForce chipset (also known as CRUSH11 or CRUSH12)

  Start with the following components:
  - An Asus A7N266-C motherboard using:
    - nForce 415-D northbridge
    - nForce MCP-D southbridge (with integrated APU)
    - ITE IT8703F-A SuperIO
    - Asus AS99127F chip
  - An AMD Athlon XP processor
  - An IDE hard disk
  - A floppy disk drive
  - A keyboard
  - A ddr dimm memory module
  Later add:
  - A Nvidia NV25 based AGP video card

*/


#include "emu.h"
#include "bus/ata/atadev.h"
#include "cpu/i386/athlon.h"
#include "machine/pci.h"
#include "machine/pci-ide.h"
#include "machine/intelfsh.h"
#include "video/virge_pci.h"
#include "bus/rs232/rs232.h"
#include "bus/rs232/hlemouse.h"
#include "bus/rs232/null_modem.h"
#include "bus/rs232/sun_kbd.h"
#include "bus/rs232/terminal.h"
#include "includes/xbox_pci.h"
#include "includes/nforcepc.h"

#if 1
// for now let's use this as the contents of the spd chip in the ddr dimm memory module
static const uint8_t test_spd_data[] = {
	0x80,0x08,0x07,0x0D,0x0A,0x01,0x40,0x00,0x04,0x75,0x75,0x00,0x82,0x10,0x00,0x01,
	0x0E,0x04,0x0C,0x01,0x02,0x20,0xC0,0xA0,0x75,0x00,0x00,0x50,0x3C,0x50,0x2D,0x40,
	0x90,0x90,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x41,0x4B,0x30,0x32,0x75,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEA,
	0xAD,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x59,0x4D,0x44,0x35,0x33,0x32,
	0x4D,0x36,0x34,0x36,0x43,0x36,0x2D,0x48,0x20,0x20,0x20
};
#else
// From a HYS72D64320HU-5-C (512MB PC3200 (400mHz) DDR CL3 ECC)
static const uint8_t test_spd_data[] = {
	0x80,0x08,0x07,0x0d,0x0a,0x02,0x48,0x00,0x04,0x50,0x50,0x02,0x82,0x08,0x08,0x01,
	0x0e,0x04,0x1c,0x01,0x02,0x20,0xc1,0x60,0x50,0x75,0x50,0x3c,0x28,0x3c,0x28,0x40,
	0x60,0x60,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x37,0x41,0x28,0x28,0x50,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
	0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x37,0x32,0x44,0x36,0x34,0x33,0x32,
	0x30,0x48,0x55,0x35,0x43,0x20,0x20,0x20,0x20,0x20,0x20,0x02,0x4c,0x05,0x44,0x01,
	0x08,0x56,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
#endif

/*
  Pci devices
*/

// NVIDIA Corporation nForce CPU bridge

DEFINE_DEVICE_TYPE(CRUSH11, crush11_host_device, "crush11", "NVIDIA Corporation nForce CPU bridge")

void crush11_host_device::config_map(address_map &map)
{
	pci_host_device::config_map(map);
	map(0x10, 0x27).rw(FUNC(pci_device::address_base_r), FUNC(pci_device::address_base_w));
	map(0x84, 0x87).rw(FUNC(crush11_host_device::ram_size_r), FUNC(crush11_host_device::ram_size_w));
	map(0xf0, 0xf0).rw(FUNC(crush11_host_device::unknown_r), FUNC(crush11_host_device::unknown_w));
}

READ8_MEMBER(crush11_host_device::header_type_r)
{
	return 0x80; // from lspci dump
}

crush11_host_device::crush11_host_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: pci_host_device(mconfig, CRUSH11, tag, owner, clock)
	, cpu(*this, finder_base::DUMMY_TAG)
	, biosrom(*this, finder_base::DUMMY_TAG)
	, ram_size(0)
{
}

void crush11_host_device::device_start()
{
	pci_host_device::device_start();
	set_multifunction_device(true);
	memory_space = &cpu->space(AS_DATA);
	io_space = &cpu->space(AS_IO);

	memory_window_start = 0;
	memory_window_end = 0xffffffff;
	memory_offset = 0;
	io_window_start = 0;
	io_window_end = 0xffff;
	io_offset = 0;
	status = 0x00b0;
}

void crush11_host_device::reset_all_mappings()
{
	pci_host_device::reset_all_mappings();
}

void crush11_host_device::device_reset()
{
	pci_host_device::device_reset();
}

void crush11_host_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
	uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
{
	io_space->install_device(0, 0xffff, *static_cast<pci_host_device *>(this), &pci_host_device::io_configuration_access_map);
	memory_space->install_device(0, 0xffffffff, *this, &crush11_host_device::bios_map);
}

void crush11_host_device::bios_map(address_map &map)
{
	map(0x000c0000, 0x000fffff).rw(biosrom, FUNC(intelfsh8_device::read), FUNC(intelfsh8_device::write));
	map(0xfffc0000, 0xffffffff).rw(biosrom, FUNC(intelfsh8_device::read), FUNC(intelfsh8_device::write));
}

READ8_MEMBER(crush11_host_device::unknown_r)
{
	return 4;
}

WRITE8_MEMBER(crush11_host_device::unknown_w)
{
	logerror("test = %02x\n", data);
}

READ32_MEMBER(crush11_host_device::ram_size_r)
{
	return ram_size * 1024 * 1024 - 1;
}

WRITE32_MEMBER(crush11_host_device::ram_size_w)
{
	logerror("trying to set size = %d\n", data);
}

// For ddr ram

DEFINE_DEVICE_TYPE(CRUSH11_MEMORY, crush11_memory_device, "crush11_memory", "nForce memory")

void crush11_memory_device::config_map(address_map &map)
{
	pci_device::config_map(map);
	/*
	bit 31 of a0,a4,a8,ac,b0 and b4 must be 0
	bit 0 of c4 and c8 must be 0
	*/
	map(0xa0, 0xa3).nopr();
	map(0xa4, 0xa7).nopr();
	map(0xa8, 0xab).nopr();
	map(0xac, 0xaf).nopr();
	map(0xb0, 0xb3).nopr();
	map(0xb4, 0xb7).nopr();
	map(0xc4, 0xc7).nopr();
	map(0xc8, 0xcb).nopr();
}

crush11_memory_device::crush11_memory_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, int ram_size)
	: crush11_memory_device(mconfig, tag, owner, clock)
{
	set_ram_size(ram_size);
}

crush11_memory_device::crush11_memory_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: pci_device(mconfig, CRUSH11_MEMORY, tag, owner, clock)
{
	set_ids(0x10de01ac, 0, 0, 0);
}

void crush11_memory_device::device_start()
{
	device_t *r = owner()->subdevice("00.0");

	pci_device::device_start();
	set_multifunction_device(true);
	ram.resize(ddr_ram_size * 1024 * 1024 / 4);
	host = dynamic_cast<crush11_host_device *>(r);
	ram_space = host->get_cpu_space(AS_PROGRAM);
	status = 0x0020;
}

void crush11_memory_device::device_reset()
{
	pci_device::device_reset();
	host->set_ram_size(ddr_ram_size);
}

void crush11_memory_device::set_ram_size(int ram_size)
{
	ddr_ram_size = ram_size;
	if (ddr_ram_size < 16)
		ddr_ram_size = 16;
}

void crush11_memory_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
	uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space)
{
	ram_space->install_ram(0x00000000, ddr_ram_size * 1024 * 1024 - 1, &ram[0]);
}

/*
  Ddevices connected to SMBus
*/

// access logger

DEFINE_DEVICE_TYPE(SMBUS_LOGGER, smbus_logger_device, "smbus_logger", "SMBUS LOGGER")

smbus_logger_device::smbus_logger_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, SMBUS_LOGGER, tag, owner, clock)
{
}

int smbus_logger_device::execute_command(int command, int rw, int data)
{
	if (rw == 1)
	{
		logerror("smbus read from %02x R %02x\n", command, buffer[command]);
		return buffer[command];
	}
	buffer[command] = (uint8_t)data;
	logerror("smbus write to %02x W %02x\n", command, data);
	return 0;
}

void smbus_logger_device::device_start()
{
	memset(buffer, 0, sizeof(buffer));
}

void smbus_logger_device::device_reset()
{
}

// read-only data

DEFINE_DEVICE_TYPE(SMBUS_ROM, smbus_rom_device, "smbus_rom", "SMBUS ROM")

smbus_rom_device::smbus_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, SMBUS_ROM, tag, owner, clock)
{
}

smbus_rom_device::smbus_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const uint8_t *data, int size) :
	smbus_rom_device(mconfig, tag, owner, clock)
{
	buffer = data;
	buffer_size = size;
}

int smbus_rom_device::execute_command(int command, int rw, int data)
{
	if ((rw == 1) && (command < buffer_size) && (buffer != nullptr))
	{
		logerror("smbus rom read from %02x %02x\n", command, buffer[command]);
		return buffer[command];
	}
	return 0;
}

void smbus_rom_device::device_start()
{
}

void smbus_rom_device::device_reset()
{
}

// Asus AS99127F chip

DEFINE_DEVICE_TYPE(AS99127F, as99127f_device, "as99127f", "Asus AS99127F")

as99127f_device::as99127f_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, AS99127F, tag, owner, clock)
{
}

int as99127f_device::execute_command(int command, int rw, int data)
{
	if (rw == 1)
	{
		logerror("smbus read from %02x R %02x\n", command, buffer[command]);
		return buffer[command];
	}
	buffer[command] = (uint8_t)data;
	logerror("smbus write to %02x W %02x\n", command, data);
	return 0;
}

void as99127f_device::device_start()
{
	memset(buffer, 0, sizeof(buffer));
	// used to read voltages by bios, measured in mV
	buffer[0x20] = 0x70; // multiplied by 0x10
	buffer[0x2] = 0x7e; // multiplied by 0x10
	buffer[0x23] = 0x96; // multiplied by 0x540 then divided by 0x32
	buffer[0x24] = 0x9e; // multiplied by 0x260 then divided by 0xa
}

DEFINE_DEVICE_TYPE(AS99127F_SENSOR2, as99127f_sensor2_device, "as99127f_sensor2", "Asus AS99127F temperature sensor 2")

as99127f_sensor2_device::as99127f_sensor2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, AS99127F_SENSOR2, tag, owner, clock)
{
}

int as99127f_sensor2_device::execute_command(int command, int rw, int data)
{
	if (rw == 1)
	{
		logerror("smbus read from %02x R %02x\n", command, buffer[command]);
		return buffer[command];
	}
	buffer[command] = (uint8_t)data;
	logerror("smbus write to %02x W %02x\n", command, data);
	return 0;
}

void as99127f_sensor2_device::device_start()
{
	memset(buffer, 0, sizeof(buffer));
}

DEFINE_DEVICE_TYPE(AS99127F_SENSOR3, as99127f_sensor3_device, "as99127f_sensor3", "Asus AS99127F temperature sensor 3")

as99127f_sensor3_device::as99127f_sensor3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, AS99127F_SENSOR3, tag, owner, clock)
{
}

int as99127f_sensor3_device::execute_command(int command, int rw, int data)
{
	if (rw == 1)
	{
		logerror("smbus read from %02x R %02x\n", command, buffer[command]);
		return buffer[command];
	}
	buffer[command] = (uint8_t)data;
	logerror("smbus write to %02x W %02x\n", command, data);
	return 0;
}

void as99127f_sensor3_device::device_start()
{
	memset(buffer, 0, sizeof(buffer));
}

// ITE IT8703F-A SuperIO

DEFINE_DEVICE_TYPE(IT8703F, it8703f_device, "it8703f_device", "ITE IT8703F-A SuperIO")

it8703f_device::it8703f_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, IT8703F, tag, owner, clock)
	, mode(OperatingMode::Run)
	, config_key_step(0)
	, config_index(0)
	, logical_device(0)
	, pin_reset_callback(*this)
	, pin_gatea20_callback(*this)
	, m_txd1_callback(*this)
	, m_ndtr1_callback(*this)
	, m_nrts1_callback(*this)
	, m_txd2_callback(*this)
	, m_ndtr2_callback(*this)
	, m_nrts2_callback(*this)
	, pc_lpt_lptdev(*this, "lpt")
	, pc_serial1_comdev(*this, "uart_0")
	, pc_serial2_comdev(*this, "uart_1")
	, m_kbdc(*this, "pc_kbdc")
	, enabled_game_port(false)
	, enabled_midi_port(false)
{
	memset(global_configuration_registers, 0, sizeof(global_configuration_registers));
	global_configuration_registers[0x20] = 0x87; // identifies it8703f
	global_configuration_registers[0x21] = 1;
	global_configuration_registers[0x24] = 4;
	memset(configuration_registers, 0, sizeof(configuration_registers));
	configuration_registers[LogicalDevice::Parallel][0x74] = 4;
	configuration_registers[LogicalDevice::Parallel][0xf0] = 0x3f;
	for (int n = 0; n < 13; n++)
		enabled_logical[n] = false;
}

void it8703f_device::device_start()
{
	pin_reset_callback.resolve_safe();
	pin_gatea20_callback.resolve_safe();
	m_txd1_callback.resolve_safe();
	m_ndtr1_callback.resolve_safe();
	m_nrts1_callback.resolve_safe();
	m_txd2_callback.resolve_safe();
	m_ndtr2_callback.resolve_safe();
	m_nrts2_callback.resolve_safe();
}

void it8703f_device::internal_memory_map(address_map &map)
{
}

void it8703f_device::internal_io_map(address_map &map)
{
	map(0x002e, 0x002f).rw(FUNC(it8703f_device::read_it8703f), FUNC(it8703f_device::write_it8703f));
}

uint16_t it8703f_device::get_base_address(int logical, int index)
{
	int position = index * 2 + 0x60;

	return ((uint16_t)configuration_registers[logical][position] << 8) + (uint16_t)configuration_registers[logical][position + 1];
}

void it8703f_device::device_add_mconfig(machine_config &config)
{
	// parallel port
	PC_LPT(config, pc_lpt_lptdev);
	pc_lpt_lptdev->irq_handler().set(FUNC(it8703f_device::irq_parallel_w));

	// serial ports
	NS16450(config, pc_serial1_comdev, XTAL(1'843'200)); // or NS16550 ?
	pc_serial1_comdev->out_int_callback().set(FUNC(it8703f_device::irq_serial1_w));
	pc_serial1_comdev->out_tx_callback().set(FUNC(it8703f_device::txd_serial1_w));
	pc_serial1_comdev->out_dtr_callback().set(FUNC(it8703f_device::dtr_serial1_w));
	pc_serial1_comdev->out_rts_callback().set(FUNC(it8703f_device::rts_serial1_w));

	NS16450(config, pc_serial2_comdev, XTAL(1'843'200));
	pc_serial2_comdev->out_int_callback().set(FUNC(it8703f_device::irq_serial2_w));
	pc_serial2_comdev->out_tx_callback().set(FUNC(it8703f_device::txd_serial2_w));
	pc_serial2_comdev->out_dtr_callback().set(FUNC(it8703f_device::dtr_serial2_w));
	pc_serial2_comdev->out_rts_callback().set(FUNC(it8703f_device::rts_serial2_w));

	// keyboard
	KBDC8042(config, m_kbdc);
	m_kbdc->set_keyboard_type(kbdc8042_device::KBDC8042_PS2);
	m_kbdc->input_buffer_full_callback().set(FUNC(it8703f_device::irq_keyboard_w));
	m_kbdc->system_reset_callback().set(FUNC(it8703f_device::kbdp20_gp20_reset_w));
	m_kbdc->gate_a20_callback().set(FUNC(it8703f_device::kbdp21_gp25_gatea20_w));
}

READ8_MEMBER(it8703f_device::read_it8703f)
{
	if (offset == 0)
	{
		if (mode == OperatingMode::Run)
			return 0;
		return config_index;
	}
	else if (offset == 1)
	{
		if (mode == OperatingMode::Run)
			return 0;
		if (config_index < 0x30)
			return read_global_configuration_register(config_index);
		else
			return read_logical_configuration_register(config_index);
	}
	else
		return 0;
}

WRITE8_MEMBER(it8703f_device::write_it8703f)
{
	uint8_t byt;

	if (offset == 0)
	{
		byt = data & 0xff;
		if (mode == OperatingMode::Run)
		{
			if (byt != 0x87)
				return;
			config_key_step++;
			if (config_key_step > 1)
			{
				config_key_step = 0;
				mode = OperatingMode::Configuration;
			}
		}
		else
		{
			if (byt == 0xaa)
			{
				mode = OperatingMode::Run;
				return;
			}
			config_index = byt;
		}
	}
	else if (offset == 1)
	{
		if (mode == OperatingMode::Run)
			return;
		byt = data & 0xff;
		if (config_index < 0x30)
			write_global_configuration_register(config_index, byt);
		else
			write_logical_configuration_register(config_index, byt);
	}
	else
		return;
}

void it8703f_device::write_global_configuration_register(int index, int data)
{
	global_configuration_registers[index] = data;
	switch (index)
	{
	case 7:
		logical_device = data;
		logerror("Selected logical device %d\n", data);
		break;
	}
	logerror("Write global configuration register %02X = %02X\n", index, data);
}

void it8703f_device::write_logical_configuration_register(int index, int data)
{
	configuration_registers[logical_device][index] = data;
	switch (logical_device)
	{
	case LogicalDevice::Serial1:
		write_serial1_configuration_register(index, data);
		break;
	case LogicalDevice::Serial2:
		write_serial2_configuration_register(index, data);
		break;
	case LogicalDevice::Parallel:
		write_parallel_configuration_register(index, data);
		break;
	case LogicalDevice::Keyboard:
		write_keyboard_configuration_register(index, data);
		break;
	case LogicalDevice::Gpio1:
		if (index == 0x30)
		{
			if (data & 1)
				enabled_game_port = true;
			if (data & 2)
				enabled_midi_port = true;
		}
		break;
	}
}

void it8703f_device::write_parallel_configuration_register(int index, int data)
{
	if (index == 0x30)
	{
		if (data & 1)
		{
			if (enabled_logical[LogicalDevice::Parallel] == false)
			{
				enabled_logical[LogicalDevice::Parallel] = true;
				lpchost->remap();
			}
			logerror("Enabled LPT at %04X\n", get_base_address(LogicalDevice::Parallel, 0));
		}
		else
		{
			if (enabled_logical[LogicalDevice::Parallel] == true)
			{
				enabled_logical[LogicalDevice::Parallel] = false;
				lpchost->remap();
			}
		}
	}
}

void it8703f_device::write_serial1_configuration_register(int index, int data)
{
	if (index == 0x30)
	{
		if (data & 1)
		{
			if (enabled_logical[LogicalDevice::Serial1] == false)
			{
				enabled_logical[LogicalDevice::Serial1] = true;
				lpchost->remap();
			}
			logerror("Enabled Serial1 at %04X\n", get_base_address(LogicalDevice::Serial1, 0));
		}
		else
		{
			if (enabled_logical[LogicalDevice::Serial1] == true)
			{
				enabled_logical[LogicalDevice::Serial1] = false;
				lpchost->remap();
			}
		}
	}
}

void it8703f_device::write_serial2_configuration_register(int index, int data)
{
	if (index == 0x30)
	{
		if (data & 1)
		{
			if (enabled_logical[LogicalDevice::Serial2] == false)
			{
				enabled_logical[LogicalDevice::Serial2] = true;
				lpchost->remap();
			}
			logerror("Enabled Serial2 at %04X\n", get_base_address(LogicalDevice::Serial2, 0));
		}
		else
		{
			if (enabled_logical[LogicalDevice::Serial2] == true)
			{
				enabled_logical[LogicalDevice::Serial2] = false;
				lpchost->remap();
			}
		}
	}
}

void it8703f_device::write_keyboard_configuration_register(int index, int data)
{
	if (index == 0x30)
	{
		if (data & 1)
		{
			if (enabled_logical[LogicalDevice::Keyboard] == false)
			{
				enabled_logical[LogicalDevice::Keyboard] = true;
				lpchost->remap();
			}
			logerror("Enabled Keyboard\n");
		}
		else
		{
			if (enabled_logical[LogicalDevice::Keyboard] == true)
			{
				enabled_logical[LogicalDevice::Keyboard] = false;
				lpchost->remap();
			}
		}
	}
}

uint16_t it8703f_device::read_global_configuration_register(int index)
{
	uint16_t ret = 0;

	ret = global_configuration_registers[index];
	switch (index)
	{
	case 7:
		ret = logical_device;
		break;
	}
	logerror("Read global configuration register %02X = %02X\n", index, ret);
	return ret;
}

uint16_t it8703f_device::read_logical_configuration_register(int index)
{
	uint16_t ret = 0;

	switch (logical_device)
	{
	case LogicalDevice::Parallel:
		ret = read_parallel_configuration_register(index);
		break;
	case LogicalDevice::Serial1:
		ret = read_serial1_configuration_register(index);
		break;
	case LogicalDevice::Serial2:
		ret = read_serial2_configuration_register(index);
		break;
	case LogicalDevice::Keyboard:
		ret = read_keyboard_configuration_register(index);
		break;
	default:
		ret = configuration_registers[logical_device][index];
		break;
	}
	return ret;
}

WRITE_LINE_MEMBER(it8703f_device::irq_parallel_w)
{
	if (enabled_logical[LogicalDevice::Parallel] == false)
		return;
	lpchost->set_virtual_line(configuration_registers[LogicalDevice::Parallel][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}

WRITE_LINE_MEMBER(it8703f_device::irq_serial1_w)
{
	if (enabled_logical[LogicalDevice::Serial1] == false)
		return;
	lpchost->set_virtual_line(configuration_registers[LogicalDevice::Serial1][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}

WRITE_LINE_MEMBER(it8703f_device::txd_serial1_w)
{
	if (enabled_logical[LogicalDevice::Serial1] == false)
		return;
	m_txd1_callback(state);
}

WRITE_LINE_MEMBER(it8703f_device::dtr_serial1_w)
{
	if (enabled_logical[LogicalDevice::Serial1] == false)
		return;
	m_ndtr1_callback(state);
}

WRITE_LINE_MEMBER(it8703f_device::rts_serial1_w)
{
	if (enabled_logical[LogicalDevice::Serial1] == false)
		return;
	m_nrts1_callback(state);
}

WRITE_LINE_MEMBER(it8703f_device::irq_serial2_w)
{
	if (enabled_logical[LogicalDevice::Serial2] == false)
		return;
	lpchost->set_virtual_line(configuration_registers[LogicalDevice::Serial2][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}

WRITE_LINE_MEMBER(it8703f_device::txd_serial2_w)
{
	if (enabled_logical[LogicalDevice::Serial2] == false)
		return;
	m_txd2_callback(state);
}

WRITE_LINE_MEMBER(it8703f_device::dtr_serial2_w)
{
	if (enabled_logical[LogicalDevice::Serial2] == false)
		return;
	m_ndtr2_callback(state);
}

WRITE_LINE_MEMBER(it8703f_device::rts_serial2_w)
{
	if (enabled_logical[LogicalDevice::Serial2] == false)
		return;
	m_nrts2_callback(state);
}

WRITE_LINE_MEMBER(it8703f_device::rxd1_w)
{
	pc_serial1_comdev->rx_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::ndcd1_w)
{
	pc_serial1_comdev->dcd_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::ndsr1_w)
{
	pc_serial1_comdev->dsr_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::nri1_w)
{
	pc_serial1_comdev->ri_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::ncts1_w)
{
	pc_serial1_comdev->cts_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::rxd2_w)
{
	pc_serial2_comdev->rx_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::ndcd2_w)
{
	pc_serial2_comdev->dcd_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::ndsr2_w)
{
	pc_serial2_comdev->dsr_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::nri2_w)
{
	pc_serial2_comdev->ri_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::ncts2_w)
{
	pc_serial2_comdev->cts_w(state);
}

WRITE_LINE_MEMBER(it8703f_device::irq_keyboard_w)
{
	if (enabled_logical[LogicalDevice::Keyboard] == false)
		return;
	lpchost->set_virtual_line(configuration_registers[LogicalDevice::Keyboard][0x70], state ? ASSERT_LINE : CLEAR_LINE);
}

WRITE_LINE_MEMBER(it8703f_device::kbdp21_gp25_gatea20_w)
{
	if (enabled_logical[LogicalDevice::Keyboard] == false)
		return;
	pin_gatea20_callback(state);
}

WRITE_LINE_MEMBER(it8703f_device::kbdp20_gp20_reset_w)
{
	if (enabled_logical[LogicalDevice::Keyboard] == false)
		return;
	pin_reset_callback(state);
}

void it8703f_device::map_lpt(address_map& map)
{
	map(0x0, 0x3).rw(FUNC(it8703f_device::lpt_read), FUNC(it8703f_device::lpt_write));
}

READ8_MEMBER(it8703f_device::lpt_read)
{
	return pc_lpt_lptdev->read(space, offset, mem_mask);
}

WRITE8_MEMBER(it8703f_device::lpt_write)
{
	pc_lpt_lptdev->write(space, offset, data, mem_mask);
}

void it8703f_device::map_lpt_addresses()
{
	uint16_t base = get_base_address(LogicalDevice::Parallel, 0);

	iospace->install_device(base, base + 3, *this, &it8703f_device::map_lpt);
}

void it8703f_device::map_serial1(address_map& map)
{
	map(0x0, 0x7).rw(FUNC(it8703f_device::serial1_read), FUNC(it8703f_device::serial1_write));
}

READ8_MEMBER(it8703f_device::serial1_read)
{
	return pc_serial1_comdev->ins8250_r(offset);
}

WRITE8_MEMBER(it8703f_device::serial1_write)
{
	pc_serial1_comdev->ins8250_w(offset, data);
}

void it8703f_device::map_serial1_addresses()
{
	uint16_t base = get_base_address(LogicalDevice::Serial1, 0);

	iospace->install_device(base, base + 7, *this, &it8703f_device::map_serial1);
}

void it8703f_device::map_serial2(address_map& map)
{
	map(0x0, 0x7).rw(FUNC(it8703f_device::serial2_read), FUNC(it8703f_device::serial2_write));
}

READ8_MEMBER(it8703f_device::serial2_read)
{
	return pc_serial2_comdev->ins8250_r(offset);
}

WRITE8_MEMBER(it8703f_device::serial2_write)
{
	pc_serial2_comdev->ins8250_w(offset, data);
}

void it8703f_device::map_serial2_addresses()
{
	uint16_t base = get_base_address(LogicalDevice::Serial2, 0);

	iospace->install_device(base, base + 7, *this, &it8703f_device::map_serial2);
}

void it8703f_device::map_keyboard(address_map &map)
{
	map(0x0, 0x0).rw(FUNC(it8703f_device::at_keybc_r), FUNC(it8703f_device::at_keybc_w));
	map(0x4, 0x4).rw(FUNC(it8703f_device::keybc_status_r), FUNC(it8703f_device::keybc_command_w));
}

void it8703f_device::unmap_keyboard(address_map &map)
{
	map(0x0, 0x0).noprw();
	map(0x4, 0x4).noprw();
}

READ8_MEMBER(it8703f_device::at_keybc_r)
{
	switch (offset) //m_kbdc
	{
	case 0:
		return m_kbdc->data_r(space, 0);
	}

	return 0xff;
}

WRITE8_MEMBER(it8703f_device::at_keybc_w)
{
	switch (offset)
	{
	case 0:
		m_kbdc->data_w(space, 0, data);
	}
}

READ8_MEMBER(it8703f_device::keybc_status_r)
{
	return m_kbdc->data_r(space, 4);
}

WRITE8_MEMBER(it8703f_device::keybc_command_w)
{
	m_kbdc->data_w(space, 4, data);
}

void it8703f_device::map_keyboard_addresses()
{
	uint16_t base = get_base_address(LogicalDevice::Keyboard, 0);

	iospace->install_device(base, base + 7, *this, &it8703f_device::map_keyboard);
}

void it8703f_device::map_extra(address_space *memory_space, address_space *io_space)
{
	memspace = memory_space;
	iospace = io_space;
	io_space->install_device(0, 0xffff, *this, &it8703f_device::internal_io_map);
	if (enabled_logical[LogicalDevice::Parallel] == true)
		map_lpt_addresses();
	if (enabled_logical[LogicalDevice::Serial1] == true)
		map_serial1_addresses();
	if (enabled_logical[LogicalDevice::Serial2] == true)
		map_serial2_addresses();
	if (enabled_logical[LogicalDevice::Keyboard] == true)
		map_keyboard_addresses();
}

void it8703f_device::set_host(int index, lpcbus_host_interface *host)
{
	lpchost = host;
	lpcindex = index;
}

/*
  Machine state
*/

class nforcepc_state : public driver_device
{
public:
	struct boot_state_info
	{
		uint8_t val;
		const char *const message;
	};

	static const boot_state_info boot_state_infos_award[];

	void nforcepc(machine_config &config);

	nforcepc_state(const machine_config &mconfig, device_type type, const char *tag);

private:
	void nforce_map(address_map &map);
	void nforce_map_io(address_map &map);
	DECLARE_WRITE8_MEMBER(boot_state_award_w);
	IRQ_CALLBACK_MEMBER(irq_callback);
	DECLARE_WRITE_LINE_MEMBER(maincpu_interrupt);

	virtual void machine_start() override;
	virtual void machine_reset() override;

	required_device<cpu_device> m_maincpu;
	required_device<mcpx_isalpc_device> isalpc;
	required_device<as99127f_device> m_as99127f;
};

nforcepc_state::nforcepc_state(const machine_config &mconfig, device_type type, const char *tag) :
	driver_device(mconfig, type, tag),
	m_maincpu(*this, "maincpu"),
	isalpc(*this, ":pci:01.0"),
	m_as99127f(*this, ":pci:01.1:12d")
{
}

void nforcepc_state::machine_start()
{
	m_as99127f->get_buffer()[0x4f] = 0x12;
}

void nforcepc_state::machine_reset()
{
}

const nforcepc_state::boot_state_info nforcepc_state::boot_state_infos_award[] = {
	{ 0xC0, "First basic initialization" },
	{ 0, nullptr }
};

WRITE8_MEMBER(nforcepc_state::boot_state_award_w)
{
	const char *desc = "";
	for (int i = 0; boot_state_infos_award[i].message; i++)
		if (boot_state_infos_award[i].val == data)
		{
			desc = boot_state_infos_award[i].message;
			break;
		}
	logerror("Boot state %02x - %s\n", data, desc);
}

IRQ_CALLBACK_MEMBER(nforcepc_state::irq_callback)
{
	return isalpc->acknowledge();
}

WRITE_LINE_MEMBER(nforcepc_state::maincpu_interrupt)
{
	m_maincpu->set_input_line(0, state ? HOLD_LINE : CLEAR_LINE);
}

void nforcepc_state::nforce_map(address_map &map)
{
	map.unmap_value_high();
}

void nforcepc_state::nforce_map_io(address_map &map)
{
	map.unmap_value_high();
}

static void isa_com(device_slot_interface& device)
{
	device.option_add("microsoft_mouse", MSFT_HLE_SERIAL_MOUSE);
	device.option_add("logitech_mouse", LOGITECH_HLE_SERIAL_MOUSE);
	device.option_add("wheel_mouse", WHEEL_HLE_SERIAL_MOUSE);
	device.option_add("msystems_mouse", MSYSTEMS_HLE_SERIAL_MOUSE);
	device.option_add("rotatable_mouse", ROTATABLE_HLE_SERIAL_MOUSE);
	device.option_add("terminal", SERIAL_TERMINAL);
	device.option_add("null_modem", NULL_MODEM);
	device.option_add("sun_kbd", SUN_KBD_ADAPTOR);
}

/*
  Machine configuration
*/

void nforcepc_state::nforcepc(machine_config &config)
{
	athlonxp_device &maincpu(ATHLONXP(config, "maincpu", 90000000));
	maincpu.set_addrmap(AS_PROGRAM, &nforcepc_state::nforce_map);
	maincpu.set_addrmap(AS_IO, &nforcepc_state::nforce_map_io);
	maincpu.set_irq_acknowledge_callback(FUNC(nforcepc_state::irq_callback));
	//maincpu.smiact().set("pci:01.0", FUNC(???_host_device::smi_act_w));

	PCI_ROOT(config, ":pci", 0);
	CRUSH11(config, ":pci:00.0", 0, "maincpu", "bios"); // 10de:01a4 NVIDIA Corporation nForce CPU bridge
	CRUSH11_MEMORY(config, ":pci:00.1", 0, 2); // 10de:01ac NVIDIA Corporation nForce 220/420 Memory Controller
	// 10de:01ad NVIDIA Corporation nForce 220/420 Memory Controller
	// 10de:01ab NVIDIA Corporation nForce 420 Memory Controller (DDR)
	mcpx_isalpc_device &isa(MCPX_ISALPC(config, ":pci:01.0", 0, 0x10430c11)); // 10de:01b2 NVIDIA Corporation nForce ISA Bridge (LPC bus)
	isa.smi().set_inputline(":maincpu", INPUT_LINE_SMI);
	isa.boot_state_hook().set(FUNC(nforcepc_state::boot_state_award_w));
	isa.interrupt_output().set(FUNC(nforcepc_state::maincpu_interrupt));
	it8703f_device &ite(IT8703F(config, ":pci:01.0:0", 0));
	ite.pin_reset().set_inputline(":maincpu", INPUT_LINE_RESET);
	ite.pin_gatea20().set_inputline(":maincpu", INPUT_LINE_A20);
	ite.txd1().set(":serport0", FUNC(rs232_port_device::write_txd));
	ite.ndtr1().set(":serport0", FUNC(rs232_port_device::write_dtr));
	ite.nrts1().set(":serport0", FUNC(rs232_port_device::write_rts));
	ite.txd2().set(":serport1", FUNC(rs232_port_device::write_txd));
	ite.ndtr2().set(":serport1", FUNC(rs232_port_device::write_dtr));
	ite.nrts2().set(":serport1", FUNC(rs232_port_device::write_rts));
	MCPX_SMBUS(config, ":pci:01.1", 0); // 10de:01b4 NVIDIA Corporation nForce PCI System Management (SMBus)
	SMBUS_ROM(config, ":pci:01.1:050", 0, test_spd_data, sizeof(test_spd_data)); // these 3 are on smbus number 0
	SMBUS_LOGGER(config, ":pci:01.1:051", 0);
	SMBUS_LOGGER(config, ":pci:01.1:052", 0);
	SMBUS_LOGGER(config, ":pci:01.1:108", 0); // these 4 are on smbus number 1
	AS99127F(config, ":pci:01.1:12d", 0);
	AS99127F_SENSOR2(config, ":pci:01.1:148", 0);
	AS99127F_SENSOR3(config, ":pci:01.1:149", 0);
	mcpx_ohci_device &ohci(MCPX_OHCI(config, ":pci:02.0", 0)); // 10de:01c2 NVIDIA Corporation nForce USB Controller
	ohci.interrupt_handler().set(":pci:01.0", FUNC(mcpx_isalpc_device::irq1));
	MCPX_OHCI(config, ":pci:03.0", 0); // 10de:01c2 NVIDIA Corporation nForce USB Controller
	MCPX_ETH(config, ":pci:04.0", 0); // 10de:01c3 NVIDIA Corporation nForce Ethernet Controller
	MCPX_APU(config, ":pci:05.0", 0, m_maincpu); // 10de:01b0 NVIDIA Corporation nForce Audio Processing Unit
	MCPX_AC97_AUDIO(config, ":pci:06.0", 0); // 10de:01b1 NVIDIA Corporation nForce AC'97 Audio Controller
	PCI_BRIDGE(config, ":pci:08.0", 0, 0x10de01b8, 0); // 10de:01b8 NVIDIA Corporation nForce PCI-to-PCI bridge
	// 10ec:8139 Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ (behind bridge)
	mcpx_ide_device &ide(MCPX_IDE(config, ":pci:09.0", 0)); // 10de:01bc NVIDIA Corporation nForce IDE
	ide.pri_interrupt_handler().set(":pci:01.0", FUNC(mcpx_isalpc_device::irq14));
	ide.sec_interrupt_handler().set(":pci:01.0", FUNC(mcpx_isalpc_device::irq15));
		/*subdevice<ide_controller_32_device>(":pci:09.0:ide")->options(ata_devices, "hdd", "cdrom", true);*/
	NV2A_AGP(config, ":pci:1e.0", 0, 0x10de01b7, 0); // 10de:01b7 NVIDIA Corporation nForce AGP to PCI Bridge
	VIRGEDX_PCI(config, ":pci:0a.0", 0);
	SST_49LF020(config, "bios", 0);

	rs232_port_device& serport0(RS232_PORT(config, "serport0", isa_com, nullptr));
	serport0.rxd_handler().set(":pci:01.0:0", FUNC(it8703f_device::rxd1_w));
	serport0.dcd_handler().set(":pci:01.0:0", FUNC(it8703f_device::ndcd1_w));
	serport0.dsr_handler().set(":pci:01.0:0", FUNC(it8703f_device::ndsr1_w));
	serport0.ri_handler().set(":pci:01.0:0", FUNC(it8703f_device::nri1_w));
	serport0.cts_handler().set(":pci:01.0:0", FUNC(it8703f_device::ncts1_w));

	rs232_port_device& serport1(RS232_PORT(config, "serport1", isa_com, nullptr));
	serport1.rxd_handler().set(":pci:01.0:0", FUNC(it8703f_device::rxd2_w));
	serport1.dcd_handler().set(":pci:01.0:0", FUNC(it8703f_device::ndcd2_w));
	serport1.dsr_handler().set(":pci:01.0:0", FUNC(it8703f_device::ndsr2_w));
	serport1.ri_handler().set(":pci:01.0:0", FUNC(it8703f_device::nri2_w));
	serport1.cts_handler().set(":pci:01.0:0", FUNC(it8703f_device::ncts2_w));
}

ROM_START(nforcepc)
	ROM_REGION32_LE(0x40000, "bios", 0) /* PC bios */
	ROM_SYSTEM_BIOS(0, "a7n266c", "a7n266c") // Motherboard dump. Chip: SST49LF020 Package: PLCC32 Label had 3 lines of text: "A7NC3" "1001.D" "GSQ98"
	ROMX_LOAD("a7n266c.bin", 0, 0x40000, CRC(f4f0e4fc) SHA1(87f11545db178914623e41fb51e328da479a2efc), ROM_BIOS(0))
	ROM_SYSTEM_BIOS(1, "a7n266c1001d", "a7n266c1001d") // bios version 1001.D downloaded from Asus website
	ROMX_LOAD("a7nc101d.awd", 0, 0x40000, CRC(ead1147c) SHA1(27227df98e0c5fb9fecdb4bb6ef72df19766c330), ROM_BIOS(1))
	ROM_SYSTEM_BIOS(2, "a7n266c1001e", "a7n266c1001e") // bios version 1001.E
	ROMX_LOAD("a7nc101e.awd", 0, 0x40000, CRC(a029cd42) SHA1(e257915534bc725f389e57945b45c81e7ef40dcc), ROM_BIOS(2))
	ROM_SYSTEM_BIOS(3, "a7n266c1002c", "a7n266c1002c") // beta bios version 1002C.003 ?
	ROMX_LOAD("1002c.003", 0, 0x40000, CRC(57ced539) SHA1(525d15523be3b373a10c1f6ae355803613506ce2), ROM_BIOS(3))
	ROM_SYSTEM_BIOS(4, "a7n266c1003", "a7n266c1003") // bios version 1003
	ROMX_LOAD("a7nc1003.awd", 0, 0x40000, CRC(ac27f751) SHA1(96d5539ee2a40ea58a32013c16109159a3c41bb8), ROM_BIOS(4))
	ROM_SYSTEM_BIOS(5, "a7n266c1004", "a7n266c1004") // bios version 1004
	ROMX_LOAD("a7nc1004.awd", 0, 0x40000, CRC(04124e4f) SHA1(8778a6722eddaf83101f89834969f0037af65cb9), ROM_BIOS(5))
	ROM_SYSTEM_BIOS(6, "a7n266c1005", "a7n266c1005") // beta bios version 1005.005 ?
	ROMX_LOAD("1005nc.005", 0, 0x40000, CRC(9ca5a9c9) SHA1(5ffb57b9f1e0e163b33c093a3e017020b247b3d3), ROM_BIOS(6))
ROM_END

static INPUT_PORTS_START(nforcepc)
	PORT_INCLUDE(at_keyboard)
INPUT_PORTS_END

COMP(2002, nforcepc, 0, 0, nforcepc, nforcepc, nforcepc_state, empty_init, "Nvidia", "Nvidia nForce PC (CRUSH11/12)", MACHINE_IS_SKELETON)