summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/trs80.cpp
blob: 4603a976a812d96a23b7223466a83b8f3385f233 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                       
                                                  
                                                                             
 
                


                           

                                                    

 
                                                          
 


                                                                                                      
                                               

                                        
                                                          
                                       
 
                                     









                                       
                                      











                                                          
                                      








                                                              
                       






                                            



                    
                                       
 
                                  

 
                                       















                                                                            






                                                


            











                                                                            
 










                                             
 







                                            
 
                    

 
                                       
 

                          
 




                                      
 
                                                                                 














                                                     
                                           







                                                                                              
                                                                                  

                                       
                          
 
                                           

 
                                       





                                  

                                                                
 
                                                                                                                        
                                             
                                
 
                                                
 


                         
                                                                           
                                                         

         
                                                                       
                            
                                             

 





                                       
                                                
 
                                                                                   
                                                                                   
 

                                                
 

                                                                   






                                                 

 
 
                                       
 

                  

                                                        

            
                                     

 






                                       
                                     
 
                            
                                        
                                         



                    
                                      
 
                                        

 
                                       
 
                                     

                                      

 
                                        







                           
                                         







                                                                                            
                          
                                                 




                      
                                     
 
                           
 



                                                             
 
                                    
 
                     
         


                                             
         
 

                         




                                       
                                       
 




                                                           








                                       
                                 
 
                            

                      
 
                                                                                                                                          
                                                                                     

 
                                 
 
                                
                                                                                



                                                                                           
                                                          
         

 
                                       
 

                                                       
                       
                       
                                
 
























                                                                            
                                                
 
                                                              
 


                             














                                                         
                                                                    








                                                                                                                     
                                                                    
                                                                                   
                                                                  


















                                                                                  
                                       
 
// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller, Robbbert
//***************************************************************************

#include "emu.h"
#include "includes/trs80.h"


#define IRQ_M1_RTC      0x80    /* RTC on Model I */
#define IRQ_M1_FDC      0x40    /* FDC on Model I */


TIMER_CALLBACK_MEMBER(trs80_state::cassette_data_callback)
{
/* This does all baud rates. 250 baud (trs80), and 500 baud (all others) set bit 7 of "cassette_data".
    1500 baud (trs80m3, trs80m4) is interrupt-driven and uses bit 0 of "cassette_data" */

	double new_val = (m_cassette->input());

	/* Check for HI-LO transition */
	if ( m_old_cassette_val > -0.2 && new_val < -0.2 )
		m_cassette_data = true;

	m_old_cassette_val = new_val;
}


/*************************************
 *
 *              Port handlers.
 *
 *************************************/


READ8_MEMBER( trs80_state::port_e8_r )
{
/* not emulated
    d7 Clear-to-Send (CTS), Pin 5
    d6 Data-Set-Ready (DSR), pin 6
    d5 Carrier Detect (CD), pin 8
    d4 Ring Indicator (RI), pin 22
    d3,d2,d0 Not used
    d1 UART Receiver Input, pin 20 (pin 20 is also DTR) */

	return 0;
}

READ8_MEMBER( trs80_state::port_ea_r )
{
/* UART Status Register
    d7 Data Received ('1'=condition true)
    d6 Transmitter Holding Register empty ('1'=condition true)
    d5 Overrun Error ('1'=condition true)
    d4 Framing Error ('1'=condition true)
    d3 Parity Error ('1'=condition true)
    d2..d0 Not used */

	uint8_t data=7;
	m_uart->write_swe(0);
	data |= m_uart->tbmt_r() ? 0x40 : 0;
	data |= m_uart->dav_r( ) ? 0x80 : 0;
	data |= m_uart->or_r(  ) ? 0x20 : 0;
	data |= m_uart->fe_r(  ) ? 0x10 : 0;
	data |= m_uart->pe_r(  ) ? 0x08 : 0;
	m_uart->write_swe(1);

	return data;
}

WRITE8_MEMBER( trs80_state::port_e8_w )
{
	m_reg_load = BIT(data, 1);
}

WRITE8_MEMBER( trs80_state::port_ea_w )
{
	if (m_reg_load)

/* d2..d0 not emulated
    d7 Even Parity Enable ('1'=even, '0'=odd)
    d6='1',d5='1' for 8 bits
    d6='0',d5='1' for 7 bits
    d6='1',d5='0' for 6 bits
    d6='0',d5='0' for 5 bits
    d4 Stop Bit Select ('1'=two stop bits, '0'=one stop bit)
    d3 Parity Inhibit ('1'=disable; No parity, '0'=parity enabled)
    d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition)
    d1 Request-to-Send (RTS), pin 4
    d0 Data-Terminal-Ready (DTR), pin 20 */

	{
		m_uart->write_cs(0);
		m_uart->write_nb1(BIT(data, 6));
		m_uart->write_nb2(BIT(data, 5));
		m_uart->write_tsb(BIT(data, 4));
		m_uart->write_eps(BIT(data, 7));
		m_uart->write_np(BIT(data, 3));
		m_uart->write_cs(1);
	}
	else
	{
/* not emulated
    d7,d6 Not used
    d5 Secondary Unassigned, pin 18
    d4 Secondary Transmit Data, pin 14
    d3 Secondary Request-to-Send, pin 19
    d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition)
    d1 Data-Terminal-Ready (DTR), pin 20
    d0 Request-to-Send (RTS), pin 4 */

	}
}


READ8_MEMBER( trs80_state::sys80_f9_r )
{
/* UART Status Register - d6..d4 not emulated
    d7 Transmit buffer empty (inverted)
    d6 CTS pin
    d5 DSR pin
    d4 CD pin
    d3 Parity Error
    d2 Framing Error
    d1 Overrun
    d0 Data Available */

	uint8_t data = 0x70;
	m_uart->write_swe(0);
	data |= m_uart->tbmt_r() ? 0 : 0x80;
	data |= m_uart->dav_r( ) ? 0x01 : 0;
	data |= m_uart->or_r(  ) ? 0x02 : 0;
	data |= m_uart->fe_r(  ) ? 0x04 : 0;
	data |= m_uart->pe_r(  ) ? 0x08 : 0;
	m_uart->write_swe(1);

	return data;
}

READ8_MEMBER( trs80_state::lnw80_fe_r )
{
	return m_lnw_mode;
}

READ8_MEMBER( trs80_state::port_ff_r )
{
/* ModeSel and cassette data
    d7 cassette data from tape
    d6 modesel setting */

	return (BIT(m_mode, 0) ? 0 : 0x40) | (m_cassette_data ? 0x80 : 0) | 0x3f;
}

WRITE8_MEMBER( trs80_state::sys80_f8_w )
{
/* not emulated
    d2 reset UART (XR pin)
    d1 DTR
    d0 RTS */
}

WRITE8_MEMBER( trs80_state::sys80_fe_w )
{
/* not emulated
    d4 select internal or external cassette player */

	m_tape_unit = BIT(data, 4) ? 2 : 1;
}

/* lnw80 can switch out all the devices, roms and video ram to be replaced by graphics ram. */
WRITE8_MEMBER( trs80_state::lnw80_fe_w )
{
/* lnw80 video options
    d3 bankswitch lower 16k between roms and hires ram (1=hires)
    d2 enable colour    \
    d1 hres             /   these 2 are the bits from the MODE command of LNWBASIC
    d0 inverse video (entire screen) */

	m_lnw_mode = data;

	m_lnw_bank->set_bank(BIT(data, 3));
}

WRITE8_MEMBER( trs80_state::port_ff_w )
{
/* Standard output port of Model I
    d3 ModeSel bit
    d2 Relay
    d1, d0 Cassette output */

	static const double levels[4] = { 0.0, 1.0, -1.0, 0.0 };
	static bool init = 0;

	m_cassette->change_state(BIT(data, 2) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR );
	m_cassette->output(levels[data & 3]);
	m_cassette_data = false;

	m_mode = (m_mode & 0xfe) | BIT(data, 3);

	if (!init)
	{
		init = 1;
		static int16_t speaker_levels[4] = { 0, -32767, 0, 32767 };
		m_speaker->set_levels(4, speaker_levels);

	}
	/* Speaker for System-80 MK II - only sounds if relay is off */
	if (!(BIT(data, 2)))
		m_speaker->level_w(data & 3);
}

/*************************************
 *
 *      Interrupt handlers.
 *
 *************************************/

INTERRUPT_GEN_MEMBER(trs80_state::rtc_interrupt)
{
/* This enables the processing of interrupts for the clock and the flashing cursor.
    The OS counts one tick for each interrupt. It is called 40 times per second. */

	m_irq |= IRQ_M1_RTC;
	m_maincpu->set_input_line(0, HOLD_LINE);

	// While we're here, let's countdown the motor timeout too.
	// Let's not... LDOS often freezes
//  if (m_timeout)
//  {
//      m_timeout--;
//      if (m_timeout == 0)
//          if (m_floppy)
//              m_floppy->mon_w(1);  // motor off
//  }
}


WRITE_LINE_MEMBER(trs80_state::intrq_w)
{
	if (state)
	{
		m_irq |= IRQ_M1_FDC;
		m_maincpu->set_input_line(0, HOLD_LINE);
	}
	else
		m_irq &= ~IRQ_M1_FDC;
}


/*************************************
 *                                   *
 *      Memory handlers              *
 *                                   *
 *************************************/

READ8_MEMBER( trs80_state::wd179x_r )
{
	uint8_t data = 0xff;
	if (BIT(m_io_config->read(), 7))
		data = m_fdc->status_r();

	return data;
}

READ8_MEMBER( trs80_state::printer_r )
{
	return m_cent_status_in->read();
}

WRITE8_MEMBER( trs80_state::printer_w )
{
	m_cent_data_out->write(data);
	m_centronics->write_strobe(0);
	m_centronics->write_strobe(1);
}

WRITE8_MEMBER( trs80_state::cassunit_w )
{
/* not emulated
    01 for unit 1 (default)
    02 for unit 2 */

	m_tape_unit = data;
}

READ8_MEMBER( trs80_state::irq_status_r )
{
/* (trs80l2) Whenever an interrupt occurs, 37E0 is read to see what devices require service.
    d7 = RTC
    d6 = FDC
    d2 = Communications (not emulated)
    All interrupting devices are serviced in a single interrupt. There is a mask byte,
    which is dealt with by the DOS. We take the opportunity to reset the cpu INT line. */

	u8 result = m_irq;
	m_maincpu->set_input_line(0, CLEAR_LINE);
	m_irq = 0;
	return result;
}


WRITE8_MEMBER( trs80_state::motor_w )
{
	m_floppy = nullptr;

	if (BIT(data, 0)) m_floppy = m_floppy0->get_device();
	if (BIT(data, 1)) m_floppy = m_floppy1->get_device();
	if (BIT(data, 2)) m_floppy = m_floppy2->get_device();
	if (BIT(data, 3)) m_floppy = m_floppy3->get_device();

	m_fdc->set_floppy(m_floppy);

	if (m_floppy)
	{
		m_floppy->mon_w(0);
		m_floppy->ss_w(BIT(data, 4));
		m_timeout = 200;
	}

	// switch to fm
	m_fdc->dden_w(1);
}

/*************************************
 *      Keyboard         *
 *************************************/
READ8_MEMBER( trs80_state::keyboard_r )
{
	u8 i, result = 0;

	for (i = 0; i < 8; i++)
		if (BIT(offset, i))
			result |= m_io_keyboard[i]->read();

	return result;
}


/*************************************
 *  Machine              *
 *************************************/

void trs80_state::machine_start()
{
	m_size_store = 0xff;
	m_tape_unit=1;
	m_reg_load=1;

	m_cassette_data_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(trs80_state::cassette_data_callback),this));
	m_cassette_data_timer->adjust( attotime::zero, 0, attotime::from_hz(11025) );
}

void trs80_state::machine_reset()
{
	m_cassette_data = false;
	// if machine has a uart but no brg, the baud is determined by dipswitch
	if (m_io_baud)
	{
		const uint16_t s_bauds[8]={ 110, 300, 600, 1200, 2400, 4800, 9600, 19200 };
		u16 s_clock = s_bauds[m_io_baud->read()] << 4;
		m_uart_clock->set_unscaled_clock(s_clock);
	}
}

MACHINE_RESET_MEMBER(trs80_state,lnw80)
{
	machine_reset();
	address_space &space = m_maincpu->space(AS_IO);
	m_reg_load = 1;
	m_lnw_mode = 0;
	lnw80_fe_w(space, 0, 0);
}


/***************************************************************************
    PARAMETERS
***************************************************************************/

#define LOG 1

#define CMD_TYPE_OBJECT_CODE                            0x01
#define CMD_TYPE_TRANSFER_ADDRESS                       0x02
#define CMD_TYPE_END_OF_PARTITIONED_DATA_SET_MEMBER     0x04
#define CMD_TYPE_LOAD_MODULE_HEADER                     0x05
#define CMD_TYPE_PARTITIONED_DATA_SET_HEADER            0x06
#define CMD_TYPE_PATCH_NAME_HEADER                      0x07
#define CMD_TYPE_ISAM_DIRECTORY_ENTRY                   0x08
#define CMD_TYPE_END_OF_ISAM_DIRECTORY_ENTRY            0x0a
#define CMD_TYPE_PDS_DIRECTORY_ENTRY                    0x0c
#define CMD_TYPE_END_OF_PDS_DIRECTORY_ENTRY             0x0e
#define CMD_TYPE_YANKED_LOAD_BLOCK                      0x10
#define CMD_TYPE_COPYRIGHT_BLOCK                        0x1f

/***************************************************************************
    IMPLEMENTATION
***************************************************************************/

QUICKLOAD_LOAD_MEMBER(trs80_state::quickload_cb)
{
	address_space &program = m_maincpu->space(AS_PROGRAM);

	uint8_t type, length;
	uint8_t data[0x100];
	uint8_t addr[2];
	void *ptr;

	while (!image.image_feof())
	{
		image.fread( &type, 1);
		image.fread( &length, 1);

		length -= 2;
		int block_length = length ? length : 256;

		switch (type)
		{
		case CMD_TYPE_OBJECT_CODE:
			{
			image.fread( &addr, 2);
			uint16_t address = (addr[1] << 8) | addr[0];
			if (LOG) logerror("/CMD object code block: address %04x length %u\n", address, block_length);
			ptr = program.get_write_ptr(address);
			image.fread( ptr, block_length);
			}
			break;

		case CMD_TYPE_TRANSFER_ADDRESS:
			{
			image.fread( &addr, 2);
			uint16_t address = (addr[1] << 8) | addr[0];
			if (LOG) logerror("/CMD transfer address %04x\n", address);
			m_maincpu->set_state_int(Z80_PC, address);
			}
			break;

		case CMD_TYPE_LOAD_MODULE_HEADER:
			image.fread( &data, block_length);
			if (LOG) logerror("/CMD load module header '%s'\n", data);
			break;

		case CMD_TYPE_COPYRIGHT_BLOCK:
			image.fread( &data, block_length);
			if (LOG) logerror("/CMD copyright block '%s'\n", data);
			break;

		default:
			image.fread( &data, block_length);
			logerror("/CMD unsupported block type %u!\n", type);
		}
	}

	return image_init_result::PASS;
}