Skip to content
Browse files

Merge branch 'belgium' of github.com:ziz/jsmess into belgium

  • Loading branch information...
2 parents 95c8c4d + 32f32c7 commit 77a87fc9493f1093ccccc2803dc6fedb93a9ca18 JustinKerk committed Nov 6, 2011
View
2 src/mess/drivers/iq151.c
@@ -53,6 +53,7 @@ X Display/Edit registers
#include "machine/iq151cart.h"
#include "machine/iq151_rom.h"
#include "machine/iq151_disc2.h"
+#include "video/iq151_grafik.h"
#include "video/iq151_video32.h"
#include "video/iq151_video64.h"
@@ -448,6 +449,7 @@ static const iq151cart_interface iq151_cart_interface =
static SLOT_INTERFACE_START(iq151_cart)
SLOT_INTERFACE("video32", IQ151_VIDEO32) // video32
SLOT_INTERFACE("video64", IQ151_VIDEO64) // video64
+ SLOT_INTERFACE("grafik" , IQ151_GRAFIK) // Grafik
SLOT_INTERFACE("disc2" , IQ151_DISC2) // Disc 2
SLOT_INTERFACE("basic6" , IQ151_BASIC6) // BASIC6
SLOT_INTERFACE("basicg" , IQ151_BASICG) // BASICG
View
140 src/mess/machine/isa_wdxt_gen.c
@@ -102,7 +102,11 @@ ADDRESS_MAP_END
//-------------------------------------------------
static ADDRESS_MAP_START( wd1015_io, AS_IO, 8, wdxt_gen_device )
- AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READ(wd1015_p1_r)
+ AM_RANGE(0x00, 0x00) AM_READWRITE(wd1015_ram_r, wd1015_ram_w)
+ AM_RANGE(0x20, 0x20) AM_READWRITE(wd1015_hdc_r, wd1015_hdc_w)
+ AM_RANGE(0x60, 0x60) AM_WRITE(wd1015_hdc_addr_w)
+ AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(wd1015_t0_r)
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(wd1015_p1_r, wd1015_p1_w)
AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(wd1015_p2_w)
ADDRESS_MAP_END
@@ -134,12 +138,25 @@ READ8_MEMBER( wdxt_gen_device::rd322_r )
return 0xff;
}
+READ8_MEMBER( wdxt_gen_device::ram_r )
+{
+ return m_ram[offset];
+}
+
+WRITE8_MEMBER( wdxt_gen_device::ram_w )
+{
+ m_ram[offset] = data;
+}
+
static WD11C00_17_INTERFACE( host_intf )
{
DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, irq5_w),
DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, drq3_w),
DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, mr_w),
- DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, rd322_r)
+ DEVCB_CPU_INPUT_LINE(WD1015_TAG, MCS48_INPUT_IRQ),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, rd322_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, ram_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, ram_w)
};
@@ -253,6 +270,70 @@ bool wdxt_gen_device::have_dack(int line)
//-------------------------------------------------
+// wd1015_ram_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wdxt_gen_device::wd1015_ram_r )
+{
+ offs_t ra = m_host->ra_r();
+
+ return m_ram[ra];
+}
+
+
+//-------------------------------------------------
+// wd1015_ram_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wdxt_gen_device::wd1015_ram_w )
+{
+ offs_t ra = m_host->ra_r();
+
+ m_ram[ra] = data;
+}
+
+
+//-------------------------------------------------
+// wd1015_hdc_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wdxt_gen_device::wd1015_hdc_r )
+{
+ return m_hdc->read(space, m_hdc_addr);
+}
+
+
+//-------------------------------------------------
+// wd1015_hdc_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wdxt_gen_device::wd1015_hdc_w )
+{
+ m_hdc->write(space, m_hdc_addr, data);
+}
+
+
+//-------------------------------------------------
+// wd1015_hdc_addr_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wdxt_gen_device::wd1015_hdc_addr_w )
+{
+ m_hdc_addr = data & 0x07;
+}
+
+
+//-------------------------------------------------
+// wd1015_t0_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wdxt_gen_device::wd1015_t0_r )
+{
+ return 0;
+}
+
+
+//-------------------------------------------------
// wd1015_p1_r -
//-------------------------------------------------
@@ -262,14 +343,14 @@ READ8_MEMBER( wdxt_gen_device::wd1015_p1_r )
bit description
- P10 INTHD
- P11 HD/_FD
- P12 TR00
- P13 SBEF
- P14 TST31
- P15 MOM
- P16 STEP (output)
- P17 DIR (output)
+ P10
+ P11
+ P12
+ P13
+ P14
+ P15
+ P16
+ P17
*/
@@ -278,6 +359,29 @@ READ8_MEMBER( wdxt_gen_device::wd1015_p1_r )
//-------------------------------------------------
+// wd1015_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wdxt_gen_device::wd1015_p1_w )
+{
+ /*
+
+ bit description
+
+ P10
+ P11
+ P12
+ P13
+ P14
+ P15
+ P16
+ P17
+
+ */
+}
+
+
+//-------------------------------------------------
// wd1015_p2_w -
//-------------------------------------------------
@@ -287,14 +391,14 @@ WRITE8_MEMBER( wdxt_gen_device::wd1015_p2_w )
bit description
- P20 TST21
- P21 TST22
- P22 TST23
- P23 TST24
- P24 _FMO
- P25 BRDY
- P26 CORRD
- P27 ERR
+ P20
+ P21
+ P22
+ P23
+ P24
+ P25
+ P26
+ P27
*/
}
View
14 src/mess/machine/isa_wdxt_gen.h
@@ -52,7 +52,17 @@ class wdxt_gen_device : public device_t,
DECLARE_WRITE_LINE_MEMBER( drq3_w );
DECLARE_WRITE_LINE_MEMBER( mr_w );
DECLARE_READ8_MEMBER( rd322_r );
+ DECLARE_READ8_MEMBER( ram_r );
+ DECLARE_WRITE8_MEMBER( ram_w );
+
+ DECLARE_READ8_MEMBER( wd1015_ram_r );
+ DECLARE_WRITE8_MEMBER( wd1015_ram_w );
+ DECLARE_READ8_MEMBER( wd1015_hdc_r );
+ DECLARE_WRITE8_MEMBER( wd1015_hdc_w );
+ DECLARE_WRITE8_MEMBER( wd1015_hdc_addr_w );
+ DECLARE_READ8_MEMBER( wd1015_t0_r );
DECLARE_READ8_MEMBER( wd1015_p1_r );
+ DECLARE_WRITE8_MEMBER( wd1015_p1_w );
DECLARE_WRITE8_MEMBER( wd1015_p2_w );
protected:
@@ -70,6 +80,10 @@ class wdxt_gen_device : public device_t,
required_device<cpu_device> m_maincpu;
required_device<wd11c00_17_device> m_host;
required_device<wd2010_device> m_hdc;
+
+ UINT8 m_ram[0x800];
+
+ UINT8 m_hdc_addr;
};
View
65 src/mess/machine/wd11c00_17.c
@@ -15,6 +15,9 @@
// MACROS / CONSTANTS
//**************************************************************************
+#define LOG 1
+
+
// status register
#define STATUS_IRQ 0x20
#define STATUS_DRQ 0x10
@@ -56,7 +59,10 @@ void wd11c00_17_device::device_config_complete()
memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb));
memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb));
memset(&m_out_mr_cb, 0, sizeof(m_out_mr_cb));
+ memset(&m_out_busy_cb, 0, sizeof(m_out_busy_cb));
memset(&m_in_rd322_cb, 0, sizeof(m_in_rd322_cb));
+ memset(&m_in_ram_cb, 0, sizeof(m_in_ram_cb));
+ memset(&m_out_ram_cb, 0, sizeof(m_out_ram_cb));
}
}
@@ -74,9 +80,11 @@ inline void wd11c00_17_device::check_interrupt()
{
int irq = ((m_status & STATUS_IRQ) && (m_mask & MASK_IRQ)) ? ASSERT_LINE : CLEAR_LINE;
int drq = ((m_status & STATUS_DRQ) && (m_mask & MASK_DMA)) ? ASSERT_LINE : CLEAR_LINE;
+ int busy = (m_status & STATUS_BUSY) ? ASSERT_LINE : CLEAR_LINE;
m_out_irq5_func(irq);
m_out_drq3_func(drq);
+ m_out_busy_func(busy);
}
@@ -105,9 +113,9 @@ inline UINT8 wd11c00_17_device::read_data()
{
UINT8 data = 0;
- if (m_select)
+ if (m_status & STATUS_BUSY)
{
- data = m_ram[m_ra & 0x3ff];
+ data = m_in_ram_func(m_ra & 0x3ff);
increment_address();
}
@@ -122,9 +130,9 @@ inline UINT8 wd11c00_17_device::read_data()
inline void wd11c00_17_device::write_data(UINT8 data)
{
- if (m_select)
+ if (m_status & STATUS_BUSY)
{
- m_ram[m_ra & 0x3ff] = data;
+ m_out_ram_func(m_ra & 0x3ff, data);
increment_address();
}
@@ -144,6 +152,18 @@ inline void wd11c00_17_device::software_reset()
}
+//-------------------------------------------------
+// select -
+//-------------------------------------------------
+
+inline void wd11c00_17_device::select()
+{
+ m_status |= STATUS_BUSY;
+
+ check_interrupt();
+}
+
+
//**************************************************************************
// LIVE DEVICE
@@ -170,7 +190,10 @@ void wd11c00_17_device::device_start()
m_out_irq5_func.resolve(m_out_irq5_cb, *this);
m_out_drq3_func.resolve(m_out_drq3_cb, *this);
m_out_mr_func.resolve(m_out_mr_cb, *this);
+ m_out_busy_func.resolve(m_out_busy_cb, *this);
m_in_rd322_func.resolve(m_in_rd322_cb, *this);
+ m_in_ram_func.resolve(m_in_ram_cb, *this);
+ m_out_ram_func.resolve(m_out_ram_cb, *this);
}
@@ -180,9 +203,11 @@ void wd11c00_17_device::device_start()
void wd11c00_17_device::device_reset()
{
- m_select = 0;
+ m_status &= ~(STATUS_IRQ | STATUS_DRQ | STATUS_BUSY);
m_mask = 0;
m_ra = 0;
+
+ check_interrupt();
}
@@ -225,18 +250,22 @@ WRITE8_MEMBER( wd11c00_17_device::write )
switch (offset)
{
case 0: // Write Data, Host to Board
+ if (LOG) logerror("%s WD11C00-17 '%s' Write Data %02x\n", machine().describe_context(), tag(), data);
write_data(data);
break;
case 1: // Board Software Reset
+ if (LOG) logerror("%s WD11C00-17 '%s' Software Reset\n", machine().describe_context(), tag());
software_reset();
break;
case 2: // Board Select
- m_select = 1;
+ if (LOG) logerror("%s WD11C00-17 '%s' Select\n", machine().describe_context(), tag());
+ select();
break;
case 3: // Set/Reset DMA, IRQ Masks
+ if (LOG) logerror("%s WD11C00-17 '%s' Mask IRQ %u DMA %u\n", machine().describe_context(), tag(), BIT(data, 1), BIT(data, 0));
m_mask = data;
check_interrupt();
break;
@@ -265,6 +294,20 @@ void wd11c00_17_device::dack_w(UINT8 data)
//-------------------------------------------------
+// ra_r -
+//-------------------------------------------------
+
+offs_t wd11c00_17_device::ra_r()
+{
+ offs_t ra = m_ra;
+
+ increment_address();
+
+ return ra;
+}
+
+
+//-------------------------------------------------
// ireq_w -
//-------------------------------------------------
@@ -295,16 +338,6 @@ WRITE_LINE_MEMBER( wd11c00_17_device::cd_w )
//-------------------------------------------------
-// busy_w -
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER( wd11c00_17_device::busy_w )
-{
- if (state) m_status |= STATUS_BUSY; else m_status &= ~STATUS_BUSY;
-}
-
-
-//-------------------------------------------------
// clct_w -
//-------------------------------------------------
View
12 src/mess/machine/wd11c00_17.h
@@ -43,7 +43,10 @@ struct wd11c00_17_interface
devcb_write_line m_out_irq5_cb;
devcb_write_line m_out_drq3_cb;
devcb_write_line m_out_mr_cb;
+ devcb_write_line m_out_busy_cb;
devcb_read8 m_in_rd322_cb;
+ devcb_read8 m_in_ram_cb;
+ devcb_write8 m_out_ram_cb;
};
@@ -62,10 +65,11 @@ class wd11c00_17_device : public device_t,
UINT8 dack_r();
void dack_w(UINT8 data);
+ offs_t ra_r();
+
DECLARE_WRITE_LINE_MEMBER( ireq_w );
DECLARE_WRITE_LINE_MEMBER( io_w );
DECLARE_WRITE_LINE_MEMBER( cd_w );
- DECLARE_WRITE_LINE_MEMBER( busy_w );
DECLARE_WRITE_LINE_MEMBER( clct_w );
protected:
@@ -80,17 +84,19 @@ class wd11c00_17_device : public device_t,
inline UINT8 read_data();
inline void write_data(UINT8 data);
inline void software_reset();
+ inline void select();
devcb_resolved_write_line m_out_irq5_func;
devcb_resolved_write_line m_out_drq3_func;
devcb_resolved_write_line m_out_mr_func;
+ devcb_resolved_write_line m_out_busy_func;
devcb_resolved_read8 m_in_rd322_func;
+ devcb_resolved_read8 m_in_ram_func;
+ devcb_resolved_write8 m_out_ram_func;
- int m_select;
UINT8 m_status;
UINT8 m_mask;
- UINT8 m_ram[0x800];
offs_t m_ra;
};
View
1 src/mess/mess.mak
@@ -1738,6 +1738,7 @@ $(MESSOBJ)/zpa.a: \
$(MESS_MACHINE)/iq151cart.o \
$(MESS_MACHINE)/iq151_rom.o \
$(MESS_MACHINE)/iq151_disc2.o \
+ $(MESS_VIDEO)/iq151_grafik.o \
$(MESS_VIDEO)/iq151_video32.o \
$(MESS_VIDEO)/iq151_video64.o \
View
198 src/mess/video/iq151_grafik.c
@@ -0,0 +1,198 @@
+/***************************************************************************
+
+ IQ151 grafik emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_grafik.h"
+
+#define LOG 0
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static I8255_INTERFACE( grafik_ppi8255_intf )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_grafik_device, x_write),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_grafik_device, y_write),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_grafik_device, control_w),
+};
+
+static MACHINE_CONFIG_FRAGMENT( iq151_grafik )
+ MCFG_I8255_ADD("ppi8255", grafik_ppi8255_intf)
+MACHINE_CONFIG_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IQ151_GRAFIK = &device_creator<iq151_grafik_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// iq151_grafik_device - constructor
+//-------------------------------------------------
+
+iq151_grafik_device::iq151_grafik_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, IQ151_GRAFIK, "IQ151 grafik", tag, owner, clock),
+ device_iq151cart_interface( mconfig, *this ),
+ m_ppi8255(*this, "ppi8255")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void iq151_grafik_device::device_start()
+{
+ // allocate the videoram
+ m_videoram = (UINT8*)auto_alloc_array_clear(machine(), UINT8, 0x4000);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void iq151_grafik_device::device_reset()
+{
+ screen_device *screen = machine().primary_screen;
+
+ // if required adjust screen size
+ if (screen->visible_area().max_x < 64*8-1)
+ screen->set_visible_area(0, 64*8-1, 0, 32*8-1);
+
+ memset(m_videoram, 0x00, 0x4000);
+}
+
+//-------------------------------------------------
+// device_mconfig_additions
+//-------------------------------------------------
+
+machine_config_constructor iq151_grafik_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( iq151_grafik );
+}
+
+//-------------------------------------------------
+// I8255 port a
+//-------------------------------------------------
+
+WRITE8_MEMBER(iq151_grafik_device::x_write)
+{
+ if (LOG) logerror("Grafik: set posx 0x%02x\n", data);
+
+ m_posx = data & 0x3f;
+}
+
+//-------------------------------------------------
+// I8255 port b
+//-------------------------------------------------
+
+WRITE8_MEMBER(iq151_grafik_device::y_write)
+{
+ if (LOG) logerror("Grafik: set posy 0x%02x\n", data);
+
+ m_posy = data;
+}
+
+//-------------------------------------------------
+// I8255 port c
+//-------------------------------------------------
+
+WRITE8_MEMBER(iq151_grafik_device::control_w)
+{
+ if (LOG) logerror("Grafik: control write 0x%02x\n", data);
+
+ m_all = BIT(data, 0);
+ m_pen = BIT(data, 1);
+ m_fast = BIT(data, 2);
+ m_ev = BIT(data, 3);
+ m_ex = (data>>4) & 0x03;
+ m_sel = BIT(data, 7);
+}
+
+
+//-------------------------------------------------
+// IO read
+//-------------------------------------------------
+
+void iq151_grafik_device::io_read(offs_t offset, UINT8 &data)
+{
+ if (offset >= 0xd0 && offset < 0xd4)
+ {
+ address_space* space = machine().device("maincpu")->memory().space(AS_IO);
+ data = m_ppi8255->read(*space, offset & 3);
+ }
+ else if (offset == 0xd4)
+ {
+ if (LOG) logerror("Grafik: vram read 0x%04x\n", m_posx + 0x40 * m_posy);
+
+ if (m_sel)
+ data = m_videoram[m_posx + 0x40 * m_posy];
+ }
+}
+
+//-------------------------------------------------
+// IO write
+//-------------------------------------------------
+
+void iq151_grafik_device::io_write(offs_t offset, UINT8 data)
+{
+ if (offset >= 0xd0 && offset < 0xd4)
+ {
+ address_space* space = machine().device("maincpu")->memory().space(AS_IO);
+ m_ppi8255->write(*space, offset & 3, data);
+ }
+ else if (offset == 0xd4)
+ {
+ if (m_sel)
+ {
+ if (LOG) logerror("Grafik: vram write 0x%04x 0x%02x\n", m_posx + 0x40 * m_posy, data);
+
+ if (m_all)
+ {
+ m_videoram[m_posx + 0x40 * m_posy] = data;
+ }
+ else
+ {
+ if (m_pen)
+ m_videoram[m_posx + 0x40 * m_posy] &= ~(1 << (data >> 5));
+ else
+ m_videoram[m_posx + 0x40 * m_posy] |= (1 << (data >> 5));
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// video update
+//-------------------------------------------------
+
+void iq151_grafik_device::video_update(bitmap_t &bitmap, const rectangle &cliprect)
+{
+ if (m_ev)
+ {
+ for (int y = 0; y < 32*8; y++)
+ {
+ for (int x = 0; x < 64; x++)
+ {
+ for (int ra = 0; ra < 8; ra++)
+ {
+ *BITMAP_ADDR16(&bitmap, y, x*8 + ra) |= BIT(m_videoram[(32*8 -1 - y)*64 + x], ra);
+ }
+ }
+ }
+ }
+}
+
View
62 src/mess/video/iq151_grafik.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#ifndef __IQ151_GRAFIK_H__
+#define __IQ151_GRAFIK_H__
+
+#include "emu.h"
+#include "machine/iq151cart.h"
+#include "machine/i8255.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> iq151_grafik_device
+
+class iq151_grafik_device :
+ public device_t,
+ public device_iq151cart_interface
+{
+public:
+ // construction/destruction
+ iq151_grafik_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ // ppi8255 callback
+ DECLARE_WRITE8_MEMBER(x_write);
+ DECLARE_WRITE8_MEMBER(y_write);
+ DECLARE_WRITE8_MEMBER(control_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "iq151_grafik"; }
+
+ // iq151cart_interface overrides
+ virtual void io_read(offs_t offset, UINT8 &data);
+ virtual void io_write(offs_t offset, UINT8 data);
+ virtual void video_update(bitmap_t &bitmap, const rectangle &cliprect);
+
+private:
+
+ required_device<i8255_device> m_ppi8255;
+
+ UINT8 * m_videoram;
+ UINT8 m_posx; // horizontal position
+ UINT8 m_posy; // vertical position
+ UINT8 m_all; // 0: bit mode 1: byte mode
+ UINT8 m_pen;
+ UINT8 m_fast;
+ UINT8 m_ev; // enable video out
+ UINT8 m_ex;
+ UINT8 m_sel; // enable vram access
+};
+
+
+// device type definition
+extern const device_type IQ151_GRAFIK;
+
+#endif /* __IQ151_GRAFIK_H__ */
View
2 src/mess/video/iq151_video32.c
@@ -58,7 +58,7 @@ void iq151_video32_device::device_reset()
screen_device *screen = machine().primary_screen;
// if required adjust screen size
- if (screen->visible_area().max_y < 32*8 - 1)
+ if (screen->visible_area().max_x < 32*8 - 1)
screen->set_visible_area(0, 32*8-1, 0, 32*8-1);
}
View
2 src/mess/video/iq151_video64.c
@@ -58,7 +58,7 @@ void iq151_video64_device::device_reset()
screen_device *screen = machine().primary_screen;
// if required adjust screen size
- if (screen->visible_area().max_y < 64*6 - 1)
+ if (screen->visible_area().max_x < 64*6 - 1)
screen->set_visible_area(0, 64*6-1, 0, 32*8-1);
}

0 comments on commit 77a87fc

Please sign in to comment.
Something went wrong with that request. Please try again.