ims_cvc: implement cursor

(nw)
* simplify handlers
* reduce logging noise
This commit is contained in:
Patrick Mackinlay 2020-01-07 14:44:57 +07:00
parent a708e8f80d
commit e9e4b0bcca
2 changed files with 157 additions and 119 deletions

View File

@ -9,8 +9,6 @@
*
* http://bitsavers.org/components/inmos/graphics/72-TRN-204-01_Graphics_Databook_Second_Edition_1990.pdf
*
* TODO
* - cursor
*/
#include "emu.h"
@ -28,7 +26,7 @@ DEFINE_DEVICE_TYPE(G300, g300_device, "g300", "INMOS G300 Colour Video Controlle
DEFINE_DEVICE_TYPE(G332, g332_device, "g332", "INMOS G332 Colour Video Controller")
DEFINE_DEVICE_TYPE(G364, g364_device, "g364", "INMOS G364 Colour Video Controller")
ims_cvc_device::ims_cvc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
ims_cvc_device::ims_cvc_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, device_palette_interface(mconfig, *this)
, m_screen(*this, finder_base::DUMMY_TAG)
@ -36,23 +34,23 @@ ims_cvc_device::ims_cvc_device(const machine_config &mconfig, device_type type,
{
}
g300_device::g300_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
g300_device::g300_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: ims_cvc_device(mconfig, G300, tag, owner, clock)
{
}
g332_device::g332_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
g332_device::g332_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock)
: ims_cvc_device(mconfig, type, tag, owner, clock)
, m_microport(*this, "microport")
{
}
g332_device::g332_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
g332_device::g332_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: g332_device(mconfig, G332, tag, owner, clock)
{
}
g364_device::g364_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
g364_device::g364_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: g332_device(mconfig, G364, tag, owner, clock)
{
}
@ -65,7 +63,7 @@ void g332_device::device_add_mconfig(machine_config &config)
void g300_device::map(address_map &map)
{
// datasheet gives unshifted addresses
const int shift = 2;
unsigned const shift = 2;
// colour palette
map(0x000 << shift, (0x0ff << shift) | 0x3).rw(FUNC(g300_device::colour_palette_r), FUNC(g300_device::colour_palette_w));
@ -99,7 +97,7 @@ void g332_device::microport_map(address_map &map)
{
// datasheet uses unshifted addresses: configure the device map for 64 bit
// address mode, bank device does handles additional shift for 32 bit mode
const int shift = 3;
unsigned const shift = 3;
map(0x000 << shift, (0x000 << shift) | 0x7).w(FUNC(g332_device::boot_w));
@ -129,11 +127,14 @@ void g332_device::microport_map(address_map &map)
// checksum registers (0c0-0c2)
// cursor start (0c7)
map(0x0c7 << shift, (0x0c7 << shift) | 0x7).rw(FUNC(g332_device::cursor_start_r), FUNC(g332_device::cursor_start_w));
// colour palette
map(0x100 << shift, (0x1ff << shift) | 0x7).rw(FUNC(g332_device::colour_palette_r), FUNC(g332_device::colour_palette_w));
// cursor store (200-3ff)
// cursor position (0c7)
map(0x200 << shift, (0x3ff << shift) | 0x7).rw(FUNC(g332_device::cursor_store_r), FUNC(g332_device::cursor_store_w));
}
void ims_cvc_device::device_start()
@ -170,11 +171,16 @@ void g332_device::device_start()
{
ims_cvc_device::device_start();
m_cursor_store = std::make_unique<u16[]>(512);
save_item(NAME(m_vpreequalise));
save_item(NAME(m_vpostequalise));
save_item(NAME(m_linestart));
save_item(NAME(m_control_a));
save_item(NAME(m_control_b));
save_item(NAME(m_cursor_start));
save_pointer(NAME(m_cursor_store), 512);
}
void g332_device::device_reset()
@ -182,7 +188,7 @@ void g332_device::device_reset()
m_control_a = 0;
}
u32 g300_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
u32 g300_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect)
{
offs_t address = m_tos;
@ -193,7 +199,7 @@ u32 g300_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, cons
return 0;
}
u32 g332_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
u32 g332_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect)
{
offs_t address = m_tos;
@ -247,30 +253,48 @@ u32 g332_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, cons
break;
}
if (!(m_control_a & CURSOR_DISABLE))
{
// get cursor origin
int const cursor_x = screen.visible_area().min_x + (s32(m_cursor_start << 8) >> 20);
int const cursor_y = screen.visible_area().min_y + (s32(m_cursor_start << 20) >> 20);
// intersect cursor with screen
rectangle cursor(cursor_x, cursor_x + 63, cursor_y, cursor_y + 63);
cursor &= bitmap.cliprect();
// check if any portion is visible
if (!cursor.empty())
{
for (int y = 0; y < 64; y++)
{
// get screen y pixel coordinate
int const ypos = cursor_y + y;
for (int x = 0; x < 8; x++)
{
// retrieve 8 pixels from cursor bitmap
u16 data = m_cursor_store[y * 8 + x];
// draw non-transparent pixels
for (int i = 0; data && i < 8; data >>= 2, i++)
{
// get screen x pixel coordinate
int const xpos = cursor_x + x * 8 + i;
// draw pixel if visible
if ((data & 3) && cursor.contains(xpos, ypos))
bitmap.pix(ypos, xpos) = pen_color(256 + (data & 3) - 1);
}
}
}
}
}
return 0;
}
u32 ims_cvc_device::colour_palette_r(offs_t offset)
{
return 0;
}
void ims_cvc_device::colour_palette_w(offs_t offset, u32 data, u32 mem_mask)
{
set_pen_color(offset >> 1, data >> 16, data >> 8, data >> 0);
}
u32 g332_device::cursor_palette_r(offs_t offset)
{
return 0;
}
void g332_device::cursor_palette_w(offs_t offset, u32 data, u32 mem_mask)
{
set_pen_color(256 + (offset >> 1), data >> 16, data >> 8, data >> 0);
}
void g332_device::boot_w(offs_t offset, u32 data, u32 mem_mask)
void g332_device::boot_w(u32 data)
{
LOG("boot_w %s clock, multiplier %d, %d bit alignment (%s)\n",
(data & PLL_SELECT) ? "PLL" : "external", (data & PLL_MULTIPLIER),
@ -278,68 +302,69 @@ void g332_device::boot_w(offs_t offset, u32 data, u32 mem_mask)
m_microport->set_shift((data & ALIGN_64) ? 0 : 1);
mem_mask &= 0x00ffffffU;
COMBINE_DATA(&m_boot);
m_boot = data & MASK24;
}
void g332_device::control_a_w(offs_t offset, u32 data, u32 mem_mask)
void g332_device::control_a_w(u32 data)
{
LOG("control_a_w 0x%08x (%s)\n", data, machine().describe_context());
mem_mask &= 0x00ffffffU;
COMBINE_DATA(&m_control_a);
if (data & VTG_ENABLE)
if ((data ^ m_control_a) & MASK24)
{
LOGMASKED(LOG_CONFIG, "VTG %s, %s, %s mode\n",
(data & VTG_ENABLE) ? "enabled" : "disabled",
(data & INTL_ENABLE) ? ((data & INTL_FORMAT) ? "interlaced (CCIR)" : "interlaced (EIA)") : "non-interlaced",
(data & SLAVE_MODE) ? "slave" : "master");
m_control_a = data & MASK24;
LOGMASKED(LOG_CONFIG, "%s sync, %s digital sync, analogue %s\n",
(data & SYNC_PATTERN) ? "plain" : "tesselated",
(data & SYNC_FORMAT) ? "separate" : "composite",
(data & VIDEO_FORMAT) ? "video only" : "composite video + sync");
if (data & VTG_ENABLE)
{
LOGMASKED(LOG_CONFIG, "VTG %s, %s, %s mode\n",
(data & VTG_ENABLE) ? "enabled" : "disabled",
(data & INTL_ENABLE) ? ((data & INTL_FORMAT) ? "interlaced (CCIR)" : "interlaced (EIA)") : "non-interlaced",
(data & SLAVE_MODE) ? "slave" : "master");
LOGMASKED(LOG_CONFIG, "%s, CBlank is %s, %s, %s\n",
(data & BLANK_LEVEL) ? "blanking pedestal" : "no blank pedestal",
(data & BLANK_IO) ? "ouput" : "input",
(data & BLANK_FUNC) ? "undelayed ClkDisable" : "delayed CBlank",
(data & BLANK_FORCE) ? "screen blanked" : (data & BLANK_DISABLE) ? "blanking disabled" : "blanking enabled");
LOGMASKED(LOG_CONFIG, "%s sync, %s digital sync, analogue %s\n",
(data & SYNC_PATTERN) ? "plain" : "tesselated",
(data & SYNC_FORMAT) ? "separate" : "composite",
(data & VIDEO_FORMAT) ? "video only" : "composite video + sync");
LOGMASKED(LOG_CONFIG, "address increment %d, DMA %s, sync delay %d cycles\n",
(data & ADDR_INC) == INC_1 ? 1 :
(data & ADDR_INC) == INC_256 ? (data & INTL_ENABLE) ? 2 : 256 :
(data & ADDR_INC) == INC_512 ? 512 : 1024,
(data & DMA_DISABLE) ? "disabled" : "enabled",
(data & SYNC_DELAY) >> 15);
LOGMASKED(LOG_CONFIG, "%s, CBlank is %s, %s, %s\n",
(data & BLANK_LEVEL) ? "blanking pedestal" : "no blank pedestal",
(data & BLANK_IO) ? "ouput" : "input",
(data & BLANK_FUNC) ? "undelayed ClkDisable" : "delayed CBlank",
(data & BLANK_FORCE) ? "screen blanked" : (data & BLANK_DISABLE) ? "blanking disabled" : "blanking enabled");
LOGMASKED(LOG_CONFIG, "interleave %s, pixel sampling %s, %s bits per pixel, cursor %s\n",
(data & INTERLEAVE) ? "enabled" : "disabled",
(data & SAMPLE_DELAY) ? "delayed" : "standard",
(data & PIXEL_BITS) == BPP_1 ? "1" :
(data & PIXEL_BITS) == BPP_2 ? "2" :
(data & PIXEL_BITS) == BPP_4 ? "4" :
(data & PIXEL_BITS) == BPP_8 ? "8" :
(data & PIXEL_BITS) == BPP_15 ? "15" :
(data & PIXEL_BITS) == BPP_16 ? "16" : "unknown",
(data & CURSOR_DISABLE) ? "disabled" : "enabled");
LOGMASKED(LOG_CONFIG, "address increment %d, DMA %s, sync delay %d cycles\n",
(data & ADDR_INC) == INC_1 ? 1 :
(data & ADDR_INC) == INC_256 ? (data & INTL_ENABLE) ? 2 : 256 :
(data & ADDR_INC) == INC_512 ? 512 : 1024,
(data & DMA_DISABLE) ? "disabled" : "enabled",
(data & SYNC_DELAY) >> 15);
LOG("display %d vdisplay %d\n", m_display, m_vdisplay);
LOG("linetime %d halfsync %d backporch %d broadpulse %d\n", m_linetime, m_halfsync, m_backporch, m_broadpulse);
LOG("vsync %d vpreequalise %d vpostequalise %d vblank %d\n", m_vsync, m_vpreequalise, m_vpostequalise, m_vblank);
LOGMASKED(LOG_CONFIG, "interleave %s, pixel sampling %s, %s bits per pixel, cursor %s\n",
(data & INTERLEAVE) ? "enabled" : "disabled",
(data & SAMPLE_DELAY) ? "delayed" : "standard",
(data & PIXEL_BITS) == BPP_1 ? "1" :
(data & PIXEL_BITS) == BPP_2 ? "2" :
(data & PIXEL_BITS) == BPP_4 ? "4" :
(data & PIXEL_BITS) == BPP_8 ? "8" :
(data & PIXEL_BITS) == BPP_15 ? "15" :
(data & PIXEL_BITS) == BPP_16 ? "16" : "unknown",
(data & CURSOR_DISABLE) ? "disabled" : "enabled");
int const hbend = (m_halfsync + m_halfsync + m_backporch) << 2;
int const vbend = (m_vpreequalise + m_vpostequalise + m_vsync + m_vblank) >> 1;
int const width = m_linetime << 2;
int const height = vbend + (m_vdisplay >> 1);
LOG("display %d vdisplay %d\n", m_display, m_vdisplay);
LOG("linetime %d halfsync %d backporch %d broadpulse %d\n", m_linetime, m_halfsync, m_backporch, m_broadpulse);
LOG("vsync %d vpreequalise %d vpostequalise %d vblank %d\n", m_vsync, m_vpreequalise, m_vpostequalise, m_vblank);
rectangle const visarea(hbend, hbend + (m_display << 2) - 1, vbend, height - 1);
int const hbend = (m_halfsync + m_halfsync + m_backporch) << 2;
int const vbend = (m_vpreequalise + m_vpostequalise + m_vsync + m_vblank) >> 1;
int const width = m_linetime << 2;
int const height = vbend + (m_vdisplay >> 1);
u32 const dotclock = (m_boot & PLL_SELECT) ? clock() * (m_boot & PLL_MULTIPLIER) : clock();
attotime const refresh = attotime::from_hz(dotclock / (width * height));
rectangle const visarea(hbend, hbend + (m_display << 2) - 1, vbend, height - 1);
m_screen->configure(width, height, visarea, refresh.as_attoseconds());
m_screen->reset_origin();
u32 const dotclock = (m_boot & PLL_SELECT) ? clock() * (m_boot & PLL_MULTIPLIER) : clock();
attotime const refresh = attotime::from_hz(dotclock / (width * height));
m_screen->configure(width, height, visarea, refresh.as_attoseconds());
m_screen->reset_origin();
}
}
}

View File

@ -13,17 +13,17 @@ class ims_cvc_device
, public device_palette_interface
{
public:
static constexpr feature_type imperfect_features() { return feature::GRAPHICS; }
static u32 const MASK24 = 0xffffffU;
// configuration
template <typename T> void set_screen(T &&tag) { m_screen.set_tag(std::forward<T>(tag)); }
template <typename T> void set_vram(T &&tag) { m_vram.set_tag(std::forward<T>(tag)); }
virtual void map(address_map &map) = 0;
virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) = 0;
virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) = 0;
protected:
ims_cvc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
ims_cvc_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
// device_t overrides
virtual void device_start() override;
@ -32,39 +32,41 @@ protected:
// device_palette_interface overrides
virtual u32 palette_entries() const override { return 256; }
u32 colour_palette_r(const offs_t offset);
void colour_palette_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU);
virtual void boot_w(u32 data) { m_boot = data & MASK24; }
// register read handlers
u32 halfsync_r() { return m_halfsync; }
void halfsync_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_halfsync); }
u32 backporch_r() { return m_backporch; }
void backporch_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_backporch); }
u32 display_r() { return m_display; }
void display_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_display); }
u32 shortdisplay_r() { return m_shortdisplay; }
void shortdisplay_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_shortdisplay); }
u32 broadpulse_r() { return m_broadpulse; }
void broadpulse_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_broadpulse); }
u32 vsync_r() { return m_vsync; }
void vsync_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_vsync); }
u32 vblank_r() { return m_vblank; }
void vblank_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_vblank); }
u32 vdisplay_r() { return m_vdisplay; }
void vdisplay_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_vdisplay); }
u32 linetime_r() { return m_linetime; }
void linetime_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_linetime); }
//u32 tos_r() { return m_tos; }
//void tos_w(const u32 data) { m_tos = data; }
u32 meminit_r() { return m_meminit; }
void meminit_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_meminit); }
u32 transferdelay_r() { return m_transferdelay; }
void transferdelay_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_transferdelay); }
u32 mask_r() { return m_mask; }
void mask_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_mask); }
u32 tos_r() { return m_tos; }
void tos_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_tos); }
virtual void boot_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_boot); }
// register write handlers
void halfsync_w(u32 data) { m_halfsync = data & MASK24; }
void backporch_w(u32 data) { m_backporch = data & MASK24; }
void display_w(u32 data) { m_display = data & MASK24; }
void shortdisplay_w(u32 data) { m_shortdisplay = data & MASK24; }
void broadpulse_w(u32 data) { m_broadpulse = data & MASK24; }
void vsync_w(u32 data) { m_vsync = data & MASK24; }
void vblank_w(u32 data) { m_vblank = data & MASK24; }
void vdisplay_w(u32 data) { m_vdisplay = data & MASK24; }
void linetime_w(u32 data) { m_linetime = data & MASK24; }
void meminit_w(u32 data) { m_meminit = data & MASK24; }
void transferdelay_w(u32 data) { m_transferdelay = data & MASK24; }
void mask_w(u32 data) { m_mask = data & MASK24; }
void tos_w(u32 data) { m_tos = data & MASK24; }
// colour palette handlers
u32 colour_palette_r(offs_t offset) { return u32(pen_color(offset >> 1)) & MASK24; }
void colour_palette_w(offs_t offset, u32 data) { set_pen_color(offset >> 1, data >> 16, data >> 8, data >> 0); }
required_device<screen_device> m_screen;
required_device<ram_device> m_vram;
@ -91,17 +93,17 @@ protected:
class g300_device : public ims_cvc_device
{
public:
g300_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
g300_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
virtual void map(address_map &map) override;
virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) override;
virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) override;
protected:
virtual void device_start() override;
u32 control_r() { return m_control; }
void control_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_control); }
void control_w(u32 data) { m_control = data & MASK24; }
private:
u32 m_control;
@ -110,11 +112,11 @@ private:
class g332_device : public ims_cvc_device
{
public:
g332_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
g332_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
virtual void map(address_map &map) override;
virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) override;
virtual u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect) override;
enum boot_mask : u32
{
@ -163,7 +165,7 @@ public:
};
protected:
g332_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
g332_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
// device_t overrides
virtual void device_add_mconfig(machine_config &config) override;
@ -175,21 +177,29 @@ protected:
virtual void microport_map(address_map &map);
virtual void boot_w(offs_t offset, u32 data, u32 mem_mask = 0x00ffffffU) override;
u32 cursor_palette_r(const offs_t offset);
void cursor_palette_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU);
virtual void boot_w(u32 data) override;
// register read handlers
u32 vpreequalise_r() { return m_vpreequalise; }
void vpreequalise_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_vpreequalise); }
u32 vpostequalise_r() { return m_vpostequalise; }
void vpostequalise_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_vpostequalise); }
u32 linestart_r() { return m_linestart; }
void linestart_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_linestart); }
u32 control_a_r() { return m_control_a; }
void control_a_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU);
u32 control_b_r() { return m_control_b; }
void control_b_w(offs_t offset, u32 data, u32 mem_mask = 0xffffffffU) { COMBINE_DATA(&m_control_b); }
u32 cursor_start_r() { return m_cursor_start; }
// register write handlers
void vpreequalise_w(u32 data) { m_vpreequalise = data & MASK24; }
void vpostequalise_w(u32 data) { m_vpostequalise = data & MASK24; }
void linestart_w(u32 data) { m_linestart = data & MASK24; }
void control_a_w(u32 data);
void control_b_w(u32 data) { m_control_b = data & MASK24; }
void cursor_start_w(u32 data) { m_cursor_start = data & MASK24; }
// cursor handlers
u32 cursor_palette_r(offs_t offset) { return u32(pen_color(256 + (offset >> 1)))& MASK24; }
u32 cursor_store_r(offs_t offset) { return m_cursor_store[offset >> 1]; }
void cursor_palette_w(offs_t offset, u32 data) { set_pen_color(256 + (offset >> 1), data >> 16, data >> 8, data >> 0); }
void cursor_store_w(offs_t offset, u32 data) { m_cursor_store[offset >> 1] = u16(data); }
private:
required_device<address_map_bank_device> m_microport;
@ -199,12 +209,15 @@ private:
u32 m_linestart;
u32 m_control_a;
u32 m_control_b;
u32 m_cursor_start;
std::unique_ptr<u16[]> m_cursor_store;
};
class g364_device : public g332_device
{
public:
g364_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
g364_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
DECLARE_DEVICE_TYPE(G300, g300_device)