summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/gp32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/drivers/gp32.c')
-rw-r--r--src/mess/drivers/gp32.c1786
1 files changed, 1786 insertions, 0 deletions
diff --git a/src/mess/drivers/gp32.c b/src/mess/drivers/gp32.c
new file mode 100644
index 00000000000..7cdd196bd82
--- /dev/null
+++ b/src/mess/drivers/gp32.c
@@ -0,0 +1,1786 @@
+/**************************************************************************
+ *
+ * gp32.c - Game Park GP32
+ * Skeleton by R. Belmont
+ *
+ * CPU: Samsung S3C2400X01 SoC
+ * S3C2400X01 consists of:
+ * ARM920T CPU core + MMU
+ * LCD controller
+ * DMA controller
+ * Interrupt controller
+ * USB controller
+ * and more.
+ *
+ **************************************************************************/
+
+#include "emu.h"
+#include "cpu/arm7/arm7.h"
+#include "cpu/arm7/arm7core.h"
+#include "machine/smartmed.h"
+#include "includes/gp32.h"
+#include "sound/dac.h"
+#include "rendlay.h"
+#include "machine/nvram.h"
+
+#define VERBOSE_LEVEL ( 0 )
+
+INLINE void ATTR_PRINTF(3,4) verboselog( running_machine &machine, int n_level, const char *s_fmt, ...)
+{
+ if (VERBOSE_LEVEL >= n_level)
+ {
+ va_list v;
+ char buf[32768];
+ va_start( v, s_fmt);
+ vsprintf( buf, s_fmt, v);
+ va_end( v);
+ logerror( "%s: %s", machine.describe_context( ), buf);
+ }
+}
+
+#define CLOCK_MULTIPLIER 1
+
+#define MPLLCON 1
+#define UPLLCON 2
+
+#define BIT(x,n) (((x)>>(n))&1)
+#define BITS(x,m,n) (((x)>>(n))&((1<<((m)-(n)+1))-1))
+
+
+static UINT32 s3c240x_get_fclk(gp32_state *state, int reg);
+static UINT32 s3c240x_get_hclk(gp32_state *state, int reg);
+static UINT32 s3c240x_get_pclk(gp32_state *state, int reg);
+
+static void s3c240x_dma_request_iis( running_machine &machine);
+static void s3c240x_dma_request_pwm( running_machine &machine);
+
+// LCD CONTROLLER
+
+
+#define BPPMODE_TFT_01 0x08
+#define BPPMODE_TFT_02 0x09
+#define BPPMODE_TFT_04 0x0A
+#define BPPMODE_TFT_08 0x0B
+#define BPPMODE_TFT_16 0x0C
+
+static rgb_t s3c240x_get_color_5551( UINT16 data)
+{
+ UINT8 r, g, b, i;
+ r = BITS( data, 15, 11) << 3;
+ g = BITS( data, 10, 6) << 3;
+ b = BITS( data, 5, 1) << 3;
+ i = BIT( data, 1) << 2;
+ return MAKE_RGB( r | i, g | i, b | i);
+}
+
+static void s3c240x_lcd_dma_reload( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ state->m_s3c240x_lcd.vramaddr_cur = state->m_s3c240x_lcd_regs[5] << 1;
+ state->m_s3c240x_lcd.vramaddr_max = ((state->m_s3c240x_lcd_regs[5] & 0xFFE00000) | state->m_s3c240x_lcd_regs[6]) << 1;
+ state->m_s3c240x_lcd.offsize = BITS( state->m_s3c240x_lcd_regs[7], 21, 11);
+ state->m_s3c240x_lcd.pagewidth_cur = 0;
+ state->m_s3c240x_lcd.pagewidth_max = BITS( state->m_s3c240x_lcd_regs[7], 10, 0);
+ verboselog( machine, 3, "LCD - vramaddr %08X %08X offsize %08X pagewidth %08X\n", state->m_s3c240x_lcd.vramaddr_cur, state->m_s3c240x_lcd.vramaddr_max, state->m_s3c240x_lcd.offsize, state->m_s3c240x_lcd.pagewidth_max);
+}
+
+static void s3c240x_lcd_dma_init( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ s3c240x_lcd_dma_reload( machine);
+ state->m_s3c240x_lcd.bppmode = BITS( state->m_s3c240x_lcd_regs[0], 4, 1);
+ state->m_s3c240x_lcd.bswp = BIT( state->m_s3c240x_lcd_regs[4], 1);
+ state->m_s3c240x_lcd.hwswp = BIT( state->m_s3c240x_lcd_regs[4], 0);
+ state->m_s3c240x_lcd.lineval = BITS( state->m_s3c240x_lcd_regs[1], 23, 14);
+ state->m_s3c240x_lcd.hozval = BITS( state->m_s3c240x_lcd_regs[2], 18, 8);
+}
+
+static UINT32 s3c240x_lcd_dma_read( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ UINT8 *vram, data[4];
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ vram = (UINT8 *)state->m_s3c240x_ram.target() + state->m_s3c240x_lcd.vramaddr_cur - 0x0C000000;
+ data[i*2+0] = vram[0];
+ data[i*2+1] = vram[1];
+ state->m_s3c240x_lcd.vramaddr_cur += 2;
+ state->m_s3c240x_lcd.pagewidth_cur++;
+ if (state->m_s3c240x_lcd.pagewidth_cur >= state->m_s3c240x_lcd.pagewidth_max)
+ {
+ state->m_s3c240x_lcd.vramaddr_cur += state->m_s3c240x_lcd.offsize << 1;
+ state->m_s3c240x_lcd.pagewidth_cur = 0;
+ }
+ }
+ if (state->m_s3c240x_lcd.hwswp == 0)
+ {
+ if (state->m_s3c240x_lcd.bswp == 0)
+ {
+ return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0] << 0);
+ }
+ else
+ {
+ return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] << 0);
+ }
+ }
+ else
+ {
+ if (state->m_s3c240x_lcd.bswp == 0)
+ {
+ return (data[1] << 24) | (data[0] << 16) | (data[3] << 8) | (data[2] << 0);
+ }
+ else
+ {
+ return (data[2] << 24) | (data[3] << 16) | (data[0] << 8) | (data[1] << 0);
+ }
+ }
+}
+
+static void s3c240x_lcd_render_01( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ bitmap_rgb32 &bitmap = state->m_bitmap;
+ UINT32 *scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ int i, j;
+ for (i = 0; i < 4; i++)
+ {
+ UINT32 data = s3c240x_lcd_dma_read( machine);
+ for (j = 0; j < 32; j++)
+ {
+ *scanline++ = palette_get_color( machine, (data >> 31) & 0x01);
+ data = data << 1;
+ state->m_s3c240x_lcd.hpos++;
+ if (state->m_s3c240x_lcd.hpos >= (state->m_s3c240x_lcd.pagewidth_max << 4))
+ {
+ state->m_s3c240x_lcd.vpos = (state->m_s3c240x_lcd.vpos + 1) % (state->m_s3c240x_lcd.lineval + 1);
+ state->m_s3c240x_lcd.hpos = 0;
+ scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ }
+ }
+ }
+}
+
+static void s3c240x_lcd_render_02( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ bitmap_rgb32 &bitmap = state->m_bitmap;
+ UINT32 *scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ int i, j;
+ for (i = 0; i < 4; i++)
+ {
+ UINT32 data = s3c240x_lcd_dma_read( machine);
+ for (j = 0; j < 16; j++)
+ {
+ *scanline++ = palette_get_color( machine, (data >> 30) & 0x03);
+ data = data << 2;
+ state->m_s3c240x_lcd.hpos++;
+ if (state->m_s3c240x_lcd.hpos >= (state->m_s3c240x_lcd.pagewidth_max << 3))
+ {
+ state->m_s3c240x_lcd.vpos = (state->m_s3c240x_lcd.vpos + 1) % (state->m_s3c240x_lcd.lineval + 1);
+ state->m_s3c240x_lcd.hpos = 0;
+ scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ }
+ }
+ }
+}
+
+static void s3c240x_lcd_render_04( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ bitmap_rgb32 &bitmap = state->m_bitmap;
+ UINT32 *scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ int i, j;
+ for (i = 0; i < 4; i++)
+ {
+ UINT32 data = s3c240x_lcd_dma_read( machine);
+ for (j = 0; j < 8; j++)
+ {
+ *scanline++ = palette_get_color( machine, (data >> 28) & 0x0F);
+ data = data << 4;
+ state->m_s3c240x_lcd.hpos++;
+ if (state->m_s3c240x_lcd.hpos >= (state->m_s3c240x_lcd.pagewidth_max << 2))
+ {
+ state->m_s3c240x_lcd.vpos = (state->m_s3c240x_lcd.vpos + 1) % (state->m_s3c240x_lcd.lineval + 1);
+ state->m_s3c240x_lcd.hpos = 0;
+ scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ }
+ }
+ }
+}
+
+static void s3c240x_lcd_render_08( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ bitmap_rgb32 &bitmap = state->m_bitmap;
+ UINT32 *scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ int i, j;
+ for (i = 0; i < 4; i++)
+ {
+ UINT32 data = s3c240x_lcd_dma_read( machine);
+ for (j = 0; j < 4; j++)
+ {
+ *scanline++ = palette_get_color( machine, (data >> 24) & 0xFF);
+ data = data << 8;
+ state->m_s3c240x_lcd.hpos++;
+ if (state->m_s3c240x_lcd.hpos >= (state->m_s3c240x_lcd.pagewidth_max << 1))
+ {
+ state->m_s3c240x_lcd.vpos = (state->m_s3c240x_lcd.vpos + 1) % (state->m_s3c240x_lcd.lineval + 1);
+ state->m_s3c240x_lcd.hpos = 0;
+ scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ }
+ }
+ }
+}
+
+static void s3c240x_lcd_render_16( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ bitmap_rgb32 &bitmap = state->m_bitmap;
+ UINT32 *scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ int i, j;
+ for (i = 0; i < 4; i++)
+ {
+ UINT32 data = s3c240x_lcd_dma_read( machine);
+ for (j = 0; j < 2; j++)
+ {
+ *scanline++ = s3c240x_get_color_5551( (data >> 16) & 0xFFFF);
+ data = data << 16;
+ state->m_s3c240x_lcd.hpos++;
+ if (state->m_s3c240x_lcd.hpos >= (state->m_s3c240x_lcd.pagewidth_max << 0))
+ {
+ state->m_s3c240x_lcd.vpos = (state->m_s3c240x_lcd.vpos + 1) % (state->m_s3c240x_lcd.lineval + 1);
+ state->m_s3c240x_lcd.hpos = 0;
+ scanline = &bitmap.pix32(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ }
+ }
+ }
+}
+
+static TIMER_CALLBACK( s3c240x_lcd_timer_exp )
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ screen_device *screen = machine.primary_screen;
+ verboselog( machine, 2, "LCD timer callback\n");
+ state->m_s3c240x_lcd.vpos = screen->vpos();
+ state->m_s3c240x_lcd.hpos = screen->hpos();
+ verboselog( machine, 3, "LCD - vpos %d hpos %d\n", state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos);
+ if (state->m_s3c240x_lcd.vramaddr_cur >= state->m_s3c240x_lcd.vramaddr_max)
+ {
+ s3c240x_lcd_dma_reload( machine);
+ }
+ verboselog( machine, 3, "LCD - vramaddr %08X\n", state->m_s3c240x_lcd.vramaddr_cur);
+ while (state->m_s3c240x_lcd.vramaddr_cur < state->m_s3c240x_lcd.vramaddr_max)
+ {
+ switch (state->m_s3c240x_lcd.bppmode)
+ {
+ case BPPMODE_TFT_01 : s3c240x_lcd_render_01( machine); break;
+ case BPPMODE_TFT_02 : s3c240x_lcd_render_02( machine); break;
+ case BPPMODE_TFT_04 : s3c240x_lcd_render_04( machine); break;
+ case BPPMODE_TFT_08 : s3c240x_lcd_render_08( machine); break;
+ case BPPMODE_TFT_16 : s3c240x_lcd_render_16( machine); break;
+ default : verboselog( machine, 0, "s3c240x_lcd_timer_exp: bppmode %d not supported\n", state->m_s3c240x_lcd.bppmode); break;
+ }
+ if ((state->m_s3c240x_lcd.vpos == 0) && (state->m_s3c240x_lcd.hpos == 0)) break;
+ }
+ state->m_s3c240x_lcd_timer->adjust( screen->time_until_pos(state->m_s3c240x_lcd.vpos, state->m_s3c240x_lcd.hpos));
+}
+
+void gp32_state::video_start()
+{
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+static SCREEN_UPDATE_RGB32( gp32 )
+{
+ gp32_state *state = screen.machine().driver_data<gp32_state>();
+ running_machine &machine = screen.machine();
+ copybitmap(bitmap, state->m_bitmap, 0, 0, 0, 0, cliprect);
+ s3c240x_lcd_dma_init( machine);
+ return 0;
+}
+
+READ32_MEMBER(gp32_state::s3c240x_lcd_r)
+{
+ UINT32 data = m_s3c240x_lcd_regs[offset];
+ switch (offset)
+ {
+ // LCDCON1
+ case 0x00 / 4 :
+ {
+ // make sure line counter is going
+ UINT32 lineval = BITS( m_s3c240x_lcd_regs[1], 23, 14);
+ data = (data & ~0xFFFC0000) | ((lineval - machine().primary_screen->vpos()) << 18);
+ }
+ break;
+ }
+ verboselog( machine(), 9, "(LCD) %08X -> %08X (PC %08X)\n", 0x14A00000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+static void s3c240x_lcd_configure( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ screen_device *screen = machine.primary_screen;
+ UINT32 vspw, vbpd, lineval, vfpd, hspw, hbpd, hfpd, hozval, clkval, hclk;
+ double framerate, vclk;
+ rectangle visarea;
+ vspw = BITS( state->m_s3c240x_lcd_regs[1], 5, 0);
+ vbpd = BITS( state->m_s3c240x_lcd_regs[1], 31, 24);
+ lineval = BITS( state->m_s3c240x_lcd_regs[1], 23, 14);
+ vfpd = BITS( state->m_s3c240x_lcd_regs[1], 13, 6);
+ hspw = BITS( state->m_s3c240x_lcd_regs[3], 7, 0);
+ hbpd = BITS( state->m_s3c240x_lcd_regs[2], 25, 19);
+ hfpd = BITS( state->m_s3c240x_lcd_regs[2], 7, 0);
+ hozval = BITS( state->m_s3c240x_lcd_regs[2], 18, 8);
+ clkval = BITS( state->m_s3c240x_lcd_regs[0], 17, 8);
+ hclk = s3c240x_get_hclk(state, MPLLCON);
+ verboselog( machine, 3, "LCD - vspw %d vbpd %d lineval %d vfpd %d hspw %d hbpd %d hfpd %d hozval %d clkval %d hclk %d\n", vspw, vbpd, lineval, vfpd, hspw, hbpd, hfpd, hozval, clkval, hclk);
+ vclk = (double)(hclk / ((clkval + 1) * 2));
+ verboselog( machine, 3, "LCD - vclk %f\n", vclk);
+ framerate = vclk / (((vspw + 1) + (vbpd + 1) + (lineval + 1) + (vfpd + 1)) * ((hspw + 1) + (hbpd + 1) + (hfpd + 1) + (hozval + 1)));
+ verboselog( machine, 3, "LCD - framerate %f\n", framerate);
+ visarea.set(0, hozval, 0, lineval);
+ verboselog( machine, 3, "LCD - visarea min_x %d min_y %d max_x %d max_y %d\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
+ screen->configure(hozval + 1, lineval + 1, visarea, HZ_TO_ATTOSECONDS( framerate));
+}
+
+static void s3c240x_lcd_start( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ screen_device *screen = machine.primary_screen;
+ verboselog( machine, 1, "LCD start\n");
+ s3c240x_lcd_configure( machine);
+ s3c240x_lcd_dma_init( machine);
+ state->m_s3c240x_lcd_timer->adjust( screen->time_until_pos(0, 0));
+}
+
+static void s3c240x_lcd_stop( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 1, "LCD stop\n");
+ state->m_s3c240x_lcd_timer->adjust( attotime::never);
+}
+
+static void s3c240x_lcd_recalc( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ if (state->m_s3c240x_lcd_regs[0] & 1)
+ {
+ s3c240x_lcd_start( machine);
+ }
+ else
+ {
+ s3c240x_lcd_stop( machine);
+ }
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_lcd_w)
+{
+ UINT32 old_value = m_s3c240x_lcd_regs[offset];
+ verboselog( machine(), 9, "(LCD) %08X <- %08X (PC %08X)\n", 0x14A00000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_lcd_regs[offset]);
+ switch (offset)
+ {
+ // LCDCON1
+ case 0x00 / 4 :
+ {
+ if ((old_value & 1) != (data & 1))
+ {
+ s3c240x_lcd_recalc( machine());
+ }
+ }
+ break;
+ }
+}
+
+// LCD PALETTE
+
+
+READ32_MEMBER(gp32_state::s3c240x_lcd_palette_r)
+{
+ UINT32 data = m_s3c240x_lcd_palette[offset];
+ verboselog( machine(), 9, "(LCD) %08X -> %08X (PC %08X)\n", 0x14A00400 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_lcd_palette_w)
+{
+ verboselog( machine(), 9, "(LCD) %08X <- %08X (PC %08X)\n", 0x14A00400 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_lcd_palette[offset]);
+ if (mem_mask != 0xffffffff)
+ {
+ verboselog( machine(), 0, "s3c240x_lcd_palette_w: unknown mask %08x\n", mem_mask);
+ }
+ palette_set_color( machine(), offset, s3c240x_get_color_5551( data & 0xFFFF));
+}
+
+// CLOCK & POWER MANAGEMENT
+
+
+static UINT32 s3c240x_get_fclk(gp32_state *state, int reg)
+{
+ UINT32 data, mdiv, pdiv, sdiv;
+ data = state->m_s3c240x_clkpow_regs[reg]; // MPLLCON or UPLLCON
+ mdiv = BITS( data, 19, 12);
+ pdiv = BITS( data, 9, 4);
+ sdiv = BITS( data, 1, 0);
+ return (UINT32)((double)((mdiv + 8) * 12000000) / (double)((pdiv + 2) * (1 << sdiv)));
+}
+
+static UINT32 s3c240x_get_hclk(gp32_state *state, int reg)
+{
+ switch (state->m_s3c240x_clkpow_regs[5] & 0x3) // CLKDIVN
+ {
+ case 0 : return s3c240x_get_fclk(state, reg) / 1;
+ case 1 : return s3c240x_get_fclk(state, reg) / 1;
+ case 2 : return s3c240x_get_fclk(state, reg) / 2;
+ case 3 : return s3c240x_get_fclk(state, reg) / 2;
+ }
+ return 0;
+}
+
+static UINT32 s3c240x_get_pclk(gp32_state *state, int reg)
+{
+ switch (state->m_s3c240x_clkpow_regs[5] & 0x3) // CLKDIVN
+ {
+ case 0 : return s3c240x_get_fclk(state, reg) / 1;
+ case 1 : return s3c240x_get_fclk(state, reg) / 2;
+ case 2 : return s3c240x_get_fclk(state, reg) / 2;
+ case 3 : return s3c240x_get_fclk(state, reg) / 4;
+ }
+ return 0;
+}
+
+READ32_MEMBER(gp32_state::s3c240x_clkpow_r)
+{
+ UINT32 data = m_s3c240x_clkpow_regs[offset];
+ verboselog( machine(), 9, "(CLKPOW) %08X -> %08X (PC %08X)\n", 0x14800000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_clkpow_w)
+{
+ verboselog( machine(), 9, "(CLKPOW) %08X <- %08X (PC %08X)\n", 0x14800000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_clkpow_regs[offset]);
+ switch (offset)
+ {
+ // MPLLCON
+ case 0x04 / 4 :
+ {
+ gp32_state *state = machine().driver_data<gp32_state>();
+ machine().device("maincpu")->set_unscaled_clock(s3c240x_get_fclk(state, MPLLCON) * CLOCK_MULTIPLIER);
+ }
+ break;
+ }
+}
+
+// INTERRUPT CONTROLLER
+
+
+static void s3c240x_check_pending_irq( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ if (state->m_s3c240x_irq_regs[0] != 0)
+ {
+ UINT32 int_type = 0, temp;
+ temp = state->m_s3c240x_irq_regs[0];
+ while (!(temp & 1))
+ {
+ int_type++;
+ temp = temp >> 1;
+ }
+ state->m_s3c240x_irq_regs[4] |= (1 << int_type); // INTPND
+ state->m_s3c240x_irq_regs[5] = int_type; // INTOFFSET
+ device_set_input_line( machine.device( "maincpu"), ARM7_IRQ_LINE, ASSERT_LINE);
+ }
+ else
+ {
+ device_set_input_line( machine.device( "maincpu"), ARM7_IRQ_LINE, CLEAR_LINE);
+ }
+}
+
+static void s3c240x_request_irq( running_machine &machine, UINT32 int_type)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 5, "request irq %d\n", int_type);
+ if (state->m_s3c240x_irq_regs[0] == 0)
+ {
+ state->m_s3c240x_irq_regs[0] |= (1 << int_type); // SRCPND
+ state->m_s3c240x_irq_regs[4] |= (1 << int_type); // INTPND
+ state->m_s3c240x_irq_regs[5] = int_type; // INTOFFSET
+ device_set_input_line( machine.device( "maincpu"), ARM7_IRQ_LINE, ASSERT_LINE);
+ }
+ else
+ {
+ state->m_s3c240x_irq_regs[0] |= (1 << int_type); // SRCPND
+ s3c240x_check_pending_irq( machine);
+ }
+}
+
+
+READ32_MEMBER(gp32_state::s3c240x_irq_r)
+{
+ UINT32 data = m_s3c240x_irq_regs[offset];
+ verboselog( machine(), 9, "(IRQ) %08X -> %08X (PC %08X)\n", 0x14400000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_irq_w)
+{
+ UINT32 old_value = m_s3c240x_irq_regs[offset];
+ verboselog( machine(), 9, "(IRQ) %08X <- %08X (PC %08X)\n", 0x14400000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_irq_regs[offset]);
+ switch (offset)
+ {
+ // SRCPND
+ case 0x00 / 4 :
+ {
+ m_s3c240x_irq_regs[0] = (old_value & ~data); // clear only the bit positions of SRCPND corresponding to those set to one in the data
+ s3c240x_check_pending_irq( machine());
+ }
+ break;
+ // INTPND
+ case 0x10 / 4 :
+ {
+ m_s3c240x_irq_regs[4] = (old_value & ~data); // clear only the bit positions of INTPND corresponding to those set to one in the data
+ }
+ break;
+ }
+}
+
+// PWM TIMER
+
+#if 0
+static const char *const timer_reg_names[] =
+{
+ "Timer config 0",
+ "Timer config 1",
+ "Timer control",
+ "Timer count buffer 0",
+ "Timer compare buffer 0",
+ "Timer count observation 0",
+ "Timer count buffer 1",
+ "Timer compare buffer 1",
+ "Timer count observation 1",
+ "Timer count buffer 2",
+ "Timer compare buffer 2",
+ "Timer count observation 2",
+ "Timer count buffer 3",
+ "Timer compare buffer 3",
+ "Timer count observation 3",
+ "Timer count buffer 4",
+ "Timer compare buffer 4",
+ "Timer count observation 4",
+};
+#endif
+
+
+READ32_MEMBER(gp32_state::s3c240x_pwm_r)
+{
+ UINT32 data = m_s3c240x_pwm_regs[offset];
+ verboselog( machine(), 9, "(PWM) %08X -> %08X (PC %08X)\n", 0x15100000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+static void s3c240x_pwm_start( running_machine &machine, int timer)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ static const int mux_table[] = { 2, 4, 8, 16 };
+ static const int prescaler_shift[] = { 0, 0, 8, 8, 8 };
+ static const int mux_shift[] = { 0, 4, 8, 12, 16 };
+ static const int tcon_shift[] = { 0, 8, 12, 16, 20 };
+ const UINT32 *regs = &state->m_s3c240x_pwm_regs[3+timer*3];
+ UINT32 prescaler, mux, cnt, cmp, auto_reload;
+ double freq, hz;
+ verboselog( machine, 1, "PWM %d start\n", timer);
+ prescaler = (state->m_s3c240x_pwm_regs[0] >> prescaler_shift[timer]) & 0xFF;
+ mux = (state->m_s3c240x_pwm_regs[1] >> mux_shift[timer]) & 0x0F;
+ freq = s3c240x_get_pclk(state, MPLLCON) / (prescaler + 1) / mux_table[mux];
+ cnt = BITS( regs[0], 15, 0);
+ if (timer != 4)
+ {
+ cmp = BITS( regs[1], 15, 0);
+ auto_reload = BIT( state->m_s3c240x_pwm_regs[2], tcon_shift[timer] + 3);
+ }
+ else
+ {
+ cmp = 0;
+ auto_reload = BIT( state->m_s3c240x_pwm_regs[2], tcon_shift[timer] + 2);
+ }
+ hz = freq / (cnt - cmp + 1);
+ verboselog( machine, 5, "PWM %d - FCLK=%d HCLK=%d PCLK=%d prescaler=%d div=%d freq=%f cnt=%d cmp=%d auto_reload=%d hz=%f\n", timer, s3c240x_get_fclk(state, MPLLCON), s3c240x_get_hclk(state, MPLLCON), s3c240x_get_pclk(state, MPLLCON), prescaler, mux_table[mux], freq, cnt, cmp, auto_reload, hz);
+ if (auto_reload)
+ {
+ state->m_s3c240x_pwm_timer[timer]->adjust( attotime::from_hz( hz), timer, attotime::from_hz( hz));
+ }
+ else
+ {
+ state->m_s3c240x_pwm_timer[timer]->adjust( attotime::from_hz( hz), timer);
+ }
+}
+
+static void s3c240x_pwm_stop( running_machine &machine, int timer)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 1, "PWM %d stop\n", timer);
+ state->m_s3c240x_pwm_timer[timer]->adjust( attotime::never);
+}
+
+static void s3c240x_pwm_recalc( running_machine &machine, int timer)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ static const int tcon_shift[] = { 0, 8, 12, 16, 20 };
+ if (state->m_s3c240x_pwm_regs[2] & (1 << tcon_shift[timer]))
+ {
+ s3c240x_pwm_start( machine, timer);
+ }
+ else
+ {
+ s3c240x_pwm_stop( machine, timer);
+ }
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_pwm_w)
+{
+ UINT32 old_value = m_s3c240x_pwm_regs[offset];
+ verboselog( machine(), 9, "(PWM) %08X <- %08X (PC %08X)\n", 0x15100000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_pwm_regs[offset]);
+ switch (offset)
+ {
+ // TCON
+ case 0x08 / 4 :
+ {
+ if ((data & 1) != (old_value & 1))
+ {
+ s3c240x_pwm_recalc( machine(), 0);
+ }
+ if ((data & 0x100) != (old_value & 0x100))
+ {
+ s3c240x_pwm_recalc( machine(), 1);
+ }
+ if ((data & 0x1000) != (old_value & 0x1000))
+ {
+ s3c240x_pwm_recalc( machine(), 2);
+ }
+ if ((data & 0x10000) != (old_value & 0x10000))
+ {
+ s3c240x_pwm_recalc( machine(), 3);
+ }
+ if ((data & 0x100000) != (old_value & 0x100000))
+ {
+ s3c240x_pwm_recalc( machine(), 4);
+ }
+ }
+ }
+}
+
+static TIMER_CALLBACK( s3c240x_pwm_timer_exp )
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ int ch = param;
+ static const int ch_int[] = { INT_TIMER0, INT_TIMER1, INT_TIMER2, INT_TIMER3, INT_TIMER4 };
+ verboselog( machine, 2, "PWM %d timer callback\n", ch);
+ if (BITS( state->m_s3c240x_pwm_regs[1], 23, 20) == (ch + 1))
+ {
+ s3c240x_dma_request_pwm( machine);
+ }
+ else
+ {
+ s3c240x_request_irq( machine, ch_int[ch]);
+ }
+}
+
+// DMA
+
+
+static void s3c240x_dma_reload( running_machine &machine, int dma)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ UINT32 *regs = &state->m_s3c240x_dma_regs[dma<<3];
+ regs[3] = (regs[3] & ~0x000FFFFF) | BITS( regs[2], 19, 0);
+ regs[4] = (regs[4] & ~0x1FFFFFFF) | BITS( regs[0], 28, 0);
+ regs[5] = (regs[5] & ~0x1FFFFFFF) | BITS( regs[1], 28, 0);
+}
+
+static void s3c240x_dma_trigger( running_machine &machine, int dma)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ UINT32 *regs = &state->m_s3c240x_dma_regs[dma<<3];
+ UINT32 curr_tc, curr_src, curr_dst;
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM);
+ int dsz, inc_src, inc_dst, servmode;
+ static const UINT32 ch_int[] = { INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3 };
+ verboselog( machine, 5, "DMA %d trigger\n", dma);
+ curr_tc = BITS( regs[3], 19, 0);
+ curr_src = BITS( regs[4], 28, 0);
+ curr_dst = BITS( regs[5], 28, 0);
+ dsz = BITS( regs[2], 21, 20);
+ servmode = BIT( regs[2], 26);
+ inc_src = BIT( regs[0], 29);
+ inc_dst = BIT( regs[1], 29);
+ verboselog( machine, 5, "DMA %d - curr_src %08X curr_dst %08X curr_tc %d dsz %d\n", dma, curr_src, curr_dst, curr_tc, dsz);
+ while (curr_tc > 0)
+ {
+ curr_tc--;
+ switch (dsz)
+ {
+ case 0 : space->write_byte( curr_dst, space->read_byte( curr_src)); break;
+ case 1 : space->write_word( curr_dst, space->read_word( curr_src)); break;
+ case 2 : space->write_dword( curr_dst, space->read_dword( curr_src)); break;
+ }
+ if (inc_src == 0) curr_src += (1 << dsz);
+ if (inc_dst == 0) curr_dst += (1 << dsz);
+ if (servmode == 0) break;
+ }
+ // update curr_src
+ regs[4] = (regs[4] & ~0x1FFFFFFF) | curr_src;
+ // update curr_dst
+ regs[5] = (regs[5] & ~0x1FFFFFFF) | curr_dst;
+ // update curr_tc
+ regs[3] = (regs[3] & ~0x000FFFFF) | curr_tc;
+ // ...
+ if (curr_tc == 0)
+ {
+ int _int, reload;
+ reload = BIT( regs[2], 22);
+ if (!reload)
+ {
+ s3c240x_dma_reload( machine, dma);
+ }
+ else
+ {
+ regs[6] &= ~(1 << 1); // clear on/off
+ }
+ _int = BIT( regs[2], 28);
+ if (_int)
+ {
+ s3c240x_request_irq( machine, ch_int[dma]);
+ }
+ }
+}
+
+static void s3c240x_dma_request_iis( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ UINT32 *regs = &state->m_s3c240x_dma_regs[2<<3];
+ verboselog( machine, 5, "s3c240x_dma_request_iis\n");
+ if ((BIT( regs[6], 1) != 0) && (BIT( regs[2], 23) != 0) && (BITS( regs[2], 25, 24) == 0))
+ {
+ s3c240x_dma_trigger( machine, 2);
+ }
+}
+
+static void s3c240x_dma_request_pwm( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ int i;
+ verboselog( machine, 5, "s3c240x_dma_request_pwm\n");
+ for (i = 0; i < 4; i++)
+ {
+ if (i != 1)
+ {
+ UINT32 *regs = &state->m_s3c240x_dma_regs[i<<3];
+ if ((BIT( regs[6], 1) != 0) && (BIT( regs[2], 23) != 0) && (BITS( regs[2], 25, 24) == 3))
+ {
+ s3c240x_dma_trigger( machine, i);
+ }
+ }
+ }
+}
+
+static void s3c240x_dma_start( running_machine &machine, int dma)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ UINT32 addr_src, addr_dst, tc;
+ UINT32 *regs = &state->m_s3c240x_dma_regs[dma<<3];
+ UINT32 dsz, tsz, reload;
+ int inc_src, inc_dst, _int, servmode, swhwsel, hwsrcsel;
+ verboselog( machine, 1, "DMA %d start\n", dma);
+ addr_src = BITS( regs[0], 28, 0);
+ addr_dst = BITS( regs[1], 28, 0);
+ tc = BITS( regs[2], 19, 0);
+ inc_src = BIT( regs[0], 29);
+ inc_dst = BIT( regs[1], 29);
+ tsz = BIT( regs[2], 27);
+ _int = BIT( regs[2], 28);
+ servmode = BIT( regs[2], 26);
+ hwsrcsel = BITS( regs[2], 25, 24);
+ swhwsel = BIT( regs[2], 23);
+ reload = BIT( regs[2], 22);
+ dsz = BITS( regs[2], 21, 20);
+ verboselog( machine, 5, "DMA %d - addr_src %08X inc_src %d addr_dst %08X inc_dst %d int %d tsz %d servmode %d hwsrcsel %d swhwsel %d reload %d dsz %d tc %d\n", dma, addr_src, inc_src, addr_dst, inc_dst, _int, tsz, servmode, hwsrcsel, swhwsel, reload, dsz, tc);
+ verboselog( machine, 5, "DMA %d - copy %08X bytes from %08X (%s) to %08X (%s)\n", dma, tc << dsz, addr_src, inc_src ? "fix" : "inc", addr_dst, inc_dst ? "fix" : "inc");
+ s3c240x_dma_reload( machine, dma);
+ if (swhwsel == 0)
+ {
+ s3c240x_dma_trigger( machine, dma);
+ }
+}
+
+static void s3c240x_dma_stop( running_machine &machine, int dma)
+{
+ verboselog( machine, 1, "DMA %d stop\n", dma);
+}
+
+static void s3c240x_dma_recalc( running_machine &machine, int dma)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ if (state->m_s3c240x_dma_regs[(dma<<3)+6] & 2)
+ {
+ s3c240x_dma_start( machine, dma);
+ }
+ else
+ {
+ s3c240x_dma_stop( machine, dma);
+ }
+}
+
+READ32_MEMBER(gp32_state::s3c240x_dma_r)
+{
+ UINT32 data = m_s3c240x_dma_regs[offset];
+ verboselog( machine(), 9, "(DMA) %08X -> %08X (PC %08X)\n", 0x14600000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_dma_w)
+{
+ UINT32 old_value = m_s3c240x_dma_regs[offset];
+ verboselog( machine(), 9, "(DMA) %08X <- %08X (PC %08X)\n", 0x14600000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_dma_regs[offset]);
+ switch (offset)
+ {
+ // DCON0
+ case 0x08 / 4 :
+ {
+ if (((data >> 22) & 1) != 0) // reload
+ {
+ m_s3c240x_dma_regs[0x18/4] &= ~(1 << 1); // clear on/off
+ }
+ }
+ break;
+ // DMASKTRIG0
+ case 0x18 / 4 :
+ {
+ if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc( machine(), 0);
+ }
+ break;
+ // DCON1
+ case 0x28 / 4 :
+ {
+ if (((data >> 22) & 1) != 0) // reload
+ {
+ m_s3c240x_dma_regs[0x38/4] &= ~(1 << 1); // clear on/off
+ }
+ }
+ break;
+ // DMASKTRIG1
+ case 0x38 / 4 :
+ {
+ if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc( machine(), 1);
+ }
+ break;
+ // DCON2
+ case 0x48 / 4 :
+ {
+ if (((data >> 22) & 1) != 0) // reload
+ {
+ m_s3c240x_dma_regs[0x58/4] &= ~(1 << 1); // clear on/off
+ }
+ }
+ break;
+ // DMASKTRIG2
+ case 0x58 / 4 :
+ {
+ if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc( machine(), 2);
+ }
+ break;
+ // DCON3
+ case 0x68 / 4 :
+ {
+ if (((data >> 22) & 1) != 0) // reload
+ {
+ m_s3c240x_dma_regs[0x78/4] &= ~(1 << 1); // clear on/off
+ }
+ }
+ break;
+ // DMASKTRIG3
+ case 0x78 / 4 :
+ {
+ if ((old_value & 2) != (data & 2)) s3c240x_dma_recalc( machine(), 3);
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c240x_dma_timer_exp )
+{
+ int ch = param;
+ verboselog( machine, 2, "DMA %d timer callback\n", ch);
+}
+
+// SMARTMEDIA
+
+static void smc_reset( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 5, "smc_reset\n");
+ state->m_smc.add_latch = 0;
+ state->m_smc.chip = 0;
+ state->m_smc.cmd_latch = 0;
+ state->m_smc.do_read = 0;
+ state->m_smc.do_write = 0;
+ state->m_smc.read = 0;
+ state->m_smc.wp = 0;
+ state->m_smc.busy = 0;
+}
+
+static void smc_init( running_machine &machine)
+{
+ verboselog( machine, 5, "smc_init\n");
+ smc_reset( machine);
+}
+
+static UINT8 smc_read( running_machine &machine)
+{
+ smartmedia_image_device *smartmedia = machine.device<smartmedia_image_device>( "smartmedia");
+ UINT8 data;
+ data = smartmedia->data_r();
+ verboselog( machine, 5, "smc_read %08X\n", data);
+ return data;
+}
+
+static void smc_write( running_machine &machine, UINT8 data)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 5, "smc_write %08X\n", data);
+ if ((state->m_smc.chip) && (!state->m_smc.read))
+ {
+ smartmedia_image_device *smartmedia = machine.device<smartmedia_image_device>( "smartmedia");
+ if (state->m_smc.cmd_latch)
+ {
+ verboselog( machine, 5, "smartmedia_command_w %08X\n", data);
+ smartmedia->command_w(data);
+ }
+ else if (state->m_smc.add_latch)
+ {
+ verboselog( machine, 5, "smartmedia_address_w %08X\n", data);
+ smartmedia->address_w(data);
+ }
+ else
+ {
+ verboselog( machine, 5, "smartmedia_data_w %08X\n", data);
+ smartmedia->data_w(data);
+ }
+ }
+}
+
+static void smc_update( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ if (!state->m_smc.chip)
+ {
+ smc_reset( machine);
+ }
+ else
+ {
+ if ((state->m_smc.do_write) && (!state->m_smc.read))
+ {
+ smc_write( machine, state->m_smc.datatx);
+ }
+ else if ((!state->m_smc.do_write) && (state->m_smc.do_read) && (state->m_smc.read) && (!state->m_smc.cmd_latch) && (!state->m_smc.add_latch))
+ {
+ state->m_smc.datarx = smc_read( machine);
+ }
+ }
+}
+
+// I2S
+
+#define I2S_L3C ( 1 )
+#define I2S_L3M ( 2 )
+#define I2S_L3D ( 3 )
+
+static void i2s_reset( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 5, "i2s_reset\n");
+ state->m_i2s.l3d = 0;
+ state->m_i2s.l3m = 0;
+ state->m_i2s.l3c = 0;
+}
+
+static void i2s_init( running_machine &machine)
+{
+ verboselog( machine, 5, "i2s_init\n");
+ i2s_reset( machine);
+}
+
+static void i2s_write( running_machine &machine, int line, int data)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ switch (line)
+ {
+ case I2S_L3C :
+ {
+ if (data != state->m_i2s.l3c)
+ {
+ verboselog( machine, 5, "I2S L3C %d\n", data);
+ state->m_i2s.l3c = data;
+ }
+ }
+ break;
+ case I2S_L3M :
+ {
+ if (data != state->m_i2s.l3m)
+ {
+ verboselog( machine, 5, "I2S L3M %d\n", data);
+ state->m_i2s.l3m = data;
+ }
+ }
+ break;
+ case I2S_L3D :
+ {
+ if (data != state->m_i2s.l3d)
+ {
+ verboselog( machine, 5, "I2S L3D %d\n", data);
+ state->m_i2s.l3d = data;
+ }
+ }
+ break;
+ }
+}
+
+// I/O PORT
+
+
+READ32_MEMBER(gp32_state::s3c240x_gpio_r)
+{
+ UINT32 data = m_s3c240x_gpio[offset];
+ switch (offset)
+ {
+ // PBCON
+ case 0x08 / 4 :
+ {
+ // smartmedia
+ data = (data & ~0x00000001);
+ if (!m_smc.read) data = data | 0x00000001;
+ }
+ break;
+ // PBDAT
+ case 0x0C / 4 :
+ {
+ // smartmedia
+ data = (data & ~0x000000FF) | (m_smc.datarx & 0xFF);
+ // buttons
+ data = (data & ~0x0000FF00) | (ioport( "IN0")->read() & 0x0000FF00);
+ }
+ break;
+ // PDDAT
+ case 0x24 / 4 :
+ {
+ smartmedia_image_device *smartmedia = machine().device<smartmedia_image_device>( "smartmedia");
+ // smartmedia
+ data = (data & ~0x000003C0);
+ if (!m_smc.busy) data = data | 0x00000200;
+ if (!m_smc.do_read) data = data | 0x00000100;
+ if (!m_smc.chip) data = data | 0x00000080;
+ if (!smartmedia->is_protected()) data = data | 0x00000040;
+ }
+ break;
+ // PEDAT
+ case 0x30 / 4 :
+ {
+ smartmedia_image_device *smartmedia = machine().device<smartmedia_image_device>( "smartmedia");
+ // smartmedia
+ data = (data & ~0x0000003C);
+ if (m_smc.cmd_latch) data = data | 0x00000020;
+ if (m_smc.add_latch) data = data | 0x00000010;
+ if (!m_smc.do_write) data = data | 0x00000008;
+ if (!smartmedia->is_present()) data = data | 0x00000004;
+ // buttons
+ data = (data & ~0x000000C0) | (ioport( "IN1")->read() & 0x000000C0);
+ }
+ break;
+ }
+ verboselog( machine(), 9, "(GPIO) %08X -> %08X (PC %08X)\n", 0x15600000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_gpio_w)
+{
+ COMBINE_DATA(&m_s3c240x_gpio[offset]);
+ verboselog( machine(), 9, "(GPIO) %08X <- %08X (PC %08X)\n", 0x15600000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ switch (offset)
+ {
+ // PBCON
+ case 0x08 / 4 :
+ {
+ // smartmedia
+ m_smc.read = ((data & 0x00000001) == 0);
+ smc_update( machine());
+ }
+ break;
+ // PBDAT
+ case 0x0C / 4 :
+ {
+ // smartmedia
+ m_smc.datatx = data & 0xFF;
+ }
+ break;
+ // PDDAT
+ case 0x24 / 4 :
+ {
+ // smartmedia
+ m_smc.do_read = ((data & 0x00000100) == 0);
+ m_smc.chip = ((data & 0x00000080) == 0);
+ m_smc.wp = ((data & 0x00000040) == 0);
+ smc_update( machine());
+ }
+ break;
+ // PEDAT
+ case 0x30 / 4 :
+ {
+ // smartmedia
+ m_smc.cmd_latch = ((data & 0x00000020) != 0);
+ m_smc.add_latch = ((data & 0x00000010) != 0);
+ m_smc.do_write = ((data & 0x00000008) == 0);
+ smc_update( machine());
+ // sound
+ i2s_write( machine(), I2S_L3D, (data & 0x00000800) ? 1 : 0);
+ i2s_write( machine(), I2S_L3M, (data & 0x00000400) ? 1 : 0);
+ i2s_write( machine(), I2S_L3C, (data & 0x00000200) ? 1 : 0);
+ }
+ break;
+#if 0
+ // PGDAT
+ case 0x48 / 4 :
+ {
+ int i2ssdo;
+ i2ssdo = BIT( data, 3);
+ }
+ break;
+#endif
+ }
+}
+
+// MEMORY CONTROLLER
+
+
+READ32_MEMBER(gp32_state::s3c240x_memcon_r)
+{
+ UINT32 data = m_s3c240x_memcon_regs[offset];
+ verboselog( machine(), 9, "(MEMCON) %08X -> %08X (PC %08X)\n", 0x14000000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_memcon_w)
+{
+ verboselog( machine(), 9, "(MEMCON) %08X <- %08X (PC %08X)\n", 0x14000000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_memcon_regs[offset]);
+}
+
+// USB HOST CONTROLLER
+
+
+READ32_MEMBER(gp32_state::s3c240x_usb_host_r)
+{
+ UINT32 data = m_s3c240x_usb_host_regs[offset];
+ verboselog( machine(), 9, "(USB H) %08X -> %08X (PC %08X)\n", 0x14200000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_usb_host_w)
+{
+ verboselog( machine(), 9, "(USB H) %08X <- %08X (PC %08X)\n", 0x14200000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_usb_host_regs[offset]);
+}
+
+// UART 0
+
+
+READ32_MEMBER(gp32_state::s3c240x_uart_0_r)
+{
+ UINT32 data = m_s3c240x_uart_0_regs[offset];
+ switch (offset)
+ {
+ // UTRSTAT0
+ case 0x10 / 4 :
+ {
+ data = (data & ~0x00000006) | 0x00000004 | 0x00000002; // [bit 2] Transmitter empty / [bit 1] Transmit buffer empty
+ }
+ break;
+ }
+ verboselog( machine(), 9, "(UART 0) %08X -> %08X (PC %08X)\n", 0x15000000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_uart_0_w)
+{
+ verboselog( machine(), 9, "(UART 0) %08X <- %08X (PC %08X)\n", 0x15000000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_uart_0_regs[offset]);
+}
+
+// UART 1
+
+
+READ32_MEMBER(gp32_state::s3c240x_uart_1_r)
+{
+ UINT32 data = m_s3c240x_uart_1_regs[offset];
+ switch (offset)
+ {
+ // UTRSTAT1
+ case 0x10 / 4 :
+ {
+ data = (data & ~0x00000006) | 0x00000004 | 0x00000002; // [bit 2] Transmitter empty / [bit 1] Transmit buffer empty
+ }
+ break;
+ }
+ verboselog( machine(), 9, "(UART 1) %08X -> %08X (PC %08X)\n", 0x15004000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_uart_1_w)
+{
+ verboselog( machine(), 9, "(UART 1) %08X <- %08X (PC %08X)\n", 0x15004000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_uart_1_regs[offset]);
+}
+
+// USB DEVICE
+
+
+READ32_MEMBER(gp32_state::s3c240x_usb_device_r)
+{
+ UINT32 data = m_s3c240x_usb_device_regs[offset];
+ verboselog( machine(), 9, "(USB D) %08X -> %08X (PC %08X)\n", 0x15200140 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_usb_device_w)
+{
+ verboselog( machine(), 9, "(USB D) %08X <- %08X (PC %08X)\n", 0x15200140 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_usb_device_regs[offset]);
+}
+
+// WATCHDOG TIMER
+
+
+READ32_MEMBER(gp32_state::s3c240x_watchdog_r)
+{
+ UINT32 data = m_s3c240x_watchdog_regs[offset];
+ verboselog( machine(), 9, "(WDOG) %08X -> %08X (PC %08X)\n", 0x15300000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_watchdog_w)
+{
+ verboselog( machine(), 9, "(WDOG) %08X <- %08X (PC %08X)\n", 0x15300000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_watchdog_regs[offset]);
+}
+
+// EEPROM
+
+static UINT8 eeprom_read( running_machine &machine, UINT16 address)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ UINT8 data;
+ data = state->m_eeprom_data[address];
+ verboselog( machine, 5, "EEPROM %04X -> %02X\n", address, data);
+ return data;
+}
+
+static void eeprom_write( running_machine &machine, UINT16 address, UINT8 data)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 5, "EEPROM %04X <- %02X\n", address, data);
+ state->m_eeprom_data[address] = data;
+}
+
+// IIC
+
+#if 0
+static UINT8 i2cmem_read_byte( running_machine &machine, int last)
+{
+ UINT8 data = 0;
+ int i;
+ i2cmem_write( machine, 0, I2CMEM_SDA, 1);
+ for (i = 0; i < 8; i++)
+ {
+ i2cmem_write( machine, 0, I2CMEM_SCL, 1);
+ data = (data << 1) + (i2cmem_read( machine, 0, I2CMEM_SDA) ? 1 : 0);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 0);
+ }
+ i2cmem_write( machine, 0, I2CMEM_SDA, last);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 1);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 0);
+ return data;
+}
+#endif
+
+#if 0
+static void i2cmem_write_byte( running_machine &machine, UINT8 data)
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ i2cmem_write( machine, 0, I2CMEM_SDA, (data & 0x80) ? 1 : 0);
+ data = data << 1;
+ i2cmem_write( machine, 0, I2CMEM_SCL, 1);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 0);
+ }
+ i2cmem_write( machine, 0, I2CMEM_SDA, 1); // ack bit
+ i2cmem_write( machine, 0, I2CMEM_SCL, 1);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 0);
+}
+#endif
+
+#if 0
+static void i2cmem_start( running_machine &machine)
+{
+ i2cmem_write( machine, 0, I2CMEM_SDA, 1);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 1);
+ i2cmem_write( machine, 0, I2CMEM_SDA, 0);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 0);
+}
+#endif
+
+#if 0
+static void i2cmem_stop( running_machine &machine)
+{
+ i2cmem_write( machine, 0, I2CMEM_SDA, 0);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 1);
+ i2cmem_write( machine, 0, I2CMEM_SDA, 1);
+ i2cmem_write( machine, 0, I2CMEM_SCL, 0);
+}
+#endif
+
+static void iic_start( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 1, "IIC start\n");
+ state->m_s3c240x_iic.data_index = 0;
+ state->m_s3c240x_iic_timer->adjust( attotime::from_msec( 1));
+}
+
+static void iic_stop( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 1, "IIC stop\n");
+ state->m_s3c240x_iic_timer->adjust( attotime::never);
+}
+
+static void iic_resume( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 1, "IIC resume\n");
+ state->m_s3c240x_iic_timer->adjust( attotime::from_msec( 1));
+}
+
+READ32_MEMBER(gp32_state::s3c240x_iic_r)
+{
+ UINT32 data = m_s3c240x_iic_regs[offset];
+ switch (offset)
+ {
+ // IICSTAT
+ case 0x04 / 4 :
+ {
+ data = data & ~0x0000000F;
+ }
+ break;
+ }
+ verboselog( machine(), 9, "(IIC) %08X -> %08X (PC %08X)\n", 0x15400000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_iic_w)
+{
+ verboselog( machine(), 9, "(IIC) %08X <- %08X (PC %08X)\n", 0x15400000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_iic_regs[offset]);
+ switch (offset)
+ {
+ // ADDR_IICCON
+ case 0x00 / 4 :
+ {
+ int interrupt_pending_flag;
+#if 0
+ static const int div_table[] = { 16, 512 };
+ int enable_interrupt, transmit_clock_value, tx_clock_source_selection
+ double clock;
+ transmit_clock_value = (data >> 0) & 0xF;
+ tx_clock_source_selection = (data >> 6) & 1;
+ enable_interrupt = (data >> 5) & 1;
+ clock = (double)(s3c240x_get_pclk(state, MPLLCON) / div_table[tx_clock_source_selection] / (transmit_clock_value + 1));
+#endif
+ interrupt_pending_flag = BIT( data, 4);
+ if (interrupt_pending_flag == 0)
+ {
+ int start_stop_condition;
+ start_stop_condition = BIT( m_s3c240x_iic_regs[1], 5);
+ if (start_stop_condition != 0)
+ {
+ iic_resume( machine());
+ }
+ }
+ }
+ break;
+ // IICSTAT
+ case 0x04 / 4 :
+ {
+ int start_stop_condition;
+ start_stop_condition = BIT( data, 5);
+ if (start_stop_condition != 0)
+ {
+ iic_start( machine());
+ }
+ else
+ {
+ iic_stop( machine());
+ }
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c240x_iic_timer_exp )
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ int enable_interrupt, mode_selection;
+ verboselog( machine, 2, "IIC timer callback\n");
+ mode_selection = BITS( state->m_s3c240x_iic_regs[1], 7, 6);
+ switch (mode_selection)
+ {
+ // master receive mode
+ case 2 :
+ {
+ if (state->m_s3c240x_iic.data_index == 0)
+ {
+ UINT8 data_shift = state->m_s3c240x_iic_regs[3] & 0xFF;
+ verboselog( machine, 5, "IIC write %02X\n", data_shift);
+ }
+ else
+ {
+ UINT8 data_shift = eeprom_read( machine, state->m_s3c240x_iic.address);
+ verboselog( machine, 5, "IIC read %02X\n", data_shift);
+ state->m_s3c240x_iic_regs[3] = (state->m_s3c240x_iic_regs[3] & ~0xFF) | data_shift;
+ }
+ state->m_s3c240x_iic.data_index++;
+ }
+ break;
+ // master transmit mode
+ case 3 :
+ {
+ UINT8 data_shift = state->m_s3c240x_iic_regs[3] & 0xFF;
+ verboselog( machine, 5, "IIC write %02X\n", data_shift);
+ state->m_s3c240x_iic.data[state->m_s3c240x_iic.data_index++] = data_shift;
+ if (state->m_s3c240x_iic.data_index == 3)
+ {
+ state->m_s3c240x_iic.address = (state->m_s3c240x_iic.data[1] << 8) | state->m_s3c240x_iic.data[2];
+ }
+ if ((state->m_s3c240x_iic.data_index == 4) && (state->m_s3c240x_iic.data[0] == 0xA0))
+ {
+ eeprom_write( machine, state->m_s3c240x_iic.address, data_shift);
+ }
+ }
+ break;
+ }
+ enable_interrupt = BIT( state->m_s3c240x_iic_regs[0], 5);
+ if (enable_interrupt)
+ {
+ s3c240x_request_irq( machine, INT_IIC);
+ }
+}
+
+// IIS
+
+static void s3c240x_iis_start( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ static const UINT32 codeclk_table[] = { 256, 384 };
+ double freq;
+ int prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk;
+ verboselog( machine, 1, "IIS start\n");
+ prescaler_enable = BIT( state->m_s3c240x_iis_regs[0], 1);
+ prescaler_control_a = BITS( state->m_s3c240x_iis_regs[2], 9, 5);
+ prescaler_control_b = BITS( state->m_s3c240x_iis_regs[2], 4, 0);
+ codeclk = BIT( state->m_s3c240x_iis_regs[1], 2);
+ freq = (double)(s3c240x_get_pclk(state, MPLLCON) / (prescaler_control_a + 1) / codeclk_table[codeclk]) * 2; // why do I have to multiply by two?
+ verboselog( machine, 5, "IIS - pclk %d psc_enable %d psc_a %d psc_b %d codeclk %d freq %f\n", s3c240x_get_pclk(state, MPLLCON), prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk_table[codeclk], freq);
+ state->m_s3c240x_iis_timer->adjust( attotime::from_hz( freq), 0, attotime::from_hz( freq));
+}
+
+static void s3c240x_iis_stop( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ verboselog( machine, 1, "IIS stop\n");
+ state->m_s3c240x_iis_timer->adjust( attotime::never);
+}
+
+static void s3c240x_iis_recalc( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ if (state->m_s3c240x_iis_regs[0] & 1)
+ {
+ s3c240x_iis_start( machine);
+ }
+ else
+ {
+ s3c240x_iis_stop( machine);
+ }
+}
+
+READ32_MEMBER(gp32_state::s3c240x_iis_r)
+{
+ UINT32 data = m_s3c240x_iis_regs[offset];
+#if 0
+ switch (offset)
+ {
+ // IISCON
+ case 0x00 / 4 :
+ {
+ data = data & ~1; // for mp3 player
+ }
+ break;
+ }
+#endif
+ verboselog( machine(), 9, "(IIS) %08X -> %08X (PC %08X)\n", 0x15508000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_iis_w)
+{
+ UINT32 old_value = m_s3c240x_iis_regs[offset];
+ verboselog( machine(), 9, "(IIS) %08X <- %08X (PC %08X)\n", 0x15508000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_iis_regs[offset]);
+ switch (offset)
+ {
+ // IISCON
+ case 0x00 / 4 :
+ {
+ if ((old_value & 1) != (data & 1)) s3c240x_iis_recalc( machine());
+ }
+ break;
+ // IISFIF
+ case 0x10 / 4 :
+ {
+ if (ACCESSING_BITS_16_31)
+ {
+ m_s3c240x_iis.fifo[m_s3c240x_iis.fifo_index++] = BITS( data, 31, 16);
+ }
+ if (ACCESSING_BITS_0_15)
+ {
+ m_s3c240x_iis.fifo[m_s3c240x_iis.fifo_index++] = BITS( data, 15, 0);
+ }
+ if (m_s3c240x_iis.fifo_index == 2)
+ {
+ dac_device *dac[2];
+ dac[0] = machine().device<dac_device>("dac1");
+ dac[1] = machine().device<dac_device>("dac2");
+ m_s3c240x_iis.fifo_index = 0;
+ dac[0]->write_signed16(m_s3c240x_iis.fifo[0] + 0x8000);
+ dac[1]->write_signed16(m_s3c240x_iis.fifo[1] + 0x8000);
+ }
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c240x_iis_timer_exp )
+{
+ verboselog( machine, 2, "IIS timer callback\n");
+ s3c240x_dma_request_iis( machine);
+}
+
+// RTC
+
+
+READ32_MEMBER(gp32_state::s3c240x_rtc_r)
+{
+ UINT32 data = m_s3c240x_rtc_regs[offset];
+ verboselog( machine(), 9, "(RTC) %08X -> %08X (PC %08X)\n", 0x15700040 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_rtc_w)
+{
+ verboselog( machine(), 9, "(RTC) %08X <- %08X (PC %08X)\n", 0x15700040 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_rtc_regs[offset]);
+}
+
+// A/D CONVERTER
+
+
+READ32_MEMBER(gp32_state::s3c240x_adc_r)
+{
+ UINT32 data = m_s3c240x_adc_regs[offset];
+ verboselog( machine(), 9, "(ADC) %08X -> %08X (PC %08X)\n", 0x15800000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_adc_w)
+{
+ verboselog( machine(), 9, "(ADC) %08X <- %08X (PC %08X)\n", 0x15800000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_adc_regs[offset]);
+}
+
+// SPI
+
+
+READ32_MEMBER(gp32_state::s3c240x_spi_r)
+{
+ UINT32 data = m_s3c240x_spi_regs[offset];
+ verboselog( machine(), 9, "(SPI) %08X -> %08X (PC %08X)\n", 0x15900000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_spi_w)
+{
+ verboselog( machine(), 9, "(SPI) %08X <- %08X (PC %08X)\n", 0x15900000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_spi_regs[offset]);
+}
+
+// MMC INTERFACE
+
+
+READ32_MEMBER(gp32_state::s3c240x_mmc_r)
+{
+ UINT32 data = m_s3c240x_mmc_regs[offset];
+ verboselog( machine(), 9, "(MMC) %08X -> %08X (PC %08X)\n", 0x15A00000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ return data;
+}
+
+WRITE32_MEMBER(gp32_state::s3c240x_mmc_w)
+{
+ verboselog( machine(), 9, "(MMC) %08X <- %08X (PC %08X)\n", 0x15A00000 + (offset << 2), data, cpu_get_pc( &space.device()));
+ COMBINE_DATA(&m_s3c240x_mmc_regs[offset]);
+}
+
+// ...
+
+static void s3c240x_machine_start( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ state->m_s3c240x_pwm_timer[0] = machine.scheduler().timer_alloc(FUNC(s3c240x_pwm_timer_exp), (void *)(FPTR)0);
+ state->m_s3c240x_pwm_timer[1] = machine.scheduler().timer_alloc(FUNC(s3c240x_pwm_timer_exp), (void *)(FPTR)1);
+ state->m_s3c240x_pwm_timer[2] = machine.scheduler().timer_alloc(FUNC(s3c240x_pwm_timer_exp), (void *)(FPTR)2);
+ state->m_s3c240x_pwm_timer[3] = machine.scheduler().timer_alloc(FUNC(s3c240x_pwm_timer_exp), (void *)(FPTR)3);
+ state->m_s3c240x_pwm_timer[4] = machine.scheduler().timer_alloc(FUNC(s3c240x_pwm_timer_exp), (void *)(FPTR)4);
+ state->m_s3c240x_dma_timer[0] = machine.scheduler().timer_alloc(FUNC(s3c240x_dma_timer_exp), (void *)(FPTR)0);
+ state->m_s3c240x_dma_timer[1] = machine.scheduler().timer_alloc(FUNC(s3c240x_dma_timer_exp), (void *)(FPTR)1);
+ state->m_s3c240x_dma_timer[2] = machine.scheduler().timer_alloc(FUNC(s3c240x_dma_timer_exp), (void *)(FPTR)2);
+ state->m_s3c240x_dma_timer[3] = machine.scheduler().timer_alloc(FUNC(s3c240x_dma_timer_exp), (void *)(FPTR)3);
+ state->m_s3c240x_iic_timer = machine.scheduler().timer_alloc(FUNC(s3c240x_iic_timer_exp), (void *)(FPTR)0);
+ state->m_s3c240x_iis_timer = machine.scheduler().timer_alloc(FUNC(s3c240x_iis_timer_exp), (void *)(FPTR)0);
+ state->m_s3c240x_lcd_timer = machine.scheduler().timer_alloc(FUNC(s3c240x_lcd_timer_exp), (void *)(FPTR)0);
+ state->m_eeprom_data = auto_alloc_array( machine, UINT8, 0x2000);
+ machine.device<nvram_device>("nvram")->set_base(state->m_eeprom_data, 0x2000);
+ smc_init( machine);
+ i2s_init( machine);
+}
+
+static void s3c240x_machine_reset( running_machine &machine)
+{
+ gp32_state *state = machine.driver_data<gp32_state>();
+ smc_reset( machine);
+ i2s_reset( machine);
+ state->m_s3c240x_iis.fifo_index = 0;
+ state->m_s3c240x_iic.data_index = 0;
+}
+
+static ADDRESS_MAP_START( gp32_map, AS_PROGRAM, 32, gp32_state )
+ AM_RANGE(0x00000000, 0x0007ffff) AM_ROM
+ AM_RANGE(0x0c000000, 0x0c7fffff) AM_RAM AM_SHARE("s3c240x_ram")
+ AM_RANGE(0x14000000, 0x1400003b) AM_READWRITE(s3c240x_memcon_r, s3c240x_memcon_w)
+ AM_RANGE(0x14200000, 0x1420005b) AM_READWRITE(s3c240x_usb_host_r, s3c240x_usb_host_w)
+ AM_RANGE(0x14400000, 0x14400017) AM_READWRITE(s3c240x_irq_r, s3c240x_irq_w)
+ AM_RANGE(0x14600000, 0x1460007b) AM_READWRITE(s3c240x_dma_r, s3c240x_dma_w)
+ AM_RANGE(0x14800000, 0x14800017) AM_READWRITE(s3c240x_clkpow_r, s3c240x_clkpow_w)
+ AM_RANGE(0x14a00000, 0x14a003ff) AM_READWRITE(s3c240x_lcd_r, s3c240x_lcd_w)
+ AM_RANGE(0x14a00400, 0x14a007ff) AM_READWRITE(s3c240x_lcd_palette_r, s3c240x_lcd_palette_w)
+ AM_RANGE(0x15000000, 0x1500002b) AM_READWRITE(s3c240x_uart_0_r, s3c240x_uart_0_w)
+ AM_RANGE(0x15004000, 0x1500402b) AM_READWRITE(s3c240x_uart_1_r, s3c240x_uart_1_w)
+ AM_RANGE(0x15100000, 0x15100043) AM_READWRITE(s3c240x_pwm_r, s3c240x_pwm_w)
+ AM_RANGE(0x15200140, 0x152001fb) AM_READWRITE(s3c240x_usb_device_r, s3c240x_usb_device_w)
+ AM_RANGE(0x15300000, 0x1530000b) AM_READWRITE(s3c240x_watchdog_r, s3c240x_watchdog_w)
+ AM_RANGE(0x15400000, 0x1540000f) AM_READWRITE(s3c240x_iic_r, s3c240x_iic_w)
+ AM_RANGE(0x15508000, 0x15508013) AM_READWRITE(s3c240x_iis_r, s3c240x_iis_w)
+ AM_RANGE(0x15600000, 0x1560005b) AM_READWRITE(s3c240x_gpio_r, s3c240x_gpio_w)
+ AM_RANGE(0x15700040, 0x1570008b) AM_READWRITE(s3c240x_rtc_r, s3c240x_rtc_w)
+ AM_RANGE(0x15800000, 0x15800007) AM_READWRITE(s3c240x_adc_r, s3c240x_adc_w)
+ AM_RANGE(0x15900000, 0x15900017) AM_READWRITE(s3c240x_spi_r, s3c240x_spi_w)
+ AM_RANGE(0x15a00000, 0x15a0003f) AM_READWRITE(s3c240x_mmc_r, s3c240x_mmc_w)
+ADDRESS_MAP_END
+
+static INPUT_PORTS_START( gp32 )
+ PORT_START("IN0")
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("R") PORT_PLAYER(1)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("L") PORT_PLAYER(1)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(1)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(1)
+ PORT_START("IN1")
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("SELECT") PORT_PLAYER(1)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("START") PORT_PLAYER(1)
+INPUT_PORTS_END
+
+static MACHINE_START( gp32 )
+{
+ s3c240x_machine_start(machine);
+}
+
+static MACHINE_RESET( gp32 )
+{
+ s3c240x_machine_reset(machine);
+}
+
+static MACHINE_CONFIG_START( gp32, gp32_state )
+ MCFG_CPU_ADD("maincpu", ARM9, 40000000)
+ MCFG_CPU_PROGRAM_MAP(gp32_map)
+
+ MCFG_PALETTE_LENGTH(32768)
+
+ MCFG_SCREEN_ADD("screen", LCD)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
+ MCFG_SCREEN_SIZE(240, 320)
+ MCFG_SCREEN_VISIBLE_AREA(0, 239, 0, 319)
+ MCFG_SCREEN_UPDATE_STATIC(gp32)
+
+ /* 320x240 is 4:3 but ROT270 causes an aspect ratio of 3:4 by default */
+ MCFG_DEFAULT_LAYOUT(layout_lcd_rot)
+
+ MCFG_MACHINE_START(gp32)
+ MCFG_MACHINE_RESET(gp32)
+
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SOUND_ADD("dac1", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ADD("dac2", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+
+ MCFG_NVRAM_ADD_1FILL("nvram")
+
+ MCFG_SMARTMEDIA_ADD("smartmedia")
+MACHINE_CONFIG_END
+
+ROM_START( gp32 )
+ ROM_REGION( 0x80000, "maincpu", 0 )
+ ROM_SYSTEM_BIOS( 0, "157e", "Firmware 1.5.7 (English)" )
+ ROMX_LOAD( "gp32157e.bin", 0x000000, 0x080000, CRC(b1e35643) SHA1(1566bc2a27980602e9eb501cf8b2d62939bfd1e5), ROM_BIOS(1) )
+ ROM_SYSTEM_BIOS( 1, "100k", "Firmware 1.0.0 (Korean)" )
+ ROMX_LOAD( "gp32100k.bin", 0x000000, 0x080000, CRC(d9925ac9) SHA1(3604d0d7210ed72eddd3e3e0c108f1102508423c), ROM_BIOS(2) )
+ ROM_SYSTEM_BIOS( 2, "156k", "Firmware 1.5.6 (Korean)" )
+ ROMX_LOAD( "gp32156k.bin", 0x000000, 0x080000, CRC(667fb1c8) SHA1(d179ab8e96411272b6a1d683e59da752067f9da8), ROM_BIOS(3) )
+ ROM_SYSTEM_BIOS( 3, "166m", "Firmware 1.6.6 (European)" )
+ ROMX_LOAD( "gp32166m.bin", 0x000000, 0x080000, CRC(4548a840) SHA1(1ad0cab0af28fb45c182e5e8c87ead2aaa4fffe1), ROM_BIOS(4) )
+ ROM_SYSTEM_BIOS( 4, "mfv2", "Mr. Spiv Multi Firmware V2" )
+ ROMX_LOAD( "gp32mfv2.bin", 0x000000, 0x080000, CRC(7ddaaaeb) SHA1(5a85278f721beb3b00125db5c912d1dc552c5897), ROM_BIOS(5) )
+#if 0
+ ROM_SYSTEM_BIOS( 5, "test", "test" )
+ ROMX_LOAD( "test.bin", 0x000000, 0x080000, CRC(00000000) SHA1(0000000000000000000000000000000000000000), ROM_BIOS(6) )
+#endif
+ROM_END
+
+CONS(2001, gp32, 0, 0, gp32, gp32, driver_device, 0, "Game Park Holdings", "GP32", ROT270|GAME_NOT_WORKING|GAME_NO_SOUND)