summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/octopus.cpp
blob: 7b9f7686b2760a9ea2aeb042135955a41d018e50 (plain) (tree)
1
2
                       
                                   
























                                                                                                                  






                                                      

                                           



                         



               
                                                    
                                          


                                                            



                                
                   



                      


                        



                       
 




































                                                                                                      
                                                                                                 



                                                                             
 
                        
                        
                            
                            
                            
                          


                             
                             

                            
                        
                           
                           


                          





                                        

                   
                     

                    



                                          

                                                                                         



                                            






                                            

                                          
                                             
                                    
                                    
                                            
                                          
                                              
                                                 
                                    
                                      

                                        

                                     
           
 


                                             
                                              
                                              
                                            


                                                      
                                            











                                                   

                                            


                                        

                                     

                                            

                                          

                                             



                                              
                                                  

                                                                                    
 







                                                                                                                                            




                                
 




                                               
 
                                                                                                       
 
                                              

                                               

                                               




                                               
                                             

                                                    
                                                
                                              
                                            
                                                        
                                                
                                                      

                                                               
                               
 







                                                                   


                              
                          

                           


                               

                               



                               
 
                                


  
















                                                                                            

                                                                                             
                                                                                           
                                 







                                                                                            

                                                                                                   
                             
                                                                                         

                                                                                                 

                                                                                       
 
 



                                                                                                                           
 


                                                    
                                                                                             
 
 

                                                  
                                                                                         
 


                                   























                                                                                         

               








                                                                                            
 

                                    

                                               



                                   

                                               


                              
































                                                    
                                                           












                                                                                                                               








                                                                            



                                     
                           


                      



                                                                          
         
 


                    













                                                               































                                                                                    









                                                                      
                           
 
                      
                                     
                              
                                     






                                   
                                     
                              
                                     

 
                               
                             









                                    
 



                                                    




                                                  


                                  




                                                           
                                                  


                                                           
                                                  

                      
                                                                           
















                                            
                                                                  

                      
                                                                  





                                                                                        






                                                                                
                                                                                  






                                          
















                                                                         
                         

 

























                                                                                                     





                                                











































                                                                                                                       

                                     
                     


                                                                                                
                                                                







                                                                                                
                                                                








                                                                                     
 


                                                            
                       


                                                               



                                                                                                                       

 


                                               
                         
 


                                                                                                    

 

                                   


                                                                                          

                            

                             
                                                             
                                                                                                                                                                         



                                 
                                 

 















                                           
                                                            
 









                                     
                            


                                           

               
                                                        
                                                                   
                                                                  





















                                                                                                                      
 

                                                         
                 



                                          

                                    
                                            
 



                                                                                         



                                             
                 

                                                                      
         

 

                                            





                                             


















                                                              
 

                                                   
                                    



                                                                                 
 


                                                                           
 









































                                                                                      
 
                                       








                                                                  
                                                              
 
                        



                                                                                 

                                                                                                   



                                                                                         
 


                                                                            


                                                                                                                  
 






                                                                                                                                                 
 
                                               
                                                                              
 
                                                                                             
                                                                              



                                                                                          
 







                                                                                                    
 


                                                                                  
                                                                                 
 
                            





                                                                                                      
                                                                              
                                       


                                                                          
 
                                                                                                                                 
 
                                                                                        
 












                                                                                                                     

                                                                                                                                             
// license:BSD-3-Clause
// copyright-holders:Barry Rodewald
/***************************************************************************

Hilger Analytical AB6089 Mk. 1 (LSI Octopus)

2013-07-26 Skeleton driver.

http://computers.mcbx.netne.net/8bit/hilger/index.htm

Below is an extract from the page:

The computer has 2 CPUs: Z80 and 8088. Most circuits are dated 1985-1986, display circuitry is made by Signetics.
Mainboard was manufactured by LSI Computers Ltd. under part numbers: 15000SS100 and 15000P4100. All steel parts
of casing are grounded by wires. It's graphics card works in pass-through mode: It takes picture from mainboard's
TTL output and adds image to it, then it puts it to monitor. Its ROM is prepared for hard disk and some type of
network, yet no HDD controller nor network interfaces are present inside - it seems that they were added as
expansion cards.

UPDATE: It's re-branded LSI Octopus computer, a very well-expandable machine which was designed to "grow with a
company". First stage was a computer which could be used even with TV set. As requirements increased, Octopus
could be equipped with hard disk controller, network adapter, multi-terminal serial port card to act as a terminal
server or even CPU cards to run concurrent systems. There were even tape backup devices for it. Octopus could run
CP/M, MP/M (concurrent - multitasking-like OS, even with terminals), or even MS-DOS - CP/M or MP/M could be used
with Z80 or 8080. There was also LSI ELSIE system, a concurrent DOS. Last British LSI machines were 386 computers
which could be used as servers for Octopus computers.

Manufacturer    Hilger Analytical / LSI Computers Ltd.

Origin  UK
Year of unit    1986?
Year of introduction    1985
End of production   ?
CPU     Z80, 8088
Speed   8MHz (8088) or 6MHz (Z80)
RAM     128kB or 256kB, expandable to 768kB
ROM     16kB (Basic)
Colors:     ??
Sound:  Speaker. Beeps :)
OS:     CP/M 80 or 86
MP/M 80 o 86
Concurrent CP/M
LSI ELSIE
MS-DOS
Text display: SCN2674B CRTC, SCB2675C for attributes
Graphics: ?? (option board, ROM is dumped)

Media:  Two internal 5.25" floppy disk drives, DS DD, 96tpi.
Probably hard disk

Power supply:
Built-in switching power supply.

I/O:    Serial port
2 parallel ports

Video TTL Output
Composite video output

Possible upgrades:  Many

Software accessibility:
Dedicated: Impossible.
CP/M - Good
DOS - Good.

It won't take XT nor AT keyboard, but pinout is quite similar. UPDATE: I saw a few photos of keyboard.
It's another Z80 computer! It has an EPROM, simple memory and CPU.

After powering on, it should perform POST writing:

TESTING...
    Main Processor
    PROM
    DMA Controllers
    RAM
    Interrupts
    Floppy Discs
    Hard Disc Controller   (optionally - if installed)

Waiting for hard Disc... (Optionally - if installed)

Firmware versions:

SYSTEM         18B (or other)
GRAPHICS      4    (if graphic card installed)

And probably it should boot or display:

Insert System Disk.

Or maybe:

Nowhere to boot from.

Load options:
    Floppy
    Pro Network
    Winchester
Enter selection:

This information was gained by studying boot ROM of the machine.

It's a very rare computer. It has 2 processors, Z80 and 8088, so it can run both MS-DOS and CP/M.

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

#include "emu.h"

#include "cpu/i86/i86.h"
#include "cpu/z80/z80.h"
#include "imagedev/floppy.h"
#include "machine/am9517a.h"
#include "machine/bankdev.h"
#include "machine/clock.h"
#include "machine/i8251.h"
#include "machine/i8255.h"
#include "machine/mc146818.h"
#include "machine/octo_kbd.h"
#include "machine/pic8259.h"
#include "machine/pit8253.h"
#include "machine/ram.h"
#include "machine/wd_fdc.h"
#include "machine/z80sio.h"
#include "sound/spkrdev.h"
#include "video/scn2674.h"

#include "bus/centronics/ctronics.h"
#include "bus/centronics/comxpl80.h"
#include "bus/centronics/epson_ex800.h"
#include "bus/centronics/epson_lx800.h"
#include "bus/centronics/epson_lx810l.h"
#include "bus/centronics/printer.h"

#include "screen.h"
#include "softlist.h"
#include "speaker.h"


class octopus_state : public driver_device
{
public:
	octopus_state(const machine_config &mconfig, device_type type, const char *tag) :
		driver_device(mconfig, type, tag),
		m_maincpu(*this, "maincpu"),
		m_subcpu(*this, "subcpu"),
		m_crtc(*this, "crtc"),
		m_vram(*this, "vram"),
		m_fontram(*this, "fram"),
		m_dma1(*this, "dma1"),
		m_dma2(*this, "dma2"),
		m_pic1(*this, "pic_master"),
		m_pic2(*this, "pic_slave"),
		m_rtc(*this, "rtc"),
		m_fdc(*this, "fdc"),
		m_floppy0(*this, "fdc:0"),
		m_floppy1(*this, "fdc:1"),
		m_kb_uart(*this, "keyboard"),
		m_pit(*this, "pit"),
		m_ppi(*this, "ppi"),
		m_speaker(*this, "speaker"),
		m_serial(*this, "serial"),
		m_parallel(*this, "parallel"),
		m_z80_bankdev(*this, "z80_bank"),
		m_ram(*this, "ram"),
		m_dswa(*this, "DSWA"),
		m_current_dma(-1),
		m_speaker_active(false),
		m_beep_active(false),
		m_z80_active(false)
	{ }

	void octopus(machine_config &config);

private:
	virtual void machine_reset() override;
	virtual void machine_start() override;
	virtual void video_start() override;
	SCN2674_DRAW_CHARACTER_MEMBER(display_pixels);
	DECLARE_READ8_MEMBER(vram_r);
	DECLARE_WRITE8_MEMBER(vram_w);
	DECLARE_READ8_MEMBER(get_slave_ack);
	DECLARE_WRITE_LINE_MEMBER(fdc_drq);
	DECLARE_READ8_MEMBER(bank_sel_r);
	DECLARE_WRITE8_MEMBER(bank_sel_w);
	DECLARE_READ8_MEMBER(dma_read);
	DECLARE_WRITE8_MEMBER(dma_write);
	DECLARE_WRITE_LINE_MEMBER(dma_hrq_changed);
	DECLARE_READ8_MEMBER(system_r);
	DECLARE_WRITE8_MEMBER(system_w);
	DECLARE_READ8_MEMBER(cntl_r);
	DECLARE_WRITE8_MEMBER(cntl_w);
	DECLARE_READ8_MEMBER(gpo_r);
	DECLARE_WRITE8_MEMBER(gpo_w);
	DECLARE_READ8_MEMBER(vidcontrol_r);
	DECLARE_WRITE8_MEMBER(vidcontrol_w);
	DECLARE_READ8_MEMBER(z80_io_r);
	DECLARE_WRITE8_MEMBER(z80_io_w);
	IRQ_CALLBACK_MEMBER(x86_irq_cb);
	DECLARE_READ8_MEMBER(rtc_r);
	DECLARE_WRITE8_MEMBER(rtc_w);
	DECLARE_READ8_MEMBER(z80_vector_r);
	DECLARE_WRITE8_MEMBER(z80_vector_w);
	DECLARE_READ8_MEMBER(parallel_r);
	DECLARE_WRITE8_MEMBER(parallel_w);
	DECLARE_READ8_MEMBER(video_latch_r);
	DECLARE_WRITE8_MEMBER(video_latch_w);

	DECLARE_WRITE_LINE_MEMBER(spk_w);
	DECLARE_WRITE_LINE_MEMBER(spk_freq_w);
	DECLARE_WRITE_LINE_MEMBER(beep_w);
	DECLARE_WRITE_LINE_MEMBER(serial_clock_w);
	DECLARE_WRITE_LINE_MEMBER(parallel_busy_w) { m_printer_busy = state; }
	DECLARE_WRITE_LINE_MEMBER(parallel_slctout_w) { m_printer_slctout = state; }

	DECLARE_WRITE_LINE_MEMBER(dack0_w) { m_dma1->hack_w(state ? 0 : 1); }  // for all unused DMA channel?
	DECLARE_WRITE_LINE_MEMBER(dack1_w) { if(!state) m_current_dma = 1; else if(m_current_dma == 1) m_current_dma = -1; }  // HD
	DECLARE_WRITE_LINE_MEMBER(dack2_w) { if(!state) m_current_dma = 2; else if(m_current_dma == 2) m_current_dma = -1; }  // RAM refresh
	DECLARE_WRITE_LINE_MEMBER(dack3_w) { m_dma1->hack_w(state ? 0 : 1); }
	DECLARE_WRITE_LINE_MEMBER(dack4_w) { m_dma1->hack_w(state ? 0 : 1); }
	DECLARE_WRITE_LINE_MEMBER(dack5_w) { if(!state) m_current_dma = 5; else if(m_current_dma == 5) m_current_dma = -1; }  // Floppy
	DECLARE_WRITE_LINE_MEMBER(dack6_w) { m_dma1->hack_w(state ? 0 : 1); }
	DECLARE_WRITE_LINE_MEMBER(dack7_w) { m_dma1->hack_w(state ? 0 : 1); }

	enum
	{
		BEEP_TIMER = 100
	};

	void octopus_io(address_map &map);
	void octopus_mem(address_map &map);
	void octopus_sub_io(address_map &map);
	void octopus_sub_mem(address_map &map);
	void octopus_vram(address_map &map);

	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

	required_device<cpu_device> m_maincpu;
	required_device<cpu_device> m_subcpu;
	required_device<scn2674_device> m_crtc;
	required_shared_ptr<uint8_t> m_vram;
	required_shared_ptr<uint8_t> m_fontram;
	required_device<am9517a_device> m_dma1;
	required_device<am9517a_device> m_dma2;
	required_device<pic8259_device> m_pic1;
	required_device<pic8259_device> m_pic2;
	required_device<mc146818_device> m_rtc;
	required_device<fd1793_device> m_fdc;
	required_device<floppy_connector> m_floppy0;
	required_device<floppy_connector> m_floppy1;
	required_device<i8251_device> m_kb_uart;
	required_device<pit8253_device> m_pit;
	required_device<i8255_device> m_ppi;
	required_device<speaker_sound_device> m_speaker;
	required_device<z80sio_device> m_serial;
	required_device<centronics_device> m_parallel;
	required_device<address_map_bank_device> m_z80_bankdev;
	required_device<ram_device> m_ram;
	required_ioport m_dswa;

	uint8_t m_hd_bank;  // HD bank select
	uint8_t m_fd_bank;  // Floppy bank select
	uint8_t m_z80_bank; // Z80 bank / RAM refresh
	int8_t m_current_dma;  // current DMA channel (-1 for none)
	uint8_t m_current_drive;
	uint8_t m_cntl;  // RTC / FDC control (PPI port B)
	uint8_t m_gpo;  // General purpose outputs (PPI port C)
	uint8_t m_vidctrl;
	bool m_speaker_active;
	bool m_beep_active;
	bool m_speaker_level;
	bool m_z80_active;
	bool m_rtc_address;
	bool m_rtc_data;
	uint8_t m_prev_cntl;
	uint8_t m_rs232_vector;
	uint8_t m_rs422_vector;
	bool m_printer_busy;
	bool m_printer_slctout;
	uint8_t m_char_latch_r;
	uint8_t m_attr_latch_r;
	uint8_t m_char_latch_w;
	uint8_t m_attr_latch_w;

	emu_timer* m_timer_beep;
};


void octopus_state::octopus_mem(address_map &map)
{
	map(0x00000, 0xcffff).bankrw("main_ram_bank");
	map(0xd0000, 0xdffff).ram().share("vram");
	map(0xe0000, 0xe3fff).noprw();
	map(0xe4000, 0xe5fff).ram().share("fram");
	map(0xe6000, 0xe7fff).rom().region("chargen", 0);
	map(0xe8000, 0xfbfff).noprw();
	map(0xfc000, 0xfffff).rom().region("user1", 0);
}

void octopus_state::octopus_io(address_map &map)
{
	map.unmap_value_high();
	map(0x00, 0x0f).rw(m_dma1, FUNC(am9517a_device::read), FUNC(am9517a_device::write));
	map(0x10, 0x1f).rw(m_dma2, FUNC(am9517a_device::read), FUNC(am9517a_device::write));
	map(0x20, 0x20).portr("DSWA");
	map(0x21, 0x2f).rw(FUNC(octopus_state::system_r), FUNC(octopus_state::system_w));
	map(0x31, 0x33).rw(FUNC(octopus_state::bank_sel_r), FUNC(octopus_state::bank_sel_w));
	map(0x50, 0x51).rw(m_kb_uart, FUNC(i8251_device::read), FUNC(i8251_device::write));
	// 0x70-73: HD controller
	map(0x80, 0x83).rw(m_pit, FUNC(pit8253_device::read), FUNC(pit8253_device::write));
	map(0xa0, 0xa0).rw(m_serial, FUNC(z80sio_device::da_r), FUNC(z80sio_device::da_w));
	map(0xa1, 0xa1).rw(m_serial, FUNC(z80sio_device::ca_r), FUNC(z80sio_device::ca_w));
	map(0xa2, 0xa2).rw(m_serial, FUNC(z80sio_device::db_r), FUNC(z80sio_device::db_w));
	map(0xa3, 0xa3).rw(m_serial, FUNC(z80sio_device::cb_r), FUNC(z80sio_device::cb_w));
	map(0xb0, 0xb1).rw(m_pic1, FUNC(pic8259_device::read), FUNC(pic8259_device::write));
	map(0xb4, 0xb5).rw(m_pic2, FUNC(pic8259_device::read), FUNC(pic8259_device::write));
	map(0xc0, 0xc7).rw(m_crtc, FUNC(scn2674_device::read), FUNC(scn2674_device::write));
	map(0xc8, 0xc8).rw(FUNC(octopus_state::vidcontrol_r), FUNC(octopus_state::vidcontrol_w));
	map(0xc9, 0xca).rw(FUNC(octopus_state::video_latch_r), FUNC(octopus_state::video_latch_w));
	// 0xcf: mode control
	map(0xd0, 0xd3).rw(m_fdc, FUNC(fd1793_device::read), FUNC(fd1793_device::write));
	map(0xe0, 0xe4).rw(FUNC(octopus_state::z80_vector_r), FUNC(octopus_state::z80_vector_w));
	map(0xf0, 0xf1).rw(FUNC(octopus_state::parallel_r), FUNC(octopus_state::parallel_w));
	map(0xf8, 0xff).rw(m_ppi, FUNC(i8255_device::read), FUNC(i8255_device::write));
}


void octopus_state::octopus_sub_mem(address_map &map)
{
	map(0x0000, 0xffff).rw(m_z80_bankdev, FUNC(address_map_bank_device::read8), FUNC(address_map_bank_device::write8));
}

void octopus_state::octopus_sub_io(address_map &map)
{
	map.unmap_value_high();
	map(0x0000, 0xffff).rw(FUNC(octopus_state::z80_io_r), FUNC(octopus_state::z80_io_w));
}

void octopus_state::octopus_vram(address_map &map)
{
	map(0x0000, 0xffff).rw(FUNC(octopus_state::vram_r), FUNC(octopus_state::vram_w));
}

/* Input ports */
static INPUT_PORTS_START( octopus )
	PORT_START("DSWA")
	PORT_DIPNAME( 0x03, 0x02, "Number of floppy drives" ) PORT_DIPLOCATION("SWA:1,2")
	PORT_DIPSETTING( 0x00, "None" )
	PORT_DIPSETTING( 0x01, "1 Floppy" )
	PORT_DIPSETTING( 0x02, "2 Floppies" )
	PORT_DIPSETTING( 0x03, "Not used" )
	PORT_DIPNAME( 0x04, 0x00, "Quad drives" ) PORT_DIPLOCATION("SWA:3")
	PORT_DIPSETTING( 0x00, "Disabled" )
	PORT_DIPSETTING( 0x04, "Enabled" )
	PORT_DIPNAME( 0x38, 0x00, "Winchester drive type" ) PORT_DIPLOCATION("SWA:4,5,6")
	PORT_DIPSETTING( 0x00, "None" )
	PORT_DIPSETTING( 0x08, "RO201" )
	PORT_DIPSETTING( 0x10, "RO202" )
	PORT_DIPSETTING( 0x18, "Reserved" )
	PORT_DIPSETTING( 0x20, "RO204" )
	PORT_DIPSETTING( 0x28, "Reserved" )
	PORT_DIPSETTING( 0x30, "RO208" )
	PORT_DIPSETTING( 0x38, "Reserved" )
	PORT_DIPNAME( 0x40, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("SWA:7")
	PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
	PORT_DIPSETTING( 0x40, DEF_STR( On ) )
	PORT_DIPNAME( 0x80, 0x80, "Colour monitor connected" ) PORT_DIPLOCATION("SWA:8")
	PORT_DIPSETTING( 0x00, DEF_STR( No ) )
	PORT_DIPSETTING( 0x80, DEF_STR( Yes ) )
INPUT_PORTS_END

void octopus_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch(id)
	{
	case BEEP_TIMER:  // switch off speaker
		m_beep_active = false;
		break;
	}
}

WRITE8_MEMBER(octopus_state::vram_w)
{
	m_vram[offset] = m_char_latch_w;
	m_vram[offset+0x1000] = m_attr_latch_w;
}

READ8_MEMBER(octopus_state::vram_r)
{
	m_char_latch_r = m_vram[offset];
	m_attr_latch_r = m_vram[offset+0x1000];
	return m_vram[offset];
}

WRITE_LINE_MEMBER(octopus_state::fdc_drq)
{
	// TODO
}

READ8_MEMBER(octopus_state::bank_sel_r)
{
	switch(offset)
	{
	case 0:
		return m_hd_bank;
	case 1:
		return m_fd_bank;
	case 2:
		return m_z80_bank;
	}
	return 0xff;
}

WRITE8_MEMBER(octopus_state::bank_sel_w)
{
	switch(offset)
	{
	case 0:
		m_hd_bank = data;
		logerror("HD bank = %i\n",data);
		break;
	case 1:
		m_fd_bank = data;
		logerror("Floppy bank = %i\n",data);
		break;
	case 2:
		m_z80_bank = data;
		m_z80_bankdev->set_bank(m_z80_bank & 0x0f);
		logerror("Z80/RAM bank = %i\n",data);
		break;
	}
}

// System control
// 0x20: read: System type, write: Z80 NMI
// 0x21: read: bit5=SLCTOUT from parallel interface, bit6=option board parity fail, bit7=main board parity fail
//       write: parity fail reset
// ports 0x20 and 0x21 read out the DIP switch configuration (the firmware function to get system config simply does IN AX,20h)
// 0x28: write: Z80 enable
WRITE8_MEMBER(octopus_state::system_w)
{
	logerror("SYS: System control offset %i data %02x\n",offset+1,data);
	switch(offset)
	{
	case 7:  // enable Z80, halt 8088
		m_subcpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
		m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
		m_z80_active = true;
		break;
	}
}

READ8_MEMBER(octopus_state::system_r)
{
	uint8_t val = 0x00;
	switch(offset)
	{
	case 0:
		val = 0x1f;
		if(m_printer_slctout)
			val |= 0x20;
		return val;  // do bits 0-4 mean anything?  Language DIPs?
	}

	return 0xff;
}

// Any I/O cycle relinquishes control of the bus
READ8_MEMBER(octopus_state::z80_io_r)
{
	z80_io_w(space,offset,0);
	return 0x00;
}

WRITE8_MEMBER(octopus_state::z80_io_w)
{
	m_subcpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
	m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
	m_z80_active = false;
}

// Z80 vector for RS232 and RS422
READ8_MEMBER(octopus_state::z80_vector_r)
{
	switch(offset)
	{
		case 0:
			return m_rs232_vector;
		case 4:
			return m_rs422_vector;
		default:
			return 0xff;
	}
	return 0xff;
}

WRITE8_MEMBER(octopus_state::z80_vector_w)
{
	switch(offset)
	{
		case 0:
			m_rs232_vector = data;
			logerror("RS232 vector set to %02x\n",data);
			break;
		case 4:
			m_rs422_vector = data;
			logerror("RS422 vector set to %02x\n",data);
			break;
		default:
			logerror("Read invalid vector port 0x%02x\n",0xe0 + offset);
	}
}

// RTC data and I/O - PPI port A
// bits 0-3 of RTC/FDC control go to control lines of the MC146818
// The technical manual does not mention what is connected to each bit
// This is an educated guess, based on the BIOS code
// bit 0 = ? (Pulsed low after writing to an RTC register)
// bit 1 = PPI Port A strobe?
// bit 2 = Data strobe?
// bit 3 = Address strobe?
READ8_MEMBER(octopus_state::rtc_r)
{
	uint8_t ret = 0xff;

	if(m_rtc_data)
		ret = m_rtc->read(1);
	else if(m_rtc_address)
		ret = m_rtc->read(0);

	return ret;
}

WRITE8_MEMBER(octopus_state::rtc_w)
{
	if(m_rtc_data)
		m_rtc->write(1,data);
	else if(m_rtc_address)
		m_rtc->write(0,data);
}

// RTC/FDC control - PPI port B
// bits0-3: RTC control lines
// bit4-5: write precomp.
// bit6-7: drive select
READ8_MEMBER(octopus_state::cntl_r)
{
	return m_cntl;
}

WRITE8_MEMBER(octopus_state::cntl_w)
{
	m_cntl = data;

	if((m_cntl & 0x08) && !(m_prev_cntl & 0x08))
	{
		m_rtc_address = true;
		m_rtc_data = false;
	}
	if((data & 0x04) && !(m_prev_cntl & 0x04))
	{
		m_rtc_address = false;
		m_rtc_data = true;
	}
	m_ppi->pc4_w(data & 0x02);
	m_prev_cntl = m_cntl;
	m_current_drive = (data & 0xc0) >> 6;
	switch(m_current_drive)
	{
	case 1:
		m_fdc->set_floppy(m_floppy0->get_device());
		m_floppy0->get_device()->mon_w(0);
		break;
	case 2:
		m_fdc->set_floppy(m_floppy1->get_device());
		m_floppy1->get_device()->mon_w(0);
		break;
	}
	logerror("Selected floppy drive %i (%02x)\n",m_current_drive,data);
}

// General Purpose Outputs - PPI port C
// bit 2 - floppy side select
// bit 1 - parallel data I/O (0 = output)
// bit 0 - parallel control I/O (0 = output)
READ8_MEMBER(octopus_state::gpo_r)
{
	return m_gpo;
}

WRITE8_MEMBER(octopus_state::gpo_w)
{
	m_gpo = data;
	switch(m_current_drive)
	{
	case 1:
		m_floppy0->get_device()->ss_w((data & 0x04) >> 2);
		break;
	case 2:
		m_floppy1->get_device()->ss_w((data & 0x04) >> 2);
		break;
	default:
		logerror("Attempted to set side on unknown drive %i\n",m_current_drive);
	}
}

// Video control register
// bit 0 - video dot clock - 0=17.6MHz, 1=16MHz
// bit 2 - floppy DDEN line
// bit 3 - floppy FCLOCK line - 0=1MHz, 1=2MHz
// bits 4-5 - character width - 0=10 dots, 1=6 dots, 2=8 dots, 3=9 dots
// bit 6 - cursor mode (colour only) - 0=inverse cursor, 1=white cursor (normal)
// bit 7 - 1=monochrome mode, 0=colour mode
// Is bit 7 writable, or just mirrors DIP switch setting?  Tech manual is unclear.
READ8_MEMBER(octopus_state::vidcontrol_r)
{
	return m_vidctrl;
}

WRITE8_MEMBER(octopus_state::vidcontrol_w)
{
	m_fdc->dden_w(BIT(data, 2));
	m_fdc->set_unscaled_clock(16_MHz_XTAL / (BIT(data, 3) ? 16 : 8));

	if (((m_vidctrl ^ data) & 0x31) != 0)
	{
		unsigned dots = 4 + ((data & 0x30) >> 3);
		if ((data & 0x30) == 0)
			dots = 10;
		else if ((data & 0x30) == 0x30)
			dots = 9;

		auto dotclk = BIT(data, 0) ? 16_MHz_XTAL : 17.6_MHz_XTAL;

		m_crtc->set_character_width(dots);
		m_crtc->set_unscaled_clock(dotclk / dots);
	}

	m_vidctrl = data;
}

// Sound hardware
// Sound level provided by i8253 timer 2
// Enabled by /DTR signal from i8251
// 100ms beep triggered by pulsing /CTS signal low on i8251
WRITE_LINE_MEMBER(octopus_state::spk_w)
{
	m_speaker_active = !state;
	m_speaker->level_w(((m_speaker_active || m_beep_active) && m_speaker_level) ? 1 : 0);
}

WRITE_LINE_MEMBER(octopus_state::spk_freq_w)
{
	m_speaker_level = state;
	m_speaker->level_w(((m_speaker_active || m_beep_active) && m_speaker_level) ? 1 : 0);
}

WRITE_LINE_MEMBER(octopus_state::beep_w)
{
	if(!state)  // active low
	{
		m_beep_active = true;
		m_speaker->level_w(((m_speaker_active || m_beep_active) && m_speaker_level) ? 1 : 0);
		m_timer_beep->adjust(attotime::from_msec(100));
	}
}

WRITE_LINE_MEMBER(octopus_state::serial_clock_w)
{
	m_serial->rxca_w(state);
	m_serial->txca_w(state);
}

// Parallel Centronics port
// 0xf0 : data
// 0xf1 : control
//      bit 2 = INIT?  On boot, bits 0 and 1 are set high, bit 2 is set low then high again, all other bits are set low
// can generate interrupts - tech manual suggests that Strobe, Init, Ack, and Busy can trigger an interrupt (IRQ14)
READ8_MEMBER(octopus_state::parallel_r)
{
	switch(offset)
	{
	case 0:
		return 0;
	case 1:
		return m_printer_busy ? 0x01 : 0x00;  // correct?  Tech manual doesn't explain which bit is which
	}
	return 0xff;
}

WRITE8_MEMBER(octopus_state::parallel_w)
{
	switch(offset)
	{
	case 0:  // data
		if(!(m_gpo & 0x02))  // parallel data direction
		{
			m_parallel->write_data0(BIT(data,0));
			m_parallel->write_data1(BIT(data,1));
			m_parallel->write_data2(BIT(data,2));
			m_parallel->write_data3(BIT(data,3));
			m_parallel->write_data4(BIT(data,4));
			m_parallel->write_data5(BIT(data,5));
			m_parallel->write_data6(BIT(data,6));
			m_parallel->write_data7(BIT(data,7));
		}
		break;
	case 1:  // control (bit order unknown?)
		if(!(m_gpo & 0x01))  // parallel control direction
		{
			m_parallel->write_init(BIT(data,2));
			m_pic2->ir6_w(!BIT(data,2));
		}
		break;
	}
}

READ8_MEMBER(octopus_state::dma_read)
{
	uint8_t byte;
	address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
	if(m_current_dma == -1)
		return 0;
	byte = prog_space.read_byte((m_fd_bank << 16) + offset);
	return byte;
}

WRITE8_MEMBER(octopus_state::dma_write)
{
	address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
	if(m_current_dma == -1)
		return;
	prog_space.write_byte((m_fd_bank << 16) + offset, data);
}

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

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

// Any interrupt will also give bus control back to the 8088
IRQ_CALLBACK_MEMBER(octopus_state::x86_irq_cb)
{
	uint8_t vector;
	m_subcpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
	m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
	m_z80_active = false;
	vector = m_pic1->inta_cb(device,irqline);
	if(vector == 0x61)  // if we have hit a serial comms IRQ, then also have the Z80SIO/2 acknowledge the interrupt
		vector = m_serial->m1_r();
	return vector;
}

void octopus_state::machine_start()
{
	m_timer_beep = timer_alloc(BEEP_TIMER);
	m_vidctrl = 0xff;

	// install RAM
	m_maincpu->space(AS_PROGRAM).install_readwrite_bank(0x0000,m_ram->size()-1,"main_ram_bank");
	m_maincpu->space(AS_PROGRAM).nop_readwrite(m_ram->size(),0xcffff);
}

void octopus_state::machine_reset()
{
	m_subcpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);  // halt Z80 to start with
	m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
	m_z80_active = false;
	m_current_dma = -1;
	m_current_drive = 0;
	m_rtc_address = true;
	m_rtc_data = false;
	membank("main_ram_bank")->set_base(m_ram->pointer());
	m_kb_uart->write_dsr(1);  // DSR is used to determine if a keyboard is connected?  If DSR is high, then the CHAR_OUT BIOS function will not output to the screen.
}

void octopus_state::video_start()
{
	m_vram.allocate(0x10000);
}

READ8_MEMBER(octopus_state::video_latch_r)
{
	if(offset & 0x01)
		return m_attr_latch_r;
	else
		return m_char_latch_r;
}

WRITE8_MEMBER(octopus_state::video_latch_w)
{
	if(offset & 0x01)
		m_attr_latch_w = data;
	else
		m_char_latch_w = data;
}

SCN2674_DRAW_CHARACTER_MEMBER(octopus_state::display_pixels)
{
	// Attributes:
	//  - common bits
	// b7 : blink
	// b3 : underline
	//  - Monochrome
	// b6 : GP1 (general purpose)
	// b5 : reverse video
	// b4 : GP2 (general purpose)
	// b2 : High intensity
	// b1 : Grey background
	// b0 : Blank (TODO)
	//  - Colour
	// b6,5,4 : background colour (RGB)
	// b2,1,0 : foreground colour (RGB)
	if(!lg)
	{
		uint8_t tile = m_vram[address & 0x0fff];
		uint8_t attr = m_vram[(address & 0x0fff) + 0x1000];
		uint8_t data = m_fontram[(tile * 16) + linecount];
		rgb_t fg,bg;
		if(m_dswa->read() & 0x80)  // monochrome or colour mode is selected by switch 8 of system DIP switches
		{
			// colour (is the background at half intensity?)
			bg.set_r((attr & 0x40) ? 0x7f : 0x00);
			bg.set_g((attr & 0x20) ? 0x7f : 0x00);
			bg.set_b((attr & 0x10) ? 0x7f : 0x00);
			fg.set_r((attr & 0x04) ? 0xff : 0x00);
			fg.set_g((attr & 0x02) ? 0xff : 0x00);
			fg.set_b((attr & 0x01) ? 0xff : 0x00);
		}
		else
		{
			// monochrome
			if(attr & 0x02)
				fg = 0xffffff;
			else
				fg = 0x7f7f7f;
			if(attr & 0x04)
				bg = 0x7f7f7f;
			else
				bg = 0x000000;

			if(attr & 0x20)  // reverse video
				data = ~data;
		}
		if(ul && (attr & 0x08))
			data = 0xff;
		if(blink && (attr & 0x80))
			data = 0x00;
		if(cursor && !blink)
		{
			bool inverse = true;

			if(!(m_dswa->read() & 0x80))  // not available in monochrome mode
				inverse = false;
			if(m_vidctrl & 0x40)  // not enabled
				inverse = false;
			if(inverse)
				data = ~data;
			else
				data = 0xff;
		}
		for (int z=0;z<8;z++)
			bitmap.pix32(y,x + z) = BIT(data,z) ? fg : bg;
	}
}

READ8_MEMBER( octopus_state::get_slave_ack )
{
	if (offset==7)
		return m_pic2->acknowledge();

	return 0x00;
}

static void octopus_floppies(device_slot_interface &device)
{
	device.option_add("525dd", FLOPPY_525_DD);
}

static void keyboard(device_slot_interface &device)
{
	device.option_add("octopus", OCTOPUS_KEYBOARD);
}

void octopus_centronics_devices(device_slot_interface &device)
{
	device.option_add("pl80", COMX_PL80);
	device.option_add("ex800", EPSON_EX800);
	device.option_add("lx800", EPSON_LX800);
	device.option_add("lx810l", EPSON_LX810L);
	device.option_add("ap2000", EPSON_AP2000);
	device.option_add("printer", CENTRONICS_PRINTER);
}

void octopus_state::octopus(machine_config &config)
{
	/* basic machine hardware */
	I8088(config, m_maincpu, 24_MHz_XTAL / 3);  // 8MHz
	m_maincpu->set_addrmap(AS_PROGRAM, &octopus_state::octopus_mem);
	m_maincpu->set_addrmap(AS_IO, &octopus_state::octopus_io);
	m_maincpu->set_irq_acknowledge_callback(FUNC(octopus_state::x86_irq_cb));

	Z80(config, m_subcpu, 24_MHz_XTAL / 4); // 6MHz
	m_subcpu->set_addrmap(AS_PROGRAM, &octopus_state::octopus_sub_mem);
	m_subcpu->set_addrmap(AS_IO, &octopus_state::octopus_sub_io);

	AM9517A(config, m_dma1, 24_MHz_XTAL / 6);  // 4MHz
	m_dma1->out_hreq_callback().set(m_dma2, FUNC(am9517a_device::dreq0_w));
	m_dma1->in_memr_callback().set(FUNC(octopus_state::dma_read));
	m_dma1->out_memw_callback().set(FUNC(octopus_state::dma_write));
	//m_dma1->in_ior_callback<0>().set_nop();
	//m_dma1->in_ior_callback<1>().set_nop();  // HDC
	//m_dma1->in_ior_callback<2>().set_nop();  // RAM Refresh
	//m_dma1->in_ior_callback<3>().set_nop();
	//m_dma1->out_iow_callback<0>().set_nop();
	//m_dma1->out_iow_callback<1>().set_nop();  // HDC
	//m_dma1->out_iow_callback<2>().set_nop();  // RAM Refresh
	//m_dma1->out_iow_callback<3>().set_nop();
	m_dma1->out_dack_callback<0>().set(FUNC(octopus_state::dack0_w));
	m_dma1->out_dack_callback<1>().set(FUNC(octopus_state::dack1_w));
	m_dma1->out_dack_callback<2>().set(FUNC(octopus_state::dack2_w));
	m_dma1->out_dack_callback<3>().set(FUNC(octopus_state::dack3_w));

	AM9517A(config, m_dma2, 24_MHz_XTAL / 6);  // 4MHz
	m_dma2->out_hreq_callback().set(FUNC(octopus_state::dma_hrq_changed));
	m_dma2->in_memr_callback().set(FUNC(octopus_state::dma_read));
	m_dma2->out_memw_callback().set(FUNC(octopus_state::dma_write));
	//m_dma2->in_ior_callback<0>().set_nop();
	m_dma2->in_ior_callback<1>().set(m_fdc, FUNC(fd1793_device::data_r));  // FDC
	//m_dma2->in_ior_callback<2>().set_nop();
	//m_dma2->in_ior_callback<3>().set_nop();
	//m_dma2->out_iow_callback<0>().set_nop();
	m_dma2->out_iow_callback<1>().set(m_fdc, FUNC(fd1793_device::data_w));  // FDC
	//m_dma2->out_iow_callback<2>().set_nop();
	//m_dma2->out_iow_callback<3>().set_nop();
	m_dma2->out_dack_callback<0>().set(FUNC(octopus_state::dack4_w));
	m_dma2->out_dack_callback<1>().set(FUNC(octopus_state::dack5_w));
	m_dma2->out_dack_callback<2>().set(FUNC(octopus_state::dack6_w));
	m_dma2->out_dack_callback<3>().set(FUNC(octopus_state::dack7_w));

	PIC8259(config, m_pic1, 0);
	m_pic1->out_int_callback().set_inputline(m_maincpu, 0);
	m_pic1->in_sp_callback().set_constant(1);
	m_pic1->read_slave_ack_callback().set(FUNC(octopus_state::get_slave_ack));

	PIC8259(config, m_pic2, 0);
	m_pic2->out_int_callback().set(m_pic1, FUNC(pic8259_device::ir7_w));
	m_pic2->in_sp_callback().set_constant(0);

	// RTC (MC146818 via i8255 PPI)
	I8255(config, m_ppi, 0);
	m_ppi->in_pa_callback().set(FUNC(octopus_state::rtc_r));
	m_ppi->in_pb_callback().set(FUNC(octopus_state::cntl_r));
	m_ppi->in_pc_callback().set(FUNC(octopus_state::gpo_r));
	m_ppi->out_pa_callback().set(FUNC(octopus_state::rtc_w));
	m_ppi->out_pb_callback().set(FUNC(octopus_state::cntl_w));
	m_ppi->out_pc_callback().set(FUNC(octopus_state::gpo_w));

	MC146818(config, m_rtc, 32.768_kHz_XTAL);
	m_rtc->irq().set(m_pic2, FUNC(pic8259_device::ir2_w));

	// Keyboard UART
	I8251(config, m_kb_uart, 0);
	m_kb_uart->rxrdy_handler().set("pic_slave", FUNC(pic8259_device::ir4_w));
	m_kb_uart->dtr_handler().set(FUNC(octopus_state::spk_w));
	m_kb_uart->rts_handler().set(FUNC(octopus_state::beep_w));
	rs232_port_device &keyboard_port(RS232_PORT(config, "keyboard_port", keyboard, "octopus"));
	keyboard_port.rxd_handler().set(m_kb_uart, FUNC(i8251_device::write_rxd));
	clock_device &keyboard_clock_rx(CLOCK(config, "keyboard_clock_rx", 9600 * 64));
	keyboard_clock_rx.signal_handler().set(m_kb_uart, FUNC(i8251_device::write_rxc));
	clock_device &keyboard_clock_tx(CLOCK(config, "keyboard_clock_tx", 1200 * 64));
	keyboard_clock_tx.signal_handler().set(m_kb_uart, FUNC(i8251_device::write_txc));

	FD1793(config, m_fdc, 16_MHz_XTAL / 8);
	m_fdc->intrq_wr_callback().set(m_pic1, FUNC(pic8259_device::ir5_w));
	m_fdc->drq_wr_callback().set(m_dma2, FUNC(am9517a_device::dreq1_w));
	FLOPPY_CONNECTOR(config, "fdc:0", octopus_floppies, "525dd", floppy_image_device::default_floppy_formats);
	FLOPPY_CONNECTOR(config, "fdc:1", octopus_floppies, "525dd", floppy_image_device::default_floppy_formats);
	SOFTWARE_LIST(config, "fd_list").set_original("octopus");

	PIT8253(config, m_pit, 0);
	m_pit->set_clk<0>(4.9152_MHz_XTAL / 2);  // DART channel A
	m_pit->out_handler<0>().set(FUNC(octopus_state::serial_clock_w));  // being able to write both Rx and Tx clocks at one time would be nice
	m_pit->set_clk<1>(4.9152_MHz_XTAL / 2);  // DART channel B
	m_pit->out_handler<1>().set(m_serial, FUNC(z80sio_device::rxtxcb_w));
	m_pit->set_clk<2>(4.9152_MHz_XTAL / 2);  // speaker frequency
	m_pit->out_handler<2>().set(FUNC(octopus_state::spk_freq_w));

	SPEAKER(config, "mono").front_center();
	SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);

	Z80SIO(config, m_serial, 16_MHz_XTAL / 4); // clock rate not mentioned in tech manual
	m_serial->out_int_callback().set(m_pic1, FUNC(pic8259_device::ir1_w));
	m_serial->out_txda_callback().set("serial_a", FUNC(rs232_port_device::write_txd));
	m_serial->out_txdb_callback().set("serial_b", FUNC(rs232_port_device::write_txd));
	m_serial->out_rtsa_callback().set("serial_a", FUNC(rs232_port_device::write_rts));
	m_serial->out_rtsb_callback().set("serial_b", FUNC(rs232_port_device::write_rts));

	rs232_port_device &serial_a(RS232_PORT(config, "serial_a", default_rs232_devices, nullptr));
	serial_a.rxd_handler().set(m_serial, FUNC(z80sio_device::rxa_w));
	serial_a.cts_handler().set(m_serial, FUNC(z80sio_device::ctsa_w)).invert();
	//serial_a.ri_handler().set(m_serial, FUNC(z80sio_device::ria_w)).invert();
	rs232_port_device &serial_b(RS232_PORT(config, "serial_b", default_rs232_devices, nullptr));
	serial_b.rxd_handler().set(m_serial, FUNC(z80sio_device::rxb_w));
	serial_b.cts_handler().set(m_serial, FUNC(z80sio_device::ctsb_w)).invert();
	//serial_b.ri_handler().set(m_serial, FUNC(z80sio_device::rib_w)).invert();

	CENTRONICS(config, m_parallel, octopus_centronics_devices, "printer");
	m_parallel->busy_handler().set(FUNC(octopus_state::parallel_busy_w));
	m_parallel->select_handler().set(FUNC(octopus_state::parallel_slctout_w));
	// TODO: Winchester HD controller (Xebec/SASI compatible? uses TTL logic)

	/* video hardware */
	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
	screen.set_raw(16_MHz_XTAL, 918, 0, 729, 350, 0, 325);
	//screen.set_raw(17.6_MHz_XTAL, 1008, 0, 792, 348, 0, 319);
	screen.set_screen_update("crtc", FUNC(scn2674_device::screen_update));

	SCN2674(config, m_crtc, 16_MHz_XTAL / 9); // dot clock and character width are both selectable
	m_crtc->intr_callback().set("pic_slave", FUNC(pic8259_device::ir0_w));
	m_crtc->set_character_width(9);
	m_crtc->set_display_callback(FUNC(octopus_state::display_pixels));
	m_crtc->set_addrmap(0, &octopus_state::octopus_vram);
	m_crtc->set_screen("screen");

	ADDRESS_MAP_BANK(config, "z80_bank").set_map(&octopus_state::octopus_mem).set_options(ENDIANNESS_LITTLE, 8, 32, 0x10000);

	RAM(config, "ram").set_default_size("256K").set_extra_options("128K,512K,768K");
}

/* ROM definition */
ROM_START( octopus )
	ROM_REGION( 0x4000, "user1", 0 )
	ROM_LOAD( "octopus_main_prom", 0x0000, 0x4000, CRC(b5b4518d) SHA1(41b8729c4c9074914fd4ea181c8b6d4805ee2b93) )

	// This rom was on the graphics card (yes, it has slots)
	ROM_REGION( 0x2000, "chargen", 0 )
	ROM_LOAD( "octopus_gfx_card",  0x0000, 0x2000, CRC(b2386534) SHA1(5e3c4682afb4eb222e48a7203269a16d26911836) )
ROM_END

/* Driver */

//    YEAR  NAME     PARENT  COMPAT  MACHINE  INPUT    CLASS          INIT        COMPANY                 FULLNAME       FLAGS
COMP( 1986, octopus, 0,      0,      octopus, octopus, octopus_state, empty_init, "Digital Microsystems", "LSI Octopus", MACHINE_NOT_WORKING)