// license:?
// copyright-holders:Kevin Thacker,Sandro Ronco
/******************************************************************************
avigo.c
TI "Avigo" PDA
system driver
Documentation:
Hans B Pufal
Avigo simulator
MEMORY MAP:
0x0000-0x03fff: flash 0 block 0
0x4000-0x07fff: bank 1
0x8000-0x0bfff: bank 2
0xc000-0x0ffff: ram block 0
Bankswitch:
Bank 1 is controlled by ports 5 and 6, port 5 is the bank select
and port 6 is the chip select, the known chip select are:
- 0: flash 0
- 1: RAM
- 3: flash 1
- 5: flash 2 (optional)
- 6: VideoRAM
- 7: flash 0
Bank 2 have the same behavior but is controlled by ports 7 and 8
Hardware:
- Z80 CPU
- 16c500c UART
- amd29f080 flash-file memory x 3 (3mb)
- 128k ram
- stylus pen
- touch-pad screen
Flash:
The following flash ID are checked by Avigo OS, if the returned
ID is different the PDA doesn't boot.
Maker ID Device ID Description
0xb0 0x21 Sharp LH28F004
0x89 0xa6 Sharp LH28F008
0x89 0xaa Sharp LH28F016
0xb0 0x88 Sharp LH28F032
0x01 0xa4 AMD AM29F040
0x01 0xd5 AMD AM29F080
0x01 0xad AMD AM29F016
TODO:
- Found a better way to emulate the touchscreen panel out of the screen
area (the six buttons at the bottom)
- Alarm doesn't work
- Serial communications and IR port.
I don't have any documentation on the hardware, so a lot of this
driver has been written using educated guesswork and a lot of help
from an existing emulation written by Hans Pufal. Hans's emulator
is also written from educated guesswork.
MESS Driver by Kevin Thacker and Sandro Ronco
******************************************************************************/
#include "includes/avigo.h"
#include "avigo.lh"
#define AVIGO_LOG 0
#define LOG(x) do { if (AVIGO_LOG) logerror x; } while (0)
/* memory 0x0000-0x03fff */
READ8_MEMBER(avigo_state::flash_0x0000_read_handler)
{
return m_flashes[0]->read(offset);
}
/* memory 0x0000-0x03fff */
WRITE8_MEMBER(avigo_state::flash_0x0000_write_handler)
{
m_flashes[0]->write(offset, data);
}
/* memory 0x04000-0x07fff */
READ8_MEMBER(avigo_state::flash_0x4000_read_handler)
{
return m_flashes[m_flash_at_0x4000]->read((m_bank1_l<<14) | offset);
}
/* memory 0x04000-0x07fff */
WRITE8_MEMBER(avigo_state::flash_0x4000_write_handler)
{
m_flashes[m_flash_at_0x4000]->write((m_bank1_l<<14) | offset, data);
}
/* memory 0x08000-0x0bfff */
READ8_MEMBER(avigo_state::flash_0x8000_read_handler)
{
return m_flashes[m_flash_at_0x8000]->read((m_bank2_l<<14) | offset);
}
/* memory 0x08000-0x0bfff */
WRITE8_MEMBER(avigo_state::flash_0x8000_write_handler)
{
m_flashes[m_flash_at_0x8000]->write((m_bank2_l<<14) | offset, data);
}
/*
IRQ bits (port 3) ordered by priority:
bit 7: power down request high priority. When it occurs, clear this bit.
bit 5: real time clock
bit 3: uart int
bit 6: pen int An interrupt when pen is pressed against screen.
bit 4: 1 sec int used for auto power off
bit 2: synchronisation link interrupt???keyboard int ;; check bit 5 of port 1,
bit 1: ??? (cleared in nmi, and then set again)
bit 0: not checked, probably unused
*/
void avigo_state::refresh_ints()
{
if (m_irq!=0)
m_maincpu->set_input_line(0, HOLD_LINE);
else
m_maincpu->set_input_line(0, CLEAR_LINE);
}
/* does not do anything yet */
WRITE_LINE_MEMBER( avigo_state::tc8521_alarm_int )
{
//#if 0
m_irq &=~(1<<5);
if (state)
{
m_irq |= (1<<5);
}
refresh_ints();
//#endif
}
void avigo_state::refresh_memory(UINT8 bank, UINT8 chip_select)
{
address_space& space = m_maincpu->space(AS_PROGRAM);
int &active_flash = (bank == 1 ? m_flash_at_0x4000 : m_flash_at_0x8000);
char bank_tag[6];
LOG(("Chip %02x mapped at %04x - %04x\n", chip_select, bank * 0x4000, bank * 0x4000 + 0x3fff));
switch (chip_select)
{
case 0x06: // videoram
space.install_readwrite_handler(bank * 0x4000, bank * 0x4000 + 0x3fff, read8_delegate(FUNC(avigo_state::vid_memory_r), this), write8_delegate(FUNC(avigo_state::vid_memory_w), this));
active_flash = -1;
break;
case 0x01: // banked RAM
sprintf(bank_tag,"bank%d", bank);
membank(bank_tag)->set_base(m_ram_base + (((bank == 1 ? m_bank1_l : m_bank2_l) & 0x07)<<14));
space.install_readwrite_bank (bank * 0x4000, bank * 0x4000 + 0x3fff, bank_tag);
active_flash = -1;
break;
case 0x00: // flash 0
case 0x03: // flash 1
case 0x05: // flash 2
case 0x07: // flash 0
if (active_flash < 0) // to avoid useless calls to install_readwrite_handler that cause slowdowns
{
if (bank == 1)
space.install_readwrite_handler(0x4000, 0x7fff, read8_delegate(FUNC(avigo_state::flash_0x4000_read_handler), this), write8_delegate(FUNC(avigo_state::flash_0x4000_write_handler), this));
else
space.install_readwrite_handler(0x8000, 0xbfff, read8_delegate(FUNC(avigo_state::flash_0x8000_read_handler), this), write8_delegate(FUNC(avigo_state::flash_0x8000_write_handler), this));
}
switch (chip_select)
{
case 0x00:
case 0x07: active_flash = 0; break;
case 0x03: active_flash = 1; break;
case 0x05: active_flash = 2; break;
}
break;
default:
logerror("Unknown chip %02x mapped at %04x - %04x\n", chip_select, bank * 0x4000, bank * 0x4000 + 0x3fff);
space.unmap_readwrite(bank * 0x4000, bank * 0x4000 + 0x3fff);
active_flash = -1;
break;
}
}
WRITE_LINE_MEMBER( avigo_state::com_interrupt )
{
LOG(("com int\r\n"));
m_irq &= ~(1<<3);
if (state)
{
m_irq |= (1<<3);
}
refresh_ints();
}
void avigo_state::machine_reset()
{
/* if is a cold start initialize flash contents */
if (!m_warm_start)
{
memcpy(m_flashes[0]->space().get_read_ptr(0), memregion("bios")->base() + 0x000000, 0x100000);
memcpy(m_flashes[1]->space().get_read_ptr(0), memregion("bios")->base() + 0x100000, 0x100000);
}
m_irq = 0;
m_bank1_l = 0;
m_bank1_h = 0;
m_bank2_l = 0;
m_bank2_h = 0;
m_flash_at_0x4000 = -1;
m_flash_at_0x8000 = -1;
refresh_memory(1, m_bank1_h & 0x07);
refresh_memory(2, m_bank2_h & 0x07);
}
void avigo_state::machine_start()
{
m_ram_base = (UINT8*)m_ram->pointer();
// bank3 always first ram bank
membank("bank3")->set_base(m_ram_base);
/* keep machine pointers to flash devices */
m_flashes[0] = machine().device<intelfsh8_device>("flash0");
m_flashes[1] = machine().device<intelfsh8_device>("flash1");
m_flashes[2] = machine().device<intelfsh8_device>("flash2");
machine().device<nvram_device>("nvram")->set_base(m_ram_base, m_ram->size());
m_warm_start = 1;
// register for state saving
save_item(NAME(m_key_line));
save_item(NAME(m_irq));
save_item(NAME(m_port2));
save_item(NAME(m_bank2_l));
save_item(NAME(m_bank2_h));
save_item(NAME(m_bank1_l));
save_item(NAME(m_bank1_h));
save_item(NAME(m_ad_control_status));
save_item(NAME(m_flash_at_0x4000));
save_item(NAME(m_flash_at_0x8000));
save_item(NAME(m_ad_value));
save_item(NAME(m_screen_column));
save_item(NAME(m_warm_start));
// save all flash contents
save_pointer(NAME((UINT8*)m_flashes[0]->space().get_read_ptr(0)), 0x100000);
save_pointer(NAME((UINT8*)m_flashes[1]->space().get_read_ptr(0)), 0x100000);
save_pointer(NAME((UINT8*)m_flashes[2]->space().get_read_ptr(0)), 0x100000);
// register postload callback
machine().save().register_postload(save_prepost_delegate(FUNC(avigo_state::postload), this));
}
void avigo_state::postload()
{
// refresh the bankswitch
refresh_memory(1, m_bank1_h & 0x07);
refresh_memory(2, m_bank2_h & 0x07);
}
static ADDRESS_MAP_START( avigo_mem , AS_PROGRAM, 8, avigo_state)
AM_RANGE(0x0000, 0x3fff) AM_READWRITE(flash_0x0000_read_handler, flash_0x0000_write_handler)
AM_RANGE(0x4000, 0x7fff) AM_READWRITE_BANK("bank1")
AM_RANGE(0x8000, 0xbfff) AM_READWRITE_BANK("bank2")
AM_RANGE(0xc000, 0xffff) AM_READWRITE_BANK("bank3")
ADDRESS_MAP_END
READ8_MEMBER(avigo_state::key_data_read_r)
{
UINT8 data = 0x0f;
if (!(m_key_line & 0x01))
{
data &= ioport("LINE0")->read();
}
if (!(m_key_line & 0x02))
{
data &= ioport("LINE1")->read();
}
if (!(m_key_line & 0x04))
{
data &= ioport("LINE2")->read();
}
/* bit 3 is cold/warm start */
data &= ((m_warm_start<<3) ^ 0xff);
/* if bit 5 is clear shows synchronisation logo! */
data |= (1<<5);
return data;
}
/* set key line(s) to read */
/* bit 0 set for line 0, bit 1 set for line 1, bit 2 set for line 2 */
WRITE8_MEMBER(avigo_state::set_key_line_w)
{
/* 5, 101, read back 3 */
m_key_line = data;
m_warm_start = BIT(data, 3);
}
READ8_MEMBER(avigo_state::irq_r)
{
return m_irq;
}
WRITE8_MEMBER(avigo_state::irq_w)
{
m_irq &= data;
refresh_ints();
}
WRITE8_MEMBER(avigo_state::port2_w)
{
/*
bit 4 LCD backlight on/off
bit 5-6 source select for a/d converter
*/
if ((m_port2 ^ data) & 0x10)
popmessage("Backlight %s", data & 0x10 ? "on" : "off");
m_port2 = data;
}
READ8_MEMBER(avigo_state::bank1_r)
{
return offset ? m_bank1_h: m_bank1_l;
}
READ8_MEMBER(avigo_state::bank2_r)
{
return offset ? m_bank2_h: m_bank2_l;
}
WRITE8_MEMBER(avigo_state::bank1_w)
{
if (offset)
{
LOG(("bank1 h w: %04x\n", data));
m_bank1_h = data;
}
else
{
LOG(("bank1 l w: %04x\n", data));
m_bank1_l = data & 0x3f;
}
refresh_memory(1, m_bank1_h & 0x07);
}
WRITE8_MEMBER(avigo_state::bank2_w)
{
if (offset)
{
LOG(("bank2 h w: %04x\n", data));
m_bank2_h = data;
}
else
{
LOG(("bank2 l w: %04x\n", data));
m_bank2_l = data & 0x3f;
}
refresh_memory(2, m_bank2_h & 0x07);
}
READ8_MEMBER(avigo_state::ad_control_status_r)
{
LOG(("avigo ad control read %02x\n", (int) m_ad_control_status));
return m_ad_control_status;
}
WRITE8_MEMBER(avigo_state::ad_control_status_w)
{
LOG(("avigo ad control w %02x\n",data));
switch (m_port2 & 0x60)
{
case 0x20:
// read main battery status valid range 0x000-0x3ff
LOG(("a/d main battery status\n"));
m_ad_value = 0x3ff;
break;
case 0x40:
// read backup battery status valid range 0x000-0x3ff
LOG(("a/d backup battery status\n"));
m_ad_value = 0x3ff;
break;
case 0x60:
if ((data & 0x070)==0x070)
{
/* bit 3 appears to select between 1 = x coord, 0 = y coord */
/* when 6,5,4 = 1 */
if ((data & 0x08)!=0)
{
LOG(("a/d select x coordinate\n"));
LOG(("x coord: %d\n", ioport("POSX")->read()));
/* on screen range 0x060->0x03a0 */
if (ioport("LINE3")->read() & 0x01)
{
/* this might not be totally accurate because hitable screen
area may include the border around the screen! */
m_ad_value = ioport("POSX")->read();
}
else
{
m_ad_value = 0;
}
LOG(("ad value: %d\n",m_ad_value));
}
else
{
/* in the avigo rom, the y coordinate is inverted! */
/* therefore a low value would be near the bottom of the display,
and a high value at the top */
/* total valid range 0x044->0x03a6 */
/* 0x0350 is also checked */
/* assumption 0x044->0x0350 is screen area and
0x0350->0x03a6 is panel at bottom */
LOG(("a/d select y coordinate\n"));
LOG(("y coord: %d\n", ioport("POSY")->read()));
if (ioport("LINE3")->read() & 0x01)
{
m_ad_value = ioport("POSY")->read();
}
else
{
m_ad_value = 0;
}
LOG(("ad value: %d\n",m_ad_value));
}
}
}
/* bit 0: 1 if a/d complete, 0 if a/d not complete */
m_ad_control_status = data | 1;
}
READ8_MEMBER(avigo_state::ad_data_r)
{
UINT8 data = 0;
/* original */
/* status AND 11110111 */
/* status OR 01110000 -> C20F */
switch (m_ad_control_status & 0x078)
{
/* x1110xxx */
/* read upper 4 bits of 10 bit A/D number */
case 0x060:
case 0x070:
case 0x078:
{
/* upper 4 bits of 10 bit A/D number in bits 7-4 of data */
/* bit 0 must be 0, bit 1 must be 0 */
/* bit 3 must be 1. bit 2 can have any value */
LOG(("a/d read upper 4 bits\n"));
data = ((m_ad_value>>6) & 0x0f)<<4;
data |= 8;
}
break;
/* x0111xxx */
case 0x020:
case 0x038:
{
/* lower 6 bits of 10-bit A/D number in bits 7-2 of data */
/* bit 0 must be 1, bit 1 must be 0 */
LOG(("a/d lower 6-bits\n"));
data = ((m_ad_value & 0x03f)<<2);
data |= 1;
}
break;
default:
break;
}
/* x coord? */
/* wait for bit 0 of status to become 1 */
/* read data -> d */
/* C20f AND 10111111 */
/* C20f OR 00001000 */
/* x0111xxx */
/* bit 1 must be 0, bit 0 must be 1 */
/* read data -> e */
/* upper 4 bits of d contain data */
/* bits 0 and 1 do not contain data of e, but all other bits do */
/* get bit 5 and 6 of d */
/* and put into bit 0 and 1 of e */
/* C20f OR 01000000 */
/* x1111xxx */
/* y coord? */
/* bit 0 must be 0, bit 1 must be 0 */
/* bit 3 must be 1. bit 2 can have any value */
/* read data -> d */
/* C20f AND 10111111 */
/* x0111xxx */
/* bit 1 must be 0, bit 0 must be 1 */
/* read data -> e */
/* original and 1111100 */
/* original or 1111000 */
/* 1111x00 */
/* if fails! */
/* original */
/* AND 1001100 */
/* OR 1001000 */
/* 1001x00 */
/* AND 1101100 */
/* OR 1101000 */
/* 1101x00 */
/* 1111x00 */
LOG(("avigo ad read %02x\n",data));
return data;
}
WRITE8_MEMBER(avigo_state::speaker_w)
{
/* Speaker output state */
m_speaker->level_w(BIT(data, 3));
}
/* port 0x04:
bit 7: ??? if set, does a write 0x00 to 0x02e */
/* port 0x029:
port 0x02e */
READ8_MEMBER(avigo_state::port_04_r)
{
/* must be both 0 for it to boot! */
return 0x0ff^((1<<7) | (1<<5));
}
static ADDRESS_MAP_START( avigo_io, AS_IO, 8, avigo_state)
ADDRESS_MAP_UNMAP_HIGH
ADDRESS_MAP_GLOBAL_MASK(0xff)
AM_RANGE(0x001, 0x001) AM_READWRITE( key_data_read_r, set_key_line_w )
AM_RANGE(0x002, 0x002) AM_WRITE( port2_w )
AM_RANGE(0x003, 0x003) AM_READWRITE( irq_r, irq_w )
AM_RANGE(0x004, 0x004) AM_READ( port_04_r )
AM_RANGE(0x005, 0x006) AM_READWRITE( bank1_r, bank1_w )
AM_RANGE(0x007, 0x008) AM_READWRITE( bank2_r, bank2_w )
AM_RANGE(0x009, 0x009) AM_READWRITE( ad_control_status_r, ad_control_status_w )
AM_RANGE(0x010, 0x01f) AM_DEVREADWRITE("rtc", rp5c01_device, read, write)
AM_RANGE(0x028, 0x028) AM_WRITE( speaker_w )
AM_RANGE(0x02d, 0x02d) AM_READ( ad_data_r )
AM_RANGE(0x030, 0x037) AM_DEVREADWRITE("ns16550", ns16550_device, ins8250_r, ins8250_w )
ADDRESS_MAP_END
INPUT_CHANGED_MEMBER( avigo_state::pen_irq )
{
LOG(("pen pressed interrupt\n"));
// an irq is generated when the pen is pressed down on the screen
// or lifted up from the screen
m_irq |= (1<<6);
refresh_ints();
}
INPUT_CHANGED_MEMBER( avigo_state::pen_move_irq )
{
// an irq is generated when the pen is down on the screen and is being moved
if (ioport("LINE3")->read() & 0x01)
{
LOG(("pen move interrupt\n"));
m_irq |= (1<<6);
refresh_ints();
}
}
INPUT_CHANGED_MEMBER( avigo_state::kb_irq )
{
LOG(("key pressed interrupt\n"));
if (!newval)
{
m_irq |= (1<<2);
refresh_ints();
}
}
INPUT_CHANGED_MEMBER( avigo_state::power_down_irq )
{
if(newval)
{
m_irq |= (1<<7);
refresh_ints();
}
}
static INPUT_PORTS_START(avigo)
PORT_START("LINE0")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("PAGE UP") PORT_CODE(KEYCODE_PGUP) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, kb_irq, NULL )
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("PAGE DOWN") PORT_CODE(KEYCODE_PGDN) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, kb_irq, NULL )
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("LIGHT") PORT_CODE(KEYCODE_L) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, kb_irq, NULL )
PORT_BIT(0xf8, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_START("LINE1")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("TO DO") PORT_CODE(KEYCODE_T) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, kb_irq, NULL )
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("ADDRESS") PORT_CODE(KEYCODE_A) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, kb_irq, NULL )
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("SCHEDULE") PORT_CODE(KEYCODE_S) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, kb_irq, NULL )
PORT_BIT(0xf8, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_START("LINE2")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("MEMO") PORT_CODE(KEYCODE_M) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, kb_irq, NULL )
PORT_BIT(0xfe, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_START("LINE3")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Pen/Stylus pressed") PORT_CODE(KEYCODE_ENTER) PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, pen_irq, NULL )
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("?? Causes a NMI") PORT_CODE(KEYCODE_W) PORT_CODE(JOYCODE_BUTTON2)
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("Power Down") PORT_CODE(KEYCODE_Q) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, power_down_irq, NULL )
/* these two ports are used to emulate the position of the pen/stylus on the screen */
PORT_START("POSX") /* Mouse - X AXIS */
PORT_BIT(0x3ff, 0x060, IPT_LIGHTGUN_X) PORT_SENSITIVITY(100) PORT_CROSSHAIR(X, 1, 0, 0) PORT_MINMAX(0x060, 0x3a0) PORT_KEYDELTA(10) PORT_PLAYER(1) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, pen_move_irq, NULL )
PORT_START("POSY") /* Mouse - Y AXIS */
PORT_BIT(0x3ff, 0x044, IPT_LIGHTGUN_Y) PORT_SENSITIVITY(100) PORT_CROSSHAIR(Y, 1, 0, 0) PORT_MINMAX(0x044, 0x3a6) PORT_INVERT PORT_KEYDELTA(10) PORT_PLAYER(1) PORT_CHANGED_MEMBER( DEVICE_SELF, avigo_state, pen_move_irq, NULL )
INPUT_PORTS_END
/* F4 Character Displayer */
static const gfx_layout avigo_charlayout =
{
8, 16, /* 8 x 16 characters */
96, /* 96 characters */
1, /* 1 bits per pixel */
{ 0 }, /* no bitplanes */
/* x offsets */
{ 0, 1, 2, 3, 4, 5, 6, 7 },
/* y offsets */
{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
8*16 /* every char takes 16 bytes */
};
static const gfx_layout avigo_8_by_14 =
{
8, 14, /* 8 x 16 characters */
1024, /* 1024 characters */
1, /* 1 bits per pixel */
{ 0 }, /* no bitplanes */
/* x offsets */
{ 0, 1, 2, 3, 4, 5, 6, 7 },
/* y offsets */
{ 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
8*32 /* every char takes 32 bytes */
};
static const gfx_layout avigo_16_by_15 =
{
16, 15, /* 8 x 16 characters */
1024, /* 1024 characters */
1, /* 1 bits per pixel */
{ 0 }, /* no bitplanes */
/* x offsets */
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
/* y offsets */
{ 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16, 8*16, 9*16, 10*16, 11*16, 12*16, 13*16, 14*16, 15*16 },
16*16 /* every char takes 16 bytes */
};
static const gfx_layout avigo_15_by_16 =
{
15, 16, /* 8 x 16 characters */
1024, /* 1024 characters */
1, /* 1 bits per pixel */
{ 0 }, /* no bitplanes */
/* x offsets */
{ 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16, 8*16, 9*16, 10*16, 11*16, 12*16, 13*16, 14*16, 15*16 },
/* y offsets */
{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
16*16 /* every char takes 16 bytes */
};
static const gfx_layout avigo_8_by_8 =
{
8, 8, /* 8 x 8 characters */
256, /* 256 characters */
1, /* 1 bits per pixel */
{ 0 }, /* no bitplanes */
/* x offsets */
{ 0, 1, 2, 3, 4, 5, 6, 7 },
/* y offsets */
{ 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
16*16 /* every char takes 16 bytes */
};
static const gfx_layout avigo_6_by_8 =
{
6, 8, /* 6 x 8 characters */
255, /* 255 characters */
1, /* 1 bits per pixel */
{ 0 }, /* no bitplanes */
/* x offsets */
{ 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
/* y offsets */
{ 7, 6, 5, 4, 3, 2, 1, 0 },
16*16 /* every char takes 16 bytes */
};
static GFXDECODE_START( avigo )
GFXDECODE_ENTRY( "bios", 0x08992, avigo_charlayout, 0, 1 )
GFXDECODE_ENTRY( "bios", 0x0c020, avigo_8_by_14, 0, 1 )
GFXDECODE_ENTRY( "bios", 0x0c020, avigo_16_by_15, 0, 1 )
GFXDECODE_ENTRY( "bios", 0x14020, avigo_15_by_16, 0, 1 )
GFXDECODE_ENTRY( "bios", 0x1c020, avigo_8_by_8, 0, 1 )
GFXDECODE_ENTRY( "bios", 0x1e020, avigo_6_by_8, 0, 1 )
GFXDECODE_END
TIMER_DEVICE_CALLBACK_MEMBER(avigo_state::avigo_scan_timer)
{
m_irq |= (1<<1);
refresh_ints();
}
TIMER_DEVICE_CALLBACK_MEMBER(avigo_state::avigo_1hz_timer)
{
m_irq |= (1<<4);
refresh_ints();
}
QUICKLOAD_LOAD_MEMBER( avigo_state,avigo)
{
address_space& flash1 = m_flashes[1]->space(0);
const char *systemname = machine().system().name;
UINT32 first_app_page = (0x50000>>14);
int app_page;
// german and spanish language are 4 pages bigger than other
if ( strcmp( systemname, "avigo_de" ) == 0 || strcmp( systemname, "avigo_es" ) == 0 )
first_app_page += 4;
// search the first empty page
for (app_page = first_app_page + 1; app_page<0x40; app_page++)
{
bool empty_page = true;
for (int offset=0; offset<0x4000; offset++)
{
if (flash1.read_byte((app_page<<14) + offset) != 0xff)
{
empty_page = false;
break;
}
}
if (empty_page)
break;
}
// if there is the required free space installs the application
if ((app_page + (image.length()>>14)) < 0x40)
{
logerror("Application loaded at 0x%05x-0x%05x\n", app_page<<14, (app_page<<14) + (UINT32)image.length());
// copy app file into flash memory
image.fread((UINT8*)m_flashes[1]->space().get_read_ptr(app_page<<14), image.length());
// update the application ID
flash1.write_byte((app_page<<14) + 0x1a5, 0x80 + (app_page - (first_app_page>>14)));
// reset the CPU for allow at the Avigo OS to recognize the installed app
m_warm_start = 1;
m_maincpu->reset();
return IMAGE_INIT_PASS;
}
return IMAGE_INIT_FAIL;
}
void avigo_state::nvram_init(nvram_device &nvram, void *base, size_t size)
{
m_warm_start = 0;
memset(base, 0x00, size);
}
static MACHINE_CONFIG_START( avigo, avigo_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", Z80, 4000000)
MCFG_CPU_PROGRAM_MAP(avigo_mem)
MCFG_CPU_IO_MAP(avigo_io)
MCFG_QUANTUM_TIME(attotime::from_hz(60))
MCFG_DEVICE_ADD( "ns16550", NS16550, XTAL_1_8432MHz )
MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport", rs232_port_device, write_txd))
MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport", rs232_port_device, write_dtr))
MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport", rs232_port_device, write_rts))
MCFG_INS8250_OUT_INT_CB(WRITELINE(avigo_state, com_interrupt))
MCFG_RS232_PORT_ADD( "serport", default_rs232_devices, NULL )
MCFG_RS232_RXD_HANDLER(DEVWRITELINE("ns16550", ins8250_uart_device, rx_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE("ns16550", ins8250_uart_device, dcd_w))
MCFG_RS232_DSR_HANDLER(DEVWRITELINE("ns16550", ins8250_uart_device, dsr_w))
MCFG_RS232_RI_HANDLER(DEVWRITELINE("ns16550", ins8250_uart_device, ri_w))
MCFG_RS232_CTS_HANDLER(DEVWRITELINE("ns16550", ins8250_uart_device, cts_w))
/* video hardware */
MCFG_SCREEN_ADD("screen", LCD)
MCFG_SCREEN_REFRESH_RATE(50)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
MCFG_SCREEN_UPDATE_DRIVER(avigo_state, screen_update)
MCFG_SCREEN_SIZE(AVIGO_SCREEN_WIDTH, AVIGO_SCREEN_HEIGHT + AVIGO_PANEL_HEIGHT)
MCFG_SCREEN_VISIBLE_AREA(0, AVIGO_SCREEN_WIDTH-1, 0, AVIGO_SCREEN_HEIGHT + AVIGO_PANEL_HEIGHT -1)
MCFG_SCREEN_PALETTE("palette")
MCFG_DEFAULT_LAYOUT(layout_avigo)
MCFG_GFXDECODE_ADD("gfxdecode", "palette", avigo)
MCFG_PALETTE_ADD("palette", AVIGO_NUM_COLOURS)
MCFG_PALETTE_INIT_OWNER(avigo_state, avigo)
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
/* real time clock */
MCFG_DEVICE_ADD("rtc", RP5C01, XTAL_32_768kHz)
MCFG_RP5C01_OUT_ALARM_CB(WRITELINE(avigo_state, tc8521_alarm_int))
/* flash ROMs */
MCFG_AMD_29F080_ADD("flash0")
MCFG_AMD_29F080_ADD("flash1")
MCFG_AMD_29F080_ADD("flash2")
/* internal ram */
MCFG_RAM_ADD(RAM_TAG)
MCFG_RAM_DEFAULT_SIZE("128K")
MCFG_NVRAM_ADD_CUSTOM_DRIVER("nvram", avigo_state, nvram_init)
// IRQ 1 is used for scan the pen and for cursor blinking
MCFG_TIMER_DRIVER_ADD_PERIODIC("scan_timer", avigo_state, avigo_scan_timer, attotime::from_hz(50))
// IRQ 4 is generated every second, used for auto power off
MCFG_TIMER_DRIVER_ADD_PERIODIC("1hz_timer", avigo_state, avigo_1hz_timer, attotime::from_hz(1))
/* quickload */
MCFG_QUICKLOAD_ADD("quickload", avigo_state, avigo, "app", 0)
MACHINE_CONFIG_END
/***************************************************************************
Game driver(s)
***************************************************************************/
ROM_START(avigo)
ROM_REGION(0x200000, "bios", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS( 0, "v1004", "v1.004" )
ROMX_LOAD("os_1004.rom", 0x000000, 0x0100000, CRC(62acd55c) SHA1(b2be12f5cc1053b6026bff2a265146ba831a7ffa), ROM_BIOS(1))
ROMX_LOAD("english_1004.rom", 0x100000, 0x050000, CRC(c9c3a225) SHA1(7939993a5615ca59ff2047e69b6d85122d437dca), ROM_BIOS(1))
ROM_SYSTEM_BIOS( 1, "v1002", "v1.002" )
ROMX_LOAD("os_1002.rom", 0x000000, 0x0100000, CRC(484bb95c) SHA1(ddc28f22f8cbc99f60f91c58ee0e2d15170024fb), ROM_BIOS(2))
ROMX_LOAD("english_1002.rom", 0x100000, 0x050000, CRC(31cab0ac) SHA1(87d337830506a12514a4beb9a8502a0de94816f2), ROM_BIOS(2))
ROM_SYSTEM_BIOS( 2, "v100", "v1.00" )
ROMX_LOAD("os_100.rom", 0x000000, 0x0100000, CRC(13ea7b38) SHA1(85566ff142d86d504ac72613f169d8758e2daa09), ROM_BIOS(3))
ROMX_LOAD("english_100.rom", 0x100000, 0x050000, CRC(e2824b44) SHA1(3252454b05c3d3a4d7df1cb48dc3441ae82f2b1c), ROM_BIOS(3))
ROM_END
ROM_START(avigo_de)
ROM_REGION(0x200000, "bios", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS( 0, "v1004", "v1.004" )
ROMX_LOAD("os_1004.rom", 0x000000, 0x0100000, CRC(62acd55c) SHA1(b2be12f5cc1053b6026bff2a265146ba831a7ffa), ROM_BIOS(1))
ROMX_LOAD("german_1004.rom", 0x100000, 0x060000, CRC(0fa437b3) SHA1(e9352aa8fee6d93b898412bd129452b82baa9a21), ROM_BIOS(1))
ROM_SYSTEM_BIOS( 1, "v1002", "v1.002" )
ROMX_LOAD("os_1002.rom", 0x000000, 0x0100000, CRC(484bb95c) SHA1(ddc28f22f8cbc99f60f91c58ee0e2d15170024fb), ROM_BIOS(2))
ROMX_LOAD("german_1002.rom", 0x100000, 0x060000, CRC(c6bf07ba) SHA1(d3185687aa510f6c3b3ab3baaabe7e8ce1a79e3b), ROM_BIOS(2))
ROM_SYSTEM_BIOS( 2, "v100", "v1.00" )
ROMX_LOAD("os_100.rom", 0x000000, 0x0100000, CRC(13ea7b38) SHA1(85566ff142d86d504ac72613f169d8758e2daa09), ROM_BIOS(3))
ROMX_LOAD("german_100.rom", 0x100000, 0x060000, CRC(117d9189) SHA1(7e959ab1381ba831821fcf87973b25d87f12d34e), ROM_BIOS(3))
ROM_END
ROM_START(avigo_fr)
ROM_REGION(0x200000, "bios", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS( 0, "v1004", "v1.004" )
ROMX_LOAD("os_1004.rom", 0x000000, 0x0100000, CRC(62acd55c) SHA1(b2be12f5cc1053b6026bff2a265146ba831a7ffa), ROM_BIOS(1))
ROMX_LOAD("french_1004.rom", 0x100000, 0x050000, CRC(5e4d90f7) SHA1(07df3af8a431ba65e079d6c987fb5d544f6541d8), ROM_BIOS(1))
ROM_SYSTEM_BIOS( 1, "v1002", "v1.002" )
ROMX_LOAD("os_1002.rom", 0x000000, 0x0100000, CRC(484bb95c) SHA1(ddc28f22f8cbc99f60f91c58ee0e2d15170024fb), ROM_BIOS(2))
ROMX_LOAD("french_1002.rom", 0x100000, 0x050000,CRC(caa3eb91) SHA1(ab199986de301d933f069a5e1f5150967e1d7f59), ROM_BIOS(2))
ROM_SYSTEM_BIOS( 2, "v100", "v1.00" )
ROMX_LOAD("os_100.rom", 0x000000, 0x0100000, CRC(13ea7b38) SHA1(85566ff142d86d504ac72613f169d8758e2daa09), ROM_BIOS(3))
ROMX_LOAD("french_100.rom", 0x100000, 0x050000, CRC(fffa2345) SHA1(399447cede3cdd0be768952cb24f7e4431147e3d), ROM_BIOS(3))
ROM_END
ROM_START(avigo_es)
ROM_REGION(0x200000, "bios", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS( 0, "v1004", "v1.004" )
ROMX_LOAD("os_1004.rom", 0x000000, 0x0100000, CRC(62acd55c) SHA1(b2be12f5cc1053b6026bff2a265146ba831a7ffa), ROM_BIOS(1))
ROMX_LOAD("spanish_1004.rom", 0x100000, 0x060000, CRC(235a7f8d) SHA1(94da4ecafb54dcd5d80bc5063cb4024e66e6a21f), ROM_BIOS(1))
ROM_SYSTEM_BIOS( 1, "v1002", "v1.002" )
ROMX_LOAD("os_1002.rom", 0x000000, 0x0100000, CRC(484bb95c) SHA1(ddc28f22f8cbc99f60f91c58ee0e2d15170024fb), ROM_BIOS(2))
ROMX_LOAD("spanish_1002.rom", 0x100000, 0x060000, CRC(a6e80cc4) SHA1(e741657558c11f7bce646ba3d7b5f845bfa275b7), ROM_BIOS(2))
ROM_SYSTEM_BIOS( 2, "v100", "v1.00" )
ROMX_LOAD("os_100.rom", 0x000000, 0x0100000, CRC(13ea7b38) SHA1(85566ff142d86d504ac72613f169d8758e2daa09), ROM_BIOS(3))
ROMX_LOAD("spanish_100.rom", 0x100000, 0x060000, CRC(953a5276) SHA1(b9ba1dbdc2127b1ef419c911ef66313024a7351a), ROM_BIOS(3))
ROM_END
ROM_START(avigo_it)
ROM_REGION(0x200000, "bios", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS( 0, "v1004", "v1.004" )
ROMX_LOAD("os_1004.rom", 0x000000, 0x0100000, CRC(62acd55c) SHA1(b2be12f5cc1053b6026bff2a265146ba831a7ffa), ROM_BIOS(1))
ROMX_LOAD("italian_1004.rom", 0x100000, 0x050000, CRC(fb7941ec) SHA1(230e8346a3b0da1ee24568ec090ce6860ebfe995), ROM_BIOS(1))
ROM_SYSTEM_BIOS( 1, "v1002", "v1.002" )
ROMX_LOAD("os_1002.rom", 0x000000, 0x0100000, CRC(484bb95c) SHA1(ddc28f22f8cbc99f60f91c58ee0e2d15170024fb), ROM_BIOS(2))
ROMX_LOAD("italian_1002.rom", 0x100000, 0x050000, CRC(093bc032) SHA1(2c75d950d356a7fd1d058808e5f0be8e15b8ea2a), ROM_BIOS(2))
ROM_SYSTEM_BIOS( 2, "v100", "v1.00" )
ROMX_LOAD("os_100.rom", 0x000000, 0x0100000, CRC(13ea7b38) SHA1(85566ff142d86d504ac72613f169d8758e2daa09), ROM_BIOS(3))
ROMX_LOAD("italian_100.rom", 0x100000, 0x050000, CRC(de359218) SHA1(6185727aba8ffc98723f2df74dda388fd0d70cc9), ROM_BIOS(3))
ROM_END
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
COMP(1997, avigo, 0, 0, avigo, avigo, driver_device, 0, "Texas Instruments", "TI Avigo 10 PDA", GAME_SUPPORTS_SAVE)
COMP(1997, avigo_de, avigo, 0, avigo, avigo, driver_device, 0, "Texas Instruments", "TI Avigo 10 PDA (German)", GAME_SUPPORTS_SAVE)
COMP(1997, avigo_fr, avigo, 0, avigo, avigo, driver_device, 0, "Texas Instruments", "TI Avigo 10 PDA (French)", GAME_SUPPORTS_SAVE)
COMP(1997, avigo_es, avigo, 0, avigo, avigo, driver_device, 0, "Texas Instruments", "TI Avigo 10 PDA (Spanish)", GAME_SUPPORTS_SAVE)
COMP(1997, avigo_it, avigo, 0, avigo, avigo, driver_device, 0, "Texas Instruments", "TI Avigo 10 PDA (Italian)", GAME_SUPPORTS_SAVE)