summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/h8.cpp
blob: be17528ffb1a9412bcd4f100b5370cf7d38cbbf9 (plain) (tree)
1
2
3
4
5
6
                       
                             



                                                                            






































                                                                                  



                                                                             
 
                            
                          
                          
                          
                              
                       
                       

                    

                



                                     
                                                                                  




                                                   
                                                

           


                                        

                                                    



                                                   
 
                                        

                                      
        


                          
                    
                               
                          
                       
                                              
                                                                     



                                                      
                                   


  
                                       



                                      
                                                    
 
                          
                                                                                         

 
                                  
 
                             
 


                                                                                            
 
                                    




















                                                
                                   
 





                                                                    

                            
                                                   
 
                                                     
                                         
 
                                                               
                          

                                          

 
                                   
 







                        
 
                                                                    
                                                   

 
















                                                                                                


                                                                                          
 















                                                                                                               





                                                                                                                 

               
                              
 
                                         
                      


                           
                             
                           
                   



                                               
                                      
                                              









                                                                                           
                                                                  
                                              




                                                                          
                                                               
                                                             
                              
                                                                                                         



                                

                           


         
                                      
                                             

 




                                              

                                            

                         





                                         









                                                                               
                                                            



                                         
                                                                 



                                   
                                  
                                    




                                                                       
 



                                      
                                               

                                                                                 

                     
                                         
                                                                           

                                                      

                                                                             
 



                                                                                                      


                                                                                                           




                                                           

















                                                                                                                                        



            

                                                                                                                             
// license:BSD-3-Clause
// copyright-holders:Robbbert
/***************************************************************************

        Heathkit H8

        2009-05-12 Skeleton driver.

        This system uses Octal rather than the usual hexadecimal.

STATUS:
        It runs, keyboard works, you can enter data.

Meaning of LEDs:
        PWR = power is turned on
        MON = controls should work
        RUN = CPU is running (not halted)
        ION = Interrupts are enabled

Pasting:
        0-F : as is
        + : ^
        - : V
        MEM : -
        ALTER : =

        Addresses must have all 6 digits entered.
        Data must have all 3 digits entered.
        System has a short beep for each key, and a slightly longer beep
            for each group of 3 digits. The largest number allowed is 377 (=0xFF).

Test Paste:
        -041000=123 245 333 144 255 366 077=-041000
        Now press up-arrow to confirm the data has been entered.

Official test program from pages 4 to 8 of the operator's manual:
        -040100=076 002 062 010 040 006 004 041 170 040 021 013 040 016 011 176
                022 043 023 015 302 117 040 016 003 076 377 315 053 000 015 302
                131 040 005 302 112 040 076 062 315 140 002 076 062 315 053 000
                076 062 315 140 002 303 105 040 377 262 270 272 275 377 222 200
                377 237 244 377 272 230 377 220 326 302 377 275 272 271 271 373
                271 240 377 236 376 362 236 376 362 236 376 362 R6=040100=4

TODO:
        - Cassette (coded but not working)

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

#include "emu.h"

#include "cpu/i8085/i8085.h"
#include "machine/i8251.h"
#include "machine/clock.h"
#include "machine/timer.h"
#include "imagedev/cassette.h"
#include "sound/beep.h"
#include "sound/wave.h"
#include "speaker.h"

#include "h8.lh"


class h8_state : public driver_device
{
public:
	h8_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag)
		, m_maincpu(*this, "maincpu")
		, m_uart(*this, "uart")
		, m_cass(*this, "cassette")
		, m_beep(*this, "beeper")
		, m_digits(*this, "digit%u", 0U)
	{ }

	DECLARE_READ8_MEMBER(portf0_r);
	DECLARE_WRITE8_MEMBER(portf0_w);
	DECLARE_WRITE8_MEMBER(portf1_w);
	DECLARE_WRITE8_MEMBER(h8_status_callback);
	DECLARE_WRITE_LINE_MEMBER(h8_inte_callback);
	DECLARE_WRITE_LINE_MEMBER(txdata_callback);
	TIMER_DEVICE_CALLBACK_MEMBER(h8_irq_pulse);
	TIMER_DEVICE_CALLBACK_MEMBER(h8_c);
	TIMER_DEVICE_CALLBACK_MEMBER(h8_p);

	void h8(machine_config &config);
	void h8_io(address_map &map);
	void h8_mem(address_map &map);
private:
	uint8_t m_digit;
	uint8_t m_segment;
	uint8_t m_irq_ctl;
	bool m_ff_b;
	uint8_t m_cass_data[4];
	bool m_cass_state;
	bool m_cassold;
	virtual void machine_reset() override;
	virtual void machine_start() override { m_digits.resolve(); }
	required_device<cpu_device> m_maincpu;
	required_device<i8251_device> m_uart;
	required_device<cassette_image_device> m_cass;
	required_device<beep_device> m_beep;
	output_finder<16> m_digits;
};


#define H8_CLOCK (XTAL(12'288'000) / 6)
#define H8_BEEP_FRQ (H8_CLOCK / 1024)
#define H8_IRQ_PULSE (H8_BEEP_FRQ / 2)


TIMER_DEVICE_CALLBACK_MEMBER(h8_state::h8_irq_pulse)
{
	if (m_irq_ctl & 1)
		m_maincpu->set_input_line_and_vector(INPUT_LINE_IRQ0, ASSERT_LINE, 0xcf);
}

READ8_MEMBER( h8_state::portf0_r )
{
	// reads the keyboard

	// The following not emulated, can occur any time even if keyboard not being scanned
	// - if 0 and RTM pressed, causes int10
	// - if 0 and RST pressed, resets cpu

	uint8_t i,keyin,data = 0xff;

	keyin = ioport("X0")->read();
	if (keyin != 0xff)
	{
		for (i = 1; i < 8; i++)
			if (!BIT(keyin,i))
				data &= ~(i<<1);
		data &= 0xfe;
	}

	keyin = ioport("X1")->read();
	if (keyin != 0xff)
	{
		for (i = 1; i < 8; i++)
			if (!BIT(keyin,i))
				data &= ~(i<<5);
		data &= 0xef;
	}
	return data;
}

WRITE8_MEMBER( h8_state::portf0_w )
{
	// this will always turn off int10 that was set by the timer
	// d0-d3 = digit select
	// d4 = int20 is allowed
	// d5 = mon led
	// d6 = int10 is allowed
	// d7 = beeper enable

	m_digit = data & 15;
	if (m_digit) m_digits[m_digit] = m_segment;

	output().set_value("mon_led", !BIT(data, 5));
	m_beep->set_state(!BIT(data, 7));

	m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
	m_irq_ctl &= 0xf0;
	if (BIT(data, 6)) m_irq_ctl |= 1;
	if (!BIT(data, 4)) m_irq_ctl |= 2;
}

WRITE8_MEMBER( h8_state::portf1_w )
{
	//d7 segment dot
	//d6 segment f
	//d5 segment e
	//d4 segment d
	//d3 segment c
	//d2 segment b
	//d1 segment a
	//d0 segment g

	m_segment = 0xff ^ bitswap<8>(data, 7, 0, 6, 5, 4, 3, 2, 1);
	if (m_digit) m_digits[m_digit] = m_segment;
}

void h8_state::h8_mem(address_map &map)
{
	map.unmap_value_high();
	map(0x0000, 0x0fff).rom(); // main rom
	map(0x1400, 0x17ff).ram(); // fdc ram
	map(0x1800, 0x1fff).rom(); // fdc rom
	map(0x2000, 0x9fff).ram(); // main ram
}

void h8_state::h8_io(address_map &map)
{
	map.unmap_value_high();
	map.global_mask(0xff);
	map(0xf0, 0xf0).rw(this, FUNC(h8_state::portf0_r), FUNC(h8_state::portf0_w));
	map(0xf1, 0xf1).w(this, FUNC(h8_state::portf1_w));
	map(0xf8, 0xf8).rw(m_uart, FUNC(i8251_device::data_r), FUNC(i8251_device::data_w));
	map(0xf9, 0xf9).rw(m_uart, FUNC(i8251_device::status_r), FUNC(i8251_device::control_w));
	// optional connection to a serial terminal @ 600 baud
	//AM_RANGE(0xfa, 0xfa) AM_DEVREADWRITE("uart1", i8251_device, data_r, data_w)
	//AM_RANGE(0xfb, 0xfb) AM_DEVREADWRITE("uart1", i8251_device, status_r, control_w)
}

/* Input ports */
static INPUT_PORTS_START( h8 )
	PORT_START("X0")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("1 SP") PORT_CODE(KEYCODE_1) PORT_CHAR('1')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("2 AF") PORT_CODE(KEYCODE_2) PORT_CHAR('2')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("3 BC") PORT_CODE(KEYCODE_3) PORT_CHAR('3')
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("4 DE GO") PORT_CODE(KEYCODE_4) PORT_CHAR('4')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("5 HL IN") PORT_CODE(KEYCODE_5) PORT_CHAR('5')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("6 PC OUT") PORT_CODE(KEYCODE_6) PORT_CHAR('6')
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("7 SI") PORT_CODE(KEYCODE_7) PORT_CHAR('7')

	PORT_START("X1")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("8 LOAD") PORT_CODE(KEYCODE_8) PORT_CHAR('8')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("9 DUMP") PORT_CODE(KEYCODE_9) PORT_CHAR('9')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("+") PORT_CODE(KEYCODE_UP) PORT_CHAR('^')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_DOWN) PORT_CHAR('V')
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CANCEL") PORT_CODE(KEYCODE_ESC) PORT_CHAR('Q')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ALTER") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MEM") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-')
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("REG") PORT_CODE(KEYCODE_R) PORT_CHAR('R')
INPUT_PORTS_END

void h8_state::machine_reset()
{
	output().set_value("pwr_led", 0);
	m_irq_ctl = 1;
	m_cass_state = 1;
	m_cass_data[0] = 0;
	m_cass_data[1] = 0;
	m_uart->write_rxd(0);
	m_cass_data[3] = 0;
	m_ff_b = 1;
}

WRITE_LINE_MEMBER( h8_state::h8_inte_callback )
{
		// operate the ION LED
	output().set_value("ion_led", !state);
	m_irq_ctl &= 0x7f | ((state) ? 0 : 0x80);
}

WRITE8_MEMBER( h8_state::h8_status_callback )
{
/* This is rather messy, but basically there are 2 D flipflops, one drives the other,
the data is /INTE while the clock is /M1. If the system is in Single Instruction mode,
a int20 (output of 2nd flipflop) will occur after 4 M1 steps, to pause the running program.
But, all of this can only occur if bit 5 of port F0 is low. */

	bool state = (data & i8080_cpu_device::STATUS_M1) ? 0 : 1;
	bool c,a = (m_irq_ctl & 0x80) ? 1 : 0;

	if (m_irq_ctl & 2)
	{
		if (!state) // rising pulse to push data through flipflops
		{
			c = !m_ff_b; // from /Q of 2nd flipflop
			m_ff_b = a; // from Q of 1st flipflop
			if (c)
				m_maincpu->set_input_line_and_vector(INPUT_LINE_IRQ0, ASSERT_LINE, 0xd7);
		}
	}
	else
	{ // flipflops are 'set'
		c = 0;
		m_ff_b = 1;
	}


		// operate the RUN LED
	output().set_value("run_led", state);
}

WRITE_LINE_MEMBER( h8_state::txdata_callback )
{
	m_cass_state = state;
}

TIMER_DEVICE_CALLBACK_MEMBER(h8_state::h8_c)
{
	m_cass_data[3]++;

	if (m_cass_state != m_cassold)
	{
		m_cass_data[3] = 0;
		m_cassold = m_cass_state;
	}

	if (m_cass_state)
		m_cass->output(BIT(m_cass_data[3], 0) ? -1.0 : +1.0); // 2400Hz
	else
		m_cass->output(BIT(m_cass_data[3], 1) ? -1.0 : +1.0); // 1200Hz
}

TIMER_DEVICE_CALLBACK_MEMBER(h8_state::h8_p)
{
	/* cassette - turn 1200/2400Hz to a bit */
	m_cass_data[1]++;
	uint8_t cass_ws = (m_cass->input() > +0.03) ? 1 : 0;

	if (cass_ws != m_cass_data[0])
	{
		m_cass_data[0] = cass_ws;
		m_uart->write_rxd((m_cass_data[1] < 12) ? 1 : 0);
		m_cass_data[1] = 0;
	}
}

MACHINE_CONFIG_START(h8_state::h8)
	/* basic machine hardware */
	MCFG_DEVICE_ADD("maincpu", I8080, H8_CLOCK)
	MCFG_DEVICE_PROGRAM_MAP(h8_mem)
	MCFG_DEVICE_IO_MAP(h8_io)
	MCFG_I8085A_STATUS(WRITE8(*this, h8_state, h8_status_callback))
	MCFG_I8085A_INTE(WRITELINE(*this, h8_state, h8_inte_callback))

	/* video hardware */
	MCFG_DEFAULT_LAYOUT(layout_h8)

	/* sound hardware */
	SPEAKER(config, "mono").front_center();
	BEEP(config, "beeper", H8_BEEP_FRQ).add_route(ALL_OUTPUTS, "mono", 1.00);
	WAVE(config, "wave", "cassette").add_route(ALL_OUTPUTS, "mono", 0.25);

	/* Devices */
	MCFG_DEVICE_ADD("uart", I8251, 0)
	MCFG_I8251_TXD_HANDLER(WRITELINE(*this, h8_state, txdata_callback))

	MCFG_DEVICE_ADD("cassette_clock", CLOCK, 4800)
	MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE("uart", i8251_device, write_txc))
	MCFG_DEVCB_CHAIN_OUTPUT(WRITELINE("uart", i8251_device, write_rxc))

	MCFG_CASSETTE_ADD("cassette")
	MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED)
	MCFG_CASSETTE_INTERFACE("h8_cass")

	MCFG_TIMER_DRIVER_ADD_PERIODIC("h8_c", h8_state, h8_c, attotime::from_hz(4800))
	MCFG_TIMER_DRIVER_ADD_PERIODIC("h8_p", h8_state, h8_p, attotime::from_hz(40000))
	MCFG_TIMER_DRIVER_ADD_PERIODIC("h8_timer", h8_state, h8_irq_pulse, attotime::from_hz(H8_IRQ_PULSE))
MACHINE_CONFIG_END

/* ROM definition */
ROM_START( h8 )
	ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF )
	// H17 fdc bios - needed by bios2&3
	ROM_LOAD( "2716_444-19_h17.rom", 0x1800, 0x0800, CRC(26e80ae3) SHA1(0c0ee95d7cb1a760f924769e10c0db1678f2435c))

	ROM_SYSTEM_BIOS(0, "bios0", "Standard")
	ROMX_LOAD( "2708_444-13_pam8.rom", 0x0000, 0x0400, CRC(e0745513) SHA1(0e170077b6086be4e5cd10c17e012c0647688c39), ROM_BIOS(1) )

	ROM_SYSTEM_BIOS(1, "bios1", "Alternate")
	ROMX_LOAD( "2708_444-13_pam8go.rom", 0x0000, 0x0400, CRC(9dbad129) SHA1(72421102b881706877f50537625fc2ab0b507752), ROM_BIOS(2) )

	ROM_SYSTEM_BIOS(2, "bios2", "Disk OS")
	ROMX_LOAD( "2716_444-13_pam8at.rom", 0x0000, 0x0800, CRC(fd95ddc1) SHA1(eb1f272439877239f745521139402f654e5403af), ROM_BIOS(3) )

	ROM_SYSTEM_BIOS(3, "bios3", "Disk OS Alt")
	ROMX_LOAD( "2732_444-70_xcon8.rom", 0x0000, 0x1000, CRC(b04368f4) SHA1(965244277a3a8039a987e4c3593b52196e39b7e7), ROM_BIOS(4) )

	// this one runs off into the weeds
	ROM_SYSTEM_BIOS(4, "bios4", "not working")
	ROMX_LOAD( "2732_444-140_pam37.rom", 0x0000, 0x1000, CRC(53a540db) SHA1(90082d02ffb1d27e8172b11fff465bd24343486e), ROM_BIOS(5) )
ROM_END

/* Driver */

/*    YEAR  NAME  PARENT  COMPAT  MACHINE  INPUT    CLASS,    INIT        COMPANY        FULLNAME       FLAGS */
COMP( 1977, h8,   0,      0,      h8,      h8,      h8_state, empty_init, "Heath, Inc.", "Heathkit H8", MACHINE_NOT_WORKING )
initialize(running_machine &machine) override; int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override; int handle_bulk_pid(int endpoint, int pid, uint8_t *buffer, int size) override; void set_region_base(uint8_t *data); void set_region(const char *_region_tag, int _region_offset); protected: virtual void device_start() override; private: void process_packet(); static const USBStandardDeviceDescriptor devdesc; static const USBStandardConfigurationDescriptor condesc; static const USBStandardInterfaceDescriptor intdesc; static const USBStandardEndpointDescriptor enddesc01; static const USBStandardEndpointDescriptor enddesc02; static const USBStandardEndpointDescriptor enddesc03; static const USBStandardEndpointDescriptor enddesc81; static const USBStandardEndpointDescriptor enddesc82; static const USBStandardEndpointDescriptor enddesc83; static const uint8_t strdesc0[]; static const uint8_t strdesc1[]; static const uint8_t strdesc2[]; const char *region_tag; int region_offset; uint8_t *region; uint8_t midi_rs232; uint8_t response[256]; uint8_t packet[4]; int response_size; int step; }; DEFINE_DEVICE_TYPE(OHCI_HLEAN2131SC, ohci_hlean2131sc_device, "ohci_hlean2131sc", "OHCI an2131sc HLE") #define MCFG_OHCI_HLEAN2131SC_REGION(_region_tag, _region_offset) \ downcast<ohci_hlean2131sc_device *>(device)->set_region(_region_tag, _region_offset); /* * Class declaration for chihiro_state */ class chihiro_state : public xbox_base_state { friend class ide_baseboard_device; public: chihiro_state(const machine_config &mconfig, device_type type, const char *tag) : xbox_base_state(mconfig, type, tag) , m_ide(*this, "ide") , m_dimmboard(*this, "rom_board") , m_hack_index(-1) , m_hack_counter(0) , m_dimm_board_memory(nullptr) , m_dimm_board_memory_size(0) { } void chihirogd(machine_config &config); void chihiro_base(machine_config &config); private: DECLARE_READ32_MEMBER(mediaboard_r); DECLARE_WRITE32_MEMBER(mediaboard_w); virtual void machine_start() override; void baseboard_ide_event(int type, uint8_t *read, uint8_t *write); uint8_t *baseboard_ide_dimmboard(uint32_t lba); void dword_write_le(uint8_t *addr, uint32_t d); void word_write_le(uint8_t *addr, uint16_t d); virtual void hack_eeprom() override; virtual void hack_usb() override; // devices optional_device<bus_master_ide_controller_device> m_ide; optional_device<naomi_gdrom_board> m_dimmboard; int m_hack_index; int m_hack_counter; uint8_t *m_dimm_board_memory; uint32_t m_dimm_board_memory_size; static void an2131qc_configuration(device_t *device); static void an2131sc_configuration(device_t *device); void chihiro_map(address_map &map); void chihiro_map_io(address_map &map); void jamtable_disasm(address_space &space, uint32_t address, uint32_t size); void jamtable_disasm_command(int ref, const std::vector<std::string> &params); void chihiro_help_command(int ref, const std::vector<std::string> &params); void debug_commands(int ref, const std::vector<std::string> &params); }; /* jamtable instructions for Chihiro (different from Xbox console) St. Instr. Comment 0x01 POKEPCI PCICONF[OP2] := OP1 0x02 OUTB PORT[OP2] := OP1 0x03 POKE MEM[OP2] := OP1 0x04 BNE IF ACC <> OP2 THEN PC := PC + OP1 0x05 PEEKPCI ACC := PCICONF[OP2] 0x06 AND/OR ACC := (ACC & OP2) | OP1 0x07 BRA PC := PC + OP1 0x08 INB ACC := PORT[OP2] 0x09 PEEK ACC := MEM[OP2] 0xE1 (prefix) execute the instruction code in OP2 with OP2 := OP1, OP1 := ACC 0xEE END */ /* jamtable disassembler */ void chihiro_state::jamtable_disasm(address_space &space, uint32_t address, uint32_t size) // 0xff000080 == fff00080 { debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); offs_t addr = (offs_t)address; if (!space.device().memory().translate(space.spacenum(), TRANSLATE_READ_DEBUG, addr)) { con.printf("Address is unmapped.\n"); return; } while (1) { offs_t base = addr; uint32_t opcode = cpu.read_byte(space, addr, true); addr++; uint32_t op1 = cpu.read_dword(space, addr, true); addr += 4; uint32_t op2 = cpu.read_dword(space, addr, true); addr += 4; char sop1[16]; char sop2[16]; char pcrel[16]; if (opcode == 0xe1) { opcode = op2 & 255; op2 = op1; //op1=edi; sprintf(sop2, "%08X", op2); sprintf(sop1, "ACC"); sprintf(pcrel, "PC+ACC"); } else { sprintf(sop2, "%08X", op2); sprintf(sop1, "%08X", op1); sprintf(pcrel, "%08X", base + 9 + op1); } con.printf("%08X ", base); // dl=instr ebx=par1 eax=par2 switch (opcode) { case 0x01: // if ((op2 & 0xff) == 0x880) op1=op1 & 0xfffffffd // out cf8,op2 // out cfc,op1 // out cf8,0 // cf8 (CONFIG_ADDRESS) format: // 31 30 24 23 16 15 11 10 8 7 2 1 0 // +-+----------+------------+---------------+-----------------+-----------------+-+-+ // | | Reserved | Bus Number | Device Number | Function Number | Register Number |0|0| // +-+----------+------------+---------------+-----------------+-----------------+-+-+ // 31 - Enable bit con.printf("POKEPCI PCICONF[%s]=%s\n", sop2, sop1); break; case 0x02: con.printf("OUTB PORT[%s]=%s\n", sop2, sop1); break; case 0x03: con.printf("POKE MEM[%s]=%s\n", sop2, sop1); break; case 0x04: con.printf("BNE IF ACC != %s THEN PC=%s\n", sop2, pcrel); break; case 0x05: // out cf8,op2 // in acc,cfc con.printf("PEEKPCI ACC=PCICONF[%s]\n", sop2); break; case 0x06: con.printf("AND/OR ACC=(ACC & %s) | %s\n", sop2, sop1); break; case 0x07: con.printf("BRA PC=%s\n", pcrel); break; case 0x08: con.printf("INB ACC=PORT[%s]\n", sop2); break; case 0x09: con.printf("PEEK ACC=MEM[%s]\n", sop2); break; case 0xee: con.printf("END\n"); break; default: con.printf("NOP ????\n"); break; } if (opcode == 0xee) break; if (size <= 9) break; size -= 9; } } void chihiro_state::jamtable_disasm_command(int ref, const std::vector<std::string> &params) { address_space &space = m_maincpu->space(); uint64_t addr, size; if (params.size() < 3) return; if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) return; if (!machine().debugger().commands().validate_number_parameter(params[2], size)) return; jamtable_disasm(space, (uint32_t)addr, (uint32_t)size); } void chihiro_state::chihiro_help_command(int ref, const std::vector<std::string> &params) { debugger_console &con = machine().debugger().console(); con.printf("Available Chihiro commands:\n"); con.printf(" chihiro jamdis,<start>,<size> -- Disassemble <size> bytes of JamTable instructions starting at <start>\n"); con.printf(" chihiro help -- this list\n"); } void chihiro_state::debug_commands(int ref, const std::vector<std::string> &params) { if (params.size() < 1) return; if (params[0] == "jamdis") jamtable_disasm_command(ref, params); else chihiro_help_command(ref, params); } void chihiro_state::hack_eeprom() { // 8003b744,3b744=0x90 0x90 m_maincpu->space(AS_PROGRAM).write_byte(0x3b744, 0x90); m_maincpu->space(AS_PROGRAM).write_byte(0x3b745, 0x90); m_maincpu->space(AS_PROGRAM).write_byte(0x3b766, 0xc9); m_maincpu->space(AS_PROGRAM).write_byte(0x3b767, 0xc3); } #define HACK_ITEMS 5 static const struct { const char *game_name; struct { uint32_t address; uint8_t write_byte; } modify[16]; } hacks[HACK_ITEMS] = { { "chihiro", { { 0, 0 } } }, { "outr2", { { 0, 0 } } }, { "crtaxihr", { { 0x14ada5/*11fda5*/, 0x90 }, { 0x14ada6/*11fda6*/, 0x90 }, { 0, 0 } } }, { "ghostsqu", { { 0x78833/*4d833*/, 0x90 }, { 0x78834/*4d834*/, 0x90 }, { 0, 0 } } }, { "vcop3", { { 0x61a23/*36a23*/, 0x90 }, { 0x61a24/*36a24*/, 0x90 }, { 0, 0 } } }, }; void chihiro_state::hack_usb() { int p; if (m_hack_counter == 1) p = m_hack_index; // need to patch the game else p = -1; if (p >= 0) { for (int a = 0; a < 16; a++) { if (hacks[p].modify[a].address == 0) break; m_maincpu->space(0).write_byte(hacks[p].modify[a].address, hacks[p].modify[a].write_byte); } } m_hack_counter++; } //************************************************************************** // BASE BOARD USB //************************************************************************** //ic10 const USBStandardDeviceDescriptor ohci_hlean2131qc_device::devdesc = { 0x12,0x01,0x0100,0x60,0x00,0x00,0x40,0x0CA3,0x0002,0x0108,0x01,0x02,0x00,0x01 }; // class 0x60 subclass 0x00 const USBStandardConfigurationDescriptor ohci_hlean2131qc_device::condesc = { 0x09,0x02,0x0058,0x01,0x01,0x00,0x80,0x96 }; const USBStandardInterfaceDescriptor ohci_hlean2131qc_device::intdesc = { 0x09,0x04,0x00,0x00,0x0A,0xFF,0x00,0x00,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc01 = { 0x07,0x05,0x01,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc02 = { 0x07,0x05,0x02,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc03 = { 0x07,0x05,0x03,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc04 = { 0x07,0x05,0x04,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc05 = { 0x07,0x05,0x05,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc81 = { 0x07,0x05,0x81,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc82 = { 0x07,0x05,0x82,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc83 = { 0x07,0x05,0x83,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc84 = { 0x07,0x05,0x84,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131qc_device::enddesc85 = { 0x07,0x05,0x85,0x02,0x0040,0x00 }; const uint8_t ohci_hlean2131qc_device::strdesc0[] = { 0x04,0x03,0x00,0x00 }; const uint8_t ohci_hlean2131qc_device::strdesc1[] = { 0x0A,0x03,0x53,0x00,0x45,0x00,0x47,0x00,0x41,0x00 }; const uint8_t ohci_hlean2131qc_device::strdesc2[] = { 0x0E,0x03,0x42,0x00,0x41,0x00,0x53,0x00,0x45,0x00,0x42,0x03,0xFF,0x0B }; ohci_hlean2131qc_device::ohci_hlean2131qc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, OHCI_HLEAN2131QC, tag, owner, clock) , ohci_function() , device_slot_card_interface(mconfig, *this) , m_jvs_master(*this, "^^^^jvs_master") { maximum_send = 0; region_tag = nullptr; region_offset = 0; region = nullptr; jvs.buffer_in_expected = 0; jvs.buffer_out_used = 0; jvs.buffer_out_packets = 0; } void ohci_hlean2131qc_device::initialize(running_machine &machine) { ohci_function::initialize(machine); add_device_descriptor(devdesc); add_configuration_descriptor(condesc); add_interface_descriptor(intdesc); // it is important to add the endpoints in the same order they are found in the device firmware add_endpoint_descriptor(enddesc01); add_endpoint_descriptor(enddesc02); add_endpoint_descriptor(enddesc03); add_endpoint_descriptor(enddesc04); add_endpoint_descriptor(enddesc05); add_endpoint_descriptor(enddesc81); add_endpoint_descriptor(enddesc82); add_endpoint_descriptor(enddesc83); add_endpoint_descriptor(enddesc84); add_endpoint_descriptor(enddesc85); add_string_descriptor(strdesc0); add_string_descriptor(strdesc1); add_string_descriptor(strdesc2); } void ohci_hlean2131qc_device::set_region_base(uint8_t *data) { region = data; } void ohci_hlean2131qc_device::set_region(const char *_region_tag, int _region_offset) { region_tag = _region_tag; region_offset = _region_offset; } int ohci_hlean2131qc_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { int sense; #ifdef VERBOSE_MSG printf("Control request to an2131qc: %x %x %x %x %x %x %x\n\r", endpoint, endpoints[endpoint].controldirection, setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); #endif if (endpoint != 0) return -1; // default valuse for data stage for (int n = 0; n < setup->wLength; n++) endpoints[endpoint].buffer[n] = 0x50 ^ n; sense = m_jvs_master->get_sense_line(); if (sense == 25) sense = 3; else sense = 0; // need to check // PINSA register, bits 0-2 connected do dip switches 1-3 on filter board, bit 4 to dip switch 4, bit 5 to dip switch 5, bits 6-7 to buttons 1-2 on filter board // bits 4-1 value must be 10 xor 15, and bit 3 is ignored since its used as the CS pin of the chip endpoints[endpoint].buffer[1] = 0x4b; // PINSB register, bits 5-7 connected to 3 leds not mounted on pcb, bit 4 connected to re/de pins of max485, bits 2-3 used as uart pins, bits 0-1 give the status of the sense pin of the jvs connector // if bits 0-1 are 11, the not all the connected jvs devices have been assigned an address yet endpoints[endpoint].buffer[2] = 0x52 | sense; // OUTB register endpoints[endpoint].buffer[3] = 0x53; // bRequest is a command value if (setup->bRequest == 0x16) { // this command is used to read data from the first i2c serial eeprom connected to the chip // setup->wValue = start address to read from // setup->wIndex = number of bytes to read // data will be transferred to the host using endpoint 1 (IN) endpoints[1].remain = setup->wIndex & 255; endpoints[1].position = region + setup->wValue; // usually wValue is 0x1f00 endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x17) { // this command is used to read data from the second i2c serial eeprom connected to the chip // setup->wValue = start address to read from // setup->wIndex = number of bytes to read // data will be transferred to the host using endpoint 2 (IN) endpoints[2].remain = setup->wIndex & 255; endpoints[2].position = region + 0x2000 + setup->wValue; endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x18) { // this command is used to read data from external memory (with respect to the internal 8051 cpu) // setup->wValue = start address to read from // setup->wIndex = number of bytes to read // data will be transferred to the host using endpoint 3 (IN) endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x19) { // this command is used to retreive the jvs packets that have been received in response to the ones of 0x20 // data for the packets will be transferred to the host using endpoint 4 (IN) // the nuber of bytes to transfer is returned at bytes 4 and 5 in the data stage of this control transfer // data transferred starts with a byte with value 0, then a byte with value the number of packets received, then a block of bytes for each packet // the bytes for a packet start with the jvs node address of the sender, then a dummy one (must be 0), then a 16 bit number in little endian format that specifies how many bytes follow // the bytes that follow contain the body of the packet as received from the jvs bus, from the 0xa0 byte to the checksum endpoints[endpoint].buffer[0] = 0; // 0 if not busy endpoints[endpoint].buffer[5] = jvs.buffer_out_used >> 8; // amount to transfer with endpoint 4 endpoints[endpoint].buffer[4] = (jvs.buffer_out_used & 0xff); // the data to be sent is prepared in command 0x20 endpoints[4].remain = jvs.buffer_out_used; endpoints[4].position = jvs.buffer_out; jvs.buffer_out_used = 0; endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x1c) { // this command is used to read from the RV5C386A chip // setup->wValue = what to read // setup->wIndex = number of bytes to read // data will be transferred to the host using endpoint 5 (IN) endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x1d) { // this command is used to write data to the first i2c serial eeprom connected to the chip // no more than 32 bytes can be written at a time // setup->wValue = start address to write to // setup->wIndex = number of bytes to write // data will be transferred from the host using endpoint 1 (OUT) endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x1e) { // this command is used to write data to the second i2c serial eeprom connected to the chip // no more than 8 bytes can be written at a time // setup->wValue = start address to write to // setup->wIndex = number of bytes to write // data will be transferred from the host using endpoint 2 (OUT) endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x1f) { // this command is used to write data to external memory (with respect to the internal 8051 cpu) // setup->wValue = start address to write to // setup->wIndex = number of bytes to write // data will be transferred from the host using endpoint 3 (OUT) endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x20) { // this command is used to send a set of jvs packets, each to a different node // for each packet sent, the respective answer will be stored, and can be retrieved with 0x19 // setup->wIndex = number of bytes to be sent by the host // data for the packets will be transferred from the host using endpoint 4 (OUT) // data sent by the host contains first a byte with value 0 that is ignored, then a byte specifying the number of packets that follow, then the data for each packet // the data for each packet contains first a byte with value 0, then the sync byte (0xe0) then all the other bytes of the packet ending with the checksum byte // broadcast packets must have a destination node address of value 0xff #ifdef VERBOSE_MSG printf(" Jvs packets data of %d bytes\n\r", setup->wIndex); #endif endpoints[endpoint].buffer[0] = 0; if (jvs.buffer_out_used == 0) { jvs.buffer_out_packets = 0; jvs.buffer_out[0] = 0; jvs.buffer_out[1] = (uint8_t)jvs.buffer_out_packets; jvs.buffer_out_used = 2; } jvs.buffer_in_expected = setup->wIndex; endpoints[4].remain = jvs.buffer_in_expected; endpoints[4].position = jvs.buffer_in; } else if (setup->bRequest == 0x24) { // this command is used to write to the RV5C386A chip // no more than 0x20 bytes can be written // setup->wValue = what to read // data will be transferred from the host using endpoint 5 (OUT) endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x30) { // this command first disables external interrupt 0 if the lower 8 bits of setup->wValue are 0 // or enables it if those bits, seen as a signed 8 bit value, represent a number greater than 0 // then it will return in byte 4 of the data stage the value 0 if external interrupt 0 has been disabled or value 1 if it has been enabled // and in byte 5 the value of an 8 bit counter that is incremented at every external interrupt 0 endpoints[endpoint].buffer[0] = 0; if ((setup->wValue & 255) == 0) endpoints[endpoint].buffer[4] = 0; else if ((setup->wValue & 255) < 128) endpoints[endpoint].buffer[4] = 1; endpoints[endpoint].buffer[5] = 0; } else endpoints[endpoint].buffer[0] = 0x99; // usnupported command endpoints[endpoint].position = endpoints[endpoint].buffer; endpoints[endpoint].remain = setup->wLength; return 0; } int ohci_hlean2131qc_device::handle_bulk_pid(int endpoint, int pid, uint8_t *buffer, int size) { #ifdef VERBOSE_MSG printf("Bulk request to an2131qc: %x %d %x\n\r", endpoint, pid, size); #endif if (((endpoint == 1) || (endpoint == 2)) && (pid == InPid)) { if (size > endpoints[endpoint].remain) size = endpoints[endpoint].remain; memcpy(buffer, endpoints[endpoint].position, size); endpoints[endpoint].position = endpoints[endpoint].position + size; endpoints[endpoint].remain = endpoints[endpoint].remain - size; } if ((endpoint == 4) && (pid == InPid)) { if (size > endpoints[4].remain) size = endpoints[4].remain; memcpy(buffer, endpoints[4].position, size); endpoints[4].position = endpoints[4].position + size; endpoints[4].remain = endpoints[4].remain - size; } if ((endpoint == 4) && (pid == OutPid)) { if (size > endpoints[4].remain) size = endpoints[4].remain; #ifdef VERBOSE_MSG for (int n = 0; n < size; n++) printf(" %02x", buffer[n]); #endif if (size > 0) { memcpy(endpoints[4].position, buffer, size); endpoints[4].position = endpoints[4].position + size; endpoints[4].remain = endpoints[4].remain - size; if (endpoints[4].remain == 0) { #ifdef VERBOSE_MSG printf("\n\r"); #endif // extract packets process_jvs_packet(); } } } return size; } void ohci_hlean2131qc_device::process_jvs_packet() { int numpk = jvs.buffer_in[1]; int p = 2; for (int n = 0; n < numpk; n++) { p++; if (jvs.buffer_in[p] != 0xe0) break; p++; int dest = jvs.buffer_in[p]; p++; int len = jvs.buffer_in[p]; p++; if ((p + len) > jvs.buffer_in_expected) break; int chk = dest + len; for (int m = len - 1; m > 0; m--) chk = chk + (int)jvs.buffer_in[p + m - 1]; chk = chk & 255; if (chk != (int)jvs.buffer_in[p + len - 1]) { p = p + len; continue; } // use data of this packet m_jvs_master->send_packet(dest, len, jvs.buffer_in + p); // generate response if (dest == 0xff) dest = 0; int recv = m_jvs_master->received_packet(jvs.buffer_out + jvs.buffer_out_used + 5); // update buffer_out if (recv > 0) { chk = 0; for (int m = 0; m < recv; m++) chk = chk + jvs.buffer_out[jvs.buffer_out_used + 5 + m]; jvs.buffer_out[jvs.buffer_out_used + 5 + recv] = chk & 255; jvs.buffer_out_packets++; // jvs node address jvs.buffer_out[jvs.buffer_out_used] = (uint8_t)dest; // dummy jvs.buffer_out[jvs.buffer_out_used + 1] = 0; // length following recv += 2; jvs.buffer_out[jvs.buffer_out_used + 2] = recv & 255; jvs.buffer_out[jvs.buffer_out_used + 3] = (recv >> 8) & 255; // body jvs.buffer_out[jvs.buffer_out_used + 4] = 0xe0; jvs.buffer_out_used = jvs.buffer_out_used + recv + 5 - 1; jvs.buffer_out[1] = (uint8_t)jvs.buffer_out_packets; } p = p + len; } } void ohci_hlean2131qc_device::device_start() { initialize(machine()); if (region_tag) set_region_base(memregion(region_tag)->base() + region_offset); } //pc20 const USBStandardDeviceDescriptor ohci_hlean2131sc_device::devdesc = { 0x12,0x01,0x0100,0x60,0x01,0x00,0x40,0x0CA3,0x0003,0x0110,0x01,0x02,0x00,0x01 }; // class 0x60 subclass 0x01 const USBStandardConfigurationDescriptor ohci_hlean2131sc_device::condesc = { 0x09,0x02,0x003C,0x01,0x01,0x00,0x80,0x96 }; const USBStandardInterfaceDescriptor ohci_hlean2131sc_device::intdesc = { 0x09,0x04,0x00,0x00,0x06,0xFF,0x00,0x00,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131sc_device::enddesc01 = { 0x07,0x05,0x01,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131sc_device::enddesc02 = { 0x07,0x05,0x02,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131sc_device::enddesc03 = { 0x07,0x05,0x03,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131sc_device::enddesc81 = { 0x07,0x05,0x81,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131sc_device::enddesc82 = { 0x07,0x05,0x82,0x02,0x0040,0x00 }; const USBStandardEndpointDescriptor ohci_hlean2131sc_device::enddesc83 = { 0x07,0x05,0x83,0x02,0x0040,0x00 }; const uint8_t ohci_hlean2131sc_device::strdesc0[] = { 0x04,0x03,0x00,0x00 }; const uint8_t ohci_hlean2131sc_device::strdesc1[] = { 0x0A,0x03,0x53,0x00,0x45,0x00,0x47,0x00,0x41,0x00 }; const uint8_t ohci_hlean2131sc_device::strdesc2[] = { 0x0E,0x03,0x42,0x00,0x41,0x00,0x53,0x00,0x45,0x00,0x42,0x00,0x44,0x00 }; ohci_hlean2131sc_device::ohci_hlean2131sc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, OHCI_HLEAN2131SC, tag, owner, clock) , ohci_function() , device_slot_card_interface(mconfig, *this) { region = nullptr; region_tag = nullptr; region_offset = 0; midi_rs232 = 0; response_size = 0; step = 0; } void ohci_hlean2131sc_device::set_region_base(uint8_t *data) { region = data; } void ohci_hlean2131sc_device::set_region(const char *_region_tag, int _region_offset) { region_tag = _region_tag; region_offset = _region_offset; } void ohci_hlean2131sc_device::initialize(running_machine &machine) { ohci_function::initialize(machine); add_device_descriptor(devdesc); add_configuration_descriptor(condesc); add_interface_descriptor(intdesc); // it is important to add the endpoints in the same order they are found in the device firmware add_endpoint_descriptor(enddesc01); add_endpoint_descriptor(enddesc02); add_endpoint_descriptor(enddesc03); add_endpoint_descriptor(enddesc81); add_endpoint_descriptor(enddesc82); add_endpoint_descriptor(enddesc83); add_string_descriptor(strdesc0); add_string_descriptor(strdesc1); add_string_descriptor(strdesc2); } int ohci_hlean2131sc_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { #ifdef VERBOSE_MSG printf("Control request to an2131sc: %x %x %x %x %x %x %x\n\r", endpoint, endpoints[endpoint].controldirection, setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength); #endif if (endpoint != 0) return -1; // default valuse for data stage for (int n = 0; n < setup->wLength; n++) endpoints[endpoint].buffer[n] = 0x50 ^ n; endpoints[endpoint].buffer[1] = 0; // PINSB register, bits 0-1 uset as rts/cts signals for uart0, bits 2-3 used as uart1, bits 5-7 used as leds (not mounted on pcb) endpoints[endpoint].buffer[2] = 0x52; // PINSB // OUTB register endpoints[endpoint].buffer[3] = 0x53; // OUTB endpoints[endpoint].buffer[4] = 0; endpoints[endpoint].buffer[5] = 0; // PINSC register, bit 7 selects default value for bit 6 after reset (connected to dip switch 5 on filter board), bits 0-1 used as uart0 pins endpoints[endpoint].buffer[6] = 0x56; // OUTC register, bit 6 specifies if uart1 should be connected to midi or rs232 endpoints[endpoint].buffer[7] = 0x57; // bRequest is a command value if (setup->bRequest == 0x16) { // this command is used to read data from the i2c serial eeprom connected to the chip // setup->wValue = start address to read from // setup->wIndex = number of bytes to read // data will be transferred to the host using endpoint 1 (IN) endpoints[1].remain = setup->wIndex & 255; endpoints[1].position = region + setup->wValue; // usually wValue is 0x1f00 endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x17) { endpoints[endpoint].buffer[0] = 0x90; } else if (setup->bRequest == 0x1a) { // used to get data received by uart0 data transferred with endpoint 2 (IN) endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x1b) { // used to get data received by uart 1 data transferred with endpoint 3 (IN) // setup->wIndex = number of bytes host would like to retrieve (must be lower than 256, 0 means get all available) endpoints[endpoint].buffer[0] = 0; // endpoints[endpoint].buffer[1] = 0; // bit 0 in buffer overflow bit 1 in parity error if ((setup->wIndex == 0) || (setup->wIndex > response_size)) { endpoints[endpoint].buffer[4] = response_size & 255; // how many bytes to transfer with endpoint 3 endpoints[endpoint].buffer[5] = (response_size >> 8) & 255; memcpy(endpoints[3].buffer, response, response_size); response_size = 0; } else { endpoints[endpoint].buffer[4] = setup->wIndex & 255; endpoints[endpoint].buffer[5] = (setup->wIndex >> 8) & 255; memcpy(endpoints[3].buffer, response, setup->wIndex); for (int n = setup->wIndex; n < response_size; n++) response[n - setup->wIndex] = response[n]; response_size = response_size - setup->wIndex; } endpoints[3].remain = setup->wIndex; endpoints[3].position = endpoints[3].buffer; } else if (setup->bRequest == 0x1d) { // this command is used to write data to the i2c serial eeprom connected to the chip // no more than 32 bytes can be written at a time // setup->wValue = start address to write to // setup->wIndex = number of bytes to write // data will be transferred from the host using endpoint 1 (OUT) endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x1e) { endpoints[endpoint].buffer[0] = 0x90; } else if (setup->bRequest == 0x22) { // send data to be output from uart0 endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x23) { // this command is used to send data to be output from uart1 // setup->wIndex = number of bytes to send // data will be transferred to the host using endpoint 3 (OUT) endpoints[endpoint].buffer[0] = 0; endpoints[3].remain = setup->wIndex; endpoints[3].position = endpoints[3].buffer; } else if (setup->bRequest == 0x25) // { endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x26) // { // set uart0 or uart1 mode endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x27) // { endpoints[endpoint].buffer[0] = 0; } else if (setup->bRequest == 0x28) { endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x29) { endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x2a) { endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x2b) { endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x2c) { endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x2d) { // set pin 1 of PORTB, used as the RTS signal of the rs232 port implemented with uart0 endpoints[endpoint].buffer[0] = 0x99; } else if (setup->bRequest == 0x2e) { // switches uart1 between rs232 mode and midi mode // low byte of wValue sets the mode: 0 mode is selected using pin 7 of PORTC (0 midi 1 rs232), 1 rs232, 2 midi, other values no mode change endpoints[endpoint].buffer[0] = 0; midi_rs232 = setup->wValue & 255; } else if (setup->bRequest == 0x2f) { // return low byte of wValue from command 0x2e endpoints[endpoint].buffer[0] = 0; endpoints[endpoint].buffer[4] = midi_rs232; } else if (setup->bRequest == 0x30) { // this command first disables external interrupt 0 if the lower 8 bits of setup->wValue are 0 // or enables it if those bits, seen as a signed 8 bit value, represent a number greater than 0 // then it will return in byte 4 of the data stage the value 0 if external interrupt 0 has been disabled or value 1 if it has been enabled // and in byte 5 the value of an 8 bit counter that is incremented at every external interrupt 0 endpoints[endpoint].buffer[0] = 0; if ((setup->wValue & 255) == 0) endpoints[endpoint].buffer[4] = 0; else if ((setup->wValue & 255) < 128) endpoints[endpoint].buffer[4] = 1; endpoints[endpoint].buffer[5] = 0; } else if (setup->bRequest == 0x31) { // set pins 4-7 of PORTB // bits 4-7 of wValue & 255 set the direction // bits 4-7 of wValue >> 8 set the level endpoints[endpoint].buffer[0] = 0; } else endpoints[endpoint].buffer[0] = 0x99; // usnupported command endpoints[endpoint].position = endpoints[endpoint].buffer; endpoints[endpoint].remain = setup->wLength; return 0; } int ohci_hlean2131sc_device::handle_bulk_pid(int endpoint, int pid, uint8_t *buffer, int size) { #ifdef VERBOSE_MSG printf("Bulk request to an2131sc: %x %d %x\n\r", endpoint, pid, size); #endif if (((endpoint == 1) || (endpoint == 2)) && (pid == InPid)) { if (size > endpoints[endpoint].remain) size = endpoints[endpoint].remain; memcpy(buffer, endpoints[endpoint].position, size); endpoints[endpoint].position = endpoints[endpoint].position + size; endpoints[endpoint].remain = endpoints[endpoint].remain - size; } if ((endpoint == 3) && (pid == InPid)) { if (size > endpoints[3].remain) size = endpoints[3].remain; memcpy(buffer, endpoints[3].position, size); endpoints[3].position = endpoints[3].position + size; endpoints[3].remain = endpoints[3].remain - size; } if ((endpoint == 3) && (pid == OutPid)) { if (size > endpoints[3].remain) size = endpoints[3].remain; memcpy(endpoints[3].position, buffer, size); endpoints[3].position = endpoints[3].position + size; endpoints[3].remain = endpoints[3].remain - size; for (int n = 0; n < size; n++) { uint8_t byt = buffer[n]; switch(step) { case 0: if ((byt & 0x80) != 0) { packet[0] = byt; step = 1; } break; case 1: packet[1] = byt; step = 2; break; case 2: packet[2] = byt; step = 3; break; case 3: packet[3] = byt; step = 0; process_packet(); break; } } } return size; } void ohci_hlean2131sc_device::process_packet() { uint8_t result = 0; #ifdef VERBOSE_MSG printf("%02X %02X %02X %02X\n\r", packet[0], packet[1], packet[2], packet[3]); #endif if (packet[0] == 0xff) // 00 00 7f result = 2; else if (packet[0] == 0x81) // 30 7f 4e result = 1; // must be 1 else if (packet[0] == 0xfc) // 00 20 5c result = 3; else if (packet[0] == 0xfd) // 00 00 7d result = 0; else if (packet[0] == 0xfa) // 00 1f 65 result = 0; else if (packet[0] == 0x83) // 40 04 47 result = 0; else if (packet[0] == 0x86) // 01 02 05 result = 0; else if (packet[0] == 0x88) // 00 04 0c result = 0; else if (packet[0] == 0x80) // 01 01 00 result = 0; else if (packet[0] == 0x84) // 01 00 05 result = 0; else if (packet[0] == 0xf0) // 00 00 70 result = 0; else if (packet[0] == 0x9d) result = 0; else if (packet[0] == 0x9e) result = 0; if (response_size < 256) { response[response_size] = result + (result << 4); response_size++; } } void ohci_hlean2131sc_device::device_start() { initialize(machine()); if (region_tag) set_region_base(memregion(region_tag)->base() + region_offset); } // ======================> ide_baseboard_device class ide_baseboard_device : public ata_mass_storage_device { public: // construction/destruction ide_baseboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual int read_sector(uint32_t