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

                                                                            
                        








                                        
                         
                              
                         



                                                                        

                                                                            
                                                 



                                                            

                                                                   









                                                                          

                                                                           



                                                                           
             

                                    


                                                                             
                
                               
                            
                             
                        
                              
                              
                          

                           
                   


                    
 


                                         
                                                                                      






                                                   

         

                                             
                                                  
                                                   
                                                    
                                                                                                       
                                
                                                              
                                                      
 
                                                 
                                            

                                           

                           

                                                   

                                                   





                                            
                                                 
 
                                                           

 
                                                  
 
                                            

 











                                                     
                                                                                   
 




                                  
                                                                                                            
 
                                                                                                    

                                             

                     


                                
                                           
                 
                                                          


                                                      




                                                                          
                                 













































                                                                                                                                              
                                 






                         













                                                               
                                   


                                                                    
                                                 
 
                                                            
              
                               

                         
                                        
                  
                                                           

                                      
                                  
         

                                                                           
         
                                       
         

                                                                          
         
            
         
                                                
                                                                   
                                          
                 






                                                                                         


                    


                                                                        
                         

                                                                                                            


                            

                                                                           
 

                                                                                                          
 

                                                                              
 
                                                                 

                         

         
                      

 







                                                                           

                                                      
                            









                                                                             
                                                               
 

                                               
                      
                                 
                                                                                                        
                                                     














                                                                                                                                                          

                       
                                                                                                                                   
 






                                                                                                              

                                                                                                            
                             



            

                                                                                                                  






                                                                                                                    
                                                     
 

                    


                                                                   


                                                  







                                                      
                       
 
                                            























                                                    



                                                 

             
 


  
                                       

       
                                                                                     


                                                  
           

                                      



                                        
                              

                                                
 
                                           

                                         
 
        


                                    
                                              



                                             















                                                                                                 
                                                                                                              


                                                                                              
 
 
                                 



                                  
                                                    
                                                   


                     
                


  
                 
                                 

               
                                  

                           


                                     

 
                                    
 
                                   



                        













                                                   
                                                   




                                      
                                                   


                                  
















                                                    



                                               
                                    



                                                                         
 
                      

                                                                           
 
                     


                                                                          
 


                                                                          
                                                                                       

                                                              
 


                                                                                                        

                    
                  
                                           
                                                                                                                      


                                                                                                            


                                                         



            

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

        BINBUG and DG640

        2013-01-14 Driver created

        All input must be in uppercase.

        Commands:
        A - See and alter memory
        B - Set breakpoint (2 permitted)
        C - Clear breakpoint
        D - cassette save
        G - Go to address, run
        L - cassette load
        S - See and alter registers

        BINBUG is an alternate bios to PIPBUG, however it uses its own
        video output. Method of output is through a DG640 board (sold by
        Applied Technology) which uses a MCM6574 as a character generator.
        The DG640 also supports blinking, reverse-video, and LORES graphics.
        It is a S100 card, also known as ETI-640.

        Keyboard input, like PIPBUG, is via a serial device.
        The baud rate is 300, 8N1.

        The SENSE and FLAG lines are used for 300 baud cassette, in
        conjunction with unknown hardware.

        There are 3 versions of BINBUG:

        - 3.6 300 baud tape routines, 300 baud keyboard, memory-mapped VDU

        - 4.4 300 baud keyboard, ACOS tape system, advanced video routines

        - 5.2 ACOS tape system, 1200 baud terminal


        Status:
        - DG640 is completely emulated, even though BINBUG doesn't use most
          of its features.
        - BINBUG works except that the cassette interface isn't the same as
          real hardware. But you can save, and load it back.

        ToDo:
        - Need dumps of 4.4 and 5.2.
        - Fix cassette

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

#include "emu.h"
#include "bus/rs232/keyboard.h"
#include "cpu/s2650/s2650.h"
#include "machine/z80daisy.h"
#include "cpu/z80/z80.h"
#include "imagedev/cassette.h"
#include "imagedev/snapquik.h"
#include "machine/timer.h"
#include "machine/z80ctc.h"
#include "machine/z80pio.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"


class binbug_state : public driver_device
{
public:
	binbug_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag)
		, m_maincpu(*this, "maincpu")
		, m_cass(*this, "cassette")
		, m_p_videoram(*this, "videoram")
		, m_p_attribram(*this, "attribram")
		, m_p_chargen(*this, "chargen")
		, m_rs232(*this, "keyboard")
	{
	}

	DECLARE_WRITE8_MEMBER(binbug_ctrl_w);
	DECLARE_READ_LINE_MEMBER(binbug_serial_r);
	DECLARE_WRITE_LINE_MEMBER(binbug_serial_w);
	DECLARE_QUICKLOAD_LOAD_MEMBER(quickload_cb);
	uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
	// needed by dg680 class
	required_device<cpu_device> m_maincpu; // S2650 or Z80
	required_device<cassette_image_device> m_cass;

	void binbug_base(machine_config &config);
	void binbug(machine_config &config);
	void binbug_data(address_map &map);
	void binbug_mem(address_map &map);
private:
	uint8_t m_framecnt;
	required_shared_ptr<uint8_t> m_p_videoram;
	required_shared_ptr<uint8_t> m_p_attribram;
	required_region_ptr<u8> m_p_chargen;
	optional_device<rs232_port_device> m_rs232;
};

WRITE8_MEMBER( binbug_state::binbug_ctrl_w )
{
}

READ_LINE_MEMBER( binbug_state::binbug_serial_r )
{
	return m_rs232->rxd_r() & (m_cass->input() < 0.03);
}

WRITE_LINE_MEMBER( binbug_state::binbug_serial_w )
{
	m_cass->output(state ? -1.0 : +1.0);
}

void binbug_state::binbug_mem(address_map &map)
{
	map.unmap_value_high();
	map(0x0000, 0x03ff).rom();
	map(0x0400, 0x77ff).ram();
	map(0x7800, 0x7bff).ram().share("videoram");
	map(0x7c00, 0x7fff).ram().share("attribram");
}

void binbug_state::binbug_data(address_map &map)
{
	map.unmap_value_high();
	map(S2650_CTRL_PORT, S2650_CTRL_PORT).w(FUNC(binbug_state::binbug_ctrl_w));
}

/* Input ports */
static INPUT_PORTS_START( binbug )
INPUT_PORTS_END

uint32_t binbug_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// attributes bit 0 = flash, bit 1 = lores. Also bit 7 of the character = reverse-video (text only).
	uint8_t y,ra,chr,gfx,attr,inv,gfxbit;
	uint16_t sy=0,ma=0,x;
	bool flash;
	m_framecnt++;

	for (y = 0; y < 16; y++)
	{
		for (ra = 0; ra < 16; ra++)
		{
			uint16_t *p = &bitmap.pix16(sy++);

			for (x = ma; x < ma + 64; x++)
			{
				attr = m_p_attribram[x];
				chr = m_p_videoram[x];
				flash = BIT(m_framecnt, 4) & BIT(attr, 0);

				if (BIT(attr, 1)) // lores gfx - can flash
				{
					if (flash) chr = 0; // blank part of flashing

					gfxbit = (ra & 0x0c)>>1;
					/* Display one line of a lores character (8 pixels) */
					*p++ = BIT(chr, gfxbit);
					*p++ = BIT(chr, gfxbit);
					*p++ = BIT(chr, gfxbit);
					*p++ = BIT(chr, gfxbit);
					gfxbit++;
					*p++ = BIT(chr, gfxbit);
					*p++ = BIT(chr, gfxbit);
					*p++ = BIT(chr, gfxbit);
					*p++ = BIT(chr, gfxbit);
				}
				else
				{
					gfx = 0;

					if (!flash)
					{
						inv = BIT(chr, 7) ? 0xff : 0; // text with bit 7 high is reversed
						chr &= 0x7f;
						gfx = inv;

						// if g,j,p,q,y; lower the descender
						if ((chr==0x2c)||(chr==0x3b)||(chr==0x67)||(chr==0x6a)||(chr==0x70)||(chr==0x71)||(chr==0x79))
						{
							if (ra > 6)
								gfx = m_p_chargen[(chr<<4) | (ra-7) ] ^ inv;
						}
						else
						{
							if ((ra > 3) & (ra < 13))
								gfx = m_p_chargen[(chr<<4) | (ra-4) ] ^ inv;
						}
					}

					/* Display a scanline of a character */
					*p++ = BIT(gfx, 7);
					*p++ = BIT(gfx, 6);
					*p++ = BIT(gfx, 5);
					*p++ = BIT(gfx, 4);
					*p++ = BIT(gfx, 3);
					*p++ = BIT(gfx, 2);
					*p++ = BIT(gfx, 1);
					*p++ = BIT(gfx, 0);
				}
			}
		}
		ma+=64;
	}
	return 0;
}

/* F4 Character Displayer */
static const gfx_layout dg640_charlayout =
{
	7, 9,                   /* 7 x 9 characters */
	128,                  /* 128 characters */
	1,                  /* 1 bits per pixel */
	{ 0 },                  /* no bitplanes */
	/* x offsets */
	{ 0, 1, 2, 3, 4, 5, 6 },
	/* y offsets */
	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8 },
	8*16                    /* every char takes 16 bytes */
};

static GFXDECODE_START( gfx_dg640 )
	GFXDECODE_ENTRY( "chargen", 0x0000, dg640_charlayout, 0, 1 )
GFXDECODE_END

QUICKLOAD_LOAD_MEMBER(binbug_state::quickload_cb)
{
	address_space &space = m_maincpu->space(AS_PROGRAM);
	int i;
	int quick_addr = 0x440;
	int exec_addr;
	int quick_length;
	std::vector<uint8_t> quick_data;
	int read_;
	image_init_result result = image_init_result::FAIL;

	quick_length = image.length();
	if (quick_length < 0x0444)
	{
		image.seterror(IMAGE_ERROR_INVALIDIMAGE, "File too short");
		image.message(" File too short");
	}
	else if (quick_length > 0x8000)
	{
		image.seterror(IMAGE_ERROR_INVALIDIMAGE, "File too long");
		image.message(" File too long");
	}
	else
	{
		quick_data.resize(quick_length);
		read_ = image.fread( &quick_data[0], quick_length);
		if (read_ != quick_length)
		{
			image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Cannot read the file");
			image.message(" Cannot read the file");
		}
		else if (quick_data[0] != 0xc4)
		{
			image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Invalid header");
			image.message(" Invalid header");
		}
		else
		{
			exec_addr = quick_data[1] * 256 + quick_data[2];

			if (exec_addr >= quick_length)
			{
				image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Exec address beyond end of file");
				image.message(" Exec address beyond end of file");
			}
			else
			{
				for (i = quick_addr; i < read_; i++)
					space.write_byte(i, quick_data[i]);

				/* display a message about the loaded quickload */
				image.message(" Quickload: size=%04X : exec=%04X",quick_length,exec_addr);

				// Start the quickload
				m_maincpu->set_state_int(S2650_PC, exec_addr);

				result = image_init_result::PASS;
			}
		}
	}

	return result;
}

static DEVICE_INPUT_DEFAULTS_START( keyboard )
	DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_300 )
	DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 )
	DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 )
	DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE )
	DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 )
DEVICE_INPUT_DEFAULTS_END

void binbug_state::binbug_base(machine_config &config)
{
	/* video hardware */
	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
	screen.set_color(rgb_t::amber());
	screen.set_refresh_hz(50);
	screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
	screen.set_screen_update(FUNC(binbug_state::screen_update));
	screen.set_size(512, 256);
	screen.set_visarea(0, 511, 0, 255);
	screen.set_palette("palette");

	GFXDECODE(config, "gfxdecode", "palette", gfx_dg640);
	PALETTE(config, "palette", palette_device::MONOCHROME);

	SPEAKER(config, "mono").front_center();

	/* Cassette */
	CASSETTE(config, m_cass);
	m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
	m_cass->add_route(ALL_OUTPUTS, "mono", 0.05);
}

void binbug_state::binbug(machine_config &config)
{
	binbug_base(config);

	/* basic machine hardware */
	s2650_device &maincpu(S2650(config, m_maincpu, XTAL(1'000'000)));
	maincpu.set_addrmap(AS_PROGRAM, &binbug_state::binbug_mem);
	maincpu.set_addrmap(AS_DATA, &binbug_state::binbug_data);
	maincpu.sense_handler().set(FUNC(binbug_state::binbug_serial_r));
	maincpu.flag_handler().set(FUNC(binbug_state::binbug_serial_w));

	/* Keyboard */
	RS232_PORT(config, m_rs232, default_rs232_devices, "keyboard").set_option_device_input_defaults("keyboard", DEVICE_INPUT_DEFAULTS_NAME(keyboard));

	/* quickload */
	QUICKLOAD(config, "quickload", "pgm", attotime::from_seconds(1)).set_load_callback(FUNC(binbug_state::quickload_cb), this);
}


/* ROM definition */
ROM_START( binbug )
	ROM_REGION( 0x8000, "maincpu", ROMREGION_ERASEFF )
	ROM_LOAD( "binbug.rom", 0x0000, 0x0400, CRC(2cb1ac6e) SHA1(a969883fc767484d6b0fa103cfa4b4129b90441b) )

	ROM_REGION( 0x0800, "chargen", 0 )
	ROM_LOAD( "6574.bin", 0x0000, 0x0800, CRC(fd75df4f) SHA1(4d09aae2f933478532b7d3d1a2dee7123d9828ca) )
	ROM_FILL(0, 16, 0x00)
ROM_END

/* Driver */

//    YEAR  NAME    PARENT  COMPAT   MACHINE    INPUT   CLASS         INIT        COMPANY      FULLNAME      FLAGS
COMP( 1980, binbug, pipbug,   0,     binbug,    binbug, binbug_state, empty_init, "MicroByte", "BINBUG 3.6", 0 )



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

/*

DG680 (ETI-680), using the DGOS-Z80 operating system.

This is a S100 card.

In some ways, this system is the ancestor of the original Microbee.

ROM is typed in from a PDF, therefore marked a bad dump.

No schematic available, most of this is guesswork.

Port 0 is the input from an ascii keyboard.

Port 2 is the cassette interface.

Port 8 controls some kind of memory protection scheme.
The code indicates that B is the page to protect, and
A is the code (0x08 = inhibit; 0x0B = unprotect;
0x0C = enable; 0x0E = protect). There are 256 pages so
each page is 256 bytes.

The clock is controlled by the byte in D80D.

Monitor Commands:
C (compare)*
E (edit)*
F (fill)*
G - Go to address
I - Inhibit CTC
M (move)*
P (clear screen)*
R (read tape)*
S (search)*
T hhmm [ss] - Set the time
W (write tape)*
X - protection status
XC - clear ram
XD - same as X
XE - enable facilities
XF - disable facilities
XP - protect block
XU - unprotect block
Z - go to 0000.

* These commands are identical to the Microbee ones.

ToDo:
- dips
- leds
- need schematic to find out what else is missing
- cassette
- ctc / clock

*/


class dg680_state : public binbug_state
{
public:
	dg680_state(const machine_config &mconfig, device_type type, const char *tag)
		: binbug_state(mconfig, type, tag)
		, m_ctc(*this, "z80ctc")
		, m_pio(*this, "z80pio")
	{ }

	DECLARE_READ8_MEMBER(porta_r);
	DECLARE_READ8_MEMBER(portb_r);
	DECLARE_WRITE8_MEMBER(portb_w);
	DECLARE_READ8_MEMBER(port08_r);
	DECLARE_WRITE8_MEMBER(port08_w);
	void kbd_put(u8 data);
	TIMER_DEVICE_CALLBACK_MEMBER(time_tick);
	TIMER_DEVICE_CALLBACK_MEMBER(uart_tick);

	void dg680(machine_config &config);
	void dg680_io(address_map &map);
	void dg680_mem(address_map &map);

private:
	uint8_t m_pio_b;
	uint8_t m_term_data;
	uint8_t m_protection[0x100];
	virtual void machine_reset() override;
	required_device<z80ctc_device> m_ctc;
	required_device<z80pio_device> m_pio;
};

void dg680_state::dg680_mem(address_map &map)
{
	map.unmap_value_high();
	map(0x0000, 0xcfff).ram();
	map(0xd000, 0xd7ff).rom();
	map(0xd800, 0xefff).ram();
	map(0xf000, 0xf3ff).ram().share("videoram");
	map(0xf400, 0xf7ff).ram().share("attribram");
}

void dg680_state::dg680_io(address_map &map)
{
	map.unmap_value_high();
	map.global_mask(0xff);
	map(0x00, 0x03).rw(m_pio, FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt));
	map(0x04, 0x07).rw(m_ctc, FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
	map(0x08, 0x08).rw(FUNC(dg680_state::port08_r), FUNC(dg680_state::port08_w)); //SWP Control and Status
	//AM_RANGE(0x09,0x09) parallel input port
	// Optional AM9519 Programmable Interrupt Controller (port c = data, port d = control)
	//AM_RANGE(0x0c,0x0d) AM_DEVREADWRITE("am9519", am9519_device, read, write)
}

void dg680_state::machine_reset()
{
	m_maincpu->set_pc(0xd000);
}

// this is a guess there is no information available
static const z80_daisy_config dg680_daisy_chain[] =
{
	{ "z80ctc" },
	{ "z80pio" },
	{ 0x00 }
};


/* Input ports */
static INPUT_PORTS_START( dg680 )
INPUT_PORTS_END

void dg680_state::kbd_put(u8 data)
{
	m_term_data = data;
	/* strobe in keyboard data */
	m_pio->strobe_a(0);
	m_pio->strobe_a(1);
}

READ8_MEMBER( dg680_state::porta_r )
{
	uint8_t data = m_term_data;
	m_term_data = 0;
	return data;
}

READ8_MEMBER( dg680_state::portb_r )
{
	return m_pio_b | (m_cass->input() > 0.03);
}

// bit 1 = cassout; bit 2 = motor on
WRITE8_MEMBER( dg680_state::portb_w )
{
	m_pio_b = data & 0xfe;
	m_cass->output(BIT(data, 1) ? -1.0 : +1.0);
}

READ8_MEMBER( dg680_state::port08_r )
{
	uint8_t breg = m_maincpu->state_int(Z80_B);
	return m_protection[breg];
}

WRITE8_MEMBER( dg680_state::port08_w )
{
	uint8_t breg = m_maincpu->state_int(Z80_B);
	m_protection[breg] = data;
}

TIMER_DEVICE_CALLBACK_MEMBER(dg680_state::time_tick)
{
// ch0 is for the clock
	m_ctc->trg0(1);
	m_ctc->trg0(0);
// no idea about ch2
	m_ctc->trg2(1);
	m_ctc->trg2(0);
}

TIMER_DEVICE_CALLBACK_MEMBER(dg680_state::uart_tick)
{
// ch3 is for cassette
	m_ctc->trg3(1);
	m_ctc->trg3(0);
}

void dg680_state::dg680(machine_config &config)
{
	binbug_base(config);

	/* basic machine hardware */
	z80_device& maincpu(Z80(config, m_maincpu, XTAL(8'000'000) / 4));
	maincpu.set_addrmap(AS_PROGRAM, &dg680_state::dg680_mem);
	maincpu.set_addrmap(AS_IO, &dg680_state::dg680_io);
	maincpu.set_daisy_config(dg680_daisy_chain);

	/* Keyboard */
	generic_keyboard_device &keyb(GENERIC_KEYBOARD(config, "keyb", 0));
	keyb.set_keyboard_callback(FUNC(dg680_state::kbd_put));

	/* Devices */
	z80ctc_device& ctc(Z80CTC(config, "z80ctc", XTAL(8'000'000) / 4));
	ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
	ctc.zc_callback<0>().set("z80ctc", FUNC(z80ctc_device::trg1));

	z80pio_device& pio(Z80PIO(config, "z80pio", XTAL(8'000'000) / 4));
	pio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
	pio.in_pa_callback().set(FUNC(dg680_state::porta_r));
	// OUT_ARDY - this activates to ask for kbd data but not known if actually used
	pio.in_pb_callback().set(FUNC(dg680_state::portb_r));
	pio.out_pb_callback().set(FUNC(dg680_state::portb_w));

	TIMER(config, "ctc0").configure_periodic(FUNC(dg680_state::time_tick), attotime::from_hz(200));
	TIMER(config, "ctc3").configure_periodic(FUNC(dg680_state::uart_tick), attotime::from_hz(4800));
}

/* ROM definition */
ROM_START( dg680 )
	ROM_REGION( 0x10000, "maincpu", 0 )
	ROM_LOAD( "dg680.rom", 0xd000, 0x0800, BAD_DUMP CRC(c1aaef6a) SHA1(1508ca8315452edfb984718e795ccbe79a0c0b58) )

	ROM_REGION( 0x0800, "chargen", 0 )
	ROM_LOAD( "6574.bin", 0x0000, 0x0800, CRC(fd75df4f) SHA1(4d09aae2f933478532b7d3d1a2dee7123d9828ca) )

	ROM_REGION( 0x0020, "proms", 0 )
	ROM_LOAD( "82s123.bin", 0x0000, 0x0020, NO_DUMP )
ROM_END

/* Driver */

//    YEAR  NAME   PARENT  COMPAT  MACHINE  INPUT  CLASS        INIT        COMPANY            FULLNAME                   FLAGS
COMP( 1980, dg680, 0,      0,      dg680,   dg680, dg680_state, empty_init, "David Griffiths", "DG680 with DGOS-Z80 1.4", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW )