diff --git a/hash/unichamp.xml b/hash/unichamp.xml new file mode 100644 index 00000000000..2d128200a84 --- /dev/null +++ b/hash/unichamp.xml @@ -0,0 +1,54 @@ + + + + + + + Professional Poker Games + 1977 + Unisonic + + + + + + + + + + Assorted Family Fun + 1977 + Unisonic + + + + + + + + + + Family Card Games + 1977 + Unisonic + + + + + + + + + + Math + 1977 + Unisonic + + + + + + + + + diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 5c299a63105..a055b0fcab7 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -849,6 +849,7 @@ function linkProjects_mame_mess(_target, _subtarget) "trs", "ultimachine", "ultratec", + "unisonic", "unisys", "veb", "vidbrain", @@ -2481,6 +2482,14 @@ files { MAME_DIR .. "src/mame/drivers/minicom.c", } +createMESSProjects(_target, _subtarget, "unisonic") +files { + MAME_DIR .. "src/mame/drivers/unichamp.c", + MAME_DIR .. "src/mame/video/gic.c", + MAME_DIR .. "src/mame/video/gic.c", +} + + createMESSProjects(_target, _subtarget, "unisys") files { MAME_DIR .. "src/mame/drivers/univac.c", diff --git a/src/mame/drivers/unichamp.c b/src/mame/drivers/unichamp.c new file mode 100644 index 00000000000..99f711c2766 --- /dev/null +++ b/src/mame/drivers/unichamp.c @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:David Viens +/************************************************************************ + * Unisonic Champion 2711 (late 1977 based on part dates) + * + * Driver from plgDavid (David Viens) + * + * Thanks to Sylvain De Chantal (Sly D.C.) for the 2 test units, + * carts and FAQ: http://www.ccjvq.com/slydc/index/faq/2711 + * + * Thanks to Paul Robson for the GIC font rom. + * (http://worstconsole.blogspot.ca/2012/12/the-worstconsoleever.html) + * Note a spare dead GIC has been given to Lord Nightmare and should be sent for decap! + * + * The Unisonc Champion is the only known GI "Gimini Mid-Range 8950 Programmable Game Set" + * to ever reach the market, and only in limited quantities (aprox 500 units ever built) + * + * Architecture: + * Master IC : AY-3-8800-1 Graphics Interface (A.K.A. GIC, 40 pin) + * Slave IC : CP1610 CPU (40 pin, same as in the Intellivision) + * EXEC ROM : 9501-01009 (40 pin) at 0x0800 (factory mapped) + * + * The GIC generates the CPU Clock, the video signals and the audio. + * The CPU does NOT access the GIC directly. + * One way CPU->GIC 'communication' takes place through 256 bytes of shared RAM + * (using two 4x256 TMS4043NL-2 (2112-1) Static Rams at U3 and U4) + * + * In this design the GIC only allows the CPU to use the BUS (and shared RAM) + * a fraction of the frame time. (4.33ms for each 16.69ms, or 26% of the time) + * (the real ratio of clocks is 7752/29868 ) + * + * Boot: When the GIC let go of !RESET_OUT the EXEC Rom pushes 0x800 onto + * the bus for the CPU to fetch and place in R7 to start execution. + * This first CPU slice only last 3ms, then the GIC sets the CPU's BUSRQ low, + * stalling it for 12.36ms, then sets it high for 4.33ms etc... + * 59.95 times a second - NTSC + ************************************************************************/ + +#include "emu.h" +#include "cpu/cp1610/cp1610.h" +#include "video/gic.h" + +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" + +class unichamp_state : public driver_device +{ +public: + unichamp_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_gic(*this, "gic"), + m_cart(*this, "cartslot"), + m_ctrls(*this, "CTRLS"){} + + required_device m_maincpu; + required_device m_gic; + required_device m_cart; + + UINT8 m_ram[256]; + DECLARE_DRIVER_INIT(unichamp); + virtual void machine_start(); + virtual void machine_reset(); + DECLARE_PALETTE_INIT(unichamp); + + DECLARE_READ8_MEMBER(bext_r); + + DECLARE_READ16_MEMBER(unichamp_gicram_r); + DECLARE_WRITE16_MEMBER(unichamp_gicram_w); + + DECLARE_READ16_MEMBER(unichamp_trapl_r); + DECLARE_WRITE16_MEMBER(unichamp_trapl_w); + + UINT32 screen_update_unichamp(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + required_ioport m_ctrls; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); +}; + +PALETTE_INIT_MEMBER(unichamp_state, unichamp) +{ + /* + palette.set_pen_color(GIC_BLACK, rgb_t(0x00, 0x00, 0x00)); + palette.set_pen_color(GIC_RED, rgb_t(0xAE, 0x49, 0x41));//(from box shot) + palette.set_pen_color(GIC_GREEN, rgb_t(0x62, 0x95, 0x88));//(from box shot) + palette.set_pen_color(GIC_WHITE, rgb_t(0xFF, 0xFF, 0xFF)); + */ + + //using from intv.c instead as suggested by RB + palette.set_pen_color(GIC_BLACK, rgb_t(0x00, 0x00, 0x00)); + palette.set_pen_color(GIC_RED, rgb_t(0xFF, 0x3D, 0x10)); + //palette.set_pen_color(GIC_GREEN, rgb_t(0x38, 0x6B, 0x3F)); //intv's DARK GREEN + palette.set_pen_color(GIC_GREEN, rgb_t(0x00, 0xA7, 0x56)); //intv's GREEN + palette.set_pen_color(GIC_WHITE, rgb_t(0xFF, 0xFC, 0xFF)); +} + + +static ADDRESS_MAP_START( unichamp_mem, AS_PROGRAM, 16, unichamp_state ) + ADDRESS_MAP_GLOBAL_MASK(0x1FFF) //B13/B14/B15 are grounded! + AM_RANGE(0x0000, 0x00FF) AM_READWRITE(unichamp_gicram_r, unichamp_gicram_w) + AM_RANGE(0x0100, 0x07FF) AM_READWRITE(unichamp_trapl_r, unichamp_trapl_w) + AM_RANGE(0x0800, 0x17FF) AM_ROM AM_REGION("maincpu", 0x0800 << 1) // Carts and EXE ROM, 10-bits wide +ADDRESS_MAP_END + + +static INPUT_PORTS_START( unichamp ) + PORT_START( "CTRLS" ) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')// P1 YES (EBCA0) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')// P1 NO (EBCA1) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')// P2 YES (EBCA2) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')// P2 NO (EBCA3) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_UNUSED +INPUT_PORTS_END + + +void unichamp_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + //TODO should we add an explicit Reset button in there just like the controller? +} + + +READ8_MEMBER(unichamp_state::bext_r) +{ + //The BEXT instruction pushes a user-defined nibble out on the four EBCA pins (EBCA0 to EBCA3) + //and reads the ECBI input pin for HIGH or LOW signal to know whether or not to branch + + //The unisonic control system couldnt be simpler in desing. + //Each of the two player controllers has three buttons: + //one tying !RESET(GIC pin 21) to ground when closed - resetting the WHOLE system. + //a YES button (connecting EBCA0 to EBCI for Player1 and EBC2 to EBCI for Player2) + //a NO button (connecting EBCA1 to EBCI for Player1 and EBC3 to EBCI for Player2) + + //The CPU outputs a MASK of whatever it needs and checks the result. + //EG: Any player can choose if one or two players are going to play the game for instance + + UINT8 port = ioport("CTRLS")->read() & 0x0F; ////only lower nibble + + //We need to return logical high or low on the EBCI pin + return (port & offset)>0?1:0; +} + + +DRIVER_INIT_MEMBER(unichamp_state,unichamp) +{ + m_gic->set_shared_memory(m_ram); +} + +void unichamp_state::machine_start() +{ + m_gic->set_shared_memory(m_ram); + + if (m_cart->exists()){ + //flip endians in more "this surely exists in MAME" way? + //NOTE The unichamp roms have the same endianness as intv on disk and in memory + UINT8*ptr = m_cart->get_rom_base(); + size_t size = m_cart->get_rom_size(); + for(size_t i=0;ispace(AS_PROGRAM).install_read_handler(0x1000, 0x1800, + read16_delegate(FUNC(generic_slot_device::read16_rom),(generic_slot_device*)m_cart)); + } +} + +/* Set Reset and INTR/INTRM Vector */ +void unichamp_state::machine_reset() +{ + /* + the intv driver did not explain this but from the CP1600 manual: + When MSYNC* goes inactive (high), the bus control signals issue lAB, + and the CPU inputs from the bus into the PC the starting address of the main program. + Note that the initialization address can be defined by the user at any desired bus address or + can be the default address resulting from the logical state of the non-driven bus + */ + + //The Unisonic EXEC ROM chip (9501-01009) is self mapped at 0x0800 + //The cart ROMS are self mapped to 0x1000 + //upon boot the EXEC ROM puts 0x0800 on the bus for the CPU to use as first INT vector + + m_maincpu->set_input_line_vector(CP1610_RESET, 0x0800); + m_maincpu->set_input_line_vector(CP1610_INT_INTRM, 0x0804);//not used anyway + m_maincpu->set_input_line_vector(CP1610_INT_INTR, 0x0804);//not used anyway + + /* Set initial PC */ + m_maincpu->set_state_int(CP1610_R7, 0x0800); +} + + +UINT32 unichamp_state::screen_update_unichamp(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + return m_gic->screen_update(screen, bitmap, cliprect); +} + +READ16_MEMBER( unichamp_state::unichamp_gicram_r ) +{ + return (int)m_ram[offset]; +} + +WRITE16_MEMBER( unichamp_state::unichamp_gicram_w ) +{ + m_ram[offset] = data&0xff; +} + +READ16_MEMBER( unichamp_state::unichamp_trapl_r ) +{ + logerror("trapl_r(%x)\n",offset); + return (int)0; +} + +WRITE16_MEMBER( unichamp_state::unichamp_trapl_w ) +{ + logerror("trapl_w(%x) = %x\n",offset,data); +} + +static MACHINE_CONFIG_START( unichamp, unichamp_state ) + /* basic machine hardware */ + + //The CPU is really clocked this way: + //MCFG_CPU_ADD("maincpu", CP1610, XTAL_3_579545MHz/4) + //But since it is only running 7752/29868 th's of the time... + //TODO find a more accurate method? (the emulation will me the same though) + MCFG_CPU_ADD("maincpu", CP1610, (int)((7752.0/29868.0)*XTAL_3_579545MHz/4)) + + MCFG_CPU_PROGRAM_MAP(unichamp_mem) + MCFG_QUANTUM_TIME(attotime::from_hz(60)) + MCFG_CP1610_BEXT_CALLBACK(READ8(unichamp_state, bext_r)) + + /* video hardware */ + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS( XTAL_3_579545MHz, + gic_device::LINE_CLOCKS, + gic_device::START_ACTIVE_SCAN, + gic_device::END_ACTIVE_SCAN, + gic_device::LINES, + gic_device::START_Y, + gic_device::START_Y + gic_device::SCREEN_HEIGHT ) + + MCFG_SCREEN_UPDATE_DRIVER(unichamp_state, screen_update_unichamp) + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD("palette", 4) + MCFG_PALETTE_INIT_OWNER(unichamp_state, unichamp) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_GIC_ADD( "gic", XTAL_3_579545MHz, "screen" ) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40) + + /* cartridge */ + MCFG_GENERIC_CARTSLOT_ADD("cartslot", generic_linear_slot, "unichamp_cart") + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_SOFTWARE_LIST_ADD("cart_list", "unichamp") + +MACHINE_CONFIG_END + + +ROM_START(unichamp) + ROM_REGION(0x10000<<1,"maincpu", ROMREGION_ERASEFF) + + ROM_LOAD16_WORD( "9501-01009.u2", 0x0800<<1, 0x1000, CRC(49a0bd8f) SHA1(f4d126d3462ad351da4b75d76c75942d5a6f27ef)) + + //these below are for local tests. you can use them in softlist or -cart + //ROM_LOAD16_WORD( "pac-02.bin", 0x1000<<1, 0x1000, CRC(fe3213be) SHA1(5b9c407fe86865f3454d4be824a7f2bf53478f73)) + //ROM_LOAD16_WORD( "pac-03.bin", 0x1000<<1, 0x1000, CRC(f81f04bd) SHA1(82e2a0fda1787d5835c457ee5745b0db0cebe079)) + //ROM_LOAD16_WORD( "pac-04.bin", 0x1000<<1, 0x1000, CRC(cac09841) SHA1(bc9db83f26ed0810938156db6b104b4576754225)) + //ROM_LOAD16_WORD( "pac-05.bin", 0x1000<<1, 0x1000, CRC(d54a6090) SHA1(e85593096f43dcf14b08fd2c9fda277008a8df8b)) +ROM_END + + +CONS( 1977, unichamp, 0, 0, unichamp, unichamp, unichamp_state, unichamp, "Unisonic", "Champion 2711", 0/*MACHINE_IMPERFECT_GRAPHICS*/) diff --git a/src/mame/mess.lst b/src/mame/mess.lst index 94f6f775a9f..307a258de57 100644 --- a/src/mame/mess.lst +++ b/src/mame/mess.lst @@ -2764,3 +2764,4 @@ squale micral rd100 proteus3 +unichamp diff --git a/src/mame/video/gic.c b/src/mame/video/gic.c new file mode 100644 index 00000000000..30461b5b9eb --- /dev/null +++ b/src/mame/video/gic.c @@ -0,0 +1,335 @@ +// license:BSD-3-Clause +// copyright-holders:David Viens +/*************************************************************************** + + gic.c + + GI AY-3-8800-1 (Datasheet exists as AY-3-8500-1 Graphics Interface Chip) + For the GIMINI "Challenger" programmable game system. + + Really only ever used in the Unisonic Champion 2711 + + More LA tests made by plgDavid on hardware pretty much confirmed what is found + in the AY-3-8950-1 datasheet, but with more fine grained detail. + + the GIC does not have internal ram of any sort apart from shift registers, + instead it relies on the external shared ram, (see page 7-85) Appendix AY-3-8950-1 + + Unverified on LA (since the video pins are all connected into a composite mix): + at line 46 it lowers GIC_BUSY, until line 240 + + Verified using LA: + It will read the external ram areas continuously while GIC_BUSY is low (for 12.36ms) + + (NOTE: OCTAL) + + 000,001,002,003,004,005, 110,111,112,113,114,115,116,117,120,121,122,123,124,125 (15 times - No first bg line?) + 006,007,010,011,012,013, 110,111,112,113,114,115,116,117,120,121,122,123,124,125 (16 times) + + 014,015,016,017,020,021, 125,126,127,130,131,132,133,134,135,136,137,140,141,142 (16 times) + 022,023,024,025,026,027, 125,126,127,130,131,132,133,134,135,136,137,140,141,142 (16 times) + + 030,031,032,033,034,035, 142,143,144,145,146,147,150,151,152,153,154,155,156,157 (16 times) + 036,037,040,041,042,043, 142,143,144,145,146,147,150,151,152,153,154,155,156,157 (16 times) + + 044,045,046,047,050,051, 157,160,161,162,163,164,165,166,167,170,171,172,173,174 (16 times) + 052,053,054,055,056,057, 157,160,161,162,163,164,165,166,167,170,171,172,173,174 (16 times) + + 060,061,062,063,064,065, 174,175,176,177,200,201,202,203,204,205,206,207,210,211 (16 times) + 066,067,070,071,072,073, 174,175,176,177,200,201,202,203,204,205,206,207,210,211 (16 times) + + 074,075,076,077,100,101, 211,212,213,214,215,216,217,220,221,222,223,224,225,226 (16 times) + 102,103,104,105,106,107, 211,212,213,214,215,216,217,220,221,222,223,224,225,226 (16 times) + + 000,001,002,003,004,005, 000,001,002,003,004,005,006,007,010,011,012,013,014,015 (once! padding?) + + for a total of (12*20*16) = 3840 RAM reads (3 clocks per read at 1.79MHz) + + Then it relingishes control to the CPU by raising BUSREQ. + + Cloking in more detail: (in 1.79MHz clocks) + boot: + busy:1 5360 clocks + busy:0 22116 clocks + busy:1 7752 clocks + busy:0 22116 clocks + busy:1 7752 clocks + (...) + + There are NO IRQ handshakes, just BUSREQ sync shared RAM + +***************************************************************************/ + +#include "emu.h" +#include "gic.h" + +// device type definition +const device_type GIC = &device_creator; + + +//Font data taken from Paul Robson's simulator +//http://worstconsole.blogspot.ca/2012/12/the-worstconsoleever.html +//A real AY-3-8800-1 (dead) is going to decap for a good dump +ROM_START( gic_font ) + ROM_REGION( 0x200, "cgrom", 0 ) + ROM_LOAD( "ay-3-8800-1.bin", 0x0000, 0x200, BAD_DUMP CRC(d9f11d2b) SHA1(60ef45d51d102cd3af78787008d9aed848137bee)) +ROM_END + + +//------------------------------------------------- +// gic_device - constructor +//------------------------------------------------- + +gic_device::gic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GIC, "GIC", tag, owner, clock, "gic", __FILE__) + , device_sound_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_cgrom(0) + , m_audiocnt(0) + , m_audioval(0) + , m_audioreset(0) + , m_ram(0) +{ +} + + +gic_device::gic_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int lines, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , device_sound_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_cgrom(0) + , m_audiocnt(0) + , m_audioval(0) + , m_audioreset(0) + , m_ram(0) +{ +} + +const rom_entry *gic_device::device_rom_region() const +{ + //there is only one... how do I get rid of this? + return ROM_NAME( gic_font ); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gic_device::device_start() +{ + m_cgrom = memregion("cgrom")->base(); + + // Let the screen create our temporary bitmap with the screen's dimensions + m_screen->register_screen_bitmap(m_bitmap); + + m_vblank_timer = timer_alloc(TIMER_VBLANK); + m_vblank_timer->adjust( m_screen->time_until_pos(1, END_ACTIVE_SCAN + 18 ), 0, m_screen->scan_period() ); + + // allocate the audio stream + m_stream = stream_alloc( 0, 1, clock()/(2*228) ); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void gic_device::device_reset() +{ + m_audiocnt=0; + m_audioval=0; + m_audioreset=0; +} + +#define GIC_CLUB 28 +#define GIC_SPACE 0 + +void gic_device::draw_char_left(int startx, int starty, UINT8 code, bitmap_ind16 &bitmap){ + + UINT8*ptr = &m_cgrom[code*GIC_CHAR_H]; + + for (size_t y=0;y>4),m_bitmap,bgColor); + }break; + + default:printf("gic unknown char! %02X\n",data); break; + } + } + } + + copybitmap( bitmap, m_bitmap, 0, 0, 0, 0, cliprect ); + return 0; +} + +/* AUDIO SECTION */ + +void gic_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch ( id ) + { + case TIMER_VBLANK: + //flag the audio to reset + m_audioreset = 1;//phase need to reset! on next clock/228 + break; + } +} + +#define GIC_AUDIO_BYTE 0x96 + +void gic_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + + //Audio is basic and badly implemented (doubt that was the intent) + //The datasheet list the 3 different frequencies the GIC can generate: 500,1000 and 2000Hz + //but it is clear (for an audio guy at least) that the resulting spectrum + //is not a pure square wav. In fact, the counter is reset on vertical sync! + //http://twitter.com/plgDavid/status/527269086016077825 + //...thus creating a buzzing sound. + + //Dumping the audio pin value each time + // either (PHI2 made a 0->1 transition (1.789MHz) + // or (PHI1 made a 1->1 transition (1.789MHz) + //I found that the granularity of audio transitions + //(including phase resets and silences) was 228 clocks + //The audio subsystem thus runs at 1.789MHz/228 = 7849.88Hz + + //when 1 + //normal period:912 clocks (228*4) + //hi for 456 clocks + //lo for 456 clocks + //reset period: (each frame) + //hi for 228 clocks + //lo for 456 clocks + //when 2 + //normal period lasts 1824 clocks (228*8) + //hi for 912 clocks + //lo for 912 clocks + //reset period: (each frame) + //hi for 912 (228*4) + //lo for 1596 (228*7) + //hi for 912 (228*4) + //when 4 + //normal period lasts 3648 clocks (228*16) + //hi for 1824(228*8) + //lo for 1824(228*8) + //Reset period: + //lo for 1824(228*8) + //hi for 2508(228*11) + //lo for 1824(228*8) + //hi for 1824(228*8) + + if(!m_ram) return; + + UINT8 audioByte = m_ram[GIC_AUDIO_BYTE]*2; + + if(!audioByte){ + for(size_t i = 0; i < samples; i++) + *buffer++ = 0; + + m_audioval = 0; + m_audiocnt = 0; + m_audioreset = 0; + return;//early + } + + //forced resynch @ 59.95Hz + if(m_audioreset){ + m_audioval = 0;//forced low + m_audiocnt = 0; + m_audioreset = 0; + } + + for(size_t i=0; i < samples; i++){ + m_audiocnt++; + if(m_audiocnt >= audioByte){ + m_audioval = !m_audioval; + m_audiocnt=0; + } + *buffer++ = m_audioval<<13; + } +} diff --git a/src/mame/video/gic.h b/src/mame/video/gic.h new file mode 100644 index 00000000000..0df8958a2ab --- /dev/null +++ b/src/mame/video/gic.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:David Viens +/*************************************************************************** + + gic.h + + GI AY-3-8800-1 (Datasheet exists as AY-3-8500-1 Graphics Interface Chip) + For the GIMINI "Challenger" programmable game system. + + Really only ever used in the Unisonic Champion 2711 + +***************************************************************************/ + +#pragma once + +#ifndef __GIC_H__ +#define __GIC_H__ + +#include "emu.h" + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_GIC_ADD(_tag, _clock, _screen_tag) \ + MCFG_DEVICE_ADD(_tag, GIC, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> gic_device + +//Palette entries +#define GIC_BLACK 0 +#define GIC_RED 1 +#define GIC_GREEN 2 +#define GIC_WHITE 3 + +#define GIC_CHAR_W 6 +#define GIC_CHAR_H 8 + +#define GIC_LEFT_H 12 +#define GIC_LEFT_W 6 + +#define GIC_RIGHT_H 6 +#define GIC_RIGHT_W 13 + +class gic_device : public device_t + , public device_sound_interface + , public device_video_interface +{ +public: + // construction/destruction + gic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + gic_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int lines, const char *shortname, const char *source); + + // static configuration helpers + static void set_screen_tag(device_t &device, const char *screen_tag) { downcast(device).m_screen_tag = screen_tag; } + + DECLARE_PALETTE_INIT(gic); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + inline bitmap_ind16 *get_bitmap() { return &m_bitmap; } + + //plgDavid please change this to a MESS friendly handshake + void set_shared_memory(const UINT8*m){ m_ram = m;}; + + // Global constants (non mesured figures) + static const int START_ACTIVE_SCAN = 10; + static const int BORDER_SIZE = GIC_CHAR_W*3; + static const int END_ACTIVE_SCAN = 10 + GIC_CHAR_W*2 + 150 + GIC_CHAR_W*2; + static const int START_Y = 1; + static const int SCREEN_HEIGHT = GIC_CHAR_H*(GIC_LEFT_H+2); + static const int LINE_CLOCKS = 455; + static const int LINES = 262; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + /* timers */ + static const device_timer_id TIMER_VBLANK = 0; + + void draw_char_left (int x, int y, UINT8 code, bitmap_ind16 &bitmap); + void draw_char_right(int x, int y, UINT8 code, bitmap_ind16 &bitmap,int bg_col); + + bitmap_ind16 m_bitmap; + UINT8 * m_cgrom; // internal chargen ROM + + emu_timer *m_vblank_timer; + sound_stream *m_stream; + + int m_audiocnt; + int m_audioval; + int m_audioreset; + const UINT8* m_ram; +}; + +// device type definition +extern const device_type GIC; + +#endif /* __GIC_H__ */