summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author David Haywood <mamehaze@users.noreply.github.com>2015-10-26 22:02:55 +0000
committer David Haywood <mamehaze@users.noreply.github.com>2015-10-26 22:02:55 +0000
commitbc6c55fe47e1380117ce1e8c14f6f480ca1398ea (patch)
treea93acd57d4e2d0e74e9207cec5b93d9e0d986f51
parent2751e76c83c2ac972a4efbfad1f301d7c769279d (diff)
new WORKING
Unisonic Champion 2711 [David Viens]
-rw-r--r--hash/unichamp.xml54
-rw-r--r--scripts/target/mame/mess.lua9
-rw-r--r--src/mame/drivers/unichamp.c277
-rw-r--r--src/mame/mess.lst1
-rw-r--r--src/mame/video/gic.c335
-rw-r--r--src/mame/video/gic.h114
6 files changed, 790 insertions, 0 deletions
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 @@
+<?xml version="1.0"?>
+<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
+
+<softwarelist name="unichamp" description="Unisonic Champion 2711 cartridges">
+
+ <software name="pac-02">
+ <description>Professional Poker Games</description>
+ <year>1977</year>
+ <publisher>Unisonic</publisher>
+ <info name="serial" value="PAC-02"/>
+ <part name="cart" interface="unichamp_cart">
+ <dataarea name="rom" size="0x1000">
+ <rom name="pac-02.bin" size="0x1000" crc="fe3213be" sha1="5b9c407fe86865f3454d4be824a7f2bf53478f73" offset="0x0000"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="pac-03">
+ <description>Assorted Family Fun</description>
+ <year>1977</year>
+ <publisher>Unisonic</publisher>
+ <info name="serial" value="PAC-03"/>
+ <part name="cart" interface="unichamp_cart">
+ <dataarea name="rom" size="0x1000">
+ <rom name="pac-03.bin" size="0x1000" crc="f81f04bd" sha1="82e2a0fda1787d5835c457ee5745b0db0cebe079" offset="0x0000"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="pac-04">
+ <description>Family Card Games</description>
+ <year>1977</year>
+ <publisher>Unisonic</publisher>
+ <info name="serial" value="PAC-04"/>
+ <part name="cart" interface="unichamp_cart">
+ <dataarea name="rom" size="0x1000">
+ <rom name="pac-04.bin" size="0x1000" crc="cac09841" sha1="bc9db83f26ed0810938156db6b104b4576754225" offset="0x0000"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="pac-05">
+ <description>Math</description>
+ <year>1977</year>
+ <publisher>Unisonic</publisher>
+ <info name="serial" value="PAC-05"/>
+ <part name="cart" interface="unichamp_cart">
+ <dataarea name="rom" size="0x1000">
+ <rom name="pac-05.bin" size="0x1000" crc="d54a6090" sha1="e85593096f43dcf14b08fd2c9fda277008a8df8b" offset="0x0000"/>
+ </dataarea>
+ </part>
+ </software>
+
+</softwarelist>
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<cpu_device> m_maincpu;
+ required_device<gic_device> m_gic;
+ required_device<generic_slot_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;i<size;i+=2){
+ UINT8 TEMP = ptr[i];
+ ptr[i] = ptr[i+1];
+ ptr[i+1] = TEMP;
+ }
+
+ m_maincpu->space(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<gic_device>;
+
+
+//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<GIC_CHAR_H;y++){
+ UINT8 current = *ptr++;
+ UINT8 nextx=0;
+ UINT8 curry= starty+y;
+ for(UINT8 x=0x20;x!=0;x=x/2){
+ if (current&x)
+ m_bitmap.pix16(curry,startx+nextx) = GIC_WHITE;
+ nextx++;
+ }
+ }
+}
+
+void gic_device::draw_char_right(int startx, int starty, UINT8 code, bitmap_ind16 &bitmap, int bg_col){
+
+ UINT8*ptr = &m_cgrom[code*GIC_CHAR_H];
+
+ for (size_t y=0;y<GIC_CHAR_H;y++){
+ UINT8 current = *ptr++;
+ UINT8 nextx=0;
+ UINT8 curry= starty+y;
+
+ m_bitmap.pix16(curry,startx+nextx) = bg_col;
+ nextx++;
+ for(UINT8 x=0x20;x!=0;x=x/2){
+ m_bitmap.pix16(curry,startx+nextx) = (current&x)?GIC_WHITE:bg_col;
+ nextx++;
+ }
+ m_bitmap.pix16(curry,startx+nextx) = bg_col;
+ nextx++;
+ m_bitmap.pix16(curry,startx+nextx) = bg_col;
+ }
+}
+
+UINT32 gic_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ m_bitmap.fill(GIC_GREEN);
+
+ size_t XSTART = BORDER_SIZE;
+ size_t YSTART = START_ACTIVE_SCAN;
+
+ //left hand side first
+ UINT8 current=0;
+ for(UINT8 cy=0;cy<GIC_LEFT_H;cy++){
+ for(UINT8 cx=0;cx<GIC_LEFT_W;cx++){
+ draw_char_left(XSTART+(cx*GIC_CHAR_W),
+ YSTART+(cy*GIC_CHAR_H),
+ m_ram[current],
+ m_bitmap);
+ current++;
+ }
+ }
+
+ //right hand side is next
+ current=0x48;//110 octal
+ XSTART+=(GIC_LEFT_W*GIC_CHAR_W)+1;
+
+ for(UINT8 cy=0;cy<GIC_RIGHT_H;cy++){
+ for(UINT8 cx=0;cx<GIC_RIGHT_W;cx++){
+ //complex case
+ UINT8 data = m_ram[current++];
+
+ size_t currX = (XSTART+ (cx*(3+GIC_CHAR_W)));
+ size_t currUP = (YSTART+ (cy*(2*GIC_CHAR_H)));
+ size_t currLOW = (YSTART+GIC_CHAR_H+(cy*(2*GIC_CHAR_H)));
+
+ switch(data&0xC0){
+ case 0x00:{
+ //lower rectangle only, normal char
+ draw_char_right(currX,currLOW,data,m_bitmap,GIC_GREEN);
+ }break;
+
+ //White block
+ case 0xC0:{
+ //upper rectangle
+ draw_char_right(currX,currUP, GIC_SPACE,m_bitmap,GIC_WHITE);
+ //lower rectangle
+ draw_char_right(currX,currLOW,GIC_SPACE,m_bitmap,GIC_WHITE);
+ }break;
+
+ //Draw a card
+ case 0x40:{
+ int bgColor = (data&0x10)?GIC_RED:GIC_BLACK;
+ //upper rectangle
+ draw_char_right(currX,currUP, (data&0xF)+0x30,m_bitmap,bgColor);
+ //lower rectangle
+ draw_char_right(currX,currLOW,GIC_CLUB+((data&0x30)>>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<gic_device &>(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__ */